About the CAN controller.

ThomasB
Posts: 38
Joined: Sun Dec 25, 2016 12:11 am

Re: About the CAN controller.

Postby ThomasB » Sun Dec 25, 2016 1:17 am

Hi guys,

Im trying to implement a CAN driver based on eerimoq's implementation, using ESP-IDF on a AI ESP-32S.

So far, there are not too much things that could go wrong... at least I thought so... I can't get any interrupts from the CAN module. The transceiver works fine with my other micros.

The plan is to go with GPIO32 for TX and GPIO33 for RX.

Im new to the ESP32. I have seen some strange mapping for the GPIOs and the pins on the boards. I hope GPIO33 is mapped to IO33 on the ESP-32S? :lol:
I have tried to implement eerimoq's approach with magic numbers, as well using the inbuild gpio API. No success :x
Im a bit confused about the IO Multiplexer, because the defines in the code are not documented :?

I use esp-idf-template as base project (empty, besides CAN). Maybe I need to configure some dependent modules?


Thanks for reading
Thomas

Code: Select all


#define ESP32_CAN              ((volatile esp32_can_t    *)0x3ff6b000)

#define CAN_SPEED_1000KBPS (ESP32_CAN_BTIM0_BRP(0x6) | ESP32_CAN_BTIM0_SJW(3) | ((ESP32_CAN_BTIM1_TSEG1(2) | ESP32_CAN_BTIM1_TSEG2(3) | ESP32_CAN_BTIM1_SAM) << 8))

#define ESP32_CAN_OCTRL_MODE_NORMAL                     BIT(1)

/** \brief  clock control bitfields */
typedef struct {
    unsigned int RR:1; 						/**< \brief CR.0 Reset Request */
    unsigned int RIE:1;            			/**< \brief CR.1 Receive Interrupt Enable */
    unsigned int TIE:1;                     /**< \brief CR.2 Transmit Interrupt Enable */
    unsigned int EIE:1;                   	/**< \brief CR.3 Error Interrupt Enable */
    unsigned int OIE:1;            			/**< \brief CR.4 Overrun Interrupt Enable */
    unsigned int reserved_24:24;            /**< \brief \internal Reserved */
} _CAN_CR_BITS;

/** \brief clock control register. */
typedef union
{
    /** \brief Unsigned access */
    unsigned int U;
    /** \brief Signed access */
    signed int I;
    /** \brief Bitfield access */
    _CAN_CR_BITS B;
} _CAN_CR_t;

typedef struct {
    uint32_t MODE;
    uint32_t COMMAND;
    uint32_t STATUS;
    uint32_t INT;
    uint32_t INTE;
    uint32_t RESERVED0;
    uint32_t BTIM0;
    uint32_t BTIM1;
    uint32_t OCTRL;
    uint32_t RESERVED1[2];
    uint32_t ALC;
    uint32_t ECC;
    uint32_t EWL;
    uint32_t RXERR;
    uint32_t TXERR;
    union {
        struct {
            uint32_t CODE[4];
            uint32_t MASK[4];
            uint32_t RESERVED2[5];
        } ACC;
        struct {
            uint32_t FRAME_INFO;
            uint32_t ID_DATA[12];
        } TX_RX;
    } U;
    uint32_t RMC;
    uint32_t RBSA;
    uint32_t CDIV;
    uint32_t IRAM[2];
}esp32_can_t;

static void CAN_isr(void *arg_p){
	ESP_LOGI("CAN", "ISR");
}

