cancel
Showing results for 
Search instead for 
Did you mean: 

STM32H743 variable not updating in interrupt handler

MSard
Associate II

Hello,

i have a strange situation happening and I really can't catch the reasons; in my project I set up an SPI transfer and set a global volatile variable that keeps trace of status state:

//Transmit Data
if(spi == AMPLI_SPI4) SPI4_TransferState = TRANSFER_ONGOING;
ret = HAL_SPI_Transmit_IT(&SpiHandle[spi], pData, Size);

Then in my interrupt handler I want to reset SPI4_TransferState:

void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi)
{
	if (hspi->Instance == SPI4)
	{
		SPI4_TransferState = READY_FOR_TRANSFER;
		SPI_ReleaseCSPin(AMPLI_SPI4);
	}
}

TRANSFER_ONGOING and READY_FOR_TRANSFER are 2 defines that stands for 1 and 0.

If i debug the code I can see that the interrupt is fired and that the instruction

SPI4_TransferState = READY_FOR_TRANSFER;

is executed; anyway the value of SPI4_TransferState does not change from 1 to 0, as if the instruction is doing nothing.

I have done some tests if, anyway, I change the interrupt handler like this:

void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi)
{
	if (hspi->Instance == SPI4)
	{
		SPI_Test = TRANSFER_ONGOING;
		SPI4_TransferState = READY_FOR_TRANSFER;
		SPI_Test = READY_FOR_TRANSFER;
		SPI_ReleaseCSPin(AMPLI_SPI4);
        }
}

where SPI_Test is a variable declared exactly like SPI4_TransferState, both SPI_Test and SPI_TransferState are updated correctly, but obviously this is an unreliable solution which doesn't make much sense.

To give a complete picture:

  • All variables are mapped in DTCM RAM, by linker script
  • Interrupt handler is in a file called interrupts.c which is mapped in ITCM RAM by linker script
  • function to transmit SPI data (HAL_SPI_Transmit_IT) is in a file called SPI.c that executes from FLASH
  • My project uses FreeRTOS, but the problem arises in early stage of application when tasks are not even created yet and scheduler hasn't started

MIght it be a cache-coherency problem? I am really clueless, can somebody please help ?

Thanks in advance

1 ACCEPTED SOLUTION

Accepted Solutions

Suspect you need to determine why the BKPT is there, likely overlying the opcodes that should be there.

Perhaps use a different variable for Rx vs Tx callbacks to eliminate possible race/ordering issues there.

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

6 REPLIES 6

Variable volatile?​

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

Hello,

yes the SPI4_TransferState variale is declared as "volatile uint32_t", but this doesn't help unluckily..

>>MIght it be a cache-coherency problem?

This is unlikely to be the case in a single core, software implementation. Cache coherency would be a potential issue when using DMA, which accesses memory directly, and where the CPU holds dirty cache lines it hasn't flushed.

Using pro-tools like Keil or IAR, or something else? Behaviour changes with/without optimization? Review code listings (disassembly) to see what the compiler generated and the CPU is executing.

Avoid opening a "Peripheral View" of the SPI device in the debugger, it tends to be invasive. Instrument the code, output telemetry via UART or SWV

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

I am using VisualGDB, optimization is disabled (O0).

I have tried to place SPI.c file in ITCM Ram and declared inside it a variable called "volatile uint32_t SPI_TransferState[NUM_DEFINED_SPIs];"; looking at the assembly produced I have noticed this strange situation:

I have defined the callback function like this:

void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi)
{
 
	if (hspi->Instance == SPI4)
	{
		SPI_TransferState[AMPLI_SPI4] = READY_FOR_TRANSFER;
		SPI_ReleaseCSPin(AMPLI_SPI4);
	}
}

Here is the assembly code:

   199: void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi)
   200: {
0x00000448  push {r7, lr} 
0x0000044a  sub sp, #8 
0x0000044c  add r7, sp, #0 
0x0000044e  str r0, [r7, #4] 
   201: 
   202: 	if (hspi->Instance == SPI4)
0x00000450  ldr r3, [r7, #4] 
0x00000452  ldr r3, [r3, #0] 
0x00000454  ldr r2, [pc, #24]	; (0x470 <HAL_SPI_TxCpltCallback+40>) 
0x00000456  cmp r3, r2 
0x00000458  bne.n 0x466 <HAL_SPI_TxCpltCallback+30> 
   203: 	{
   204: 		SPI_TransferState[AMPLI_SPI4] = READY_FOR_TRANSFER;
0x0000045a  ldr r3, [pc, #24]	; (0x474 <HAL_SPI_TxCpltCallback+44>) 
0x0000045c  movs r2, #0 
0x0000045e  str r2, [r3, #0] 
   205: 		SPI_ReleaseCSPin(AMPLI_SPI4);
0x00000460  movs r0, #0 
0x00000462  bl 0x42ec <SPI_ReleaseCSPin> 
   206: 	}
   207: }

The interesting part is from row 16 on; r3 is loaded correctly with SPI_TransferState address (0x200072c4) , which is zeroed out in subsequent instrusctions; the callback works correctly.

But now I am stuck in the Rx callback which is defined like this:

void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi)
{
	if (hspi->Instance == SPI4)
	{
		SPI_TransferState[AMPLI_SPI4] = READY_FOR_TRANSFER;
		SPI_ReleaseCSPin(AMPLI_SPI4);
	}
}

In this case the assembly code is:

   218: void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi)
   219: {
0x00000478  push {r7, lr} 
0x0000047a  sub sp, #8 
0x0000047c  add r7, sp, #0 
0x0000047e  str r0, [r7, #4] 
   220: 	if (hspi->Instance == SPI4)
0x00000480  ldr r3, [r7, #4] 
0x00000482  ldr r3, [r3, #0] 
0x00000484  ldr r2, [pc, #24]	; (0x4a0 <HAL_SPI_RxCpltCallback+40>) 
0x00000486  cmp r3, r2 
0x00000488  bne.n 0x496 <HAL_SPI_RxCpltCallback+30> 
   221: 	{
   222: 		SPI_TransferState[AMPLI_SPI4] = READY_FOR_TRANSFER;
0x0000048a  bkpt 0x0011 
0x0000048c  movs r2, #0 
0x0000048e  str r2, [r3, #0] 
   223: 		SPI_ReleaseCSPin(AMPLI_SPI4);
0x00000490  movs r0, #0 
0x00000492  bl 0x42ec <SPI_ReleaseCSPin> 
   224: 	}
   225: }

In this case the function isn't working and i can guess the reason: it seems to me that r3 isn't loaded with SPI_TransferState address :(

Am I guessing right ?

How could that be ?

Suspect you need to determine why the BKPT is there, likely overlying the opcodes that should be there.

Perhaps use a different variable for Rx vs Tx callbacks to eliminate possible race/ordering issues there.

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

BKPT instruction is there because i had a software breakpoint set and so the instruction on which I wanted to break was temporarily replaced with the BKPT op code, then it is up to the debugger to execute the original code.

Anyway, as you suggested, I used different variables for Rx and Tx calls and everything now seems to be working perfectly, so thank you for your suggestion.

Now I am going to test deeply to try and find the reasons of this misbehaviour, but the important thing is that now the firmware is doing its job well.

Thank you again for your help.