Skip to content
This repository was archived by the owner on Jun 8, 2023. It is now read-only.

Commit a5b3912

Browse files
committed
implement proper pin management
1 parent fe6c290 commit a5b3912

File tree

3 files changed

+3175
-23
lines changed

3 files changed

+3175
-23
lines changed

mkcandata.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#!/usr/bin/python3
2+
3+
def defines(name, suffix):
4+
print(f'const can_function {name} [] = {{')
5+
for instance in (0, 1):
6+
for function in 'HI':
7+
for port in 'ABCD':
8+
for idx in range(32):
9+
pin = f'P{port}{idx:02d}'
10+
pinmux = f'PINMUX_{pin}{function}_CAN{instance}_{suffix}'
11+
print(f'''\
12+
#if defined({pinmux}) && ! defined(IGNORE_PIN_{pin})
13+
{{PIN_{pin} >> 5, PIN_{pin} & 0x1f, {instance}, {pinmux} & 0xf}},
14+
#endif''')
15+
print(f'}};')
16+
print()
17+
18+
print('''\
19+
struct can_function {
20+
unsigned port:3;
21+
unsigned pin:5;
22+
unsigned instance:1;
23+
unsigned mux:4;
24+
};
25+
26+
''')
27+
28+
defines('can_rx', 'RX')
29+
defines('can_tx', 'TX')

src/CANSAME5x.cpp

Lines changed: 60 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -9,23 +9,34 @@
99

1010
#include "same51.h"
1111

12+
namespace
13+
{
14+
#include "CANSAME5x_port.h"
15+
}
16+
1217
#define hw (reinterpret_cast<Can *>(this->_hw))
1318
#define state (reinterpret_cast<_canSAME5x_state *>(this->_state))
1419

1520
#define DIV_ROUND(a, b) (((a) + (b) / 2) / (b))
1621
#define DIV_ROUND_UP(a, b) (((a) + (b)-1) / (b))
1722

1823
#define GCLK_CAN1 GCLK_PCHCTRL_GEN_GCLK1_Val
24+
#define GCLK_CAN0 GCLK_PCHCTRL_GEN_GCLK1_Val
1925
#define ADAFRUIT_ZEROCAN_TX_BUFFER_SIZE (1)
2026
#define ADAFRUIT_ZEROCAN_RX_FILTER_SIZE (1)
2127
#define ADAFRUIT_ZEROCAN_RX_FIFO_SIZE (8)
2228
#define ADAFRUIT_ZEROCAN_MAX_MESSAGE_LENGTH (8)
2329

24-
#define CAN0_FUNCTION (EPioType(8))
25-
#define CAN1_FUNCTION (EPioType(7))
26-
2730
namespace
2831
{
32+
33+
template <class T, std::size_t N>
34+
constexpr size_t size(const T (&array)[N]) noexcept
35+
{
36+
return N;
37+
}
38+
39+
2940
// Adapted from ASF3 interrupt_sam_nvic.c:
3041

3142
volatile unsigned long cpu_irq_critical_section_counter = 0;
@@ -93,8 +104,7 @@ struct _canSAME5x_state
93104
// This data must be in the first 64kB of RAM. The "canram" section
94105
// receives special support from the linker file in the Feather M4 CAN's
95106
// board support package.
96-
// TODO support CAN0 and CAN1 simultaneously (state would be an array of 2)
97-
__attribute__((section("canram"))) _canSAME5x_state can_state;
107+
__attribute__((section(".canram"))) _canSAME5x_state can_state[2];
98108

99109
constexpr uint32_t can_frequency = VARIANT_GCLK1_FREQ;
100110
bool compute_nbtp(uint32_t baudrate, CAN_NBTP_Type &result)
@@ -113,6 +123,24 @@ bool compute_nbtp(uint32_t baudrate, CAN_NBTP_Type &result)
113123
result.bit.NSJW = DIV_ROUND(clocks_after_sample, divisor * 4);
114124
return true;
115125
}
126+
127+
EPioType find_pin(const can_function *table, size_t n, int arduino_pin, int &instance) {
128+
if(arduino_pin < 0 || arduino_pin > PINS_COUNT) {
129+
return (EPioType)-1;
130+
}
131+
132+
unsigned port = g_APinDescription[arduino_pin].ulPort;
133+
unsigned pin = g_APinDescription[arduino_pin].ulPin;
134+
for(size_t i = 0; i<n; i++) {
135+
if(table[i].port == port && table[i].pin == pin) {
136+
if(instance == -1 || table[i].instance == instance) {
137+
instance = table[i].instance;
138+
return EPioType(table[i].mux);
139+
}
140+
}
141+
}
142+
}
143+
116144
} // namespace
117145

118146
CANSAME5x::CANSAME5x(uint8_t TX_PIN, uint8_t RX_PIN)
@@ -130,22 +158,33 @@ int CANSAME5x::begin(long baudrate) {
130158
return 0;
131159
}
132160

