Unable to Update register using bitfield structure

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Unable to Update register using bitfield structure

1,010 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by mathseng on Thu Sep 18 23:31:13 MST 2014
Hi,
Can anyone advise me why I do not seem to be able to update registers using bitfield structs.

Specifically, when updating the PCLKSEL1 register, when using a bitfield struct, writing to one bitfield results in other fields being incorrectly updated. My example is updating PCLK_TIMER2, which is 2 bits at 13:12.


I have attached a source file which can be used to demonstrate the issue.
Below are snippets

Regards,
Mathseng

<code>
//Using the format to update TIMER2 with <anyPCLK value, eg PCLK1 ( divide by 1 clock)>, and then extract the PCLK value ALWAYS works
LPC_SC->PCLKSEL1 &= ~((0b11 << 12) | ((0b11 << 8) | (0b11 << 24))); // desired bitfield at 13:12 and reserved bitfields at 9:8, 25:24.
LPC_SC->PCLKSEL1 &= ~(0b11 << 12); // desired bitfield at 13:12, ignoring reserved bitfields at 9:8, 25:24.
LPC_SC->PCLKSEL1 |= (PCLK1 << 12);
PCLK_type pclk = ((LPC_SC->PCLKSEL1) & (0b11 << 12)) >> 12;

//Using a bitfield struct to read the register always works, but updating the register results in other fields being corrupted.
volatile PCLKSEL1_Type * pClkSel = (PCLKSEL1_Type*)&(LPC_SC->PCLKSEL1);
pClkSel->PCLK_TIMER2 = PCLK1;// FAILS with other register field values being corrupted
PCLK_type pValu = pClkSel->PCLK_TIMER2;// Always works

//Using the same bitfield struct to operate on a memory variable ALWAYS works correctly:
volatile uint32_t memVar = 0;
volatile PCLKSEL1_Type * pMemVar = (PCLKSEL1_Type*)&memVar ;
pMemVar ->PCLK_TIMER2 = PCLK1;// Always works
PCLK_type memClk = pMemVar ->PCLK_TIMER2;// Always works
</code>

Original Attachment has been moved to: WriteRegFail.c.zip

Labels (1)
0 Kudos
Reply
5 Replies

957 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by lpcxpresso-support on Fri Sep 19 01:33:33 MST 2014
You should not use bitfields on hardware registers, as hardware registers do not behave the same way as RAM when accessed as byte/half-word/word. This is why all LPCOpen and every example uses bit manipulation and not bitfields.
0 Kudos
Reply

956 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by mathseng on Fri Sep 19 01:16:35 MST 2014
I looked at the size of the code generated, but not explicitly the instructions. The code generated by the bitfield is shorter, and more importantly for me, easier to write/maintain because the code reads in 'user speak', not in magic numbers.

I am just now looking at a post on www.embeddedrelated.com  (Using Bit Field structures to access LPC-2000 registers)  at http://www.embeddedrelated.com/groups/lpc2000/show/40838.php

This series of posts note that bitfield writing using GCC appears to be bytewide, which is consistent with the pattern of data I am seeing.
With an original register value of 0x00, writing a 0x01 to 13:12 causes replication of the data every byte. I got bogged down by writing data to other registers, and I could not see the pattern.

Writing pattern -1 (all 1's) to the register results in one reserved register being set to 0b00, the other to 0b11. No observed anomalies resulted.

Update:
Code generated by bitfield write is definitely BYTE, hence the reason observed issues.
<code>
pSelS->PCLK_TIMER2 = PCLK1;
504:7843      ldrbr3, [r0, #1]
506:f023 0330 bic.wr3, r3, #48; 0x30
50a:f043 0310 orr.wr3, r3, #16
50e:7043      strbr3, [r0, #1]
</code>
0 Kudos
Reply

956 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by TheFallGuy on Fri Sep 19 00:17:31 MST 2014
So, what doe you mean by 'doesn't work? Have you looked at the code generated by the compiler to see what it is doing? And compared it with the working version?
0 Kudos
Reply

957 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by mathseng on Fri Sep 19 00:15:43 MST 2014
I don't believe so.

reg |= value   is read/modifywrite, and that works.

Also, looking at the data in the struct for the reserved fields, they are both 0 (zero), so writing 0 should not be an issue.

0 Kudos
Reply

957 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by TheFallGuy on Fri Sep 19 00:05:14 MST 2014
Just a guess. Bitfields work by doing a read-modify-write. So reserved bits are going to be read and then written -  possibly illegally. This is why most embedded libraries do not use bitfields. Could this explain what you are seeing?
0 Kudos
Reply