2

我的 AT91SAM7X512 的 SPI 外设在我写入的 X 时间(X 变化)上被禁用SPI_TDR。结果,处理器挂起检查TDRE标志的 while 循环SPI_SR。此 while 循环位于SPI_Write()属于 ATMEL 提供的软件包/库的函数中。问题是任意发生的 - 有时一切正常,有时重复尝试失败(尝试 = 将相同的二进制文件下载到 MCU 并运行程序)。

配置是(按写作顺序定义):

  1. SPI_MR
    • MSTR= 1
    • PS= 0
    • PCSDEC= 0
    • PCS= 0111
    • DLYBCS= 0
  2. SPI_CSR[3]
    • CPOL= 0
    • NCPHA= 1
    • CSAAT= 0
    • BITS= 0000
    • SCBR= 20
    • DLYBS= 0
    • DLYBCT= 0
  3. 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.
}

问题:

  1. 是什么导致 SPI 外设在写入时被禁用SPI_TDR
  2. 我应该取消注释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);
    }
    
  3. 上面传输 5 个字节数据的代码有问题吗?

请注意:

  • NPCS 行号。3 是 GPIO 线(表示处于 PIO 模式),不受 SPI 控制器控制。我在代码中自己控制这条线,在需要时通过取消/断言 ChipSelect#3 (NPCS3) 引脚。我这样做的原因是在尝试让 SPI 控制器控制该引脚时出现问题。
  • 我没有使用 PDC/DMA 控制器,也不想使用它。
  • 我没有重置 SPI 外设两次,因为勘误表告诉我只有在我执行重置时才重置它两次——我不这样做。引用勘误表:

    如果执行软件复位(SPI 控制寄存器中的 SWRST),SPI 可能无法正常工作(在片选之前使能时钟。)
    问题修复/解决方法
    SPI 控制寄存器字段,SWRST(软件复位)需要写入两次才能正确设置。

  • 我注意到有时,如果我在写入SPI_TDR寄存器(in SPI_Write())之前延迟,那么代码可以完美运行并且通信成功。

有用的链接:

一个初始化 SPI 和执行 5 个字节传输的例子非常受欢迎和有用。

4

1 回答 1

1

你用

while(i-- < dataSize)

递减一个有符号整数i,而不是递增它并访问data[i]直到i溢出到一个正值。谁知道会发生什么,您正在访问哪些内存或寄存器?如果您不需要保存负值,则使用无符号整数通常会更好。

此外,您已经在检查是否TXEMPTY意味着数据被移动到移位寄存器并被发送出去。所以,你也不需要检查TDRE,这意味着数据被移动到移位寄存器但可能不会被发送出去。

此外,如果您不同时交换数据,我强烈建议使用 PDC,我认为情况并非如此。

于 2013-05-15T09:18:51.180 回答