Skip to content

Commit 203b815

Browse files
committed
Add initial support for the ESP32's built-in SJA1000 compatible CAN controller
1 parent f65f343 commit 203b815

File tree

5 files changed

+454
-0
lines changed

5 files changed

+454
-0
lines changed

src/CAN.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44
#ifndef CAN_H
55
#define CAN_H
66

7+
#ifdef ARDUINO_ARCH_ESP32
8+
#include "ESP32SJA1000.h"
9+
#else
710
#include "MCP2515.h"
11+
#endif
812

913
#endif

src/ESP32SJA1000.cpp

Lines changed: 382 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,382 @@
1+
// Copyright (c) Sandeep Mistry. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+
#ifdef ARDUINO_ARCH_ESP32
5+
6+
#include "esp_intr.h"
7+
#include "soc/dport_reg.h"
8+
#include "driver/gpio.h"
9+
10+
#include "ESP32SJA1000.h"
11+
12+
#define REG_BASE 0x3ff6b000
13+
14+
#define REG_MOD 0x00
15+
#define REG_CMR 0x01
16+
#define REG_SR 0x02
17+
#define REG_IR 0x03
18+
#define REG_IER 0x04
19+
20+
#define REG_BTR0 0x06
21+
#define REG_BTR1 0x07
22+
#define REG_OCR 0x08
23+
24+
#define REG_ALC 0x0b
25+
#define REG_ECC 0x0c
26+
#define REG_EWLR 0x0d
27+
#define REG_RXERR 0x0e
28+
#define REG_TXERR 0x0f
29+
#define REG_SFF 0x10
30+
#define REG_EFF 0x10
31+
#define REG_ACRn(n) (0x10 + n)
32+
#define REG_AMRn(n) (0x14 + n)
33+
34+
#define REG_CDR 0x1F
35+
36+
37+
ESP32SJA1000Class::ESP32SJA1000Class() :
38+
CANControllerClass(),
39+
_rxPin(DEFAULT_CAN_RX_PIN),
40+
_txPin(DEFAULT_CAN_TX_PIN),
41+
_loopback(false),
42+
_intrHandle(NULL)
43+
{
44+
}
45+
46+
ESP32SJA1000Class::~ESP32SJA1000Class()
47+
{
48+
}
49+
50+
int ESP32SJA1000Class::begin(long baudRate)
51+
{
52+
CANControllerClass::begin(baudRate);
53+
54+
_loopback = false;
55+
56+
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_CAN_RST);
57+
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_CAN_CLK_EN);
58+
59+
// RX pin
60+
gpio_set_direction(_rxPin, GPIO_MODE_INPUT);
61+
gpio_matrix_in(_rxPin, CAN_RX_IDX, 0);
62+
gpio_pad_select_gpio(_rxPin);
63+
64+
// TX pin
65+
gpio_set_direction(_txPin, GPIO_MODE_OUTPUT);
66+
gpio_matrix_out(_txPin, CAN_TX_IDX, 0, 0);
67+
gpio_pad_select_gpio(_txPin);
68+
69+
modifyRegister(REG_CDR, 0x80, 0x80); // pelican mode
70+
modifyRegister(REG_BTR0, 0xc0, 0x40); // SJW = 1
71+
modifyRegister(REG_BTR1, 0x70, 0x10); // TSEG2 = 1
72+
73+
switch (baudRate) {
74+
case (long)1000E3:
75+
modifyRegister(REG_BTR1, 0x0f, 0x04);
76+
modifyRegister(REG_BTR0, 0x3f, 4);
77+
break;
78+
79+
case (long)500E3:
80+
modifyRegister(REG_BTR1, 0x0f, 0x0c);
81+
modifyRegister(REG_BTR0, 0x3f, 4);
82+
break;
83+
84+
case (long)250E3:
85+
modifyRegister(REG_BTR1, 0x0f, 0x0c);
86+
modifyRegister(REG_BTR0, 0x3f, 9);
87+
break;
88+
89+
case (long)200E3:
90+
modifyRegister(REG_BTR1, 0x0f, 0x0c);
91+
modifyRegister(REG_BTR0, 0x3f, 12);
92+
break;
93+
94+
case (long)125E3:
95+
modifyRegister(REG_BTR1, 0x0f, 0x0c);
96+
modifyRegister(REG_BTR0, 0x3f, 19);
97+
break;
98+
99+
case (long)100E3:
100+
modifyRegister(REG_BTR1, 0x0f, 0x0c);
101+
modifyRegister(REG_BTR0, 0x3f, 24);
102+
break;
103+
104+
case (long)80E3:
105+
modifyRegister(REG_BTR1, 0x0f, 0x0c);
106+
modifyRegister(REG_BTR0, 0x3f, 30);
107+
break;
108+
109+
case (long)50E3:
110+
modifyRegister(REG_BTR1, 0x0f, 0x0c);
111+
modifyRegister(REG_BTR0, 0x3f, 49);
112+
break;
113+
114+
case (long)40E3:
115+
modifyRegister(REG_BTR1, 0x0f, 0x0c);
116+
modifyRegister(REG_BTR0, 0x3f, 62);
117+
break;
118+
119+
case (long)20E3:
120+
modifyRegister(REG_BTR1, 0x0f, 0x0c);
121+
modifyRegister(REG_BTR0, 0x3f, 124);
122+
break;
123+
124+
case (long)10E3:
125+
modifyRegister(REG_BTR1, 0x0f, 0x0c);
126+
modifyRegister(REG_BTR0, 0x3f, 249);
127+
break;
128+
129+
default:
130+
return 0;
131+
break;
132+
}
133+
134+
modifyRegister(REG_BTR1, 0x80, 0x80); // SAM = 1
135+
writeRegister(REG_IER, 0xff); // enable all interrupts
136+
137+
// set filter to allow anything
138+
writeRegister(REG_ACRn(0), 0x00);
139+
writeRegister(REG_ACRn(1), 0x00);
140+
writeRegister(REG_ACRn(2), 0x00);
141+
writeRegister(REG_ACRn(3), 0x00);
142+
writeRegister(REG_AMRn(0), 0xff);
143+
writeRegister(REG_AMRn(1), 0xff);
144+
writeRegister(REG_AMRn(2), 0xff);
145+
writeRegister(REG_AMRn(3), 0xff);
146+
147+
148+
modifyRegister(REG_OCR, 0x03, 0x02); // normal output mode
149+
// reset error counters
150+
writeRegister(REG_TXERR, 0x00);
151+
writeRegister(REG_RXERR, 0x00);
152+
153+
// clear errors and interrupts
154+
readRegister(REG_ECC);
155+
readRegister(REG_IR);
156+
157+
// normal mode
158+
modifyRegister(REG_MOD, 0x1f, 0x00);
159+
160+
return 1;
161+
}
162+
163+
void ESP32SJA1000Class::end()
164+
{
165+
if (_intrHandle) {
166+
esp_intr_free(_intrHandle);
167+
_intrHandle = NULL;
168+
}
169+
170+
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_CAN_RST);
171+
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_CAN_CLK_EN);
172+
173+
CANControllerClass::end();
174+
}
175+
176+
int ESP32SJA1000Class::endPacket()
177+
{
178+
if (!CANControllerClass::endPacket()) {
179+
return 0;
180+
}
181+
182+
// wait for TX buffer to free
183+
while ((readRegister(REG_SR) & 0x04) != 0x04) {
184+
yield();
185+
}
186+
187+
int dataReg;
188+
189+
if (_txExtended) {
190+
writeRegister(REG_EFF, 0x80 | (_txRtr ? 0x40 : 0x00) | (0x0f & _txLength));
191+
writeRegister(REG_EFF + 1, _txId >> 21);
192+
writeRegister(REG_EFF + 2, _txId >> 13);
193+
writeRegister(REG_EFF + 3, _txId >> 5);
194+
writeRegister(REG_EFF + 4, _txId << 3);
195+
196+
dataReg = REG_EFF + 5;
197+
} else {
198+
writeRegister(REG_SFF, (_txRtr ? 0x40 : 0x00) | (0x0f & _txLength));
199+
writeRegister(REG_SFF + 1, _txId >> 3);
200+
writeRegister(REG_SFF + 2, _txId << 5);
201+
202+
dataReg = REG_SFF + 3;
203+
}
204+
205+
for (int i = 0; i < _txLength; i++) {
206+
writeRegister(dataReg + i, _txData[i]);
207+
}
208+
209+
if ( _loopback) {
210+
// self reception request
211+
modifyRegister(REG_CMR, 0x1f, 0x10);
212+
} else {
213+
// transmit request
214+
modifyRegister(REG_CMR, 0x1f, 0x01);
215+
}
216+
217+
// wait for TX complete
218+
while ((readRegister(REG_SR) & 0x08) != 0x08) {
219+
if (readRegister(REG_ECC) == 0xd9) {
220+
modifyRegister(REG_CMR, 0x1f, 0x02); // error, abort
221+
return 0;
222+
}
223+
yield();
224+
}
225+
226+
return 1;
227+
}
228+
229+
int ESP32SJA1000Class::parsePacket()
230+
{
231+
if ((readRegister(REG_SR) & 0x01) != 0x01) {
232+
// no packet
233+
return 0;
234+
}
235+
236+
_rxExtended = (readRegister(REG_SFF) & 0x80) ? true : false;
237+
_rxRtr = (readRegister(REG_SFF) & 0x40) ? true : false;
238+
_rxDlc = (readRegister(REG_SFF) & 0x0f);
239+
_rxIndex = 0;
240+
241+
int dataReg;
242+
243+
if (_rxExtended) {
244+
_rxId = (readRegister(REG_EFF + 1) << 21) |
245+
(readRegister(REG_EFF + 2) << 13) |
246+
(readRegister(REG_EFF + 3) << 5) |
247+
(readRegister(REG_EFF + 4) >> 3);
248+
249+
dataReg = REG_EFF + 5;
250+
} else {
251+
_rxId = (readRegister(REG_SFF + 1) << 3) | ((readRegister(REG_SFF + 2) >> 5) & 0x07);
252+
253+
dataReg = REG_SFF + 3;
254+
}
255+
256+
if (_rxRtr) {
257+
_rxLength = 0;
258+
} else {
259+
_rxLength = _rxDlc;
260+
261+
for (int i = 0; i < _rxLength; i++) {
262+
_rxData[i] = readRegister(dataReg + i);
263+
}
264+
}
265+
266+
// release RX buffer
267+
modifyRegister(REG_CMR, 0x04, 0x04);
268+
269+
return _rxDlc;
270+
}
271+
272+
void ESP32SJA1000Class::onReceive(void(*callback)(int))
273+
{
274+
CANControllerClass::onReceive(callback);
275+
276+
if (_intrHandle) {
277+
esp_intr_free(_intrHandle);
278+
_intrHandle = NULL;
279+
}
280+
281+
if (callback) {
282+
esp_intr_alloc(ETS_CAN_INTR_SOURCE, 0, ESP32SJA1000Class::onInterrupt, this, &_intrHandle);
283+
}
284+
}
285+
286+
int ESP32SJA1000Class::observe()
287+
{
288+
modifyRegister(REG_MOD, 0x1f, 0x01); // reset
289+
modifyRegister(REG_MOD, 0x1f, 0x02); // observe
290+
291+
return 1;
292+
}
293+
294+
int ESP32SJA1000Class::loopback()
295+
{
296+
_loopback = true;
297+
298+
modifyRegister(REG_MOD, 0x1f, 0x01); // reset
299+
modifyRegister(REG_MOD, 0x1f, 0x04); // self test mode
300+
301+
return 1;
302+
}
303+
304+
int ESP32SJA1000Class::sleep()
305+
{
306+
modifyRegister(REG_MOD, 0x1f, 0x10);
307+
308+
return 1;
309+
}
310+
311+
int ESP32SJA1000Class::wakeup()
312+
{
313+
modifyRegister(REG_MOD, 0x1f, 0x00);
314+
315+
return 1;
316+
}
317+
318+
void ESP32SJA1000Class::setPins(int rx, int tx)
319+
{
320+
_rxPin = (gpio_num_t)rx;
321+
_txPin = (gpio_num_t)tx;
322+
}
323+
324+
void ESP32SJA1000Class::dumpRegisters(Stream& out)
325+
{
326+
for (int i = 0; i < 32; i++) {
327+
byte b = readRegister(i);
328+
329+
out.print("0x");
330+
if (i < 16) {
331+
out.print('0');
332+
}
333+
out.print(i, HEX);
334+
out.print(": 0x");
335+
if (b < 16) {
336+
out.print('0');
337+
}
338+
out.println(b, HEX);
339+
}
340+
}
341+
342+
void ESP32SJA1000Class::handleInterrupt()
343+
{
344+
uint8_t ir = readRegister(REG_IR);
345+
346+
if (ir & 0x01) {
347+
// received packet, parse and call callback
348+
parsePacket();
349+
350+
_onReceive(available());
351+
}
352+
}
353+
354+
uint8_t ESP32SJA1000Class::readRegister(uint8_t address)
355+
{
356+
volatile uint32_t* reg = (volatile uint32_t*)(REG_BASE + address * 4);
357+
358+
return *reg;
359+
}
360+
361+
void ESP32SJA1000Class::modifyRegister(uint8_t address, uint8_t mask, uint8_t value)
362+
{
363+
volatile uint32_t* reg = (volatile uint32_t*)(REG_BASE + address * 4);
364+
365+
*reg = (*reg & ~mask) | value;
366+
}
367+
368+
void ESP32SJA1000Class::writeRegister(uint8_t address, uint8_t value)
369+
{
370+
volatile uint32_t* reg = (volatile uint32_t*)(REG_BASE + address * 4);
371+
372+
*reg = value;
373+
}
374+
375+
void ESP32SJA1000Class::onInterrupt(void* arg)
376+
{
377+
((ESP32SJA1000Class*)arg)->handleInterrupt();
378+
}
379+
380+
ESP32SJA1000Class CAN;
381+
382+
#endif

0 commit comments

Comments
 (0)