diff --git a/f4/can/include/can.h b/f4/can/include/can.h new file mode 100644 index 0000000000000000000000000000000000000000..c5c8b91af398736415ce3be4a82011fde5d33a79 --- /dev/null +++ b/f4/can/include/can.h @@ -0,0 +1,104 @@ +#ifndef CAN_F4_H +#define CAN_F4_H + +#include "stm32f4xx_hal.h" +#include "comm.h" + +typedef struct +{ + unsigned char irq_priority; + unsigned char irq_subpriority; +}TCAN_IRQ_Priorities; + +typedef enum +{ + CAN_10KBPS, + CAN_20KBPS, + CAN_50KBPS, + CAN_83K3BPS, + CAN_100KBPS, + CAN_125KBPS, + CAN_250KBPS, + CAN_500KBPS, + CAN_1000KBPS +} CAN_SPEED; + +typedef enum +{ + VERSION_1, + VERSION_2, + VERSION_NULL +} DynamixelVersion; + +typedef struct TDynamixelMessage +{ + unsigned char received_bytes; +/** + * \brief + * + */ + unsigned char rx_buffer[MAX_DYN_SLAVE_RX_BUFFER_LEN]; +/** + * \brief + * + */ + unsigned char Len_L; +/** + * \brief + * + */ + unsigned char Len_H; +/** + * \brief + * + */ + unsigned int length; +/** + * \brief + * + */ + DynamixelVersion version; +/** + * \brief + * + */ + unsigned char packet_init; +/** + * \brief + * + */ + unsigned char packet_incomplete; +/** + * \brief + * + */ + unsigned char send_packet; +/** + * \brief + * + */ + unsigned char iterations; +/** + * \brief + * + */ +}TDynamixelMessage; + +/* 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,CAN_SPEED bitrate); +void can_set_filter(TComm *comm_dev,CAN_FilterTypeDef *filter); +void can_set_can_id(TComm *comm_dev,unsigned int id); +/* 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); +/* DMA functions */ +unsigned char can_send_dma(unsigned char *data,unsigned short int length); +unsigned char can_receive_dma(unsigned char *data,unsigned short int length); +unsigned char can_cancel_receive_dma(void); + +#endif diff --git a/f4/can/include/can_common.h b/f4/can/include/can_common.h new file mode 100644 index 0000000000000000000000000000000000000000..f7eabaff39d5986f886369ab1df4663a2b8ff2ad --- /dev/null +++ b/f4/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/f4/can/src/can.c b/f4/can/src/can.c new file mode 100644 index 0000000000000000000000000000000000000000..d8eb65395df2498e0c04f794fc8d7341d9fa1ea8 --- /dev/null +++ b/f4/can/src/can.c @@ -0,0 +1,442 @@ +#include "can.h" + +#define CAN CAN1 +#define CAN_ENABLE_CLK __HAL_RCC_CAN1_CLK_ENABLE() +#define CAN_IRQnRX CAN1_RX0_IRQn +#define CAN_IRQnTX CAN1_TX_IRQn + +#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; +CAN_FilterTypeDef CANFilterConfig; +CAN_TxHeaderTypeDef CAN_txHeader; +uint8_t *CAN_txMessage; +uint32_t TxMailbox; +CAN_RxHeaderTypeDef CAN_rxHeader; +uint8_t CAN_rxMessage[8]; + +TComm *can_comm_dev; +unsigned char can_dma_phase; +unsigned char *can_dma_phase_data; +unsigned short int can_dma_phase_length; +unsigned short int can_dma_phase_write_ptr; + +unsigned char can_missing_bytes_data[255]; +unsigned short int can_missing_bytes_length; +unsigned short int can_missing_bytes_write_ptr; + +unsigned short int can_send_lenght; +unsigned short int can_send_iterations; +unsigned char can_send_data[255]; + +TDynamixelMessage message; + +void can_init(TComm *comm_dev,CAN_InitTypeDef *conf,TCAN_IRQ_Priorities *priorities) +{ + CANHandle.Instance = CAN; + can_config(comm_dev,conf); + + 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_TX_PIN|CAN_RX_PIN; + GPIO_InitStructure.Mode = GPIO_MODE_AF_PP; + GPIO_InitStructure.Pull = GPIO_NOPULL; + GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStructure.Alternate = GPIO_AF9_CAN1; + HAL_GPIO_Init(CAN_TX_GPIO_PORT, &GPIO_InitStructure); + + can_set_priorities(comm_dev,priorities); + + HAL_CAN_Init(&CANHandle); + + /* 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; + if(comm_dev->use_dma) + { + comm_dev->send_dma=can_send_dma; + comm_dev->receive_dma=can_receive_dma; + comm_dev->cancel_receive_dma=can_cancel_receive_dma; + } + 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; + + can_dma_phase=0x00; + can_dma_phase_data=0x00; + can_dma_phase_length=0; + can_dma_phase_write_ptr=0; + can_missing_bytes_length = 0; + can_missing_bytes_write_ptr = 0; + can_send_lenght = 0; + can_send_iterations = 0; + + message.packet_init = 0x00; + message.packet_incomplete = 0x00; + message.send_packet = 0x00; + message.iterations = 0; + /////////////////////////////////////////////////////////////////////////// + //default tx message Configuration + CAN_txHeader.DLC = 1; + CAN_txHeader.IDE = CAN_ID_STD; + CAN_txHeader.RTR = CAN_RTR_DATA; + CAN_txHeader.StdId = 0x00; + CAN_txHeader.ExtId = 0x01; + //default configration for the filer -> none + CANFilterConfig.FilterBank = 0; + CANFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK; + CANFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; + CANFilterConfig.FilterIdHigh = 0x0000; + CANFilterConfig.FilterIdLow = 0x0000; + CANFilterConfig.FilterMaskIdHigh = 0x0000; + CANFilterConfig.FilterMaskIdLow = 0x0000; + CANFilterConfig.FilterFIFOAssignment = 0; + CANFilterConfig.FilterActivation = ENABLE; + CANFilterConfig.SlaveStartFilterBank = 0; + //configure the filter + HAL_CAN_ConfigFilter(&CANHandle, &CANFilterConfig); + //start the can device + HAL_CAN_Start(&CANHandle); + //Activate default interrupt when message in FIFO0 + HAL_CAN_ActivateNotification(&CANHandle, CAN_IT_RX_FIFO0_MSG_PENDING); +} + +void can_config(TComm *comm_dev,CAN_InitTypeDef *conf) +{ + CANHandle.Init.Prescaler = conf->Prescaler; + CANHandle.Init.Mode = conf->Mode; + CANHandle.Init.SyncJumpWidth = conf->SyncJumpWidth; + CANHandle.Init.TimeSeg1 = conf->TimeSeg1; + CANHandle.Init.TimeSeg2 = conf->TimeSeg2; + CANHandle.Init.TimeTriggeredMode = conf->TimeTriggeredMode; + CANHandle.Init.AutoBusOff = conf->AutoBusOff; + CANHandle.Init.AutoWakeUp = conf->AutoWakeUp; + CANHandle.Init.AutoRetransmission = conf->AutoRetransmission; + CANHandle.Init.ReceiveFifoLocked = conf->ReceiveFifoLocked; + CANHandle.Init.TransmitFifoPriority = conf->TransmitFifoPriority; +} + +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); +} + +// This only works on APB1 clock of 42Mhz +void can_set_bitrate(TComm *comm_dev,CAN_SPEED bitrate) +{ + switch (bitrate) { + case CAN_10KBPS: + CANHandle.Init.Prescaler = 280; + CANHandle.Init.TimeSeg1 = CAN_BS1_12TQ; + CANHandle.Init.TimeSeg2 = CAN_BS2_2TQ; + CANHandle.Init.SyncJumpWidth = CAN_SJW_1TQ; + break; + case CAN_20KBPS: + CANHandle.Init.Prescaler = 140; + CANHandle.Init.TimeSeg1 = CAN_BS1_12TQ; + CANHandle.Init.TimeSeg2 = CAN_BS2_2TQ; + CANHandle.Init.SyncJumpWidth = CAN_SJW_1TQ; + break; + case CAN_50KBPS: + CANHandle.Init.Prescaler = 56; + CANHandle.Init.TimeSeg1 = CAN_BS1_12TQ; + CANHandle.Init.TimeSeg2 = CAN_BS2_2TQ; + CANHandle.Init.SyncJumpWidth = CAN_SJW_1TQ; + break; + case CAN_83K3BPS: + CANHandle.Init.Prescaler = 28; + CANHandle.Init.TimeSeg1 = CAN_BS1_15TQ; + CANHandle.Init.TimeSeg2 = CAN_BS2_2TQ; + CANHandle.Init.SyncJumpWidth = CAN_SJW_1TQ; + break; + case CAN_100KBPS: + CANHandle.Init.Prescaler = 28; + CANHandle.Init.TimeSeg1 = CAN_BS1_12TQ; + CANHandle.Init.TimeSeg2 = CAN_BS2_2TQ; + CANHandle.Init.SyncJumpWidth = CAN_SJW_1TQ; + break; + case CAN_125KBPS: + CANHandle.Init.Prescaler = 21; + CANHandle.Init.TimeSeg1 = CAN_BS1_13TQ; + CANHandle.Init.TimeSeg2 = CAN_BS2_2TQ; + CANHandle.Init.SyncJumpWidth = CAN_SJW_1TQ; + break; + case CAN_250KBPS: + CANHandle.Init.Prescaler = 12; + CANHandle.Init.TimeSeg1 = CAN_BS1_11TQ; + CANHandle.Init.TimeSeg2 = CAN_BS2_2TQ; + CANHandle.Init.SyncJumpWidth = CAN_SJW_1TQ; + break; + case CAN_500KBPS: + CANHandle.Init.Prescaler = 6; + CANHandle.Init.TimeSeg1 = CAN_BS1_11TQ; + CANHandle.Init.TimeSeg2 = CAN_BS2_2TQ; + CANHandle.Init.SyncJumpWidth = CAN_SJW_1TQ; + break; + case CAN_1000KBPS: + CANHandle.Init.Prescaler = 3; + CANHandle.Init.TimeSeg1 = CAN_BS1_11TQ; + CANHandle.Init.TimeSeg2 = CAN_BS2_2TQ; + CANHandle.Init.SyncJumpWidth = CAN_SJW_1TQ; + break; + } +} + +void can_set_filter(TComm *comm_dev,CAN_FilterTypeDef *filter) +{ + HAL_CAN_ConfigFilter(&CANHandle, filter); +} + +void can_set_can_id(TComm *comm_dev,unsigned int id) +{ + CAN_txHeader.StdId = id; + //CANHandle.pTxMsg->StdId = id; +} + +/** + * HAL_CAN_ErrorCallback + * Callback function for CAN errors. + * @param CANHandle Pointer to a CAN_HandleTypeDef structure that contains + * the configuration information for a given CAN peripheral. + */ +void HAL_CAN_ErrorCallback(CAN_HandleTypeDef* CANHandle) +{ + //HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4,GPIO_PIN_SET); +} + + +void HAL_CAN_TxMailbox0CompleteCallback(CAN_HandleTypeDef* CANHandle) +{ + if (can_send_lenght != 0) + { + if (can_send_lenght > 8) + { + CAN_txHeader.DLC = 8; + for (uint8_t i=0;i<8;i++) + { + CAN_txMessage[i] = can_send_data[i+(8*can_send_iterations)]; + //CANHandle->pTxMsg->Data[i] = can_send_data[i+(8*can_send_iterations)]; + } + can_send_lenght = can_send_lenght - 8; + can_send_iterations++; + //HAL_CAN_Transmit_IT(CANHandle); + HAL_CAN_AddTxMessage(CANHandle, &CAN_txHeader, CAN_txMessage, &TxMailbox); + } + else + { + //CANHandle->pTxMsg->DLC = can_send_lenght; + for (uint8_t i=0;i<can_send_lenght;i++) + { + CAN_txMessage[i] = can_send_data[i+(8*can_send_iterations)]; + //CANHandle->pTxMsg->Data[i] = can_send_data[i+(8*can_send_iterations)]; + } + can_send_lenght = 0; + can_send_iterations = 0; + //HAL_CAN_Transmit_IT(CANHandle); + HAL_CAN_AddTxMessage(CANHandle, &CAN_txHeader, CAN_txMessage, &TxMailbox); + uint8_t byte; + comm_do_dma_send(can_comm_dev); + comm_do_irq_send(can_comm_dev,&byte); + } + } +} + +void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef* CANHandle) +{ + HAL_CAN_GetRxMessage(CANHandle, CAN_RX_FIFO0, &CAN_rxHeader, CAN_rxMessage); + if(can_missing_bytes_length == 0){ + for(uint8_t i=0;i<CAN_rxHeader.DLC;i++) + { + if(!can_dma_phase) + { + comm_do_irq_receive(can_comm_dev,CAN_rxMessage[i]); + } + else + { + if(can_dma_phase_length<5){ + can_dma_phase_data[can_dma_phase_write_ptr]=CAN_rxMessage[i]; + can_dma_phase_length--; + can_dma_phase_write_ptr++; + if(can_dma_phase_length==0){ + comm_do_dma_receive(can_comm_dev); + } + } + } + } + if(can_dma_phase_length>4){ + for(uint8_t i=0;i<CAN_rxHeader.DLC;i++) + can_missing_bytes_data[i] = CAN_rxMessage[i]; + can_missing_bytes_length = can_dma_phase_length-4; + can_missing_bytes_write_ptr = 7; + } + } + else + { + if(can_missing_bytes_length<=8){ + for(uint8_t i=0;i<CAN_rxHeader.DLC;i++) + { + can_missing_bytes_write_ptr++; + can_missing_bytes_length--; + can_missing_bytes_data[can_missing_bytes_write_ptr] = CAN_rxMessage[i]; + } + for(uint8_t i=0;i<=can_missing_bytes_write_ptr;i++) + { + if(!can_dma_phase) + comm_do_irq_receive(can_comm_dev,can_missing_bytes_data[i]); + else + { + can_dma_phase_data[can_dma_phase_write_ptr]=can_missing_bytes_data[i]; + can_dma_phase_length--; + can_dma_phase_write_ptr++; + if(can_dma_phase_length==0){ + comm_do_dma_receive(can_comm_dev); + can_missing_bytes_length = 0; + can_missing_bytes_write_ptr = 0; + } + } + } + } + else + { + for(uint8_t i=0;i<CAN_rxHeader.DLC;i++) + { + can_missing_bytes_write_ptr++; + can_missing_bytes_length--; + can_missing_bytes_data[can_missing_bytes_write_ptr] = CAN_rxMessage[i]; + } + } + } +} + +// interrupt handlers +void CAN1_RX0_IRQHandler(void) +{ + /* USER CODE BEGIN USB_LP_CAN1_RX0_IRQn 0 */ + + /* USER CODE END USB_LP_CAN1_RX0_IRQn 0 */ + HAL_CAN_IRQHandler(&CANHandle); + /* USER CODE BEGIN USB_LP_CAN1_RX0_IRQn 1 */ + + /* USER CODE END USB_LP_CAN1_RX0_IRQn 1 */ +} + +void 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(&CANHandle); + /* USER CODE BEGIN USB_HP_CAN1_TX_IRQn 1 */ + + /* USER CODE END USB_HP_CAN1_TX_IRQn 1 */ +} + +unsigned char can_send_irq(unsigned char first_byte) +{ + return 0x00; +} + +unsigned char can_enable_tx_irq(void) +{ + return 0x00; +} + +unsigned char can_receive_irq(void) +{ + can_dma_phase=0x00; + can_dma_phase_write_ptr=0x00; + //HAL_CAN_Receive_IT(&CANHandle,CAN_FIFO0); + HAL_CAN_GetRxMessage(&CANHandle, CAN_RX_FIFO0, &CAN_rxHeader, CAN_rxMessage); + return 0x00; +} + +unsigned char can_cancel_receive_irq(void) +{ + return 0x00; +} + +/* DMA functions */ +unsigned char can_send_dma(unsigned char *data,unsigned short int length) +{ + __HAL_CAN_CLEAR_FLAG(&CANHandle,CAN_FLAG_RQCP0); + __HAL_CAN_CLEAR_FLAG(&CANHandle,CAN_FLAG_TXOK0); + if(length > 8){ + CAN_txHeader.DLC = 8; + for (uint8_t i=0;i<length;i++) + { + can_send_data[i] = data[i]; + } + can_send_lenght = length - 8; + can_send_iterations = 1; + // for (uint8_t i=0;i<8;i++) + // { + // CANHandle.pTxMsg->Data[i] = data[i]; + // } + //HAL_CAN_Transmit_IT(&CANHandle); + HAL_CAN_AddTxMessage(&CANHandle, &CAN_txHeader, data, &TxMailbox); + } + else{ + CAN_txHeader.DLC = length; + // for (uint8_t i=0;i<length;i++) + // { + // CANHandle.pTxMsg->Data[i] = data[i]; + // } + can_send_lenght = 0; + can_send_iterations = 0; + //HAL_CAN_Transmit_IT(&CANHandle); + HAL_CAN_AddTxMessage(&CANHandle, &CAN_txHeader, data, &TxMailbox); + uint8_t byte; + comm_do_dma_send(can_comm_dev); + comm_do_irq_send(can_comm_dev,&byte); + } + return 0x00; +} + +unsigned char can_receive_dma(unsigned char *data,unsigned short int length) +{ + can_dma_phase=0x01; + can_dma_phase_data=data; + can_dma_phase_length=length; + can_dma_phase_write_ptr=0; + + return 0x00; +} + +unsigned char can_cancel_receive_dma(void) +{ + can_dma_phase=0x00; + can_dma_phase_data=0x00; + can_dma_phase_length=0; + can_dma_phase_write_ptr=0; + //can_missing_bytes_length=0; + //can_missing_bytes_write_ptr=0; + + return 0x00; +}