diff --git a/src/generic/canbus.c b/src/generic/canbus.c index a4f33aa..1be0ead 100644 --- a/src/generic/canbus.c +++ b/src/generic/canbus.c @@ -4,19 +4,23 @@ // // This file may be distributed under the terms of the GNU GPLv3 license. -#include "canbus.h" // canbus_send -#include "canserial.h" // canserial_send +#include "autoconf.h" // CONFIG_CANBUS_FREQUENCY +#include "canbus.h" // canhw_send +#include "canserial.h" // canserial_notify_tx +#include "command.h" // DECL_CONSTANT + +DECL_CONSTANT("CANBUS_FREQUENCY", CONFIG_CANBUS_FREQUENCY); int -canserial_send(struct canbus_msg *msg) +canbus_send(struct canbus_msg *msg) { - return canbus_send(msg); + return canhw_send(msg); } void -canserial_set_filter(uint32_t id) +canbus_set_filter(uint32_t id) { - canbus_set_filter(id); + canhw_set_filter(id); } void diff --git a/src/generic/canbus.h b/src/generic/canbus.h index 8032611..f21a7cc 100644 --- a/src/generic/canbus.h +++ b/src/generic/canbus.h @@ -18,10 +18,12 @@ struct canbus_msg { #define CANMSG_DATA_LEN(msg) ((msg)->dlc > 8 ? 8 : (msg)->dlc) // callbacks provided by board specific code -int canbus_send(struct canbus_msg *msg); -void canbus_set_filter(uint32_t id); +int canhw_send(struct canbus_msg *msg); +void canhw_set_filter(uint32_t id); // canbus.c +int canbus_send(struct canbus_msg *msg); +void canbus_set_filter(uint32_t id); void canbus_notify_tx(void); void canbus_process_data(struct canbus_msg *msg); diff --git a/src/generic/canserial.c b/src/generic/canserial.c index 73ef034..153507c 100644 --- a/src/generic/canserial.c +++ b/src/generic/canserial.c @@ -10,7 +10,7 @@ #include "board/io.h" // readb #include "board/irq.h" // irq_save #include "board/misc.h" // console_sendf -#include "canbus.h" // canbus_set_uuid +#include "canbus.h" // canbus_send #include "canserial.h" // canserial_notify_tx #include "command.h" // DECL_CONSTANT #include "fasthash.h" // fasthash64 @@ -68,7 +68,7 @@ canserial_tx_task(void) break; msg.dlc = now; memcpy(msg.data, &CanData.transmit_buf[tpos], now); - int ret = canserial_send(&msg); + int ret = canbus_send(&msg); if (ret <= 0) break; tpos += now; @@ -153,7 +153,7 @@ can_process_query_unassigned(struct canbus_msg *msg) send.data[7] = CANBUS_CMD_SET_CANBOOT_NODEID; // Send with retry for (;;) { - int ret = canserial_send(&send); + int ret = canbus_send(&send); if (ret >= 0) return; } @@ -170,7 +170,7 @@ static void can_id_conflict(void) { CanData.assigned_id = 0; - canserial_set_filter(CanData.assigned_id); + canbus_set_filter(CanData.assigned_id); } static void @@ -182,7 +182,7 @@ can_process_set_canboot_nodeid(struct canbus_msg *msg) if (can_check_uuid(msg)) { if (newid != CanData.assigned_id) { CanData.assigned_id = newid; - canserial_set_filter(CanData.assigned_id); + canbus_set_filter(CanData.assigned_id); } } else if (newid == CanData.assigned_id) { can_id_conflict(); diff --git a/src/generic/canserial.h b/src/generic/canserial.h index e2f5552..e8f3767 100644 --- a/src/generic/canserial.h +++ b/src/generic/canserial.h @@ -6,13 +6,9 @@ #define CANBUS_ID_ADMIN 0x3f0 #define CANBUS_ID_ADMIN_RESP 0x3f1 -// callbacks provided by board specific code -struct canbus_msg; -int canserial_send(struct canbus_msg *msg); -void canserial_set_filter(uint32_t id); - // canserial.c void canserial_notify_tx(void); +struct canbus_msg; int canserial_process_data(struct canbus_msg *msg); void canserial_set_uuid(uint8_t *raw_uuid, uint32_t raw_uuid_len); diff --git a/src/rp2040/can.c b/src/rp2040/can.c index 9c42cf3..6cae2a7 100644 --- a/src/rp2040/can.c +++ b/src/rp2040/can.c @@ -26,7 +26,7 @@ static struct can2040 cbus; // Transmit a packet int -canbus_send(struct canbus_msg *msg) +canhw_send(struct canbus_msg *msg) { int ret = can2040_transmit(&cbus, (void*)msg); if (ret < 0) @@ -36,7 +36,7 @@ canbus_send(struct canbus_msg *msg) // Setup the receive packet filter void -canbus_set_filter(uint32_t id) +canhw_set_filter(uint32_t id) { // Filter not implemented (and not necessary) } diff --git a/src/stm32/can.c b/src/stm32/can.c index 665338a..9167d0d 100644 --- a/src/stm32/can.c +++ b/src/stm32/can.c @@ -92,7 +92,7 @@ // Transmit a packet int -canbus_send(struct canbus_msg *msg) +canhw_send(struct canbus_msg *msg) { uint32_t tsr = SOC_CAN->TSR; if (!(tsr & (CAN_TSR_TME0|CAN_TSR_TME1|CAN_TSR_TME2))) { @@ -129,7 +129,7 @@ canbus_send(struct canbus_msg *msg) // Setup the receive packet filter void -canbus_set_filter(uint32_t id) +canhw_set_filter(uint32_t id) { /* Select the start slave bank */ SOC_CAN->FMR |= CAN_FMR_FINIT; @@ -268,7 +268,7 @@ can_init(void) ; /*##-2- Configure the CAN Filter #######################################*/ - canbus_set_filter(0); + canhw_set_filter(0); /*##-3- Configure Interrupts #################################*/ armcm_enable_irq(CAN_IRQHandler, CAN_RX0_IRQn, 0); diff --git a/src/stm32/fdcan.c b/src/stm32/fdcan.c index c142420..3b01b48 100644 --- a/src/stm32/fdcan.c +++ b/src/stm32/fdcan.c @@ -1,84 +1,107 @@ -// Serial over CAN emulation for STM32 boards. +// FDCAN support on stm32 chips // +// Copyright (C) 2021-2022 Kevin O'Connor // Copyright (C) 2019 Eug Krashtan // Copyright (C) 2020 Pontus Borg -// Copyright (C) 2021 Kevin O'Connor // // This file may be distributed under the terms of the GNU GPLv3 license. -#include // memcpy -#include "autoconf.h" // CONFIG_MACH_STM32F1 -#include "board/irq.h" // irq_disable #include "command.h" // DECL_CONSTANT_STR #include "generic/armcm_boot.h" // armcm_enable_irq #include "generic/canbus.h" // canbus_notify_tx #include "generic/canserial.h" // CANBUS_ID_ADMIN -#include "generic/serial_irq.h" // serial_rx_byte #include "internal.h" // enable_pclock #include "sched.h" // DECL_INIT -typedef struct -{ - __IO uint32_t id_section; - __IO uint32_t dlc_section; - __IO uint32_t data[64 / 4]; -}FDCAN_FIFO_TypeDef; -#define FDCAN_XTD (1<<30) -#define FDCAN_RTR (1<<29) - -typedef struct -{ - __IO uint32_t FLS[28]; // Filter list standard - __IO uint32_t FLE[16]; // Filter list extended - FDCAN_FIFO_TypeDef RXF0[3]; - FDCAN_FIFO_TypeDef RXF1[3]; - __IO uint32_t TEF[6]; // Tx event FIFO - FDCAN_FIFO_TypeDef TXFIFO[3]; -}FDCAN_MSG_RAM_TypeDef; - -typedef struct -{ - FDCAN_MSG_RAM_TypeDef fdcan1; - FDCAN_MSG_RAM_TypeDef fdcan2; -}FDCAN_RAM_TypeDef; - -FDCAN_RAM_TypeDef *fdcan_ram = (FDCAN_RAM_TypeDef *)(SRAMCAN_BASE); - -#define FDCAN_IE_TC (FDCAN_IE_TCE | FDCAN_IE_TCFE | FDCAN_IE_TFEE) +/**************************************************************** + * Pin configuration + ****************************************************************/ #if CONFIG_STM32_CANBUS_PA11_PA12 DECL_CONSTANT_STR("RESERVE_PINS_CAN", "PA11,PA12"); #define GPIO_Rx GPIO('A', 11) #define GPIO_Tx GPIO('A', 12) +#elif CONFIG_STM32_CANBUS_PA11_PB9 + DECL_CONSTANT_STR("RESERVE_PINS_CAN", "PA11,PB9"); + #define GPIO_Rx GPIO('A', 11) + #define GPIO_Tx GPIO('B', 9) #elif CONFIG_STM32_CANBUS_PB8_PB9 DECL_CONSTANT_STR("RESERVE_PINS_CAN", "PB8,PB9"); #define GPIO_Rx GPIO('B', 8) #define GPIO_Tx GPIO('B', 9) +#elif CONFIG_STM32_CANBUS_PD0_PD1 + DECL_CONSTANT_STR("RESERVE_PINS_CAN", "PD0,PD1"); + #define GPIO_Rx GPIO('D', 0) + #define GPIO_Tx GPIO('D', 1) +#elif CONFIG_STM32_CANBUS_PD12_PD13 + DECL_CONSTANT_STR("RESERVE_PINS_CAN", "PD12,PD13"); + #define GPIO_Rx GPIO('D', 12) + #define GPIO_Tx GPIO('D', 13) #elif CONFIG_STM32_CANBUS_PB0_PB1 DECL_CONSTANT_STR("RESERVE_PINS_CAN", "PB0,PB1"); #define GPIO_Rx GPIO('B', 0) #define GPIO_Tx GPIO('B', 1) +#elif CONFIG_STM32_CANBUS_PC2_PC3 + DECL_CONSTANT_STR("RESERVE_PINS_CAN", "PC2,PC3"); + #define GPIO_Rx GPIO('C', 2) + #define GPIO_Tx GPIO('C', 3) #endif -#if !CONFIG_STM32_CANBUS_PB0_PB1 +#if !(CONFIG_STM32_CANBUS_PB0_PB1 || CONFIG_STM32_CANBUS_PC2_PC3) #define SOC_CAN FDCAN1 - #define MSG_RAM fdcan_ram->fdcan1 + #define MSG_RAM (((struct fdcan_ram_layout*)SRAMCAN_BASE)->fdcan1) #else #define SOC_CAN FDCAN2 - #define MSG_RAM fdcan_ram->fdcan2 + #define MSG_RAM (((struct fdcan_ram_layout*)SRAMCAN_BASE)->fdcan2) #endif -#define CAN_IT0_IRQn TIM16_FDCAN_IT0_IRQn -#define CAN_FUNCTION GPIO_FUNCTION(3) // Alternative function mapping number - -#ifndef SOC_CAN - #error No known CAN device for configured MCU +#if CONFIG_MACH_STM32G0 + #define CAN_IT0_IRQn TIM16_FDCAN_IT0_IRQn + #define CAN_FUNCTION GPIO_FUNCTION(3) // Alternative function mapping number +#elif CONFIG_MACH_STM32H7 || CONFIG_MACH_STM32G4 + #define CAN_IT0_IRQn FDCAN1_IT0_IRQn + #define CAN_FUNCTION GPIO_FUNCTION(9) // Alternative function mapping number #endif + +/**************************************************************** + * Message ram layout + ****************************************************************/ + +struct fdcan_fifo { + uint32_t id_section; + uint32_t dlc_section; + uint32_t data[64 / 4]; +}; + +#define FDCAN_XTD (1<<30) +#define FDCAN_RTR (1<<29) + +struct fdcan_msg_ram { + uint32_t FLS[28]; // Filter list standard + uint32_t FLE[16]; // Filter list extended + struct fdcan_fifo RXF0[3]; + struct fdcan_fifo RXF1[3]; + uint32_t TEF[6]; // Tx event FIFO + struct fdcan_fifo TXFIFO[3]; +}; + +struct fdcan_ram_layout { + struct fdcan_msg_ram fdcan1; + struct fdcan_msg_ram fdcan2; +}; + + +/**************************************************************** + * CANbus code + ****************************************************************/ + +#define FDCAN_IE_TC (FDCAN_IE_TCE | FDCAN_IE_TCFE | FDCAN_IE_TFEE) + // Transmit a packet int -canbus_send(struct canbus_msg *msg) +canhw_send(struct canbus_msg *msg) { uint32_t txfqs = SOC_CAN->TXFQS; if (txfqs & FDCAN_TXFQS_TFQF) @@ -86,7 +109,7 @@ canbus_send(struct canbus_msg *msg) return -1; uint32_t w_index = ((txfqs & FDCAN_TXFQS_TFQPI) >> FDCAN_TXFQS_TFQPI_Pos); - FDCAN_FIFO_TypeDef *txfifo = &MSG_RAM.TXFIFO[w_index]; + struct fdcan_fifo *txfifo = &MSG_RAM.TXFIFO[w_index]; uint32_t ids; if (msg->id & CANMSG_ID_EFF) ids = (msg->id & 0x1fffffff) | FDCAN_XTD; @@ -97,6 +120,7 @@ canbus_send(struct canbus_msg *msg) txfifo->dlc_section = (msg->dlc & 0x0f) << 16; txfifo->data[0] = msg->data32[0]; txfifo->data[1] = msg->data32[1]; + barrier(); SOC_CAN->TXBAR = ((uint32_t)1 << w_index); return CANMSG_DATA_LEN(msg); } @@ -112,7 +136,7 @@ can_filter(uint32_t index, uint32_t id) // Setup the receive packet filter void -canbus_set_filter(uint32_t id) +canhw_set_filter(uint32_t id) { if (!CONFIG_CANBUS_FILTER) return; @@ -128,10 +152,18 @@ canbus_set_filter(uint32_t id) can_filter(0, CANBUS_ID_ADMIN); can_filter(1, id); can_filter(2, id + 1); + +#if CONFIG_MACH_STM32G0 SOC_CAN->RXGFC = ((id ? 3 : 1) << FDCAN_RXGFC_LSS_Pos | 0x02 << FDCAN_RXGFC_ANFS_Pos); +#elif CONFIG_MACH_STM32H7 || CONFIG_MAC_STM32G4 + uint32_t flssa = (uint32_t)MSG_RAM.FLS - SRAMCAN_BASE; + SOC_CAN->SIDFC = flssa | ((id ? 3 : 1) << FDCAN_SIDFC_LSS_Pos); + SOC_CAN->GFC = 0x02 << FDCAN_GFC_ANFS_Pos; +#endif /* Leave the initialisation mode for the filter */ + barrier(); SOC_CAN->CCCR &= ~FDCAN_CCCR_CCE; SOC_CAN->CCCR &= ~FDCAN_CCCR_INIT; } @@ -149,7 +181,7 @@ CAN_IRQHandler(void) if (rxf0s & FDCAN_RXF0S_F0FL) { // Read and ack data packet uint32_t idx = (rxf0s & FDCAN_RXF0S_F0GI) >> FDCAN_RXF0S_F0GI_Pos; - FDCAN_FIFO_TypeDef *rxf0 = &MSG_RAM.RXF0[idx]; + struct fdcan_fifo *rxf0 = &MSG_RAM.RXF0[idx]; uint32_t ids = rxf0->id_section; struct canbus_msg msg; if (ids & FDCAN_XTD) @@ -160,6 +192,7 @@ CAN_IRQHandler(void) msg.dlc = (rxf0->dlc_section >> 16) & 0x0f; msg.data32[0] = rxf0->data[0]; msg.data32[1] = rxf0->data[1]; + barrier(); SOC_CAN->RXF0A = idx; // Process packet @@ -251,15 +284,25 @@ can_init(void) SOC_CAN->NBTP = btr; +#if CONFIG_MACH_STM32H7 || CONFIG_MAC_STM32G4 + /* Setup message RAM addresses */ + uint32_t f0sa = (uint32_t)MSG_RAM.RXF0 - SRAMCAN_BASE; + SOC_CAN->RXF0C = f0sa | (ARRAY_SIZE(MSG_RAM.RXF0) << FDCAN_RXF0C_F0S_Pos); + SOC_CAN->RXESC = (7 << FDCAN_RXESC_F1DS_Pos) | (7 << FDCAN_RXESC_F0DS_Pos); + uint32_t tbsa = (uint32_t)MSG_RAM.TXFIFO - SRAMCAN_BASE; + SOC_CAN->TXBC = tbsa | (ARRAY_SIZE(MSG_RAM.TXFIFO) << FDCAN_TXBC_TFQS_Pos); + SOC_CAN->TXESC = 7 << FDCAN_TXESC_TBDS_Pos; +#endif + /* Leave the initialisation mode */ SOC_CAN->CCCR &= ~FDCAN_CCCR_CCE; SOC_CAN->CCCR &= ~FDCAN_CCCR_INIT; /*##-2- Configure the CAN Filter #######################################*/ - canbus_set_filter(0); + canhw_set_filter(0); /*##-3- Configure Interrupts #################################*/ - armcm_enable_irq(CAN_IRQHandler, CAN_IT0_IRQn, 0); + armcm_enable_irq(CAN_IRQHandler, CAN_IT0_IRQn, 1); SOC_CAN->ILE = FDCAN_ILE_EINT0; SOC_CAN->IE = FDCAN_IE_RF0NE | FDCAN_IE_TC; }