Easylink_CAN_Waker/lib/arduino-CAN-master/src/ESP32SJA1000.cpp

416 lines
9.3 KiB
C++

// Copyright (c) Sandeep Mistry. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#ifdef ARDUINO_ARCH_ESP32
#include "esp_intr.h"
#include "soc/dport_reg.h"
#include "driver/gpio.h"
#include "ESP32SJA1000.h"
#define REG_BASE 0x3ff6b000
#define REG_MOD 0x00
#define REG_CMR 0x01
#define REG_SR 0x02
#define REG_IR 0x03
#define REG_IER 0x04
#define REG_BTR0 0x06
#define REG_BTR1 0x07
#define REG_OCR 0x08
#define REG_ALC 0x0b
#define REG_ECC 0x0c
#define REG_EWLR 0x0d
#define REG_RXERR 0x0e
#define REG_TXERR 0x0f
#define REG_SFF 0x10
#define REG_EFF 0x10
#define REG_ACRn(n) (0x10 + n)
#define REG_AMRn(n) (0x14 + n)
#define REG_CDR 0x1F
ESP32SJA1000Class::ESP32SJA1000Class() :
CANControllerClass(),
_rxPin(DEFAULT_CAN_RX_PIN),
_txPin(DEFAULT_CAN_TX_PIN),
_loopback(false),
_intrHandle(NULL)
{
}
ESP32SJA1000Class::~ESP32SJA1000Class()
{
}
int ESP32SJA1000Class::begin(long baudRate)
{
CANControllerClass::begin(baudRate);
_loopback = false;
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_CAN_RST);
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_CAN_CLK_EN);
// RX pin
gpio_set_direction(_rxPin, GPIO_MODE_INPUT);
gpio_matrix_in(_rxPin, CAN_RX_IDX, 0);
gpio_pad_select_gpio(_rxPin);
// TX pin
gpio_set_direction(_txPin, GPIO_MODE_OUTPUT);
gpio_matrix_out(_txPin, CAN_TX_IDX, 0, 0);
gpio_pad_select_gpio(_txPin);
modifyRegister(REG_CDR, 0x80, 0x80); // pelican mode
modifyRegister(REG_BTR0, 0xc0, 0x40); // SJW = 1
modifyRegister(REG_BTR1, 0x70, 0x10); // TSEG2 = 1
switch (baudRate) {
case (long)1000E3:
modifyRegister(REG_BTR1, 0x0f, 0x04);
modifyRegister(REG_BTR0, 0x3f, 4);
break;
case (long)500E3:
modifyRegister(REG_BTR1, 0x0f, 0x0c);
modifyRegister(REG_BTR0, 0x3f, 4);
break;
case (long)250E3:
modifyRegister(REG_BTR1, 0x0f, 0x0c);
modifyRegister(REG_BTR0, 0x3f, 9);
break;
case (long)200E3:
modifyRegister(REG_BTR1, 0x0f, 0x0c);
modifyRegister(REG_BTR0, 0x3f, 12);
break;
case (long)125E3:
modifyRegister(REG_BTR1, 0x0f, 0x0c);
modifyRegister(REG_BTR0, 0x3f, 19);
break;
case (long)100E3:
modifyRegister(REG_BTR1, 0x0f, 0x0c);
modifyRegister(REG_BTR0, 0x3f, 24);
break;
case (long)80E3:
modifyRegister(REG_BTR1, 0x0f, 0x0c);
modifyRegister(REG_BTR0, 0x3f, 30);
break;
case (long)50E3:
modifyRegister(REG_BTR1, 0x0f, 0x0c);
modifyRegister(REG_BTR0, 0x3f, 49);
break;
/*
Due to limitations in ESP32 hardware and/or RTOS software, baudrate can't be lower than 50kbps.
See https://esp32.com/viewtopic.php?t=2142
*/
default:
return 0;
break;
}
modifyRegister(REG_BTR1, 0x80, 0x80); // SAM = 1
writeRegister(REG_IER, 0xef); // enable all interrupts
// set filter to allow anything
writeRegister(REG_ACRn(0), 0x00);
writeRegister(REG_ACRn(1), 0x00);
writeRegister(REG_ACRn(2), 0x00);
writeRegister(REG_ACRn(3), 0x00);
writeRegister(REG_AMRn(0), 0xff);
writeRegister(REG_AMRn(1), 0xff);
writeRegister(REG_AMRn(2), 0xff);
writeRegister(REG_AMRn(3), 0xff);
modifyRegister(REG_OCR, 0x03, 0x02); // normal output mode
// reset error counters
writeRegister(REG_TXERR, 0x00);
writeRegister(REG_RXERR, 0x00);
// clear errors and interrupts
readRegister(REG_ECC);
readRegister(REG_IR);
// normal mode
modifyRegister(REG_MOD, 0x08, 0x08);
modifyRegister(REG_MOD, 0x17, 0x00);
return 1;
}
void ESP32SJA1000Class::end()
{
if (_intrHandle) {
esp_intr_free(_intrHandle);
_intrHandle = NULL;
}
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_CAN_RST);
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_CAN_CLK_EN);
CANControllerClass::end();
}
int ESP32SJA1000Class::endPacket()
{
if (!CANControllerClass::endPacket()) {
return 0;
}
// wait for TX buffer to free
while ((readRegister(REG_SR) & 0x04) != 0x04) {
yield();
}
int dataReg;
if (_txExtended) {
writeRegister(REG_EFF, 0x80 | (_txRtr ? 0x40 : 0x00) | (0x0f & _txLength));
writeRegister(REG_EFF + 1, _txId >> 21);
writeRegister(REG_EFF + 2, _txId >> 13);
writeRegister(REG_EFF + 3, _txId >> 5);
writeRegister(REG_EFF + 4, _txId << 3);
dataReg = REG_EFF + 5;
} else {
writeRegister(REG_SFF, (_txRtr ? 0x40 : 0x00) | (0x0f & _txLength));
writeRegister(REG_SFF + 1, _txId >> 3);
writeRegister(REG_SFF + 2, _txId << 5);
dataReg = REG_SFF + 3;
}
for (int i = 0; i < _txLength; i++) {
writeRegister(dataReg + i, _txData[i]);
}
if ( _loopback) {
// self reception request
modifyRegister(REG_CMR, 0x1f, 0x10);
} else {
// transmit request
modifyRegister(REG_CMR, 0x1f, 0x01);
}
// wait for TX complete
while ((readRegister(REG_SR) & 0x08) != 0x08) {
if (readRegister(REG_ECC) == 0xd9) {
modifyRegister(REG_CMR, 0x1f, 0x02); // error, abort
return 0;
}
yield();
}
return 1;
}
int ESP32SJA1000Class::parsePacket()
{
if ((readRegister(REG_SR) & 0x01) != 0x01) {
// no packet
return 0;
}
_rxExtended = (readRegister(REG_SFF) & 0x80) ? true : false;
_rxRtr = (readRegister(REG_SFF) & 0x40) ? true : false;
_rxDlc = (readRegister(REG_SFF) & 0x0f);
_rxIndex = 0;
int dataReg;
if (_rxExtended) {
_rxId = (readRegister(REG_EFF + 1) << 21) |
(readRegister(REG_EFF + 2) << 13) |
(readRegister(REG_EFF + 3) << 5) |
(readRegister(REG_EFF + 4) >> 3);
dataReg = REG_EFF + 5;
} else {
_rxId = (readRegister(REG_SFF + 1) << 3) | ((readRegister(REG_SFF + 2) >> 5) & 0x07);
dataReg = REG_SFF + 3;
}
if (_rxRtr) {
_rxLength = 0;
} else {
_rxLength = _rxDlc;
for (int i = 0; i < _rxLength; i++) {
_rxData[i] = readRegister(dataReg + i);
}
}
// release RX buffer
modifyRegister(REG_CMR, 0x04, 0x04);
return _rxDlc;
}
void ESP32SJA1000Class::onReceive(void(*callback)(int))
{
CANControllerClass::onReceive(callback);
if (_intrHandle) {
esp_intr_free(_intrHandle);
_intrHandle = NULL;
}
if (callback) {
esp_intr_alloc(ETS_CAN_INTR_SOURCE, 0, ESP32SJA1000Class::onInterrupt, this, &_intrHandle);
}
}
int ESP32SJA1000Class::filter(int id, int mask)
{
id &= 0x7ff;
mask = ~(mask & 0x7ff);
modifyRegister(REG_MOD, 0x17, 0x01); // reset
writeRegister(REG_ACRn(0), id >> 3);
writeRegister(REG_ACRn(1), id << 5);
writeRegister(REG_ACRn(2), 0x00);
writeRegister(REG_ACRn(3), 0x00);
writeRegister(REG_AMRn(0), mask >> 3);
writeRegister(REG_AMRn(1), (mask << 5) | 0x1f);
writeRegister(REG_AMRn(2), 0xff);
writeRegister(REG_AMRn(3), 0xff);
modifyRegister(REG_MOD, 0x17, 0x00); // normal
return 1;
}
int ESP32SJA1000Class::filterExtended(long id, long mask)
{
id &= 0x1FFFFFFF;
mask &= ~(mask & 0x1FFFFFFF);
modifyRegister(REG_MOD, 0x17, 0x01); // reset
writeRegister(REG_ACRn(0), id >> 21);
writeRegister(REG_ACRn(1), id >> 13);
writeRegister(REG_ACRn(2), id >> 5);
writeRegister(REG_ACRn(3), id << 3);
writeRegister(REG_AMRn(0), mask >> 21);
writeRegister(REG_AMRn(1), mask >> 13);
writeRegister(REG_AMRn(2), mask >> 5);
writeRegister(REG_AMRn(3), (mask << 3) | 0x1f);
modifyRegister(REG_MOD, 0x17, 0x00); // normal
return 1;
}
int ESP32SJA1000Class::observe()
{
modifyRegister(REG_MOD, 0x17, 0x01); // reset
modifyRegister(REG_MOD, 0x17, 0x02); // observe
return 1;
}
int ESP32SJA1000Class::loopback()
{
_loopback = true;
modifyRegister(REG_MOD, 0x17, 0x01); // reset
modifyRegister(REG_MOD, 0x17, 0x04); // self test mode
return 1;
}
int ESP32SJA1000Class::sleep()
{
modifyRegister(REG_MOD, 0x1f, 0x10);
return 1;
}
int ESP32SJA1000Class::wakeup()
{
modifyRegister(REG_MOD, 0x1f, 0x00);
return 1;
}
void ESP32SJA1000Class::setPins(int rx, int tx)
{
_rxPin = (gpio_num_t)rx;
_txPin = (gpio_num_t)tx;
}
void ESP32SJA1000Class::dumpRegisters(Stream& out)
{
for (int i = 0; i < 32; i++) {
byte b = readRegister(i);
out.print("0x");
if (i < 16) {
out.print('0');
}
out.print(i, HEX);
out.print(": 0x");
if (b < 16) {
out.print('0');
}
out.println(b, HEX);
}
}
void ESP32SJA1000Class::handleInterrupt()
{
uint8_t ir = readRegister(REG_IR);
if (ir & 0x01) {
// received packet, parse and call callback
parsePacket();
_onReceive(available());
}
}
uint8_t ESP32SJA1000Class::readRegister(uint8_t address)
{
volatile uint32_t* reg = (volatile uint32_t*)(REG_BASE + address * 4);
return *reg;
}
void ESP32SJA1000Class::modifyRegister(uint8_t address, uint8_t mask, uint8_t value)
{
volatile uint32_t* reg = (volatile uint32_t*)(REG_BASE + address * 4);
*reg = (*reg & ~mask) | value;
}
void ESP32SJA1000Class::writeRegister(uint8_t address, uint8_t value)
{
volatile uint32_t* reg = (volatile uint32_t*)(REG_BASE + address * 4);
*reg = value;
}
void ESP32SJA1000Class::onInterrupt(void* arg)
{
((ESP32SJA1000Class*)arg)->handleInterrupt();
}
ESP32SJA1000Class CAN;
#endif