cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F030C8Tx was a hard fault when using SPI (HAL)

Marcus Nguyen
Associate II

Hi everyone,

My name is Chinh, I am working on stm32f030c8t6 for my project. I am using SPI1 to interface with an RF module. This program run very good when I implement on stm32f103c8t6, to save money I decide to switch to stm32f0 which have a lower cost than F1. Unfortunately, I have a big problem that I can't understand and I have ever seen during the working time on stm32 MCU series.

I used a pointer (ui8) to point an array and if I change the value of pointer such increasing one by one after every transmission that goes to hardfault handle when putting data to DR register.

Examples:

uint8_t table[] = {0x06, 0x02, 0x52, x64, 0x01, 0x00};

uint8_t rx[10];

uint8_t *p;

p = table;

TransmitReceive(spi, p, rx, 2, timeout);

p++;

TransmitReceive(spi, p, rx, 2, timeout); -> hardfault

If I change a bit

TransmitReceive(spi, p, rx, 2, timeout);

p++;

TransmitReceive(spi, p, rx, 1, timeout);

-> No hardfault

Or:

TransmitReceive(spi, p, rx, 1, timeout);

p++;

TransmitReceive(spi, p, rx, 1, timeout); 

-> No hardfault

I attached a project with this situation below. It uses HAL library and Keil C v5. If you have a kit development or any PCB, you could run to check that. It's very weird

Addition, SPI1 and SPI2 also have the same result

Does anyone help me?

Thanks a lot!

1 ACCEPTED SOLUTION

Accepted Solutions

Are you using SPI in 16-bit or 8-bit mode?

use

uint16_t temp16 = (uint16_t)pTxData[0] + ((uint16_t)pTxData[1] << 8);

hspi->Instance->DR = temp16;

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

View solution in original post

9 REPLIES 9

CM0 has sensitivity to memory alignment, make sure the the TransmitReceive() code doesn't cast the unaligned byte pointer into a 16-bit word pointer.

Have the Hard Fault Handler report the offending instructions, and then go look at them to see why they are faulting.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

Thank Clive,

TransmitReceive() is HAL_SPI_TransmitReceive(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size, uint32_t Timeout) of HAL library. I have just write that to fast indicate.

I find the position that the latest before occur hardfaul is 

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

And I don't know What do I do next?

Are you using SPI in 16-bit or 8-bit mode?

use

uint16_t temp16 = (uint16_t)pTxData[0] + ((uint16_t)pTxData[1] << 8);

hspi->Instance->DR = temp16;

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

I am using 8-bit mode.

I try you request, It run not hardfault. Can you explain for me why we have to do that?

By the way, I have reprimands to st team firmware for stm32F0, you make me waste much time for it.

Marcus Nguyen
Associate II

I fixed this bug. I would like to send a bad reprimand to team firmware STM32F0. Especially is the SPI team, you have to check more elaborate before releasing a library for the user. I know your purpose is very nice, you wanna improve performance but you don't check clearly after you implement your code. I edited your library in below for someone who has the same bug like me.

Thanks!

Chinh Nguyen,

maurizio23
Associate II

I have the same problem. STM32F030R8 use 8bit mode SPI with 2 bytes to transmit.

If the C file that has the function has few global variables it works weel the HAL_SPI_Transmit(..), as soon I add some global variables to module the same function generate HardFault as soon it is call the following block inside stm32f0xx_hal_spi.c v1.4.0 or v 1.9.0

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

   if((hspi->Instance->SR & SPI_FLAG_TXE) == SPI_FLAG_TXE)

   {

    if(hspi->TxXferCount > 1)

    {

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

     hspi->Instance->DR = *((uint16_t*)hspi->pTxBuffPtr); //generate hard fault

     hspi->pTxBuffPtr += sizeof(uint16_t);

     hspi->TxXferCount -= 2;

    }

    else

    {

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

     hspi->TxXferCount--;

    }

   }