int CAN_start(){

	volatile esp32_can_t *p_regs=ESP32_CAN;

	volatile uint16_t test=0;
    /* Enable the CAN hardware. */
    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 in the GPIO matrix and IO MUX. */
    gpio_set_direction(GPIO_NUM_32,GPIO_MODE_OUTPUT);
    gpio_matrix_out(GPIO_NUM_32,CAN_TX_IDX,0,0);

    /* Configure RX pin in the GPIO matrix and IO MUX. */
	gpio_set_direction(GPIO_NUM_33,GPIO_MODE_INPUT);
	gpio_matrix_in(GPIO_NUM_33,CAN_RX_IDX,0);
	
//    ESP32_GPIO->FUNC_IN_SEL_CFG[ESP32_PERIPHERAL_SIGNAL_CAN_RX] = 33;
//    ESP32_GPIO->PIN[33] = 0;
//    ESP32_IO_MUX->PIN[7] = (ESP32_IO_MUX_PIN_MCU_SEL_GPIO| ESP32_IO_MUX_PIN_FUNC_IE);

//    +    /* Configure RX pin in the GPIO matrix and IO MUX. */
//    +    ESP32_GPIO->FUNC_IN_SEL_CFG[ESP32_PERIPHERAL_SIGNAL_CAN_RX] = rx_pin_p->id;
//    +    ESP32_GPIO->PIN[rx_pin_p->id] = 0;
//    +    ESP32_IO_MUX->PIN[rx_pin_p->iomux] = (ESP32_IO_MUX_PIN_MCU_SEL_GPIO
//    +                                          | ESP32_IO_MUX_PIN_FUNC_IE);

    /* Clock configuration. */
    p_regs->CDIV = BIT(7);

    /* Bus speed configuration. */
    p_regs->BTIM0 = LO8(CAN_cfg.speed);
    p_regs->BTIM1 = HI8(CAN_cfg.speed);

    /* Enable all interrupts. */
    p_regs->INTE = 0xff;

    /* Accept all frames. */
    p_regs->U.ACC.CODE[0] = 0;
    p_regs->U.ACC.CODE[1] = 0;
    p_regs->U.ACC.CODE[2] = 0;
    p_regs->U.ACC.CODE[3] = 0;
    p_regs->U.ACC.MASK[0] = 0xff;
    p_regs->U.ACC.MASK[1] = 0xff;
    p_regs->U.ACC.MASK[2] = 0xff;
    p_regs->U.ACC.MASK[3] = 0xff;

    p_regs->OCTRL = (ESP32_CAN_OCTRL_MODE_NORMAL);

    /* Clear error counters and error code capture */
    p_regs->TXERR = 0;
    p_regs->RXERR = 0;
    (void)p_regs->ECC;

    /* Clear interrupt flags by reading the interrupt status  register.  */
    (void)p_regs->INT;

    /* Install the interrupt handler. */
    xt_set_interrupt_handler(ESP32_CPU_INTR_CAN_NUM, CAN_isr,  NULL);
    xt_ints_on(BIT(ESP32_CPU_INTR_CAN_NUM));

    /* Map the CAN peripheral interrupt to the CAN CPU interrupt. */
    intr_matrix_set(xPortGetCoreID(), ESP32_INTR_SOURCE_CAN, ESP32_CPU_INTR_CAN_NUM);

    /* Set chip to normal mode. */
    p_regs->MODE = 0;

    return (0);
}
Last edited by ThomasB on Sun Dec 25, 2016 11:12 am, edited 1 time in total.

ESP_igrr
Posts: 2072
Joined: Tue Dec 01, 2015 8:37 am

Re: About the CAN controller.

Postby ESP_igrr » Sun Dec 25, 2016 10:33 am

If you are running this code with latest ESP-IDF, you may need to change the part which attaches interrupt handler.
Currently allocating interrupt number, enabling interrupt input, configuring the interrupt matrix, is done using esp_intr_alloc function.

Another thing — it is not safe to use ESP_LOGI inside an interrupt handler (just like printf). You can either use ESP_EARLY_LOGI, or better, use a semaphore or a queue to relay information about the interrupt to some task and print from there.

ThomasB
Posts: 38
Joined: Sun Dec 25, 2016 12:11 am

Re: About the CAN controller.

Postby ThomasB » Sun Dec 25, 2016 3:30 pm

Please note that this is still work in progress (e.g. Frame info register etc) but it should be a good starting point.
Also please note that this code is based on eerimoq's implementation.

I found that GPIO32 and GPIO 33 are not connected to IO32/IO33 on the AI ESP32S. Therefore I use GPIO4 and GPIO5.... this is confusing and can be really frustrating...

Definitions

Code: Select all


