diff --git a/include/can.h b/include/can.h index 388df52d..6723a79d 100644 --- a/include/can.h +++ b/include/can.h @@ -33,24 +33,37 @@ THE SOFTWARE. #include "gs_usb.h" +#if defined(FDCAN1) +#define GS_HOST_FRAME gs_host_frame_canfd +#define GS_HOST_FRAME_CLASSIC gs_host_frame +#else +#define GS_HOST_FRAME gs_host_frame +#endif + typedef struct { - CAN_TypeDef *instance; - uint16_t brp; - uint8_t phase_seg1; - uint8_t phase_seg2; - uint8_t sjw; +#if defined(FDCAN1) + FDCAN_HandleTypeDef channel; +#else + CAN_HandleTypeDef channel; +#endif } can_data_t; +#if defined(FDCAN1) +void can_init(can_data_t *hcan, FDCAN_GlobalTypeDef *instance); +void can_enable(can_data_t *hcan, bool loop_back, bool listen_only, bool one_shot, bool can_mode_fd); +bool can_set_data_bittiming(can_data_t *hcan, uint16_t brp, uint8_t phase_seg1, uint8_t phase_seg2, uint8_t sjw); +#else void can_init(can_data_t *hcan, CAN_TypeDef *instance); -bool can_set_bittiming(can_data_t *hcan, uint16_t brp, uint8_t phase_seg1, uint8_t phase_seg2, uint8_t sjw); void can_enable(can_data_t *hcan, bool loop_back, bool listen_only, bool one_shot); +#endif +bool can_set_bittiming(can_data_t *hcan, uint16_t brp, uint8_t phase_seg1, uint8_t phase_seg2, uint8_t sjw); void can_disable(can_data_t *hcan); bool can_is_enabled(can_data_t *hcan); -bool can_receive(can_data_t *hcan, struct gs_host_frame *rx_frame); +bool can_receive(can_data_t *hcan, struct GS_HOST_FRAME *rx_frame); bool can_is_rx_pending(can_data_t *hcan); -bool can_send(can_data_t *hcan, struct gs_host_frame *frame); +bool can_send(can_data_t *hcan, struct GS_HOST_FRAME *frame); /** return CAN->ESR register which contains tx/rx error counters and * LEC (last error code). @@ -61,4 +74,4 @@ uint32_t can_get_error_status(can_data_t *hcan); * @param frame : will hold the generated error frame * @return 1 when status changes (if any) need a new error frame sent */ -bool can_parse_error_status(uint32_t err, uint32_t last_err, can_data_t *hcan, struct gs_host_frame *frame); +bool can_parse_error_status(uint32_t err, uint32_t last_err, can_data_t *hcan, struct GS_HOST_FRAME *frame); diff --git a/include/config.h b/include/config.h index 55c4b0f6..fb9b276c 100644 --- a/include/config.h +++ b/include/config.h @@ -236,7 +236,6 @@ THE SOFTWARE. #define CAN_INTERFACE FDCAN1 #define CAN_INTERFACE2 FDCAN2 #define CAN_CLOCK_SPEED 64000000 - #define NUM_CAN_CHANNEL 2 #define CANFD_SUPPORT #define nCANSTBY_Port GPIOA diff --git a/include/gs_usb.h b/include/gs_usb.h index 85d5eaa9..852e452d 100644 --- a/include/gs_usb.h +++ b/include/gs_usb.h @@ -311,4 +311,7 @@ struct gs_host_frame_canfd { u8 reserved; u8 data[64]; + + u32 timestamp_us; + } __packed __aligned(4); diff --git a/include/usbd_gs_can.h b/include/usbd_gs_can.h index e09043e9..03ed5ebe 100644 --- a/include/usbd_gs_can.h +++ b/include/usbd_gs_can.h @@ -36,8 +36,13 @@ THE SOFTWARE. /* Define these here so they can be referenced in other files */ +#if defined(FDCAN1) +#define CAN_DATA_MAX_PACKET_SIZE 64 /* Endpoint IN & OUT Packet size */ +#define CAN_CMD_PACKET_SIZE 72 /* Control Endpoint Packet size */ +#else #define CAN_DATA_MAX_PACKET_SIZE 32 /* Endpoint IN & OUT Packet size */ #define CAN_CMD_PACKET_SIZE 64 /* Control Endpoint Packet size */ +#endif #define USB_CAN_CONFIG_DESC_SIZ 50 #define NUM_CAN_CHANNEL 1 #define USBD_GS_CAN_VENDOR_CODE 0x20 @@ -58,6 +63,9 @@ extern USBD_ClassTypeDef USBD_GS_CAN; // RX FIFO size chosen according to reference manual RM0368 which suggests // using (largest packet size / 4) + 1 # define USB_RX_FIFO_SIZE ((256U / 4U) + 1U) +#elif defined(STM32G0) +# define USB_INTERFACE USB_DRD_FS +# define USB_INTERRUPT USB_UCPD1_2_IRQn #endif uint8_t USBD_GS_CAN_Init(USBD_HandleTypeDef *pdev, queue_t *q_frame_pool, queue_t *q_from_host, led_data_t *leds); @@ -70,5 +78,5 @@ bool USBD_GS_CAN_CustomDeviceRequest(USBD_HandleTypeDef *pdev, USBD_SetupReqType bool USBD_GS_CAN_CustomInterfaceRequest(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req); bool USBD_GS_CAN_DfuDetachRequested(USBD_HandleTypeDef *pdev); -uint8_t USBD_GS_CAN_SendFrame(USBD_HandleTypeDef *pdev, struct gs_host_frame *frame); +uint8_t USBD_GS_CAN_SendFrame(USBD_HandleTypeDef *pdev, struct GS_HOST_FRAME *frame); uint8_t USBD_GS_CAN_Transmit(USBD_HandleTypeDef *pdev, uint8_t *buf, uint16_t len); diff --git a/src/can.c b/src/can.c index 4b2b0531..3f15ee1f 100644 --- a/src/can.c +++ b/src/can.c @@ -24,11 +24,14 @@ */ +#include #include "can.h" #include "config.h" #include "gs_usb.h" #include "hal_include.h" + +#if !defined(FDCAN1) // The STM32F0 only has one CAN interface, define it as CAN1 as // well, so it doesn't need to be handled separately. #if !defined(CAN1) && defined(CAN) @@ -52,13 +55,18 @@ static void rcc_reset(CAN_TypeDef *instance) } #endif } +#endif +#if defined(FDCAN1) +void can_init(can_data_t *hcan, FDCAN_GlobalTypeDef *instance) +#else void can_init(can_data_t *hcan, CAN_TypeDef *instance) +#endif { - __HAL_RCC_CAN1_CLK_ENABLE(); GPIO_InitTypeDef itd; #if defined(STM32F0) + __HAL_RCC_CAN1_CLK_ENABLE(); itd.Pin = GPIO_PIN_8|GPIO_PIN_9; itd.Mode = GPIO_MODE_AF_PP; itd.Pull = GPIO_NOPULL; @@ -66,23 +74,59 @@ void can_init(can_data_t *hcan, CAN_TypeDef *instance) itd.Alternate = GPIO_AF4_CAN; HAL_GPIO_Init(GPIOB, &itd); #elif defined(STM32F4) + __HAL_RCC_CAN1_CLK_ENABLE(); itd.Pin = GPIO_PIN_0|GPIO_PIN_1; itd.Mode = GPIO_MODE_AF_PP; itd.Pull = GPIO_NOPULL; itd.Speed = GPIO_SPEED_FREQ_VERY_HIGH; itd.Alternate = GPIO_AF9_CAN1; HAL_GPIO_Init(GPIOD, &itd); -#endif +#elif defined(STM32G0) + RCC_PeriphCLKInitTypeDef PeriphClkInit = {0}; + PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_FDCAN; + PeriphClkInit.FdcanClockSelection = RCC_FDCANCLKSOURCE_PCLK1; + HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit); + __HAL_RCC_FDCAN_CLK_ENABLE(); + __HAL_RCC_GPIOB_CLK_ENABLE(); + itd.Pin = GPIO_PIN_9|GPIO_PIN_8; + itd.Mode = GPIO_MODE_AF_PP; + itd.Pull = GPIO_NOPULL; + itd.Speed = GPIO_SPEED_FREQ_LOW; + itd.Alternate = GPIO_AF3_FDCAN1; + HAL_GPIO_Init(GPIOB, &itd); +#endif /* STM32G0 */ + + hcan->channel.Instance = instance; - hcan->instance = instance; - hcan->brp = 6; - hcan->sjw = 1; #if defined(STM32F0) - hcan->phase_seg1 = 13; - hcan->phase_seg2 = 2; + hcan->channel.Init.SyncJumpWidth = 1; + hcan->channel.Init.Prescaler = 6; + hcan->channel.Init.TimeSeg1 = 13; + hcan->channel.Init.TimeSeg2 = 2; #elif defined(STM32F4) - hcan->phase_seg1 = 12; - hcan->phase_seg2 = 1; + hcan->channel.Init.SyncJumpWidth = 1; + hcan->channel.Init.Prescaler = 6; + hcan->channel.Init.TimeSeg1 = 12; + hcan->channel.Init.TimeSeg2 = 1; +#elif defined(STM32G0) + hcan->channel.Init.ClockDivider = FDCAN_CLOCK_DIV1; + hcan->channel.Init.FrameFormat = FDCAN_FRAME_FD_BRS; + hcan->channel.Init.Mode = FDCAN_MODE_NORMAL; + hcan->channel.Init.AutoRetransmission = DISABLE; + hcan->channel.Init.TransmitPause = DISABLE; + hcan->channel.Init.ProtocolException = ENABLE; + hcan->channel.Init.NominalPrescaler = 8; + hcan->channel.Init.NominalSyncJumpWidth = 1; + hcan->channel.Init.NominalTimeSeg1 = 13; + hcan->channel.Init.NominalTimeSeg2 = 2; + hcan->channel.Init.DataPrescaler = 2; + hcan->channel.Init.DataSyncJumpWidth = 4; + hcan->channel.Init.DataTimeSeg1 = 15; + hcan->channel.Init.DataTimeSeg2 = 4; + hcan->channel.Init.StdFiltersNbr = 0; + hcan->channel.Init.ExtFiltersNbr = 0; + hcan->channel.Init.TxFifoQueueMode = FDCAN_TX_FIFO_OPERATION; + HAL_FDCAN_Init(&hcan->channel); #endif } @@ -93,29 +137,86 @@ bool can_set_bittiming(can_data_t *hcan, uint16_t brp, uint8_t phase_seg1, uint8 && (phase_seg2>0) && (phase_seg2<=8) && (sjw>0) && (sjw<=4) ) { - hcan->brp = brp & 0x3FF; - hcan->phase_seg1 = phase_seg1; - hcan->phase_seg2 = phase_seg2; - hcan->sjw = sjw; +#if defined(FDCAN1) + hcan->channel.Init.NominalSyncJumpWidth = sjw; + hcan->channel.Init.NominalTimeSeg1 = phase_seg1; + hcan->channel.Init.NominalTimeSeg2 = phase_seg2; + hcan->channel.Init.NominalPrescaler = brp; +#else + hcan->channel.Init.SyncJumpWidth = sjw; + hcan->channel.Init.TimeSeg1 = phase_seg1; + hcan->channel.Init.TimeSeg2 = phase_seg2; + hcan->channel.Init.Prescaler = brp; +#endif + return true; + } else { + return false; + } +} + +#if defined(FDCAN1) +bool can_set_data_bittiming(can_data_t *hcan, uint16_t brp, uint8_t phase_seg1, uint8_t phase_seg2, uint8_t sjw) +{ + if ( (brp>0) && (brp<=1024) + && (phase_seg1>0) && (phase_seg1<=16) + && (phase_seg2>0) && (phase_seg2<=8) + && (sjw>0) && (sjw<=4) + ) { + hcan->channel.Init.DataSyncJumpWidth = sjw; + hcan->channel.Init.DataTimeSeg1 = phase_seg1; + hcan->channel.Init.DataTimeSeg2 = phase_seg2; + hcan->channel.Init.DataPrescaler = brp; return true; } else { return false; } } +#endif +#if defined(FDCAN1) +void can_enable(can_data_t *hcan, bool loop_back, bool listen_only, bool one_shot, bool can_mode_fd) +{ + hcan->channel.Init.AutoRetransmission = one_shot ? DISABLE : ENABLE; + if (loop_back && listen_only) hcan->channel.Init.Mode = FDCAN_MODE_INTERNAL_LOOPBACK; + else if (loop_back) hcan->channel.Init.Mode = FDCAN_MODE_EXTERNAL_LOOPBACK; + else if (listen_only) hcan->channel.Init.Mode = FDCAN_MODE_BUS_MONITORING; + else hcan->channel.Init.Mode = FDCAN_MODE_NORMAL; + hcan->channel.Init.FrameFormat = can_mode_fd ? FDCAN_FRAME_FD_BRS : FDCAN_FRAME_CLASSIC; + + HAL_FDCAN_Init(&hcan->channel); + + /* Configure reception filter to Rx FIFO 0 on both FDCAN instances */ + FDCAN_FilterTypeDef sFilterConfig; + sFilterConfig.IdType = FDCAN_STANDARD_ID; + sFilterConfig.FilterIndex = 0; + sFilterConfig.FilterType = FDCAN_FILTER_RANGE; + sFilterConfig.FilterConfig = FDCAN_FILTER_DISABLE; + sFilterConfig.FilterID1 = 0x000; + sFilterConfig.FilterID2 = 0x7FF; + + HAL_FDCAN_ConfigFilter(&hcan->channel, &sFilterConfig); + + /* Configure global filter on both FDCAN instances: + Filter all remote frames with STD and EXT ID + Reject non matching frames with STD ID and EXT ID */ + HAL_FDCAN_ConfigGlobalFilter(&hcan->channel, FDCAN_ACCEPT_IN_RX_FIFO0, FDCAN_ACCEPT_IN_RX_FIFO0, FDCAN_FILTER_REMOTE, FDCAN_FILTER_REMOTE); + + // Start CAN using HAL + HAL_FDCAN_Start(&hcan->channel); +#else void can_enable(can_data_t *hcan, bool loop_back, bool listen_only, bool one_shot) { - CAN_TypeDef *can = hcan->instance; + CAN_TypeDef *can = hcan->channel.Instance; uint32_t mcr = CAN_MCR_INRQ | CAN_MCR_ABOM | CAN_MCR_TXFP | (one_shot ? CAN_MCR_NART : 0); - uint32_t btr = ((uint32_t)(hcan->sjw-1)) << 24 - | ((uint32_t)(hcan->phase_seg1-1)) << 16 - | ((uint32_t)(hcan->phase_seg2-1)) << 20 - | (hcan->brp - 1) + uint32_t btr = ((uint32_t)(hcan->channel.Init.SyncJumpWidth - 1)) << 24 + | ((uint32_t)(hcan->channel.Init.TimeSeg1 - 1)) << 16 + | ((uint32_t)(hcan->channel.Init.TimeSeg2 - 1)) << 20 + | (hcan->channel.Init.Prescaler - 1) | (loop_back ? CAN_MODE_LOOPBACK : 0) | (listen_only ? CAN_MODE_SILENT : 0); @@ -148,40 +249,87 @@ void can_enable(can_data_t *hcan, bool loop_back, bool listen_only, bool one_sho can->FFA1R &= ~filter_bit; // assign filter 0 to FIFO 0 can->FA1R |= filter_bit; // enable filter can->FMR &= ~CAN_FMR_FINIT; +#endif #ifdef nCANSTBY_Pin - HAL_GPIO_WritePin(nCANSTBY_Port, nCANSTBY_Pin, GPIO_PIN_SET); + HAL_GPIO_WritePin(nCANSTBY_Port, nCANSTBY_Pin, nCANSTBY_Active_High == 0 ? GPIO_PIN_RESET : GPIO_PIN_RESET); #endif } void can_disable(can_data_t *hcan) { - CAN_TypeDef *can = hcan->instance; +#if defined(FDCAN1) + HAL_FDCAN_Stop(&hcan->channel); +#else + CAN_TypeDef *can = hcan->channel.Instance; + can->MCR |= CAN_MCR_INRQ; // send can controller into initialization mode +#endif #ifdef nCANSTBY_Pin - HAL_GPIO_WritePin(nCANSTBY_Port, nCANSTBY_Pin, GPIO_PIN_RESET); + HAL_GPIO_WritePin(nCANSTBY_Port, nCANSTBY_Pin, nCANSTBY_Active_High == 0 ? GPIO_PIN_RESET : GPIO_PIN_RESET); #endif - can->MCR |= CAN_MCR_INRQ; // send can controller into initialization mode } bool can_is_enabled(can_data_t *hcan) { - CAN_TypeDef *can = hcan->instance; +#if defined(FDCAN1) + return hcan->channel.State == HAL_FDCAN_STATE_BUSY; +#else + CAN_TypeDef *can = hcan->channel.Instance; return (can->MCR & CAN_MCR_INRQ) == 0; +#endif } bool can_is_rx_pending(can_data_t *hcan) { - CAN_TypeDef *can = hcan->instance; +#if defined(FDCAN1) + return (HAL_FDCAN_GetRxFifoFillLevel(&hcan->channel, FDCAN_RX_FIFO0) >= 1); +#else + CAN_TypeDef *can = hcan->channel.Instance; return ((can->RF0R & CAN_RF0R_FMP0) != 0); +#endif } -bool can_receive(can_data_t *hcan, struct gs_host_frame *rx_frame) +bool can_receive(can_data_t *hcan, struct GS_HOST_FRAME *rx_frame) { - CAN_TypeDef *can = hcan->instance; +#if defined(FDCAN1) + FDCAN_RxHeaderTypeDef RxHeader; + + if (HAL_FDCAN_GetRxMessage(&hcan->channel, FDCAN_RX_FIFO0, &RxHeader, rx_frame->data) != HAL_OK) { + return false; + } + + rx_frame->channel = 0; + rx_frame->flags = 0; + + rx_frame->can_id = RxHeader.Identifier; + + if (RxHeader.IdType == FDCAN_EXTENDED_ID) { + rx_frame->can_id |= CAN_EFF_FLAG; + } + + if (RxHeader.RxFrameType == FDCAN_REMOTE_FRAME) { + rx_frame->can_id |= CAN_RTR_FLAG; + } + + rx_frame->can_dlc = (RxHeader.DataLength & 0x000F0000) >> 16; + + if (RxHeader.FDFormat == FDCAN_FD_CAN) { + /* this is a CAN-FD frame */ + rx_frame->flags = GS_CAN_FLAG_FD; + if (RxHeader.BitRateSwitch == FDCAN_BRS_ON) { + rx_frame->flags |= GS_CAN_FLAG_BRS; + } + } + return true; +#else + CAN_TypeDef *can = hcan->channel.Instance; if (can_is_rx_pending(hcan)) { CAN_FIFOMailBox_TypeDef *fifo = &can->sFIFOMailBox[0]; + rx_frame->channel = 0; + rx_frame->flags = 0; + if (fifo->RIR & CAN_RI0R_IDE) { rx_frame->can_id = CAN_EFF_FLAG | ((fifo->RIR >> 3) & 0x1FFFFFFF); } else { @@ -209,11 +357,13 @@ bool can_receive(can_data_t *hcan, struct gs_host_frame *rx_frame) } else { return false; } +#endif } +#if !defined(FDCAN1) static CAN_TxMailBox_TypeDef *can_find_free_mailbox(can_data_t *hcan) { - CAN_TypeDef *can = hcan->instance; + CAN_TypeDef *can = hcan->channel.Instance; uint32_t tsr = can->TSR; if ( tsr & CAN_TSR_TME0 ) { @@ -226,9 +376,51 @@ static CAN_TxMailBox_TypeDef *can_find_free_mailbox(can_data_t *hcan) return 0; } } +#endif -bool can_send(can_data_t *hcan, struct gs_host_frame *frame) +bool can_send(can_data_t *hcan, struct GS_HOST_FRAME *frame) { +#if defined(FDCAN1) + FDCAN_TxHeaderTypeDef TxHeader; + + TxHeader.DataLength = frame->can_dlc << 16; + TxHeader.ErrorStateIndicator = FDCAN_ESI_ACTIVE; + TxHeader.TxEventFifoControl = FDCAN_NO_TX_EVENTS; + TxHeader.MessageMarker = 0; + + TxHeader.TxFrameType = frame->can_id & CAN_RTR_FLAG ? FDCAN_REMOTE_FRAME : FDCAN_DATA_FRAME; + + + if (frame->can_id & CAN_EFF_FLAG) { + TxHeader.IdType = FDCAN_EXTENDED_ID; + TxHeader.Identifier = frame->can_id & 0x1FFFFFFF; + } + else { + TxHeader.IdType = FDCAN_STANDARD_ID; + TxHeader.Identifier = frame->can_id & 0x7FF; + } + + if (frame->flags & GS_CAN_FLAG_FD) { + TxHeader.FDFormat = FDCAN_FD_CAN; + if (frame->flags & GS_CAN_FLAG_BRS) { + TxHeader.BitRateSwitch = FDCAN_BRS_ON; + } + else { + TxHeader.BitRateSwitch = FDCAN_BRS_OFF; + } + } + else { + TxHeader.BitRateSwitch = FDCAN_BRS_OFF; + TxHeader.FDFormat = FDCAN_CLASSIC_CAN; + } + + if (HAL_FDCAN_AddMessageToTxFifoQ(&hcan->channel, &TxHeader, frame->data) != HAL_OK) { + return false; + } + else { + return true; + } +#else CAN_TxMailBox_TypeDef *mb = can_find_free_mailbox(hcan); if (mb != 0) { @@ -267,26 +459,38 @@ bool can_send(can_data_t *hcan, struct gs_host_frame *frame) } else { return false; } +#endif } uint32_t can_get_error_status(can_data_t *hcan) { - CAN_TypeDef *can = hcan->instance; +#if defined(FDCAN1) + uint32_t err = hcan->channel.Instance->PSR; + /* Write 7 to LEC so we know if it gets set to the same thing again */ + hcan->channel.Instance->PSR = 7; +#else + CAN_TypeDef *can = hcan->channel.Instance; uint32_t err = can->ESR; /* Write 7 to LEC so we know if it gets set to the same thing again */ can->ESR = 7<<4; +#endif return err; } static bool status_is_active(uint32_t err) { +#if defined(FDCAN1) + return !(err & (FDCAN_PSR_BO | FDCAN_PSR_EP)); +#else return !(err & (CAN_ESR_BOFF | CAN_ESR_EPVF)); +#endif + } -bool can_parse_error_status(uint32_t err, uint32_t last_err, can_data_t *hcan, struct gs_host_frame *frame) +bool can_parse_error_status(uint32_t err, uint32_t last_err, can_data_t *hcan, struct GS_HOST_FRAME *frame) { /* We build up the detailed error information at the same time as we decide * whether there's anything worth sending. This variable tracks that final @@ -306,6 +510,45 @@ bool can_parse_error_status(uint32_t err, uint32_t last_err, can_data_t *hcan, s frame->data[6] = 0; frame->data[7] = 0; + /* We transitioned from passive/bus-off to active, so report the edge. */ + if (!status_is_active(last_err) && status_is_active(err)) { + frame->can_id |= CAN_ERR_CRTL; + frame->data[1] |= CAN_ERR_CRTL_ACTIVE; + should_send = true; + } + +#if defined (FDCAN1) + if (err & FDCAN_PSR_BO) { + if (!(last_err & FDCAN_PSR_BO)) { + /* We transitioned to bus-off. */ + frame->can_id |= CAN_ERR_BUSOFF; + should_send = true; + } + } + /* The Linux sja1000 driver puts these counters here. Seems like as good a + * place as any. */ + // TX error count + frame->data[6] = ((hcan->channel.Instance->ECR & FDCAN_ECR_TEC) >> FDCAN_ECR_TEC_Pos); + // RX error count + frame->data[7] = ((hcan->channel.Instance->ECR & FDCAN_ECR_REC) >> FDCAN_ECR_REC_Pos); + + if (err & FDCAN_PSR_EP) { + if (!(last_err & FDCAN_PSR_EP)) { + frame->can_id |= CAN_ERR_CRTL; + frame->data[1] |= CAN_ERR_CRTL_RX_PASSIVE | CAN_ERR_CRTL_TX_PASSIVE; + should_send = true; + } + } + else if (err & FDCAN_PSR_EW) { + if (!(last_err & FDCAN_PSR_EW)) { + frame->can_id |= CAN_ERR_CRTL; + frame->data[1] |= CAN_ERR_CRTL_RX_WARNING | CAN_ERR_CRTL_TX_WARNING; + should_send = true; + } + } + + uint8_t lec = err & FDCAN_PSR_LEC; +#else if (err & CAN_ESR_BOFF) { if (!(last_err & CAN_ESR_BOFF)) { /* We transitioned to bus-off. */ @@ -321,13 +564,6 @@ bool can_parse_error_status(uint32_t err, uint32_t last_err, can_data_t *hcan, s return should_send; } - /* We transitioned from passive/bus-off to active, so report the edge. */ - if (!status_is_active(last_err) && status_is_active(err)) { - frame->can_id |= CAN_ERR_CRTL; - frame->data[1] |= CAN_ERR_CRTL_ACTIVE; - should_send = true; - } - uint8_t tx_error_cnt = (err>>16) & 0xFF; uint8_t rx_error_cnt = (err>>24) & 0xFF; /* The Linux sja1000 driver puts these counters here. Seems like as good a @@ -350,6 +586,7 @@ bool can_parse_error_status(uint32_t err, uint32_t last_err, can_data_t *hcan, s } uint8_t lec = (err>>4) & 0x07; +#endif switch (lec) { case 0x01: /* stuff error */ frame->can_id |= CAN_ERR_PROT; diff --git a/src/main.c b/src/main.c index 4145c835..b503cfbb 100644 --- a/src/main.c +++ b/src/main.c @@ -46,7 +46,7 @@ THE SOFTWARE. void HAL_MspInit(void); static void SystemClock_Config(void); -static bool send_to_host_or_enqueue(struct gs_host_frame *frame); +static bool send_to_host_or_enqueue(struct GS_HOST_FRAME *frame); static void send_to_host(void); static can_data_t hCAN = {0}; @@ -88,7 +88,7 @@ int main(void) q_to_host = queue_create(CAN_QUEUE_SIZE); assert_basic(q_frame_pool && q_from_host && q_to_host); - struct gs_host_frame *msgbuf = calloc(CAN_QUEUE_SIZE, sizeof(struct gs_host_frame)); + struct GS_HOST_FRAME *msgbuf = calloc(CAN_QUEUE_SIZE, sizeof(struct GS_HOST_FRAME)); assert_basic(msgbuf); for (unsigned i=0; itimestamp_us = timer_get(); frame->echo_id = 0xFFFFFFFF; // not a echo frame - frame->channel = 0; - frame->flags = 0; frame->reserved = 0; send_to_host_or_enqueue(frame); @@ -152,7 +150,7 @@ int main(void) // to report even if multiple pass by. } else { uint32_t can_err = can_get_error_status(&hCAN); - struct gs_host_frame *frame = queue_pop_front(q_frame_pool); + struct GS_HOST_FRAME *frame = queue_pop_front(q_frame_pool); if (frame != 0) { frame->timestamp_us = timer_get(); if (can_parse_error_status(can_err, last_can_error_status, &hCAN, frame)) { @@ -284,7 +282,7 @@ void SystemClock_Config(void) HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0); } -bool send_to_host_or_enqueue(struct gs_host_frame *frame) +bool send_to_host_or_enqueue(struct GS_HOST_FRAME *frame) { queue_push_back(q_to_host, frame); return true; @@ -292,7 +290,7 @@ bool send_to_host_or_enqueue(struct gs_host_frame *frame) void send_to_host(void) { - struct gs_host_frame *frame = queue_pop_front(q_to_host); + struct GS_HOST_FRAME *frame = queue_pop_front(q_to_host); if (!frame) return; diff --git a/src/usbd_gs_can.c b/src/usbd_gs_can.c index 08164665..ae1e55a0 100644 --- a/src/usbd_gs_can.c +++ b/src/usbd_gs_can.c @@ -52,7 +52,7 @@ typedef struct { queue_t *q_frame_pool; queue_t *q_from_host; - struct gs_host_frame *from_host_buf; + struct GS_HOST_FRAME *from_host_buf; can_data_t *channels[NUM_CAN_CHANNEL]; @@ -272,6 +272,10 @@ static const struct gs_device_bt_const USBD_GS_CAN_btconst = { | GS_CAN_FEATURE_HW_TIMESTAMP | GS_CAN_FEATURE_IDENTIFY | GS_CAN_FEATURE_PAD_PKTS_TO_MAX_PKT_SIZE +#if defined(FDCAN1) + | GS_CAN_FEATURE_FD + | GS_CAN_FEATURE_BT_CONST_EXT +#endif #ifdef TERM_Pin | GS_CAN_FEATURE_TERMINATION #endif @@ -287,6 +291,40 @@ static const struct gs_device_bt_const USBD_GS_CAN_btconst = { 1, // brp increment; }; +#if defined(FDCAN1) +static const struct gs_device_bt_const_extended USBD_GS_CAN_btconst_extended = { + GS_CAN_FEATURE_LISTEN_ONLY // supported features + | GS_CAN_FEATURE_LOOP_BACK + | GS_CAN_FEATURE_HW_TIMESTAMP + | GS_CAN_FEATURE_IDENTIFY + | GS_CAN_FEATURE_USER_ID + | GS_CAN_FEATURE_PAD_PKTS_TO_MAX_PKT_SIZE + | GS_CAN_FEATURE_FD + | GS_CAN_FEATURE_BT_CONST_EXT +#ifdef TERM_Pin + | GS_CAN_FEATURE_TERMINATION +#endif + , + CAN_CLOCK_SPEED, // can timing base clock + 1, // tseg1 min + 16, // tseg1 max + 1, // tseg2 min + 8, // tseg2 max + 4, // sjw max + 1, // brp min + 1024, //brp_max + 1, // brp increment; + + 1, // dtseg1_min + 16, // dtseg1_max + 1, // dtseg2_min + 8, // dtseg2_max + 4, // dsjw_max + 1, // dbrp_min + 1024, //dbrp_max + 1, // dbrp_inc; +}; +#endif /* It's unclear from the documentation, but it appears that the USB library is * not safely reentrant. It attempts to signal errors via return values if it is * reentered, but that code is not interrupt-safe and the error values are @@ -423,6 +461,9 @@ static uint8_t USBD_GS_CAN_EP0_RxReady(USBD_HandleTypeDef *pdev) { (mode->flags & GS_CAN_MODE_LISTEN_ONLY) != 0, (mode->flags & GS_CAN_MODE_ONE_SHOT) != 0 // triple sampling not supported on bxCAN +#if defined(FDCAN1) + ,((mode->flags & GS_CAN_MODE_FD) != 0) +#endif ); led_set_mode(hcan->leds, led_mode_normal); @@ -442,7 +483,20 @@ static uint8_t USBD_GS_CAN_EP0_RxReady(USBD_HandleTypeDef *pdev) { ); } break; - +#if defined(FDCAN1) + case GS_USB_BREQ_DATA_BITTIMING: + timing = (struct gs_device_bittiming*)hcan->ep0_buf; + if (req->wValue < NUM_CAN_CHANNEL) { + can_set_data_bittiming( + hcan->channels[req->wValue], + timing->brp, + timing->prop_seg + timing->phase_seg1, + timing->phase_seg2, + timing->sjw + ); + } + break; +#endif default: break; } @@ -494,6 +548,9 @@ static uint8_t USBD_GS_CAN_Config_Request(USBD_HandleTypeDef *pdev, USBD_SetupRe case GS_USB_BREQ_HOST_FORMAT: case GS_USB_BREQ_MODE: case GS_USB_BREQ_BITTIMING: +#if defined(FDCAN1) + case GS_USB_BREQ_DATA_BITTIMING: +#endif case GS_USB_BREQ_IDENTIFY: hcan->last_setup_request = *req; USBD_CtlPrepareRx(pdev, hcan->ep0_buf, req->wLength); @@ -521,7 +578,12 @@ static uint8_t USBD_GS_CAN_Config_Request(USBD_HandleTypeDef *pdev, USBD_SetupRe memcpy(hcan->ep0_buf, &USBD_GS_CAN_btconst, sizeof(USBD_GS_CAN_btconst)); USBD_CtlSendData(pdev, hcan->ep0_buf, req->wLength); break; - +#if defined(FDCAN1) + case GS_USB_BREQ_BT_CONST_EXT: + memcpy(hcan->ep0_buf, &USBD_GS_CAN_btconst_extended, sizeof(USBD_GS_CAN_btconst_extended)); + USBD_CtlSendData(pdev, hcan->ep0_buf, req->wLength); + break; +#endif case GS_USB_BREQ_TIMESTAMP: memcpy(hcan->ep0_buf, &hcan->sof_timestamp_us, sizeof(hcan->sof_timestamp_us)); USBD_CtlSendData(pdev, hcan->ep0_buf, sizeof(hcan->sof_timestamp_us)); @@ -622,7 +684,11 @@ static uint8_t USBD_GS_CAN_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum) { USBD_GS_CAN_HandleTypeDef *hcan = (USBD_GS_CAN_HandleTypeDef*)pdev->pClassData; uint32_t rxlen = USBD_LL_GetRxDataSize(pdev, epnum); - if (rxlen < (sizeof(struct gs_host_frame)-4)) { +#if defined(FDCAN1) + if (rxlen < (sizeof(struct GS_HOST_FRAME_CLASSIC)-4)) { +#else + if (rxlen < (sizeof(struct GS_HOST_FRAME)-4)) { +#endif // Invalid frame length, just ignore it and receive into the same buffer // again next time. USBD_GS_CAN_PrepareReceive(pdev); @@ -684,12 +750,12 @@ uint8_t USBD_GS_CAN_Transmit(USBD_HandleTypeDef *pdev, uint8_t *buf, uint16_t le } } -uint8_t USBD_GS_CAN_SendFrame(USBD_HandleTypeDef *pdev, struct gs_host_frame *frame) +uint8_t USBD_GS_CAN_SendFrame(USBD_HandleTypeDef *pdev, struct GS_HOST_FRAME *frame) { - uint8_t buf[CAN_DATA_MAX_PACKET_SIZE],*send_addr; + uint8_t buf[sizeof(struct GS_HOST_FRAME)],*send_addr; USBD_GS_CAN_HandleTypeDef *hcan = (USBD_GS_CAN_HandleTypeDef*)pdev->pClassData; - size_t len = sizeof(struct gs_host_frame); + size_t len = sizeof(struct GS_HOST_FRAME); if (!hcan->timestamps_enabled) { len -= 4;