我的 AT91SAM7X512 的 SPI 外设在我写入的 X 时间(X 变化)上被禁用SPI_TDR
。结果,处理器挂起检查TDRE
标志的 while 循环SPI_SR
。此 while 循环位于SPI_Write()
属于 ATMEL 提供的软件包/库的函数中。问题是任意发生的 - 有时一切正常,有时重复尝试失败(尝试 = 将相同的二进制文件下载到 MCU 并运行程序)。
配置是(按写作顺序定义):
SPI_MR
:MSTR
= 1PS
= 0PCSDEC
= 0PCS
= 0111DLYBCS
= 0
SPI_CSR[3]
:CPOL
= 0NCPHA
= 1CSAAT
= 0BITS
= 0000SCBR
= 20DLYBS
= 0DLYBCT
= 0
SPI_CR
:SPIEN
= 1
SPIENS
设置配置后,代码通过检查标志来验证 SPI 是否已启用。
我执行字节传输如下:
const short int dataSize = 5;
// Filling array with random data
unsigned char data[dataSize] = {0xA5, 0x34, 0x12, 0x00, 0xFF};
short int i = 0;
volatile unsigned short dummyRead;
SetCS3(); // NPCS3 == PIOA15
while(i-- < dataSize) {
mySPI_Write(data[i]);
while((AT91C_BASE_SPI0->SPI_SR & AT91C_SPI_TXEMPTY) == 0);
dummyRead = SPI_Read(); // SPI_Read() from Atmel's library
}
ClearCS3();
/**********************************/
void mySPI_Write(unsigned char data) {
while ((AT91C_BASE_SPI0->SPI_SR & AT91C_SPI_TXEMPTY) == 0);
AT91C_BASE_SPI0->SPI_TDR = data;
while ((AT91C_BASE_SPI0->SPI_SR & AT91C_SPI_TDRE) == 0); // <-- This is where
// the processor hangs, because that the SPI peripheral is disabled
// (SPIENS equals 0), which makes TDRE equal to 0 forever.
}
问题:
- 是什么导致 SPI 外设在写入时被禁用
SPI_TDR
? 我应该取消注释
SPI_Write()
读取SPI_RDR
寄存器的行吗?
意思是,下面代码中的第 4 行:(第 4 行原本标记为注释)void SPI_Write(AT91S_SPI *spi, unsigned int npcs, unsigned short data) { // Discard contents of RDR register //volatile unsigned int discard = spi->SPI_RDR; /* Send data */ while ((spi->SPI_SR & AT91C_SPI_TXEMPTY) == 0); spi->SPI_TDR = data | SPI_PCS(npcs); while ((spi->SPI_SR & AT91C_SPI_TDRE) == 0); }
上面传输 5 个字节数据的代码有问题吗?
请注意:
- NPCS 行号。3 是 GPIO 线(表示处于 PIO 模式),不受 SPI 控制器控制。我在代码中自己控制这条线,在需要时通过取消/断言 ChipSelect#3 (NPCS3) 引脚。我这样做的原因是在尝试让 SPI 控制器控制该引脚时出现问题。
- 我没有使用 PDC/DMA 控制器,也不想使用它。
我没有重置 SPI 外设两次,因为勘误表告诉我只有在我执行重置时才重置它两次——我不这样做。引用勘误表:
如果执行软件复位(SPI 控制寄存器中的 SWRST),SPI 可能无法正常工作(在片选之前使能时钟。)
问题修复/解决方法
SPI 控制寄存器字段,SWRST(软件复位)需要写入两次才能正确设置。我注意到有时,如果我在写入
SPI_TDR
寄存器(inSPI_Write()
)之前延迟,那么代码可以完美运行并且通信成功。
有用的链接:
一个初始化 SPI 和执行 5 个字节传输的例子非常受欢迎和有用。