Skip to content

Commit 6cac2d2

Browse files
committed
stm32: Add machine.CAN implementation.
Implemented according to API docs in a parent comment. Adds new multi_extmod/machine_can_* tests which pass when testing between NUCLEO_G474RE, NUCLEO_H723ZG and PYBDV11. This work was mostly funded through GitHub Sponsors. Signed-off-by: Angus Gratton <angus@redyak.com.au>
1 parent 6f835b3 commit 6cac2d2

31 files changed

Lines changed: 2367 additions & 295 deletions

ports/stm32/can.c

Lines changed: 293 additions & 79 deletions
Large diffs are not rendered by default.

ports/stm32/can.h

Lines changed: 86 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,19 +47,48 @@
4747
#define LIST32 (3)
4848

4949
#if MICROPY_HW_ENABLE_FDCAN
50+
// Interface compatibility for the classic CAN controller HAL
5051
#define CAN_TypeDef FDCAN_GlobalTypeDef
5152
#define CAN_HandleTypeDef FDCAN_HandleTypeDef
5253
#define CanTxMsgTypeDef FDCAN_TxHeaderTypeDef
5354
#define CanRxMsgTypeDef FDCAN_RxHeaderTypeDef
55+
56+
#define CAN_MODE_NORMAL FDCAN_MODE_NORMAL
57+
#define CAN_MODE_LOOPBACK FDCAN_MODE_EXTERNAL_LOOPBACK
58+
#define CAN_MODE_SILENT FDCAN_MODE_BUS_MONITORING
59+
#define CAN_MODE_SILENT_LOOPBACK FDCAN_MODE_INTERNAL_LOOPBACK
60+
61+
// FDCAN peripheral has independent indexes for standard id vs extended id filters
62+
#if defined(STM32G4)
63+
#define CAN_HW_MAX_STD_FILTER 28
64+
#define CAN_HW_MAX_EXT_FILTER 8
65+
#elif defined(STM32H7)
66+
// The RAM filtering section is configured for 64 x 1 word elements for 11-bit standard
67+
// identifiers, and 31 x 2 words elements for 29-bit extended identifiers.
68+
// The total number of words reserved for the filtering per FDCAN instance is 126 words.
69+
#define CAN_HW_MAX_STD_FILTER 64
70+
#define CAN_HW_MAX_EXT_FILTER 31
5471
#endif
5572

56-
enum {
73+
// Value reported via machine.CAN.FILTER_MAX, somewhat optimistic as requires using
74+
// the exact numbers of each type of filter.
75+
#define CAN_HW_MAX_FILTER (CAN_HW_MAX_STD_FILTER + CAN_HW_MAX_EXT_FILTER)
76+
77+
#else
78+
79+
// CAN1 & CAN2 have 28 filters which can be arbitrarily split, but machine.CAN
80+
// implementation hard-codes to 14/14. CAN3 has 14 independent filters.
81+
#define CAN_HW_MAX_FILTER 14
82+
83+
#endif
84+
85+
typedef enum {
5786
CAN_STATE_STOPPED,
5887
CAN_STATE_ERROR_ACTIVE,
5988
CAN_STATE_ERROR_WARNING,
6089
CAN_STATE_ERROR_PASSIVE,
6190
CAN_STATE_BUS_OFF,
62-
};
91+
} can_state_t;
6392

