Embedded STM32 SPI驱动程序始终接收数据0

Embedded STM32 SPI驱动程序始终接收数据0,embedded,stm32,microcontroller,spi,Embedded,Stm32,Microcontroller,Spi,我正在尝试使用stm32 LL库(针对STML4系统)编写SPI驱动程序。我正在测试SPI驱动程序,向MOSI线写入2个字节,并在MISO线上监听1个字节。使用示波器,我能够验证2个字节是否正确传输,SPI从设备以一个字节响应。请参阅随附的屏幕截图: 在图中,我正在探测SCLK和MISO线。显然,MISO线上的最后8位是0b01110011,这是预期的数据。我编写的驱动程序没有反映这一点,并且总是从SPI DR寄存器中读取0。我在调试模式下运行代码时遇到问题,因为SPI外围设备(可能我遗漏了一

我正在尝试使用stm32 LL库(针对STML4系统)编写SPI驱动程序。我正在测试SPI驱动程序,向MOSI线写入2个字节,并在MISO线上监听1个字节。使用示波器,我能够验证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 );
}
void spi_发送_接收(spi_类型定义*spi,uint8_t*tx,uint8_t*rx,uint16_t大小)
{
如果(!LL_SPI_isnabled(SPI))
{
LL_SPI_Enable(SPI);
}
如果(大小>1)
{
LL_SPI_setrxfiothreshold(SPI、LL_SPI_RX_FIFO_半满);
}
其他的
{
LL_SPI_setrxfiothreshold(SPI、LL_SPI_RX_FIFO_四分之一满);
}
uint8_t*rx_ptr=rx;
uint8_t*tx_ptr=tx;
uint16\u t tx\u计数=大小;
uint16\u t rx\u计数=大小;
而(发送计数>0 | |接收计数>0)
{
如果(发送计数>0&&LL\u SPI\u为激活滞后\u TXE(SPI))
{
如果(发送计数>1)
{
LL_SPI_传输数据16(SPI,*((uint16_t*)发送ptr));
tx_ptr+=尺寸f(uint16_t);
tx_计数-=2;
}
其他的
{
LL_SPI_传输数据8(SPI,*tx_ptr);
tx_计数-=1;
}
}
如果(rx\u计数>0&&LL\u SPI\u为激活滞后\u RXNE(SPI))
{
如果(接收计数>1)
{
*((uint16_t*)rx_ptr)=LL_SPI_ReceiveData16(SPI);
rx_ptr+=sizeof(uint16_t);
rx_计数-=2;

如果(rx_count您没有指定特定的STM32部件,因此无法提供特定的用户手册参考,则在STM32部件范围内至少有两种SPI外设变体,因此无法确定您的部件,但STM32F1xx和STM32F2xx SPI_DR的文档说明(我的重点):

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

这是无效的,在事务的中间将帧从16位改为8位。看来你应该只在8位模式下操作这个设备,然后简单地发送两个字节。我认为,只有在所有传输都是16位的倍数的情况下,16位帧的使用才是合适的。 我想现在发生的情况是,设备保持在16位模式,正在以MSB发送的数据首先在SPI_DR的MSB中结束。但是,由于文档表明这是未定义的行为,所以所有赌注都是无效的


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