This library for Seeed Studio's CAN-BUS Shield has a similar API to mbed's LPC1768 CAN library making it easy to add CAN functionality to mbed systems that support Arduino type 'Shields. This Beta release of my CAN-BUS Library is largely working but lacks interrupt 'attach' functions.

Dependents:   Seeed_CAN_Hello_World ws-canrecv-1 CAN_SPI_modulo

Fork of SEEED_CAN by Sophie Dexter

Files at this revision

API Documentation at this revision

Comitter:
Just4pLeisure
Date:
Wed Nov 06 20:16:11 2013 +0000
Parent:
0:f5d099885d3d
Child:
2:fd026fcfde94
Commit message:
Beta release of a CAN-BUS library for Seeed Studios' CAN BUS Shield

Changed in this revision

seeed_can.cpp Show annotated file Show diff for this revision Revisions of this file
seeed_can.h Show annotated file Show diff for this revision Revisions of this file
seeed_can_api.cpp Show annotated file Show diff for this revision Revisions of this file
seeed_can_api.h Show annotated file Show diff for this revision Revisions of this file
seeed_can_defs.h Show annotated file Show diff for this revision Revisions of this file
seeed_can_spi.h Show annotated file Show diff for this revision Revisions of this file
--- a/seeed_can.cpp	Tue Nov 05 22:37:35 2013 +0000
+++ b/seeed_can.cpp	Wed Nov 06 20:16:11 2013 +0000
@@ -16,9 +16,9 @@
 
 #include "seeed_can.h"
 
-/** Seeed Studios CAN-BUS Shield Constructor - initialise FRDM-KL25Z's SPI0 for the MCP2515
+/** Seeed Studios CAN-BUS Shield Constructor - Create a SEEED_CAN interface connected to the specified pins.
  */
-SEEED_CAN::SEEED_CAN(PinName ncs, PinName irq, PinName mosi, PinName miso, PinName clk, int spiBitrate, int canBitrate) :
+SEEED_CAN::SEEED_CAN(PinName ncs, PinName irq, PinName mosi, PinName miso, PinName clk, int spiBitrate) :
     _spi(mosi, miso, clk),
     _can(_spi, ncs, irq)
 {
@@ -27,18 +27,25 @@
     // Set up the spi interface
     _can.spi.format(8, 3);
     _can.spi.frequency(spiBitrate);
-    mcpInit(&_can, canBitrate);                                             
+    _can.irq.fall(this, &SEEED_CAN::call_irq);
+}
+
+/** Open initialises the Seeed Studios CAN-BUS Shield.
+ */
+int SEEED_CAN::open(int canBitrate)
+{
+    return mcpInit(&_can, (uint32_t) canBitrate);
 }
 
-/** Set CAN-BUS frequency (Bit Rate)
+/** Set the CAN bus frequency (Bit Rate)
 */
-int SEEED_CAN::frequency(int setBitRate)
+int SEEED_CAN::frequency(int canBitRate)
 {
-//    return mcpSetBitRate(&_can, (uint32_t) setBitRate);
-    return mcpInit(&_can, (uint32_t) setBitRate);
+//    return mcpSetBitRate(&_can, (uint32_t) canBitRate);
+    return mcpInit(&_can, (uint32_t) canBitRate);
 }
 
-/** Read a CAN bus message from the MCP2515 (if there is one)
+/** Read a CAN bus message from the MCP2515 (if one has been received)
  */
 int SEEED_CAN::read(SEEED_CANMessage &msg)
 {
@@ -52,6 +59,20 @@
     return mcpCanWrite(&_can, msg);
 }
 
+/** Configure one of the Accpetance Masks (0 or 1)
+ */
+int SEEED_CAN::mask(int maskNum, int canId, CANFormat format)
+{
+    return mcpInitMask(&_can, maskNum, canId, format);
+}
+
+/** Configure one of the Acceptance Filters (0 through 5)
+ */
+int SEEED_CAN::filter(int filterNum, int canId, CANFormat format)
+{
+    return mcpInitFilter(&_can, filterNum, canId, format);
+}
+
 /** Returns number of message reception (read) errors to detect read overflow errors.
  */
 unsigned char SEEED_CAN::rderror(void)
