ESP32: CAN module (#1958)

* can extension

* can extension: bit timing and filter

* can -> CAN

* post CAN data callback

* CAN docs

* CAN: fixed receive, filter, extended frame

* reorder fn in can.md, remove driver_can/Kconfig

* fixed a leak when can.stop()
This commit is contained in:
zelll 2017-05-07 15:35:17 +08:00 committed by Arnim Läuger
parent 1915714bc2
commit ff30f479e1
9 changed files with 870 additions and 0 deletions

241
components/driver_can/CAN.c Normal file
View File

@ -0,0 +1,241 @@
/**
* @section License
*
* The MIT License (MIT)
*
* Copyright (c) 2017, Thomas Barth, barth-dev.de
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
#include "CAN.h"
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "esp_intr.h"
#include "soc/dport_reg.h"
#include <math.h>
#include "driver/gpio.h"
#include "can_regdef.h"
#include "CAN_config.h"
static void CAN_read_frame();
static void CAN_isr(void *arg_p);
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) {
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) {
}
}
static void CAN_read_frame(){
//byte iterator
uint8_t __byte_i;
//frame read buffer
CAN_frame_t __frame;
// for extended format frames, FF is 1.
if(MODULE_CAN->MBX_CTRL.FCTRL.FIR.B.FF==1){
//Get Message ID
__frame.MsgID = (((uint32_t)MODULE_CAN->MBX_CTRL.FCTRL.TX_RX.EXT.ID[0] << 21)
| (MODULE_CAN->MBX_CTRL.FCTRL.TX_RX.EXT.ID[1] << 13)
| (MODULE_CAN->MBX_CTRL.FCTRL.TX_RX.EXT.ID[2] << 5)
| (MODULE_CAN->MBX_CTRL.FCTRL.TX_RX.EXT.ID[3] >> 3));
//get DLC
__frame.DLC = MODULE_CAN->MBX_CTRL.FCTRL.FIR.B.DLC;
__frame.Extended = 1;
//deep copy data bytes
for(__byte_i=0;__byte_i<__frame.DLC;__byte_i++)
__frame.data.u8[__byte_i]=MODULE_CAN->MBX_CTRL.FCTRL.TX_RX.EXT.data[__byte_i];
} else {
//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;
__frame.Extended = 0;
//deep copy data bytes
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);
}
int CAN_write_frame(const CAN_frame_t* p_frame){
//byte iterator
uint8_t __byte_i;
if(p_frame->Extended) {
MODULE_CAN->MBX_CTRL.FCTRL.FIR.U=p_frame->DLC | 0x80;
//Write message ID
MODULE_CAN->MBX_CTRL.FCTRL.TX_RX.EXT.ID[0] = ((p_frame->MsgID & 0x1fe00000) >> 21);
MODULE_CAN->MBX_CTRL.FCTRL.TX_RX.EXT.ID[1] = ((p_frame->MsgID & 0x001fe000) >> 13);
MODULE_CAN->MBX_CTRL.FCTRL.TX_RX.EXT.ID[2] = ((p_frame->MsgID & 0x00001fe0) >> 5);
MODULE_CAN->MBX_CTRL.FCTRL.TX_RX.EXT.ID[3] = ((p_frame->MsgID & 0x0000001f) << 3);
// 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.EXT.data[__byte_i]=p_frame->data.u8[__byte_i];
} else {
//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;
}
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;
//synchronization jump width is the same for all baud rates
MODULE_CAN->BTR0.B.SJW =0x1;
//select time quantum and set TSEG1
switch(CAN_cfg.speed){
case CAN_SPEED_1000KBPS:
case CAN_SPEED_800KBPS:
MODULE_CAN->BTR1.B.TSEG1 = 8 - 1;
MODULE_CAN->BTR1.B.TSEG2 = 1 - 1;
MODULE_CAN->BTR0.B.BRP = APB_CLK_FREQ / CAN_cfg.speed / 2000 / (1 + 8 + 1) - 1;
break;
default:
MODULE_CAN->BTR1.B.TSEG1 = 13 - 1;
MODULE_CAN->BTR1.B.TSEG2 = 2 - 1;
MODULE_CAN->BTR0.B.BRP = APB_CLK_FREQ / CAN_cfg.speed/ 2000 / (1 + 13 + 2) - 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;
MODULE_CAN->MOD.B.AFM = CAN_cfg.dual_filter? 0 : 1;
//no acceptance filtering, as we want to fetch all messages
MODULE_CAN->MBX_CTRL.ACC.CODE[0] = CAN_cfg.code >> 24;
MODULE_CAN->MBX_CTRL.ACC.CODE[1] = (CAN_cfg.code >> 16) & 0x00ff;
MODULE_CAN->MBX_CTRL.ACC.CODE[2] = (CAN_cfg.code >> 8) & 0x00ff;
MODULE_CAN->MBX_CTRL.ACC.CODE[3] = CAN_cfg.code & 0x00ff;
MODULE_CAN->MBX_CTRL.ACC.MASK[0] = CAN_cfg.mask >> 24;
MODULE_CAN->MBX_CTRL.ACC.MASK[1] = (CAN_cfg.mask >> 16) & 0x00ff;
MODULE_CAN->MBX_CTRL.ACC.MASK[2] = (CAN_cfg.mask >> 8) & 0x00ff;
MODULE_CAN->MBX_CTRL.ACC.MASK[3] = CAN_cfg.mask & 0x00ff;
//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;
}
int CAN_stop(){
MODULE_CAN->MOD.B.RM = 1;
return 0;
}

View File

@ -0,0 +1,9 @@
#
# Main component makefile.
#
# This Makefile can be left empty. By default, it will take the sources in the
# src/ directory, compile them and link them into lib(subdirectory_name).a
# in the build directory. This behaviour is entirely configurable,
# please read the ESP-IDF documents if you need to do this.
#

View File

@ -0,0 +1,69 @@
/**
* @section License
*
* The MIT License (MIT)
*
* Copyright (c) 2017, Thomas Barth, barth-dev.de
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef __DRIVERS_CAN_H__
#define __DRIVERS_CAN_H__
#include <stdint.h>
#include "CAN_config.h"
/** \brief CAN Frame structure */
typedef struct {
uint8_t Extended;
uint32_t MsgID; /**< \brief Message ID */
uint32_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 0 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);
#endif

View File

@ -0,0 +1,62 @@
/**
* @section License
*
* The MIT License (MIT)
*
* Copyright (c) 2017, Thomas Barth, barth-dev.de
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef __DRIVERS_CAN_CFG_H__
#define __DRIVERS_CAN_CFG_H__
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "driver/gpio.h"
/** \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. */
uint32_t code;
uint32_t mask;
bool dual_filter;
}CAN_device_t;
/** \brief CAN configuration reference */
extern CAN_device_t CAN_cfg;
#endif /* __DRIVERS_CAN_CFG_H__ */

