Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lots of improvements, FDCAN preparation #45

Merged
merged 51 commits into from
Jan 23, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
41ad5e8
add alternative constructors for more pin configuration options
duckylotl Dec 28, 2024
f099f77
add setMode function to set a mode by arg. Better hints that modes ar…
duckylotl Dec 29, 2024
c2ae037
allow configuration of the IRQ priorities, default to lowest priority
duckylotl Dec 29, 2024
0817a12
be specific with IRQ aliasing, add notes
duckylotl Dec 30, 2024
ca37a27
enable / disable the Rx0 IRQ as well
duckylotl Dec 30, 2024
7d0bb7c
add hook for the CEC Handler for the F0 Platform.
duckylotl Dec 30, 2024
fe2af09
detect USB Driver and print incompatibility error
duckylotl Dec 30, 2024
6cbfeb8
Add workaround (enabled by user) for F1 in case USB is used. Uses FIF…
duckylotl Dec 30, 2024
9239e50
add constructor that takes digital pins as arguments
duckylotl Dec 30, 2024
8cdb947
move CAN_HandleTypeDef object into the class together with a pointer …
duckylotl Dec 31, 2024
064f6d9
protect HAL calls from uninitialized handle
duckylotl Jan 1, 2025
817fa8a
fix: do not enable the Tx interrupt flag if TX IRQ is blocked by USB
duckylotl Jan 1, 2025
4898233
fix: handle the special case with shared USB IRQ in enableMBInterrupt…
duckylotl Jan 1, 2025
be7ae1a
fix: don't setup not connected pin
duckylotl Jan 1, 2025
374018c
move peripheral resolving and registration with globals into begin()
duckylotl Jan 1, 2025
fb81317
let setBaudrate() be called before begin(). Save baudrate and use on …
duckylotl Jan 1, 2025
a9038c1
allow restarting bus with other baudrate
duckylotl Jan 1, 2025
807198b
only initialize filters on first start, not on each re-start
duckylotl Jan 1, 2025
8a821fe
add end() function to de-initialize and release can peripheral
duckylotl Jan 1, 2025
53271d9
on F1 platform verify that both pins are using the same alternate fun…
duckylotl Jan 1, 2025
f3aa639
fix: set SlaveStartFilterBank for all ConfigFilter calls. And cleanup…
duckylotl Jan 2, 2025
a05be3d
turn off unused filters during init
duckylotl Jan 2, 2025
b583569
add feedback to baudrate calculation, don't start with impossible clo…
duckylotl Jan 2, 2025
dc12061
use HAL function to get bus clock directly
duckylotl Jan 2, 2025
6d50b4f
remove redundant mode member variable
duckylotl Jan 2, 2025
ff8fbfc
move static init value initialization from begin() to init()
duckylotl Jan 2, 2025
53d09a0
add proper support for all filter types. Legacy function still has ol…
duckylotl Jan 2, 2025
f44452a
change FIFO target to action in prep for FDCAN
duckylotl Jan 2, 2025
473b58d
add setFilter variant that sets filter state without changing filter …
duckylotl Jan 2, 2025
ea1900b
fix: add CAN2 filter index offset
duckylotl Jan 2, 2025
a2d634f
fix: properly only set state without clobbering other filter settings…
duckylotl Jan 2, 2025
221a84c
add macros to select default FIFO based on platform limitations
duckylotl Jan 2, 2025
972ca0e
use custom filter functions for filter initialization
duckylotl Jan 2, 2025
6e07d48
read all pending messages. Multiple message events can happen before …
duckylotl Jan 2, 2025
6b1f21f
rename getAPB1Clock() to more generic getCanPeripheralClock()
duckylotl Jan 5, 2025
60a9e2d
remove CanHandle arg from baudrate calculation functions, use member …
duckylotl Jan 5, 2025
50edb2f
formatting, group functions according to operational state
duckylotl Jan 5, 2025
c13ee3e
change STM32 style filter function return value to true on success. K…
duckylotl Jan 5, 2025
a9bcfa3
fix: check filter bank bounds
duckylotl Jan 5, 2025
f594cf6
fix: check if instance is initialized
duckylotl Jan 5, 2025
6add54a
fix: rename state arg to enabled
duckylotl Jan 5, 2025
db1bca5
add discovery functions for type and amount of filter banks
duckylotl Jan 5, 2025
053cfb3
Rename enums to upper snake case
duckylotl Jan 5, 2025
0cb3e84
add setters for pre-begin() configuration options
duckylotl Jan 5, 2025
8e3e6b5
add additional workaround for USB+CAN on F3 Platform. If USB IRQs are…
duckylotl Jan 5, 2025
eb6de54
fix: don't use ifdef for combined logic
duckylotl Jan 6, 2025
392b5e1
fix: don't lock up (Error_Handler) when calling hasPeripheral or free…
duckylotl Jan 8, 2025
b1351e6
allocatePeripheral() takes peripheral as arg and sets up handle.Insta…
duckylotl Jan 8, 2025
89dd4d9
add destructor, stop peripheral and release everything
duckylotl Jan 15, 2025
7589260
enable RX pullup. Eases use of loopback modes without external circui…
duckylotl Jan 18, 2025
9900652
update readme
duckylotl Jan 22, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
141 changes: 109 additions & 32 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,27 @@ STM32 core: https://github.com/stm32duino/Arduino_Core_STM32