@@ -66,7 +87,7 @@
     return mcpTransmissionErrorCount(&_can);
 }
 
-/** Check if any type of error has been detected
+/** Check if any type of error has been detected on the CAN bus
  */
 int SEEED_CAN::errors(void)
 {
@@ -80,34 +101,24 @@
     mcpMonitor(&_can, silent);
 }
 
-/** Puts or removes the Seeed Studios CAN-BUS shield into the specified mode
+/** Change the Seeed Studios CAN-BUS shield CAN operation mode
  */
 int SEEED_CAN::mode(Mode mode)
 {
     return mcpMode(&_can, (CANMode)mode);
 }
 
-/** Configure one of the Accpetance Masks (0 or 1)
- */
-int SEEED_CAN::Mask(int maskNum, int canId, CANFormat format) {
-    return mcpInitMask(&_can, maskNum, canId, format);
-}
-
-/** Configure one of the Acceptance Filters (0 through 5)
- */
-int SEEED_CAN::Filter(int filterNum, int canId, CANFormat format) {
-    return mcpInitFilter(&_can, filterNum, canId, format);
-}
-
 /** Attach a function to call whenever a CAN frame received interrupt is generated.
  */
 void SEEED_CAN::attach(void (*fptr)(void), IrqType type)
 {
-    _can.irq.fall(fptr);
-/*    if (fptr) {
-        _irq[(CanIrqType)type].attach(fptr);
-        can_irq_set(&_can, (CanIrqType)type, 1);
-    } else {
-        can_irq_set(&_can, (CanIrqType)type, 0);
-    }*/
+    _callback_irq.attach(fptr);
+    mcpWrite(&_can, MCP_CANINTE, MCP_RX0IF | MCP_RX1IF);                // RX buffers can generate a interrupt
+//    _can.irq.fall(fptr);
+    /*    if (fptr) {
+            _irq[(CanIrqType)type].attach(fptr);
+            can_irq_set(&_can, (CanIrqType)type, 1);
+        } else {
+            can_irq_set(&_can, (CanIrqType)type, 0);
+        }*/
 }
