AnsweredAssumed Answered

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

Question asked by wolff.roger on Mar 22, 2016
Latest reply on Mar 22, 2016 by Clive One
 
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?

Outcomes