cancel
Showing results for 
Search instead for 
Did you mean: 

STM32C5 HAL SPI: CRC error not reported via error callback when using CRC

ChristianZ
Associate II

Hello,

I am facing an issue with the STM32C5 HAL SPI driver related to CRC error detection.

In my setup, CRC is enabled for SPI. When a CRC error occurs, I can observe that the CRCERR flag is set before the transfer is closed. However, the CRC error is never reported via the HAL error callback.

Looking into the HAL implementation, I noticed the following behavior:

  • SPI_CloseTransfer() calls LL_SPI_Disable()
  • After disabling SPI, SPI_CloseTransfer() checks LL_SPI_IsActiveFlag_CRCERR()
  • When this check is performed after LL_SPI_Disable(), the CRC error is no longer detected
  • If I move the LL_SPI_IsActiveFlag_CRCERR() check before LL_SPI_Disable(), the CRC error is detected correctly

Additionally, in my case SPI_CloseTransfer() is called from HAL_SPI_IRQHandler(), but:

  • the return value of SPI_CloseTransfer() is not evaluated
  • only the Tx/Rx complete callback is invoked
  • my error callback is never called, even though a CRC error has occurred

From my understanding:

  • LL_SPI_Disable() itself does not clear the CRCERR flag
  • therefore, it seems the HAL state machine closes the transfer and reports completion before properly propagating CRC errors

Could you please clarify:

  1. What is the intended sequence for CRC error detection in the HAL SPI driver?
  2. Should CRC errors be detected and handled before disabling the SPI peripheral?
  3. Is this a known issue or limitation in the STM32C5 HAL SPI implementation?

I would appreciate guidance or confirmation whether this is a HAL bug.

Best regards
Christian

1 ACCEPTED SOLUTION

Accepted Solutions

Hello @ChristianZ,

The developer had the same doubts about the other error flags and created the following fix, which will also be included in the release:

diff --git a/Code/c5/hal_spi.c b/Code/c5/hal_spi.c
index 7ad8f4f..1779cc7 100644
--- a/Code/c5/hal_spi.c
+++ b/Code/c5/hal_spi.c
@@ -5276,18 +5276,6 @@
   }
 #endif /* USE_HAL_SPI_CRC */
 
-  LL_SPI_Disable((SPI_TypeDef *)((uint32_t)hspi->instance));
-
-  /* Disable ITs */
-  LL_SPI_DisableIT((SPI_TypeDef *)((uint32_t)hspi->instance),
-                   LL_SPI_IT_EOT | LL_SPI_IT_TXP | LL_SPI_IT_RXP | LL_SPI_IT_DXP |
-                   LL_SPI_IT_UDR | LL_SPI_IT_OVR | LL_SPI_IT_TIFRE | LL_SPI_IT_MODF);
-
-#if defined(USE_HAL_SPI_DMA) && (USE_HAL_SPI_DMA == 1)
-  LL_SPI_DisableDMAReq_TX((SPI_TypeDef *)((uint32_t)hspi->instance));
-  LL_SPI_DisableDMAReq_RX((SPI_TypeDef *)((uint32_t)hspi->instance));
-#endif /* USE_HAL_SPI_DMA */
-
   /* Report Underrun error for non RX Only communication */
   if (hspi->global_state != HAL_SPI_STATE_RX_ACTIVE)
   {
@@ -5340,6 +5328,19 @@
 
     status = HAL_ERROR;
   }
+
+  LL_SPI_Disable((SPI_TypeDef *)((uint32_t)hspi->instance));
+
+  /* Disable ITs */
+  LL_SPI_DisableIT((SPI_TypeDef *)((uint32_t)hspi->instance),
+                   LL_SPI_IT_EOT | LL_SPI_IT_TXP | LL_SPI_IT_RXP | LL_SPI_IT_DXP |
+                   LL_SPI_IT_UDR | LL_SPI_IT_OVR | LL_SPI_IT_TIFRE | LL_SPI_IT_MODF);
+
+#if defined(USE_HAL_SPI_DMA) && (USE_HAL_SPI_DMA == 1)
+  LL_SPI_DisableDMAReq_TX((SPI_TypeDef *)((uint32_t)hspi->instance));
+  LL_SPI_DisableDMAReq_RX((SPI_TypeDef *)((uint32_t)hspi->instance));
+#endif /* USE_HAL_SPI_DMA */
+
   hspi->tx_xfer_count = (uint16_t)0UL;
   hspi->rx_xfer_count = (uint16_t)0UL;
 

Regarding CRC no longer being inside the if (hspi->global_state != HAL_SPI_STATE_TX_ACTIVE) statement, this is expected, since this case should be handled in all cases, not only in HAL_SPI_STATE_TX_ACTIVE.

For example, it may be necessary when the state is HAL_SPI_STATE_TX_RX_ACTIVE.

