AT91SAM7X512的SPI外设在写入SPI_TDR时被禁止

时间:2010-03-18 18:00:56

标签: embedded arm spi atmel

我的AT91SAM7X512的SPI外设在我写入SPI_TDR的X时间(X变化)被禁用。 结果,处理器挂起while循环,检查TDRE中的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
  4. 设置配置后,代码通过检查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. 时被禁用
    3. 我应该取消注释SPI_Write()注册SPI_RDR的{​​{1}}行吗? 意味着,以下代码中的第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);
      }
      
    4. 上面的代码是否有错误传输5个字节的数据?

    5. 请注意:

      • NPCS行号3是GPIO线(意味着,在PIO模式下),不受SPI控制器控制。 我在代码中自己控制这一行,在需要时通过de /断言ChipSelect#3(NPCS3)引脚。 我这样做的原因是因为在试图让SPI控制器控制该引脚时发生了问题。
      • 我没有使用PDC / DMA控制器,也不想使用它。
      • 我没有重置SPI外设两次,因为勘误表示只有在我执行复位时才重置两次 - 我不这样做。引用勘误表:

          

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

      • 我注意到有时是,如果我在写入SPI_TDR寄存器(SPI_Write())之前放一个延迟,那么代码就可以完美地运行了沟通成功。

      有用的链接:

      初始化SPI并执行5个字节的传输的示例非常受欢迎且非常有用。

1 个答案:

答案 0 :(得分:1)

您使用

while(i-- < dataSize)

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

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

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