带有 STM32F7 的 SPI 从模式和循环 DMA

Posted

技术标签:

【中文标题】带有 STM32F7 的 SPI 从模式和循环 DMA【英文标题】:SPI Slave mode and circular DMA with STM32F7 【发布时间】:2021-09-15 05:13:03 【问题描述】:

我目前正在使用以 SPI(主模式)进行通信的外围设备。 本机发送一个 27 位数据包,每个接收 8 个 27 位数据包。 在我的 STM32 中,我在从机模式(全双工)下使用 SPI 协议,我使用 27 位缓冲存储器进行接收(RxBuffer [26])和 8 个 27 位缓冲器,每个用于传输。 (TxBufferPKG0[27]、TxBufferPKG1[27]、...、TxBufferPKG7[27])。 接收效果很好。 问题是一个接一个地发送 8 个数据包。 我在传输过程中发生了位移。不幸的是,我没有示波器来查看帧。 我不想使用 216 位 (8 * 27) 缓冲区。

我正在使用 void DMA_IRQHandler () 函数将内存传输到 SPI。但是,我似乎无法使用中断标志来完成发送。 我知道标志是 DMA_IT_HT 和 DMA_IT_TC,但我不知道如何正确使用它们。

我想一个一个地发送 27 位数据包,并且没有延迟。

感谢您的帮助。

我的代码:

uint8_t TbufferPKG0[27] =  0, 0x7F, 0x7F, 0x63, 0x41, 0x00, 0x00, 0x20, 0x10, 0x08, 0x04, 0x02, 0x00, 0x20, 0x10, 0x08, 0x04, 0x02, 0x00, 0x20, 0x10, 0x08, 0x04, 0x02, 0x00, 0, 0 ;
uint8_t TbufferPKG1[27] =  24, 0x7E, 0x11, 0x11, 0x11, 0x7E, 0x00, 0x7F, 0x49, 0x49, 0x49, 0x36, 0x00, 0x3E, 0x41, 0x41, 0x41, 0x22, 0x00, 0x7F, 0x41, 0x41, 0x41, 0x3E, 0x00, 0, 0 ;
uint8_t TbufferPKG2[27] =  48, 0x7F, 0x49, 0x49, 0x49, 0x41, 0x00, 0x7F, 0x09, 0x09, 0x09, 0x01, 0x00, 0x3E, 0x41, 0x49, 0x49, 0x3A, 0x00, 0x7F, 0x08, 0x08, 0x08, 0x7F, 0x00, 0, 0 ;
uint8_t TbufferPKG3[27] =  72, 0x02, 0x04, 0x08, 0x10, 0x20, 0x00, 0x02, 0x04, 0x08, 0x10, 0x20, 0x00, 0x02, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x41, 0x63, 0x7F, 0x7F, 0x00, 0, 0 ;
uint8_t TbufferPKG4[27] =  96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ;
uint8_t TbufferPKG5[27] =  120, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ;
uint8_t TbufferPKG6[27] =  144, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ;
uint8_t TbufferPKG7[27] =  168, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0C, 0, 0x20, 0, 0, 0, 0x58, 0, 0, 0 ;

uint8_t Tbuffer[27] =  168, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0C, 0, 0x20, 0, 0, 0, 0x58, 0, 0, 0 ;

uint8_t Rbuffer[27] = 0;

void DMA1_Stream4_IRQHandler(void) 

HAL_DMA_IRQHandler(&hdma_spi2_tx);

if (TxPKG_SPI2 == 0)  memmove(Tbuffer, TbufferPKG0, sizeof(Tbuffer)); 
if (TxPKG_SPI2 == 1)  memmove(Tbuffer, TbufferPKG1, sizeof(Tbuffer)); 
if (TxPKG_SPI2 == 2)  memmove(Tbuffer, TbufferPKG2, sizeof(Tbuffer)); 
if (TxPKG_SPI2 == 3)  memmove(Tbuffer, TbufferPKG3, sizeof(Tbuffer)); 
if (TxPKG_SPI2 == 4)  memmove(Tbuffer, TbufferPKG4, sizeof(Tbuffer)); 
if (TxPKG_SPI2 == 5)  memmove(Tbuffer, TbufferPKG5, sizeof(Tbuffer)); 
if (TxPKG_SPI2 == 6)  memmove(Tbuffer, TbufferPKG6, sizeof(Tbuffer)); 
if (TxPKG_SPI2 == 7)  memmove(Tbuffer, TbufferPKG7, sizeof(Tbuffer)); 

TxPKG_SPI2 += 1;
if (TxPKG_SPI2 >= 8)  TxPKG_SPI2 = 0; 



/* SPI2_TX Init */
hdma_spi2_tx.Instance = DMA1_Stream4;
hdma_spi2_tx.Init.Channel = DMA_CHANNEL_0;
hdma_spi2_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_spi2_tx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_spi2_tx.Init.MemInc = DMA_MINC_ENABLE;
hdma_spi2_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_spi2_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_spi2_tx.Init.Mode = DMA_CIRCULAR;
hdma_spi2_tx.Init.Priority = DMA_PRIORITY_VERY_HIGH;
hdma_spi2_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;

【问题讨论】:

你说的是27位,但是代码声明了27字节的数组,你是什么意思? 您也将 DMA 设置为循环模式。这将永远一遍又一遍地传输相同的缓冲区,而不会传输到下一个。 使用不正确的时钟沿可能会导致移位一位。检查两端的时钟极性和相位设置是否正确。 这是一个 27 位的缓冲区数组。该数组用于 SPI 中的传输。发送缓冲区[27] 如何使用循环 DMA 将一个缓冲区连接到另一个缓冲区? 【参考方案1】:

我解决了我的问题。 我将 DMA 循环替换为 DMA 正常,并调用 HAL_SPI_TxRxCpltCallback 函数。

【讨论】:

以上是关于带有 STM32F7 的 SPI 从模式和循环 DMA的主要内容,如果未能解决你的问题,请参考以下文章

STM32F7 发现 - USB FS 主机/设备模式检测

如何将带有 SPL 的 STM32F3 代码移植到 STM32F7

如何将 STM32f4 编程为 SPI 从设备

带有 AXIM/ITCM 闪存的 STM32F7 VMA 和 LMA

STM32F7系列时钟相关问题:HSE模式配置(旁路模式非旁路模式

STM32F7:ADC DMA 传输只工作一次