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:
parent
1915714bc2
commit
ff30f479e1
|
@ -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;
|
||||
}
|
|
@ -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.
|
||||
#
|
||||
|
|
@ -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
|
|
@ -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__ */
|
|
@ -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_ */
|
|
@ -67,6 +67,12 @@ config LUA_MODULE_BTHCI
|
|||
help
|
||||
Includes the simple BlueTooth HCI module.
|
||||
|
||||
config LUA_MODULE_CAN
|
||||
bool "CAN module"
|
||||
default "n"
|
||||
help
|
||||
Includes the can module.
|
||||
|
||||
config LUA_MODULE_DHT
|
||||
bool "DHT11/21/22/AM2301/AM2302 module"
|
||||
default "n"
|
||||
|
|
|
@ -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);
|
|
@ -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
|
|
@ -35,6 +35,7 @@ pages:
|
|||
- 'adc': 'en/modules/adc.md'
|
||||
- 'bit': 'en/modules/bit.md'
|
||||
- 'bthci': 'en/modules/bthci.md'
|
||||
- 'can': 'en/modules/can.md'
|
||||
- 'dht': 'en/modules/dht.md'
|
||||
- 'file': 'en/modules/file.md'
|
||||
- 'gpio': 'en/modules/gpio.md'
|
||||
|
|
Loading…
Reference in New Issue