--- a/seeed_can.h	Tue Nov 05 22:37:35 2013 +0000
+++ b/seeed_can.h	Wed Nov 06 20:16:11 2013 +0000
@@ -63,25 +63,32 @@
  */
 class SEEED_CAN
 {
-    /** can operator functions
-     */
 public:
-    /** Create a SEEED_CAN interface, connected to the specified pins
+    /** Seeed Studios CAN-BUS Shield Constructor - Create a SEEED_CAN interface connected to the specified pins.
      *
-     * The Seeed Studio CAN-BUS shield is an Arduino compatible shield and connects to the FRDM-KL25Z SPI0 interface using pins PTD2 (mosi) PTD3 (miso) PTD1 (clk). The Active low chip select normally connects to the FRDM-KL25Z's PTD0 pin, but there is an option on the Seeed Studio CAN-BUS shield to connect to the PTD5 pin. The CAN-BUS shield uses the FRDM-KL25Z's PTD4 pin for its (active low) interrupt capability.
+     * The Seeed Studio CAN-BUS shield is an Arduino compatible shield and connects to the FRDM-KL25Z SPI0 interface using pins PTD2 (mosi) PTD3 (miso) PTD1 (clk). The Active low chip select normally connects to the FRDM-KL25Z's PTD0 pin, but there is an option on the Seeed Studio CAN-BUS shield to connect to the PTD5 pin. The CAN-BUS shield uses the FRDM-KL25Z's PTD4 pin for its (active low) interrupt capability. The defaults allow you to plug the Seeed Studios' CAN-BUS Shield into a FRDM-KL25Z mbed and it to work without specifying any parameters.
      *
-     * @param ncs Active low chip select (This function accepts mbed (PTD0/5) and Seeed Studios' (CS/IO9) pin names. The default value would be PTD0 or CS but if you change the link on the Seeed Studios CAN-BUS shield you should use a volue of PTD5 or IO9 instead).
+     * @param ncs Active low chip select (default SEEED_CAN_CS is FRDM-KL25Z PTD0 pin but if you change the link on the Seeed Studios CAN-BUS shield you should use a value of SEEED_CAN_IO9 or PTD5 instead).
      * @param irq Active low interrupt pin (default SEEED_CAN_IRQ is FRDM-KL25Z PTD4 pin).
      * @param mosi SPI Master Out, Slave In pin  (default SEEED_CAN_MOSI is FRDM-KL25Z PTD2 pin).
      * @param miso SPI Master In, Slave Out pin  (default SEEED_CAN_MISO is FRDM-KL25Z PTD3 pin).
      * @param clk SPI Clock pin (default SEEED_CAN_MISO is FRDM-KL25Z PTD1 pin).
      * @param spiBitrate SPI Clock frequency (default: 1 MHz).
-     * @param canBitrate CAN Bus Clock frequency (default: 100 kHz).
      */
-    SEEED_CAN(PinName ncs, PinName irq=SEEED_CAN_IRQ, PinName mosi=SEEED_CAN_MOSI, PinName miso=SEEED_CAN_MISO, PinName clk=SEEED_CAN_CLK, int spiBitrate=1000000, int canBitrate=100000);
+    SEEED_CAN(PinName ncs=SEEED_CAN_CS, PinName irq=SEEED_CAN_IRQ, PinName mosi=SEEED_CAN_MOSI, PinName miso=SEEED_CAN_MISO, PinName clk=SEEED_CAN_CLK, int spiBitrate=1000000);
 //    virtual ~SEEED_CAN(); // !!! Need a de-constructor for the interrrupt pin !!!
 
-    /** Set the frequency of the CAN interface
+    /** Open initialises the Seeed Studios CAN-BUS Shield.
+     *
+     * @param canBitrate CAN Bus Clock frequency (default: 100 kHz).
+     *
+     *  @returns
+     *    1 if successful,
+     *    0 otherwise
+     */
+    int open(int canBitrate=100000);
+
+    /** Set the CAN bus frequency (Bit Rate)
      *
      *  @param hz The bus frequency in Hertz
      *
@@ -89,28 +96,28 @@
      *    1 if successful,
      *    0 otherwise
      */
-    int frequency(int setBitRate);
+    int frequency(int canBitRate);
 
-    /** Write a CANMessage to the bus.
+    /** Read a CAN bus message from the MCP2515 (if one has been received)
+     *
+     *  @param msg A CANMessage to read to.
+     *
+     *  @returns
+     *    1 if any messages have arrived
+     *    0 if no message arrived,
+     */
+    int read(SEEED_CANMessage &msg);
+
+    /** Write a CAN bus message to the MCP2515 (if there is a free message buffer)
      *
      *  @param msg The CANMessage to write.
      *
      *  @returns
+     *    1 if write was successful
      *    0 if write failed,
-     *    1 if write was successful
      */
     int write(SEEED_CANMessage msg);
 
-    /** Read a CANMessage from the bus.
-     *
-     *  @param msg A CANMessage to read to.
-     *
-     *  @returns
-     *    0 if no message arrived,
-     *    1 if message arrived
-     */
-    int read(SEEED_CANMessage &msg);
-
     /** Configure one of the Accpetance Masks (0 or 1)
      *
      *  @param maskNum The number of the Acceptance Mask to configure (Acceptance Mask 0 is associated with Filters 0 and 1, Acceptance Mask 1 is associated with Filters 2 through 5).
@@ -118,10 +125,10 @@
      *  @param format Describes if the Acceptance Mask is for a standard (CANStandard) or extended (CANExtended) CAN message frame format (default: CANStandard).
      *
      *  @returns
+     *    1 if Acceptance Mask was set
      *    0 if the Acceptance Mask could not be set
-     *    1 if Acceptance Mask was set
      */
-    int Mask(int maskNum, int canId, CANFormat format = CANStandard);
+    int mask(int maskNum, int canId, CANFormat format = CANStandard);
 
     /** Configure one of the Acceptance Filters (0 through 5)
      *
@@ -130,24 +137,30 @@
      *  @param format Describes if the Acceptance Filter is for a standard (CANStandard) or extended (CANExtended) CAN message frame format (default: CANStandard).
      *
      *  @returns
+     *    1 if Acceptance Filter was set
      *    0 if the Acceptance Filter could not be set
-     *    1 if Acceptance Filter was set
      */
-    int Filter(int filterNum, int canId, CANFormat format = CANStandard);
+    int filter(int filterNum, int canId, CANFormat format = CANStandard);
 
     /** Returns number of message reception (read) errors to detect read overflow errors.
+     *
+     *  @returns
+     *    Number of reception errors
      */
     unsigned char rderror(void);
 
     /** Returns number of message transmission (write) errors to detect write overflow errors.
+     *
+     *  @returns
+     *    Number of transmission errors
      */
     unsigned char tderror(void);
 
-    /** Check if any type of error
+    /** Check if any type of error has been detected on the CAN bus
      *
      *  @returns
+     *    1 if any type of error has been detected
      *    0 if no errors
-     *    1 if any type of error has been detected
      */
     int errors(void);
 
@@ -166,13 +179,13 @@
         Reset
     };
 
