Hi everyone,
I'm using a MSP430F6659 rev A
I have defined my peripherals registers as structures with bitfields, then linked them at the correct place. It mostly works well.
/* Timer TAx Registers Type */ typedef struct { /* TAxCTL */ union { struct { G_UWord_t Taifg_UW_1Bit :1; /* Timer A counter interrupt flag */ G_UWord_t Taie_UW_1Bit :1; /* Timer A counter interrupt enable */ G_UWord_t Taclr_UW_1Bit :1; /* Timer A counter clear */ G_UWord_t Reserved_3_UW_1Bit :1; /* Reserved_3 */ G_UWord_t Mc_UW_2Bit :2; /* Timer A mode control */ G_UWord_t Id_UW_2Bit :2; /* Timer A clock input divider */ G_UWord_t Tassel_UW_2Bit :2; /* Timer A clock source select */ G_UWord_t Reserved_10_15_UW_6Bit :6; /* Reserved_10_15 */ } Bits; G_UWord_t Value; } Taxctl_U; /* TAxCTL */
etc. for other register words of the structure.
But as I tried to write into 2 bits of TimerA0 register, I found the microcontroller writing it one byte lower than I expected.
The c line of code is the following:
McuTimerA_G_TimerA0Regs_S.Taxctl_U.Bits.Tassel_UW_2Bit = 0b10;
It was translated by the compiler as the following assembly code, which seems right
;---------------------------------------------------------------------- ; 338 | McuTimerA_G_TimerA0Regs_S.Taxctl_U.Bits.Tassel_UW_2Bit = 0b10; // SMCLK ;---------------------------------------------------------------------- MOV.W #252,r15 ; [] |338| AND.B &McuTimerA_G_TimerA0Regs_S+1,r15 ; [] |338| OR.B #2,r15 ; [] |338| MOV.B r15,&McuTimerA_G_TimerA0Regs_S+1 ; [] |338|
After some masking of the register, it corresponds to moving my '2' value to the 2nd byte of the structure at address 0x340 with a MOV.B r15,&0x341, which looks right (and rules out placement / alignment issues, as 0x341 is where I want to write my bits)
Except when I execute this assembly instruction with the memory at 0x340 previously = 0x0000, I end up with: 0x0002 instead of 0x0200.
In other words, the MOV.B r15, 0x341 seems to have executed MOV.B r15, 0x340
I find that very strange, as it seems a byte operation can be executed on an odd address (and if not, why would the compiler generate this instruction ?)
The read of the memory is done with the Lauterbach sensor tool, which shows me expected values in all registers, and when the instruction MOV.B r15, 0x341 is executed, an interrupt is trigged afterwards which corresponds to having writen the Interrupt flag bit (bit 1 of 0x340) in the timerA register.
If i do the write operation by a 16bit overwriting of all the CTL register, the result is fine and i don't have any interrupt.
So i'm pretty sure the memory is really modified at address 0x340 and not 0x341, even if I were not to trust my toolchain, or to suspect an endianess interpretation problem.
I have looked into the compiler options to see if I had somehow messed up some alignement option, thus forbidding such odd address write, but i didn't find anything of the sort, and the code is produced by the compiler...
I have no idea of how that can be happening except for a sillicon bug, so any help would be appreciated.