View File

@ -0,0 +1,237 @@
/**
* @section License
*
* The MIT License (MIT)
*
* Copyright (c) 2017, Thomas Barth, barth-dev.de
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef __DRIVERS_CAN_REGDEF_H_
#define __DRIVERS_CAN_REGDEF_H_
/** \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]; /**< \brief Acceptance Message ID */
uint32_t MASK[4]; /**< \brief Acceptance Mask */
uint32_t RESERVED2[5];
} ACC; /**< \brief Acceptance filtering */
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; /**< \brief Frame information record */
union{
struct {
uint32_t ID[2]; /**< \brief Standard frame message-ID*/
uint32_t data[8]; /**< \brief Standard frame payload */
uint32_t reserved[2];
} STD; /**< \brief Standard frame format */
struct {
uint32_t ID[4]; /**< \brief Extended frame message-ID*/
uint32_t data[8]; /**< \brief Extended frame payload */
} EXT; /**< \brief Extended frame format */
}TX_RX; /**< \brief RX/TX interface */
}FCTRL; /**< \brief Function control regs */
} MBX_CTRL; /**< \brief Mailbox control */
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;
#endif /* __DRIVERS_CAN_REGDEF_H_ */

View File

@ -67,6 +67,12 @@ config LUA_MODULE_BTHCI
help help
Includes the simple BlueTooth HCI module. Includes the simple BlueTooth HCI module.
config LUA_MODULE_CAN
bool "CAN module"
default "n"
help
Includes the can module.
config LUA_MODULE_DHT config LUA_MODULE_DHT
bool "DHT11/21/22/AM2301/AM2302 module" bool "DHT11/21/22/AM2301/AM2302 module"
default "n" default "n"

