2017-11-13 09:04 AM
Hello,
I am using the STM32F429ZIT uC and it is currently communicating with another uC through SPI. The STM32 is slave and the other is the master. The master sends 10 bytes and the slave replies with another 10 bytes in full duplex. Every 150ms.
The communication works fine , attached you can see 'Working_with_all_the_Frames.jpg'. (yellow = CS, green = MISO, white = CLK).
But after a while (randomly 10 min, 1h ...) the communication is corrupted just in the MISO signal , the STM32 sends the 10 bytes frame but instead of sending Byte0 Byte1 Byte2 Byte3 Byte4 Byte5 Byte6 Byte7 Byte8 Byte9 Byte10, (LSB first)
it sends:
Byte10 Byte0 Byte1 Byte2 Byte3 Byte4 Byte5 Byte6 Byte7 Byte8 Byte9, IT IS MOVED TO RIGTH 1 byte!?!?
Attached you can see the capture 'Working.jpg' with byte0 = 0x02 and the rest of the bytes = 0. In the other capture 'NOT_working.jpg' is a capture with the problem. Both uC were working properly for a while and suddenly the STM32 uC started to send this frame all the time (the communication frame is byte = 0x02 and the rest of the bytes = 0 in order to see easily this error).
I have tried the communication in:
'Init.Mode = DMA_NORMAL' and 'DMA_CIRCULAR', and both configuration have the same behaviour.On the other hand, this problem always happens in debug mode when I click on 'suspend' (pause) and 'resume'(play) as soon as I click on 'resume' and the processor continues with the program, the MISO signal is shifted forever.
Additionally I am using TIM1, TIM5, TIM2, TIM3 and TIM4 for other things like PWM and interruptions but not related to SPI...
I have tried to solve this problem modifying all the NVIC priorities for all interruptions and so on but the problem get worst.
I am using System Workbench for STM32 latest version.Any help is appreciate! Thanks in advance and best regards.
Alejandro
Bellow you can see my configuration for SPI and DMA if it can help you:
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); }}#spi #dma #communication #dma-problem #spi-over-dma #spi-dmaSolved! Go to Solution.
2017-11-17 01:32 AM
Hello,
I finally got the solution, I found what the problem was!
Usually, the CS signal goes from 1 to 0, then MISO and MOSI communicates, and once the communication finishes CS signal goes from 0 to 1, and the STM32F429 continues with the rest of the tasks...
This was happening every 150 ms, that's the period of thime both uC are communicating. But the STM32 uC has another tasks with more priority than SPI communication.
When one of this higher priority starts during SPI communication, and once this higher priority is done then the uC continues with the task was doing ( it was SPI),
obviously
this frame is lost and 'HAL_SPI_ErrorCallback' is executed, and then SPI is restarted.If SPI is restarted when CS signal is 1, (spi idle), then there is no problem, SPI is restarted properly and the next frame will be received without problem. BUT if SPI is restarted when CS signal is 0 (STM32 SPI is selected and ready to communicate) then the STM32 is waiting to send and receive an amount of bytes but it will receives less, so an a mismatch of communication bytes is the key of the PROBLEM.I have solved this issue just adding:
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);
}}I have to modify 'WHILE' in order to not stop the processor , but it is the first approximation.
Now the communication is working all the time, but some times a frame is lost (and ' HAL_SPI_ErrorCallback' is called) due to higher priority task. But it is normal, a CRC is implemented to note that.
Thansk JW to help me and support.
I hope this helps to other people.
Best regards.
Alejandro.
2017-11-13 02:09 PM
How do you start the Tx DMA?
What is in the SPI6 interrupt routine?
JW
2017-11-14 12:59 AM
Thanks for quyck reply.
During initialization code, I configure SPI6 and DMA as it is described before, just after that I enable communication using:
HAL_SPI_TransmitReceive_DMA(&hspi6, (uint8_t*)HMI_slave_TX_data, (uint8_t*)HMI_slave_RX_data, 10);
Also it were added the following 2 functions related to SPI communication:
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);
}}There is not more functions related to DMA nor SPI. Just the functions related to how to handle the information received and the information to be send. But checking the TX and RX frames using STMStudio, always the uC receives properly the information and the buffer used to send the TX frames are also OK after and before the issue, which means (i suppose) that the problem is related to DMA, because if the uC TX buffer memory is OK, why send them in a wronk byte position???
Another intreresting thing related to STMStudio, is when i check 2 variables: 'DMA_counter_RX' and 'DMA_counter_TX':
DMA_counter_RX = __HAL_DMA_GET_COUNTER(&hdma_spi6_rx);
DMA_counter_TX = __HAL_DMA_GET_COUNTER(&hdma_spi6_tx);Using this '__HAL_DMA_GET_COUNTER' (as far as i understand) I receive the NDTR register value for SPI6 TX and RX.
When the communication is going well DMA_counter_RX = 10 BUT DMA_counter_TX = 9 (i would say that should be 10...) but the comunication goes well... AND as soon as the problem occurs, both variables are = 10 !!! very wird for me...
Thanks for your suport and best regards.
Alejandro
2017-11-14 01:21 AM
You have enabled the SPI interrupt. If you don't have an explicit ISR ('handler') for it, it may be called repeatedly, flood the processor and cause surprises. Remove the SPI interrupt enable.
The Tx DMA places one byte to the transmitter holding register immediately upon enable, but it does not get transmitted until the master starts clocking, that's why you see the Tx DMA advanced by one byte compared to Rx DMA, that's normal .
JW
2017-11-14 03:05 AM
Hello JW, thanks again for your quick reply.
STM cube mx automatically creates:
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 */
}I didnt modified nothing on them. Is it necessary to modify something? or do you mean other interruption handler?
Many thanks
Alejandro
2017-11-14 03:52 AM
Just comment out
HAL_NVIC_EnableIRQ(SPI6_IRQn);
compile, test, and report back.
JW
2017-11-14 04:59 AM
Hello JW, I have tested the code with '//HAL_NVIC_EnableIRQ(SPI6_IRQn);' and at the beginning was working good but after some minutes uC doesnt modify its RX buffer, I mean, just after program and reset the STM uC the communication between both uC is correct but after some minutes the STM doesnt update their RX frame, like if always received the same RX frame.
So , the shifted frames problem is solved but due to comment this interruption , there is a new bug
:(
.Looks like that is related to interruption....
On the other hand, I have realized that in both SW verision (with HAL_NVIC_EnableIRQ(SPI6_IRQn) commented and uncommented) some times 'void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi)' is executed. The execution of this function doent affect:
I have added a counter within this ErrorCallback function and using STM Studio I have seen this counter increasing little by little but the comunication was going well.
Thanks for your support and best regards.
Alejandro
2017-11-14 06:15 AM
I don't and won't use Cube.
You probably should find you why that callback is called.
JW
2017-11-17 01:32 AM
Hello,
I finally got the solution, I found what the problem was!
Usually, the CS signal goes from 1 to 0, then MISO and MOSI communicates, and once the communication finishes CS signal goes from 0 to 1, and the STM32F429 continues with the rest of the tasks...
This was happening every 150 ms, that's the period of thime both uC are communicating. But the STM32 uC has another tasks with more priority than SPI communication.
When one of this higher priority starts during SPI communication, and once this higher priority is done then the uC continues with the task was doing ( it was SPI),
obviously
this frame is lost and 'HAL_SPI_ErrorCallback' is executed, and then SPI is restarted.If SPI is restarted when CS signal is 1, (spi idle), then there is no problem, SPI is restarted properly and the next frame will be received without problem. BUT if SPI is restarted when CS signal is 0 (STM32 SPI is selected and ready to communicate) then the STM32 is waiting to send and receive an amount of bytes but it will receives less, so an a mismatch of communication bytes is the key of the PROBLEM.I have solved this issue just adding:
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);
}}I have to modify 'WHILE' in order to not stop the processor , but it is the first approximation.
Now the communication is working all the time, but some times a frame is lost (and ' HAL_SPI_ErrorCallback' is called) due to higher priority task. But it is normal, a CRC is implemented to note that.
Thansk JW to help me and support.
I hope this helps to other people.
Best regards.
Alejandro.