-    /** Change CAN operation to the specified mode
+    /** Change the Seeed Studios CAN-BUS shield CAN operation mode
      *
      *  @param mode The new operation mode (SEED_CAN::Normal, SEED_CAN::Sleep, SEED_CAN::Loopback, SEED_CAN::Monitor, SEEED_CAN::Reset)
      *
      *  @returns
+     *    1 if mode change was successful
      *    0 if mode change failed or unsupported,
-     *    1 if mode change was successful
      */
     int mode(Mode mode);
 
@@ -188,16 +201,14 @@
         IdIrq
     };
 
-    /** Attach a function to call whenever a CAN frame received interrupt is
-     *  generated.
+    /** Attach a function to call whenever a CAN frame received interrupt is generated.
      *
      *  @param fptr A pointer to a void function, or 0 to set as none
      *  @param event Which CAN interrupt to attach the member function to (CAN::RxIrq for message received, CAN::TxIrq for transmitted or aborted, CAN::EwIrq for error warning, CAN::DoIrq for data overrun, CAN::WuIrq for wake-up, CAN::EpIrq for error passive, CAN::AlIrq for arbitration lost, CAN::BeIrq for bus error)
      */
     void attach(void (*fptr)(void), IrqType type=RxIrq);
 
-    /** Attach a member function to call whenever a CAN frame received interrupt
-     *  is generated.
+    /** Attach a member function to call whenever a CAN frame received interrupt is generated.
      *
      *  @param tptr pointer to the object to call the member function on
      *  @param mptr pointer to the member function to be called
@@ -205,18 +216,23 @@
      */
     template<typename T>
     void attach(T* tptr, void (T::*mptr)(void), IrqType type=RxIrq) {
-        _can.irq.fall(tptr, mptr);
-/*        if((mptr != NULL) && (tptr != NULL)) {
-            _irq[type].attach(tptr, mptr);
-            can_irq_set(&_can, (CanIrqType)type, 1);
-        } else {
-            can_irq_set(&_can, (CanIrqType)type, 0);
-        }*/
+        _callback_irq.attach(tptr, mptr);
+        mcpWrite(obj, MCP_CANINTE, MCP_RX0IF | MCP_RX1IF);                  // RX buffers can generate a interrupt
+//        _can.irq.fall(tptr, mptr);
+        /*        if((mptr != NULL) && (tptr != NULL)) {
+                    _irq[type].attach(tptr, mptr);
+                    can_irq_set(&_can, (CanIrqType)type, 1);
+                } else {
+                    can_irq_set(&_can, (CanIrqType)type, 0);
+                }*/
     }
 
+    void call_irq(void) { _callback_irq.call(); }
+    
 protected:
-    SPI     _spi;
-    can_t   _can;
+    SPI             _spi;
+    can_t           _can;
+    FunctionPointer _callback_irq;
 
 };
 
