Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

How set buffers to receive 4 different CAN frames? PIC18F46K80

Status
Not open for further replies.

Triode

Well-Known Member
I'm using a PIC18F46K80. I have some inherited code that I need to add two CAN frames to by the end of the week. I do intend to gain a solid understanding of the ECAN module, but I'm reading the datasheet and given the time limit I think it's too complex to figure out that quickly.

Currently it reads 2 frames, and since there are 2 buffers it has one receive filter on each buffer. On the datasheet under settings for the "RECEIVE FILTER BUFFER CONTROL REGISTER" it lists more buffers. But due to naming I am wary that they may not be what I hope they are, are B0 and B1 aditional full buffers, or something else?

Code:
0000 = Filter n is associated with
RXB0 0001 = Filter n is associated with
RXB1 0010 = Filter n is associated with
B0 0011 = Filter n is associated with B1
...

These settings seem to imply there are more buffers - but some of the diagrams only list RXB0 and RXB1. I could be totally on the wrong track here, maybe I don't need more buffers to read more CAN messages.

Here is the code that sets up the buffers, the first block below is just for completeness, the second has the filter settings that I think need to be fixed.

Code:
void CAN_Init()
{
    // Enter CAN module into config mode
    CANCON = 0x80;
    while(!(CANCON & 0x80));

    // Enter CAN module into Mode 1
    ECANCON = 0x40;

    //  500 Kbps @ 8MHz
    BRGCON1 = 0x00; //0000 0000
    BRGCON2 = 0x91; //1001 0001
    BRGCON3 = 0x01; //0000 0001

    // Setup Programmable buffers (all receive buffers, unused)
    BSEL0 = 0x00;

    // Initialize Receive Masks
    //  The first mask is used that accepts all SIDs and no EIDs
    //  The second mask is used to ignore all SIDs and EIDs
    RXM0EIDH = 0x00;    // 0's for EID and 1's for SID
    RXM0EIDL = 0x00;
    RXM0SIDH = 0xFF;
    RXM0SIDL = 0xFF;

    RXM1EIDH = 0x00;    // 0's for EID and SID
    RXM1EIDL = 0x00;
    RXM1SIDH = 0x00;
    RXM1SIDL = 0x00;

    // Enable Filters
    //  Only using first two filters, so the rest can be disabled
    RXFCON0 = 0x03;     //Enable Filters 0,1,2 (do I need to change this?)
    RXFCON1 = 0x00;     //Disable all others

    // Assign Filters to Masks
    //  Only one mask is used for three filters //CAN MASK SELECT REGISTER
    MSEL0 = 0xC0;     //Assign Filters 0-2 to Mask 0 and 3 to Mask 1
    MSEL1 = 0xFF;     //Assign Filters 4-7 to Mask 1
    MSEL2 = 0xFF;     //Assign Filters 8-11 to Mask 1
    MSEL3 = 0xFF;     //Assign Filters 12-15 to Mask 1

    // Assign Filters to Buffers
    //  Have the first buffer only accept the first filter, the second buffer accept
    //  the second filter.
    RXFBCON0 = 0x10;     //Assign Filter 0 to RXB0, and Filter 1 to RXB1

    RXFBCON1 = 0xFF;     //Assign the rest of the buffers with no filter
    RXFBCON2 = 0xFF; 
    RXFBCON3 = 0xFF;
    RXFBCON4 = 0xFF;
    RXFBCON5 = 0xFF;
    RXFBCON6 = 0xFF;
    RXFBCON7 = 0xFF;

Now here is where I'm thinking I need to add something (besides the spot noted above)
Elsewhere in the .h file for this c file that CAN_RecieveFrames array is set up with something like this for each CAN frame

STATUS_FRAME, 0, 0x102, 0x08, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
These are parts of an enum defined as this
name, refreshRate, arbitrationID, DLC (data length code), DATA[8] (the data payload)
I have added entries for my two new frames to that array with their arbitration IDs

So as you can see below, the code makes use of CAN_ReceiveFrames[0].arbitrationID, and the same for element [1], of course I need to add 2 and 3

Do I put them so they go into the B0 and B1 register? Do I need to change this filter? Like I said, I do plan to take the time to fully understand this, but I'm running out of time for now and it's pretty complicated.

Code:
    // Initialize Receive Filters
    RXF0EIDH = 0x00;
    RXF0EIDL = 0x00;
    RXF0SIDH = (unsigned char)((CAN_ReceiveFrames[0].arbitrationID >> 3) & 0x00FFU);//SIDH takes the 8 MSB's of the 11-bit arbitration ID
    RXF0SIDL = (unsigned char)((CAN_ReceiveFrames[0].arbitrationID << 5) & 0x00FFU);//SIDL takes the 3 LSB's, padded ON THE RIGHT with 0's

    RXF1EIDH = 0x00;
    RXF1EIDL = 0x00;
    RXF1SIDH = (unsigned char)((CAN_ReceiveFrames[1].arbitrationID >> 3) & 0x00FFU);//SIDH takes the 8 MSB's of the 11-bit arbitration ID
    RXF1SIDL = (unsigned char)((CAN_ReceiveFrames[1].arbitrationID << 5) & 0x00FFU);//SIDL takes the 3 LSB's, padded ON THE RIGHT with 0's

    // Enter CAN module into normal mode
    CANCON = 0x00;
    while(CANCON & 0xE0);

    // Set Receive Mode for buffers
    RXB0CON = 0x00;
    RXB1CON = 0x00;

}

