cancel
Showing results for 
Search instead for 
Did you mean: 

ATOMIC_SET_BIT() stopping code execution

cbcooper
Associate II

A similar problem to this post but not quite the same:

I've got my own low-level LPUART transmission code, it works like this:

1) Initialize LPUART in FIFO mode with thresholds at 1/2 full

2) When a buffer needs to be sent, write bytes to TDR until all bytes sent or transmit FIFO is full

3) If transmit FIFO is full, enable USART_CR3_TXFTIE and let the ISR handle the rest.

4) When the ISR has written all the bytes to the FIFO, it disables USART_CR3_TXFTIE

What I see is this:

1) Send first packet.  It's 10 bytes long, the first byte gets moved immediately to the TX shift register and 8 bytes fill up the FIFO so there's 1 byte left.  The interrupt is enabled, the ISR fires, the last byte is written to the FIFO, the interrupt is disabled.

2) Send second packet.  It's 7 bytes long so fits completely in the FIFO and the interrupt is left disabled

3) Send third packet.  It's 71 bytes long, the first byte gets moved immediately to the TX shift register and 8 bytes fill up the FIFO so there are 62 bytes left.  It calls 

ATOMIC_SET_BIT(pUART->CR3, USART_CR3_TXFTIE)

to enable the interrupt, and the interrupt never comes.  I finally noticed that when I hit the "Suspend" button in the debugger, it shows that the current code location is that call to ATOMIC_SET_BIT() so that call never completed.

If I replace that call with a simple 

pUART->CR3 |= USART_CR3_TXFTIE;

everything works as it should.

In the post I linked at the top, the problem was that he had interrupts every few microseconds, I am running the ADC at top speed (in the ADC1_2_IRQHandler I'm reading the value and then immediately setting ADC_CR_ADSTART) so it's possible I also have that many interrupts (I haven't dug into it deeply enough to determine the exact timing) but the solution given for the previous post was "if an interrupt is called between these, the STREX fails and it has to go do the LDREX again" and that leaves some lingering questions.

1) I've got my ADC running the whole time, so why does ATOMIC_SET_BIT() work the first time through?  Shouldn't this problem affect every call to ATOMIC_SET_BIT(), not just some?

2) Let's say my situation is similar to the previous post and the CPU is spending 66% of its time servicing the ADC interrupt. From the time the code calls ATOMIC_SET_BIT() until I press the "Suspend" button in the debugger is several seconds, which means the CPU has had literally millions of chances to do LDREX/STREX.  It doesn't seem plausible that every single one of those LDREX/STREX pairs fails.

3) Is there any benefit, in this situation, to calling ATOMIC_SET_BIT() instead of just setting the bit directly?  I'm assuming the reason to call ATOMIC_SET_BIT() is to prevent other processes from jumping in and modifying CR3 between my code loading it, modifying it, and storing it back, but in this case nobody else should be touching CR3.

1 ACCEPTED SOLUTION

Accepted Solutions
TDK
Super User

FWIW, I think your problem is exactly the same as the linked thread.

If the chip is executing code but is stuck on ATOMIC_SET_BIT, there are only two possibilities:

  • LDREX/STREX fails to complete due to interrupt storm.
  • LDREX/STREX fail to even get ran due to interrupt storm.

This is further reinforced by the code succeeding when you replace it with a simple bit set. So actually only the first case is a possibility.

 

There are explanations for (1) and (2). I don't see those ruling out the above cases.

For (3) above, the benefit to ATOMIC_SET_BIT is only when CR3 is being modified by multiple threads. For UART, this can happen if TX and RX are handled separately.

If you feel a post has answered your question, please click "Accept as Solution".

View solution in original post

2 REPLIES 2
Saket_Om
ST Employee

Hello @cbcooper 

Please refer to the post below:

Solved: ATOMIC_SET_BIT() stopping code execution - STMicroelectronics Community

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.
Saket_Om
TDK
Super User

FWIW, I think your problem is exactly the same as the linked thread.

If the chip is executing code but is stuck on ATOMIC_SET_BIT, there are only two possibilities:

  • LDREX/STREX fails to complete due to interrupt storm.
  • LDREX/STREX fail to even get ran due to interrupt storm.

This is further reinforced by the code succeeding when you replace it with a simple bit set. So actually only the first case is a possibility.

 

There are explanations for (1) and (2). I don't see those ruling out the above cases.

For (3) above, the benefit to ATOMIC_SET_BIT is only when CR3 is being modified by multiple threads. For UART, this can happen if TX and RX are handled separately.

If you feel a post has answered your question, please click "Accept as Solution".