--- a/seeed_can_api.cpp	Tue Nov 05 22:37:35 2013 +0000
+++ b/seeed_can_api.cpp	Wed Nov 06 20:16:11 2013 +0000
@@ -42,20 +42,16 @@
     for (uint32_t i = 0; i < 3; i++) {                                  // Clear all CAN TX buffers
         mcpWriteMultiple(obj, canBuffer[i], y, sizeof(x) );             // using empty CAN message (as an array)
     }
-    mcpWrite(obj, MCP_CANINTE, MCP_RX0IF | MCP_RX1IF);                  // RX buffers can generate a interrupt
-#if (DEBUG_RXANY==1)
-    // enable both receive-buffers to receive any message and enable rollover
-    mcpBitModify(obj, MCP_RXB0CTRL, MCP_RXB_RX_MASK | MCP_RXB_BUKT_MASK, MCP_RXB_RX_ANY | MCP_RXB_BUKT_MASK);
-    mcpBitModify(obj, MCP_RXB1CTRL, MCP_RXB_RX_MASK, MCP_RXB_RX_ANY);
-#else
-    // enable both receive-buffers to receive messages with std. and ext. identifiers and enable rollover
+    // enable both receive-buffers, using filters to receive messages with std. and ext. identifiers that meet the filter criteria and enable rollover from RXB0 to RXB1 if RXB0 is full
     mcpBitModify(obj, MCP_RXB0CTRL, MCP_RXB_RX_MASK | MCP_RXB_BUKT_MASK, MCP_RXB_RX_STDEXT | MCP_RXB_BUKT_MASK );
     mcpBitModify(obj, MCP_RXB1CTRL, MCP_RXB_RX_MASK, MCP_RXB_RX_STDEXT);
-#endif
 #ifdef DEBUG
     printf("Setting bit rate\r\n");
 #endif
