Here a CAN driver with basic interfaces. Absolutely no warranty! If you have ideas for improvement, let me know.
I only need standard format frame in my application.
If you want to use extended frames, use the MODULE_CAN->MBX_CTRL.FCTRL.TX_RX.EXT structure and set MBX_CTRL.FCTRL.FIR.B.FF to 1.
API definitions
Code: Select all
/** \brief CAN Frame structure */
typedef struct {
uint32_t MsgID; /**< \brief Message ID */
uint8_t DLC; /**< \brief Length */
union {
uint8_t u8[8]; /**< \brief Payload byte access*/
uint32_t u32[2]; /**< \brief Payload u32 access*/
} data;
}CAN_frame_t;
/**
* \brief Initialize the CAN Module
*
* \return 0 CAN Module had been initialized
*/
int CAN_init(void);
/**
* \brief Send a can frame
*
* \param p_frame Pointer to the frame to be send, see #CAN_frame_t
* \return Frame has been written to the module
*/
int CAN_write_frame(const CAN_frame_t* p_frame);
/**
* \brief Stops the CAN Module
*
* \return 0 CAN Module was stopped
*/
int CAN_stop(void);
Configuration
Code: Select all
/** \brief CAN Node Bus speed */
typedef enum {
CAN_SPEED_250KBPS, /**< \brief CAN Node runs at 250kBit/s. */
CAN_SPEED_500KBPS, /**< \brief CAN Node runs at 500kBit/s. */
CAN_SPEED_1000KBPS /**< \brief CAN Node runs at 1000kBit/s. */
}CAN_speed_t;
/** \brief CAN configuration structure */
typedef struct {
CAN_speed_t speed; /**< \brief CAN speed. */
gpio_num_t tx_pin_id; /**< \brief TX pin. */
gpio_num_t rx_pin_id; /**< \brief RX pin. */
QueueHandle_t rx_queue; /**< \brief Handler to FreeRTOS RX queue. */
}CAN_device_t;
extern CAN_device_t CAN_cfg;
CAN_device_t CAN_cfg = {
.speed=CAN_SPEED_500KBPS,
.tx_pin_id = GPIO_NUM_5,
.rx_pin_id = GPIO_NUM_4,
.rx_queue=NULL,
};
Regdef
Code: Select all
/** \brief Start address of CAN registers */
#define MODULE_CAN ((volatile CAN_Module_t *)0x3ff6b000)
/** \brief Interrupt status register */
typedef enum {
__CAN_IRQ_RX= BIT(0), /**< \brief RX Interrupt */
__CAN_IRQ_TX= BIT(1), /**< \brief TX Interrupt */
__CAN_IRQ_ERR= BIT(2), /**< \brief Error Interrupt */
__CAN_IRQ_DATA_OVERRUN= BIT(3), /**< \brief Date Overrun Interrupt */
__CAN_IRQ_WAKEUP= BIT(4), /**< \brief Wakeup Interrupt */
__CAN_IRQ_ERR_PASSIVE= BIT(5), /**< \brief Passive Error Interrupt */
__CAN_IRQ_ARB_LOST= BIT(6), /**< \brief Arbitration lost interrupt */
__CAN_IRQ_BUS_ERR= BIT(7), /**< \brief Bus error Interrupt */
}__CAN_IRQ_t;
/** \brief OCMODE options. */
typedef enum {
__CAN_OC_BOM=0b00, /**< \brief bi-phase output mode */
__CAN_OC_TOM=0b01, /**< \brief test output mode */
__CAN_OC_NOM=0b10, /**< \brief normal output mode */
__CAN_OC_COM=0b11, /**< \brief clock output mode */
}__CAN_OCMODE_t;
/**
* CAN controller (SJA1000).
*/
typedef struct {
union{uint32_t U; /**< \brief Unsigned access */
struct {
unsigned int RM:1; /**< \brief MOD.0 Reset Mode */
unsigned int LOM:1; /**< \brief MOD.1 Listen Only Mode */
unsigned int STM:1; /**< \brief MOD.2 Self Test Mode */
unsigned int AFM:1; /**< \brief MOD.3 Acceptance Filter Mode */
unsigned int SM:1; /**< \brief MOD.4 Sleep Mode */
unsigned int reserved_27:27; /**< \brief \internal Reserved */
} B;
} MOD;
union{uint32_t U; /**< \brief Unsigned access */
struct {
unsigned int TR:1; /**< \brief CMR.0 Transmission Request */
unsigned int AT:1; /**< \brief CMR.1 Abort Transmission */
unsigned int RRB:1; /**< \brief CMR.2 Release Receive Buffer */
unsigned int CDO:1; /**< \brief CMR.3 Clear Data Overrun */
unsigned int GTS:1; /**< \brief CMR.4 Go To Sleep */
unsigned int reserved_27:27; /**< \brief \internal Reserved */
} B;
} CMR;
union{uint32_t U; /**< \brief Unsigned access */
struct {
unsigned int RBS:1; /**< \brief SR.0 Receive Buffer Status */
unsigned int DOS:1; /**< \brief SR.1 Data Overrun Status */
unsigned int TBS:1; /**< \brief SR.2 Transmit Buffer Status */
unsigned int TCS:1; /**< \brief SR.3 Transmission Complete Status */
unsigned int RS:1; /**< \brief SR.4 Receive Status */
unsigned int TS:1; /**< \brief SR.5 Transmit Status */
unsigned int ES:1; /**< \brief SR.6 Error Status */
unsigned int BS:1; /**< \brief SR.7 Bus Status */
unsigned int reserved_24:24; /**< \brief \internal Reserved */
} B;
} SR;
union{uint32_t U; /**< \brief Unsigned access */
struct {
unsigned int RI:1; /**< \brief IR.0 Receive Interrupt */
unsigned int TI:1; /**< \brief IR.1 Transmit Interrupt */
unsigned int EI:1; /**< \brief IR.2 Error Interrupt */
unsigned int DOI:1; /**< \brief IR.3 Data Overrun Interrupt */
unsigned int WUI:1; /**< \brief IR.4 Wake-Up Interrupt */
unsigned int EPI:1; /**< \brief IR.5 Error Passive Interrupt */
unsigned int ALI:1; /**< \brief IR.6 Arbitration Lost Interrupt */
unsigned int BEI:1; /**< \brief IR.7 Bus Error Interrupt */
unsigned int reserved_24:24; /**< \brief \internal Reserved */
} B;
} IR;
union{uint32_t U; /**< \brief Unsigned access */
struct {
unsigned int RIE:1; /**< \brief IER.0 Receive Interrupt Enable */
unsigned int TIE:1; /**< \brief IER.1 Transmit Interrupt Enable */
unsigned int EIE:1; /**< \brief IER.2 Error Interrupt Enable */
unsigned int DOIE:1; /**< \brief IER.3 Data Overrun Interrupt Enable */
unsigned int WUIE:1; /**< \brief IER.4 Wake-Up Interrupt Enable */
unsigned int EPIE:1; /**< \brief IER.5 Error Passive Interrupt Enable */
unsigned int ALIE:1; /**< \brief IER.6 Arbitration Lost Interrupt Enable */
unsigned int BEIE:1; /**< \brief IER.7 Bus Error Interrupt Enable */
unsigned int reserved_24:24; /**< \brief \internal Reserved */
} B;
} IER;
uint32_t RESERVED0;
union{uint32_t U; /**< \brief Unsigned access */
struct {
unsigned int BRP:6; /**< \brief BTR0[5:0] Baud Rate Prescaler */
unsigned int SJW:2; /**< \brief BTR0[7:6] Synchronization Jump Width*/
unsigned int reserved_24:24; /**< \brief \internal Reserved */
} B;
} BTR0;
union{uint32_t U; /**< \brief Unsigned access */
struct {
unsigned int TSEG1:4; /**< \brief BTR1[3:0] Timing Segment 1 */
unsigned int TSEG2:3; /**< \brief BTR1[6:4] Timing Segment 2*/
unsigned int SAM:1; /**< \brief BTR1.7 Sampling*/
unsigned int reserved_24:24; /**< \brief \internal Reserved */
} B;
} BTR1;
union{uint32_t U; /**< \brief Unsigned access */
struct {
unsigned int OCMODE:2; /**< \brief OCR[1:0] Output Control Mode, see # */
unsigned int OCPOL0:1; /**< \brief OCR.2 Output Control Polarity 0 */
unsigned int OCTN0:1; /**< \brief OCR.3 Output Control Transistor N0 */
unsigned int OCTP0:1; /**< \brief OCR.4 Output Control Transistor P0 */
unsigned int OCPOL1:1; /**< \brief OCR.5 Output Control Polarity 1 */
unsigned int OCTN1:1; /**< \brief OCR.6 Output Control Transistor N1 */
unsigned int OCTP1:1; /**< \brief OCR.7 Output Control Transistor P1 */
unsigned int reserved_24:24; /**< \brief \internal Reserved */
} B;
} OCR;
uint32_t RESERVED1[2];
union{uint32_t U; /**< \brief Unsigned access */
struct {
unsigned int ALC:8; /**< \brief ALC[7:0] Arbitration Lost Capture */
unsigned int reserved_24:24; /**< \brief \internal Reserved */
} B;
} ALC;
union{uint32_t U; /**< \brief Unsigned access */
struct {
unsigned int ECC:8; /**< \brief ECC[7:0] Error Code Capture */
unsigned int reserved_24:24; /**< \brief \internal Reserved */
} B;
} ECC;
union{uint32_t U; /**< \brief Unsigned access */
struct {
unsigned int EWLR:8; /**< \brief EWLR[7:0] Error Warning Limit */
unsigned int reserved_24:24; /**< \brief \internal Reserved */
} B;
} EWLR;
union{uint32_t U; /**< \brief Unsigned access */
struct {
unsigned int RXERR:8; /**< \brief RXERR[7:0] Receive Error Counter */
unsigned int reserved_24:24; /**< \brief \internal Reserved */
} B;
} RXERR;
union{uint32_t U; /**< \brief Unsigned access */
struct {
unsigned int TXERR:8; /**< \brief TXERR[7:0] Transmit Error Counter */
unsigned int reserved_24:24; /**< \brief \internal Reserved */
} B;
} TXERR;
union {
struct {
uint32_t CODE[4];
uint32_t MASK[4];
uint32_t RESERVED2[5];
} ACC;
struct {
union{uint32_t U; /**< \brief Unsigned access */
struct {
unsigned int DLC:4; /**< \brief [3:0] DLC, Data length container */
unsigned int unknown_2:2; /**< \brief \internal unknown */
unsigned int RTR:1; /**< \brief [6:6] RTR, Remote Transmission Request */
unsigned int FF:1; /**< \brief [7:7] Frame Format */
unsigned int reserved_24:24; /**< \brief \internal Reserved */
} B;
} FIR;
union{
struct {
uint32_t ID[2];
uint32_t data[8];
uint32_t reserved[2];
} STD;
struct {
uint32_t ID[4];
uint32_t data[8];
} EXT;
}TX_RX;
}FCTRL;
} MBX_CTRL;
union{uint32_t U; /**< \brief Unsigned access */
struct {
unsigned int RMC:8; /**< \brief RMC[7:0] RX Message Counter */
unsigned int reserved_24:24; /**< \brief \internal Reserved Enable */
} B;
} RMC;
union{uint32_t U; /**< \brief Unsigned access */
struct {
unsigned int RBSA:8; /**< \brief RBSA[7:0] RX Buffer Start Address */
unsigned int reserved_24:24; /**< \brief \internal Reserved Enable */
} B;
} RBSA;
union{uint32_t U; /**< \brief Unsigned access */
struct {
unsigned int COD:3; /**< \brief CDR[2:0] CLKOUT frequency selector based of fOSC*/
unsigned int COFF:1; /**< \brief CDR.3 CLKOUT off*/
unsigned int reserved_1:1; /**< \brief \internal Reserved */
unsigned int RXINTEN:1; /**< \brief CDR.5 This bit allows the TX1 output to be used as a dedicated receive interrupt output*/
unsigned int CBP:1; /**< \brief CDR.6 allows to bypass the CAN input comparator and is only possible in reset mode.*/
unsigned int CAN_M:1; /**< \brief CDR.7 If CDR.7 is at logic 0 the CAN controller operates in BasicCAN mode. If set to logic 1 the CAN controller operates in PeliCAN mode. Write access is only possible in reset mode*/
unsigned int reserved_24:24; /**< \brief \internal Reserved */
} B;
} CDR;
uint32_t IRAM[2];
}CAN_Module_t;
Init:
Code: Select all
int CAN_init(){
//enable module
SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_CAN_CLK_EN);
CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_CAN_RST);
//configure TX pin
gpio_set_direction(CAN_cfg.tx_pin_id,GPIO_MODE_OUTPUT);
gpio_matrix_out(CAN_cfg.tx_pin_id,CAN_TX_IDX,0,0);
gpio_pad_select_gpio(CAN_cfg.tx_pin_id);
//configure RX pin
gpio_set_direction(CAN_cfg.rx_pin_id,GPIO_MODE_INPUT);
gpio_matrix_in(CAN_cfg.rx_pin_id,CAN_RX_IDX,0);
gpio_pad_select_gpio(CAN_cfg.rx_pin_id);
//set to PELICAN mode
MODULE_CAN->CDR.B.CAN_M=0x1;
//Bus timing configuration
switch(CAN_cfg.speed){
//Values based on http://www.esacademy.com/en/library/calculators/sja1000-timing-calculator.html with 80Mhz Clock
case CAN_SPEED_1000KBPS:
MODULE_CAN->BTR0.B.BRP =0x4;
MODULE_CAN->BTR0.B.SJW =0x1;
MODULE_CAN->BTR1.B.TSEG1 =0x4;
MODULE_CAN->BTR1.B.TSEG2 =0x1;
break;
case CAN_SPEED_500KBPS:
MODULE_CAN->BTR0.B.BRP =0x4;
MODULE_CAN->BTR0.B.SJW =0x1;
MODULE_CAN->BTR1.B.TSEG1 =0xc;
MODULE_CAN->BTR1.B.TSEG2 =0x1;
break;
case CAN_SPEED_250KBPS:
MODULE_CAN->BTR0.B.BRP =0x9;
MODULE_CAN->BTR0.B.SJW =0x1;
MODULE_CAN->BTR1.B.TSEG1 =0xc;
MODULE_CAN->BTR1.B.TSEG2 =0x1;
break;
}
/* Set sampling
* 1 -> triple; the bus is sampled three times; recommended for low/medium speed buses (class A and B) where filtering spikes on the bus line is beneficial
* 0 -> single; the bus is sampled once; recommended for high speed buses (SAE class C)*/
MODULE_CAN->BTR1.B.SAM =0x1;
//enable all interrupts
MODULE_CAN->IER.U = 0xff;
//no acceptance filtering in this demo
MODULE_CAN->MBX_CTRL.ACC.CODE[0] = 0;
MODULE_CAN->MBX_CTRL.ACC.CODE[1] = 0;
MODULE_CAN->MBX_CTRL.ACC.CODE[2] = 0;
MODULE_CAN->MBX_CTRL.ACC.CODE[3] = 0;
MODULE_CAN->MBX_CTRL.ACC.MASK[0] = 0xff;
MODULE_CAN->MBX_CTRL.ACC.MASK[1] = 0xff;
MODULE_CAN->MBX_CTRL.ACC.MASK[2] = 0xff;
MODULE_CAN->MBX_CTRL.ACC.MASK[3] = 0xff;
//set to normal mode
MODULE_CAN->OCR.B.OCMODE=__CAN_OC_NOM;
//clear error counters
MODULE_CAN->TXERR.U = 0;
MODULE_CAN->RXERR.U = 0;
(void)MODULE_CAN->ECC;
//clear interrupt flags
(void)MODULE_CAN->IR.U;
//install CAN ISR
esp_intr_alloc(ETS_CAN_INTR_SOURCE,0,CAN_isr,NULL,NULL);
//Showtime. Release Reset Mode.
MODULE_CAN->MOD.B.RM = 0;
return (0);
}
CAN_ISR:
Code: Select all
static void CAN_isr(void *arg_p){
uint8_t interrupt;
// Read interrupt status and clears flags
interrupt = MODULE_CAN->IR.U;
// Handle TX complete interrupt
if ((interrupt & __CAN_IRQ_TX) != 0) {
}
// Handle RX frame available interrupt
if ((interrupt & __CAN_IRQ_RX) != 0) {
//only handle message if we have a FreeRTOS queue. Be carefull! The Frame is not removed from the FIFO if we stop here!
if (CAN_cfg.rx_queue == NULL)
return;
CAN_read_frame();
}
// Handle error interrupts.
if ((interrupt & (__CAN_IRQ_ERR //0x4
| __CAN_IRQ_DATA_OVERRUN //0x8
| __CAN_IRQ_WAKEUP //0x10
| __CAN_IRQ_ERR_PASSIVE //0x20
| __CAN_IRQ_ARB_LOST //0x40
| __CAN_IRQ_BUS_ERR //0x80
)) != 0) {
}
}
read frame
Code: Select all
static void CAN_read_frame(){
//byte iterator
uint8_t __byte_i;
//frame read buffer
CAN_frame_t __frame;
//only handle standard frames
if(MODULE_CAN->MBX_CTRL.FCTRL.FIR.B.FF==1){
// Let the hardware know the frame has been read.
MODULE_CAN->CMR.B.RRB=1;
return;
}
//Get Message ID
__frame.MsgID = (((uint32_t)MODULE_CAN->MBX_CTRL.FCTRL.TX_RX.STD.ID[0] << 3) | (MODULE_CAN->MBX_CTRL.FCTRL.TX_RX.STD.ID[1]>>5));
//get DLC
__frame.DLC = MODULE_CAN->MBX_CTRL.FCTRL.FIR.B.DLC;
for(__byte_i=0;__byte_i<__frame.DLC;__byte_i++)
__frame.data.u8[__byte_i]=MODULE_CAN->MBX_CTRL.FCTRL.TX_RX.STD.data[__byte_i];
// Let the hardware know the frame has been read.
MODULE_CAN->CMR.B.RRB=1;
//send frame to input queue
//xQueueSendFromISR(CAN_cfg.rx_queue,&__frame,0);
}
write frame
Code: Select all
int CAN_write_frame(const CAN_frame_t* p_frame){
//byte iterator
uint8_t __byte_i;
//set frame format to standard and no RTR (needs to be done in a single write)
MODULE_CAN->MBX_CTRL.FCTRL.FIR.U=p_frame->DLC;
//Write message ID
MODULE_CAN->MBX_CTRL.FCTRL.TX_RX.STD.ID[0] = ((p_frame->MsgID) >> 3);
MODULE_CAN->MBX_CTRL.FCTRL.TX_RX.STD.ID[1] = ((p_frame->MsgID) << 5);
// Copy the frame data to the hardware
for(__byte_i=0;__byte_i<p_frame->DLC;__byte_i++)
MODULE_CAN->MBX_CTRL.FCTRL.TX_RX.STD.data[__byte_i]=p_frame->data.u8[__byte_i];
// Transmit frame
MODULE_CAN->CMR.B.TR=1;
return 0;
}
CAN Stop
Code: Select all
int CAN_stop(){
MODULE_CAN->MOD.B.RM = 1;
return 0;
}