FRDM-K64F 上的 SPI 驱动程序和连续时钟
SPI driver on the FRDM-K64F and continuous clock
我正在尝试在 FRDM-K64F 板上创建自己的 SPI 裸机驱动程序。我暂时只写了一个初始化函数
为了测试功能我设置了连续时钟寄存器。我预计连续时钟会 always 生成一个时钟,即使总线上没有设置数据。但是我在示波器上没有看到时钟。
为什么我在示波器上看不到时钟?我误解了连续时钟寄存器吗?还是我忘了实现另一个寄存器?
int frdm_spi_init(SPI_Type *spi, struct frdm_spi_mode *mode, uint32_t hz)
{
if(mode->frame < FRDM_SPI_MIN_FRAME_SIZE) {
return -1;
}
// Enable clock
SIM_SCGC6 |= SIM_SCGC6_SPI0(FRDM_ENABLE);
// For debug purpose
SPI_MCR_REG(spi) &= ~SPI_MCR_CONT_SCKE_MASK;
SPI_MCR_REG(spi) |= (FRDM_ENABLE<<SPI_MCR_CLR_RXF_SHIFT);
// Master/slave
SPI_MCR_REG(spi) &= ~SPI_MCR_MSTR_MASK;
SPI_MCR_REG(spi) |= (mode->mode<<SPI_MCR_MSTR_SHIFT);
if(mode->mode == FRDM_SPI_MASTER) {
//Frame size
SPI_CTAR_REG(spi,0) &= ~SPI_CTAR_FMSZ_MASK;
SPI_CTAR_REG(spi,0) |= (((mode->frame-1) & 0x0F)<<SPI_CTAR_FMSZ_SHIFT);
// Spi mode
SPI_CTAR_REG(spi,0) &= ~SPI_CTAR_CPOL_MASK;
SPI_CTAR_REG(spi,0) |= (mode->CPOL)<<SPI_CTAR_CPOL_SHIFT;
SPI_CTAR_REG(spi,0) &= ~SPI_CTAR_CPHA_MASK;
SPI_CTAR_REG(spi,0) |= (mode->CPHA)<<SPI_CTAR_CPHA_SHIFT;
//Always in msb mode
SPI_CTAR_REG(spi,0) &= ~SPI_CTAR_LSBFE_MASK;
} else if(mode->mode == FRDM_SPI_SLAVE) {
/*TODO*/
}
//frequency
SPI_CTAR_REG(spi,0) &= ~SPI_CTAR_ASC_MASK;
SPI_CTAR_REG(spi,0) |= 1<<SPI_CTAR_ASC_SHIFT;
SPI_CTAR_REG(spi,0) &= ~SPI_CTAR_PASC_MASK;
SPI_CTAR_REG(spi,0) |= 0<<SPI_CTAR_PASC_SHIFT;
SPI_CTAR_REG(spi,0) &= ~SPI_CTAR_DBR_MASK;
SPI_CTAR_REG(spi,0) |= 0<<SPI_CTAR_DBR_SHIFT;
// Fifo
SPI_MCR_REG(spi) &= ~SPI_MCR_DIS_TXF_MASK;
SPI_MCR_REG(spi) != 0<<SPI_MCR_DIS_TXF_SHIFT;
//Enable
SPI_MCR_REG(spi) &= ~SPI_MCR_MDIS_MASK;
SPI_MCR_REG(spi) != 0<<SPI_MCR_MDIS_SHIFT;
// Start hardware
SPI_MCR_REG(spi) &= ~SPI_MCR_HALT_MASK;
SPI_MCR_REG(spi) |= 0<<SPI_MCR_HALT_SHIFT;
return 0;
}
提供的代码没有为 SPI 配置引脚控制寄存器;这可能在其他地方完成,但您应该验证引脚配置是否正确,并且您正在使用的 SPI 端口的 SCK 是否已 MUX 到您期望的引脚。无论如何,在这个函数中设置引脚配置可能会更好。
这个区块看起来也很可疑:
//frequency
SPI_CTAR_REG(spi,0) &= ~SPI_CTAR_ASC_MASK;
SPI_CTAR_REG(spi,0) |= 1<<SPI_CTAR_ASC_SHIFT;
SPI_CTAR_REG(spi,0) &= ~SPI_CTAR_PASC_MASK;
SPI_CTAR_REG(spi,0) |= 0<<SPI_CTAR_PASC_SHIFT;
SPI_CTAR_REG(spi,0) &= ~SPI_CTAR_DBR_MASK;
SPI_CTAR_REG(spi,0) |= 0<<SPI_CTAR_DBR_SHIFT;
不使用hz
参数,Y |= 0 << X
永远等于Y
。它留下 ASC = 1、PASC = 0、DBR = 0,只有最后一个会影响时钟频率。您尚未设置 BR 和 PBR:
SCK baud rate = (fP /PBR) x [(1+DBR)/BR]
假设当前值处于复位状态,则时钟为 fP/4.
此外你有一个错字:
//Enable
SPI_MCR_REG(spi) &= ~SPI_MCR_MDIS_MASK;
SPI_MCR_REG(spi) != 0<<SPI_MCR_MDIS_SHIFT;
// ^
// error |= not !=
然而,即使在更正后第二行也没有做任何事情,但是第一行已经清除了该位,并且 OR'ing 为零(仍然)没有做任何事情(仍然),因此错误是良性的。但是令我惊讶的是您的编译器没有发出 "statement does nothing" 警告。
我相信有一些宏可以单独设置外围寄存器字段,例如 SPI_CTAR_ASC(x)
、SPI_CTAR_PASC(x)
等。您可能应该使用这些宏来清楚并避免屏蔽错误和维护噩梦。
我正在尝试在 FRDM-K64F 板上创建自己的 SPI 裸机驱动程序。我暂时只写了一个初始化函数
为了测试功能我设置了连续时钟寄存器。我预计连续时钟会 always 生成一个时钟,即使总线上没有设置数据。但是我在示波器上没有看到时钟。
为什么我在示波器上看不到时钟?我误解了连续时钟寄存器吗?还是我忘了实现另一个寄存器?
int frdm_spi_init(SPI_Type *spi, struct frdm_spi_mode *mode, uint32_t hz)
{
if(mode->frame < FRDM_SPI_MIN_FRAME_SIZE) {
return -1;
}
// Enable clock
SIM_SCGC6 |= SIM_SCGC6_SPI0(FRDM_ENABLE);
// For debug purpose
SPI_MCR_REG(spi) &= ~SPI_MCR_CONT_SCKE_MASK;
SPI_MCR_REG(spi) |= (FRDM_ENABLE<<SPI_MCR_CLR_RXF_SHIFT);
// Master/slave
SPI_MCR_REG(spi) &= ~SPI_MCR_MSTR_MASK;
SPI_MCR_REG(spi) |= (mode->mode<<SPI_MCR_MSTR_SHIFT);
if(mode->mode == FRDM_SPI_MASTER) {
//Frame size
SPI_CTAR_REG(spi,0) &= ~SPI_CTAR_FMSZ_MASK;
SPI_CTAR_REG(spi,0) |= (((mode->frame-1) & 0x0F)<<SPI_CTAR_FMSZ_SHIFT);
// Spi mode
SPI_CTAR_REG(spi,0) &= ~SPI_CTAR_CPOL_MASK;
SPI_CTAR_REG(spi,0) |= (mode->CPOL)<<SPI_CTAR_CPOL_SHIFT;
SPI_CTAR_REG(spi,0) &= ~SPI_CTAR_CPHA_MASK;
SPI_CTAR_REG(spi,0) |= (mode->CPHA)<<SPI_CTAR_CPHA_SHIFT;
//Always in msb mode
SPI_CTAR_REG(spi,0) &= ~SPI_CTAR_LSBFE_MASK;
} else if(mode->mode == FRDM_SPI_SLAVE) {
/*TODO*/
}
//frequency
SPI_CTAR_REG(spi,0) &= ~SPI_CTAR_ASC_MASK;
SPI_CTAR_REG(spi,0) |= 1<<SPI_CTAR_ASC_SHIFT;
SPI_CTAR_REG(spi,0) &= ~SPI_CTAR_PASC_MASK;
SPI_CTAR_REG(spi,0) |= 0<<SPI_CTAR_PASC_SHIFT;
SPI_CTAR_REG(spi,0) &= ~SPI_CTAR_DBR_MASK;
SPI_CTAR_REG(spi,0) |= 0<<SPI_CTAR_DBR_SHIFT;
// Fifo
SPI_MCR_REG(spi) &= ~SPI_MCR_DIS_TXF_MASK;
SPI_MCR_REG(spi) != 0<<SPI_MCR_DIS_TXF_SHIFT;
//Enable
SPI_MCR_REG(spi) &= ~SPI_MCR_MDIS_MASK;
SPI_MCR_REG(spi) != 0<<SPI_MCR_MDIS_SHIFT;
// Start hardware
SPI_MCR_REG(spi) &= ~SPI_MCR_HALT_MASK;
SPI_MCR_REG(spi) |= 0<<SPI_MCR_HALT_SHIFT;
return 0;
}
提供的代码没有为 SPI 配置引脚控制寄存器;这可能在其他地方完成,但您应该验证引脚配置是否正确,并且您正在使用的 SPI 端口的 SCK 是否已 MUX 到您期望的引脚。无论如何,在这个函数中设置引脚配置可能会更好。
这个区块看起来也很可疑:
//frequency
SPI_CTAR_REG(spi,0) &= ~SPI_CTAR_ASC_MASK;
SPI_CTAR_REG(spi,0) |= 1<<SPI_CTAR_ASC_SHIFT;
SPI_CTAR_REG(spi,0) &= ~SPI_CTAR_PASC_MASK;
SPI_CTAR_REG(spi,0) |= 0<<SPI_CTAR_PASC_SHIFT;
SPI_CTAR_REG(spi,0) &= ~SPI_CTAR_DBR_MASK;
SPI_CTAR_REG(spi,0) |= 0<<SPI_CTAR_DBR_SHIFT;
不使用hz
参数,Y |= 0 << X
永远等于Y
。它留下 ASC = 1、PASC = 0、DBR = 0,只有最后一个会影响时钟频率。您尚未设置 BR 和 PBR:
SCK baud rate = (fP /PBR) x [(1+DBR)/BR]
假设当前值处于复位状态,则时钟为 fP/4.
此外你有一个错字:
//Enable
SPI_MCR_REG(spi) &= ~SPI_MCR_MDIS_MASK;
SPI_MCR_REG(spi) != 0<<SPI_MCR_MDIS_SHIFT;
// ^
// error |= not !=
然而,即使在更正后第二行也没有做任何事情,但是第一行已经清除了该位,并且 OR'ing 为零(仍然)没有做任何事情(仍然),因此错误是良性的。但是令我惊讶的是您的编译器没有发出 "statement does nothing" 警告。
我相信有一些宏可以单独设置外围寄存器字段,例如 SPI_CTAR_ASC(x)
、SPI_CTAR_PASC(x)
等。您可能应该使用这些宏来清楚并避免屏蔽错误和维护噩梦。