As for the release date of the next HAL2 update, there is still no fixed date I can share.

Best regards,

To improve visibility of answered topics, please click 'Accept as Solution' on the reply that resolved your issue or answered your question.

View solution in original post

8 REPLIES 8
STackPointer64
ST Employee

Hello @ChristianZ, and Welcome to ST Community!

I have escalated the issue to the relevant team for resolution. It is being tracked internally under ticket number CDM0061755.

Best regards,

To improve visibility of answered topics, please click 'Accept as Solution' on the reply that resolved your issue or answered your question.
Sara BEN HADJ YAHYA
ST Employee

Hello,

this thread has been moved to the STM32 MCUs Embedded software forum because it relates only to HAL2, not STM32CubeMX2. This will help improve visibility and ensure the right experts are involved.

Regards,

Sara.


In order to give better visibility on the answered topics, please click on 'Accept as Solution' on the reply which solved your issue or answered your question.
STackPointer64
ST Employee

Hello @ChristianZ,

I have just received the following fix for the issue you are encountering:

 

-    (void)SPI_CloseTransfer(hspi);
+    if (SPI_CloseTransfer(hspi) != HAL_OK)
+    {
+#if defined(USE_HAL_SPI_REGISTER_CALLBACKS) && (USE_HAL_SPI_REGISTER_CALLBACKS == 1)
+      hspi->p_error_cb(hspi);
+#else
+      HAL_SPI_ErrorCallback(hspi);
+#endif /* USE_HAL_SPI_REGISTER_CALLBACKS */
+    }

This patch will be available in the next releases of HAL2 for all products, including C5.

Best regards,

To improve visibility of answered topics, please click 'Accept as Solution' on the reply that resolved your issue or answered your question.

Hello @STackPointer64,

thank you for your response.

Is this behavior only relevant in HAL_SPI_IRQHandler()? What about the other transfer methods (e.g. polling or DMA)?

From my analysis, this fix does not work in my case. SPI_CloseTransfer() never returns HAL_ERROR when a CRC error occurs, because the CRC error flag seems to be cleared by LL_SPI_Disable() (line 5256).

When I move the USE_HAL_SPI_CRC section (lines 5295–5309) before the call to LL_SPI_Disable(), the CRC error is detected correctly and status is set to HAL_ERROR. With the additional fix you mentioned regarding the SPI_CloseTransfer() return value, the error callback is then triggered as expected.

Did this really work for you without modifying SPI_CloseTransfer()? If so, could you please clarify how this was tested, or what I might be missing?

Thank you very much for your help.

Best regards,
Christian

STackPointer64
ST Employee

Hello @ChristianZ,

This is the rest of the fix regarding CRC:

diff --git a/Code/c5/hal_spi.c b/Code/c5/hal_spi.c
index 35affef..7ad8f4f 100644
--- a/Code/c5/hal_spi.c
+++ b/Code/c5/hal_spi.c
@@ -5260,6 +5260,22 @@
   /* Clear the Status flags in the SR register */
   LL_SPI_ClearFlag((SPI_TypeDef *)((uint32_t)hspi->instance), LL_SPI_FLAG_EOT | LL_SPI_FLAG_TXTF);
 
+#if (USE_HAL_SPI_CRC != 0UL)
+  /* Check if CRC error occurred */
+  if (LL_SPI_IsEnabledCRC((SPI_TypeDef *)((uint32_t)hspi->instance)) != 0UL)
+  {
+    if (LL_SPI_IsActiveFlag_CRCERR((SPI_TypeDef *)((uint32_t)hspi->instance)) != 0UL)
+    {
+#if defined(USE_HAL_SPI_GET_LAST_ERRORS) && (USE_HAL_SPI_GET_LAST_ERRORS == 1)
+      STM32_SET_BIT(hspi->last_error_codes, HAL_SPI_ERROR_CRC);
+#endif /* USE_HAL_SPI_GET_LAST_ERRORS */
+      LL_SPI_ClearFlag_CRCERR((SPI_TypeDef *)((uint32_t)hspi->instance));
+
+      status = HAL_ERROR;
+    }
+  }
+#endif /* USE_HAL_SPI_CRC */
+
   LL_SPI_Disable((SPI_TypeDef *)((uint32_t)hspi->instance));
 
   /* Disable ITs */
@@ -5298,22 +5314,6 @@
 
       status = HAL_ERROR;
     }
