Hot!CAN initialization on dspic30f6010a

Author
MPaulHolmes
Starting Member
  • Total Posts : 37
  • Reward points : 0
  • Joined: 2009/10/31 10:52:40
  • Location: 0
  • Status: offline
2018/01/09 00:27:30 (permalink)
0

CAN initialization on dspic30f6010a

hello, I took down the $100 reward.  
post edited by MPaulHolmes - 2018/01/09 20:27:43
#1

18 Replies Related Threads

    btbass
    Super Member
    • Total Posts : 352
    • Reward points : 0
    • Joined: 2004/12/10 13:50:32
    • Status: offline
    Re: CAN initialization on dspic30f6010a 2018/01/09 03:19:18 (permalink)
    0
    I hope this might help.
    It is working CAN code for the dsPIC30F family.
    The only thing you will have to look at is setting the baud rate. This code had a 10MHz clock.
    The attached file is a zip file, I had to add the '.txt' on the end to upload it.
     
    To set up CAN:
     

     
    void CanInit(void);                                                  /* Call this function first */
    void CanSetMask(uint8_t mask_no, uint16_t mask);  /* Then set up masks */
    void CanSetFilter(uint8_t filter_no, uint16_t sid);       /* and filters */
    void CanConfig(void);                                             /* Then call this function last, to enable can. */
     

     
    Typically send message:
     

     
    void canTxStatus(void)
      {
      CANMSG msg;

      msg.sid = PUMP_STATUS;
      msg.length = 7;

      msg.data[0] = CanStatus.temperature;
      msg.data[1] = getErrorFlags(1U);
      msg.data[2] = CanStatus.current;
      msg.data[3] = getErrorFlags(3U);
      msg.data[4] = (CanStatus.speed / 10) >> 8;
      msg.data[5] = CanStatus.speed / 10;
      msg.data[6] = 0;

      CanSendMessage(&msg);
      }
     

     
    Types file:
     

    #ifndef TYPES_H
    #define TYPES_H
                
    /*--- Standard type definitions. ---*/

    /* Plain char, only to be used for the storage and use of character values. Misra Rule 6.1 (Required) */

    typedef unsigned char uint8_t; /* unsigned 8 bit type definition */
    typedef signed char int8_t; /* signed 8 bit type definition */
    typedef unsigned int uint16_t; /* unsigned 16 bit type definition */
    typedef signed int int16_t; /* signed 16 bit type definition */
    typedef unsigned long uint32_t; /* unsigned 32 bit type definition */
    typedef signed long int32_t; /* signed 32 bit type definition */
    typedef unsigned int Bool; /* Bool type definition */

    /*--- Standard constant definition. ---*/

    #define False ((uint16_t)0x0000U)
    #define True ((uint16_t)0x0001U)

    /*--- End of file. ---*/

    #endif

    post edited by btbass - 2018/01/09 03:26:56
    #2
    btbass
    Super Member
    • Total Posts : 352
    • Reward points : 0
    • Joined: 2004/12/10 13:50:32
    • Status: offline
    Re: CAN initialization on dspic30f6010a 2018/01/09 07:23:25 (permalink)
    0
    A few more code snippets.
    This is my init:
    /*********************************************************************************************
      Function: void initCan(void)

      PreCondition: none.
     
      Input: none.

      Output: none.

      Side Effects: Can module is initialized.

      Overview: This function is called first to intialise the Can module and set
                the masks and filters to receive can id's 0x390, 0x580 and 0x101
                using functions in the 'CanLib.a' library.
                Can receive and can error interrupt flags are cleared and can
                receive interrupt is enabled.
                       
    **********************************************************************************************/

    void initCan(void)
      {
      CanInit();
      CanSetMask(0U, 0x7ffU); /* Buffer 0 higher priority for GM diagnostic messages */
      CanSetFilter(0U, 0x101U); /* Mask and filter set for 0x101 messages */

      CanSetMask(1U, 0x1efU); /* Buffer 1 mask set for 0x390 and 0x580 messages */
      CanSetFilter(2U, 0x390U);
      CanSetFilter(3U, 0x580U);
      
      CanConfig();

      IPC6bits.C1IP = 1U; /* Set can interrupt priority */

      C1INTFbits.RX0IF = 0U; /* Clear Receive buffer interrupt flags */
      C1INTFbits.RX1IF = 0U;
      C1INTEbits.RX0IE = 1U; /* Enable Receive buffer interrupts */
      C1INTEbits.RX1IE = 1U;

      C1INTFbits.RX0OVR = 0U; /* Clear Receive error interrupt flags */
      C1INTFbits.RX1OVR = 0U;
      C1INTFbits.ERRIF = 0U;
      C1INTEbits.ERRIE = 1U; /* Enable Receive error interrupts */
      
      IFS1bits.C1IF = 0U; /* Clear can interrupt flag */
      IEC1bits.C1IE = 1U; /* Enable can interrupts */

      writePtr = 0U;
      readPtr = 0U; /* Clear message buffer pointers */
      }

     
    Can errors can be a bit tricky.
     
    /*--- Can error flags data structure ---*/

    typedef struct
      {
      unsigned Rx0_OVERFLOW:1; /* Receive buffer 0 has overflowed */
      unsigned Rx1_OVERFLOW:1; /* Receive buffer 1 has overflowed */
      unsigned RxBUSPASSIVE:1; /* Receiver in error state, bus passive */
      unsigned RxWARNING:1; /* Receiver in error state, warning */
      unsigned LOSTCOMMS:1; /* */
      }CANERROR;

    volatile CANERROR CANERRORbits;

     
    Rx messages received in a circular buffer.
     
    /*--- Rx can message circular buffer ---*/

    #define BUFFERSIZE 12

    CANMSG canMsg[BUFFERSIZE];
    uint8_t writePtr;
    uint8_t readPtr;

     
    Interrupt receive function.
     
    /*********************************************************************************************
      Function: void __attribute__((__interrupt__)) _C1Interrupt(void)

      PreCondition: Can1 receive interrupts are enabled
     
      Input: none.

      Output: none.

      Side Effects: ERRORflags and CANERRORbits may be set or cleared.

      Overview: Can receive interrupt routine is entered on receipt of a can message.
                The error flags are checked and used to set or clear flags in the CANERROR
                structure. If an overflow has occurred and a message lost, receive buffers are cleared
                else the received message is read and stored in the message buffer and the
                buffer pointer incremented.
                            
      Note 1: RX0OVR, RX1OVR must be cleared in order to clear ERRIF.
              RXEP and EWARN are set and cleared by hardware.
    **********************************************************************************************/

    void __attribute__((__interrupt__)) _C1Interrupt(void)
      {
      IFS1bits.C1IF = 0; /* Clear can interrupt flag */

      if(C1INTFbits.ERRIF) /* Check for receive errors */
        {
        ERRORflags.CANERR = 1; /* Set Can error flag */

        if(C1INTFbits.RX0OVR) /* Rx0 has overflowed, message has been lost */
          {
          CANERRORbits.Rx0_OVERFLOW = 1; /* Set CANERRORbits */
          C1RX0CONbits.RXFUL = 0; /* Clear Rx0 buffer */
          C1INTFbits.RX0OVR = 0; /* Clear interrupt flag */
          }
        else{
          CANERRORbits.Rx0_OVERFLOW = 0; /* clear CANERRORbits */
          }

        if(C1INTFbits.RX1OVR) /* Rx1 has overflowed, message has been lost */
          {
          CANERRORbits.Rx1_OVERFLOW = 1; /* Set CANERRORbits */
          C1RX1CONbits.RXFUL = 0; /* Clear Rx1 buffer */
          C1INTFbits.RX1OVR = 0; /* Clear interrupt flag */
          }
        else{
          CANERRORbits.Rx1_OVERFLOW = 0; /* clear CANERRORbits */
          }
          
        C1INTFbits.ERRIF = 0; /* Clear can error flag, must be done last */
        }
      else /* no can errors */
        {
        ERRORflags.CANERR = 0;
        CanReceiveMessage(&canMsg[writePtr]);
        if(++writePtr >= BUFFERSIZE){
          writePtr = 0;
          }
        }
      
      if(C1INTFbits.RX0IF){ /* Message received in buffer 0 (only clear one flag at a time) */
        C1INTFbits.RX0IF = 0;
        }
      else if(C1INTFbits.RX1IF){ /* Message received in buffer 1 */
        C1INTFbits.RX1IF = 0;
        }

      CANERRORbits.RxBUSPASSIVE = C1INTFbits.RXEP; /* Can bus error state counters */
      CANERRORbits.RxWARNING = C1INTFbits.EWARN; /* Set or clear CANERRORbits */
      if(C1INTFbits.EWARN){ /* Set CANERR bit if error count warning set */
        ERRORflags.CANERR = 1;
        }
      }


    #3
    MPaulHolmes
    Starting Member
    • Total Posts : 37
    • Reward points : 0
    • Joined: 2009/10/31 10:52:40
    • Location: 0
    • Status: offline
    Re: CAN initialization on dspic30f6010a 2018/01/09 08:04:20 (permalink)
    0
    Thank you, btbass.  I have a question about this part:

    void CanConfig(void)
    {
    C1CFG1bits.BRP = 1; /* 10 Meg clock */
    C1CFG1bits.SJW = 3; /* Synchronized jump width time is 4Tq. */
    C1CFG2bits.PRSEG = 7; /* Propagation time segment = 8Tq. */
    C1CFG2bits.SEG1PH = 5; /* Phase buffer Segment 1 = 6Tq. */
    C1CFG2bits.SAM = 0; /* Bus is sampled once. */
    C1CFG2bits.SEG2PHTS = 1; /* PhaseSeg2 is freely programmable. */
    C1CFG2bits.SEG2PH = 4; /* Phase buffer Segment 2 = 5Tq. */
    C1CTRL = 0x8000; /* Can clock is Fcy = 10MHz. Request normal operation mode. */
    while(C1CTRLbits.OPMODE != 0){
    ;
    }
    }

    C1CTRLbits.CANCKS = 0 in your case, but that means Fcan = 4*Fcy = 40MHz?  Or am I misuderstanding something?
    #4
    btbass
    Super Member
    • Total Posts : 352
    • Reward points : 0
    • Joined: 2004/12/10 13:50:32
    • Status: offline
    Re: CAN initialization on dspic30f6010a 2018/01/09 08:29:25 (permalink)
    0
    Yes, that is confusing.
    I think they screwed up there, because if you look at sample code, when CANCKS = 0, clock is Fcy/4.
    Not * 4!
    So its divide by 4, not times 4.
     
    Does Mplab X have a can baud rate calculator which you could use?
    I still use Mplab IDE. 
     
    #5
    MPaulHolmes
    Starting Member
    • Total Posts : 37
    • Reward points : 0
    • Joined: 2009/10/31 10:52:40
    • Location: 0
    • Status: offline
    Re: CAN initialization on dspic30f6010a 2018/01/09 08:33:38 (permalink)
    0
    I also still use mplab IDE too.  haha.  That's good to know that there may be a mistake!  I'll see if that helps.
    #6
    btbass
    Super Member
    • Total Posts : 352
    • Reward points : 0
    • Joined: 2004/12/10 13:50:32
    • Status: offline
    Re: CAN initialization on dspic30f6010a 2018/01/09 08:55:43 (permalink)
    0
    30MHz is not an ideal freq?
    I have done a few calculations and I get odd BRP values.
    I think it needs to be divisible by 8 or by 5 to get round integer results? 
     
    I dont think it will matter if both boards use the same settings?
     
    #7
    MPaulHolmes
    Starting Member
    • Total Posts : 37
    • Reward points : 0
    • Joined: 2009/10/31 10:52:40
    • Location: 0
    • Status: offline
    Re: CAN initialization on dspic30f6010a 2018/01/09 09:07:55 (permalink)
    0
    So, you had CANCKS = 0, so your Fcan was 2.5MHz?
    #8
    btbass
    Super Member
    • Total Posts : 352
    • Reward points : 0
    • Joined: 2004/12/10 13:50:32
    • Status: offline
    Re: CAN initialization on dspic30f6010a 2018/01/09 09:22:39 (permalink)
    0
    No, the Fcan was 10Mhz.
    The Fosc was 40Mhz
     
    There is some confusion between Fosc and Fcy
     
    Now Im confused, this was 12 years ago, after a bit of calc I do need a 40M clock to 500k baud.
    Let me do some calculations, Ill get back to you!
     
     
    post edited by btbass - 2018/01/09 09:28:53
    #9
    MPaulHolmes
    Starting Member
    • Total Posts : 37
    • Reward points : 0
    • Joined: 2009/10/31 10:52:40
    • Location: 0
    • Status: offline
    Re: CAN initialization on dspic30f6010a 2018/01/09 09:27:54 (permalink)
    0
    I'm using a x16 pll with an external crystal of 7.5MHz, so Fosc = 7.5MHz  * 16, right?  And then Fcy = Fosc / 4.  Then, if I use CANCKS = 0, that means Fcan = Fcy / 4 (even though the datasheet says it means Fcan = 4 * Fcy).  So, if I use CANCKS = 0, Fcan = 7.5MHz?

    EDIT:  OK, CANCKS = 0 means Fcan = Fosc / 4?  So, in my case, since Fosc = 120MHz, Fcan = 30Mhz if CANCKS = 0?
    post edited by MPaulHolmes - 2018/01/09 09:31:37
    #10
    btbass
    Super Member
    • Total Posts : 352
    • Reward points : 0
    • Joined: 2004/12/10 13:50:32
    • Status: offline
    Re: CAN initialization on dspic30f6010a 2018/01/09 09:33:41 (permalink)
    0
    If CANCKS = 0 then your Fcan will be 120Mhz
    If CANCKS = 1 then your Fcan will be 30MHz
    #11
    MPaulHolmes
    Starting Member
    • Total Posts : 37
    • Reward points : 0
    • Joined: 2009/10/31 10:52:40
    • Location: 0
    • Status: offline
    Re: CAN initialization on dspic30f6010a 2018/01/09 12:06:49 (permalink)
    0
    OK I have a $100 reward for anyone who can change this so that it works on my 2 boards, who are attempting to communicate with each other.  I will paypal the first person who fixes it so that when I test it, it works for me:
    I am running a 7.5MHz crystal, with xtpll of x16, so that Fcy = 30MHz, and Fosc = 120MHz.
    Here's the first file, slightly modified, from btbass (thank you btbass for all your help!!)
     
    First is CanLib.c

     
     
     
    /*--------------------------------------------------------------------
     
     
     
    Title : Can routines for dsPIC30f.
    Filename : CanLib.c
    Author : RW

    ----------------------------------------------------------------------
     
     
     
    CHANGE HISTORY
     
     
     
    Issue Modifier Date Change Description
    1.0 RW 02/09/05 First Issue

    ----------------------------------------------------------------------
     
     
     
    Module Description:
    Can utility library.
    Configure can module.
    Send and receive can messages with standard identifiers.

    --------------------------------------------------------------------*/
     
     
     
    #include "canlib.h"
     
     
     
    /*--- Function prototypes ---*/
     
     
     
    static uint8_t getTxbuffer(void);
     
     
     
    /*********************************************************************
    * Function Name : CanInit
    * Description : Put can into configuration mode.

    *********************************************************************/
     
     
     
    void CanInit(void)
    {
    C2CTRLbits.REQOP = 4; /* Request configuration mode */
    while(C2CTRLbits.OPMODE != 4){ /* Wait until configuration mode entered */
    ;
    }
    }
     
     
     
    /*********************************************************************
    * Function Name : CanConfig
    * Description : Sets baud rate to 20Kbps with 15Tq and a Fcan clock of 30MHz

    *********************************************************************/
     
     
     
    void CanConfig(void)
    {
    C2CFG1bits.BRP = 49; /* 30 MHz clock */
    C2CFG1bits.SJW = 2 - 1; /* Synchronized jump width time is 2Tq. */
    C2CFG2bits.PRSEG = 3 - 1; /* Propagation time segment = 3Tq. */
    C2CFG2bits.SEG1PH = 5 - 1; /* Phase buffer Segment 1 = 5Tq. */
    C2CFG2bits.SAM = 0; /* Bus is sampled once. */
    C2CFG2bits.SEG2PHTS = 1; /* PhaseSeg2 is freely programmable. */
    C2CFG2bits.SEG2PH = 5 - 1; /* Phase buffer Segment 2 = 5Tq. */
    //C2CTRL = 0x8000; /* Can clock is Fcy = 30MHz. Request normal operation mode. */
    C2CTRL = 0b1000100000000000; // set CANCKS = 1, so that Fcan = Fcy = 30MHz, according to family reference manual.
    //C2CTRL = 0b1000000000000000; // Or is this right? set CANCKS = 0, so that Fcan = Fosc / 4 = 30MHz?????
     
     
     
    while(C2CTRLbits.OPMODE != 0){
    ;
    }
    }
     
     
     
    /*********************************************************************
    * Function Name : CanSetFilter
    * Description : This function sets the acceptance filter, SID for
    standard length identifiers.
     
     
     
    * Parameters : uint16_t: filter_no: (Filter number 0-5)
    * uint16_t: sid: (SID value)
    *********************************************************************/
     
     
     
    void CanSetFilter(uint8_t filter_no, uint16_t sid)
    {
    switch(filter_no)
    {
    case 0: C2RXF0SID = 0;
    C2RXF0SIDbits.SID = sid;
    break;
    case 1: C2RXF1SID = 0;
    C2RXF1SIDbits.SID = sid;
    break;
    case 2: C2RXF2SID = 0;
    C2RXF2SIDbits.SID = sid;
    break;
    case 3: C2RXF3SID = 0;
    C2RXF3SIDbits.SID = sid;
    break;
    case 4: C2RXF4SID = 0;
    C2RXF4SIDbits.SID = sid;
    break;
    case 5: C2RXF5SID = 0;
    C2RXF5SIDbits.SID = sid;
    break;

    default:C2RXF0SID = 0;
    C2RXF0SIDbits.SID = sid;
    break;
    }
    }
     
     
     
    /*************************************************************************
    * Function Name : CanSetMask
    * Description : This function sets the values for the acceptance
    * filter masks for standard length identifiers.
     
     
     
    * Parameters : uint16_t: mask_no: (Mask number 0-1)
    * uint16_t: mask: (Mask value)
    **************************************************************************/
     
     
     
    void CanSetMask(uint8_t mask_no, uint16_t mask)
    {
    switch(mask_no)
    {
    case 0: C2RXM0SID = 0x0001;
    C2RXM0SIDbits.SID = mask;
    break;
    case 1: C2RXM1SID = 0x0001;
    C2RXM1SIDbits.SID = mask;
    break;

    default:C2RXM0SID = 0x0001;
    C2RXM0SIDbits.SID = mask;
    break;
    }
    }
     
     
     
    /*************************************************************************
    * Function Name : CanSetPriority
    * Description : This function sets the message transmission
    * priority bits.
     
     
     
    * Parameters : uint16_t: buffer: (Transmit buffer number 0-2)
    uint16_t: priority: (Transmit priority 0-2)
    **************************************************************************/
     
     
     
    void CanSetPriority(uint8_t buffer, uint8_t priority)
    {
    priority = (priority > 2U) ? 2U : priority;
     
     
     
    switch(buffer)
    {
    case 0: C2TX0CONbits.TXPRI = priority;
    break;
    case 1: C2TX1CONbits.TXPRI = priority;
    break;
    case 2: C2TX2CONbits.TXPRI = priority;
    break;
    default:
    break;
    }
    }

    /*********************************************************************
    * Function Name : CanSendMessage
    * Description : This function writes the message identifier(SID),
    writes the data to be transmitted into the Transmit buffer
    * and sets the corresponding Transmit request bit.
     
     
     
    * Parameters : Pointer to structure CANMSG defined in can.h
    *********************************************************************/
     
     
     
    void CanSendMessage(const CANMSG *message)
    {
    uint8_t buffer;
    uint16_t ix = ((message->sid & 0x07C0) << 5) | ((message->sid & 0x003F) << 2);
     
     
     
    buffer = getTxbuffer();

    switch(buffer)
    {
    case 0: C2TX0SID = ix;
    break;
    case 1: C2TX1SID = ix;
    break;
    case 2: C2TX2SID = ix;
    break;
     
     
     
    default:C2TX0SID = ix;
    break;
    }
     
     
     
    for(ix = 0; ix < message->length; ix++)
    {
    switch(buffer)
    {
    case 0: *((uint8_t *)&C2TX0B1+ix) = message->data[ix];
    break;
    case 1: *((uint8_t *)&C2TX1B1+ix) = message->data[ix];
    break;
    case 2: *((uint8_t *)&C2TX2B1+ix) = message->data[ix];
    break;
    default:*((uint8_t *)&C2TX0B1+ix) = message->data[ix];
    break;
    }
    }
     
     
     
    switch(buffer)
    {
    case 0: C2TX0DLC = 0x0180;
    C2TX0DLCbits.DLC = message->length;
    C2TX0CONbits.TXREQ = 1;
    break;
    case 1: C2TX1DLC = 0x0180;
    C2TX1DLCbits.DLC = message->length;
    C2TX1CONbits.TXREQ = 1;
    break;
    case 2: C2TX2DLC = 0x0180;
    C2TX2DLCbits.DLC = message->length;
    C2TX2CONbits.TXREQ = 1;
    break;
    default:break;
    }
    }
     
     
     
    /*************************************************************************
    * Function Name : CanReceiveMessage
    * Description : If a message has been received, read the data from
    the receive buffer into the structure CANMSG
    and clear the RXFUL bit.
     
     
     
    * Parameters : Pointer to structure CANMSG defined in can.h
    * Returns : True if message received else False.
    **************************************************************************/
     
     
     
    Bool CanReceiveMessage(CANMSG *message)
    {
    uint8_t ix, buffer = 0xff;
     
     
     
    if(C2RX0CONbits.RXFUL){
    buffer = 0;
    }
    else if(C2RX1CONbits.RXFUL){
    buffer = 1;
    }
     
     
     
    if(buffer != 0xff)
    {
    switch(buffer)
    {
    case 0: message->sid = (C2RX0SID >> 2) & 0x07ff;
    message->length = C2RX0DLCbits.DLC;
    break;
    case 1: message->sid = (C2RX1SID >> 2) & 0x07ff;
    message->length = C2RX1DLCbits.DLC;
    break;
    default:
    break;
    }
     
     
     
    for(ix = 0; ix < message->length; ix++)
    {
    switch(buffer)
    {
    case 0: message->data[ix] = *((uint8_t *)&C2RX0B1 + ix);
    break;
    case 1: message->data[ix] = *((uint8_t *)&C2RX1B1 + ix);
    break;
    default:
    break;
    }
    }
     
     
     
    switch(buffer)
    {
    case 0: C2RX0CONbits.RXFUL = 0;
    break;
    case 1: C2RX1CONbits.RXFUL = 0;
    break;
    default:
    break;
    }
    }
     
     
     
    return (buffer != 0xff) ? True : False;
    }
     
     
     
    /*************************************************************************
    * Function Name : getTxbuffer
    * Description : Returns an available empty transmit buffer.
     
     
     
    * Returns : Transmit buffer number 0-2.
    **************************************************************************/
     
     
     
    static uint8_t getTxbuffer(void)
    {
    uint8_t buffer = 0;
     
     
     
    if(C2TX0CONbits.TXREQ == 0){
    buffer = 0;
    }
    else if(C2TX1CONbits.TXREQ == 0){
    buffer = 1;
    }
    else if(C2TX2CONbits.TXREQ == 0){
    buffer = 2;
    }
     
     
     
    return buffer;
    }
     
     
     
    /*--- End of file.---*/
     
     
     

     
    Next, is CanLib.h:

     
     
     
    /*********************************************************************
    * File Name : CanLib.h
    * Description : Header file for CanLib.c
     
     
     
    * Revision : 1.0
    * Date : 02/09/05
    *********************************************************************/
     
     
     
    #ifndef CANLIB_H
    #define CANLIB_H
     
     
     
    #include <p30fxxxx.h>
    #include "types.h"
     
     
     
    /*--- Can message structure. ---*/
     
     
     
    typedef struct
    {
    uint16_t sid;
    uint8_t length;
    uint8_t data[8];
    }CANMSG;

    /*--- CanLib function prototypes. ---*/
     
     
     
    void CanInit(void); /* Call this function first */
    void CanSetMask(uint8_t mask_no, uint16_t mask); /* Then set up masks */
    void CanSetFilter(uint8_t filter_no, uint16_t sid); /* and filters */
    void CanConfig(void); /* Then call this function last, to enable can. */
     
     
     
    void CanSetPriority(uint8_t buffer, uint8_t priority);
    void CanSendMessage(const CANMSG *message);
    Bool CanReceiveMessage(CANMSG *message); /* Returns True if message received. */
     
     
     
    /*--- End of file. ---*/
     
     
     
    #endif
     
     
     
     

     
    Next, we have TVU.c, where main() resides:

     
     
     
    #include "tvu.h"
     
     
     
    /*****************Config bit settings****************/
    _FOSC(0xFFFF & XT_PLL16);//XT_PLL4); // Use XT with external crystal from 4MHz to 10MHz. FRM Pg. 178
    // nominal clock is 128kHz. The counter is 1 byte.
    //#define STANDARD_THROTTLE
    //#ifdef DEBUG
    _FWDT(WDT_OFF);
    //#else
    // _FWDT(WDT_ON & WDTPSA_64 & WDTPSB_8); // See Pg. 709 in F.R.M. Timeout in 1 second or so. 128000 / 64 / 8 / 256
    //#endif
     
     
     
    _FBORPOR(0xFFFF & BORV27 & PWRT_64 & MCLR_EN & PWMxL_ACT_HI & PWMxH_ACT_HI); // Brown Out voltage set to 2.7v. Power up time of 64 ms. MCLR is enabled.
    // PWMxL_ACT_HI means PDC1 = 0 would mean PWM1L is 0 volts. Just the opposite of how I always thought it worked. haha.
    // PWMxH_ACT_HI means, in complementary mode, that PDC1 = 0 would mean PWM1H is 0v, and PWM1L is 5v.
    _FGS(GWRP_OFF & GSS_OFF);
     
     
     
    //#ifdef NODE_MASTER
    //_FICD(PGD); // the debugging channel is EMUD3 and EMUC3. I'm already using PDC and PGD for A/D channels unfortunately.
    //#else
    //_FICD(PGD3);
    //#endif
     
     
     
    //extern void CANConfig();
     
     
     
    void InitTimers();
    void InitIORegisters();
    volatile CANMSG receivingMessage = {1, 8, {'1', '2', '3', '4', '5', '6', '7','8'}}; // just filling it with junk so I can know if a real mesaage is received.
    volatile CANMSG sendingMessage = {1, 8, {10, 20, 30, 40, 50, 60, 70, 80} }; // holds all 8 voltages. voltages.data[0] is battery 0's voltage, etc...
     
     
     
    int main() {
    int i = 0;
    unsigned int now;
    InitIORegisters();
    InitTimers();
    TMR5 = 0;
    while (TMR5 < 2000); // wait around for almost 5 seconds, just because.
    CanInit();
    CanSetMask(0,0b00000000000); // don't require ANY of the bits to match
    CanSetMask(1,0b00000000000); // don't require any of the bits to match. I want to accept whatever message is sent!
    CanSetFilter(0,1); // set the filter to 1 for each one. So, if the received message is 1, it will be accepted. Well, the sending message's ID is 1, so it should be accepted!
    CanSetFilter(1,1);
    CanSetFilter(2,1);
    CanSetFilter(3,1);
    CanSetFilter(4,1);
    CanSetFilter(5,1);
    CanConfig();
     
     
     
    TMR5 = 0;
    while (TMR5 < 2000); // wait around for another 5 seconds.
     
     
     

    now = TMR5;
    while (1) {
    if (CanReceiveMessage((CANMSG *)&receivingMessage)) { // if the controller receives a message, then open or close the contactor (giant relay) that it controls (so I can hear that something is happening!)
    if (O_PORT_CONTACTOR == 0) O_LAT_CONTACTOR = 1;
    else O_LAT_CONTACTOR = 0;
    }
    if (TMR5 - now > 500u) { // ATTEMPT to send a message around 1 time per second.
    now = TMR5;
    CanSendMessage((CANMSG *)&sendingMessage); // send the sending message, which has an ID of 1, 8 bytes long, and the bytes are 10,20,30,...
    }
    }
    return 0;
    }
    // So, both controllers are attempting to send "sendingMessage" to the other controller at 1 time per second. That shouldn't be too high of a data rate.
     
     
     
    void InitTimers() {
    T1CON = 0; // Make sure it starts out as 0.
    T1CONbits.TCKPS = 0b11; // prescale of 256. So, timer1 will run at 115200Hz if Fcy is 7.3728*4 MHz.
    PR1 = 0xFFFF; //
    T1CONbits.TON = 1; // Start the timer.
     
     
     
    T2CONbits.T32 = 1; // 32 bit mode.
    T2CONbits.TCKPS = 0b11; // 1:1 prescaler.
    T2CONbits.TCS = 0; // use internal 15MHz Fcy for the clock.
    PR3 = 0x0FFFF; // HIGH 16 BITS.
    PR2 = 0x0FFFF; // low 16 bits.
    // Now, TMR3:TMR2 makes up the 32 bit timer, running at 58.6KHz.
     
     
     
    T4CONbits.T32 = 1; // 32 bit mode.
    T4CONbits.TCKPS = 0b00; // 1:1 prescaler.
    T4CONbits.TCS = 0; // use internal 15MHz Fcy for the clock.
    PR5 = 0x0FFFF; // HIGH 16 BITS.
    PR4 = 0x0FFFF; // low 16 bits.
     
     
     
    T2CONbits.TON = 1; // Start the timer.
    T4CONbits.TON = 1; // Start the timer.
     
     
     
    TMR3 = 0; // Timer3:Timer2 high word
    TMR5 = 0; // Timer5:Timer4 high word
     
     
     
    TMR2 = 0; // Timer3:Timer2 low word
    TMR4 = 0; // Timer5:Timer4 low word
    }
     
     
     
    void InitIORegisters() {
    // ADPCFG = 0b1111111010111011; // 0 is analog. 1 is digital.

    O_TRIS_CONTACTOR = 0;
    O_LAT_CONTACTOR = 0; // OFF.
    }
     
     
     

    And here is TVU.h:



     
     
     

    #ifndef TVU_H
    #define TVU_H
    //#include "P30F4011.h"
    #include "P30F6010a.h"
    #include "types.h"
    #include "canlib.h"
     
     
     

    #include <libpic30.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
     
     
     
    #define I_TRIS_THROTTLE _TRISB0
    #define I_TRIS_CURRENT1 _TRISB1
    #define I_TRIS_CURRENT2 _TRISB2
    #define I_TRIS_INDEX _TRISB3
    #define I_TRIS_QEA _TRISB4
    #define I_TRIS_QEB _TRISB5
    #define I_TRIS_BRAKE _TRISB6
    #define I_TRIS_INPUT4 _TRISB7
    #define I_TRIS_INPUT6 _TRISA10
    #define I_TRIS_INPUT7 _TRISB8
    #define I_TRIS_INPUT5 _TRISB13
    #define O_TRIS_CONTACTOR _TRISC3
     
     
     
     
     
     
     
    #define I_LAT_THROTTLE _LATB0
    #define I_LAT_CURRENT1 _LATB1
    #define I_LAT_CURRENT2 _LATB2
    #define I_LAT_INDEX _LATB3
    #define I_LAT_QEA _LATB4
    #define I_LAT_QEB _LATB5
    #define I_LAT_BRAKE _LATB6
    #define I_LAT_INPUT4 _LATB7
    #define I_LAT_INPUT6 _LATA10
    #define I_LAT_INPUT7 _LATB8
    #define I_LAT_INPUT5 _LATB13
    #define O_LAT_CONTACTOR _LATC3
     
     
     

    #define I_PORT_THROTTLE _RB0
    #define I_PORT_CURRENT1 _RB1
    #define I_PORT_CURRENT2 _RB2
    #define I_PORT_INDEX _RB3
    #define I_PORT_QEA _RB4
    #define I_PORT_QEB _RB5
    #define I_PORT_BRAKE _RB6
    #define I_PORT_INPUT4 _RB7
    #define I_PORT_INPUT6 _RA10
    #define I_PORT_INPUT7 _RB8
    #define I_PORT_INPUT5 _RB13
    #define O_PORT_CONTACTOR _RC3
     
     
     
     
     
     
     
    #endif
     
     
     

    On your mark, get set go!  haha.  My goal is, to have the 2 controllers each send the same 8 bytes to each other, and have the receiving struct actually receive it.
    post edited by MPaulHolmes - 2018/01/09 12:10:49
    #12
    btbass
    Super Member
    • Total Posts : 352
    • Reward points : 0
    • Joined: 2004/12/10 13:50:32
    • Status: offline
    Re: CAN initialization on dspic30f6010a 2018/01/09 14:41:41 (permalink)
    0
    Keep it simple,
    My clock 10M your clock 30M
    Keep everything the same but divide by 3.
    My BRP
    C1CFG1bits.BRP = 1; (+1) Total 2

    Your BRP
    C1CFG1bits.BRP = 5 (+1) Total 6
    Three times slower.
    So try keeping everything the same but set your BRP to 5.
     
    Just a thought, have you terminated each end of the bus with 120R ?
    post edited by btbass - 2018/01/09 15:09:07
    #13
    MPaulHolmes
    Starting Member
    • Total Posts : 37
    • Reward points : 0
    • Joined: 2009/10/31 10:52:40
    • Location: 0
    • Status: offline
    Re: CAN initialization on dspic30f6010a 2018/01/09 18:46:20 (permalink)
    0
    I can't get it to work with BRP = 5, and your values for the Tq stuff.  Yes, I have a 120Ohm resistor on each end.  The resistance of the bus is 60Ohms.  I'm using an MCP2551 can transceiver, with a 10k resistor from Rs to +5v.  I wonder if it should be shorted to +5v or ground.  Something really weird is going on.
    #14
    btbass
    Super Member
    • Total Posts : 352
    • Reward points : 0
    • Joined: 2004/12/10 13:50:32
    • Status: offline
    Re: CAN initialization on dspic30f6010a 2018/01/10 02:28:25 (permalink)
    0
    Shouldn't the Rs resistor go to GND?
     
    DATA SHEET:
    1.7.8 SLOPE RESISTOR INPUT (RS)
    The RS pin is used to select High-speed, Slope-control
    or Standby modes via an external biasing resistor.
     
    1.4.3 STANDBY MODE
    The device may be placed in standby or “SLEEP” mode
    by applying a high-level to RS. In SLEEP mode, the
    transmitter is switched off and the receiver operates at
    a lower current. The receive pin on the controller side
    (RXD) is still functional but will operate at a slower rate.
    The attached microcontroller can monitor RXD for CAN
    bus activity and place the transceiver into normal
    operation via the RS pin (at higher bus rates, the first
    CAN message may be lost).
     
    The diagrams show it going to GND.


     
    post edited by btbass - 2018/01/10 02:45:23
    #15
    MPaulHolmes
    Starting Member
    • Total Posts : 37
    • Reward points : 0
    • Joined: 2009/10/31 10:52:40
    • Location: 0
    • Status: offline
    Re: CAN initialization on dspic30f6010a 2018/01/10 09:21:51 (permalink)
    0
    Well, the datasheet I read said it could go to either +5v or ground (EDIT:  IT ACTUALLy said VOL, but usually ground, whatever VOL is), as long as it was biased, but I had the same thought as you last night in a dream.  haha, and I tried it this morning (did you transport it to me secretly while I was sleeping?!) and yes that was the problem!  

    edit:  actually the dream said I needed to include a diode (well, a dream version of a diode, which I took to mean a pull to gorundn in the dream.  it was weird), but that led to it. lol
    post edited by MPaulHolmes - 2018/01/10 11:20:51
    #16
    MPaulHolmes
    Starting Member
    • Total Posts : 37
    • Reward points : 0
    • Joined: 2009/10/31 10:52:40
    • Location: 0
    • Status: offline
    Re: CAN initialization on dspic30f6010a 2018/01/13 12:09:13 (permalink)
    0
    Does anybody know if the dspic30f family reference manual is wrong here?
    CiTXnDLC:
    bit 8-7 TXRB<1:0>: Reserved Bits
    Note: User must set these bits to ‘0’ according to CAN protocol.
     
    However, the Can library btbass included sets those bits to 1 & 1 when it is getting ready to send a message.  Is the dspic datasheet wrong there?
    #17
    btbass
    Super Member
    • Total Posts : 352
    • Reward points : 0
    • Joined: 2004/12/10 13:50:32
    • Status: offline
    Re: CAN initialization on dspic30f6010a 2018/01/14 01:26:39 (permalink)
    0
    In the family reference manual that I have
    Hardcopy-DS70070B section 23-7
    CiTXnDLC:
    bit 8-7 TXRB<1:0> Reserved Bits
    Note: User must set these bits to '1' according to CAN protocol.
     
    So conflicting information.
    I will try to find out what the CAN spec. really says.
     
    One thing in the libs favour, it has been used successfully in several products over the years with no reported problems.
    #18
    btbass
    Super Member
    • Total Posts : 352
    • Reward points : 0
    • Joined: 2004/12/10 13:50:32
    • Status: offline
    Re: CAN initialization on dspic30f6010a 2018/01/14 01:55:33 (permalink)
    0
    From what I can see in example messages, 1 bit is used in standard and 2 bits are used in extended messages.
    In the example messages they are set to '0'.
    So my manual would appear to be wrong, it was printed in 2003.
     
    They are marked as reserved so they are not used.
    Looks like I got away with it!
     
    #19
    Jump to:
    © 2018 APG vNext Commercial Version 4.5