View previous topic :: View next topic |
Author |
Message |
alan
Joined: 12 Nov 2012 Posts: 357 Location: South Africa
|
Accessing only 1 byte of a SRF |
Posted: Fri Oct 11, 2013 12:02 am |
|
|
Hi All.
How do I access only one byte of a SFR in a 16 bit PIC?
Code: | #word __P1DTCON1 = getenv("SFR:P1DTCON1") //PWM1 Dead time register1
|
For example I want to update only the high byte of P1DTCON1.
For normal RAM I just use a struct and union.
Regards |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19598
|
|
Posted: Fri Oct 11, 2013 12:57 am |
|
|
Look at #BIT and #BYTE
You can just use the struct and union though. If you 'pre-declare' a variable, then #byte can be used to locate _that variable_ at a location.
The variable can be a structure, just as easily as any other variable type.
So declare the structure and union as you would for RAM, then use:
#byte variable_name = getenv("SFR:P1DTCON1") //PWM1 Dead time register1
Which will then locate the variable called 'variable_name' at the specified location.
Best Wishes |
|
|
alan
Joined: 12 Nov 2012 Posts: 357 Location: South Africa
|
|
Posted: Fri Oct 11, 2013 1:47 am |
|
|
Thanks Ttelmah,
Didn't know you could do it that way.
I started doing it as you suggested and the code are now shorter, however I still seem to misunderstand something as shown in the following code.
Code: | .................... typedef union {
.................... uint16_t WRD;
.................... struct {
.................... uint8_t High;
.................... uint8_t Low;
.................... }BTY;
.................... } __DEADTIME;
.................... __DEADTIME __DeadTimeREG;
.................... void SetDeadTimeRegA(DutyCycle) { \
.................... __DeadTimeREG.BTY.Low &= (uint8_t)(0xC0); /*Clr values*/ \
*
09B2: MOV 81A,W4
09B4: LSR W4,#8,W4
09B6: AND.B #C0,W4L
09B8: MOV.B W4L,W0L
09BA: MOV.B W0L,81B
|
Why does the compiler do a LSR and then do the AND in W4 move it W0 and then back to the byte?
I don't think you would need more than this.
Code: | #asm MOV.B __DeadTimeREG.BTY.Low,W0
AND.B 0xC0,W0
MOV.B W0,__DeadTimeREG.BTY.Low
#endasm
| Doesn't compile but hopefully you get the drift.
Probably doesn't make much difference the 2 extra instructions as it is a dsPIC33EP64FJ12MC202, but I like to understand for when I am in a jam regarding speed.
Regards |
|
|
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Fri Oct 11, 2013 6:18 am |
|
|
To avoid any overhead, define #BYTE registers
Code: | #byte __P1DTCON1L = getenv("SFR:P1DTCON1")
#byte __P1DTCON1H = getenv("SFR:P1DTCON1")+1 |
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19598
|
|
Posted: Fri Oct 11, 2013 6:34 am |
|
|
Second guessing why the assembler does things is often quite 'fun'....
As an experiment, I tried changing the union to use a two char array, instead of the separate high/low defines.
Code changes to:
Code: |
union splitter {
unsigned int16 word;
char bytes[2];
};
union splitter __using_array;
#byte __using_array = getenv("SFR:PMDOUT2") //PWM1 Dead time register1
.................... __using_array.bytes[1] &= (0xC0);
0254: MOV.B PMDOUT2.7,W0L
0256: SE W0,W0
0258: AND #C0,W0
025A: MOV.B W0L,PMDOUT2.7H
|
If however the char is changed to 'unsigned', then using this or direct #byte defines, or the named array, then it always performs the 16bit access.
It looks as if this is it's default way of accessing a 'byte' to give an empty top byte in the case of unsigned types....
Best Wishes |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19598
|
|
Posted: Fri Oct 11, 2013 12:39 pm |
|
|
FvM wrote: | To avoid any overhead, define #BYTE registers
Code: | #byte __P1DTCON1L = getenv("SFR:P1DTCON1")
#byte __P1DTCON1H = getenv("SFR:P1DTCON1")+1 |
|
Actually this does the same.....
It appears it is CCS's default way of accessing a 'byte', if it is unsigned. It uses the rotation to clear the top byte, even if the result only uses the low byte. If signed, it uses SE instead.
Best Wishes |
|
|
|