168
components/modules/can.c Normal file
View File

@ -0,0 +1,168 @@
// Module for interfacing with adc hardware
#include "module.h"
#include "lauxlib.h"
#include "platform.h"
#include "CAN.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "esp_task.h"
#include "esp_log.h"
#include <string.h>
#include "task/task.h"
CAN_device_t CAN_cfg = {
.speed = CAN_SPEED_1000KBPS, // CAN Node baudrade
.tx_pin_id = -1, // CAN TX pin
.rx_pin_id = -1, // CAN RX pin
.rx_queue = NULL, // FreeRTOS queue for RX frames
.code = 0,
.mask = 0xffffffff,
.dual_filter = false
};
static task_handle_t can_data_task_id;
static int can_on_received = LUA_NOREF;
static xTaskHandle xCanTaskHandle = NULL;
// LUA
static void can_data_task( task_param_t param, task_prio_t prio ) {
CAN_frame_t *frame = (CAN_frame_t *)param;
if(can_on_received == LUA_NOREF) {
free( frame );
return;
}
lua_State *L = lua_getstate();
lua_rawgeti(L, LUA_REGISTRYINDEX, can_on_received);
lua_pushinteger(L, frame->Extended? 1 : 0);
lua_pushinteger(L, frame->MsgID);
lua_pushlstring(L, (char *)frame->data.u8, frame->DLC);
free( frame );
lua_call(L, 3, 0);
}
// RTOS
static void task_CAN( void *pvParameters ){
(void)pvParameters;
//frame buffer
CAN_frame_t frame;
//create CAN RX Queue
CAN_cfg.rx_queue = xQueueCreate(10, sizeof(CAN_frame_t));
//start CAN Module
CAN_init();
for (;;){
//receive next CAN frame from queue
if( xQueueReceive( CAN_cfg.rx_queue, &frame, 3 * portTICK_PERIOD_MS ) == pdTRUE ){
CAN_frame_t *postFrame = (CAN_frame_t *)malloc( sizeof( CAN_frame_t ) );
memcpy(postFrame, &frame, sizeof( CAN_frame_t ));
task_post_medium( can_data_task_id, (task_param_t)postFrame );
}
}
}
// Lua: setup( {}, callback )
static int can_setup( lua_State *L )
{
if(xCanTaskHandle != NULL)
luaL_error( L, "Stop CAN before setup" );
luaL_checkanytable (L, 1);
luaL_checkanyfunction (L, 2);
lua_settop (L, 2);
if(can_on_received != LUA_NOREF) luaL_unref(L, LUA_REGISTRYINDEX, can_on_received);
can_on_received = luaL_ref(L, LUA_REGISTRYINDEX);
lua_getfield (L, 1, "speed");
CAN_cfg.speed = luaL_checkint(L, -1);
lua_getfield (L, 1, "tx");
CAN_cfg.tx_pin_id = luaL_checkint(L, -1);
lua_getfield (L, 1, "rx");
CAN_cfg.rx_pin_id = luaL_checkint(L, -1);
lua_getfield (L, 1, "dual_filter");
CAN_cfg.dual_filter = lua_toboolean(L, 0);
lua_getfield (L, 1, "code");
CAN_cfg.code = (uint32_t)luaL_optnumber(L, -1, 0);
lua_getfield (L, 1, "mask");
CAN_cfg.mask = (uint32_t)luaL_optnumber(L, -1, 0x0ffffffff);
return 0;
}
static int can_start( lua_State *L )
{
if(xCanTaskHandle != NULL)
luaL_error( L, "CAN started" );
xTaskCreate(task_CAN, "CAN", 2048, NULL, ESP_TASK_MAIN_PRIO + 1, &xCanTaskHandle);
return 0;
}
static int can_stop( lua_State *L )
{
if(xCanTaskHandle) {
vTaskDelete(xCanTaskHandle);
xCanTaskHandle = NULL;
}
CAN_stop();
if(CAN_cfg.rx_queue) {
vQueueDelete( CAN_cfg.rx_queue );
CAN_cfg.rx_queue = NULL;
}
return 0;
}
static int can_send( lua_State *L )
{
uint32_t format = (uint8_t)luaL_checkinteger( L, 1 );
uint32_t msg_id = luaL_checkinteger( L, 2 );
size_t len;
const char *data = luaL_checklstring( L, 3, &len );
uint8_t i;
CAN_frame_t frame;
if(xCanTaskHandle == NULL)
luaL_error( L, "CAN not started" );
if(len > 8)
luaL_error( L, "CAN can not send more than 8 bytes" );
frame.Extended = format? 1 : 0;
frame.MsgID = msg_id;
frame.DLC = len;
for(i = 0; i < len; i++)
frame.data.u8[i] = data[i];
CAN_write_frame(&frame);
return 0;
}
// Module function map
static const LUA_REG_TYPE can_map[] =
{
{ LSTRKEY( "setup" ), LFUNCVAL( can_setup ) },
{ LSTRKEY( "start" ), LFUNCVAL( can_start ) },
{ LSTRKEY( "stop" ), LFUNCVAL( can_stop ) },
{ LSTRKEY( "send" ), LFUNCVAL( can_send ) },
{ LSTRKEY( "STANDARD_FRAME" ), LNUMVAL( 0 ) },
{ LSTRKEY( "EXTENDED_FRAME" ), LNUMVAL( 1 ) },
{ LNILKEY, LNILVAL }
};
int luaopen_can( lua_State *L ) {
can_data_task_id = task_get_id( can_data_task ); // reset CAN after sw reset
CAN_stop();
return 0;
}
NODEMCU_MODULE(CAN, "can", can_map, luaopen_can);

