Hi, I decided to work on a different twist of the current libraries and forks of collin80, teachop, and pawelsky, and rework most of the existing code from scratch into a new library that has, currently, these features:
Before you ask, I'm currently doing it on a 3.6 and only for FLEXCAN0 until it matures, only then I would add CAN1 support and 3.2 registers
Debug will be enabled for initial version for any testers interested on testing, and suggesting other ideas to implement.
Secondly, I havn't added masking/filter support yet as I work on the structure, but by default I enable both in FIFO mode and mailbox mode all frames accepted, again, until it matures, then they will be added
1) FIFO (enabled or disabled dynamically), with interrupt capability (enableFIFOInterrupt/disableFIFOInterrupt)
2) Dynamic mailbox setup support: setMB(MB9, TX) (transmit mailbox), or setMB(MB9,RX,IDE) (setup an extended ID reception box)
3) Individual mailbox interrupt enabling (*.enableMBInterrupt(MB5)/*.disableMBInterrupt(MB5);
4) there is a pollFIFO() function that can give a user direct access to the FIFO frames, and at the same time, disable MB/FIFO interrupts, for as long as you poll frames.
This allows users to access frames directly rather than handling in their callbacks. The interrupts are restored when pollFIFO is called with a 0 overload. (myCAN.pollFIFO(msg, 1))(disable interrupt)(CAN.pollFIFO(msg, 0))(enable interrupt)
5) Callbacks, you have a global callback, and, if necessary, I've added individual mailbox callbacks as well!
This allows you to handle specific mailboxes with interrupts. everything else goes in global callback, including the individual which goes to both.
6) The constructor is pretty basic with only 2 initializers:
7) The .write(...) function has been redesigned. There is an attempt to scan for transmit buffers that are available, if none are available, it checks 2 more times before returning to user (0) that a transmit wasnt possible.
This has FIFO check routine for adaptation.
8) The .read(...) function has been redesigned. FIFO check routine optimizes mailbox reading. read(...) is not meant to read the FIFO buffer, use pollFIFO for that. However, the new way the read() function is done is it goes incrementally up each mailbox each read, so every time you request a read(), it never hits the same mailbox twice, ensuring even data requests. Should it encouter any TX buffers, it will skip them till the next available read buffer. Should nothing be readable (no data) within 2 cycles, the function is exited with a return of 0 as it should.
9) By default, when you enable FIFO, the library will setup FIFO for you with the 8 remaining mailboxes as transmit buffers. When you disable FIFO, the library will setup the first 4 mailboxes for Standard IDs and the next 4 for Extended IDs, remaining 8 for TX buffers. Should you want to change specific ones later on, just use setMB.
simple sending in the main loop :
and reading mailboxes:
Here is the All / Individual callbacks tests:
Output:
*** MB1 dipicts code printed from MB1 callback
without the *** dipicts normal catchall callback
An individual callback frame will be in both.
And here is the receiving MCU receiving the loop sends:
One of a good ideas is that in FIFO mode, we can setMB a mailbox with a reception interrupt box, keep FIFO interrupts off, and when you receive a match in your mailbox you could trigger the poll method to collect all your frames in ordered fashion. Mailboxes have interrupt priority over FIFO, I've tested an extended frame reception on MB9 with FIFO enabled and was able to do what I want when the callback fired
pollFIFO would be very useful for external libraries, where you can pass the frames directly to another function without touching your callback
By the way, I'm testing also with Fusion's dual can transceiver breakout from Tindie
Current Compilation:
Blank Sketch:
IFCT Library Demo Sketch:
Flexcan_Library Demo compilation:
looks like a 1200 byte memory difference betweeen blank sketch
The fork demo is 2K difference between mine as well
Here's a video of it in action:
https://www.youtube.com/watch?v=9H0HKlfSoRY
I should have it up on github sometime today
Before you ask, I'm currently doing it on a 3.6 and only for FLEXCAN0 until it matures, only then I would add CAN1 support and 3.2 registers
Debug will be enabled for initial version for any testers interested on testing, and suggesting other ideas to implement.
Secondly, I havn't added masking/filter support yet as I work on the structure, but by default I enable both in FIFO mode and mailbox mode all frames accepted, again, until it matures, then they will be added
1) FIFO (enabled or disabled dynamically), with interrupt capability (enableFIFOInterrupt/disableFIFOInterrupt)
2) Dynamic mailbox setup support: setMB(MB9, TX) (transmit mailbox), or setMB(MB9,RX,IDE) (setup an extended ID reception box)
3) Individual mailbox interrupt enabling (*.enableMBInterrupt(MB5)/*.disableMBInterrupt(MB5);
4) there is a pollFIFO() function that can give a user direct access to the FIFO frames, and at the same time, disable MB/FIFO interrupts, for as long as you poll frames.
This allows users to access frames directly rather than handling in their callbacks. The interrupts are restored when pollFIFO is called with a 0 overload. (myCAN.pollFIFO(msg, 1))(disable interrupt)(CAN.pollFIFO(msg, 0))(enable interrupt)
5) Callbacks, you have a global callback, and, if necessary, I've added individual mailbox callbacks as well!
Code:
void onReceive(const IFCTMBNUM &mb_num, _MB_ptr handler); /* individual mailbox callback function */
void onReceive(_MB_ptr handler); /* global callback function */
6) The constructor is pretty basic with only 2 initializers:
Code:
IFCT myCAN = IFCT(); // initialized default, 1Mbps on Can0
// or
IFCT myCAN = IFCT(1000000,FLEXCAN0_BASE); // initialize with 1Mbps on Can0 (register base address);
// or just do baud alone
IFCT myCAN = IFCT(1000000);
7) The .write(...) function has been redesigned. There is an attempt to scan for transmit buffers that are available, if none are available, it checks 2 more times before returning to user (0) that a transmit wasnt possible.
This has FIFO check routine for adaptation.
8) The .read(...) function has been redesigned. FIFO check routine optimizes mailbox reading. read(...) is not meant to read the FIFO buffer, use pollFIFO for that. However, the new way the read() function is done is it goes incrementally up each mailbox each read, so every time you request a read(), it never hits the same mailbox twice, ensuring even data requests. Should it encouter any TX buffers, it will skip them till the next available read buffer. Should nothing be readable (no data) within 2 cycles, the function is exited with a return of 0 as it should.
9) By default, when you enable FIFO, the library will setup FIFO for you with the 8 remaining mailboxes as transmit buffers. When you disable FIFO, the library will setup the first 4 mailboxes for Standard IDs and the next 4 for Extended IDs, remaining 8 for TX buffers. Should you want to change specific ones later on, just use setMB.
simple sending in the main loop :
Code:
msg.flags.extended = random(0,2);
msg.flags.remote = 0;
msg.len = 8;
msg.id = random(0x69, 0x178);
msg.buf[0] = random(0, 255);
msg.buf[1] = random(0, 255);
msg.buf[2] = random(0, 255);
msg.buf[3] = random(0, 255);
msg.buf[4] = random(0, 255);
msg.buf[5] = random(0, 255);
msg.buf[6] = random(0, 255);
msg.buf[7] = random(0, 255);
CAN.write(msg);
and reading mailboxes:
Code:
if (CAN.read(msg)) {
Serial.print(" LEN: "); Serial.print(msg.len);
Serial.print(" EXT: "); Serial.print(msg.flags.extended);
Serial.print(" REMOTE: "); Serial.print(msg.rtr);
Serial.print(" TS: "); Serial.print(msg.timestamp);
Serial.print(" ID: "); Serial.print(msg.id);
Serial.print(" Buffer: ");
for ( uint8_t i = 0; i < msg.len; i++ ) {
Serial.print(msg.buf[i], HEX); Serial.print(" ");
} Serial.println();
}
Here is the All / Individual callbacks tests:
Code:
CAN.enableFIFO(0);
CAN.enableFIFOInterrupt(0);
CAN.onReceive(myMSG);
CAN.onReceive(MB1, MB1cb);
Output:
Code:
MB 0 LEN: 8 EXT: 0 REMOTE: 0 TS: 61237 ID: 256 Buffer: BE 14 0 64 80 40 20 10
MB 1 LEN: 8 EXT: 0 REMOTE: 0 TS: 61360 ID: 256 Buffer: BF 14 0 64 80 40 20 10
*** MB 1 LEN: 8 EXT: 0 REMOTE: 0 TS: 61360 ID: 256 Buffer: BF 14 0 64 80 40 20 10
MB 4 LEN: 8 EXT: 1 REMOTE: 0 TS: 44858 ID: 291 Buffer: A 14 0 64 80 40 20 10
MB 0 LEN: 8 EXT: 0 REMOTE: 0 TS: 61481 ID: 256 Buffer: C0 14 0 64 80 40 20 10
MB 1 LEN: 8 EXT: 0 REMOTE: 0 TS: 61603 ID: 256 Buffer: C1 14 0 64 80 40 20 10
*** MB 1 LEN: 8 EXT: 0 REMOTE: 0 TS: 61603 ID: 256 Buffer: C1 14 0 64 80 40 20 10
MB 0 LEN: 8 EXT: 0 REMOTE: 0 TS: 12683 ID: 256 Buffer: C3 14 0 64 80 40 20 10
MB 1 LEN: 8 EXT: 0 REMOTE: 0 TS: 12804 ID: 256 Buffer: C4 14 0 64 80 40 20 10
*** MB 1 LEN: 8 EXT: 0 REMOTE: 0 TS: 12804 ID: 256 Buffer: C4 14 0 64 80 40 20 10
MB 4 LEN: 8 EXT: 1 REMOTE: 0 TS: 61845 ID: 291 Buffer: A 14 0 64 80 40 20 10
MB 0 LEN: 8 EXT: 0 REMOTE: 0 TS: 12927 ID: 256 Buffer: C5 14 0 64 80 40 20 10
MB 1 LEN: 8 EXT: 0 REMOTE: 0 TS: 13049 ID: 256 Buffer: C6 14 0 64 80 40 20 10
*** MB 1 LEN: 8 EXT: 0 REMOTE: 0 TS: 13049 ID: 256 Buffer: C6 14 0 64 80 40 20 10
MB 0 LEN: 8 EXT: 0 REMOTE: 0 TS: 29664 ID: 256 Buffer: C8 14 0 64 80 40 20 10
MB 1 LEN: 8 EXT: 0 REMOTE: 0 TS: 29787 ID: 256 Buffer: C9 14 0 64 80 40 20 10
*** MB 1 LEN: 8 EXT: 0 REMOTE: 0 TS: 29787 ID: 256 Buffer: C9 14 0 64 80 40 20 10
*** MB1 dipicts code printed from MB1 callback
without the *** dipicts normal catchall callback
An individual callback frame will be in both.
And here is the receiving MCU receiving the loop sends:
Code:
LEN: 8 EXT: 1 REMOTE: 0 TS: 11536 ID: 354 Buffer: 11 82 57 4F 4A 4C 8D 21
LEN: 8 EXT: 1 REMOTE: 0 TS: 31544 ID: 268 Buffer: 82 46 4F F1 DA 9C 7D A6
LEN: 8 EXT: 0 REMOTE: 0 TS: 51550 ID: 173 Buffer: B0 52 F4 7D 2 5F E5 C6
LEN: 8 EXT: 0 REMOTE: 0 TS: 6021 ID: 288 Buffer: 4C F4 AB 2F B8 88 CE 21
LEN: 8 EXT: 1 REMOTE: 0 TS: 26028 ID: 351 Buffer: 18 24 39 C4 E5 51 39 3E
LEN: 8 EXT: 0 REMOTE: 0 TS: 46035 ID: 361 Buffer: B1 B1 F2 C1 BA FE 56 44
LEN: 8 EXT: 0 REMOTE: 0 TS: 506 ID: 319 Buffer: DF 6 54 7 E2 DA D3 59
LEN: 8 EXT: 1 REMOTE: 0 TS: 20512 ID: 140 Buffer: 61 41 A 44 59 B6 DA 72
LEN: 8 EXT: 0 REMOTE: 0 TS: 40519 ID: 353 Buffer: 23 D0 92 2A EE F7 71 2E
LEN: 8 EXT: 1 REMOTE: 0 TS: 60527 ID: 153 Buffer: DB 1A BC 57 F3 A7 9F 2C
LEN: 8 EXT: 1 REMOTE: 0 TS: 14998 ID: 226 Buffer: 61 B5 3E D8 CB 40 14 E0
LEN: 8 EXT: 1 REMOTE: 0 TS: 35005 ID: 221 Buffer: 61 FB 14 B0 1C 85 D 19
LEN: 8 EXT: 0 REMOTE: 0 TS: 55012 ID: 232 Buffer: 47 F8 14 23 C7 32 D1 5B
LEN: 8 EXT: 1 REMOTE: 0 TS: 9483 ID: 261 Buffer: AB A2 93 E8 F3 9 59 73
LEN: 8 EXT: 1 REMOTE: 0 TS: 29490 ID: 198 Buffer: 35 70 C0 84 27 A5 50 DC
LEN: 8 EXT: 1 REMOTE: 0 TS: 49497 ID: 112 Buffer: 69 D5 36 56 95 F0 B5 54
LEN: 8 EXT: 0 REMOTE: 0 TS: 3969 ID: 171 Buffer: DE A5 98 48 14 C5 34 F7
LEN: 8 EXT: 0 REMOTE: 0 TS: 23976 ID: 208 Buffer: 13 50 E7 34 6A 41 D3 81
LEN: 8 EXT: 0 REMOTE: 0 TS: 43983 ID: 195 Buffer: 22 4 FE 31 71 12 F1 1F
One of a good ideas is that in FIFO mode, we can setMB a mailbox with a reception interrupt box, keep FIFO interrupts off, and when you receive a match in your mailbox you could trigger the poll method to collect all your frames in ordered fashion. Mailboxes have interrupt priority over FIFO, I've tested an extended frame reception on MB9 with FIFO enabled and was able to do what I want when the callback fired
pollFIFO would be very useful for external libraries, where you can pass the frames directly to another function without touching your callback
By the way, I'm testing also with Fusion's dual can transceiver breakout from Tindie
Current Compilation:
Blank Sketch:
Code:
Sketch uses 9200 bytes (0%) of program storage space. Maximum is 1048576 bytes.
Global variables use 4212 bytes (1%) of dynamic memory, leaving 257932 bytes for local variables. Maximum is 262144 bytes.
IFCT Library Demo Sketch:
Code:
Sketch uses 20348 bytes (1%) of program storage space. Maximum is 1048576 bytes.
Global variables use 5416 bytes (2%) of dynamic memory, leaving 256728 bytes for local variables. Maximum is 262144 bytes.
Flexcan_Library Demo compilation:
Code:
Sketch uses 16924 bytes (1%) of program storage space. Maximum is 1048576 bytes.
Global variables use 7624 bytes (2%) of dynamic memory, leaving 254520 bytes for local variables. Maximum is 262144 bytes.
looks like a 1200 byte memory difference betweeen blank sketch
The fork demo is 2K difference between mine as well
Here's a video of it in action:
https://www.youtube.com/watch?v=9H0HKlfSoRY
I should have it up on github sometime today
Last edited: