STM32F-带DMA的SPI“;ErrorCallback";帧移动了
我正在通信2个uC(一个arduino显示器作为主显示器,STM32F429作为从显示器)。它的通信由10个字节组成,通过使用DMA的SPI全双工,每150ms一次 在几分钟内,通信进行得非常顺利,两个uC都正确地发送了10个字节。在这段时间里,我注意到调用了“HAL_SPI_ErrorCallback”函数,因为我在其中添加了一个计数器,并且它一点一点地增加,但是通信仍然进行得很顺利 我的第一个问题是:有时随机调用ErrorCallback函数是否正常?由于噪音或其他原因,通讯出现瞬时错误。。。我想 另一方面,在一段时间(随机10分钟,1h…)之后,仅在MISO信号中通信被破坏,STM32发送10字节帧,但不是发送字节0字节1字节2字节3字节4字节5字节6字节7字节8字节9字节10,(LSB优先) 它发送: 字节10字节0字节1字节2字节3字节4字节5字节6字节7字节8字节9,它被移动到右1字节 附加您可以看到捕获“Working.jpg”,字节0=0x02,其余字节=0。在另一个捕获中,“NOT_working.jpg”是一个有问题的捕获。两个uC都正常工作了一段时间,突然STM32 uC开始一直发送此帧(通信帧为字节=0x02,其余字节=0,以便轻松查看此错误) 我尝试了以下沟通方式: “Init.Mode=DMA_NORMAL”和“DMA_CIRCULAR”,这两种配置具有相同的行为。 为了找出问题,我对两个变量进行了验证:STM32F-带DMA的SPI“;ErrorCallback";帧移动了,stm32,spi,dma,stm32f4discovery,stm32f4,Stm32,Spi,Dma,Stm32f4discovery,Stm32f4,我正在通信2个uC(一个arduino显示器作为主显示器,STM32F429作为从显示器)。它的通信由10个字节组成,通过使用DMA的SPI全双工,每150ms一次 在几分钟内,通信进行得非常顺利,两个uC都正确地发送了10个字节。在这段时间里,我注意到调用了“HAL_SPI_ErrorCallback”函数,因为我在其中添加了一个计数器,并且它一点一点地增加,但是通信仍然进行得很顺利 我的第一个问题是:有时随机调用ErrorCallback函数是否正常?由于噪音或其他原因,通讯出现瞬时错误。。
DMA_counter_RX = __HAL_DMA_GET_COUNTER(&hdma_spi6_rx);
DMA_counter_TX = __HAL_DMA_GET_COUNTER(&hdma_spi6_tx);
通信进展顺利,DMA_计数器_RX=10,但DMA_计数器_TX=9。该值为正常值。但一旦发生移位错误,两个DMA计数器都将=10
此外,在调试模式下,当我单击“暂停”(暂停)和“恢复”(播放)时,此问题总是会发生。一旦我单击“恢复”,处理器继续执行程序,MISO信号将永远移动
此外,我使用TIM1,TIM5,TIM2,TIM3和TIM4的其他东西,如PWM和中断,但不涉及SPI
我试图解决这个问题,修改所有中断的NVIC优先级等,但问题变得更糟
我正在使用System Workbench for STM32最新版本
任何帮助都是感激的!提前感谢并致以最良好的问候
亚历杭德罗
很抱歉问了这么长时间…:(
下面您可以看到我的SPI和DMA配置,如果它可以帮助您:
void MX_DMA_Init(void)
{
__HAL_RCC_DMA2_CLK_ENABLE();
HAL_NVIC_SetPriority(DMA2_Stream5_IRQn, 2, 0);
HAL_NVIC_EnableIRQ(DMA2_Stream5_IRQn);
HAL_NVIC_SetPriority(DMA2_Stream6_IRQn, 2, 0);
HAL_NVIC_EnableIRQ(DMA2_Stream6_IRQn);
}
void MX_SPI6_Init(void)
{
hspi6.Instance = SPI6;
hspi6.Init.Mode = SPI_MODE_SLAVE;
hspi6.Init.Direction = SPI_DIRECTION_2LINES;
hspi6.Init.DataSize = SPI_DATASIZE_8BIT;
hspi6.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi6.Init.CLKPhase = SPI_PHASE_1EDGE;
hspi6.Init.NSS = SPI_NSS_HARD_INPUT;
hspi6.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi6.Init.TIMode = SPI_TIMODE_DISABLE;
hspi6.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi6.Init.CRCPolynomial = 10;
if (HAL_SPI_Init(&hspi6) != HAL_OK)
{
Error_Handler();
}
}
void HAL_SPI_MspInit(SPI_HandleTypeDef* hspi)
{
GPIO_InitTypeDef GPIO_InitStruct;
if(hspi->Instance==SPI6)
{
__HAL_RCC_SPI6_CLK_ENABLE();
/**SPI6 GPIO Configuration
PG8 ------> SPI6_NSS
PG12 ------> SPI6_MISO
PG13 ------> SPI6_SCK
PG14 ------> SPI6_MOSI
*/
GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI6;
HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);
hdma_spi6_rx.Instance = DMA2_Stream6;
hdma_spi6_rx.Init.Channel = DMA_CHANNEL_1;
hdma_spi6_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_spi6_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_spi6_rx.Init.MemInc = DMA_MINC_ENABLE;
hdma_spi6_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_spi6_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_spi6_rx.Init.Mode = DMA_NORMAL;
hdma_spi6_rx.Init.Priority = DMA_PRIORITY_MEDIUM;
hdma_spi6_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
if (HAL_DMA_Init(&hdma_spi6_rx) != HAL_OK)
{
Error_Handler();
}
__HAL_LINKDMA(hspi,hdmarx,hdma_spi6_rx);
hdma_spi6_tx.Instance = DMA2_Stream5;
hdma_spi6_tx.Init.Channel = DMA_CHANNEL_1;
hdma_spi6_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_spi6_tx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_spi6_tx.Init.MemInc = DMA_MINC_ENABLE;
hdma_spi6_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_spi6_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_spi6_tx.Init.Mode = DMA_NORMAL;
hdma_spi6_tx.Init.Priority = DMA_PRIORITY_MEDIUM;
hdma_spi6_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
if (HAL_DMA_Init(&hdma_spi6_tx) != HAL_OK)
{
Error_Handler();
}
__HAL_LINKDMA(hspi,hdmatx,hdma_spi6_tx);
/* Peripheral interrupt init */
HAL_NVIC_SetPriority(SPI6_IRQn, 2, 0);
HAL_NVIC_EnableIRQ(SPI6_IRQn);
}
}
在初始化代码期间,我按照前面所述配置SPI6和DMA,然后使用以下方式启用通信:
HAL_SPI_TransmitReceive_DMA(&hspi6, (uint8_t*)HMI_slave_TX_data, (uint8_t*)HMI_slave_RX_data, 10);
此外,还添加了与SPI通信相关的以下2个功能:
void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi)
{
if(hspi -> Instance == SPI6)
{
HAL_SPI_TransmitReceive_DMA(&hspi6, (uint8_t*)HMI_slave_TX_data, (uint8_t*)HMI_slave_RX_data, 10);
}
}
void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi)
{
if(hspi -> Instance == SPI6)
{
HAL_SPI_TransmitReceive_DMA(&hspi6, (uint8_t*)HMI_slave_TX_data, (uint8_t*)HMI_slave_RX_data,10);
}
}
自动创建的STM多维数据集mx:
void DMA2_Stream5_IRQHandler(void)
{
/* USER CODE BEGIN DMA2_Stream5_IRQn 0 */
/* USER CODE END DMA2_Stream5_IRQn 0 */
HAL_DMA_IRQHandler(&hdma_spi6_tx);
/* USER CODE BEGIN DMA2_Stream5_IRQn 1 */
/* USER CODE END DMA2_Stream5_IRQn 1 */
}
/**
* @brief This function handles DMA2 stream6 global interrupt.
*/
void DMA2_Stream6_IRQHandler(void)
{
/* USER CODE BEGIN DMA2_Stream6_IRQn 0 */
/* USER CODE END DMA2_Stream6_IRQn 0 */
HAL_DMA_IRQHandler(&hdma_spi6_rx);
/* USER CODE BEGIN DMA2_Stream6_IRQn 1 */
/* USER CODE END DMA2_Stream6_IRQn 1 */
}
void SPI6_IRQHandler(void)
{
/* USER CODE BEGIN SPI6_IRQn 0 */
/* USER CODE END SPI6_IRQn 0 */
HAL_SPI_IRQHandler(&hspi6);
/* USER CODE BEGIN SPI6_IRQn 1 */
/* USER CODE END SPI6_IRQn 1 */
}
------------------------------编辑----------------------------
我添加了2个SPI寄存器的捕获
我终于找到了解决办法,我找到了问题所在 通常,CS信号从1变为0,然后MISO和MOSI通信,一旦通信完成,CS信号从0变为1,STM32F429继续执行其余任务 这种情况每150毫秒发生一次,这是两个uC通信的时间段。但是STM32 uC还有比SPI通信优先级更高的任务 在SPI通信期间,当其中一个较高优先级启动时,一旦完成该较高优先级,则uC继续执行正在执行的任务(它是SPI),很明显,该帧丢失,执行“HAL_SPI_ErrorCallback”,然后重新启动SPI。如果在CS信号为1时重新启动SPI,(SPI空闲),则没有问题,SPI已正确重新启动,下一帧将无问题接收。但如果在CS信号为0时重新启动SPI(已选择STM32 SPI并准备好通信)然后,STM32正在等待发送和接收一定数量的字节,但接收的字节会更少,因此通信字节不匹配是问题的关键 我已经解决了这个问题,只需添加:
void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi)
{
if(hspi -> Instance == SPI6)
{
while(HAL_GPIO_ReadPin(GPIOG, GPIO_PIN_8) != GPIO_PIN_SET) // CS signal
{
}
HAL_SPI_TransmitReceive_DMA(&hspi6, (uint8_t*)HMI_slave_TX_data, (uint8_t*)HMI_slave_RX_data,10);
}
}
为了不停止处理器,我必须修改“WHILE”,但这是第一个近似值
现在,通信一直在工作,但有时由于更高优先级的任务而丢失帧(并调用“HAL_SPI_ErrorCallback”)。但这是正常的,需要实现CRC来注意这一点
谢谢你对我的帮助和支持
我希望这对其他人有帮助
致以最良好的祝愿
亚历杭德罗。我终于找到了解决办法,我找到了问题所在 通常,CS信号从1变为0,然后MISO和MOSI通信,一旦通信完成,CS信号从0变为1,STM32F429继续执行其余任务 这种情况每150毫秒发生一次,这是两个uC通信的时间段。但是STM32 uC还有比SPI通信优先级更高的任务 在SPI通信期间,当其中一个较高优先级启动时,一旦完成该较高优先级,则uC继续执行正在执行的任务(它是SPI),很明显,该帧丢失,执行“HAL_SPI_ErrorCallback”,然后重新启动SPI。如果在CS信号为1时重新启动SPI,(SPI空闲),则没有问题,SPI已正确重新启动,下一帧将无问题接收。但如果在CS信号为0时重新启动SPI(已选择STM32 SPI并准备好通信)然后,STM32正在等待发送和接收一定数量的字节,但接收的字节会更少,因此通信字节不匹配是问题的关键 我已经解决了这个问题,只需添加:
void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi)
{
if(hspi -> Instance == SPI6)
{
while(HAL_GPIO_ReadPin(GPIOG, GPIO_PIN_8) != GPIO_PIN_SET) // CS signal
{
}
HAL_SPI_TransmitReceive_DMA(&hspi6, (uint8_t*)HMI_slave_TX_data, (uint8_t*)HMI_slave_RX_data,10);
}
}
为了不停止处理器,我必须修改“WHILE”,但这是第一个近似值
现在,通信一直在工作,但有时会丢失一帧(和“HAL_SPI_Erro”)