This is the function call

void spiWriteReg(uint8_t regAddr, uint8_t regData)

{

txBuffer[0] = regAddr;

txBuffer[1] = regData;

/*Chip select is automatic control by SPI peripheral NSS pin */

MAX7456_CS_LOW;

/*WRITE Transmit Address register first and Data second*/

if(HAL_SPI_Transmit(prthspi1, txBuffer, 2, 100) != HAL_OK)

{

Error_Handler_spi1(1);

}

MAX7456_CS_HIGH;

}

Why increasing the number of global uint8_t XX variables inside the C module the error on SPI appear or disappears?

Any suggestion if can be possible solve the problem?

Maybe change to STM32F1/F4 with stable SPI?

Thank you

Maurizio

maurizio23
Associate II

I better understand the SPI behaviors. Packing mode need some trick to be used with 8bit mode and odd byte to trasmit or receive.

The reason of memory alignment is critical for SPI with STM32F0. I make a wrong decision to use global array to store the register and data to trasmit to SPI. This affect the memoruy alignemnt for SPI that work in packing mode especially with 8bit data.

The trick is to use local variable uint16bit and merge the 2 value the transmit.

Actually I have solve with the suggestion of Clive. This is the new API with changing from 8bit to 16bit the SPI mode:

static void spiWriteReg16bit(uint8_t regAddr, uint8_t regData)

{

uint16_t temp16[1] = {(uint16_t)regAddr + ((uint16_t)regData << 😎 }; //trick for packing mode SPI

//Set SPI to 16bit mode

hspi1.Init.DataSize = SPI_DATASIZE_16BIT;

 prthspi1->Instance->CR1 = (prthspi1->Init.Mode | prthspi1->Init.Direction |

             prthspi1->Init.CLKPolarity | prthspi1->Init.CLKPhase | (prthspi1->Init.NSS & SPI_CR1_SSM) |

             prthspi1->Init.BaudRatePrescaler | prthspi1->Init.FirstBit | prthspi1->Init.CRCCalculation);

/*Chip select is automatic control by SPI peripheral NSS pin */

MAX7456_CS_LOW;

/*WRITE Transmit Address register first and Data second*/

if(HAL_SPI_Transmit(prthspi1, (uint8_t*)temp16, 1, 100) != HAL_OK)

{

Error_Handler_spi1(1);

}

MAX7456_CS_HIGH;

//Replace SPI to 8bit mode for next SPI API

hspi1.Init.DataSize = SPI_DATASIZE_8BIT;

 prthspi1->Instance->CR1 = (prthspi1->Init.Mode | prthspi1->Init.Direction |

             prthspi1->Init.CLKPolarity | prthspi1->Init.CLKPhase | (prthspi1->Init.NSS & SPI_CR1_SSM) |

             prthspi1->Init.BaudRatePrescaler | prthspi1->Init.FirstBit | prthspi1->Init.CRCCalculation);

}

Another trick when need to send odd bytes is to separate into even byte sequence and activate chip select only when exist true bytes to transmit, else use dummy bytes to match even bytes.

SPI clock speed is critical and is useful keep the prescale high as much as possible.

I hope this could be helpful for other developer. Maybe I could jump again into SPI problem with next developemnt with STM32F0 series. Keep update on this argument.

Maurizio

Did you try the modified spi library below? I think it's the most simple to fix it

I have compare the old and last HAL library file to understand what change. I study the manual and understand that when you use HAL_SPI_Transmi many time the RXFIFO became nont empty RXNE active. So the easy solution is to flush the RXFIFO until RXNE is set. This must be done at begin of next spiReadRegister function of my code. With this trick I'm able to run the spi clock at max speed with low Prescaler.

Study the manual und understanding the spi help me how to use with my extra HAL function.

It can be modify the library but program became not portable with HAL and CubeMx.

ST should update the library to solve this behaviour with SPI packing mode.