New CAN-bus library for STM32 (#725)
* Use new CAN-library * Fix CAN3 pin number * Fix building on other platforms
This commit is contained in:
parent
d0bbb24563
commit
34116ad223
|
@ -65,7 +65,7 @@ framework = arduino
|
|||
board = black_f407ve
|
||||
lib_deps = stm32duino/STM32duino RTC
|
||||
board_build.core = stm32
|
||||
build_flags = -std=gnu++11 -UBOARD_MAX_IO_PINS -DENABLE_HWSERIAL2 -DENABLE_HWSERIAL3 -DUSBCON -DHAL_PCD_MODULE_ENABLED -DUSBD_USE_CDC
|
||||
build_flags = -std=gnu++11 -UBOARD_MAX_IO_PINS -DENABLE_HWSERIAL2 -DENABLE_HWSERIAL3 -DUSBCON -DHAL_PCD_MODULE_ENABLED -DUSBD_USE_CDC -DHAL_CAN_MODULE_ENABLED
|
||||
upload_protocol = dfu
|
||||
debug_tool = stlink
|
||||
monitor_speed = 115200
|
||||
|
|
|
@ -320,20 +320,12 @@ void ignitionSchedule8Interrupt(HardwareTimer*);
|
|||
***********************************************************************************************************
|
||||
* CAN / Second serial
|
||||
*/
|
||||
#if defined(STM32F407xx) || defined(STM32F103xB) || defined(STM32F405xx)
|
||||
#if HAL_CAN_MODULE_ENABLED
|
||||
#define NATIVE_CAN_AVAILABLE
|
||||
//HardwareSerial CANSerial(PD6, PD5);
|
||||
#include <src/STM32_CAN/STM32_CAN.h>
|
||||
//This activates CAN1 interface on STM32, but it's named as Can0, because that's how Teensy implementation is done
|
||||
extern STM32_CAN Can0;
|
||||
/*
|
||||
Second CAN interface is also available if needed or it can be used also as primary CAN interface.
|
||||
for STM32F4 the default CAN1 pins are PD0 & PD1. Alternative (ALT) pins are PB8 & PB9 and ALT2 pins are PA11 and PA12:
|
||||
for STM32F4 the default CAN2 pins are PB5 & PB6. Alternative (ALT) pins are PB12 & PB13.
|
||||
for STM32F1 the default CAN1 pins are PA11 & PA12. Alternative (ALT) pins are PB8 & PB9.
|
||||
Example of using CAN2 as secondary CAN bus with alternative pins:
|
||||
STM32_CAN Can1 (_CAN2,ALT);
|
||||
*/
|
||||
|
||||
static CAN_message_t outMsg;
|
||||
static CAN_message_t inMsg;
|
||||
|
|
|
@ -6,10 +6,15 @@
|
|||
#include "scheduler.h"
|
||||
#include "HardwareTimer.h"
|
||||
|
||||
#if defined(STM32F407xx) || defined(STM32F103xB) || defined(STM32F405xx)
|
||||
#define NATIVE_CAN_AVAILABLE
|
||||
#if HAL_CAN_MODULE_ENABLED
|
||||
//This activates CAN1 interface on STM32, but it's named as Can0, because that's how Teensy implementation is done
|
||||
STM32_CAN Can0 (_CAN1,DEF);
|
||||
STM32_CAN Can0 (CAN1, ALT_2, RX_SIZE_256, TX_SIZE_16);
|
||||
/*
|
||||
These CAN interfaces and pins are available for use, depending on the chip/package:
|
||||
Default CAN1 pins are PA11 and PA12. Alternative (ALT) pins are PB8 & PB9 and ALT_2 pins are PD0 & PD1.
|
||||
Default CAN2 pins are PB12 & PB13. Alternative (ALT) pins are PB5 & PB6.
|
||||
Default CAN3 pins are PA8 & PA15. Alternative (ALT) pins are PB3 & PB4.
|
||||
*/
|
||||
#endif
|
||||
|
||||
#if defined(SRAM_AS_EEPROM)
|
||||
|
|
|
@ -433,7 +433,7 @@ void sendCancommand(uint8_t cmdtype, uint16_t canaddress, uint8_t candata1, uint
|
|||
//send to truecan send routine
|
||||
//canaddress == speeduino canid, candata1 == canin channel dest, paramgroup == can address to request from
|
||||
//This section is to be moved to the correct can output routine later
|
||||
#if defined(CORE_TEENSY) || defined(STM32F407xx) || defined(STM32F103xB) || defined(STM32F405xx) //Scope guarding this for now, but this needs a bit of a rethink for how it can be handled better across multiple archs
|
||||
#if defined(NATIVE_CAN_AVAILABLE)
|
||||
outMsg.id = (canaddress);
|
||||
outMsg.len = 8;
|
||||
outMsg.buf[0] = 0x0B ; //11;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,26 +1,22 @@
|
|||
/*
|
||||
This is CAN library for STM32 to be used in Speeduino engine management system by pazi88.
|
||||
The library is created because at least currently (year 2020) there is no CAN library in the STM32 core.
|
||||
This library is mostly based on the STM32 CAN examples by nopnop2002 and it has been combined with few
|
||||
This is universal CAN library for STM32 that was made to be used with Speeduino EFI.
|
||||
It should support all STM32 MCUs that are also supported in stm32duino Arduino_Core_STM32 and supports up to 3x CAN busses.
|
||||
The library is created because at least currently (year 2021) there is no official CAN library in the STM32 core.
|
||||
This library is based on several STM32 CAN example libraries linked below and it has been combined with few
|
||||
things from Teensy FlexCAN library to make it compatible with the CAN features that exist in speeduino for Teensy.
|
||||
Link to the nopnop2002 repository:
|
||||
Links to repositories that have helped with this:
|
||||
https://github.com/nopnop2002/Arduino-STM32-CAN
|
||||
https://github.com/J-f-Jensen/libraries/tree/master/STM32_CAN
|
||||
https://github.com/jiauka/STM32F1_CAN
|
||||
|
||||
STM32 core: https://github.com/stm32duino/Arduino_Core_STM32
|
||||
*/
|
||||
#if HAL_CAN_MODULE_ENABLED
|
||||
#ifndef STM32_CAN_H
|
||||
#define STM32_CAN_H
|
||||
|
||||
#if defined(STM32F407xx) || defined(STM32F1xx) || defined(STM32F405xx)
|
||||
#include <Arduino.h>
|
||||
|
||||
#define STM32_CAN_TIR_TXRQ (1U << 0U) // Bit 0: Transmit Mailbox Request
|
||||
#define STM32_CAN_RIR_RTR (1U << 1U) // Bit 1: Remote Transmission Request
|
||||
#define STM32_CAN_RIR_IDE (1U << 2U) // Bit 2: Identifier Extension
|
||||
#define STM32_CAN_TIR_RTR (1U << 1U) // Bit 1: Remote Transmission Request
|
||||
#define STM32_CAN_TIR_IDE (1U << 2U) // Bit 2: Identifier Extension
|
||||
|
||||
#define CAN_EXT_ID_MASK 0x1FFFFFFFU
|
||||
#define CAN_STD_ID_MASK 0x000007FFU
|
||||
|
||||
// This struct is directly copied from Teensy FlexCAN library to retain compatibility with it. Not all are in use with STM32.
|
||||
// Source: https://github.com/tonton81/FlexCAN_T4/
|
||||
|
||||
|
@ -37,65 +33,152 @@ typedef struct CAN_message_t {
|
|||
uint8_t len = 8; // length of data
|
||||
uint8_t buf[8] = { 0 }; // data
|
||||
int8_t mb = 0; // used to identify mailbox reception
|
||||
uint8_t bus = 1; // used to identify where the message came from when events() is used. CAN(1) and CAN(2) in use
|
||||
uint8_t bus = 1; // used to identify where the message came (CAN1, CAN2 or CAN3)
|
||||
bool seq = 0; // sequential frames
|
||||
} CAN_message_t;
|
||||
|
||||
typedef const struct
|
||||
{
|
||||
uint8_t TS2;
|
||||
uint8_t TS1;
|
||||
uint8_t BRP;
|
||||
} CAN_bit_timing_config_t;
|
||||
|
||||
typedef enum CAN_PINS {DEF, ALT, ALT_2,} CAN_PINS;
|
||||
|
||||
//STM32 has only 3 TX mailboxes
|
||||
typedef enum CAN_MAILBOX {
|
||||
typedef enum RXQUEUE_TABLE {
|
||||
RX_SIZE_2 = (uint16_t)2,
|
||||
RX_SIZE_4 = (uint16_t)4,
|
||||
RX_SIZE_8 = (uint16_t)8,
|
||||
RX_SIZE_16 = (uint16_t)16,
|
||||
RX_SIZE_32 = (uint16_t)32,
|
||||
RX_SIZE_64 = (uint16_t)64,
|
||||
RX_SIZE_128 = (uint16_t)128,
|
||||
RX_SIZE_256 = (uint16_t)256,
|
||||
RX_SIZE_512 = (uint16_t)512,
|
||||
RX_SIZE_1024 = (uint16_t)1024
|
||||
} RXQUEUE_TABLE;
|
||||
|
||||
typedef enum TXQUEUE_TABLE {
|
||||
TX_SIZE_2 = (uint16_t)2,
|
||||
TX_SIZE_4 = (uint16_t)4,
|
||||
TX_SIZE_8 = (uint16_t)8,
|
||||
TX_SIZE_16 = (uint16_t)16,
|
||||
TX_SIZE_32 = (uint16_t)32,
|
||||
TX_SIZE_64 = (uint16_t)64,
|
||||
TX_SIZE_128 = (uint16_t)128,
|
||||
TX_SIZE_256 = (uint16_t)256,
|
||||
TX_SIZE_512 = (uint16_t)512,
|
||||
TX_SIZE_1024 = (uint16_t)1024
|
||||
} TXQUEUE_TABLE;
|
||||
|
||||
/* Teensy FlexCAN uses Mailboxes for different RX filters, but in STM32 there is Filter Banks. These work practically same way,
|
||||
so the Filter Banks are named as mailboxes in "setMBFilter" -functions, to retain compatibility with Teensy FlexCAN library.
|
||||
*/
|
||||
typedef enum CAN_BANK {
|
||||
MB0 = 0,
|
||||
MB1 = 1,
|
||||
MB2 = 2
|
||||
} CAN_MAILBOX;
|
||||
MB2 = 2,
|
||||
MB3 = 3,
|
||||
MB4 = 4,
|
||||
MB5 = 5,
|
||||
MB6 = 6,
|
||||
MB7 = 7,
|
||||
MB8 = 8,
|
||||
MB9 = 9,
|
||||
MB10 = 10,
|
||||
MB11 = 11,
|
||||
MB12 = 12,
|
||||
MB13 = 13,
|
||||
MB14 = 14,
|
||||
MB15 = 15,
|
||||
MB16 = 16,
|
||||
MB17 = 17,
|
||||
MB18 = 18,
|
||||
MB19 = 19,
|
||||
MB20 = 20,
|
||||
MB21 = 21,
|
||||
MB22 = 22,
|
||||
MB23 = 23,
|
||||
MB24 = 24,
|
||||
MB25 = 25,
|
||||
MB26 = 26,
|
||||
MB27 = 27
|
||||
} CAN_BANK;
|
||||
|
||||
#ifndef CAN2
|
||||
typedef enum CAN_CHANNEL {_CAN1,} CAN_CHANNEL;
|
||||
#elif defined CAN2
|
||||
typedef enum CAN_CHANNEL {_CAN1, _CAN2,} CAN_CHANNEL;
|
||||
#endif
|
||||
|
||||
//Bit timings depend on the APB1 clock speed and need to be calculated based on that.
|
||||
//APB1 at 42MHz:
|
||||
#if defined(STM32F407xx) || defined(STM32F405xx)
|
||||
CAN_bit_timing_config_t can_configs[6] = {{2, 12, 56}, {2, 12, 28}, {2, 13, 21}, {2, 11, 12}, {2, 11, 6}, {1, 5, 6}};
|
||||
//APB1 at 36MHz
|
||||
#elif defined(STM32F1xx)
|
||||
CAN_bit_timing_config_t can_configs[6] = {{2, 13, 45}, {2, 15, 20}, {2, 13, 18}, {2, 13, 9}, {2, 15, 4}, {2, 15, 2}};
|
||||
//APB1 at 45MHz
|
||||
#elif defined(STM32F446xx)
|
||||
CAN_bit_timing_config_t can_configs[6] = {{2, 12, 60}, {2, 12, 30}, {2, 12, 24}, {2, 12, 12}, {2, 12, 6}, {1, 7, 5}};
|
||||
//If support for more APB1 clock speeds is needed, use this calculator: http://www.bittiming.can-wiki.info/
|
||||
#endif
|
||||
typedef enum CAN_FLTEN {
|
||||
ACCEPT_ALL = 0,
|
||||
REJECT_ALL = 1
|
||||
} CAN_FLTEN;
|
||||
|
||||
class STM32_CAN {
|
||||
const CAN_CHANNEL _channel;
|
||||
const CAN_PINS _pins;
|
||||
|
||||
private:
|
||||
void CANSetGpio(GPIO_TypeDef * addr, uint8_t index, uint8_t speed = 3);
|
||||
void CANSetFilter(uint8_t index, uint8_t scale, uint8_t mode, uint8_t fifo, uint32_t bank1, uint32_t bank2);
|
||||
void writeTxMailbox(uint8_t mb_num, CAN_message_t &CAN_tx_msg);
|
||||
uint8_t CANMsgAvail();
|
||||
void SetTXRX();
|
||||
|
||||
public:
|
||||
STM32_CAN(const CAN_CHANNEL channel, CAN_PINS pins) : _channel (channel), _pins (pins) { };
|
||||
void begin();
|
||||
// Default buffer sizes are set to 16. But this can be changed by using constructor in main code.
|
||||
STM32_CAN(CAN_TypeDef* canPort, CAN_PINS pins, RXQUEUE_TABLE rxSize = RX_SIZE_16, TXQUEUE_TABLE txSize = TX_SIZE_16);
|
||||
// Begin. By default the automatic retransmission is enabled. If it causes problems, use begin(false) to disable it.
|
||||
void begin(bool retransmission = true);
|
||||
void setBaudRate(uint32_t baud);
|
||||
int write(CAN_message_t &CAN_tx_msg); // use any available mailbox for transmitting
|
||||
int write(CAN_MAILBOX mb_num, CAN_message_t &CAN_tx_msg); // use a single mailbox for transmitting
|
||||
int read(CAN_message_t &CAN_rx_msg);
|
||||
bool write(CAN_message_t &CAN_tx_msg, bool sendMB = false);
|
||||
bool read(CAN_message_t &CAN_rx_msg);
|
||||
// Manually set STM32 filter bank parameters
|
||||
bool setFilter(uint8_t bank_num, uint32_t filter_id, uint32_t mask, uint32_t filter_mode = CAN_FILTERMODE_IDMASK, uint32_t filter_scale = CAN_FILTERSCALE_32BIT, uint32_t fifo = CAN_FILTER_FIFO0);
|
||||
// Teensy FlexCAN style "set filter" -functions
|
||||
bool setMBFilterProcessing(CAN_BANK bank_num, uint32_t filter_id, uint32_t mask);
|
||||
void setMBFilter(CAN_FLTEN input); /* enable/disable traffic for all MBs (for individual masking) */
|
||||
void setMBFilter(CAN_BANK bank_num, CAN_FLTEN input); /* set specific MB to accept/deny traffic */
|
||||
bool setMBFilter(CAN_BANK bank_num, uint32_t id1); /* input 1 ID to be filtered */
|
||||
bool setMBFilter(CAN_BANK bank_num, uint32_t id1, uint32_t id2); /* input 2 ID's to be filtered */
|
||||
|
||||
void enableLoopBack(bool yes = 1);
|
||||
void enableSilentMode(bool yes = 1);
|
||||
void enableSilentLoopBack(bool yes = 1);
|
||||
void enableFIFO(bool status = 1);
|
||||
void enableMBInterrupts();
|
||||
void disableMBInterrupts();
|
||||
|
||||
// These are public because these are also used from interupts.
|
||||
typedef struct RingbufferTypeDef {
|
||||
volatile uint16_t head;
|
||||
volatile uint16_t tail;
|
||||
uint16_t size;
|
||||
volatile CAN_message_t *buffer;
|
||||
} RingbufferTypeDef;
|
||||
|
||||
RingbufferTypeDef rxRing;
|
||||
RingbufferTypeDef txRing;
|
||||
|
||||
bool addToRingBuffer(RingbufferTypeDef &ring, const CAN_message_t &msg);
|
||||
bool removeFromRingBuffer(RingbufferTypeDef &ring, CAN_message_t &msg);
|
||||
|
||||
protected:
|
||||
uint16_t sizeRxBuffer;
|
||||
uint16_t sizeTxBuffer;
|
||||
|
||||
private:
|
||||
void initializeFilters();
|
||||
bool isInitialized() { return rx_buffer != 0; }
|
||||
void initRingBuffer(RingbufferTypeDef &ring, volatile CAN_message_t *buffer, uint32_t size);
|
||||
void initializeBuffers(void);
|
||||
bool isRingBufferEmpty(RingbufferTypeDef &ring);
|
||||
uint32_t ringBufferCount(RingbufferTypeDef &ring);
|
||||
void calculateBaudrate(CAN_HandleTypeDef *CanHandle, int Baudrate);
|
||||
uint32_t getAPB1Clock(void);
|
||||
|
||||
volatile CAN_message_t *rx_buffer;
|
||||
volatile CAN_message_t *tx_buffer;
|
||||
|
||||
bool _canIsActive = false;
|
||||
CAN_PINS _pins;
|
||||
|
||||
CAN_HandleTypeDef *n_pCanHandle;
|
||||
CAN_TypeDef* _canPort;
|
||||
|
||||
};
|
||||
|
||||
static STM32_CAN* _CAN1 = nullptr;
|
||||
static CAN_HandleTypeDef hcan1;
|
||||
#ifdef CAN2
|
||||
static STM32_CAN* _CAN2 = nullptr;
|
||||
static CAN_HandleTypeDef hcan2;
|
||||
#endif
|
||||
#ifdef CAN3
|
||||
static STM32_CAN* _CAN3 = nullptr;
|
||||
static CAN_HandleTypeDef hcan3;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif
|
Loading…
Reference in New Issue