get rid of esp32_nmea2000

This commit is contained in:
andreas 2023-08-24 18:39:51 +02:00
parent 7baa5688ef
commit 80486eff75
5 changed files with 0 additions and 791 deletions

View File

@ -1,291 +0,0 @@
/**
* @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_
#ifdef __cplusplus
extern "C" {
#endif
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 frame type (standard/extended)
*/
typedef enum {
CAN_frame_std=0, /**< Standard frame, using 11 bit identifer. */
CAN_frame_ext=1 /**< Extended frame, using 29 bit identifer. */
}CAN_frame_format_t;
/**
* \brief CAN RTR
*/
typedef enum {
CAN_no_RTR=0, /**< No RTR frame. */
CAN_RTR=1 /**< RTR frame. */
}CAN_RTR_t;
/** \brief Frame information record type */
typedef union{uint32_t U; /**< \brief Unsigned access */
struct {
uint8_t DLC:4; /**< \brief [3:0] DLC, Data length container */
unsigned int unknown_2:2; /**< \brief \internal unknown */
CAN_RTR_t RTR:1; /**< \brief [6:6] RTR, Remote Transmission Request */
CAN_frame_format_t FF:1; /**< \brief [7:7] Frame Format, see# CAN_frame_format_t*/
unsigned int reserved_24:24; /**< \brief \internal Reserved */
} B;
} CAN_FIR_t;
/** \brief Start address of CAN registers */
#define MODULE_CAN ((volatile CAN_Module_t *)0x3ff6b000)
/** \brief Get standard message ID */
#define _CAN_GET_STD_ID (((uint32_t)MODULE_CAN->MBX_CTRL.FCTRL.TX_RX.STD.ID[0] << 3) | \
(MODULE_CAN->MBX_CTRL.FCTRL.TX_RX.STD.ID[1] >> 5))
/** \brief Get extended message ID */
#define _CAN_GET_EXT_ID (((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 ))
/** \brief Set standard message ID */
#define _CAN_SET_STD_ID(x) MODULE_CAN->MBX_CTRL.FCTRL.TX_RX.STD.ID[0] = ((x) >> 3); \
MODULE_CAN->MBX_CTRL.FCTRL.TX_RX.STD.ID[1] = ((x) << 5);
/** \brief Set extended message ID */
#define _CAN_SET_EXT_ID(x) MODULE_CAN->MBX_CTRL.FCTRL.TX_RX.EXT.ID[0] = ((x) >> 21); \
MODULE_CAN->MBX_CTRL.FCTRL.TX_RX.EXT.ID[1] = ((x) >> 13); \
MODULE_CAN->MBX_CTRL.FCTRL.TX_RX.EXT.ID[2] = ((x) >> 5); \
MODULE_CAN->MBX_CTRL.FCTRL.TX_RX.EXT.ID[3] = ((x) << 3); \
/** \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 {
CAN_FIR_t 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;
#ifdef __cplusplus
}
#endif
#endif /* __DRIVERS_CAN_REGDEF_H_ */

View File