-    return (mcpSetBitRate(obj, bitRate)) ? 1 : 0;                       // set baudrate and return
+    if (!mcpSetBitRate(obj, bitRate)) {                                 // set baudrate
+        return 0;
+    }
+    return mcpSetMode(obj, MODE_NORMAL) ? 1 : 0;                        // set Normal mode and return
 }
 
 /**  set MCP2515 operation mode
@@ -130,14 +126,15 @@
     uint32_t bestCanRate = 0;
     uint32_t minBRP = (MCP_CLOCK_FREQ / (2 * MCP_MAX_TIME_QUANTA * bitRate));
     uint32_t maxBRP = (MCP_CLOCK_FREQ / (2 * MCP_MIN_TIME_QUANTA * bitRate));
-    
-    #ifdef DEBUG
-        printf("Setting configuration mode\r\n");
-    #endif
-        if(!mcpSetMode(obj, MODE_CONFIG)) {                                      // Go into configuration mode
-            return 0;
-        }
-    
+
+#ifdef DEBUG
+    printf("Setting configuration mode\r\n");
+#endif
+    uint8_t initialMode = mcpRead(obj, MCP_CANCTRL) & MODE_MASK;        // Store the current operation mode
+    if(!mcpSetMode(obj, MODE_CONFIG)) {                             // Go into configuration mode
+        return 0;
+    }
+
     for (uint32_t i = 0; i < sizeof(x); i++) y[i] = NULL;               // Initialise CANtiming (btlmode, sjw and sam all = 0)
     if ((bitRate < CAN_MIN_RATE) || (bitRate > CAN_MAX_RATE)) {
 #ifdef DEBUG
@@ -171,7 +168,7 @@
     printf("Syncseg: 1\tPropSeg: %d\tPhaseSeg1: %d\tPhaseSeg2: %d\r\n", (x.prseg+1), (x.phseg1+1), (x.phseg1+1));
     printf("Setting normal mode\r\n");
 #endif
-    return (mcpSetMode(obj, MODE_NORMAL)) ? 1 : 0;                      // desired bit rate set enter normal mode and return
+    return (mcpSetMode(obj, initialMode)) ? 1 : 0;                      // desired bit rate set enter normal mode and return
 }
 
 /** write a CAN id to a mask, filter or transmit buffer
@@ -322,11 +319,12 @@
 #ifdef DEBUG
     printf("Begin to set Mask!!\r\n");
 #endif
+    uint8_t initialMode = mcpRead(obj, MCP_CANCTRL) & MODE_MASK;        // Store the current operation mode
     if(!mcpSetMode(obj, MODE_CONFIG)) {
         return 0;
     }
     mcpWriteId(obj, mask[num], ext, ulData);
-    if(!mcpSetMode(obj, MODE_NORMAL)) {
+    if(!mcpSetMode(obj, initialMode)) {
         return 0;
     }
 #ifdef DEBUG
@@ -350,11 +348,12 @@
 #ifdef DEBUG
     printf("Begin to set Filter!!\r\n");
 #endif
+    uint8_t initialMode = mcpRead(obj, MCP_CANCTRL) & MODE_MASK;        // Store the current operation mode
     if(!mcpSetMode(obj, MODE_CONFIG)) {
         return 0;
     }
     mcpWriteId(obj, filter[num], ext, ulData);
-    if(!mcpSetMode(obj, MODE_NORMAL)) {
+    if(!mcpSetMode(obj, initialMode)) {
         return 0;
     }
 #ifdef DEBUG
--- a/seeed_can_api.h	Tue Nov 05 22:37:35 2013 +0000
+++ b/seeed_can_api.h	Wed Nov 06 20:16:11 2013 +0000
@@ -33,7 +33,7 @@
 //  Process and manipulate the struct in an ordered way
 //  Copy the struct to/from the MCP2512 as an array
 
-/// Type definition to hold an MCP2515 CAN id structure
+/// Type definition to hold an MCP2515 Timing Register set structure
     struct MCP_CANtiming {
         uint8_t phseg2    : 3;      // PS2 length bits 2..0 (PHSEG2 + 1) Tq (minimum valid setting is 2 Tq)
         uint8_t reserved1 : 3;      // Unused bits (read as '0')
@@ -64,7 +64,7 @@
     };
     typedef struct MCP_CANid CANid;
 
-/// Type definition to hold an MCP2515 CAN message structure
+/// Type definition to hold an MCP2515 CAN id structure
     struct MCP_CANMsg {
         CANid id;
         uint8_t dlc       : 4;      // Bits 3..0: DLC - Data Length Counter
@@ -129,7 +129,6 @@
     void mcpMonitor(can_t *obj, const bool silent);                     // Select between monitor (silent = 1) and normal (silent = 0) modes
     uint8_t mcpMode(can_t *obj, const CANMode mode);                    // Change CAN operation to the specified mode
 
-
 #ifdef __cplusplus
 };
 #endif
--- a/seeed_can_defs.h	Tue Nov 05 22:37:35 2013 +0000
+++ b/seeed_can_defs.h	Wed Nov 06 20:16:11 2013 +0000
@@ -24,12 +24,12 @@
 
     /** FRDM-KL25Z port pins used by Seeed Studios CAN-BUS Shield
      */
+#define SEEED_CAN_CS        PTD0
+#define SEEED_CAN_CLK       PTD1
 #define SEEED_CAN_MOSI      PTD2
 #define SEEED_CAN_MISO      PTD3
-#define SEEED_CAN_CLK       PTD1
-#define SEEED_CAN_CS        PTD0
+#define SEEED_CAN_IRQ       PTD4
 #define SEEED_CAN_IO9       PTD5
-#define SEEED_CAN_IRQ       PTD4
     /** Define MCP2515 register addresses
      */
 #define MCP_RXF0SIDH        0x00
--- a/seeed_can_spi.h	Tue Nov 05 22:37:35 2013 +0000
+++ b/seeed_can_spi.h	Wed Nov 06 20:16:11 2013 +0000
@@ -24,7 +24,8 @@
 
     /** CAN driver typedefs
      */
-    struct Seeed_MCP_CAN_Shield {
+ /// Type definition to hold a Seeed Studios CAN-BUS Shield connections and resources structure
+   struct Seeed_MCP_CAN_Shield {
         SPI             spi;
         DigitalOut      ncs;
         InterruptIn     irq;