|
|
View previous topic :: View next topic |
Author |
Message |
Guest
|
Problem with struct fields with pointers |
Posted: Thu Jun 19, 2008 2:13 pm |
|
|
I am trying to write a driver for the CAN module for the dsPic30F6012A (because there is no support for it that I am aware of). I am using PCD version 4.068.
I have unions/structs defined for the registers of the CAN module like this:
Code: | typedef union {
struct {
int1 void0:1;//bit0 read as 0
int ICODE:3;//Interrupt Flag code bits
int void4:1;//bit4 read as 0
int OPMODE:3;//Operation mode bits
int REQOP:3;//Request operation mode
int CANCKS:1;//CAN Master Clock select
int ABAT:1;//Abort all pending transmissions bit
int CSIDL:1;//Stop in idle mode bit
int void14:1;
int CANCAP:1;//CAN message receive capture enable bit
} ;
int16 Word;
}CiCTRL;
CiCTRL C1CTRL;
#word C1CTRL = 0x0390 |
I then try to access the register via a pointer as follows for example...
Code: | CiCTRL * ctrl;
ctrl = &C1CTRL;
ctrl->CANCAP = 1; |
This does not work. trying to modify CANCAP by using C1CTRL.CANCAP = 1 works just fine.
Looking at the assembled code from the list file, it is obvious that it will not work.
Code: | .................... ctrl->CANCAP = 1;
004F2: MOV #1,W0
004F4: ADD 8CE,W0 //8CE is the address of the pointer 'ctrl' I think
004F6: MOV W0,W5
004F8: MOV #FFFF,W0
004FA: AND 57
004FC: SL W5,#E,W0
004FE: AND #3FF,W0
00500: IOR 57 |
nowhere in that assembled code does it even try to do any form of indirect addressing, which would be necessary to modify data from a pointer.
It should be able to just do something like this:
Code: | MOV 8CE,W0
BSET [W0],#F |
if I try to access a different field, perhaps one that is not just one bit:
Code: | int16 op;
op = 2;
ctrl->REQOP = op; |
Code: | .................... ctrl->REQOP = op;
00582: MOV #1,W0
00584: ADD 8CE,W0 //Add 1 to ctrl pointer, OK, now at upper byte of C1CTRL word
00586: MOV W0,W5
00588: MOV #FFF8,W0 //OK, clears the 3 bits associated with REQOP
0058A: AND.B W0L,[W5],[W5] //preparing to write in the new value...
0058C: MOV.B 8D0,W0L //move 'op' to W0L
0058E: AND.B #F8,W0L //clears the 3 bits I need for REQOP?? this should be AND.B #07,W0L
00590: IOR.B W0L, [W5],[W5] |
The problem with this is that it ands the 'op' value with #F8, when it should be ANDing it with the inverse of #F8 (Actually even if it did, that this code would still not functionally work because of the nature of this control register, but that is besides the point).
If I try to change REQOP directly by doing
ctrl->REQOP = 2;
that works fine.
Also doing ctrl->CANCAP vs. (*ctrl).CANCAP makes no difference
One more example: (*ctrl).Word |= 0x8000;
Code: | .................... (*ctrl).Word |=0x8000;
0054C: MOV 8CE,W0 //put pointer address in W0
0054E: MOV W0,W5 //move W0 to W5...?
00550: ADD W5,#0,W5 //add 0 to W5....??
00552: MOV W5,W6 //.....move W5 to W6......?
00554: MOV #8000,W0 //OK, put 0x8000 in W0
00556: IOR W0, [W6],W0 //OR 0x8000 with [W6] this is good...
00558: SUB.B W6L,#2,W6L //subtract 2 from my pointer address....why?
0055A: MOV.B W6L,[W6] //put the low byte of the pointer address in the pointer location???
0055C: MOV.B #0,W0L //put 0 in W0L
0055E: MOV.B W0L,[W6+#0]//put W0L (0) in [W6]?? what? |
I have stepped through with the debugger while observing the RAM and this definitely does not work.
Has anyone else had any problems using pointers with structs/unions?
Is this actually a compiler problem or am I just doing something stupid? |
|
|
Ttelmah Guest
|
|
Posted: Thu Jun 19, 2008 3:11 pm |
|
|
What happens if you simplify the declarations without using typedef?. I have had problems at times with typedef, and pointers, and feel it is safer to run without it, especially for pointer operations. So:
Code: |
union Cictrl {
struct {
int void0:1;//bit0 read as 0
int ICODE:3;//Interrupt Flag code bits
int void4:1;//bit4 read as 0
int OPMODE:3;//Operation mode bits
int REQOP:3;//Request operation mode
int CANCKS:1;//CAN Master Clock select
int ABAT:1;//Abort all pending transmissions bit
int CSIDL:1;//Stop in idle mode bit
int void14:1;
int CANCAP:1;//CAN message receive capture enable bit
};
int16 Word;
}C1CTRL;
//As a comment, use _either_ int1, or a bit field, not both
union Cictrl C1CTRL;
#word C1CTRL = 0x0390
union Cictrl *ctrl;
ctrl = &C1CTRL;
ctrl->fields.CANCAP = 1;
|
I'd quite expect it to be a compiler problem.
Does it change if you use *, rather than -> to access the element?.
So:
(*ctrl).CANCAP=1;
Even on the more mature versions of the compiler, operations wit pointers and typedef, sometimes go completely potty, s I'm not at all surprised f the 'D' version is even worse here.... :-(
Try giving the structure a name. The 'anonymous' form you are using, is a relatively recent addition to the compiler's (supposed) abilities, and I'd not be surprised if this caused problems. So:
Code: |
typedef union {
struct {
int void0:1;//bit0 read as 0
int ICODE:3;//Interrupt Flag code bits
int void4:1;//bit4 read as 0
int OPMODE:3;//Operation mode bits
int REQOP:3;//Request operation mode
int CANCKS:1;//CAN Master Clock select
int ABAT:1;//Abort all pending transmissions bit
int CSIDL:1;//Stop in idle mode bit
int void14:1;
int CANCAP:1;//CAN message receive capture enable bit
} fields;
int16 Word;
}CiCTRL;
CiCTRL C1CTRL;
#word C1CTRL = 0x0390
CiCTRL * ctrl;
ctrl = &C1CTRL;
ctrl->fields.CANCAP = 1;
|
You may well find this forces the compiler to understand what is wanted.
Best Wishes |
|
|
kemp05jeff
Joined: 19 Jun 2008 Posts: 1
|
|
Posted: Thu Jun 19, 2008 3:28 pm |
|
|
Thanks for your reply,
I have tried this:
Code: | union CiCTRL{
struct {
int1 void0:1;//bit0 read as 0
int ICODE:3;//Interrupt Flag code bits
int void4:1;//bit4 read as 0
int OPMODE:3;//Operation mode bits
int REQOP:3;//Request operation mode
int CANCKS:1;//CAN Master Clock select
int ABAT:1;//Abort all pending transmissions bit
int CSIDL:1;//Stop in idle mode bit
int void14:1;
int CANCAP:1;//CAN message receive capture enable bit
}Fields ;
int16 Word;
};
union CiCTRL C1CTRL;
#word C1CTRL = 0x0390
............
union CiCTRL *ctrl
........
ctrl->Fields.CANCAP = 1; |
this generates:
Code: | .................... ctrl->Fields.CANCAP = 1;
0049A: MOV #1,W0
0049C: ADD 8CE,W0
0049E: MOV W0,W5
004A0: MOV #FFFF,W0
004A2: AND 57
004A4: SL W5,#E,W0
004A6: AND #3FF,W0
004A8: IOR 57 |
which Is exactly the same as before.
Here is (*ctrl).Fields.CANCAP = 1:
Code: | .................... (*ctrl).Fields.CANCAP = 1;
004CA: MOV 8CE,W0
004CC: MOV W0,W5
004CE: ADD W5,#1,W5
004D0: MOV W5,W6
004D2: MOV #FFFF,W0
004D4: AND 77
004D6: SL W6,#E,W0
004D8: AND #3FF,W0
004DA: IOR 77 |
It is slightly different, but just as wrong... |
|
|
Ttelmah Guest
|
|
Posted: Fri Jun 20, 2008 2:02 am |
|
|
You still have the int1 and field width definitions, used together, which is not really 'legal'. However I doubt if this is the problem.
You need to make an error report to CCS.
Best Wishes |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|