I'm playing around with an S12 micro to help me understand how to use CAN interrupts with a sleeping uP.
What I have in place is an infinite loop - while(1) - that puts the micro to sleep.
I (think I) have only enabled the CAN RXFIE - Receiver Full Interrupt Enable.
When the uP wakes up due to an inbound CAN msg, I get it to read the msg and then send a msg based on the contents of the received message.
The uP then goes to sleep again due to the loop.
Here's the problem - the msgs sent by the uP are not the ones I expected.
Upon startup it doesn't seem to always respond to my first few command msgs.
After a few msgs are sent, it then seems to lag behind my commands by 4 msgs.
Obviously I want it to respond to the command I just sent...
Does anyone know why this is the case? Have I just setup something wrong, or am I going about it the wrong way?
Thanks
解決済! 解決策の投稿を見る。
Aha. There are five hardware Rx buffers mappable to the same address CAN0RXIDRx etc. Each time you service Rx interrupt clearing RXF flag, next Rx buffer gets mapped to CPU address space. And this explains why you "receive" garbage 4 times. You need to copy Rx data to RAM in your ISR routine before clearing RXF flag. Use this data to fill Tx buffer.
CAN needs clock for operation. Without clock it is not possible to receive CAN messages. So what power saving mode are you using and what happens to oscilator when you put MCU to sleep? Oscilator needs some time to wake. It easily can make you unable to receive first message. Try using wait mode or maybe pseudostop mode. You should have no problems receiving all messages waking up from wait.
.
Thanks Edward.
I have looked through my code and can confirm I am using the asm(WAI) command to put the MCU to sleep.
Your answer seems to imply that this would be an appropriate method; is this true?
Perhaps it will help if I supply more information.
Please find a CAN trace snippet below of what I am seeing upon the initial start of the MCU:
2084.0 Rx | 010 8 FF 01 00 00 00 00 00 00 |
2085.2 Rx | 201 8 59 DF 01 01 00 77 4E DF |
2184.0 Rx | 010 8 FF 02 00 00 00 00 00 00 |
2185.1 Rx | 201 8 59 DF 02 02 00 00 03 A5 |
2284.1 Rx | 010 8 FF 03 00 00 00 00 00 00 |
2285.2 Rx | 201 8 27 DE 03 03 12 7E EF 30 |
2384.1 Rx | 010 8 FF 04 00 00 00 00 00 00 |
2385.2 Rx | 201 8 27 DE 04 04 03 5B E9 91 |
2484.2 Rx | 010 8 FF 05 00 00 00 00 00 00 |
2485.4 Rx | 201 8 FF 01 05 05 00 00 00 10 |
2584.2 Rx | 010 8 FF 06 00 00 00 00 00 00 |
2585.4 Rx | 201 8 FF 02 06 06 00 00 00 10 |
2684.2 Rx | 010 8 FF 07 00 00 00 00 00 00 |
2685.5 Rx | 201 8 FF 03 07 07 00 00 00 10 |
0x010 is my "command msg" - Bytes 0 and 1 are to be echoed back on Bytes 0 and 1 on the MCU's ack msg (0x201) - all other Bytes are set to 0x00
In Bytes 2 and 3 of the ack msg, the MCU should write its internal "wakeup counter" i.e. the number of times that it is woken up. Bytes 4, 5, 6 and 7 is the CAN ID of the msg that it just received.
This is why I am confused. The MCU clearly sends its ack msg as expected, but it's data is... corrupt?
Only after 4 cmd msgs have been sent does the MCU ack msg appear to do what I expect, but even then it seems to be 4 msgs behind according to Byte 1...
Further suggestions would be greatly appreciated.
"I have looked through my code and can confirm I am using the asm(WAI) command to put the MCU to sleep.
Your answer seems to imply that this would be an appropriate method; is this true?"
Yes, I'm using WAI and no messages are lost.
It looks like some weird software issue. Isn't it some Rx queue which you forgot to clear at initialization?
Ok...
I wasn't aware that I would have to flush the buffers.
I haven't seen anything explicitly mentioned in the documentation.
Do you or anyone else know have suggestions how to do this?
I mean software fifo buffer, not hardware buffers. Hardware receive buffers are properly emptied on chip reset.
Is this FIFO buffer implicitly created?
I ask because I haven't set anything up.
All I have done is to read the CAN0RXDSR1 byte directly and piped this to the ack msg mentioned above.
Could you show your code? If not your own software FIFO, then something else is wrong. It is not hardware issue (unless you have very odd CAN logger).
Sure
/* loop forever */
while(1) {
asm (WAI);
counter++;
/* Formats Standard CAN ID */
canID.b.b0 = CAN0RXIDR0;
canID.b.b1 = CAN0RXIDR1;
canID.b.b2 = CAN0RXIDR2;
canID.b.b3 = CAN0RXIDR3;
canID.d >>= 21;
/* Data values */
data.b[0] = CAN0RXDSR0;
data.b[1] = CAN0RXDSR1;
data.b[2] = counter;
data.b[3] = counter;
data.d[1] = canID.d;
/* Send CAN msg */
(void)SendFrameExt(0x201,0,8,data.b);
}
Like I said, the main loop itself doesn't do much at all - just sends a msg.
Other low level initialisation has been done using an auto-code generator - CodeWarrior's Device Init
I am using a PCAN logger to record/view my trace.
Any ideas?
Aha. There are five hardware Rx buffers mappable to the same address CAN0RXIDRx etc. Each time you service Rx interrupt clearing RXF flag, next Rx buffer gets mapped to CPU address space. And this explains why you "receive" garbage 4 times. You need to copy Rx data to RAM in your ISR routine before clearing RXF flag. Use this data to fill Tx buffer.
Brilliant! :smileyhappy:
That works. I didn't know this was the case.
Thank you Edward.