STM32 SPI驱动接收数据一直为0
STM32 SPI Driver Receiving Data Always 0
我正在尝试使用 stm32 LL 库(用于 STML4 系统)编写 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 );
}
您没有指定具体的 STM32 部件,因此无法提供具体的用户手册参考,STM32 部件范围内至少有两种 SPI 外设变体,因此无法确定对于您而言,STM32F1xx 和 STM32F2xx 的文档 SPI_DR 状态(我的重点):
Depending on the data frame format selection bit (DFF in SPI_CR1 register), the data
sent or received is either 8-bit or 16-bit. This selection has to be made before enabling
the SPI to ensure correct operation.
也就是说,在交易过程中将帧从 16 位更改为 8 位是无效的。看来你应该专门在 8 位模式下操作这个设备并简单地发送两个字节。我认为,如果所有传输都是 16 位的倍数,则使用 16 位帧是合适的仅。
我想象正在发生的事情是设备保持在 16 位模式并且发送的数据 MSB 首先在 SPI_DR 的 MSB 中结束。但是由于文档表明这是未定义的行为,所以所有的赌注都被取消了。
我正在尝试使用 stm32 LL 库(用于 STML4 系统)编写 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 );
}
您没有指定具体的 STM32 部件,因此无法提供具体的用户手册参考,STM32 部件范围内至少有两种 SPI 外设变体,因此无法确定对于您而言,STM32F1xx 和 STM32F2xx 的文档 SPI_DR 状态(我的重点):
Depending on the data frame format selection bit (DFF in SPI_CR1 register), the data sent or received is either 8-bit or 16-bit. This selection has to be made before enabling the SPI to ensure correct operation.
也就是说,在交易过程中将帧从 16 位更改为 8 位是无效的。看来你应该专门在 8 位模式下操作这个设备并简单地发送两个字节。我认为,如果所有传输都是 16 位的倍数,则使用 16 位帧是合适的仅。
我想象正在发生的事情是设备保持在 16 位模式并且发送的数据 MSB 首先在 SPI_DR 的 MSB 中结束。但是由于文档表明这是未定义的行为,所以所有的赌注都被取消了。