diff --git a/include/can.h b/include/can.h new file mode 100644 index 0000000..e1cfdc6 --- /dev/null +++ b/include/can.h @@ -0,0 +1,8 @@ +#pragma once + +#include +#include "stm32f0xx_hal.h" + +void can_set_bittiming(CAN_HandleTypeDef *hcan, uint16_t brp, uint8_t phase_seg1, uint8_t phase_seg2, uint8_t sjw); +void can_enable(CAN_HandleTypeDef *hcan, bool loop_back, bool listen_only, bool one_shot, bool triple_sample); +void can_disable(CAN_HandleTypeDef *hcan); diff --git a/include/usbd_gs_can.h b/include/usbd_gs_can.h index 127b849..515dc19 100644 --- a/include/usbd_gs_can.h +++ b/include/usbd_gs_can.h @@ -3,7 +3,9 @@ #include "usbd_def.h" -extern USBD_ClassTypeDef USBD_GS_CAN; +extern USBD_ClassTypeDef USBD_GS_CAN; + +void USBD_GS_CAN_SetChannel(USBD_HandleTypeDef *pdev, uint8_t channel, CAN_HandleTypeDef* handle); void USBD_GS_CAN_SendFrameToHost( USBD_HandleTypeDef *pdev, diff --git a/src/can.c b/src/can.c new file mode 100644 index 0000000..979d224 --- /dev/null +++ b/src/can.c @@ -0,0 +1,44 @@ +#include "can.h" + +void can_set_bittiming(CAN_HandleTypeDef *hcan, uint16_t brp, uint8_t phase_seg1, uint8_t phase_seg2, uint8_t sjw) +{ + HAL_CAN_DeInit(hcan); + + hcan->Init.Prescaler = brp; + + if ((phase_seg1>0) && (phase_seg1<17)) { + hcan->Init.BS1 = (phase_seg1-1)<<16; + } + + if ((phase_seg2>0) && (phase_seg2<9)) { + hcan->Init.BS2 = (phase_seg2-1)<<20; + } + + if ((sjw>0) && (sjw<5)) { + hcan->Init.SJW = (sjw-1)<<24; + } + + HAL_CAN_Init(hcan); +} + +void can_enable(CAN_HandleTypeDef *hcan, bool loop_back, bool listen_only, bool one_shot, bool triple_sample) +{ + hcan->Init.Mode = 0; + if (loop_back) { + hcan->Init.Mode |= CAN_MODE_LOOPBACK; + } + if (listen_only) { + hcan->Init.Mode |= CAN_MODE_SILENT; + } + + hcan->Init.NART = one_shot ? ENABLE : DISABLE; + + // tripple sample not supported on bxCAN + + HAL_CAN_Init(hcan); +} + +void can_disable(CAN_HandleTypeDef *hcan) +{ + HAL_CAN_DeInit(hcan); +} diff --git a/src/main.c b/src/main.c index 61d6d54..b590182 100644 --- a/src/main.c +++ b/src/main.c @@ -74,6 +74,7 @@ int main(void) USBD_Init(&hUsbDeviceFS, &FS_Desc, DEVICE_FS); USBD_RegisterClass(&hUsbDeviceFS, &USBD_GS_CAN); + USBD_GS_CAN_SetChannel(&hUsbDeviceFS, 0, &hcan); USBD_Start(&hUsbDeviceFS); while (1) { diff --git a/src/usbd_gs_can.c b/src/usbd_gs_can.c index 9c6362d..5463017 100644 --- a/src/usbd_gs_can.c +++ b/src/usbd_gs_can.c @@ -1,27 +1,31 @@ #include "usbd_gs_can.h" + +#include "stm32f0xx_hal.h" #include "usbd_desc.h" #include "usbd_ctlreq.h" #include "usbd_ioreq.h" #include "gs_usb.h" +#include "can.h" #define CAN_DATA_MAX_PACKET_SIZE 32 /* Endpoint IN & OUT Packet size */ #define CAN_CMD_PACKET_SIZE 64 /* Control Endpoint Packet size */ #define USB_CAN_CONFIG_DESC_SIZ 32 +#define NUM_CAN_CHANNEL 1 typedef struct { __IO uint32_t TxState; - uint8_t req_bRequest; - uint8_t req_wLength; + uint8_t req_bRequest; + uint16_t req_wLength; + uint16_t req_wValue; uint8_t ep0_buf[CAN_CMD_PACKET_SIZE]; uint8_t ep_out_buf[CAN_DATA_MAX_PACKET_SIZE]; uint8_t ep_in_buf[CAN_DATA_MAX_PACKET_SIZE]; struct gs_host_config host_config; - struct gs_device_mode device_mode; - struct gs_device_bittiming bittiming; + CAN_HandleTypeDef *channels[NUM_CAN_CHANNEL]; } USBD_GS_CAN_HandleTypeDef; static uint8_t USBD_GS_CAN_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx); @@ -127,6 +131,13 @@ static uint8_t USBD_GS_CAN_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx) return ret; } +void USBD_GS_CAN_SetChannel(USBD_HandleTypeDef *pdev, uint8_t channel, CAN_HandleTypeDef* handle) { + USBD_GS_CAN_HandleTypeDef *hcan = (USBD_GS_CAN_HandleTypeDef*) pdev->pClassData; + if ((hcan!=NULL) && (channel < NUM_CAN_CHANNEL)) { + hcan->channels[channel] = handle; + } +} + static uint8_t USBD_GS_CAN_DeInit(USBD_HandleTypeDef *pdev, uint8_t cfgidx) { (void) cfgidx; @@ -148,6 +159,10 @@ static uint8_t USBD_GS_CAN_EP0_RxReady(USBD_HandleTypeDef *pdev) { USBD_GS_CAN_HandleTypeDef *hcan = (USBD_GS_CAN_HandleTypeDef*) pdev->pClassData; + struct gs_device_bittiming *timing; + struct gs_device_mode *mode; + CAN_HandleTypeDef *ch; + switch (hcan->req_bRequest) { case GS_USB_BREQ_HOST_FORMAT: @@ -156,20 +171,45 @@ static uint8_t USBD_GS_CAN_EP0_RxReady(USBD_HandleTypeDef *pdev) { break; case GS_USB_BREQ_MODE: - // TODO set device mode (flags, start/reset...) - memcpy(&hcan->device_mode, hcan->ep0_buf, sizeof(hcan->device_mode)); + if (hcan->req_wValue < NUM_CAN_CHANNEL) { + + mode = (struct gs_device_mode*)hcan->ep0_buf; + ch = hcan->channels[hcan->req_wValue]; + + if (mode->mode == GS_CAN_MODE_RESET) { + + can_disable(ch); + + } else if (mode->mode == GS_CAN_MODE_START) { + + can_enable(ch, + (mode->flags & GS_CAN_MODE_LOOP_BACK) != 0, + (mode->flags & GS_CAN_MODE_LISTEN_ONLY) != 0, + (mode->flags & GS_CAN_MODE_ONE_SHOT) != 0, + (mode->flags & GS_CAN_MODE_TRIPLE_SAMPLE) != 0 + ); + + } + } break; case GS_USB_BREQ_BITTIMING: - // TODO set bit timing - memcpy(&hcan->bittiming, hcan->ep0_buf, sizeof(hcan->bittiming)); + timing = (struct gs_device_bittiming*)hcan->ep0_buf; + if (hcan->req_wValue < NUM_CAN_CHANNEL) { + can_set_bittiming( + hcan->channels[hcan->req_wValue], + timing->brp, + timing->prop_seg + timing->phase_seg1, + timing->phase_seg2, + timing->sjw + ); + } break; default: break; } - hcan->req_bRequest = 0xFF; return USBD_OK; } @@ -203,7 +243,8 @@ static uint8_t USBD_GS_CAN_Vendor_Request(USBD_HandleTypeDef *pdev, USBD_SetupRe case GS_USB_BREQ_MODE: case GS_USB_BREQ_BITTIMING: hcan->req_bRequest = req->bRequest; - hcan->req_wLength = (uint8_t)req->wLength; + hcan->req_wLength = req->wLength; + hcan->req_wValue = req->wValue; USBD_CtlPrepareRx(pdev, hcan->ep0_buf, req->wLength); break; @@ -324,7 +365,5 @@ void USBD_GS_CAN_SendFrameToHost( hf.data[i] = data[i]; } - if (hcan->device_mode.mode == GS_CAN_MODE_START) { - USBD_GS_CAN_Transmit(pdev, (uint8_t*)&hf, sizeof(hf)); - } + USBD_GS_CAN_Transmit(pdev, (uint8_t*)&hf, sizeof(hf)); }