-
-#if (USE_HAL_SPI_CRC != 0UL)
-    /* Check if CRC error occurred */
-    if (LL_SPI_IsEnabledCRC((SPI_TypeDef *)((uint32_t)hspi->instance)) != 0UL)
-    {
-      if (LL_SPI_IsActiveFlag_CRCERR((SPI_TypeDef *)((uint32_t)hspi->instance)) != 0UL)
-      {
-#if defined(USE_HAL_SPI_GET_LAST_ERRORS) && (USE_HAL_SPI_GET_LAST_ERRORS == 1)
-        STM32_SET_BIT(hspi->last_error_codes, HAL_SPI_ERROR_CRC);
-#endif /* USE_HAL_SPI_GET_LAST_ERRORS */
-        LL_SPI_ClearFlag_CRCERR((SPI_TypeDef *)((uint32_t)hspi->instance));
-
-        status = HAL_ERROR;
-      }
-    }
-#endif /* USE_HAL_SPI_CRC */
   }
 
   /* SPI Mode Fault error interrupt occurred -------------------------------*/

Best regards,

To improve visibility of answered topics, please click 'Accept as Solution' on the reply that resolved your issue or answered your question.

Hello @STackPointer64,

thank you for the clarification.

What about the other error flags – are they affected in a similar way and would they also need to be evaluated before calling LL_SPI_Disable()?

Additionally, if only the CRC handling is moved, it would no longer be inside if (hspi->global_state != HAL_SPI_STATE_TX_ACTIVE) { ... } together with the LL_SPI_IsActiveFlag_OVR() check.

In this case, is moving only the CRC part considered the correct and complete fix, or is it intended as an intermediate workaround?

Finally, is there already any information available regarding the schedule for the next HAL2 driver release?

Best regards,

Christian

Hello @ChristianZ,

The developer had the same doubts about the other error flags and created the following fix, which will also be included in the release:

diff --git a/Code/c5/hal_spi.c b/Code/c5/hal_spi.c
index 7ad8f4f..1779cc7 100644
--- a/Code/c5/hal_spi.c
+++ b/Code/c5/hal_spi.c
@@ -5276,18 +5276,6 @@
   }
 #endif /* USE_HAL_SPI_CRC */
 
-  LL_SPI_Disable((SPI_TypeDef *)((uint32_t)hspi->instance));
-
-  /* Disable ITs */
-  LL_SPI_DisableIT((SPI_TypeDef *)((uint32_t)hspi->instance),
-                   LL_SPI_IT_EOT | LL_SPI_IT_TXP | LL_SPI_IT_RXP | LL_SPI_IT_DXP |
-                   LL_SPI_IT_UDR | LL_SPI_IT_OVR | LL_SPI_IT_TIFRE | LL_SPI_IT_MODF);
-
-#if defined(USE_HAL_SPI_DMA) && (USE_HAL_SPI_DMA == 1)
-  LL_SPI_DisableDMAReq_TX((SPI_TypeDef *)((uint32_t)hspi->instance));
-  LL_SPI_DisableDMAReq_RX((SPI_TypeDef *)((uint32_t)hspi->instance));
-#endif /* USE_HAL_SPI_DMA */
-
   /* Report Underrun error for non RX Only communication */
   if (hspi->global_state != HAL_SPI_STATE_RX_ACTIVE)
   {
@@ -5340,6 +5328,19 @@
 
     status = HAL_ERROR;
   }
+
+  LL_SPI_Disable((SPI_TypeDef *)((uint32_t)hspi->instance));
+
+  /* Disable ITs */
+  LL_SPI_DisableIT((SPI_TypeDef *)((uint32_t)hspi->instance),
+                   LL_SPI_IT_EOT | LL_SPI_IT_TXP | LL_SPI_IT_RXP | LL_SPI_IT_DXP |
+                   LL_SPI_IT_UDR | LL_SPI_IT_OVR | LL_SPI_IT_TIFRE | LL_SPI_IT_MODF);
+
+#if defined(USE_HAL_SPI_DMA) && (USE_HAL_SPI_DMA == 1)
+  LL_SPI_DisableDMAReq_TX((SPI_TypeDef *)((uint32_t)hspi->instance));
+  LL_SPI_DisableDMAReq_RX((SPI_TypeDef *)((uint32_t)hspi->instance));
+#endif /* USE_HAL_SPI_DMA */
+
   hspi->tx_xfer_count = (uint16_t)0UL;
   hspi->rx_xfer_count = (uint16_t)0UL;
 

Regarding CRC no longer being inside the if (hspi->global_state != HAL_SPI_STATE_TX_ACTIVE) statement, this is expected, since this case should be handled in all cases, not only in HAL_SPI_STATE_TX_ACTIVE.

For example, it may be necessary when the state is HAL_SPI_STATE_TX_RX_ACTIVE.

As for the release date of the next HAL2 update, there is still no fixed date I can share.

Best regards,

To improve visibility of answered topics, please click 'Accept as Solution' on the reply that resolved your issue or answered your question.

Hello @ChristianZ,

Did the fix solve your issue? If so, please click “Accept as Solution” on the reply that resolved your issue or answered your question.

Best regards,

To improve visibility of answered topics, please click 'Accept as Solution' on the reply that resolved your issue or answered your question.