volatile PMBox pTxMB= (PMBox)&(g_pCanReg->MB[TX_MB_num]);
while (1) {
dwTxDLC = (dwTxDlen << CAN_CS_DLC_SHIFT);
pTxMB->CS |= CAN_CS_CODE(CAN_TX_MSG_BUFFER_NOT_ACTIVE);
pTxMB->WORD0 = dwData0++;
pTxMB->WORD1 = htonl(dwData1++);
pTxMB->CS |= (CAN_CS_CODE(CAN_MESSAGE_TRANSMIT_ONCE) | dwTxDLC);
dwRTRBit = pTxMB->CS; // check for RTR bit
if ((dwRTRBit & CAN_CS_RTR_MASK) == CAN_CS_RTR_MASK) {
iRTRNotSetCount++;
}
else if ((dwRTRBit & CAN_CS_CODE(CAN_TX_MSG_BUFFER_NOT_ACTIVE))== CAN_CS_CODE(CAN_TX_MSG_BUFFER_NOT_ACTIVE)) {
//Version 1
g_pCanReg->MB[TX_MB_num].CS &= ~(CAN_CS_CODE_MASK);
g_pCanReg->MB[TX_MB_num].CS |= (CAN_CS_CODE(CAN_MESSAGE_TRANSMIT_RESPONED) | dwTxDLC);
//Version 2
//pTxMB->CS &= ~(CAN_CS_CODE_MASK); // Reset the code
//pTxMB->CS |= (CAN_CS_CODE(CAN_MESSAGE_TRANSMIT_RESPONED) | dwTxDLC);
//Version 3
//pTxMB->CS = pTxMB->CS & ~(CAN_CS_CODE_MASK); // Reset the code
//pTxMB->CS = pTxMB->CS | (CAN_CS_CODE(CAN_MESSAGE_TRANSMIT_RESPONED) | dwTxDLC);
iRTRSetCount++;
}
// other code omitted ....
} //endof while
I tried three versions code as above. But only //version 1 works. I don't know why version2 and version 3 behave differently as version 1.
Thank you,
David Zhou
Hello David,
Sorry i misunderstand it .
And when you define the structure of "PMBox", have you use the "volatile" ?
If not, please try use it . Do you use CodeWarrior IDE?
BR
Alice
Hello David,
About this "volatile PMBox pTxMB= (PMBox)&(g_pCanReg->MB[TX_MB_num]);"
do you want to forced the "(g_pCanReg->MB[TX_MB_num])" into "PMBox" ? If yes, here is not
need "&" , i think the right way is
volatile PMBox pTxMB= (PMBox)(g_pCanReg->MB[TX_MB_num]);
Hope it helps
Alice
Hi Alice,
Sorry for not making clear with PMBox. It is a pointer to the MB struct. I want to force it to the fixed index of MB[16] array. The pointer assignment to the member of MB array is correct.
volatile PMBox pTxMB= (PMBox)&(g_pCanReg->MB[TX_MB_num]);
(without & operator, compilation error).
In the Read Thread, I had pRxMB replaced g_pCanReg->MB[RX_MB_num]. It works.
But in the Write Thread, all pTxMB pointer replaces all g_pCanReg->MB[TX_MB_num].
except:
g_pCanReg->MB[TX_MB_num].CS &= ~(CAN_CS_CODE_MASK);
g_pCanReg->MB[TX_MB_num].CS |= (CAN_CS_CODE(CAN_MESSAGE_TRANSMIT_RESPONED) | dwTxDLC);
If the above two lines are replaced with pMBox pointer, it has weird behavior.
Thank you,
David
Hi Alice,
I think the pTxMBox pointer is optimized by the compiler.
I added a line just before the pointer usage:
volatile PMBox pTxMBx=(PMBox)&g_pCanReg->MB[TX_MB_num];
pTxMBx->CS &= ~(CAN_CS_CODE_MASK);
pTxMBx->CS |= (CAN_CS_CODE(CAN_MESSAGE_TRANSMIT_RESPONED) | dwTxDLC);
That works.
But the question is why the compiler optimized out a volatile pointer?
how to prevent from being optimized out?
Thank you,
David
Hello David
The pointers to volatile variables are very common, especially with memory-mapped I/O registers.
When you define a pointer using volatile keyword like below, the pointer itself is not volatile, but the object it points to (in your case, g_pCanReg->MB[TX_MB_num]) is volatile. So the compiler may optimize on your pointer.
volatile PMBox pTxMBx=(PMBox)&g_pCanReg->MB[TX_MB_num];
If you want to define a volatile pointer, it should be:
PMBox volatile pTxMBx=(PMBox)&g_pCanReg->MB[TX_MB_num];
However, volatile pointers to non-volatile data are rare in common use.
For details, please refer to this link:
http://www.barrgroup.com/Embedded-Systems/How-To/C-Volatile-Keyword
Best Regards
Fiona Kuang
Technical Information & Commercial Support
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------
Hi Fiona & Alice,
This is a weird problem, I added volatile to many places, it still doesn't work. Let me explain here:
The Can Mem Map structure is redefined as:
typedef struct {
volatile uint32_t CS;
volatile uint32_t ID;
volatile uint32_t WORD0;
volatile uint32_t WORD1;
} MBox, *PMBox;
typedef struct CanMemMap {
uint32_t MCR;
//omitted...
volatile MBox MB[16];
uint8_t RESERVED_3[1792];
uint32_t RXIMR[16];
} volatile *CanMemMapPtr;
//for CanReadTask: -I replaced MB[index] with a pointer. It works OK.
void CanRead_Task(uint32_t param) {
PMBox pMB= (PMBox)&(g_pCanReg->MB[RX_MB_num]); //not even use volatile
while (1) {
if (_lwevent_wait_ticks(&lwEvent, 1 << RX_MB_num, FALSE, 0) != MQX_OK) {
pMB->CS;
dwID = -1;
dwDLen = pMB->CS & CAN_CS_DLC_MASK;
dwDLC = dwDLen >> CAN_CS_DLC_SHIFT;
if (dwFormat == FLEXCAN_STANDARD) {
dwID = ((pMB->ID & CAN_ID_STD_MASK) >> CAN_ID_STD_SHIFT);
bCode = (uint8_t) (pMB->CS >> CAN_CS_CODE_SHIFT);
if (bCode == CAN_RX_MSG_BUFFER_FULL) {
dwData0 = pMB->WORD0 ;
dwData1 = pMB->WORD1 ;
}
pMB->WORD0 = 0;
pMB->WORD1 = 0;
pMB->CS &= ~(CAN_CS_CODE_MASK);
pMB->CS |= (CAN_CS_CODE(CAN_RX_MSG_BUFFER_EMPTY) | dwDLen);
g_pCanReg->TIMER; //FLEXCAN_Unlock_mailbox(CAN_DEVICE);
FLEXCAN_Request_message(CAN_DEVICE, RX_remote_MB_num, dwFormat);
_time_delay(1);
}
}
//for CanTxTask -
void CanWrite_Task(uint32_t param) {
volatile PMBox volatile pTxMB= (PMBox)&(g_pCanReg->MB[TX_MB_num]);
while (1) {
dwTxDLC = (dwTxDlen << CAN_CS_DLC_SHIFT);
pTxMB->CS |= CAN_CS_CODE(CAN_TX_MSG_BUFFER_NOT_ACTIVE);
pTxMB->WORD0 = g_aCanTxBuf[bCanTxBufTail].WORD0;
pTxMB->WORD1 = g_aCanTxBuf[bCanTxBufTail].WORD1;
pTxMB->CS |= (CAN_CS_CODE(CAN_MESSAGE_TRANSMIT_ONCE) | dwTxDLC);
dwRTRBit = pTxMB->CS; // check for RTR bit
if ((dwRTRBit & CAN_CS_CODE(CAN_TX_MSG_BUFFER_NOT_ACTIVE))==
CAN_CS_CODE(CAN_TX_MSG_BUFFER_NOT_ACTIVE)) {
//volatile PMBox pTxMBx= (PMBox)&(g_pCanReg->MB[TX_MB_num]);
pTxMB->CS &= ~(CAN_CS_CODE_MASK); //LineA
pTxMB->CS |= (CAN_CS_CODE(CAN_MESSAGE_TRANSMIT_RESPONED) | dwTxDLC);//LineB
//g_pCanReg->MB[TX_MB_num].CS &= ~(CAN_CS_CODE_MASK);//LineC
//g_pCanReg->MB[TX_MB_num].CS |= (CAN_CS_CODE(CAN_MESSAGE_TRANSMIT_RESPONED) | dwTxDLC);//LineD
_time_delay(1);
}
}
Note: (both tasks are based on FlexCan/test.c in the example folder. some code is omitted for clearness.)
If pTxMBx is defined, and LineA and LineB are pTxMBx->, then it transmits CAN messages. (OK)
if use LineC, and LineD to replace LineA and LineB, it also works.
I checked pTxMB address, it points to the right memory. It never changes. But only LineA and LineB can not use pTxMB pointer. Otherwise, it doesn't transmit CAN messages. (or may have one message transmitted).
Thank you,
David