diff --git a/f1/can/include/can.h b/f1/can/include/can.h
new file mode 100644
index 0000000000000000000000000000000000000000..0d65b11d627dc2c0a2e72762879d16a62ed3123e
--- /dev/null
+++ b/f1/can/include/can.h
@@ -0,0 +1,19 @@
+#ifndef CAN_F1_H
+#define CAN_F1_H
+
+#include "stm32f1xx_hal.h"
+#include "comm.h"
+
+/* public functions */
+void can_init(TComm *comm_dev,CAN_InitTypeDef *conf,TCAN_IRQ_Priorities *priorities);
+void can_config(TComm *comm_dev,CAN_InitTypeDef *conf);
+void can_set_priorities(TComm *comm_dev,TCAN_IRQ_Priorities *priorities);
+void can_set_bitrate(TComm *comm_dev,unsigned int bitrate);
+void can_set_filter(TComm *comm_dev,CAN_FilterTypeDef *filter)
+/* IRQ functions */
+unsigned char can_send_irq(unsigned char first_byte);
+unsigned char can_enable_tx_irq(void);
+unsigned char can_receive_irq(void);
+unsigned char can_cancel_receive_irq(void);
+
+#endif
diff --git a/f1/can/include/can_common.h b/f1/can/include/can_common.h
new file mode 100644
index 0000000000000000000000000000000000000000..f7eabaff39d5986f886369ab1df4663a2b8ff2ad
--- /dev/null
+++ b/f1/can/include/can_common.h
@@ -0,0 +1,22 @@
+#ifndef CAN_COMMON_F1_H
+#define CAN_COMMON_F1_H
+
+typedef struct
+{
+  unsigned char irq_priority;
+  unsigned char irq_subpriority;
+}TCAN_IRQ_Priorities;
+
+enum CAN_SPEED { //only applies when APB1 = 36Mhz
+    CAN_10KBPS,
+    CAN_20KBPS,
+    CAN_50KBPS,
+    CAN_83K3BPS,
+    CAN_100KBPS,
+    CAN_125KBPS,
+    CAN_250KBPS,
+    CAN_500KBPS,
+    CAN_1000KBPS
+};
+
+#endif
diff --git a/f1/can/src/can.c b/f1/can/src/can.c
new file mode 100644
index 0000000000000000000000000000000000000000..0f2894d96e314d65e9a850e5b99685e38366b8fa
--- /dev/null
+++ b/f1/can/src/can.c
@@ -0,0 +1,193 @@
+#include "can.h"
+
+#define     CAN                    CAN1
+#define     CAN_ENABLE_CLK         __HAL_RCC_CAN1_CLK_ENABLE()
+#define     CAN_IRQnRX             USB_LP_CAN1_RX0_IRQn
+#define     CAN_IRQnTX             USB_HP_CAN1_TX_IRQn
+#define     CAN_IRQHandler         USB_LP_CAN1_RX0CAN_IRQHandler
+
+#define     CAN_TX_PIN             GPIO_PIN_9
+#define     CAN_TX_GPIO_PORT       GPIOB
+#define     CAN_ENABLE_TX_GPIO_CLK __HAL_RCC_GPIOB_CLK_ENABLE()
+
+#define     CAN_RX_PIN             GPIO_PIN_8
+#define     CAN_RX_GPIO_PORT       GPIOB
+#define     CAN_ENABLE_RX_GPIO_CLK __HAL_RCC_GPIOB_CLK_ENABLE()
+
+// private variables
+CAN_HandleTypeDef CANHandle;
+CanTxMsgTypeDef CAN_txMessage;
+CanRxMsgTypeDef CAN_rxMessage;
+TComm *can_comm_dev;
+
+
+void can_init(TComm *comm_dev,CAN_InitTypeDef *conf,TCAN_IRQ_Priorities *priorities)
+{
+  GPIO_InitTypeDef GPIO_InitStructure;
+
+  /* Enable GPIO clock */
+  CAN_ENABLE_TX_GPIO_CLK;
+  CAN_ENABLE_RX_GPIO_CLK;
+
+  CAN_ENABLE_CLK;
+
+  /**CAN GPIO Configuration
+   PB8     ------> CAN_RX
+   PB9     ------> CAN_TX
+   */
+  /* Configure CAN Tx and Rx as alternate function push-pull */
+  GPIO_InitStructure.Pin       = CAN_RX_PIN;
+  GPIO_InitStructure.Pull      = GPIO_PULLDOWN;
+  GPIO_InitStructure.Mode      = GPIO_MODE_INPUT;
+  HAL_GPIO_Init(CAN_RX_GPIO_PORT, &GPIO_InitStructure);
+
+  GPIO_InitStructure.Pin       = CAN_TX_PIN;
+  GPIO_InitStructure.Mode      = GPIO_MODE_AF_PP;
+  GPIO_InitStructure.Speed     = GPIO_SPEED_FREQ_HIGH;
+  HAL_GPIO_Init(CAN_TX_GPIO_PORT, &GPIO_InitStructure);
+
+  _HAL_AFIO_REMAP_CAN1_2();
+
+
+  CANHandle.Instance          = CAN;
+  can_config(comm_dev,conf);
+
+  can_set_priorities(comm_dev,priorities);
+
+  /* Initialize the comm structure */
+  comm_dev->send_irq=can_send_irq;
+  comm_dev->enable_tx_irq=can_enable_tx_irq;
+  comm_dev->receive_irq=can_receive_irq;
+  comm_dev->cancel_receive_irq=can_cancel_receive_irq;
+  comm_dev->irq_send_cb=0x00000000;
+  comm_dev->irq_receive_cb=0x00000000;
+  comm_dev->dma_send_cb=0x00000000;
+  comm_dev->dma_receive_cb=0x00000000;
+
+  /* initialize internal variables */
+  can_comm_dev=comm_dev;
+  HAL_CAN_Start(CANHandle);
+}
+
+void can_config(TComm *comm_dev,CAN_InitTypeDef *conf)
+{
+  CANHandle.Init.Prescaler = conf->Prescaler;
+  CANHandle.Init.Mode = conf->Mode;
+  CANHandle.Init.SJW = conf->SJW;
+  CANHandle.Init.BS1 = conf->BS1;
+  CANHandle.Init.BS2 = conf->BS2;
+  CANHandle.Init.TTCM = conf->TTCM;
+  CANHandle.Init.ABOM = conf->ABOM;
+  CANHandle.Init.AWUM = conf->AWUM;
+  CANHandle.Init.NART = conf->NART;
+  CANHandle.Init.RFLM = conf->RFLM;
+  CANHandle.Init.TXFP = conf->TXFP;
+  HAL_CAN_Init(&CANHandle);
+}
+
+void can_set_priorities(TComm *comm_dev,TCAN_IRQ_Priorities *priorities)
+{
+  HAL_NVIC_SetPriority(CAN_IRQnRX, priorities->irq_priority, priorities->irq_subpriority);
+  HAL_NVIC_EnableIRQ(CAN_IRQnRX);
+  HAL_NVIC_SetPriority(CAN_IRQnTX, priorities->irq_priority, priorities->irq_subpriority);
+  HAL_NVIC_EnableIRQ(CAN_IRQnTX);
+}
+
+void can_set_bitrate(TComm *comm_dev,CAN_SPEED bitrate)
+{
+  switch (CAN_SPEED) {
+    case CAN_10KBPS:
+      CANHandle.Init.Prescaler = 225;
+      CANHandle.Init.TimeSeg1 = 13;
+      CANHandle.Init.TimeSeg2 = 2;
+      CANHandle.Init.SyncJumpWidth = 1;
+      break;
+    case CAN_20KBPS:
+      CANHandle.Init.Prescaler = 100;
+      CANHandle.Init.TimeSeg1 = 15;
+      CANHandle.Init.TimeSeg2 = 2;
+      CANHandle.Init.SyncJumpWidth = 1;
+      break;
+    case CAN_50KBPS:
+      CANHandle.Init.Prescaler = 45;
+      CANHandle.Init.TimeSeg1 = 13;
+      CANHandle.Init.TimeSeg2 = 2;
+      CANHandle.Init.SyncJumpWidth = 1;
+      break;
+    case CAN_83K3BPS:
+      CANHandle.Init.Prescaler = 27;
+      CANHandle.Init.TimeSeg1 = 13;
+      CANHandle.Init.TimeSeg2 = 2;
+      CANHandle.Init.SyncJumpWidth = 1;
+      break;
+    case CAN_100KBPS:
+      CANHandle.Init.Prescaler = 20;
+      CANHandle.Init.TimeSeg1 = 15;
+      CANHandle.Init.TimeSeg2 = 2;
+      CANHandle.Init.SyncJumpWidth = 1;
+      break;
+    case CAN_125KBPS:
+      CANHandle.Init.Prescaler = 18;
+      CANHandle.Init.TimeSeg1 = 13;
+      CANHandle.Init.TimeSeg2 = 2;
+      CANHandle.Init.SyncJumpWidth = 1;
+      break;
+    case CAN_250KBPS:
+      CANHandle.Init.Prescaler = 9;
+      CANHandle.Init.TimeSeg1 = 13;
+      CANHandle.Init.TimeSeg2 = 2;
+      CANHandle.Init.SyncJumpWidth = 1;
+      break;
+    case CAN_500KBPS:
+      CANHandle.Init.Prescaler = 4;
+      CANHandle.Init.TimeSeg1 = 15;
+      CANHandle.Init.TimeSeg2 = 2;
+      CANHandle.Init.SyncJumpWidth = 1;
+      break;
+    case CAN_1000KBPS:
+      CANHandle.Init.Prescaler = 2;
+      CANHandle.Init.TimeSeg1 = 15;
+      CANHandle.Init.TimeSeg2 = 2;
+      CANHandle.Init.SyncJumpWidth = 1;
+      break;
+  }
+}
+
+void can_set_filter(TComm *comm_dev,CAN_FilterTypeDef *filter)
+{
+  HAL_CAN_ConfigFilter(&CANHandle, &filter);
+  HAL_CAN_Receive_IT(&CANHandle,CAN_FIFO0);
+}
+
+// interrupt handlers
+void USB_LP_CAN1_RX0_IRQHandler(void)
+{
+  /* USER CODE BEGIN USB_LP_CAN1_RX0_IRQn 0 */
+
+  /* USER CODE END USB_LP_CAN1_RX0_IRQn 0 */
+  HAL_PCD_IRQHandler(&PCDHandle);
+  /* USER CODE BEGIN USB_LP_CAN1_RX0_IRQn 1 */
+
+  /* USER CODE END USB_LP_CAN1_RX0_IRQn 1 */
+}
+
+void USB_HP_CAN1_TX_IRQHandler(void)
+{
+  /* USER CODE BEGIN USB_HP_CAN1_TX_IRQn 0 */
+
+  /* USER CODE END USB_HP_CAN1_TX_IRQn 0 */
+  HAL_CAN_IRQHandler(&hcan);
+  /* USER CODE BEGIN USB_HP_CAN1_TX_IRQn 1 */
+
+  /* USER CODE END USB_HP_CAN1_TX_IRQn 1 */
+}
+
+void usb_disconnect(void)
+{
+  HAL_PCD_DevDisconnect(&PCDHandle);
+}
+
+void usb_connect(void)
+{
+  HAL_PCD_DevConnect(&PCDHandle);
+}