【问题标题】:STM32 SPI Driver Receiving Data Always 0STM32 SPI驱动接收数据始终为0
【发布时间】:2021-03-31 20:12:19
【问题描述】:

我正在尝试使用 stm32 LL 库(用于 SXML4 系统)编写 SPI 驱动程序。我正在通过向 MOSI 线写入 2 个字节并在 MISO 线上监听 1 个字节来测试 SPI 驱动程序。使用示波器,我能够验证 2 个字节是否正确传输,并且 SPI 从设备响应一个字节。见附件截图:

在图像中,我正在探测 SCLK 和 MISO 线。显然,MISO 行的最后 8 位是 0b01110011,这是预期的数据。我编写的驱动程序没有反映这一点,并且总是从 SPI DR 寄存器读取 0。由于 SPI 外围设备(可能我遗漏了一些东西)并且无法使用 printf 输出值(无法访问 UART 接口),我在尝试在调试模式下运行代码时遇到问题。我希望对可能存在的问题提出一些想法。

void spi_transmit_receive( SPI_TypeDef* spi, uint8_t* tx, uint8_t* rx, uint16_t size )
{

    if( !LL_SPI_IsEnabled( spi ) )
    {
        LL_SPI_Enable( spi );
    }

    if( size > 1 )
    {
        LL_SPI_SetRxFIFOThreshold( spi, LL_SPI_RX_FIFO_HALF_FULL );
    }
    else
    {
        LL_SPI_SetRxFIFOThreshold( spi, LL_SPI_RX_FIFO_QUARTER_FULL );
    }


    uint8_t* rx_ptr = rx;
    uint8_t* tx_ptr = tx;

    uint16_t tx_count = size;
    uint16_t rx_count = size;

    while( tx_count > 0 || rx_count > 0 )
    {
        if( tx_count > 0 && LL_SPI_IsActiveFlag_TXE( spi ) )
        {
            if( tx_count > 1 )
            {
                LL_SPI_TransmitData16( spi, *((uint16_t*)tx_ptr) );

                tx_ptr += sizeof( uint16_t );

                tx_count -= 2;
            }
            else
            {
                LL_SPI_TransmitData8( spi, *tx_ptr );

                tx_count -= 1;
            }
        }

        if( rx_count > 0 && LL_SPI_IsActiveFlag_RXNE( spi ) )
        {
            if( rx_count > 1 )
            {
                *((uint16_t*)rx_ptr) = LL_SPI_ReceiveData16( spi );
                rx_ptr += sizeof( uint16_t );
                rx_count -= 2;

                if( rx_count <= 1 )
                {
                    // Switch to 8 bit mode for last 8 bits
                    LL_SPI_SetRxFIFOThreshold( spi, LL_SPI_RX_FIFO_QUARTER_FULL );
                }
            }
            else
            {
                *rx_ptr = LL_SPI_ReceiveData8( spi );
                //rx_ptr += sizeof(uint8_t);
                rx_count -= 1;
            }
        }
    }

    while( LL_SPI_IsActiveFlag_BSY( spi ) ) {}

    LL_SPI_Disable( spi );
}

【问题讨论】:

  • 可能在 LL_SPI_ReceiveData8(spi) 中您没有读取正确的字节。 16 位 SPI 寄存器的最高有效字节或最低有效字节
  • 当 SPI_DR 寄存器中的字节被移动到移位寄存器时,即在字节传输开始时,TXE 标志被置位。当来自移位寄存器的字节被移动到 SPI_DR 寄存器时,即在传输结束时,RXNE 标志被置位。您的代码实际上可能正在读取字节 2 而不是字节 3。
  • 我们在 House 中使用了一种 STM32,但我不是编写这些驱动程序的人。但是一旦在另一个微控制器上,我必须将 SPI CLK 引脚声明为输出和输入,以便 CLK 在内部重新输入以启用 MISO 采样
  • @NGI 感谢大家的投入!原来正确的字节在 16 位寄存器的 MSB 中。 NGI 的建议是正确的。我现在试图理解为什么会这样。我原以为将 FIFO 设置为 LL_SPI_RX_FIFO_QUARTER_FULL 会将移入的数据放置到寄存器的下部。有什么想法吗?

标签: embedded stm32 microcontroller spi


【解决方案1】:

您没有指定具体的 STM32 部件,因此无法提供具体的用户手册参考,在 STM32 部件的范围内至少有两个 SPI 外设变体,因此无法确定您的部分,但 STM32F1xx 和 STM32F2xx SPI_DR 状态的文档(我的重点):

取决于数据帧格式选择位(SPI_CR1寄存器中的DFF),数据 发送或接收是 8 位或 16 位。 必须在启用之前进行此选择 SPI 以确保正确操作

也就是说,在事务处理过程中将帧从 16 位更改为 8 位是无效的。看来您应该只在 8 位模式下操作此设备,并且只需发送两个字节。我认为,如果所有传输都是 16 位的 倍数,则使用 16 位帧是合适的。

我想正在发生的事情是设备保持在 16 位模式,并且发送的数据 MSB 首先以 SPI_DR 的 MSB 结束。但由于文档表明这是未定义的行为,所有的赌注都没有了。

【讨论】:

    猜你喜欢
    • 2021-05-07
    • 2022-01-02
    • 1970-01-01
    • 2017-07-03
    • 2017-04-14
    • 1970-01-01
    • 2019-04-06
    • 2011-07-31
    相关资源
    最近更新 更多