/** \brief Start address of CAN registers */
#define MODULE_CAN              						((volatile CAN_Module_t    *)0x3ff6b000)

/* Interrupt status register. */
#define MODULE_CAN_INT_RX                                BIT(0)
#define MODULE_CAN_INT_TX                                BIT(1)
#define MODULE_CAN_INT_ERR                               BIT(2)
#define MODULE_CAN_INT_DATA_OVERRUN                      BIT(3)
#define MODULE_CAN_INT_WAKEUP                            BIT(4)
#define MODULE_CAN_INT_ERR_PASSIVE                       BIT(5)
#define MODULE_CAN_INT_ARB_LOST                          BIT(6)
#define MODULE_CAN_INT_BUS_ERR                           BIT(7)
#define MODULE_CAN_FRAME_INFO_FF                         BIT(7)

/** \brief Frame info register. */
typedef union{

    /** \brief Unsigned access */
    uint32_t U;

    /** \brief Bitfield 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;
} _CAN_FIR_t;


/** \brief control register. */
typedef union{

    /** \brief Unsigned access */
    uint32_t U;

    /** \brief Signed access */
    struct {
        unsigned int RR:1; 							/**< \brief CR.0 Reset Request */
        unsigned int RIE:1;            				/**< \brief CR.1 Receive Interrupt Enable */
        unsigned int TIE:1;                     	/**< \brief CR.2 Transmit Interrupt Enable */
        unsigned int EIE:1;                   		/**< \brief CR.3 Error Interrupt Enable */
        unsigned int OIE:1;            				/**< \brief CR.4 Overrun Interrupt Enable */
        unsigned int reserved_24:24;            	/**< \brief \internal Reserved */
    } B;
} _CAN_CR_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 {
            uint32_t FRAME_INFO;
            uint32_t ID_DATA[12];
        } TX_RX;
    } U;
	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

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){

		case CAN_SPEED_1000KBPS:
			MODULE_CAN->BTR0.B.BRP	=0x6;
			MODULE_CAN->BTR0.B.SJW	=0x3;
			MODULE_CAN->BTR1.B.TSEG1	=0x2;
			MODULE_CAN->BTR1.B.TSEG2	=0x3;
			break;

		case CAN_SPEED_500KBPS:
			MODULE_CAN->BTR0.B.BRP	=0x4;
			MODULE_CAN->BTR0.B.SJW	=0x2;
			MODULE_CAN->BTR1.B.TSEG1	=0x7;
			MODULE_CAN->BTR1.B.TSEG2	=0x6;
			break;

		case CAN_SPEED_250KBPS:
			MODULE_CAN->BTR0.B.BRP	=0x6;
			MODULE_CAN->BTR0.B.SJW	=0x3;
			MODULE_CAN->BTR1.B.TSEG1	=0x2;
			MODULE_CAN->BTR1.B.TSEG2	=0x3;
			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->U.ACC.CODE[0] = 0;
    MODULE_CAN->U.ACC.CODE[1] = 0;
    MODULE_CAN->U.ACC.CODE[2] = 0;
    MODULE_CAN->U.ACC.CODE[3] = 0;
    MODULE_CAN->U.ACC.MASK[0] = 0xff;
    MODULE_CAN->U.ACC.MASK[1] = 0xff;
    MODULE_CAN->U.ACC.MASK[2] = 0xff;
    MODULE_CAN->U.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);
}

WiFive
Posts: 3529
Joined: Tue Dec 01, 2015 7:35 am

Re: About the CAN controller.

Postby WiFive » Sun Dec 25, 2016 10:32 pm

ThomasB wrote:I found that GPIO32 and GPIO 33 are not connected to IO32/IO33 on the AI ESP32S. Therefore I use GPIO4 and GPIO5.... this is confusing and can be really frustrating...
Are you sure its not related to this:
http://esp32.com/viewtopic.php?f=13&t=694

ThomasB
Posts: 38
Joined: Sun Dec 25, 2016 12:11 am

Re: About the CAN controller.

Postby ThomasB » Sun Dec 25, 2016 11:26 pm

