Electronic – How to set up both CAN modules on the PIC DSPIC33EP128GM604

canmicrochipmicrocontrollerpic

So I am in the midst of my first proper PIC project, and it has been interesting to say the least. The problem I'm having is setting up the CAN modules. The PIC I'm using has two ECAN modules. Using the code examples provided, I set up CAN1 (module 1) to transmit a message, and it works absolutely fine. I can see the signal on the designated I/O pin.

The problem is when I try to use the same code with CAN2 (the second module on the PIC). It transmits some data, but not the one I set up in the buffer; all I see is 0x0000 throughout the package.

My code is mostly from the the ECAN application notes, with my few configuration tweeks. CAN1 works just fine, but CAN2 does not. When I ask both modules to transmit (CAN1 first then CAN2), only CAN1 works, but CAN2 doesn't budge at all (I have no idea why). When I turn off CAN1 and only ask CAN2 to transmit, as mentioned above, it works, but only transmits 0's (it seems like it's not talking to the DMA properly, even though I'm using the same tried-and-tested code that I used for CAN1).

Set up DMA1 for CAN transmit:

DMA1CONbits.SIZE = 0x0;
DMA1CONbits.DIR = 0x1; //From peripheral to DMA
DMA1CONbits.AMODE = 0x2;
DMA1CONbits.MODE = 0x0;
DMA1REQ = 70;
DMA1CNT = 7; //Data length
DMA1PAD = (volatile unsigned int) &C1TXD; //Point to peripheral register
DMA1STAL = (unsigned int) &CAN1MsgBuf; //Point to buffer
DMA1STAH = (unsigned int) &CAN1MsgBuf; //Point to buffer
DMA1CONbits.CHEN = 0x1; //Enable

Set CAN bus speed (This is a peripheral Library function):

CAN1Initialize(CAN_SYNC_JUMP_WIDTH2 &
               CAN_BAUD_PRE_SCALE(4),
               CAN_WAKEUP_BY_FILTER_DIS &
               CAN_PHASE_SEG2_TQ(3) &
               CAN_PHASE_SEG1_TQ(3) &
               CAN_PROPAGATIONTIME_SEG_TQ(3) &
               CAN_SEG2_FREE_PROG &
               CAN_SAMPLE1TIME); //CAN-IN

Send the Data:

    C1TR01CONbits.TXEN0 = 0x1;
    C1TR01CONbits.TX0PRI = 0x3;

    /* At this point the ECAN1 module is ready to transmit a message. Place the ECAN module in
       Normal mode. */
    C1CTRL1bits.REQOP = 0;
    while (C1CTRL1bits.OPMODE != 0)
        ;

    /* Write to message buffer 0. */
    /* CiTRBnSID = 0bxxx1 0010 0011 1100
       IDE = 0b0
       SRR = 0b0
       SID<10:0>= 0b100 1000 1111 */

    unsigned int ID = 0xB1;
    CAN1MsgBuf[0][0] = ID<<2;
    /* CiTRBnEID = 0bxxxx 0000 0000 0000
       EID<17:6> = 0b0000 0000 0000 */

    CAN1MsgBuf[0][1] = 0x0000;
    /* CiTRBnDLC = 0b0000 0000 xxx0 1111
       EID<17:6> = 0b000000
       RTR = 0b0
       RB1 = 0b0
       RB0 = 0b0
       DLC = 0b1111 */
    CAN1MsgBuf[0][2] = 0x0008;

    /* Write message data bytes */
    CAN1MsgBuf[0][3] = 0xabcd;
    CAN1MsgBuf[0][4] = 0xabcd;
    CAN1MsgBuf[0][5] = 0xabcd;
    CAN1MsgBuf[0][6] = 0xabcd;

    /* Request message buffer 0 transmission */
    C1TR01CONbits.TXREQ0 = 0x1;

    /* The following shows an example of how the TXREQ bit
       can be polled to check if transmission is complete. */
    while (C1TR01CONbits.TXREQ0 == 1)
        ;

    /* Message was placed successfully on the bus. */

I am using the same code for both modules. I only switch the 1's to the 2's for the address names. For example, C1TR01CON for CAN1 becomes C2TR01CON for CAN2, etc.

Best Answer

Argh, I finally found what was wrong. Initializing the DMA for the CAN module (or otherwise) includes:

  1. Pointing to the Peripherals Register --> I had done that correctly

  2. Pointing to the buffers in use ---> I had done that correctly too

  3. Selecting the required peripheral as the interrupt source for the DMA --> I had done this correctly for CAN1 (DMA1REQ = 70;), but I did not change this when I copied the code to set up the DMA for CAN2 which was IRQ 71 and not 70! Changing this to DMA1REQ = 71 for CAN2 fixed everything!