cancel
Showing results for 
Search instead for 
Did you mean: 

HAL_SPI_Transmit on F0, F1, F4, F7

VLev
Associate II

Hi!

I have module for transmit dates to SPI Interface.

Data is - pointer to data buffer uint8_t.

In F1 & F4 all will be ok.

But in F0 & F7 modules will send *((uint16_t *)pData) (see modules below)

Program for F1 or F4 will not work on F0 & F7.

Where error?

STM32Cube_FW_F7_V1.14.0:

HAL_StatusTypeDef HAL_SPI_Transmit(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout)

 /* Transmit data in 8 Bit mode */

 else

 {

   while (hspi->TxXferCount > 0U)

   {

     /* Wait until TXE flag is set to send data */

     if (__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_TXE))

     {

       if (hspi->TxXferCount > 1U)

       {

         /* write on the data register in packing mode */

         hspi->Instance->DR = *((uint16_t *)pData);

         pData += sizeof(uint16_t);

         hspi->TxXferCount -= 2U;

       }

       else…..

STM32Cube_FW_F4_V1.18.0:

 /* Transmit data in 8 Bit mode */

 else

 {

   if((hspi->Init.Mode == SPI_MODE_SLAVE)|| (hspi->TxXferCount == 0x01))

   {

     *((__IO uint8_t*)&hspi->Instance->DR) = (*pData);

     pData += sizeof(uint8_t);

     hspi->TxXferCount--;

   }

   while (hspi->TxXferCount > 0U)

   {

     /* Wait until TXE flag is set to send data */

     if(__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_TXE))

     {

       *((__IO uint8_t*)&hspi->Instance->DR) = (*pData);

       pData += sizeof(uint8_t);

       hspi->TxXferCount--;

     }

     else…

STM32Cube_FW_F1_V1.7.0:

 /* Transmit data in 8 Bit mode */

 else

 {

   if((hspi->Init.Mode == SPI_MODE_SLAVE)|| (hspi->TxXferCount == 0x01))

   {

     *((__IO uint8_t*)&hspi->Instance->DR) = (*pData);

     pData += sizeof(uint8_t);

     hspi->TxXferCount--;

   }

   while (hspi->TxXferCount > 0U)

   {

     /* Wait until TXE flag is set to send data */

     if(__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_TXE))

     {

       *((__IO uint8_t*)&hspi->Instance->DR) = (*pData);

       pData += sizeof(uint8_t);

       hspi->TxXferCount--;

     }

     else…

STM32Cube_FW_F0_V1.9.0:

/* Transmit data in 8 Bit mode */

 else

 {

   if ((hspi->Init.Mode == SPI_MODE_SLAVE) || (hspi->TxXferCount == 0x01U))

   {

     if (hspi->TxXferCount > 1U)

     {

       /* write on the data register in packing mode */

       hspi->Instance->DR = *((uint16_t *)pData);

       pData += sizeof(uint16_t);

       hspi->TxXferCount -= 2U;

     }

     else

     {

       *((__IO uint8_t *)&hspi->Instance->DR) = (*pData++);

       hspi->TxXferCount--;

     }

   }

   while (hspi->TxXferCount > 0U)

   {

     /* Wait until TXE flag is set to send data */

     if (__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_TXE))

     {

       if (hspi->TxXferCount > 1U)

       {

         /* write on the data register in packing mode */

         hspi->Instance->DR = *((uint16_t *)pData);

         pData += sizeof(uint16_t);

         hspi->TxXferCount -= 2U;

       }

       else

       {

         *((__IO uint8_t *)&hspi->Instance->DR) = (*pData++);

         hspi->TxXferCount--;

       }

17 REPLIES 17

Same answer that I gave above - It depends on which processor. For Cortex-M0 cores (STM32F0xxx), yes, BUT only if pData contains a 16-bit WORD aligned address. For Cortex-M4 cores (F4, F7), yes always because the M4 core can handle un-aligned word accesses.

For example, on the M0 core, if pData = 0x20000100 then that 16-bit access will work. However, if pData = 0x20000101, then that 16-bit access will generate a hard fault as the address is not aligned to a 16-bit word. So for M0 cores, it all depends on where the buffer is located in memory. And I don't know that any compiler would think to try and align a buffer of 8-bit values to start on a WORD or DWORD address boundary.

So, to me, this appears to be an issue with the F0 HAL library (@Amel NASRI​ would you have someone please look at this issue).

Well I'll be a monkey's uncle. At least for the L4xx series, the ARM GCC compiler DOES align buffers in memory. In fact it appears to align them to multiples of 8 bytes. For example:

uint8_t dummy_buf1[5];
uint8_t dummy_buf2[12];
// other global variable definitions....
 
void SomeFunction( void )
{
   uint8_t dummy_buf3[6] = "Hello";
   uint8_t dummy_buf4[3] = "Hi";
 
   printf( "&dummy_buf3 = 0x%lx, &dummy_buf4 = 0x%lx\n", (uint32_t)dummy_buf3, (uint32_t)dummy_buf4 );
}

dummy_buf1 is at 0x0801dc80 and buddy_buf2 is at 0x0801dce8. Note that they are not necessarily contiguous. The compiler/linker moves them around to (hopefully) minimize holes in memory due to alignment requirements.

And the local buffers in SomeFunction() are also aligned on 8b-yte boundaries. In my case, dummy_buf3 is at 0x2000ffc8 and dummy_buf4 is at 0x2000ffb8.

I guess you need to see if the compiler output for the STM32F0xxxx family also aligns buffers like this. If it does, then I cannot explain why the 16-bit access in the SPI functions causes a hard fault.

S.Ma
Principal

In debug mode, if you get a hard fault, can you check the function call stack and go from C to disassembly to grab some clues?

VLev
Associate II

Hi Bob!

thank you for answer.

I think it's not about alignment.

even if the data array is not in an even position, nothing terrible should happen.

Maxim what will happen in this case, the program will not work correctly, but should not fall into hard error.

the problem is that, when you run this line in 8 bit mode, the processor knows that it is working in 8 bit mode.

hspi-> Instance-> DR = * ((uint16_t *) pData);

and the processor will not execute this command, dropping into hard error.

not clear another.

one and the same team developing the same driver writes different implementations for f0, f7 and f1, f4.

why do it? if this implementation works great.

everything is absolutely transparent and clear.

pay attention ( __IO uint8_t *) & hspi-> Instance-> DR - it is clearly stated that the data type wint8_t will be transmitted.

* ((__ IO uint8_t *) & hspi-> Instance-> DR) = (* pData);

  pData + = sizeof (uint8_t);

  hspi-> TxXferCount--;

until the end it is not clear what is the point of changing the driver in this place for f0, f7?

VLev
Associate II

Hi Bob!

thank you for answer.

I think it's not about alignment.

even if the data array is not in an even position, nothing terrible should happen.

Maxim what will happen in this case, the program will not work correctly, but should not fall into hard error.

the problem is that, when you run this line in 8 bit mode, the processor knows that it is working in 8 bit mode.

hspi-> Instance-> DR = * ((uint16_t *) pData);

and the processor will not execute this command, dropping into hard error.

not clear another.

one and the same team developing the same driver writes different implementations for f0, f7 and f1, f4.

why do it? if this implementation works great.

everything is absolutely transparent and clear.

pay attention ( __IO uint8_t *) & hspi-> Instance-> DR - it is clearly stated that the data type wint8_t will be transmitted.

* ((__ IO uint8_t *) & hspi-> Instance-> DR) = (* pData);

  pData + = sizeof (uint8_t);

  hspi-> TxXferCount--;

until the end it is not clear what is the point of changing the driver in this place for f0, f7?

VLev
Associate II

the problem is that, when you run this line in 8 bit mode, the processor knows that it is working in 8 bit mode.

hspi-> Instance-> DR = * ((uint16_t *) pData);

and the processor will not execute this command, dropping into hard error.

not clear another.

one and the same team developing the same driver writes different implementations for f0, f7 and f1, f4.

why do it? if this implementation works great.

everything is absolutely transparent and clear.

pay attention ( __IO uint8_t *) & hspi-> Instance-> DR - it is clearly stated that the data type wint8_t will be transmitted.

* ((__ IO uint8_t *) & hspi-> Instance-> DR) = (* pData);

  pData + = sizeof (uint8_t);

  hspi-> TxXferCount--;

until the end it is not clear what is the point of changing the driver in this place for f0, f7?

I'm pretty sure I talked about this before. Using 16-bit writes to the DR is an optimization to minimize delays between bytes on the SPI interface (on devices that don't have FIFOs).

Since you don't believe that it is an alignment issue (and it could not be), the only way to know for sure why you are getting the hard fault is to put code in the HardFault_Handler() that you can set a breakpoint on. Then when the fault occurs, look at the various fault status registers. Consult the ST STM32F0 series Cortex M0 programming manual for details of the available registers and bit values. Or search this forum. There have been several discussions about hard fault handlers, and one of them may have posted code, or a link to somewhere that has code to do this.

1 measurement is worth a thousand guesses.

VLev
Associate II

thank you.

---

Sincerely,

Vitaly.