@ -1,385 +0,0 @@
/*
NMEA2000_esp32.cpp
Copyright (c) 2015-2020 Timo Lappalainen, Kave Oy, www.kave.fi
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.
Inherited NMEA2000 object for ESP32 modules. See also NMEA2000 library.
Thanks to Thomas Barth, barth-dev.de, who has written ESP32 CAN code. To avoid extra
libraries, I implemented his code directly to the NMEA2000_esp32 to avoid extra
can.h library, which may cause even naming problem.
*/
#include "driver/periph_ctrl.h"
#include "soc/dport_reg.h"
#include "NMEA2000_esp32.h"
//time to reinit CAN bus if the queue is full for that time
#define SEND_CANCEL_TIME 2000
//reinit CAN bis if nothing send/received within this time
#define RECEIVE_REINIT_TIME 60000
bool tNMEA2000_esp32::CanInUse=false;
tNMEA2000_esp32 *pNMEA2000_esp32=0;
void ESP32Can1Interrupt(void *);
#define ECDEBUG(fmt,args...) if(debugStream){debugStream->printf(fmt, ## args);}
//*****************************************************************************
tNMEA2000_esp32::tNMEA2000_esp32(gpio_num_t _TxPin,
gpio_num_t _RxPin,
Print *dbg) :
tNMEA2000(), IsOpen(false),
speed(CAN_SPEED_250KBPS), TxPin(_TxPin), RxPin(_RxPin),
RxQueue(NULL), TxQueue(NULL) {
debugStream=dbg;
}
//*****************************************************************************
bool tNMEA2000_esp32::CANSendFrame(unsigned long id, unsigned char len, const unsigned char *buf, bool /*wait_sent*/) {
tCANFrame frame;
unsigned long now=millis();
if ( uxQueueSpacesAvailable(TxQueue)==0 ) {
if (lastSend && (lastSend + SEND_CANCEL_TIME) < now){
ECDEBUG("CanSendFrame Aborting and emptying queue\n");
while (xQueueReceive(TxQueue,&frame,0)){}
errReinit++;
CAN_init(false);
if ( uxQueueSpacesAvailable(TxQueue)==0 ) return false;
}
else{
ECDEBUG("CanSendFrame queue full\n");
return false; // can not send to queue
}
}
lastSend=now;
frame.id=id;
frame.len=len>8?8:len;
memcpy(frame.buf,buf,len);
CheckBusOff();
ECDEBUG("CanSendFrame IntrCnt %d\n",cntIntr);
ECDEBUG("CanSendFrame Error TX/RX %d/%d\n",MODULE_CAN->TXERR.U,MODULE_CAN->RXERR.U);
ECDEBUG("CanSendFrame Error Overrun %d\n",errOverrun);
ECDEBUG("CanSendFrame Error Arbitration %d\n",errArb);
ECDEBUG("CanSendFrame Error Bus %d\n",errBus);
ECDEBUG("CanSendFrame Error Recovery %d\n",errRecovery);
ECDEBUG("CanSendFrame ErrorCount %d\n",errCountTxInternal);
ECDEBUG("CanSendFrame ErrorCancel %d\n",errCancelTransmit);
ECDEBUG("CanSendFrame ErrorReinit %d\n",errReinit);
ECDEBUG("CanSendFrame busOff=%d, errPassive=%d\n",MODULE_CAN->SR.B.BS,MODULE_CAN->SR.B.ES)
xQueueSendToBack(TxQueue,&frame,0); // Add frame to queue
if ( MODULE_CAN->SR.B.TBS==0 ) {
ECDEBUG("CanSendFrame: wait for ISR to send %d\n",frame.id);
return true; // Currently sending, ISR takes care of sending
}
if ( MODULE_CAN->SR.B.TBS==1 ) { // Check again and restart send, if is not going on
xQueueReceive(TxQueue,&frame,0);
ECDEBUG("CanSendFrame: send direct %d\n",frame.id);
CAN_send_frame(frame);
//return MODULE_CAN->TXERR.U < 127;
}
return true;
}
//*****************************************************************************
void tNMEA2000_esp32::InitCANFrameBuffers() {
if (MaxCANReceiveFrames<10 ) MaxCANReceiveFrames=50; // ESP32 has plenty of RAM
if (MaxCANSendFrames<10 ) MaxCANSendFrames=40;
uint16_t CANGlobalBufSize=MaxCANSendFrames-4;
MaxCANSendFrames=4; // we do not need much libary internal buffer since driver has them.
RxQueue=xQueueCreate(MaxCANReceiveFrames,sizeof(tCANFrame));
TxQueue=xQueueCreate(CANGlobalBufSize,sizeof(tCANFrame));
tNMEA2000::InitCANFrameBuffers(); // call main initialization
}
//*****************************************************************************
bool tNMEA2000_esp32::CANOpen() {
if (IsOpen) return true;
if (CanInUse) return false; // currently prevent accidental second instance. Maybe possible in future.
pNMEA2000_esp32=this;
IsOpen=true;
CAN_init();
CanInUse=IsOpen;
return IsOpen;
}
//*****************************************************************************
bool tNMEA2000_esp32::CANGetFrame(unsigned long &id, unsigned char &len, unsigned char *buf) {
bool HasFrame=false;
tCANFrame frame;
CheckBusOff();
unsigned long now=millis();
//receive next CAN frame from queue
if ( xQueueReceive(RxQueue,&frame, 0)==pdTRUE ) {
HasFrame=true;
id=frame.id;
len=frame.len;
memcpy(buf,frame.buf,frame.len);
lastReceive=now;
}
else{
if (lastReceive != 0 && (lastReceive + RECEIVE_REINIT_TIME) < now && (lastSend + RECEIVE_REINIT_TIME) < now){
ECDEBUG("Noting received within %d ms, reinit",RECEIVE_REINIT_TIME);
CAN_init(false);
}
}
return HasFrame;
}
//*****************************************************************************
void tNMEA2000_esp32::CAN_init(bool installIsr) {
//Time quantum
double __tq;
// A soft reset of the ESP32 leaves it's CAN controller in an undefined state so a reset is needed.
// Reset CAN controller to same state as it would be in after a power down reset.
periph_module_reset(PERIPH_CAN_MODULE);
//enable module
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_CAN_CLK_EN);
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_CAN_RST);
//configure RX pin
gpio_set_direction(RxPin,GPIO_MODE_INPUT);
gpio_matrix_in(RxPin,CAN_RX_IDX,0);
gpio_pad_select_gpio(RxPin);
//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 (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 = ((float)1000/speed) / 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 = 0xef; // bit 0x10 contains Baud Rate Prescaler Divider (BRP_DIV) bit
//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
if (installIsr) esp_intr_alloc(ETS_CAN_INTR_SOURCE,0,ESP32Can1Interrupt,NULL,NULL);
//configure TX pin
// We do late configure, since some initialization above caused CAN Tx flash
// shortly causing one error frame on startup. By setting CAN pin here
// it works right.
gpio_set_direction(TxPin,GPIO_MODE_OUTPUT);
gpio_matrix_out(TxPin,CAN_TX_IDX,0,0);
gpio_pad_select_gpio(TxPin);
//Showtime. Release Reset Mode.
MODULE_CAN->MOD.B.RM = 0;
}
//*****************************************************************************
void tNMEA2000_esp32::CAN_read_frame() {
tCANFrame frame;
CAN_FIR_t FIR;
//get FIR
FIR.U=MODULE_CAN->MBX_CTRL.FCTRL.FIR.U;
frame.len=FIR.B.DLC>8?8:FIR.B.DLC;
// Handle only extended frames
if (FIR.B.FF==CAN_frame_ext) { //extended frame
//Get Message ID
frame.id = _CAN_GET_EXT_ID;
//deep copy data bytes
for( size_t i=0; i<frame.len; i++ ) {
frame.buf[i]=MODULE_CAN->MBX_CTRL.FCTRL.TX_RX.EXT.data[i];
}
//send frame to input queue
xQueueSendToBackFromISR(RxQueue,&frame,0);
}
//Let the hardware know the frame has been read.
MODULE_CAN->CMR.B.RRB=1;
}
//*****************************************************************************
void tNMEA2000_esp32::CAN_send_frame(tCANFrame &frame) {
CAN_FIR_t FIR;
FIR.U=0;
FIR.B.DLC=frame.len>8?8:frame.len;
FIR.B.FF=CAN_frame_ext;
//copy frame information record
MODULE_CAN->MBX_CTRL.FCTRL.FIR.U=FIR.U;
//Write message ID
_CAN_SET_EXT_ID(frame.id);
// Copy the frame data to the hardware
for ( size_t i=0; i<frame.len; i++) {
MODULE_CAN->MBX_CTRL.FCTRL.TX_RX.EXT.data[i]=frame.buf[i];
}
// Transmit frame
MODULE_CAN->CMR.B.TR=1;
}
#define CAN_MAX_TX_RETRY 12
#define RECOVERY_RETRY_MS 1000
void tNMEA2000_esp32::CAN_bus_off_recovery(){
unsigned long now=millis();
if (recoveryStarted && (recoveryStarted + RECOVERY_RETRY_MS) > now ) return;
ECDEBUG("CAN_bus_off_recovery started\n");
recoveryStarted=now;
errRecovery++;
MODULE_CAN->CMR.B.AT=1; // abort transmission
(void)MODULE_CAN->SR.U;
MODULE_CAN->TXERR.U = 127;
MODULE_CAN->RXERR.U = 0;
MODULE_CAN->MOD.B.RM = 0;
}
void tNMEA2000_esp32::CheckBusOff(){
//should we really recover here?
if (MODULE_CAN->SR.B.BS){
ECDEBUG("Bus off detected, trying recovery\n");
CAN_bus_off_recovery();
}
}
//*****************************************************************************
void tNMEA2000_esp32::InterruptHandler() {
//Interrupt flag buffer
cntIntr++;
uint32_t interrupt;
// Read interrupt status and clear flags
interrupt = (MODULE_CAN->IR.U & 0xff);
// Handle TX complete interrupt
//see http://uglyduck.vajn.icu/PDF/wireless/Espressif/ESP32/Eco_and_Workarounds_for_Bugs_in_ESP32.pdf, 3.13.4
if ((interrupt & __CAN_IRQ_TX) != 0 || MODULE_CAN->SR.B.TBS) {
tCANFrame frame;
if ( (xQueueReceiveFromISR(TxQueue,&frame,NULL)==pdTRUE) ) {
CAN_send_frame(frame);
}
}
// Handle RX frame available interrupt
if ((interrupt & __CAN_IRQ_RX) != 0) {
CAN_read_frame();
}
// Handle error interrupts.
if ((interrupt & (__CAN_IRQ_ERR //0x4
| __CAN_IRQ_WAKEUP //0x10
| __CAN_IRQ_ERR_PASSIVE //0x20
)) != 0) {
/*handler*/
}
//https://www.esp32.com/viewtopic.php?t=5010
// Handle error interrupts.
if (interrupt & __CAN_IRQ_DATA_OVERRUN ) { //0x08
errOverrun++;
MODULE_CAN->CMR.B.CDO=1;
(void)MODULE_CAN->SR.U; // read SR after write to CMR to settle register changes
}
if (interrupt & __CAN_IRQ_ARB_LOST ) { //0x40
errArb++;
(void)MODULE_CAN->ALC.U; // must be read to re-enable interrupt
errCountTxInternal++;
}
if (interrupt & __CAN_IRQ_BUS_ERR ) { //0x80
errBus++;
(void)MODULE_CAN->ECC.U; // must be read to re-enable interrupt
errCountTxInternal+=2;
}
if (MODULE_CAN->TXERR.U == 0){
recoveryStarted=0;
}
if (errCountTxInternal >= 2 *CAN_MAX_TX_RETRY){
MODULE_CAN->CMR.B.AT=1; // abort transmission
(void)MODULE_CAN->SR.U;
errCountTxInternal=0;
}
}
//*****************************************************************************
void ESP32Can1Interrupt(void *) {
pNMEA2000_esp32->InterruptHandler();
}

