315 lines
11 KiB
C
315 lines
11 KiB
C
|
/*
|
||
|
Copyright (c) 2013 Arduino. All right reserved.
|
||
|
|
||
|
This library is free software; you can redistribute it and/or
|
||
|
modify it under the terms of the GNU Lesser General Public
|
||
|
License as published by the Free Software Foundation; either
|
||
|
version 2.1 of the License, or (at your option) any later version.
|
||
|
|
||
|
This library is distributed in the hope that it will be useful,
|
||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||
|
See the GNU Lesser General Public License for more details.
|
||
|
|
||
|
You should have received a copy of the GNU Lesser General Public
|
||
|
License along with this library; if not, write to the Free Software
|
||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||
|
*/
|
||
|
|
||
|
#ifndef _CAN_LIBRARY_
|
||
|
#define _CAN_LIBRARY_
|
||
|
|
||
|
#include <Arduino.h>
|
||
|
|
||
|
//add some extra stuff that is needed for Arduino 1.5.2
|
||
|
#ifndef PINS_CAN0
|
||
|
static const uint8_t CAN1RX = 88;
|
||
|
static const uint8_t CAN1TX = 89;
|
||
|
|
||
|
// CAN0
|
||
|
#define PINS_CAN0 (90u)
|
||
|
// CAN1
|
||
|
#define PINS_CAN1 (91u)
|
||
|
#define ARDUINO152
|
||
|
#endif
|
||
|
|
||
|
#define CAN Can0
|
||
|
#define CAN2 Can1
|
||
|
|
||
|
#define CAN0_EN 50 //these enable pins match most all recent EVTV boards (EVTVDue, CAN Due 2.0)
|
||
|
#define CAN1_EN 48 //they're only defaults, you can set whichever pin you need when calling begin()
|
||
|
|
||
|
/** Define the Mailbox mask for eight mailboxes. */
|
||
|
#define GLOBAL_MAILBOX_MASK 0x000000ff
|
||
|
|
||
|
/** Disable all interrupt mask */
|
||
|
#define CAN_DISABLE_ALL_INTERRUPT_MASK 0xffffffff
|
||
|
|
||
|
/** Define the typical baudrate for CAN communication. */
|
||
|
#ifdef CAN_BPS_500K
|
||
|
#undef CAN_BPS_1000K
|
||
|
#undef CAN_BPS_800K
|
||
|
#undef CAN_BPS_500K
|
||
|
#undef CAN_BPS_250K
|
||
|
#undef CAN_BPS_125K
|
||
|
#undef CAN_BPS_50K
|
||
|
#undef CAN_BPS_33333
|
||
|
#undef CAN_BPS_25K
|
||
|
#undef CAN_BPS_10K
|
||
|
#undef CAN_BPS_5K
|
||
|
#endif
|
||
|
|
||
|
#define CAN_BPS_1000K 1000000
|
||
|
#define CAN_BPS_800K 800000
|
||
|
#define CAN_BPS_500K 500000
|
||
|
#define CAN_BPS_250K 250000
|
||
|
#define CAN_BPS_125K 125000
|
||
|
#define CAN_BPS_50K 50000
|
||
|
#define CAN_BPS_33333 33333
|
||
|
#define CAN_BPS_25K 25000
|
||
|
#define CAN_BPS_10K 10000
|
||
|
#define CAN_BPS_5K 5000
|
||
|
|
||
|
#define CAN_DEFAULT_BAUD CAN_BPS_250K
|
||
|
|
||
|
/** Define the mailbox mode. */
|
||
|
#define CAN_MB_DISABLE_MODE 0
|
||
|
#define CAN_MB_RX_MODE 1
|
||
|
#define CAN_MB_RX_OVER_WR_MODE 2
|
||
|
#define CAN_MB_TX_MODE 3
|
||
|
#define CAN_MB_CONSUMER_MODE 4
|
||
|
#define CAN_MB_PRODUCER_MODE 5
|
||
|
|
||
|
/** Define CAN mailbox transfer status code. */
|
||
|
#define CAN_MAILBOX_TRANSFER_OK 0 //! Read from or write into mailbox successfully.
|
||
|
#define CAN_MAILBOX_NOT_READY 0x01 //! Receiver is empty or transmitter is busy.
|
||
|
#define CAN_MAILBOX_RX_OVER 0x02 //! Message overwriting happens or there're messages lost in different receive modes.
|
||
|
#define CAN_MAILBOX_RX_NEED_RD_AGAIN 0x04 //! Application needs to re-read the data register in Receive with Overwrite mode.
|
||
|
|
||
|
#define SIZE_RX_BUFFER 32 //RX incoming ring buffer is this big
|
||
|
#define SIZE_TX_BUFFER 16 //TX ring buffer is this big
|
||
|
#define SIZE_LISTENERS 4 //number of classes that can register as listeners with this class
|
||
|
|
||
|
/** Define the timemark mask. */
|
||
|
#define TIMEMARK_MASK 0x0000ffff
|
||
|
|
||
|
/* CAN timeout for synchronization. */
|
||
|
#define CAN_TIMEOUT 100000
|
||
|
|
||
|
/** The max value for CAN baudrate prescale. */
|
||
|
#define CAN_BAUDRATE_MAX_DIV 128
|
||
|
|
||
|
/** Define the scope for TQ. */
|
||
|
#define CAN_MIN_TQ_NUM 8
|
||
|
#define CAN_MAX_TQ_NUM 25
|
||
|
|
||
|
/** Define the fixed bit time value. */
|
||
|
#define CAN_BIT_SYNC 1
|
||
|
#define CAN_BIT_IPT 2
|
||
|
|
||
|
typedef struct {
|
||
|
uint8_t uc_tq; //! CAN_BIT_SYNC + uc_prog + uc_phase1 + uc_phase2 = uc_tq, 8 <= uc_tq <= 25.
|
||
|
uint8_t uc_prog; //! Propagation segment, (3-bits + 1), 1~8;
|
||
|
uint8_t uc_phase1; //! Phase segment 1, (3-bits + 1), 1~8;
|
||
|
uint8_t uc_phase2; //! Phase segment 2, (3-bits + 1), 1~8, CAN_BIT_IPT <= uc_phase2;
|
||
|
uint8_t uc_sjw; //! Resynchronization jump width, (2-bits + 1), min(uc_phase1, 4);
|
||
|
uint8_t uc_sp; //! Sample point value, 0~100 in percent.
|
||
|
} can_bit_timing_t;
|
||
|
|
||
|
|
||
|
/** Values of bit time register for different baudrates, Sample point = ((1 + uc_prog + uc_phase1) / uc_tq) * 100%. */
|
||
|
const can_bit_timing_t can_bit_time[] = {
|
||
|
{8, (2 + 1), (1 + 1), (1 + 1), (2 + 1), 75},
|
||
|
{9, (1 + 1), (2 + 1), (2 + 1), (1 + 1), 67},
|
||
|
{10, (2 + 1), (2 + 1), (2 + 1), (2 + 1), 70},
|
||
|
{11, (3 + 1), (2 + 1), (2 + 1), (3 + 1), 72},
|
||
|
{12, (2 + 1), (3 + 1), (3 + 1), (3 + 1), 67},
|
||
|
{13, (3 + 1), (3 + 1), (3 + 1), (3 + 1), 77},
|
||
|
{14, (3 + 1), (3 + 1), (4 + 1), (3 + 1), 64},
|
||
|
{15, (3 + 1), (4 + 1), (4 + 1), (3 + 1), 67},
|
||
|
{16, (4 + 1), (4 + 1), (4 + 1), (3 + 1), 69},
|
||
|
{17, (5 + 1), (4 + 1), (4 + 1), (3 + 1), 71},
|
||
|
{18, (4 + 1), (5 + 1), (5 + 1), (3 + 1), 67},
|
||
|
{19, (5 + 1), (5 + 1), (5 + 1), (3 + 1), 68},
|
||
|
{20, (6 + 1), (5 + 1), (5 + 1), (3 + 1), 70},
|
||
|
{21, (7 + 1), (5 + 1), (5 + 1), (3 + 1), 71},
|
||
|
{22, (6 + 1), (6 + 1), (6 + 1), (3 + 1), 68},
|
||
|
{23, (7 + 1), (7 + 1), (6 + 1), (3 + 1), 70},
|
||
|
{24, (6 + 1), (7 + 1), (7 + 1), (3 + 1), 67},
|
||
|
{25, (7 + 1), (7 + 1), (7 + 1), (3 + 1), 68}
|
||
|
};
|
||
|
|
||
|
//This is architecture specific. DO NOT USE THIS UNION ON ANYTHING OTHER THAN THE CORTEX M3 / Arduino Due
|
||
|
//UNLESS YOU DOUBLE CHECK THINGS!
|
||
|
typedef union {
|
||
|
uint64_t value;
|
||
|
struct {
|
||
|
uint32_t low;
|
||
|
uint32_t high;
|
||
|
};
|
||
|
struct {
|
||
|
uint16_t s0;
|
||
|
uint16_t s1;
|
||
|
uint16_t s2;
|
||
|
uint16_t s3;
|
||
|
};
|
||
|
uint8_t bytes[8];
|
||
|
uint8_t byte[8]; //alternate name so you can omit the s if you feel it makes more sense
|
||
|
} BytesUnion;
|
||
|
|
||
|
typedef struct
|
||
|
{
|
||
|
uint32_t id; // EID if ide set, SID otherwise
|
||
|
uint32_t fid; // family ID
|
||
|
uint8_t rtr; // Remote Transmission Request
|
||
|
uint8_t priority; // Priority but only important for TX frames and then only for special uses.
|
||
|
uint8_t extended; // Extended ID flag
|
||
|
uint8_t length; // Number of data bytes
|
||
|
BytesUnion data; // 64 bits - lots of ways to access it.
|
||
|
} CAN_FRAME;
|
||
|
|
||
|
class CANListener
|
||
|
{
|
||
|
public:
|
||
|
CANListener();
|
||
|
|
||
|
virtual void gotFrame(CAN_FRAME *frame, int mailbox);
|
||
|
|
||
|
void attachMBHandler(uint8_t mailBox);
|
||
|
void detachMBHandler(uint8_t mailBox);
|
||
|
void attachGeneralHandler();
|
||
|
void detachGeneralHandler();
|
||
|
|
||
|
private:
|
||
|
int callbacksActive; //bitfield letting the code know which callbacks to actually try to use (for object oriented callbacks only)
|
||
|
|
||
|
friend class CANRaw; //class has to have access to the the guts of this one
|
||
|
};
|
||
|
|
||
|
class CANRaw
|
||
|
{
|
||
|
protected:
|
||
|
int numTXBoxes; //There are 8 mailboxes, anything not TX will be set RX
|
||
|
|
||
|
private:
|
||
|
/* CAN peripheral, set by constructor */
|
||
|
Can* m_pCan ;
|
||
|
|
||
|
volatile CAN_FRAME rx_frame_buff[SIZE_RX_BUFFER];
|
||
|
volatile CAN_FRAME tx_frame_buff[SIZE_TX_BUFFER];
|
||
|
|
||
|
volatile uint16_t rx_buffer_head, rx_buffer_tail;
|
||
|
volatile uint16_t tx_buffer_head, tx_buffer_tail;
|
||
|
void mailbox_int_handler(uint8_t mb, uint32_t ul_status);
|
||
|
|
||
|
uint8_t enablePin;
|
||
|
uint32_t busSpeed; //what speed is the bus currently initialized at? 0 if it is off right now
|
||
|
|
||
|
uint32_t write_id; //public storage for an id. Will be used by the write function to set which ID to send to.
|
||
|
bool bigEndian;
|
||
|
|
||
|
void (*cbCANFrame[9])(CAN_FRAME *); //8 mailboxes plus an optional catch all
|
||
|
CANListener *listener[SIZE_LISTENERS];
|
||
|
|
||
|
public:
|
||
|
|
||
|
// Constructor
|
||
|
CANRaw( Can* pCan, uint32_t En);
|
||
|
|
||
|
int setRXFilter(uint32_t id, uint32_t mask, bool extended);
|
||
|
int setRXFilter(uint8_t mailbox, uint32_t id, uint32_t mask, bool extended);
|
||
|
int watchFor(); //allow anything through
|
||
|
int watchFor(uint32_t id); //allow just this ID through (automatic determination of extended status)
|
||
|
int watchFor(uint32_t id, uint32_t mask); //allow a range of ids through
|
||
|
int watchForRange(uint32_t id1, uint32_t id2); //try to allow the range from id1 to id2 - automatically determine base ID and mask
|
||
|
|
||
|
void setNumTXBoxes(int txboxes);
|
||
|
int findFreeRXMailbox();
|
||
|
uint8_t mailbox_get_mode(uint8_t uc_index);
|
||
|
uint32_t mailbox_get_id(uint8_t uc_index);
|
||
|
uint32_t getMailboxIer(int8_t mailbox);
|
||
|
uint32_t set_baudrate(uint32_t ul_baudrate);
|
||
|
|
||
|
uint32_t init(uint32_t ul_baudrate);
|
||
|
uint32_t begin();
|
||
|
uint32_t begin(uint32_t baudrate);
|
||
|
uint32_t begin(uint32_t baudrate, uint8_t enablePin);
|
||
|
uint32_t getBusSpeed();
|
||
|
|
||
|
void enable();
|
||
|
void disable();
|
||
|
|
||
|
bool sendFrame(CAN_FRAME& txFrame);
|
||
|
void setWriteID(uint32_t id);
|
||
|
template <typename t> void write(t inputValue); //write a variable # of bytes out in a frame. Uses id as the ID.
|
||
|
void setBigEndian(bool);
|
||
|
|
||
|
void setCallback(int mailbox, void (*cb)(CAN_FRAME *));
|
||
|
void setGeneralCallback(void (*cb)(CAN_FRAME *));
|
||
|
//note that these below versions still use mailbox number. There isn't a good way around this.
|
||
|
void attachCANInterrupt(void (*cb)(CAN_FRAME *)); //alternative callname for setGeneralCallback
|
||
|
void attachCANInterrupt(uint8_t mailBox, void (*cb)(CAN_FRAME *));
|
||
|
void detachCANInterrupt(uint8_t mailBox);
|
||
|
|
||
|
//now, object oriented versions to make OO projects easier
|
||
|
boolean attachObj(CANListener *listener);
|
||
|
boolean detachObj(CANListener *listener);
|
||
|
|
||
|
void reset_all_mailbox();
|
||
|
void interruptHandler();
|
||
|
bool rx_avail();
|
||
|
int available(); //like rx_avail but returns the number of waiting frames
|
||
|
|
||
|
uint32_t get_rx_buff(CAN_FRAME &);
|
||
|
uint32_t read(CAN_FRAME &);
|
||
|
|
||
|
//misc old cruft kept around just in case anyone actually used any of it in older code.
|
||
|
//some are used within the functions above. Unless you really know of a good reason to use
|
||
|
//any of these you probably should steer clear of them.
|
||
|
void disable_low_power_mode();
|
||
|
void enable_low_power_mode();
|
||
|
void disable_autobaud_listen_mode();
|
||
|
void enable_autobaud_listen_mode();
|
||
|
void disable_overload_frame();
|
||
|
void enable_overload_frame();
|
||
|
void set_timestamp_capture_point(uint32_t ul_flag);
|
||
|
void disable_time_triggered_mode();
|
||
|
void enable_time_triggered_mode();
|
||
|
void disable_timer_freeze();
|
||
|
void enable_timer_freeze();
|
||
|
void disable_tx_repeat();
|
||
|
void enable_tx_repeat();
|
||
|
void set_rx_sync_stage(uint32_t ul_stage);
|
||
|
void enable_interrupt(uint32_t dw_mask);
|
||
|
void disable_interrupt(uint32_t dw_mask);
|
||
|
uint32_t get_interrupt_mask();
|
||
|
uint32_t get_status();
|
||
|
uint32_t get_internal_timer_value();
|
||
|
uint32_t get_timestamp_value();
|
||
|
uint8_t get_tx_error_cnt();
|
||
|
uint8_t get_rx_error_cnt();
|
||
|
void reset_internal_timer();
|
||
|
void global_send_transfer_cmd(uint8_t uc_mask);
|
||
|
void global_send_abort_cmd(uint8_t uc_mask);
|
||
|
void mailbox_set_timemark(uint8_t uc_index, uint16_t us_cnt);
|
||
|
uint32_t mailbox_get_status(uint8_t uc_index);
|
||
|
void mailbox_send_transfer_cmd(uint8_t uc_index);
|
||
|
void mailbox_send_abort_cmd(uint8_t uc_index);
|
||
|
void mailbox_init(uint8_t uc_index);
|
||
|
uint32_t mailbox_read(uint8_t uc_index, volatile CAN_FRAME *rxframe);
|
||
|
uint32_t mailbox_tx_frame(uint8_t uc_index);
|
||
|
void mailbox_set_id(uint8_t uc_index, uint32_t id, bool extended);
|
||
|
void mailbox_set_priority(uint8_t uc_index, uint8_t pri);
|
||
|
void mailbox_set_accept_mask(uint8_t uc_index, uint32_t mask, bool ext);
|
||
|
void mailbox_set_mode(uint8_t uc_index, uint8_t mode);
|
||
|
void mailbox_set_databyte(uint8_t uc_index, uint8_t bytepos, uint8_t val);
|
||
|
void mailbox_set_datalen(uint8_t uc_index, uint8_t dlen);
|
||
|
void mailbox_set_datal(uint8_t uc_index, uint32_t val);
|
||
|
void mailbox_set_datah(uint8_t uc_index, uint32_t val);
|
||
|
};
|
||
|
|
||
|
extern CANRaw Can0;
|
||
|
extern CANRaw Can1;
|
||
|
|
||
|
#endif // _CAN_LIBRARY_
|