2019-11-04 07:09 AM
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:
MIght it be a cache-coherency problem? I am really clueless, can somebody please help ?
Thanks in advance
Solved! Go to Solution.
2019-11-04 09:09 AM
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.
2019-11-04 07:21 AM
Variable volatile?
2019-11-04 07:24 AM
Hello,
yes the SPI4_TransferState variale is declared as "volatile uint32_t", but this doesn't help unluckily..
2019-11-04 08:10 AM
>>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
2019-11-04 08:58 AM
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 ?
2019-11-04 09:09 AM
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.
2019-11-05 05:13 AM
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.