161+
int instance = -1;
162+
EPioType tx_function = find_pin(can_tx, size(can_tx), _tx, instance);
163+
EPioType rx_function = find_pin(can_rx, size(can_rx), _rx, instance);
164+
165+
if(tx_function == EPioType(-1) || rx_function == EPioType(-1) || instance == -1) {
166+
return 0;
167+
}
168+
133169
CAN_NBTP_Type nbtp;
134170
if (!compute_nbtp(baudrate, nbtp)) {
135171
return 0;
136172
}
137173

138-
// TODO: Support the CAN0 peripheral, which uses pinmux 8
139-
_hw = reinterpret_cast<void *>(CAN1);
140-
_state = reinterpret_cast<void *>(&can_state);
141-
_idx = 1;
142-
memset(state, 0, sizeof(*state));
174+
_idx = instance;
175+
_hw = reinterpret_cast<void *>(_idx == 0 ? CAN0 : CAN1);
176+
_state = reinterpret_cast<void *>(&can_state[_idx]);
143177

144-
pinPeripheral(_tx, CAN1_FUNCTION);
145-
pinPeripheral(_rx, CAN1_FUNCTION);
178+
memset(state, 0, sizeof(*state));
146179

147-
GCLK->PCHCTRL[CAN1_GCLK_ID].reg = GCLK_CAN1 | (1 << GCLK_PCHCTRL_CHEN_Pos);
180+
pinPeripheral(_tx, tx_function);
181+
pinPeripheral(_rx, rx_function);
148182

183+
if(_idx == 0) {
184+
GCLK->PCHCTRL[CAN0_GCLK_ID].reg = GCLK_CAN0 | (1 << GCLK_PCHCTRL_CHEN_Pos);
185+
} else {
186+
GCLK->PCHCTRL[CAN1_GCLK_ID].reg = GCLK_CAN1 | (1 << GCLK_PCHCTRL_CHEN_Pos);
187+
}
149188
// reset and allow configuration change
150189
hw->CCCR.bit.INIT = 1;
151190
while (!hw->CCCR.bit.INIT) {
@@ -223,7 +262,12 @@ int CANSAME5x::begin(long baudrate) {
223262

224263
// Enable receive IRQ (masked until enabled in NVIC)
225264
hw->IE.bit.RF0NE = true;
226-
hw->ILE.bit.EINT0 = true;
265+
if (_idx == 0) {
266+
hw->ILE.bit.EINT0 = true;
267+
} else {
268+
hw->ILE.bit.EINT1 = true;
269+
}
270+
hw->ILS.bit.RF0NL = _idx;
227271

228272
// Set nominal baud rate
229273
hw->NBTP.reg = nbtp.reg;
@@ -336,23 +380,17 @@ void CANSAME5x::onReceive(void(*callback)(int))
336380
{
337381
CANControllerClass::onReceive(callback);
338382

339-
static_assert(CAN0_IRQn + 1 == CAN1_IRQn);
340-
341-
auto irq = IRQn_Type(CAN0_IRQn + _idx);
383+
auto irq = _idx == 0 ? CAN0_IRQn : CAN1_IRQn;
342384
if(callback) {
343-
Serial.println("enabling irq");
344385
NVIC_EnableIRQ(irq);
345386
} else {
346-
Serial.println("disabling irq");
347387
NVIC_DisableIRQ(irq);
348388
}
349389
}
350390

351391
void CANSAME5x::handleInterrupt() {
352392
uint32_t ir = hw->IR.reg;
353393

354-
// Serial.print("in irq");
355-
// Serial.println(ir, HEX);
356394
if (ir & CAN_IR_RF0N) {
357395
while(int i = parsePacket()) _onReceive(i);
358396
}
@@ -373,7 +411,6 @@ int CANSAME5x::filter(int id, int mask)
373411
state->extended_rx_filter[0].XIDFE_0.bit.EFEC = CAN_XIDFE_0_EFEC_REJECT_Val;
374412
state->extended_rx_filter[0].XIDFE_1.bit.EFID2 = 0; // mask
375413
state->extended_rx_filter[0].XIDFE_1.bit.EFT = CAN_XIDFE_1_EFT_CLASSIC_Val;
376-
//TODO
377414
}
378415

379416
int CANSAME5x::filterExtended(long id, long mask)
@@ -439,7 +476,7 @@ int CANSAME5x::wakeup() {
439476
return 1;
440477
}
441478
void CANSAME5x::onInterrupt() {
442-
for(int i=0; i<2; i++) {
479+
for(int i=0; i<size(instances); i++) {
443480
CANSAME5x *instance = instances[i];
444481
if(instance) {
445482
instance->handleInterrupt();

0 commit comments

Comments
 (0)