void CAN_init(void) {
TRISB = 0b00001000; /* CANRX(RB3) is input, CANTX(RB2) is output*/
PORTB = 0b00000000;
CANCON = 0b10000000; /* Request configuration mode (CANCON<7:5> = 0b1xx) */
/* Wait until op mode is configuration mode (CANSTAT<7:5> = 0b100) */
while ((CANSTAT & 0b11100000) != 0b100) {
Nop();
}
/* Set up baud rate registers */
/* 500 Kbps @ 40MHz */
BRGCON1 = 0b01000001; /* SWJ = 2TQ BPS = 1 */
BRGCON2 = 0b10111010; /* SEG2PHTS = 1, sampled once, PS1 = 8TQ, PropagationT = 3TQ */
BRGCON3 = 0b00000111; /* Wake-up disabled, PS2 = 8Tq */
/* Receive all valid messages, double buffer enabled */
RXB0CON = 0b00000100;
RXB1CON = 0b00000000;
/* Set masks */
RXM0SIDH = 0;
RXM0SIDL = 0;
RXM0EIDH = 0;
RXM0EIDL = 0;
RXM1SIDH = 0;
RXM1SIDL = 0;
RXM1EIDH = 0;
RXM1EIDL = 0;
/* Set filters */
RXF0SIDH = 0;
RXF0SIDL = 0;
RXF0EIDH = 0;
RXF0EIDL = 0;
RXF1SIDH = 0;
RXF1SIDL = 0;
RXF1EIDH = 0;
RXF1EIDL = 0;
RXF2SIDH = 0;
RXF2SIDL = 0b00001000;
RXF2EIDH = 0;
RXF2EIDL = 0;
RXF3SIDH = 0;
RXF3SIDL = 0b00001000;
RXF3EIDH = 0;
RXF3EIDL = 0;
RXF4SIDH = 0;
RXF4SIDL = 0b00001000;
RXF4EIDH = 0;
RXF4EIDL = 0;
RXF5SIDH = 0;
RXF5SIDL = 0b00001000;
RXF5EIDH = 0;
RXF5EIDL = 0;
CANCON = 0x00; /* Request normal mode (CANCON<7:5> = 0b000) */
/* Wait until op mode is normal mode (CANSTAT<7:5> = 0b000) */
while ((CANSTAT & 0b11100000) != 0b000) {
Nop();
}
}
char CAN_read(struct _CANframe *frame) {
unsigned char RXflag, hi, lo;
RXflag = 0;
/* Check RXB0 */
if (RXB0CONbits.RXFUL) {
if (RXB0SIDLbits.EXID == 0) {
/* Standard ID */
/* SID low byte = RXBnSIDH<4:0> (high 5 bits), RXBnSIDL<7:5> (low 3 bits)
* SID high byte = 0b00000 (high 5 bits), RXBnSIDH<7:5> (low 3 bits)
*/
lo = ((RXB0SIDH & 0b00011111) << 3) | ((RXB0SIDL & 0b11100000) >> 5);
hi = (RXB0SIDH & 0b11100000) >> 5;
frame->ID = (unsigned long)MAKEWORD(lo, hi);
} else {
/* Extended ID
* EID low word = RXBnEIDH:RXBnEIDL
* EID high word:
* MSB => 0b000 (high 3 bits), RXBnSIDH<7:3> (low 5 bits)
* LSB => RXBnSIDH<2:0> (high 3 bits), RXBnSIDL<7:5> (middle 3 bits), RXBnSIDL<1:0> (low 2 bits)
*/
lo = ((RXB0SIDH & 0b00000111) << 5) | ((RXB0SIDL & 0b11100000) >> 3) | (RXB0SIDL & 0b00000011);
hi = (RXB0SIDH & 0b11111000) >> 3;
frame->ID = MAKELONG(MAKEWORD(RXB0EIDL, RXB0EIDH), MAKEWORD(lo, hi));
}
frame->length = RXB0DLC & 0b00000111;
frame->data[0] = RXB0D0;
frame->data[1] = RXB0D1;
frame->data[2] = RXB0D2;
frame->data[3] = RXB0D3;
frame->data[4] = RXB0D4;
frame->data[5] = RXB0D5;
frame->data[6] = RXB0D6;
frame->data[7] = RXB0D7;
RXB0CONbits.RXFUL = 0;
RXflag = 1;
}
/* Check RXB1 */
else if (RXB1CONbits.RXFUL) {
if (RXB1SIDLbits.EXID == 0) {
/* Standard ID */
/* SID low byte = RXBnSIDH<4:0> (high 5 bits), RXBnSIDL<7:5> (low 3 bits)
* SID high byte = 0b00000 (high 5 bits), RXBnSIDH<7:5> (low 3 bits)
*/
lo = ((RXB1SIDH & 0b00011111) << 3) | ((RXB1SIDL & 0b11100000) >> 5);
hi = (RXB1SIDH & 0b11100000) >> 5;
frame->ID = (unsigned long)MAKEWORD(lo, hi);
} else {
/* Extended ID
* EID low word = RXBnEIDH:RXBnEIDL
* EID high word:
* MSB => 0b000 (high 3 bits), RXBnSIDH<7:3> (low 5 bits)
* LSB => RXBnSIDH<2:0> (high 3 bits), RXBnSIDL<7:5> (middle 3 bits), RXBnSIDL<1:0> (low 2 bits)
*/
lo = ((RXB1SIDH & 0b00000111) << 5) | ((RXB1SIDL & 0b11100000) >> 3) | (RXB1SIDL & 0b00000011);
hi = (RXB1SIDH & 0b11111000) >> 3;
frame->ID = MAKELONG(MAKEWORD(RXB1EIDL, RXB1EIDH), MAKEWORD(lo, hi));
}
frame->length = RXB1DLC & 0b00000111;
frame->data[0] = RXB1D0;
frame->data[1] = RXB1D1;
frame->data[2] = RXB1D2;
frame->data[3] = RXB1D3;
frame->data[4] = RXB1D4;
frame->data[5] = RXB1D5;
frame->data[6] = RXB1D6;
frame->data[7] = RXB1D7;
RXB1CONbits.RXFUL = 0;
RXflag = 1;
}
if (RXflag == 1) {
RXflag = 0x00;
PIR3bits.RXB0IF = 0;
PIR3bits.RXB1IF = 0;
return 1;
} else {
return 0;
}
}