## How to use.
To use this library, CAN module needs to be enabled in HAL drivers. If PIO is used, it's enough
to add -DHAL_CAN_MODULE_ENABLED as build flag. With Arduino IDE it's easiest to create hal_conf_extra.h -file
to same folder with sketch and haven #define HAL_CAN_MODULE_ENABLED there. See examples for this.
to add `-DHAL_CAN_MODULE_ENABLED` as build flag. With Arduino IDE it's easiest to create `hal_conf_extra.h` file
to same folder with sketch and haven `#define HAL_CAN_MODULE_ENABLED` there. See examples for this.

### Setup
The sketch needs include in the header to use the library.
```
```Cpp
#include "STM32_CAN.h"
```
Use constructor to set which CAN interface and pins to use.
```Cpp
STM32_CAN Can1( CAN1 ); //by peripheral. Uses first pin defined in arduino PeripheralPins maps
STM32_CAN Can1( PA11 /* rx pin */, PA12 /* tx pin */); //by arduino digital pin number. Finds matching peripheral automatically
STM32_CAN Can1( PA_11, PA_12 ); //by PinName. Finds matching peripheral automatically
```
**Note**: Digital pin and PinName may not be mixed or one will be implicitly converted and possibly causing unintended behavior. PinNames are defined with an underscore between port and pin. Digital pin numbers are aliased with port and pinnumber without an underscore.
Can convert between the two with `digitalPinToPinName()` and `pinNametoDigitalPin()`.

Tx pin may be defined as `PNUM_NOT_DEFINED` (digital pin number) or `NC` (PinName). Then only Rx is setup, allowing a listen only mode.

The original method by choosing from 3 sets of fixed pin combinations can still be used as well for compatibility.
```Cpp
STM32_CAN Can1( CAN1, DEF );
```
Depending on the STM32 model, there is CAN1, CAN2 and CAN3 available.
Expand All @@ -45,11 +56,98 @@ The pins are:
- ALT: PB3/4

In constructor you can optionally set TX and RX buffer sizes. Default is 16 messages.
```Cpp
STM32_CAN Can1 (PA_11, PA_12, RX_SIZE_256, TX_SIZE_256);
```

#### Additional settings
Following settings may be changed before starting the driver with `begin()`.
```Cpp
setIRQPriority(uint32_t preemptPriority, uint32_t subPriority); // default: lowest prio, 0
setAutoRetransmission(bool enabled); //default: true
setRxFIFOLock(bool fifo0locked); //default: false
setTxBufferMode(TX_BUFFER_MODE mode); //default: FIFO
setTimestampCounter(bool enabled); //default: false
setMode(MODE mode); //default: NORMAL
setAutoBusOffRecovery(bool enabled); //default: false
```
**Note**: `setTimestampCounter()` should always be set `false`. Feature is marked as non functioning in Erratas.

**Note**: begin() will overwrite `setAutoRetransmission()` setting (`false` by default).

#### Start / Stop bus

Before using library commands, begin must be called.
```Cpp
Can1.begin();
```
Optionally automatic retransmission can be enabled with begin.
```Cpp
Can1.begin(true);
```
Set baud rate by using.
```Cpp
Can1.setBaudRate(500000);
```
500 kbit/s in this case.

`setBaudRate` may be called before or after begin. Bus start once both are called.

It may also be called while running to change baudrate.

Call
```Cpp
Can1.end();
```
to stop the bus and release all resources. Will be implicitly called by destructor when freeing object.
Only one STM32_CAN instance can control a CAN Peripheral at one time. It reserves the peripheral from begin() to end().

#### Filters
Filters may only be set after bus is started (`begin()` & `setBaudRate()` was called).

By default bank 0 will receive CAN messages with all IDs. But using filters, we can set the CAN to receive
only specific message IDs. The CAN peripheral has many different methods of defining filters for messages.
These functions help setting up filters:
```Cpp
bool setFilterSingleMask(uint8_t bank_num, uint32_t id, uint32_t mask, IDE std_ext);
bool setFilterDualID (uint8_t bank_num, uint32_t id1, uint32_t id2, IDE std_ext1, IDE std_ext2);
bool setFilterDualMask (uint8_t bank_num, uint32_t id1, uint32_t mask1, IDE std_ext1, uint32_t id2, uint32_t mask2, IDE std_ext2);
bool setFilterQuadID (uint8_t bank_num, uint32_t id1, IDE std_ext1, uint32_t id2, IDE std_ext2, uint32_t id3, IDE std_ext3, uint32_t id4, IDE std_ext4);
```
The simplest one is `setFilterSingleMask`. The others allow setting multiple filters into a single filter bank. When using the functions `setFilterDualMask` and `setFilterQuadID` for extended ids, the 15 LSBs of the ID are always masked out.

Example: we want to receive only messages with standard ID 0x153 and extended ID 0x613, so we use bank 0 and 1.
```Cpp
Can1.setFilterSingleMask( 0, 0x153, 0x7FF, STD);
Can1.setFilterSingleMask( 1, 0x613, 0x1FFFFFFF, EXT);
```
First number is the bank number. Second is message ID. 3rd ID mask. And last one defines ID type: `AUTO`, `STD` or `EXT`.


**Note**: optional args of filter settings allow storing messages into the non-default RxFIFO. `read()` currently only reads from the default FIFO, so messages will not be accessible if sent to other FIFO.

**Note**: the following function allowed setting filters in the past. This function was bugged and did only work as long as optional args filter_mode and filter_scale where not changed.
Its behavior was kept in the broken state for compatibility. It has a 4th arg for ID type, defaults to `AUTO`.
```Cpp
bool setFilter(uint8_t bank_num, uint32_t filter_id, uint32_t mask)
```
STM32_CAN Can1 (CAN1, ALT_2, RX_SIZE_256, TX_SIZE_256);

To disable a filter bank call (`true` to re-enable it)
```Cpp
Can1.setFilter(bank_num, false);
```
There is structure to contain CAN packets and info about those.


The amount of available filter banks can be queried with:
```Cpp
Can1.getFilterBankCount()
```
**Note**: Single CAN devices have 14, dual CAN devices 28. Driver does split the 28 into 14 for each CAN instance.


### Main loop
The library defines this structure to describe a CAN message.
```Cpp
typedef struct CAN_message_t {
uint32_t id = 0; // can identifier
uint16_t timestamp = 0; // time when message arrived
Expand All @@ -67,41 +165,20 @@ typedef struct CAN_message_t {
bool seq = 0; // sequential frames
} CAN_message_t;
```
In sketch.
```
static CAN_message_t CAN_msg;
```
Before using library commands, begin must be called.
```
Can1.begin();
```
Optionally automatic retransmission can be enabled with begin.
```
Can1.begin(true);
```
Set baud rate by using.
```
Can1.setBaudRate(500000);
```
500 kbit/s in this case.

By default bank 0 will receive CAN messages with all IDs. But using filters, we can set the CAN to receive
only specific message IDs. Ie. if we want to receive only message IDs 0x153 and 0x613, so we use bank 0 and 1.
```
Can1.setFilter( 0, 0x153, 0x1FFFFFFF );
Can1.setFilter( 1, 0x613, 0x1FFFFFFF );
Define variable to store a message
```Cpp
CAN_message_t CAN_msg;
```
First number is the bank number. Second is message ID. And last one is mask.

### Main loop
To read CAN messages from buffer:
```
Can1.read(CAN_msg)
```Cpp
Can1.read(CAN_msg);
```
This will return true if there is messages available on receive buffer.

To write messages to send queue.
```
```Cpp
Can1.write(CAN_msg);
```
This will return true if there room in the send queue.
Loading
Loading