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
Revision 1:ad71faa09868, committed 2013-11-06
- 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
--- 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;