6493
typedef enum _rx_state_t {
6594
RX_STATE_FIFO_EMPTY = 0,
@@ -76,8 +105,31 @@ typedef enum {
76105
CAN_INT_ERR_BUS_OFF,
77106
CAN_INT_ERR_PASSIVE,
78107
CAN_INT_ERR_WARNING,
108+
109+
CAN_INT_TX_COMPLETE,
79110
} can_int_t;
80111

112+
typedef enum {
113+
CAN_TX_FIFO,
114+
CAN_TX_QUEUE,
115+
} can_tx_mode_t;
116+
117+
// Counter data as used by pyb.CAN.info() and machine.CAN.get_counters()
118+
typedef struct {
119+
unsigned tec;
120+
unsigned rec;
121+
unsigned tx_pending;
122+
unsigned rx_fifo0_pending;
123+
unsigned rx_fifo1_pending;
124+
} can_counters_t;
125+
126+
#if defined(STM32H7)
127+
#define CAN_TX_QUEUE_LEN 16
128+
#else
129+
// FDCAN STM32G4, bxCAN
130+
#define CAN_TX_QUEUE_LEN 3
131+
#endif
132+
81133
// RX FIFO numbering
82134
//
83135
// Note: For traditional CAN peripheral, the values of CAN_FIFO0 and CAN_FIFO1 are the same
@@ -87,12 +139,29 @@ typedef enum {
87139
CAN_RX_FIFO1,
88140
} can_rx_fifo_t;
89141

90-
bool can_init(CAN_HandleTypeDef *can, int can_id, uint32_t mode, uint32_t prescaler, uint32_t sjw, uint32_t bs1, uint32_t bs2, bool auto_restart);
142+
bool can_init(CAN_HandleTypeDef *can, int can_id, can_tx_mode_t tx_mode, uint32_t mode, uint32_t prescaler, uint32_t sjw, uint32_t bs1, uint32_t bs2, bool auto_restart);
91143
void can_deinit(CAN_HandleTypeDef *can);
92144

145+
uint32_t can_get_source_freq(void);
146+
93147
int can_receive(CAN_HandleTypeDef *can, can_rx_fifo_t fifo, CanRxMsgTypeDef *msg, uint8_t *data, uint32_t timeout_ms);
148+
149+
// Transmit a CAN frame (callee to choose the transmit slot). Used by pyb.CAN only, does not enable TX interrupt
150+
// On FDCAN this function invalidates the 'txmsg' structure if successful.
94151
HAL_StatusTypeDef can_transmit(CAN_HandleTypeDef *hcan, CanTxMsgTypeDef *txmsg, uint8_t *data, uint32_t Timeout);
95152

153+
// Tell the controller to copy a CAN frame copied to 'index' and start transmitting
154+
// On FDCAN this function invalidates the 'txmsg' structure if successful.
155+
HAL_StatusTypeDef can_transmit_buf_index(CAN_HandleTypeDef *hcan, int index, CanTxMsgTypeDef *txmsg, const uint8_t *data);
156+
157+
// Cancel the pending transmission in the specified buffer index. Returns after buffer stops transmitting.
158+
// Result is true if buffer was transmitting, false if not transmitting (or finished transmitting before cancellation)
159+
bool can_cancel_transmit(CAN_HandleTypeDef *hcan, int index);
160+
161+
// Get the lowest index of a buffer in FAILED or SUCCEEDED state, or -1 if none exists
162+
// Calling this function also re-enables the TX done IRQ for this peripheral
163+
int can_get_transmit_finished(CAN_HandleTypeDef *hcan, bool *is_success);
164+
96165
// Disable all CAN receive interrupts for a FIFO
97166
void can_disable_rx_interrupts(CAN_HandleTypeDef *can, can_rx_fifo_t fifo);
98167

@@ -101,22 +170,33 @@ void can_disable_rx_interrupts(CAN_HandleTypeDef *can, can_rx_fifo_t fifo);
101170
// Interrupt for CAN_INT_MESSAGE_RECEIVED is only enabled if enable_msg_received is set.
102171
void can_enable_rx_interrupts(CAN_HandleTypeDef *can, can_rx_fifo_t fifo, bool enable_msg_received);
103172

173+
// Disable all pending TX interrupts (ahead of restart or deinit). Will re-enable n next transmit
174+
void can_disable_tx_interrupts(CAN_HandleTypeDef *can);
175+
104176
can_state_t can_get_state(CAN_HandleTypeDef *can);
105177

178+
void can_get_counters(CAN_HandleTypeDef *can, can_counters_t *counters);
179+
180+
// Restart controller (clears error states). Caller expected to check controller initialised already.
181+
void can_restart(CAN_HandleTypeDef *can);
182+
106183
// Implemented in pyb_can.c, called from lower layer
107-
extern void can_irq_handler(uint can_id, can_int_t interrupt, can_rx_fifo_t fifo);
184+
extern void pyb_can_irq_handler(uint can_id, can_int_t interrupt, can_rx_fifo_t fifo);
185+
186+
// Implemented in machine_can.c, called from lower layer
187+
extern void machine_can_irq_handler(uint can_id, can_int_t interrupt);
108188

109189
#if MICROPY_HW_ENABLE_FDCAN
110190

111-
static inline unsigned can_rx_pending(CAN_HandleTypeDef *can, can_rx_fifo_t fifo) {
191+
static inline unsigned can_is_rx_pending(CAN_HandleTypeDef *can, can_rx_fifo_t fifo) {
112192
return HAL_FDCAN_GetRxFifoFillLevel(can, fifo == CAN_RX_FIFO0 ? FDCAN_RX_FIFO0 : FDCAN_RX_FIFO1);
113193
}
114194

115195
void can_clearfilter(CAN_HandleTypeDef *can, uint32_t filter_num, bool is_extid);
116196

117197
#else
118198

119-
static inline unsigned can_rx_pending(CAN_HandleTypeDef *can, can_rx_fifo_t fifo) {
199+
static inline unsigned can_is_rx_pending(CAN_HandleTypeDef *can, can_rx_fifo_t fifo) {
120200
return __HAL_CAN_MSG_PENDING(can, fifo == CAN_RX_FIFO0 ? CAN_FIFO0 : CAN_FIFO1);
121201
}
122202

0 commit comments

Comments
 (0)