Thats possible. I can remember that I had seen a oscillating pattern with my logic analyzer but my assumption was that the CAN is running with the wrong clock.

On the other hand, I have seen the repository just ~2 days ago for the first time :?

ThomasB
Posts: 38
Joined: Sun Dec 25, 2016 12:11 am

Re: About the CAN controller.

Postby ThomasB » Mon Jan 02, 2017 7:17 pm

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;
}

ThomasB
Posts: 38
Joined: Sun Dec 25, 2016 12:11 am

Re: About the CAN controller.

Postby ThomasB » Tue Jan 03, 2017 3:16 pm

Found a bug in eerimoq's code.
The timing values are not correct for 1Mbit. I calculated the settings for 1M/500k/250k with http://www.esacademy.com/en/library/cal ... lator.html (80Mhz Clock) and updated my previous post. I successfully have tested all speeds but as I dont know if the input clock really is 80Mhz this remains a best guess and might be inaccurate. Also I dont know about the accuracy of the input clock.

ThomasB
Posts: 38
Joined: Sun Dec 25, 2016 12:11 am

Re: About the CAN controller.

Postby ThomasB » Tue Jan 17, 2017 9:01 pm

Update.
Now the driver calculates the baud rate prescaler based on the APB clock and I added a few more baud rates. (requires math.h)

CAN_Init

Code: Select all

intCAN_init(){

	//Time quantum
	double __tq = 0;

	//Bit timing
	float __bt = 1000/CAN_cfg.speed;

    //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;

	//synchronization jump width is the same for all baud rates
	MODULE_CAN->BTR0.B.SJW		=0x1;

	//TSEG2 is the same for all baud rates
	MODULE_CAN->BTR1.B.TSEG2	=0x1;

	//select time quantum and set TSEG1
	switch(CAN_cfg.speed){
		case CAN_SPEED_1000KBPS:
			MODULE_CAN->BTR1.B.TSEG1	=0x4;
			__tq = 0.125;
			break;

		case CAN_SPEED_800KBPS:
			MODULE_CAN->BTR1.B.TSEG1	=0x6;
			__tq = 0.125;
			break;
		default:
			MODULE_CAN->BTR1.B.TSEG1	=0xc;
			__tq = __bt / 16;
	}

	//set baud rate prescaler
	MODULE_CAN->BTR0.B.BRP=(uint8_t)round((((APB_CLK_FREQ * __tq) / 2) - 1)/1000000)-1;

    /* 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, as we want to fetch all messages
    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;
}
Configuration

Code: Select all

/** \brief CAN Node Bus speed */
typedef enum  {
	CAN_SPEED_100KBPS=100, 				/**< \brief CAN Node runs at 100kBit/s. */
	CAN_SPEED_125KBPS=125, 				/**< \brief CAN Node runs at 125kBit/s. */
	CAN_SPEED_250KBPS=250, 				/**< \brief CAN Node runs at 250kBit/s. */
	CAN_SPEED_500KBPS=500, 				/**< \brief CAN Node runs at 500kBit/s. */
	CAN_SPEED_800KBPS=800, 				/**< \brief CAN Node runs at 800kBit/s. */
	CAN_SPEED_1000KBPS=1000				/**< \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,
};

Beck-Sisyphus
Posts: 14
Joined: Sun Jan 03, 2016 12:15 am

Re: About the CAN controller.

Postby Beck-Sisyphus » Thu Jan 19, 2017 8:51 am

Hi all,

I am excited to see that ESP32 is compatible with SJA1000 CAN controller, may I know if it will be compatible with SN65NVD230 as well?
I realize that the SN65NVD is compatible with ISO 11898-2, but not sure if its data link is compatible with CAN bus 2.0B.


Thanks,

Beck

ESP_Sprite
Posts: 9766
Joined: Thu Nov 26, 2015 4:08 am

Re: About the CAN controller.

Postby ESP_Sprite » Fri Jan 20, 2017 1:47 am

I am not familiar with that chip, and Google yields no datasheets; do you have a link with more info about it?

Who is online

Users browsing this forum: No registered users and 68 guests