I'm writing a CAN transmit function and I'm having problems with the wrong data being transmitted onto the bus. The data that is transmitted on to the bus (and received when in loopback mode) is not what I am writing into the IDR0..3, DSR0..7, and DLR registers. I can scope the tx line and see the data transmitted is, indeed, what is being received in loopback mode: the wrong data.
I'm using Codewarrior V6.2 and the DEMOJM board. The tx function follows:
void CAN_send_bytes(N_AI_t N_AI, N_data_t* data, signed int len) { char *dataptr; volatile char temp0, temp1, temp2, temp3; DisableInterrupts; //standard (11-bit) addressing only temp0 = (char)( N_AI.CANID >> 3 ); temp1 = (char)( N_AI.CANID << 5 ); temp1 &= ~0x10;// CANRIDR1_IDE = 0; if(N_AI.RTR) temp1 |= 0x08; else temp1 &= ~0x08; temp2 = 0; temp3 = 0; CANRIDR0 = temp0; CANRIDR1 = temp1; CANRIDR2 = temp2; CANRIDR3 = temp3; CANRDLR = 8;//(char)len + 1; //data + 1 N_PCI byte temp0 = (char)(len & 0x0F); CANRDSR0 = temp0; dataptr = (char*)&CANRDSR1; while(len--) { *dataptr = *data; ++dataptr; ++data; } do { CANTBSEL = CANTFLG; }while(!CANTBSEL); //select available transmit register. keep looping until one is available. CANTFLG = CANTBSEL; EnableInterrupts; }
I think that I'm using the process stated in the Functional Description and Programmer's Model sections of the data sheet. Any ideas on where I'm going wrong?
This should be done before accessing TX message buffer, not after:
do
{
CANTBSEL = CANTFLG;
}while(!CANTBSEL); //select available transmit register.
CANTBSEL is used to map one of 3 TX buffers to the memory map. So you should first set up CANTBSEL, fill TX buffer (DSRx, IDRx, DLC registers), then clear TX flag like you do CANTFLG=CANTBSEL.
No luck with that last effort. I simplified the function to just write constants to the CANRIDRx and CANRDSRx registers as follows:
void CAN_send_bytes(N_AI_t N_AI, N_data_t* data, signed int len){ char *dataptr; volatile char temp0, temp1, temp2, temp3; do { CANTBSEL = CANTFLG; }while(!CANTBSEL); //select available transmit register. keep looping until one is available. CANRIDR0 = 0x55; CANRIDR1 = 0x55; CANRIDR2 = 0x55; CANRIDR3 = 0x55; CANRDSR0 = 0xAA; CANRDSR1 = 0xAA; CANRDSR2 = 0xAA; CANRDSR3 = 0xAA; CANRDSR4 = 0xAA; CANRDSR5 = 0xAA; CANRDSR6 = 0xAA; CANRDSR7 = 0xAA; CANRDLR = 8; CANTFLG = CANTBSEL;}
The frame that is received in loopback mode has CANRIDR0 = 0x92 and CANRIDR1 = 0xF0, CANRDSR0 = 0x69 and CANRDSR1 = 0x4D. CANRDLR is always 12 (0xC). Other registers are random.
Any other suggestions? I'm running out of ideas as to what I could be doing wrong and how to debug this.
Don't know why IDR0 and DLC differ, but please don't compare DSR. You are sending 11bit-ID message with RTR set, so no data is sent.
Do you read all messages from receive queue? Is RXF=0 before you send your message, and RXF=1 after?
Understood on not comparing DSR, as the (corrupt) received data indicates it isn't a a data frame.
I am receiving the frame using the CANrx interrupt, so the flag must be getting set by the CAN module. Just to double-check, I checked the RXF before the CANTFLG=CANTBSEL; line and the flag is cleared. There is only one frame in the receive FIFO for each frame I attempt to send.
Just for reference, the frame I am trying to send (at least prior to the last post) has the ID = 0x7DF, IDE=0, and RTR=0 and DLR = 8.
Thanks, by the way, for the help.