Thank you for any ideas on how to make this work.
 
Last edited:
Here is the part that receives the messages and puts them in the data array

Code:
void CAN_Receive() {
    if (RXB0CONbits.RXFUL) //CheckRXB0
    {
        if (CAN_ReceiveFrames[0].arbitrationID != ( (unsigned int)RXB0SIDH << 3 ) + ( ((unsigned int)RXB0SIDL & 0xE0 ) >> 5)) return;
        CAN_ReceiveFrames[0].DLC = RXB0DLC;
        CAN_ReceiveFrames[0].DATA[0] = RXB0D0;
        CAN_ReceiveFrames[0].DATA[1] = RXB0D1;
        CAN_ReceiveFrames[0].DATA[2] = RXB0D2;
        CAN_ReceiveFrames[0].DATA[3] = RXB0D3;
        CAN_ReceiveFrames[0].DATA[4] = RXB0D4;
        CAN_ReceiveFrames[0].DATA[5] = RXB0D5;
        CAN_ReceiveFrames[0].DATA[6] = RXB0D6;
        CAN_ReceiveFrames[0].DATA[7] = RXB0D7;
        RXB0CONbits.RXFUL = 0;
        PIR5bits.RXB0IF = 0;  //In Mode 1 this is RXBnIF
        CAN_SNAstate[0].SNA = FALSE;
        TimerPWM_Reset(&CAN_SNAtimers[0]);
        //LATDbits.LATD7 ^= 1;
    }
    if (RXB1CONbits.RXFUL) //CheckRXB1
    {
        if (CAN_ReceiveFrames[1].arbitrationID != ( (unsigned int)RXB1SIDH << 3 ) + ( ((unsigned int)RXB1SIDL & 0xE0 ) >> 5)) return;
        CAN_ReceiveFrames[1].DLC = RXB1DLC;
        CAN_ReceiveFrames[1].DATA[0] = RXB1D0;
        CAN_ReceiveFrames[1].DATA[1] = RXB1D1;
        CAN_ReceiveFrames[1].DATA[2] = RXB1D2;
        CAN_ReceiveFrames[1].DATA[3] = RXB1D3;
        CAN_ReceiveFrames[1].DATA[4] = RXB1D4;
        CAN_ReceiveFrames[1].DATA[5] = RXB1D5;
        CAN_ReceiveFrames[1].DATA[6] = RXB1D6;
        CAN_ReceiveFrames[1].DATA[7] = RXB1D7;
        RXB1CONbits.RXFUL = 0;
        PIR5bits.RXB1IF = 0;  //In Mode 1 this is RXBnIF
        CAN_SNAstate[1].SNA = FALSE;
        TimerPWM_Reset(&CAN_SNAtimers[1]);
        //LATDbits.LATD6 ^= 1;
    }
...

So I can see that it check the arbitration ID for a specific frame "CAN_ReceiveFrames[1]" so if I had the filters set such that a buffer would accept another frame I could add a case to read it here. I'm not quite sure how to do that though.
 
Ask in the Microchip (CAN forum ) with two or three regulars tht could help easily. Myself did w/ 3 nodes in the 18F4585. In maybe 3 days from now I could post. Surgery few hours ago. CAN is fun to me.
 
Hola At,

Hope all is well and a speedy recovery.

Regards,
Inq
 
I don't seem to be able to post the the Microchip forum yet. It says access denied. I'm not sure if it requires more replies first or what.

So I've figured out that those other buffers are programable, so I need to set two (B0 and B1) to receive and then set them up. That could be tricky but I think I have the next step figured out.
 
Now I'm looking at filter hit bits. Apparently I can assign multiple filters to a buffer and the FILHIT bits will tell me which one triggered it? I'm not sure if it would be better to use these with the two RX buffers or to use the programmable buffers in RX mode with their own filters.
 
If anyone is curious about how it wrapped up, since the deadline was coming up I went and read all the sections on the datasheet related to CAN and a couple of App notes and figured it out. There were quite a few changes to get it working. In the end I added one of the programmable buffers and got it working, it turns out that one of the frames that was filtered to share a buffer was coming in about 100x as often as the other, and as a result the slower message usually didn't get read before another message came in and occupied the read/clear sequence again and as a result the higher layer code was declaring that message missing and saying the CAN bus was down. Putting that frame of it's own allowed it to be read and stopped it from timing out. So really the issue was in the higher layer protocol someone had written before I got the code, not in the CAN setup, but I had to brush up on CAN a bit to realize that.
 
Status
Not open for further replies.
Back
Top