Skip to main content
re.wolff9
Senior
March 22, 2016
Question

Subject: When are you allowed to change regs using |= and &= and when are you not?

  • March 22, 2016
  • 1 reply
  • 438 views
Posted on March 22, 2016 at 12:36

DEAR ST: 

Participating in your forum, helping other people is ''enjoyable'' as long as the technology does not get in the way. So if I have something to say, I want to post it. What absolutely pisses me off is that I go through the trouble of writing a reply trying to help you and your customer. I get an error message about ''no such file'' and then a link offering to help troubleshoot  windows sharepoint servics. Well.... I don't have any windows sharepoint services that need debugging. 

----------------------------------------------------------------------------------------------

The tmp = ... construct is ''dangerous''. You have to be sure that there won't be an interrupt that modifies the register and that  occurs between the tmp =... and the ... = tmp.

If an interrupt does occur, it will modify the peripheral register while the interrupted program continues to have the old value stored in the ''tmp'' variable (probably in some CPU register). The modified version based on the OLD value is written back a few instructions later. 

Two options: either disable interrupts for the operation, or KNOW that your code does not modify this register in any interrupt. 

The bad part is, that the other option is effectively the same. The CPU cannot perform the OR operation in memory so it has to load the peripheral register into a CPU-register, perform the operation and write it back. 

The annoying thing is, that IF this goes wrong, the bugs are hard to find, as they only trigger very seldomly. 

From: arnold_w

Posted: Tuesday, March 22, 2016 10:12 AM

Subject: When are you allowed to change regs using |= and &= and when are you not?

I have recently reversed-engineer some HAL source code and I see that sometimes a temporary variable is used to manipulate a register, for example

uint32_t tmp = 0;

tmp = hdma->Instance->CR;

tmp |=  hdma->Init.MemBurst | hdma->Init.PeriphBurst;

hdma->Instance->CR = tmp;

At other times, the register is changed directly, for exaple:

#define __HAL_SPI_ENABLE(__HANDLE__) ((__HANDLE__)->Instance->CR1 |=  SPI_CR1_SPE)

What is the rule here?

    This topic has been closed for replies.

    1 reply

    Tesla DeLorean
    Guru
    March 22, 2016
    Posted on March 22, 2016 at 13:22

    In the load-store model used here, all operations occur through a 'tmp' it is just less obvious. So same issue with interrupts exists. A number of registers have write specific behaviour for just this reason. Ie TIM-SR

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