77
docs/en/modules/can.md Normal file
View File

@ -0,0 +1,77 @@
# CAN Module
| Since | Origin / Contributor | Maintainer | Source |
| :----- | :-------------------- | :---------- | :------ |
| 2017-04-27 | [@ThomasBarth](https://github.com/ThomasBarth/ESP32-CAN-Driver/), zelll | | [can.c](../../../components/modules/can.c)|
The CAN module provides access to the in-built CAN controller.
## can.send()
Send a frame.
#### Syntax
`can.send(format, msg_id, data)`
#### Parameters
- `format` Frame format. `can.STANDARD_FRAME` or `can.EXTENDED_FRAME`
- `msg_id` CAN Messge ID
- `data` CAN data, up to 8 bytes
#### Returns
nil
## can.setup()
Configuration CAN controller.
#### Syntax
```lua
can.setup({
speed = 1000,
tx = 5,
rx = 4,
dual_filter = false,
code = 0,
mask = 0xffffffff
}, function(format, msg_id, data) end)
```
#### Parameters
- `config`
- `speed` kbps. One of following value: `1000`, `800`, `500`, `250`, `100`.
- `tx` Pin num for TX.
- `rx` Pin num for RX.
- `dual_filter` `true` dual filter mode, `false` single filter mode (default)
- `code` 4-bytes integer. Use this with mask to filter CAN frame. Default: `0`. See [SJA1000](http://www.nxp.com/documents/data_sheet/SJA1000.pdf)
- `mask` 4-bytes integer. Default: `0xffffffff`
- `callback` function to be called when CAN data received.
- `format` Frame format. `can.STANDARD_FRAME` or `can.EXTENDED_FRAME`
- `msg_id` CAN Messge ID
- `data` CAN data, up to 8 bytes
#### Returns
nil
## can.start()
Start CAN controller.
#### Syntax
`can.start()`
#### Parameters
#### Returns
nil
## can.stop()
Stop CAN controller.
#### Syntax
`can.stop()`
#### Parameters
#### Returns
nil

View File

@ -35,6 +35,7 @@ pages:
- 'adc': 'en/modules/adc.md' - 'adc': 'en/modules/adc.md'
- 'bit': 'en/modules/bit.md' - 'bit': 'en/modules/bit.md'
- 'bthci': 'en/modules/bthci.md' - 'bthci': 'en/modules/bthci.md'
- 'can': 'en/modules/can.md'
- 'dht': 'en/modules/dht.md' - 'dht': 'en/modules/dht.md'
- 'file': 'en/modules/file.md' - 'file': 'en/modules/file.md'
- 'gpio': 'en/modules/gpio.md' - 'gpio': 'en/modules/gpio.md'