View File

@ -1,106 +0,0 @@
/*
NMEA2000_esp32.h
Copyright (c) 2015-2020 Timo Lappalainen, Kave Oy, www.kave.fi
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.
Inherited NMEA2000 object for ESP32 modules. See also NMEA2000 library.
Thanks to Thomas Barth, barth-dev.de, who has written ESP32 CAN code. To avoid extra
libraries, I implemented his code directly to the NMEA2000_esp32 to avoid extra
can.h library, which may cause even naming problem.
The library sets as default CAN Tx pin to GPIO 16 and CAN Rx pint to GPIO 4. If you
want to use other pins (I have not tested can any pins be used), add defines e.g.
#define ESP32_CAN_TX_PIN GPIO_NUM_34
#define ESP32_CAN_RX_PIN GPIO_NUM_35
before including NMEA2000_esp32.h or NMEA2000_CAN.h
*/
#ifndef _NMEA2000_ESP32_H_
#define _NMEA2000_ESP32_H_
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "driver/gpio.h"
#include "NMEA2000.h"
#include "N2kMsg.h"
#include "ESP32_CAN_def.h"
#ifndef ESP32_CAN_TX_PIN
#define ESP32_CAN_TX_PIN GPIO_NUM_16
#endif
#ifndef ESP32_CAN_RX_PIN
#define ESP32_CAN_RX_PIN GPIO_NUM_4
#endif
class tNMEA2000_esp32 : public tNMEA2000
{
private:
bool IsOpen;
static bool CanInUse;
protected:
struct tCANFrame {
uint32_t id; // can identifier
uint8_t len; // length of data
uint8_t buf[8];
};
protected:
CAN_speed_t speed;
gpio_num_t TxPin;
gpio_num_t RxPin;
QueueHandle_t RxQueue;
QueueHandle_t TxQueue;
Print *debugStream;
int errOverrun=0;
int errArb=0;
int errBus=0;
int errRecovery=0;
int errCountTxInternal=0;
int errCancelTransmit=0;
int errReinit=0;
unsigned long recoveryStarted=0;
unsigned long lastSend=0;
unsigned long lastReceive=0;
int cntIntr=0;
protected:
void CAN_read_frame(); // Read frame to queue within interrupt
void CAN_send_frame(tCANFrame &frame); // Send frame
void CAN_init(bool installIsr=true);
void CAN_bus_off_recovery(); //recover from bus off
void CheckBusOff();
protected:
bool CANSendFrame(unsigned long id, unsigned char len, const unsigned char *buf, bool wait_sent=true);
bool CANOpen();
bool CANGetFrame(unsigned long &id, unsigned char &len, unsigned char *buf);
virtual void InitCANFrameBuffers();
public:
tNMEA2000_esp32(gpio_num_t _TxPin=ESP32_CAN_TX_PIN,
gpio_num_t _RxPin=ESP32_CAN_RX_PIN,
Print *debugStream=NULL);
void InterruptHandler();
};
#endif

View File

@ -1,3 +0,0 @@
forked from https://github.com/ttlappalainen/NMEA2000_esp32
with some error handling additions
based on https://www.esp32.com/viewtopic.php?t=5010

View File

@ -12,7 +12,6 @@
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "GwAppInfo.h"
#define USE_TWAI
// #define GW_MESSAGE_DEBUG_ENABLED
//#define FALLBACK_SERIAL
//#define CAN_ESP_DEBUG
@ -110,13 +109,8 @@ typedef std::map<String,String> StringMap;
GwLog logger(LOGLEVEL,NULL);
GwConfigHandler config(&logger);
#ifndef USE_TWAI
#include <NMEA2000_esp32.h> // forked from https://github.com/ttlappalainen/NMEA2000_esp32
tNMEA2000 &NMEA2000=*(new tNMEA2000_esp32(ESP32_CAN_TX_PIN,ESP32_CAN_RX_PIN,CDBS));
#else
#include "Nmea2kTwai.h"
tNMEA2000 &NMEA2000=*(new Nmea2kTwai(ESP32_CAN_TX_PIN,ESP32_CAN_RX_PIN,&logger));
#endif
#ifdef GWBUTTON_PIN
bool fixedApPass=false;