我正在通信2 uC(arduino显示为MASTER,STM32F429为从属)。它通过SPI使用DMA,每隔150ms进行全双工10字节。
在几分钟内,通信非常好,uC正在正确发送10个字节。在此期间,我注意到" HAL_SPI_ErrorCallback"函数被称为因为我已经添加了一个计数器并且它一点一点地增加,但是通信仍然很顺利。
我的第一个问题是:有时候随机调用ErrorCallback函数是否正常?由于噪音或任何通讯有瞬间错误......我猜..
Here are a capture of the MISO signal in green, CLK in whie and CS in yellow
另一方面,一段时间后(随机10分钟,1小时......)通信在MISO信号中被破坏,STM32发送10字节帧但不发送Byte0 Byte1 Byte2 Byte3 Byte4 Byte5 Byte6 Byte7 Byte8 Byte9 Byte10,(LSB优先)
它发送:
Byte10 Byte0 Byte1 Byte2 Byte3 Byte4 Byte5 Byte6 Byte7 Byte8 Byte9,它被移动到1字节!?!?
附上你可以看到捕获" Working.jpg" byte0 = 0x02,其余字节= 0.在另一个捕获" NOT_working.jpg"是一个有问题的捕获。两个uC都正常工作了一段时间,突然STM32 uC开始一直发送这个帧(通信帧是字节= 0x02,其余的字节= 0,以便轻易看到这个错误)。
Working.jpg - which is MISO signal sending the frame properly
NOT_working.jpg - which is MISO signal sending the frame incorrectly
我尝试过以下方面的沟通: " Init.Mode = DMA_NORMAL"和" DMA_CIRCULAR",并且两种配置都具有相同的行为。 为了找出问题,我创建了2个变量:
DMA_counter_RX = __HAL_DMA_GET_COUNTER(&hdma_spi6_rx);
DMA_counter_TX = __HAL_DMA_GET_COUNTER(&hdma_spi6_tx);
并且通信顺利,DMA_counter_RX = 10但是DMA_counter_TX = 9.这个值是正常的。但是一旦发生移位错误,两个DMA计数器都是= 10。
当我点击"暂停"此问题也总是在调试模式下发生。 (暂停)和"恢复"(播放)我一点击"恢复"并且处理器继续该程序,MISO信号永远移位。
此外,我将TIM1,TIM5,TIM2,TIM3和TIM4用于其他事情,如PWM和中断,但与SPI无关......
我试图解决这个问题,修改所有中断的所有NVIC优先级等等,但问题变得更糟。
我正在使用System Workbench for STM32最新版本。
任何帮助都很感激!在此先感谢和最诚挚的问候。
亚历
很抱歉很长的问题...... :(
Bellow你可以看到我的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 cube 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 */
}
------------------------------ EDITED ---------------- ------------ 我添加了2个SPI寄存器的捕获
答案 0 :(得分:0)
我终于得到了解决方案,我发现了问题所在!
通常,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(STM32 SPI被选择并准备好通信)时,如果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是为了注意到这一点。
感谢您帮助我并支持我们。
我希望这对其他人有帮助。
最好的问候。
亚历。