├── Additional Drivers ├── CAN │ ├── CAN.c │ ├── CAN.h │ └── CAN_Defines.h ├── Console │ ├── Console.c │ └── Console.h └── GPIO │ ├── GPIO.c │ └── GPIO.h ├── Application Code ├── main.c └── main.h ├── ODrive ├── ODrive.c └── ODrive.h ├── ODrive_CAN_Test.zip └── README.md /Additional Drivers/CAN/CAN.c: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | #include "CAN.h" 5 | 6 | 7 | /* 8 | * @func : CAN_Init 9 | * @rev : 1 10 | * @Comment : None 11 | * @input param : mailbox 12 | * @output param : none 13 | * @operation : Configures the CAN controller as per the CAN_Config struct. 14 | * Take a look at the examples and the CAN_Config structure for 15 | * more information 16 | */ 17 | int CAN_Init(CAN_Init_Typedef *init) 18 | { 19 | RCC -> APB1ENR &= ~RCC_APB1ENR_CAN1EN; 20 | GPIO_Pin_Setup(GPIOA, 12, ALTERNATE_FUNCTION_OUTPUT_PUSHPULL, 9); 21 | GPIO_Pin_Setup(GPIOA, 11, ALTERNATE_FUNCTION_OUTPUT_PUSHPULL, 9); 22 | RCC -> APB1ENR |= RCC_APB1ENR_CAN1EN; 23 | 24 | 25 | init -> CAN_INSTANCE -> MCR |= CAN_MCR_INRQ; 26 | init -> CAN_INSTANCE -> MCR |= CAN_MCR_NART; 27 | init -> CAN_INSTANCE -> IER |= init -> interrupt; 28 | init -> CAN_INSTANCE -> BTR = init -> baudrate; 29 | 30 | return 1; 31 | } 32 | 33 | int CAN_Filter_Init(CAN_Init_Typedef *init, CAN_Filter_TypeDef *filter) 34 | { 35 | uint32_t can_id = 0; 36 | init -> CAN_INSTANCE -> FMR |= CAN_FMR_FINIT; 37 | 38 | if(filter->filter_id > 13) 39 | { 40 | return -1; 41 | } 42 | else 43 | { 44 | // ID INFORMATION 45 | if(filter -> id_type == CAN_ID_Standard) 46 | { 47 | can_id = (filter->ID << 21) | 0; 48 | } 49 | else 50 | { 51 | can_id = (filter->ID << 3) | 4; 52 | } 53 | 54 | if(filter -> frame_type == CAN_Frame_Remote) 55 | { 56 | can_id |= 2; 57 | } 58 | 59 | init -> CAN_INSTANCE -> FA1R &= ~(1 << filter -> filter_id); 60 | 61 | init -> CAN_INSTANCE -> FS1R |= (1 << filter -> filter_id); 62 | 63 | init -> CAN_INSTANCE -> sFilterRegister[filter->filter_id].FR1 = can_id; 64 | init -> CAN_INSTANCE -> sFilterRegister[filter->filter_id].FR2 = can_id; 65 | 66 | init -> CAN_INSTANCE -> FFA1R &= ~(1 << filter->filter_id); 67 | init -> CAN_INSTANCE -> FA1R |= (1 << filter->filter_id); 68 | 69 | init -> CAN_INSTANCE -> FMR &= ~CAN_FMR_FINIT; 70 | 71 | } 72 | return 1; 73 | } 74 | 75 | void CAN_Start(CAN_Init_Typedef *init) 76 | { 77 | init -> CAN_INSTANCE -> MCR &= ~CAN_MCR_SLEEP; 78 | init -> CAN_INSTANCE -> MCR &= ~CAN_MCR_INRQ; 79 | while((init -> CAN_INSTANCE -> MSR & CAN_MSR_SLAK)){} 80 | while((init -> CAN_INSTANCE ->MSR & CAN_MSR_INAK)); 81 | } 82 | 83 | void CAN_Send_Packet(CAN_Init_Typedef *init, CAN_TX_Typedef *tx) 84 | { 85 | init -> CAN_INSTANCE -> sTxMailBox[0].TDHR &= ~0xFFFFFFFF; 86 | init -> CAN_INSTANCE -> sTxMailBox[0].TDLR &= ~0xFFFFFFFF; 87 | init -> CAN_INSTANCE -> sTxMailBox[0].TDTR &= ~0xFFFFFFFF; 88 | init -> CAN_INSTANCE -> sTxMailBox[0].TIR &= ~0xFFFFFFFF; 89 | //--------------------------------------------------------------------------------------------------------------------- 90 | switch (tx->id_type) 91 | { 92 | case CAN_ID_Standard: 93 | { 94 | init -> CAN_INSTANCE -> sTxMailBox[0].TIR = tx->ID << 21; 95 | init -> CAN_INSTANCE -> sTxMailBox[0].TIR &= ~1 << 2; 96 | } 97 | break; 98 | case CAN_ID_Extended: 99 | { 100 | init -> CAN_INSTANCE -> sTxMailBox[0].TIR = tx->ID << 3; 101 | init -> CAN_INSTANCE -> sTxMailBox[0].TIR |= 1 << 2; 102 | } 103 | break; 104 | } 105 | //--------------------------------------------------------------------------------------------------------------------- 106 | switch (tx->frame_type) 107 | { 108 | case CAN_Frame_Data: 109 | { 110 | init -> CAN_INSTANCE -> sTxMailBox[0].TIR &= ~(1 << 1); 111 | } 112 | break; 113 | case CAN_Frame_Remote: 114 | { 115 | init -> CAN_INSTANCE -> sTxMailBox[0].TIR |= (1 << 1); 116 | } 117 | break; 118 | } 119 | //--------------------------------------------------------------------------------------------------------------------- 120 | init -> CAN_INSTANCE -> sTxMailBox[0].TDTR = tx->data_length; 121 | init -> CAN_INSTANCE -> sTxMailBox[0].TDTR &= ~CAN_TDT0R_TGT; 122 | init -> CAN_INSTANCE -> sTxMailBox[0].TDHR = tx->data[7] << 24 | tx->data[6] << 16 | tx->data[5] << 8 | tx->data[4] << 0; 123 | init -> CAN_INSTANCE -> sTxMailBox[0].TDLR = tx->data[3] << 24 | tx->data[2] << 16 | tx->data[1] << 8 | tx->data[0] << 0; 124 | init -> CAN_INSTANCE -> sTxMailBox[0].TIR |= (1 << 0); 125 | while(init -> CAN_INSTANCE -> sTxMailBox[0].TIR & (1 << 0)){} 126 | 127 | } 128 | 129 | void CAN_Get_Packet(CAN_Init_Typedef *init, CAN_RX_Typedef *rx) 130 | { 131 | 132 | 133 | int frame_type = 0; 134 | int id_type = 0; 135 | 136 | 137 | 138 | id_type = (CAN1 -> sFIFOMailBox[0].RIR & CAN_RI0R_IDE_Msk) >> CAN_RI0R_IDE_Pos ; 139 | frame_type = (CAN1 -> sFIFOMailBox[0].RIR & CAN_RI0R_RTR_Msk) >> CAN_RI0R_RTR_Pos ; 140 | 141 | if(id_type) 142 | { 143 | //Extended ID 144 | rx->id_type = CAN_ID_Extended; 145 | rx->ID = (init -> CAN_INSTANCE -> sFIFOMailBox[0].RIR & CAN_RI0R_EXID_Msk) >> CAN_RI0R_EXID_Pos; 146 | } 147 | else 148 | { 149 | //Standard ID 150 | rx->id_type = CAN_ID_Standard; 151 | rx->ID = (init -> CAN_INSTANCE -> sFIFOMailBox[0].RIR & CAN_RI0R_STID_Msk) >> CAN_RI0R_STID_Pos; 152 | } 153 | 154 | if(frame_type) 155 | { 156 | //RTR Frame 157 | rx->frame_type = CAN_Frame_Remote; 158 | rx->data_length = (init -> CAN_INSTANCE -> sFIFOMailBox[0].RDTR & CAN_RDT0R_DLC_Msk) >> CAN_RDT0R_DLC_Pos; 159 | init -> CAN_INSTANCE -> RF0R |= CAN_RF0R_RFOM0; 160 | while((init -> CAN_INSTANCE -> RF0R & CAN_RF0R_RFOM0)){} 161 | } 162 | else 163 | { 164 | //Data Frame 165 | rx->frame_type = CAN_Frame_Data; 166 | rx->data_length = (init -> CAN_INSTANCE -> sFIFOMailBox[0].RDTR & CAN_RDT0R_DLC_Msk) >> CAN_RDT0R_DLC_Pos; 167 | for(int i = 0; i < rx->data_length; i++) 168 | { 169 | if(i < 4) 170 | { 171 | rx->data[i] = (init -> CAN_INSTANCE -> sFIFOMailBox[0].RDLR & ( 0xFF << (8*i))) >> (8*i); 172 | } 173 | else 174 | { 175 | rx->data[i] = (init -> CAN_INSTANCE -> sFIFOMailBox[0].RDHR & ( 0xFF << (8*(i-4)))) >> (8*(i-4)); 176 | } 177 | } 178 | 179 | init -> CAN_INSTANCE -> RF0R |= CAN_RF0R_RFOM0; } 180 | 181 | 182 | } 183 | -------------------------------------------------------------------------------- /Additional Drivers/CAN/CAN.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef CAN_H_ 3 | #define CAN_H_ 4 | 5 | #include "main.h" 6 | #include "GPIO.h" 7 | #include "CAN_defines.h" 8 | 9 | #define Transmit_Mailbox_Empty CAN_IER_TMEIE 10 | #define Fifo0_Message_Pending CAN_IER_FMPIE0 11 | #define Fifo1_Message_Pending CAN_IER_FMPIE1 12 | #define Fifo0_Full CAN_IER_FFIE0 13 | #define Fifo1_Full CAN_IER_FFIE1 14 | #define Fifo0_Overflow CAN_IER_FOVIE0 15 | #define Fifo1_Overflow CAN_IER_FOVIE1 16 | 17 | typedef struct CAN_RX_Typedef 18 | { 19 | int message_timestamp; 20 | int data_length; 21 | int data[8]; 22 | int filter_index; 23 | int frame_type; 24 | int id_type; 25 | int32_t ID; 26 | }CAN_RX_Typedef; 27 | 28 | typedef struct CAN_Filter_TypeDef{ 29 | int filter_id; 30 | int enable; 31 | int id_type; 32 | int frame_type; 33 | 34 | 35 | int type; 36 | int scale; 37 | int bank_id; 38 | uint32_t ID; 39 | }CAN_Filter_TypeDef; 40 | 41 | typedef struct CAN_TX_Typedef{ 42 | int id_type; 43 | int frame_type; 44 | int send_timestamp; 45 | int32_t ID; 46 | int data_length; 47 | int data[8]; 48 | }CAN_TX_Typedef; 49 | 50 | typedef struct CAN_Init_Typedef 51 | { 52 | CAN_TypeDef *CAN_INSTANCE; //CAN1 OR CAN2 53 | int32_t baudrate; 54 | int timestamp_enable; 55 | int interrupt; 56 | }CAN_Init_Typedef; 57 | 58 | 59 | 60 | 61 | int CAN_Init(CAN_Init_Typedef *init); 62 | 63 | int CAN_Filter_Init(CAN_Init_Typedef *init, CAN_Filter_TypeDef *filter); 64 | 65 | void CAN_Start(CAN_Init_Typedef *init); 66 | 67 | void CAN_Send_Packet(CAN_Init_Typedef *init, CAN_TX_Typedef *tx); 68 | 69 | void CAN_Get_Packet(CAN_Init_Typedef *init, CAN_RX_Typedef *rx); 70 | 71 | #endif /* CAN_H_ */ 72 | -------------------------------------------------------------------------------- /Additional Drivers/CAN/CAN_Defines.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef CAN_DEFINES_H_ 3 | #define CAN_DEFINES_H_ 4 | 5 | #include "main.h" 6 | 7 | #define CAN_BAUDRATE_1000_KBPS 0x001a0002 8 | 9 | 10 | #define CAN_BAUDRATE_500_KBPS 0x001a0005 11 | #define CAN_BAUDRATE_250_KBPS 0x001a000b 12 | #define CAN_BAUDRATE_125_KBPS 0x001c0014 13 | #define CAN_BAUDRATE_100_KBPS 0x001b001b 14 | #define CAN_BAUDRATE_50_KBPS 0x001b0037 15 | #define CAN_BAUDRATE_10_KBPS 0x001b0117 16 | 17 | #define CAN_Frame_Data 0 18 | #define CAN_Frame_Remote 10 19 | #define CAN_ID_Standard 0 20 | #define CAN_ID_Extended 10 21 | 22 | #define CAN_FILTER_MASK_MODE 0 23 | #define CAN_FILTER_LIST_MODE 10 24 | 25 | #define CAN_Timestamp_Enable 1 26 | #define CAN_Timestamp_Disable 0 27 | 28 | 29 | #define CAN_Initialization_Mode 0x10 30 | #define CAN_Sleep_Mode 0xEF 31 | #define CAN_Normal_Mode 0x45 32 | 33 | #define CAN_TX_Mailbox_0 0x00 34 | #define CAN_TX_Mailbox_1 0xAA 35 | #define CAN_TX_Mailbox_2 0xFF 36 | 37 | #define CAN_Timestamp_Enable 1 38 | #define CAN_Timestamp_Disable 0 39 | 40 | #define CAN_Filter_Scale_16bit 0 41 | #define CAN_Filter_Scale_32bit 1 42 | 43 | #define CAN_Filter_Bank_FIFO0 0 44 | #define CAN_Filter_Bank_FIFO1 1 45 | 46 | #define CAN_TX_Buffer_0 1 47 | #define CAN_TX_Buffer_1 2 48 | #define CAN_TX_Buffer_2 3 49 | 50 | #define CAN_RX_Buffer_1 4 51 | #define CAN_RX_Buffer_2 5 52 | 53 | 54 | #define CAN_TX_All_Buffers 10 55 | #define CAN_RX_ALL_Buffers 20 56 | 57 | 58 | 59 | 60 | #endif /* CAN_DEFINES_H_ */ 61 | -------------------------------------------------------------------------------- /Additional Drivers/Console/Console.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Console.c 3 | * 4 | * Created on: Nov 17, 2021 5 | * Author: Kunal 6 | */ 7 | 8 | #include "Console.h" 9 | void Console_Init(int baudrate) 10 | { 11 | 12 | RCC -> APB2ENR |= RCC_APB2ENR_USART1EN; 13 | RCC -> AHB1ENR |= RCC_AHB1ENR_GPIOAEN; 14 | GPIOA -> MODER |= ((0xC0 & 0x8C)>>6) << (2 * 9); 15 | GPIOA -> OTYPER |= ((0x30 & 0x8C)>>4) << (1 * 9); 16 | GPIOA -> OSPEEDR |= ((0x0C & 0x8C)>>2) << (2 * 9); 17 | GPIOA -> PUPDR |= ((0x03 & 0x8C)>>0) << (2 * 9); 18 | GPIOA -> AFR[1] |= ( 7 << (4 * (9 - 8))); 19 | USART1 ->CR1 |= USART_CR1_UE; 20 | USART1->BRR |= (int)(84000000 / (16 * baudrate)) << 4; 21 | USART1 ->CR1 |= USART_CR1_TE ; 22 | USART1 ->CR1 |= USART_CR1_RE ; 23 | 24 | } 25 | 26 | 27 | void printConsole(char *msg, ...) 28 | { 29 | 30 | char buff[10000]; 31 | // #ifdef DEBUG_UART 32 | 33 | va_list args; 34 | va_start(args, msg); 35 | vsprintf(buff, msg, args); 36 | 37 | for(int i = 0; i<= strlen(buff)-1; i++) 38 | { 39 | USART1 -> DR = buff[i]; 40 | while (!(USART1->SR & USART_SR_TXE)); 41 | } 42 | 43 | // #endif 44 | } 45 | -------------------------------------------------------------------------------- /Additional Drivers/Console/Console.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Console.h 3 | * 4 | * Created on: Nov 14, 2021 5 | * Author: Kunal 6 | */ 7 | 8 | #ifndef CONSOLE_CONSOLE_H_ 9 | #define CONSOLE_CONSOLE_H_ 10 | 11 | #include "main.h" 12 | 13 | 14 | void Console_Init(int baudrate); 15 | void printConsole(char *msg, ...); 16 | 17 | 18 | #endif /* CONSOLE_CONSOLE_H_ */ 19 | -------------------------------------------------------------------------------- /Additional Drivers/GPIO/GPIO.c: -------------------------------------------------------------------------------- 1 | /* 2 | * GPIO.c 3 | * 4 | * Created on: Nov 17, 2021 5 | * Author: Kunal 6 | */ 7 | 8 | 9 | #include "GPIO.h" 10 | 11 | 12 | void GPIO_Pin_Setup(GPIO_TypeDef *Port, uint8_t pin, uint8_t function, uint8_t alternate_function) 13 | { 14 | if(Port == GPIOA) 15 | { 16 | RCC -> AHB1ENR |= RCC_AHB1ENR_GPIOAEN; 17 | }else if(Port == GPIOB) 18 | { 19 | RCC -> AHB1ENR |= RCC_AHB1ENR_GPIOBEN; 20 | }else if(Port == GPIOC) 21 | { 22 | RCC -> AHB1ENR |= RCC_AHB1ENR_GPIOCEN; 23 | }else if(Port == GPIOD) 24 | { 25 | RCC -> AHB1ENR |= RCC_AHB1ENR_GPIODEN; 26 | }else if(Port == GPIOE) 27 | { 28 | RCC -> AHB1ENR |= RCC_AHB1ENR_GPIOEEN; 29 | } 30 | 31 | Port -> MODER |= ((0xC0 & function)>>6) << (2 * pin); 32 | Port -> OTYPER |= ((0x30 & function)>>4) << (1 * pin); 33 | Port -> OSPEEDR |= ((0x0C & function)>>2) << (2 * pin); 34 | Port -> PUPDR |= ((0x03 & function)>>0) << (2 * pin); 35 | 36 | if(pin < 8)Port -> AFR[0] |= ( alternate_function << (4 * (pin))); 37 | else Port -> AFR[1] |= ( alternate_function << (4 * (pin - 8))); 38 | 39 | if (alternate_function == NONE) {} 40 | } 41 | 42 | void GPIO_Pin_High(GPIO_TypeDef *Port, int pin) 43 | { 44 | Port -> BSRR |= 1 << pin; 45 | } 46 | 47 | 48 | void GPIO_Pin_Low(GPIO_TypeDef *Port, int pin) 49 | { 50 | Port -> BSRR |= GPIO_BSRR_BR0 << pin; 51 | } 52 | 53 | 54 | void GPIO_Interrupt_Setup(int pin, int edge_select) 55 | { 56 | EXTI ->IMR |= 1 << pin; 57 | switch (edge_select) { 58 | case 0: 59 | EXTI ->RTSR |= 1 << pin; 60 | break; 61 | case 1: 62 | EXTI ->FTSR |= 1 << pin; 63 | break; 64 | case 2: 65 | EXTI ->RTSR |= 1 << pin; 66 | EXTI ->FTSR |= 1 << pin; 67 | break; 68 | } 69 | 70 | 71 | } 72 | -------------------------------------------------------------------------------- /Additional Drivers/GPIO/GPIO.h: -------------------------------------------------------------------------------- 1 | /* 2 | * GPIO.h 3 | * 4 | * Created on: Nov 17, 2021 5 | * Author: Kunal 6 | */ 7 | 8 | #ifndef GPIO_GPIO_H_ 9 | #define GPIO_GPIO_H_ 10 | 11 | 12 | #include "main.h" 13 | 14 | #define NONE 0 15 | 16 | //****************************************GENERAL PURPPOSE OUTPUT*************************** 17 | // MODER[7:6] = 01 18 | // OTYPER[5:4] = 00 19 | // OSPEEDR[3:2] = 11 20 | // PUPDR[1:0] = 00 21 | #define GENERAL_PURPOSE_OUTPUT_PUSHPULL 0x4C 22 | // MODER[7:6] = 01 23 | // OTYPER[5:4] = 00 24 | // OSPEEDR[3:2] = 11 25 | // PUPDR[1:0] = 01 26 | #define GENERAL_PURPOSE_OUTPUT_PUSHPULL_PULLUP 0x4D 27 | // MODER[7:6] = 01 28 | // OTYPER[5:4] = 00 29 | // OSPEEDR[3:2] = 11 30 | // PUPDR[1:0] = 10 31 | #define GENERAL_PURPOSE_OUTPUT_PUSHPULL_PULLDW 0x4E 32 | // MODER[7:6] = 01 33 | // OTYPER[5:4] = 01 34 | // OSPEEDR[3:2] = 11 35 | // PUPDR[1:0] = 00 36 | #define GENERAL_PURPOSE_OUTPUT_OPENDRAIN 0x5C 37 | // MODER[7:6] = 01 38 | // OTYPER[5:4] = 01 39 | // OSPEEDR[3:2] = 11 40 | // PUPDR[1:0] = 01 41 | #define GENERAL_PURPOSE_OUTPUT_OPENDRAIN_PULLUP 0x5D 42 | // MODER[7:6] = 01 43 | // OTYPER[5:4] = 01 44 | // OSPEEDR[3:2] = 11 45 | // PUPDR[1:0] = 10 46 | #define GENERAL_PURPOSE_OUTPUT_OPENDRAIN_PULLDW 0x5E 47 | 48 | //****************************************ALTERNATE FUNCTION OUTPUT*************************** 49 | // MODER[7:6] = 10 50 | // OTYPER[5:4] = 00 51 | // OSPEEDR[3:2] = 11 52 | // PUPDR[1:0] = 00 53 | #define ALTERNATE_FUNCTION_OUTPUT_PUSHPULL 0x8C 54 | // MODER[7:6] = 10 55 | // OTYPER[5:4] = 00 56 | // OSPEEDR[3:2] = 11 57 | // PUPDR[1:0] = 01 58 | #define ALTERNATE_FUNCTION_OUTPUT_PUSHPULL_PULLUP 0x8D 59 | // MODER[7:6] = 10 60 | // OTYPER[5:4] = 00 61 | // OSPEEDR[3:2] = 11 62 | // PUPDR[1:0] = 10 63 | #define ALTERNATE_FUNCTION_OUTPUT_PUSHPULL_PULLDW 0x8E 64 | // MODER[7:6] = 10 65 | // OTYPER[5:4] = 01 66 | // OSPEEDR[3:2] = 11 67 | // PUPDR[1:0] = 00 68 | #define ALTERNATE_FUNCTION_OUTPUT_OPENDRAIN 0x9C 69 | // MODER[7:6] = 10 70 | // OTYPER[5:4] = 01 71 | // OSPEEDR[3:2] = 11 72 | // PUPDR[1:0] = 01 73 | #define ALTERNATE_FUNCTION_OUTPUT_OPENDRAIN_PULLUP 0x9D 74 | // MODER[7:6] = 10 75 | // OTYPER[5:4] = 01 76 | // OSPEEDR[3:2] = 11 77 | // PUPDR[1:0] = 10 78 | #define ALTERNATE_FUNCTION_OUTPUT_OPENDRAIN_PULLDW 0x9E 79 | 80 | //****************************************GENERAL PURPPOSE INTPUT*************************** 81 | // MODER[7:6] = 00 82 | // OTYPER[5:4] = 00 83 | // OSPEEDR[3:2] = 00 84 | // PUPDR[1:0] = 00 85 | #define INPUT_FLOATING 0x00 86 | // MODER[7:6] = 00 87 | // OTYPER[5:4] = 00 88 | // OSPEEDR[3:2] = 00 89 | // PUPDR[1:0] = 01 90 | #define INPUT_PULLUP 0x01 91 | // MODER[7:6] = 00 92 | // OTYPER[5:4] = 00 93 | // OSPEEDR[3:2] = 00 94 | // PUPDR[1:0] = 10 95 | #define INPUT_PULLDW 0x02 96 | 97 | /*****************************************ANALOG INPUT*********************************************************/ 98 | // MODER[7:6] = 11 99 | // OTYPER[5:4] = 00 100 | // OSPEEDR[3:2] = 00 101 | // PUPDR[1:0] = 00 102 | #define ANALOG_INPUT 0xC0 103 | 104 | //ALTERNATE FUNCTION 105 | #define MCO_FUNCTION 0 106 | 107 | /***************************************** Timer **************************************************************/ 108 | #define TIM1_BKIN 1 109 | #define TIM1_CH1 1 110 | #define TIM1_CH2 1 111 | #define TIM1_CH3 1 112 | #define TIM1_CH4 1 113 | #define TIM1_CH1N 1 114 | #define TIM1_CH2N 1 115 | #define TIM1_CH3N 1 116 | #define TIM1_CH4N 1 117 | 118 | #define TIM2_CH1 1 119 | #define TIM2_CH2 1 120 | #define TIM2_CH3 1 121 | #define TIM2_CH4 1 122 | 123 | #define TIM3_CH1 2 124 | #define TIM3_CH2 2 125 | #define TIM3_CH3 2 126 | #define TIM3_CH4 2 127 | 128 | #define TIM4_CH1 2 129 | #define TIM4_CH2 2 130 | #define TIM4_CH3 2 131 | #define TIM4_CH4 2 132 | 133 | #define TIM5_CH1 2 134 | #define TIM5_CH2 2 135 | #define TIM5_CH3 2 136 | #define TIM5_CH4 2 137 | 138 | #define TIM8_CH1 3 139 | #define TIM8_CH2 3 140 | #define TIM8_CH3 3 141 | #define TIM8_CH4 3 142 | 143 | #define TIM9_CH1 3 144 | #define TIM9_CH2 3 145 | #define TIM9_CH3 3 146 | #define TIM9_CH4 3 147 | 148 | #define TIM10_CH1 3 149 | #define TIM10_CH2 3 150 | #define TIM10_CH3 3 151 | #define TIM10_CH4 3 152 | 153 | #define TIM11_CH1 3 154 | #define TIM11_CH2 3 155 | #define TIM11_CH3 3 156 | #define TIM11_CH4 3 157 | 158 | #define TIM12_CH1 9 159 | #define TIM12_CH2 9 160 | #define TIM12_CH3 9 161 | #define TIM12_CH4 9 162 | 163 | #define TIM13_CH1 9 164 | #define TIM13_CH2 9 165 | #define TIM13_CH3 9 166 | #define TIM13_CH4 9 167 | 168 | #define TIM14_CH1 14 169 | #define TIM14_CH2 14 170 | #define TIM14_CH3 14 171 | #define TIM14_CH4 14 172 | 173 | /**************************************************************************************************************/ 174 | 175 | /***************************************** I2C **************************************************************/ 176 | #define I2C1_SCL 4 177 | #define I2C1_SDA 4 178 | 179 | #define I2C2_SCL 4 180 | #define I2C2_SDA 4 181 | 182 | #define I2C3_SCL 4 183 | #define I2C3_SDA 9 184 | /**************************************************************************************************************/ 185 | 186 | /***************************************** I2C ****************************************************************/ 187 | #define SPI1_NSS 5 188 | #define SPI1_CLK 5 189 | #define SPI1_MOSI 5 190 | #define SPI1_MISO 5 191 | 192 | #define SPI2_CLK 5 193 | #define SPI2_MOSI 5 194 | #define SPI2_MISO 5 195 | 196 | #define SPI3_CLK 7 197 | #define SPI3_MOSI 6 198 | #define SPI3_MISO 6 199 | /**************************************************************************************************************/ 200 | 201 | /***************************************** I2S ****************************************************************/ 202 | #define I2S1_WS 5 203 | #define I2S1_CK 5 204 | #define I2S1_SD 5 205 | 206 | #define I2S2_WS 4 207 | #define I2S2_CK 7 208 | #define I2S2_SD 6 209 | 210 | #define I2S3_WS 6 211 | #define I2S3_CK 5 212 | #define I2S3_SD 5 213 | /**************************************************************************************************************/ 214 | 215 | /***************************************** I2S ****************************************************************/ 216 | #define USART1_CLK 7 217 | #define USART1_TX 7 218 | #define USART1_RX 7 219 | #define USART1_CTS 7 220 | #define USART1_RTS 7 221 | 222 | #define USART2_CLK 7 223 | #define USART2_TX 7 224 | #define USART2_RX 7 225 | #define USART2_CTS 7 226 | #define USART2_RTS 7 227 | 228 | #define USART3_CLK 7 229 | #define USART3_TX 7 230 | #define USART3_RX 7 231 | #define USART3_CTS 7 232 | #define USART3_RTS 7 233 | 234 | #define USART4_TX 8 235 | #define USART4_RX 8 236 | 237 | #define USART5_TX 8 238 | #define USART5_RX 8 239 | 240 | #define USART6_TX 8 241 | #define USART6_RX 8 242 | /**************************************************************************************************************/ 243 | 244 | /***************************************** SDIO ***************************************************************/ 245 | #define SDIO_CMD 12 246 | #define SDIO_D1 12 247 | #define SDIO_D2 12 248 | #define SDIO_D3 12 249 | #define SDIO_D4 12 250 | #define SDIO_D5 12 251 | #define SDIO_D6 12 252 | #define SDIO_D7 12 253 | /**************************************************************************************************************/ 254 | 255 | #define RISING_EDGE 0 256 | #define FALLING_EDGE 1 257 | #define RISING_FALLING_EDGE 2 258 | 259 | void GPIO_Pin_Setup(GPIO_TypeDef *Port, uint8_t pin, uint8_t function, uint8_t alternate_function); 260 | void GPIO_Pin_High(GPIO_TypeDef *Port, int pin); 261 | void GPIO_Pin_Low(GPIO_TypeDef *Port, int pin); 262 | void GPIO_Interrupt_Setup(int pin, int edge_select); 263 | 264 | 265 | #endif /* GPIO_GPIO_H_ */ 266 | -------------------------------------------------------------------------------- /Application Code/main.c: -------------------------------------------------------------------------------- 1 | 2 | // Example Application Code 3 | 4 | #include "main.h" 5 | #include "Console.h" 6 | #include "CAN.h" 7 | #include "ODrive.h" 8 | 9 | 10 | Axis AXIS0; // Declare Axis Struct Instance 11 | 12 | 13 | void SystemClock_Config(void); 14 | static void MX_GPIO_Init(void); 15 | void CAN1_RX0_IRQHandler(void); 16 | 17 | 18 | 19 | 20 | int main(void) 21 | { 22 | //Init Axis Id and CAN Instance 23 | AXIS0.AXIS_ID = 0x010; 24 | AXIS0.CAN_INSTANCE = CAN1; 25 | 26 | HAL_Init(); 27 | SystemClock_Config(); 28 | MX_GPIO_Init(); 29 | 30 | 31 | //Initialize CAN 32 | CAN_Setup(CAN1, CAN_BAUDRATE_250_KBPS); 33 | HAL_Delay(100); 34 | 35 | 36 | //Example Code 37 | Set_Controller_Modes(AXIS0, VELOCITY_CONTROL, PASSTHROUGH); 38 | Set_Axis_Requested_State(AXIS0, CLOSED_LOOP_CONTROL); 39 | Set_Input_Vel(AXIS0, 2, 0); 40 | HAL_Delay(1000); 41 | Set_Input_Vel(AXIS0, 0, 0); 42 | 43 | 44 | while (1) 45 | { 46 | 47 | } 48 | 49 | } 50 | 51 | 52 | 53 | 54 | 55 | void CAN1_RX0_IRQHandler(void){ 56 | //Callback function to be placed in Interrupt Handler 57 | ODrive_RX_CallBack(&AXIS0); 58 | } 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | /** 73 | * @brief System Clock Configuration 74 | * @retval None 75 | */ 76 | void SystemClock_Config(void) 77 | { 78 | RCC_OscInitTypeDef RCC_OscInitStruct = {0}; 79 | RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; 80 | 81 | /** Configure the main internal regulator output voltage 82 | */ 83 | __HAL_RCC_PWR_CLK_ENABLE(); 84 | __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); 85 | 86 | /** Initializes the RCC Oscillators according to the specified parameters 87 | * in the RCC_OscInitTypeDef structure. 88 | */ 89 | RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; 90 | RCC_OscInitStruct.HSEState = RCC_HSE_ON; 91 | RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; 92 | RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; 93 | RCC_OscInitStruct.PLL.PLLM = 4; 94 | RCC_OscInitStruct.PLL.PLLN = 168; 95 | RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; 96 | RCC_OscInitStruct.PLL.PLLQ = 4; 97 | if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) 98 | { 99 | Error_Handler(); 100 | } 101 | 102 | /** Initializes the CPU, AHB and APB buses clocks 103 | */ 104 | RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK 105 | |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; 106 | RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; 107 | RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; 108 | RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4; 109 | RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2; 110 | 111 | if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK) 112 | { 113 | Error_Handler(); 114 | } 115 | } 116 | 117 | /** 118 | * @brief GPIO Initialization Function 119 | * @param None 120 | * @retval None 121 | */ 122 | static void MX_GPIO_Init(void) 123 | { 124 | 125 | /* GPIO Ports Clock Enable */ 126 | __HAL_RCC_GPIOH_CLK_ENABLE(); 127 | __HAL_RCC_GPIOA_CLK_ENABLE(); 128 | 129 | } 130 | 131 | /* USER CODE BEGIN 4 */ 132 | 133 | /* USER CODE END 4 */ 134 | 135 | /** 136 | * @brief This function is executed in case of error occurrence. 137 | * @retval None 138 | */ 139 | void Error_Handler(void) 140 | { 141 | /* USER CODE BEGIN Error_Handler_Debug */ 142 | /* User can add his own implementation to report the HAL error return state */ 143 | __disable_irq(); 144 | while (1) 145 | { 146 | } 147 | /* USER CODE END Error_Handler_Debug */ 148 | } 149 | 150 | #ifdef USE_FULL_ASSERT 151 | /** 152 | * @brief Reports the name of the source file and the source line number 153 | * where the assert_param error has occurred. 154 | * @param file: pointer to the source file name 155 | * @param line: assert_param error line source number 156 | * @retval None 157 | */ 158 | void assert_failed(uint8_t *file, uint32_t line) 159 | { 160 | /* USER CODE BEGIN 6 */ 161 | /* User can add his own implementation to report the file name and line number, 162 | ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ 163 | /* USER CODE END 6 */ 164 | } 165 | #endif /* USE_FULL_ASSERT */ 166 | 167 | 168 | 169 | 170 | 171 | 172 | -------------------------------------------------------------------------------- /Application Code/main.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef __MAIN_H 3 | #define __MAIN_H 4 | 5 | #ifdef __cplusplus 6 | extern "C" { 7 | #endif 8 | 9 | #include "stm32f4xx_hal.h" 10 | #include 11 | #include "string.h" 12 | #include "stdbool.h" 13 | #include "stdlib.h" 14 | #include "stdarg.h" 15 | #include "stdint.h" 16 | #include "stdlib.h" 17 | #include "stdio.h" 18 | #include "inttypes.h" 19 | #include "math.h" 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | void Error_Handler(void); 28 | 29 | 30 | #ifdef __cplusplus 31 | } 32 | #endif 33 | 34 | #endif /* __MAIN_H */ 35 | -------------------------------------------------------------------------------- /ODrive/ODrive.c: -------------------------------------------------------------------------------- 1 | /* 2 | * ODrive.c 3 | * 4 | * Created on: 07-Jul-2022 5 | * Author: sidiyer27 6 | */ 7 | 8 | 9 | #include "ODrive.h" 10 | 11 | CAN_TX_Typedef TX; 12 | CAN_RX_Typedef RX; 13 | CAN_Filter_TypeDef filter; 14 | CAN_Init_Typedef CAN; 15 | 16 | 17 | void CAN_Setup(CAN_TypeDef *CAN_INSTANCE, int32_t baudrate){ 18 | CAN.CAN_INSTANCE = CAN_INSTANCE; 19 | CAN.baudrate = baudrate; 20 | CAN.interrupt = Fifo0_Message_Pending; 21 | CAN_Init(&CAN); 22 | filter.ID = 0x0; 23 | filter.filter_id = 0; 24 | filter.id_type = CAN_ID_Standard; 25 | filter.frame_type = CAN_Frame_Data; 26 | CAN_Filter_Init(&CAN, &filter); 27 | CAN_Start(&CAN); 28 | __disable_irq(); 29 | HAL_NVIC_SetPriority(CAN1_RX0_IRQn, 0, 0); 30 | HAL_NVIC_EnableIRQ(CAN1_RX0_IRQn); 31 | __enable_irq(); 32 | } 33 | 34 | void Set_TX_Param(int AXIS_ID, int COMMAND_ID, int id_type, int frame_type, int data_length){ 35 | TX.ID = (AXIS_ID << 5) | COMMAND_ID; 36 | TX.id_type = id_type; 37 | TX.frame_type = frame_type; 38 | TX.data_length = data_length; 39 | } 40 | 41 | void Set_Axis_Requested_State(Axis Axis, Axis_State state){ 42 | Set_TX_Param(Axis.AXIS_ID, SET_AXIS_REQUESTED_STATE, CAN_ID_Standard, CAN_Frame_Data, 4); 43 | unsigned int Requested_State = state; 44 | uint8_t *ptrToFloat; 45 | ptrToFloat = (uint8_t *)&Requested_State; 46 | TX.data[0] = ptrToFloat[0]; 47 | TX.data[1] = ptrToFloat[1]; 48 | TX.data[2] = ptrToFloat[2]; 49 | TX.data[3] = ptrToFloat[3]; 50 | CAN_Send_Packet(&CAN, &TX); 51 | } 52 | 53 | void Set_Input_Vel(Axis Axis, float vel, float torqueff){ 54 | Set_TX_Param(Axis.AXIS_ID, SET_INPUT_VEL, CAN_ID_Standard, CAN_Frame_Data, 8); 55 | uint8_t *ptrVel; 56 | ptrVel = (uint8_t *)&vel; 57 | uint8_t *ptrTor; 58 | ptrTor = (uint8_t *)&torqueff; 59 | TX.data[0] = ptrVel[0]; 60 | TX.data[1] = ptrVel[1]; 61 | TX.data[2] = ptrVel[2]; 62 | TX.data[3] = ptrVel[3]; 63 | TX.data[4] = ptrTor[0]; 64 | TX.data[5] = ptrTor[1]; 65 | TX.data[6] = ptrTor[2]; 66 | TX.data[7] = ptrTor[3]; 67 | CAN_Send_Packet(&CAN, &TX); 68 | } 69 | 70 | void Clear_Errors(Axis Axis){ 71 | Set_TX_Param(Axis.AXIS_ID, CLEAR_ERRORS, CAN_ID_Standard, CAN_Frame_Data, 0); 72 | CAN_Send_Packet(&CAN, &TX); 73 | } 74 | 75 | void Reboot_ODrive(Axis Axis){ 76 | Set_TX_Param(Axis.AXIS_ID, REBOOT_ODRIVE, CAN_ID_Standard, CAN_Frame_Data, 0); 77 | CAN_Send_Packet(&CAN, &TX); 78 | } 79 | 80 | void Set_Controller_Modes(Axis Axis, Control_Mode ControlMode, Input_Mode InputMode){ 81 | Set_TX_Param(Axis.AXIS_ID, SET_CONTROLLER_MODES, CAN_ID_Standard, CAN_Frame_Data, 8); 82 | int Control = ControlMode; 83 | int Input = InputMode; 84 | uint8_t *ptrControl; 85 | ptrControl = (uint8_t *)&Control; 86 | uint8_t *ptrInput; 87 | ptrInput = (uint8_t *)&Input; 88 | TX.data[0] = ptrControl[0]; 89 | TX.data[1] = ptrControl[1]; 90 | TX.data[2] = ptrControl[2]; 91 | TX.data[3] = ptrControl[3]; 92 | TX.data[4] = ptrInput[0]; 93 | TX.data[5] = ptrInput[1]; 94 | TX.data[6] = ptrInput[2]; 95 | TX.data[7] = ptrInput[3]; 96 | CAN_Send_Packet(&CAN, &TX); 97 | } 98 | 99 | void Set_Input_Pos(Axis Axis, float Input_Pos, int Vel_FF, int Torque_FF){ 100 | Set_TX_Param(Axis.AXIS_ID, SET_INPUT_POS, CAN_ID_Standard, CAN_Frame_Data, 8); 101 | uint8_t *ptrPos; 102 | ptrPos = (uint8_t *)&Input_Pos; 103 | uint8_t *ptrVel; 104 | ptrVel = (uint8_t *)&Vel_FF; 105 | uint8_t *ptrTor; 106 | ptrTor = (uint8_t *)&Torque_FF; 107 | TX.data[0] = ptrPos[0]; 108 | TX.data[1] = ptrPos[1]; 109 | TX.data[2] = ptrPos[2]; 110 | TX.data[3] = ptrPos[3]; 111 | TX.data[4] = ptrVel[0]; 112 | TX.data[5] = ptrVel[1]; 113 | TX.data[6] = ptrTor[0]; 114 | TX.data[7] = ptrTor[1]; 115 | CAN_Send_Packet(&CAN, &TX); 116 | } 117 | 118 | void Get_Encoder_Count(Axis Axis){ 119 | Set_TX_Param(Axis.AXIS_ID, GET_ENCODER_COUNT, CAN_ID_Standard, CAN_Frame_Remote, 0); 120 | CAN_Send_Packet(&CAN, &TX); 121 | } 122 | 123 | void Set_Input_Torque(Axis Axis, float torque){ 124 | Set_TX_Param(Axis.AXIS_ID, SET_INPUT_TORQUE, CAN_ID_Standard, CAN_Frame_Data, 4); 125 | uint8_t *ptrTor; 126 | ptrTor = (uint8_t *)&torque; 127 | TX.data[0] = ptrTor[0]; 128 | TX.data[1] = ptrTor[1]; 129 | TX.data[2] = ptrTor[2]; 130 | TX.data[3] = ptrTor[3]; 131 | CAN_Send_Packet(&CAN, &TX); 132 | } 133 | 134 | void Get_Bus_Voltage_Current(Axis Axis){ 135 | Set_TX_Param(Axis.AXIS_ID, GET_BUS_VOLTAGE_CURRENT, CAN_ID_Standard, CAN_Frame_Remote, 0); 136 | CAN_Send_Packet(&CAN, &TX); 137 | } 138 | 139 | void Get_IQ(Axis Axis){ 140 | Set_TX_Param(Axis.AXIS_ID, GET_IQ, CAN_ID_Standard, CAN_Frame_Remote, 0); 141 | CAN_Send_Packet(&CAN, &TX); 142 | } 143 | 144 | void Set_Position_Gain(Axis Axis, float pos_gain){ 145 | Set_TX_Param(Axis.AXIS_ID, SET_POSITION_GAIN, CAN_ID_Standard, CAN_Frame_Data, 4); 146 | uint8_t *ptrPos; 147 | ptrPos = (uint8_t *)&pos_gain; 148 | TX.data[0] = ptrPos[0]; 149 | TX.data[1] = ptrPos[1]; 150 | TX.data[2] = ptrPos[2]; 151 | TX.data[3] = ptrPos[3]; 152 | CAN_Send_Packet(&CAN, &TX); 153 | } 154 | 155 | void Set_Vel_Gains(Axis Axis, float Vel_Gain, float Vel_Int_Gain){ 156 | Set_TX_Param(Axis.AXIS_ID, SET_VEL_GAINS, CAN_ID_Standard, CAN_Frame_Data, 8); 157 | uint8_t *ptrVelGain; 158 | ptrVelGain = (uint8_t *)&Vel_Gain; 159 | uint8_t *ptrVelIntGain; 160 | ptrVelIntGain = (uint8_t *)&Vel_Int_Gain; 161 | TX.data[0] = ptrVelGain[0]; 162 | TX.data[1] = ptrVelGain[1]; 163 | TX.data[2] = ptrVelGain[2]; 164 | TX.data[3] = ptrVelGain[3]; 165 | TX.data[4] = ptrVelIntGain[0]; 166 | TX.data[5] = ptrVelIntGain[1]; 167 | TX.data[6] = ptrVelIntGain[2]; 168 | TX.data[7] = ptrVelIntGain[3]; 169 | CAN_Send_Packet(&CAN, &TX); 170 | } 171 | 172 | void Set_Axis_Node_ID(Axis Axis, uint32_t node_id){ 173 | Set_TX_Param(Axis.AXIS_ID, SET_AXIS_NODE_ID, CAN_ID_Standard, CAN_Frame_Data, 4); 174 | uint8_t *ptrNodeId; 175 | ptrNodeId = (uint8_t *)&node_id; 176 | TX.data[0] = ptrNodeId[0]; 177 | TX.data[1] = ptrNodeId[1]; 178 | TX.data[2] = ptrNodeId[2]; 179 | TX.data[3] = ptrNodeId[3]; 180 | CAN_Send_Packet(&CAN, &TX); 181 | } 182 | 183 | void Set_Limits(Axis Axis, float vel_lim, float curr_lim){ 184 | Set_TX_Param(Axis.AXIS_ID, SET_LIMITS, CAN_ID_Standard, CAN_Frame_Data, 8); 185 | uint8_t *ptrVelLim; 186 | ptrVelLim = (uint8_t *)&vel_lim; 187 | uint8_t *ptrCurrLim; 188 | ptrCurrLim = (uint8_t *)&curr_lim; 189 | TX.data[0] = ptrVelLim[0]; 190 | TX.data[1] = ptrVelLim[1]; 191 | TX.data[2] = ptrVelLim[2]; 192 | TX.data[3] = ptrVelLim[3]; 193 | TX.data[4] = ptrCurrLim[0]; 194 | TX.data[5] = ptrCurrLim[1]; 195 | TX.data[6] = ptrCurrLim[2]; 196 | TX.data[7] = ptrCurrLim[3]; 197 | CAN_Send_Packet(&CAN, &TX); 198 | 199 | } 200 | 201 | void ODrive_RX_CallBack(Axis *AXIS){ 202 | int32_t ID = 0; 203 | CAN_Get_Packet(&CAN, &RX); 204 | ID = RX.ID; 205 | int32_t NODE_ID = (ID >> 5); 206 | int32_t CMD_ID = (ID & 0x01F); 207 | 208 | 209 | if(NODE_ID == AXIS->AXIS_ID){ 210 | 211 | switch(CMD_ID){ 212 | 213 | case ODRIVE_HEARTBEAT_MESSAGE: 214 | AXIS->AXIS_Error = (RX.data[0] | RX.data[1]<<8 | RX.data[2]<<16 | RX.data[3]<<24); 215 | AXIS->AXIS_Current_State = RX.data[4]; 216 | AXIS->Controller_Status = RX.data[5]; 217 | break; 218 | 219 | 220 | case ENCODER_ESTIMATES: ; 221 | 222 | uint32_t *ptrEncPos; 223 | ptrEncPos = (uint32_t *)&(AXIS->AXIS_Encoder_Pos); 224 | *ptrEncPos = (RX.data[0] + (RX.data[1]<<8) + (RX.data[2]<<16) + (RX.data[3]<<24)); 225 | uint32_t *ptrEncVel; 226 | ptrEncVel = (uint32_t *)&(AXIS->AXIS_Encoder_Vel); 227 | *ptrEncVel = (RX.data[4] + (RX.data[5]<<8) + (RX.data[6]<<16) + (RX.data[7]<<24)); 228 | break; 229 | 230 | case GET_ENCODER_COUNT: 231 | AXIS->AXIS_Encoder_Shadow = (RX.data[0] | RX.data[1]<<8 | RX.data[2]<<16 | RX.data[3]<<24); 232 | AXIS->AXIS_Encoder_CPR = (RX.data[4] | RX.data[5]<<8 | RX.data[6]<<16 | RX.data[7]<<24); 233 | break; 234 | 235 | case GET_BUS_VOLTAGE_CURRENT: ; 236 | 237 | uint32_t *ptrBusV; 238 | ptrBusV = (uint32_t *)&(AXIS->AXIS_Bus_Voltage); 239 | *ptrBusV = (RX.data[0] + (RX.data[1]<<8) + (RX.data[2]<<16) + (RX.data[3]<<24)); 240 | uint32_t *ptrBusI; 241 | ptrBusI = (uint32_t *)&(AXIS->AXIS_Bus_Current); 242 | *ptrBusI = (RX.data[4] + (RX.data[5]<<8) + (RX.data[6]<<16) + (RX.data[7]<<24)); 243 | break; 244 | 245 | 246 | case GET_IQ: ; 247 | 248 | uint32_t *ptrIqSet; 249 | ptrIqSet = (uint32_t *)&(AXIS->AXIS_Iq_Setpoint); 250 | *ptrIqSet = (RX.data[0] + (RX.data[1]<<8) + (RX.data[2]<<16) + (RX.data[3]<<24)); 251 | uint32_t *ptrIqMsr; 252 | ptrIqMsr = (uint32_t *)&(AXIS->AXIS_Iq_Measured); 253 | *ptrIqMsr = (RX.data[4] + (RX.data[5]<<8) + (RX.data[6]<<16) + (RX.data[7]<<24)); 254 | break; 255 | 256 | 257 | } 258 | } 259 | } 260 | -------------------------------------------------------------------------------- /ODrive/ODrive.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ODrive.h 3 | * 4 | * Created on: 07-Jul-2022 5 | * Author: sidiyer27 6 | */ 7 | 8 | #ifndef ODRIVE_ODRIVE_H_ 9 | #define ODRIVE_ODRIVE_H_ 10 | 11 | #include "main.h" 12 | #include "CAN.h" 13 | 14 | 15 | //COMMAND ID 16 | #define ODRIVE_HEARTBEAT_MESSAGE 0x001 17 | #define SET_AXIS_NODE_ID 0x006 18 | #define SET_AXIS_REQUESTED_STATE 0x007 19 | #define ENCODER_ESTIMATES 0x009 20 | #define GET_ENCODER_COUNT 0x00A 21 | #define SET_CONTROLLER_MODES 0x00B 22 | #define SET_INPUT_POS 0x00C 23 | #define SET_INPUT_VEL 0x00D 24 | #define SET_INPUT_TORQUE 0x00E 25 | #define SET_LIMITS 0x00F 26 | #define GET_IQ 0x014 27 | #define REBOOT_ODRIVE 0x016 28 | #define GET_BUS_VOLTAGE_CURRENT 0x017 29 | #define CLEAR_ERRORS 0x018 30 | #define SET_POSITION_GAIN 0x01A 31 | #define SET_VEL_GAINS 0x01B 32 | 33 | 34 | //Axis Parameters 35 | typedef struct Axis 36 | { 37 | int AXIS_ID; 38 | float AXIS_Encoder_Pos; 39 | float AXIS_Encoder_Vel; 40 | int32_t AXIS_Encoder_CPR; 41 | int32_t AXIS_Encoder_Shadow; 42 | float AXIS_Bus_Voltage; 43 | float AXIS_Bus_Current; 44 | float AXIS_Iq_Setpoint; 45 | float AXIS_Iq_Measured; 46 | uint32_t AXIS_Error; 47 | uint8_t AXIS_Current_State; 48 | uint8_t Controller_Status; 49 | CAN_TypeDef *CAN_INSTANCE; 50 | }Axis; 51 | 52 | //Axis States 53 | typedef enum{ 54 | UNDEFINED = 0x0, 55 | IDLE = 0x1, 56 | STARTUP_SEQUENCE = 0x2, 57 | FULL_CALIBRATION_SEQUENCE = 0x3, 58 | MOTOR_CALIBRATION = 0x4, 59 | ENCODER_INDEX_SEARCH = 0x6, 60 | ENCODER_OFFSET_CALIBRATION = 0x7, 61 | CLOSED_LOOP_CONTROL = 0x8, 62 | LOCKIN_SPIN = 0x9, 63 | ENCODER_DIR_FIND = 0xA, 64 | HOMING = 0xB, 65 | ENCODER_HALL_POLARITY_CALIBRATION = 0xC, 66 | ENCODER_HALL_PHASE_CALIBRATION = 0xD 67 | } Axis_State; 68 | 69 | //Control Modes 70 | typedef enum{ 71 | VOLTAGE_CONTROL = 0x0, 72 | TORQUE_CONTROL = 0x1, 73 | VELOCITY_CONTROL = 0x2, 74 | POSITION_CONTROL = 0x3 75 | } Control_Mode; 76 | 77 | //Input Modes 78 | typedef enum{ 79 | INACTIVE = 0x0, 80 | PASSTHROUGH = 0x1, 81 | VEL_RAMP = 0x2, 82 | POS_FILTER = 0x3, 83 | MIX_CHANNELS = 0x4, 84 | TRAP_TRAJ = 0x5, 85 | TORQUE_RAMP = 0x6, 86 | MIRROR = 0x7, 87 | TUNING = 0x8 88 | } Input_Mode; 89 | 90 | 91 | /* 92 | * @function : CAN_Setup 93 | * @version : 1 94 | * @date : 14-07-2022 95 | * @parameter : 1. CAN_INSTANCE 96 | * @Type: CAN_TypeDef * 97 | * @brief: Defines which CAN Instance is used(CAN1, CAN2) 98 | * 2. baudrate 99 | * @Type: int32_t 100 | * @brief: Sets baudrate of CAN. (Use macros defined in CAN_Defines. E.g CAN_BAUDRATE_250_KBPS) 101 | 102 | * @return type : none 103 | * @brief : Used to initialize the CAN instance to be used with the ODrive CAN Bus. Pins used: CAN1(PA11, PA12), CAN2(PB12,PB13)). 104 | * These pins will be connected to a CAN transceiver as a front end. Baudrate to be set depending on baudrate of ODrive. 105 | */ 106 | 107 | void CAN_Setup(CAN_TypeDef *CAN_INSTANCE, int32_t baudrate); 108 | 109 | 110 | 111 | /* 112 | * @function : Set_Axis_Requested_State 113 | * @version : 1 114 | * @date : 14-07-2022 115 | * @parameter : 1. Axis 116 | * @Type: Axis (struct) 117 | * @brief: Defines Axis Instance 118 | * 2. state 119 | * @Type: Axis_State (enum) 120 | * @brief: Used to select Axis_State 121 | * @return type : none 122 | * @brief : Sends a CAN Data Packet with the required Axis ID and Command ID to command the axis 123 | * to change state or perform certain routines. List of Axis States listed above. 124 | */ 125 | 126 | void Set_Axis_Requested_State(Axis Axis, Axis_State state); 127 | 128 | 129 | 130 | /* 131 | * @function : Set_Input_Vel 132 | * @version : 1 133 | * @date : 14-07-2022 134 | * @parameter : 1. Axis 135 | * @Type: Axis (struct) 136 | * @brief: Defines Axis Instance 137 | * 2. vel 138 | * @Type: float 139 | * @brief: Sets the desired velocity of the axis 140 | * 3. torqueff 141 | * @Type: float 142 | * @brief: sets the feed-forward torque of the torque controller 143 | * @return type : none 144 | * @brief : Sends a CAN Data Packet with the required Axis ID and Command ID to set the desired 145 | * velocity of the axis and the the feed-forward torque of the torque controller 146 | */ 147 | 148 | void Set_Input_Vel(Axis Axis, float vel, float torqueff); 149 | 150 | 151 | 152 | /* 153 | * @function : Set_TX_Param 154 | * @version : 1 155 | * @date : 14-07-2022 156 | * @parameter : 1. AXIS_ID 157 | * @Type: int 158 | * @brief: Axis ID of the given Axis 159 | * 2. COMMAND_ID 160 | * @Type: int 161 | * @brief: Command ID of command to be executed 162 | * 3. id_type 163 | * @Type: int 164 | * @brief: Used to select standard or extended ID(CAN_ID_Standard,CAN_ID_Extended) 165 | * 4. frame_type 166 | * @Type: int 167 | * @brief: Select frame type: RTR or Data(CAN_Frame_Data, CAN_Frame_Remote) 168 | * 5. data_length 169 | * @Type: int 170 | * @brief: Set data length of packet to be sent 171 | * @return type : none 172 | * @brief : Used to set the CAN TX Struct Parameters such as data_length, frame_type, id_type, ID 173 | */ 174 | 175 | void Set_TX_Param(int AXIS_ID, int COMMAND_ID, int id_type, int frame_type, int data_length); 176 | 177 | 178 | 179 | /* 180 | * @function : Clear_Errors 181 | * @version : 1 182 | * @date : 14-07-2022 183 | * @parameter : 1. Axis 184 | * @Type: Axis (struct) 185 | * @brief: Defines Axis Instance 186 | 187 | * @return type : none 188 | * @brief : Sends a CAN Data Packet with the required Axis ID and Command ID to clear all 189 | * the errors of this device including all contained submodules. 190 | */ 191 | 192 | void Clear_Errors(Axis Axis); 193 | 194 | 195 | 196 | /* 197 | * @function : Reboot_ODrive 198 | * @version : 1 199 | * @date : 14-07-2022 200 | * @parameter : 1. Axis 201 | * @Type: Axis (struct) 202 | * @brief: Defines Axis Instance 203 | 204 | * @return type : none 205 | * @brief : Sends a CAN Data Packet with the required Axis ID and Command ID to reboot 206 | * the controller without saving the current configuraiton. 207 | * Message can be sent to either address on a given ODrive board. 208 | */ 209 | 210 | void Reboot_ODrive(Axis AXIS_ID); 211 | 212 | 213 | 214 | /* 215 | * @function : Set_Controller_Modes 216 | * @version : 1 217 | * @date : 14-07-2022 218 | * @parameter : 1. Axis 219 | * @Type: Axis (struct) 220 | * @brief: Defines Axis Instance 221 | * 2. ControlMode 222 | * @Type: Control_Mode (enum declared above) 223 | * @brief: Sets the control mode of specified axis 224 | * 3. torqueff 225 | * @Type: Input_Mode (enum declared above) 226 | * @brief: sets the input mode of specified axis 227 | * @return type : none 228 | * @brief : Sends a CAN Data Packet with the required Axis ID and Command ID to 229 | * set the Control Mode and Input Mode of given axis 230 | */ 231 | 232 | void Set_Controller_Modes(Axis Axis, Control_Mode ControlMode, Input_Mode InputMode); 233 | 234 | 235 | 236 | /* 237 | * @function : Set_Input_Pos 238 | * @version : 1 239 | * @date : 14-07-2022 240 | * @parameter : 1. Axis 241 | * @Type: Axis (struct) 242 | * @brief: Defines Axis Instance 243 | * 2. Input_Pos 244 | * @Type: float 245 | * @brief: Set the desired position of the axis 246 | * 3. Vel_FF 247 | * @Type: float 248 | * @brief: sets the feed-forward velocity of the velocity controller 249 | * 3. Torque_FF 250 | * @Type: float 251 | * @brief: sets the feed-forward torque of the torque controller 252 | * @return type : none 253 | * @brief : Sends a CAN Data Packet with the required Axis ID and Command ID to set 254 | * the desired position of the axis as well as the feed-forward velocity 255 | * and feed-forward torque 256 | */ 257 | 258 | void Set_Input_Pos(Axis Axis, float Input_Pos, int Vel_FF, int Torque_FF); 259 | 260 | 261 | 262 | /* 263 | * @function : Get_Encoder_Count 264 | * @version : 1 265 | * @date : 14-07-2022 266 | * @parameter : 1. Axis 267 | * @Type: Axis (struct) 268 | * @brief: Defines Axis Instance 269 | * @return type : none 270 | * @brief : Sends a CAN RTR Frame with required ID to the ODrive to request Encoder Shadow Count 271 | * and Encoder Count in CPR. 272 | * Note: Function only sends the RTR frame. Data will be received and variables will be updated 273 | * via the CallBack function when an reception interrupt is triggered. 274 | * 275 | */ 276 | 277 | void Get_Encoder_Count(Axis Axis); 278 | 279 | 280 | 281 | /* 282 | * @function : Set_Input_Torque 283 | * @version : 1 284 | * @date : 14-07-2022 285 | * @parameter : 1. Axis 286 | * @Type: Axis (struct) 287 | * @brief: Defines Axis Instance 288 | * 2. torque 289 | * @Type: float 290 | * @brief: Sets the desired output torque of the axis 291 | * @return type : none 292 | * @brief : Sends a CAN Data Packet with the required Axis ID and Command ID to set 293 | * the desired torque of the axis. 294 | */ 295 | 296 | void Set_Input_Torque(Axis Axis, float torque); 297 | 298 | 299 | 300 | /* 301 | * @function : Get_Bus_Voltage_Current 302 | * @version : 1 303 | * @date : 14-07-2022 304 | * @parameter : 1. Axis 305 | * @Type: Axis (struct) 306 | * @brief: Defines Axis Instance 307 | * @return type : none 308 | * @brief : Sends a CAN RTR Frame with required ID to the ODrive to request Bus Voltage and Bus Current. 309 | * Note: Function only sends the RTR frame. Data will be received and variables will be updated 310 | * via the CallBack function when an reception interrupt is triggered. 311 | * 312 | */ 313 | 314 | void Get_Bus_Voltage_Current(Axis Axis); 315 | 316 | 317 | 318 | /* 319 | * @function : Get_IQ 320 | * @version : 1 321 | * @date : 14-07-2022 322 | * @parameter : 1. Axis 323 | * @Type: Axis (struct) 324 | * @brief: Defines Axis Instance 325 | * @return type : none 326 | * @brief : Sends a CAN RTR Frame with required ID to the ODrive to request Iq Setpoint and Iq Measured. 327 | * Note: Function only sends the RTR frame. Data will be received and variables will be updated 328 | * via the CallBack function when an reception interrupt is triggered. 329 | * 330 | */ 331 | 332 | void Get_IQ(Axis Axis); 333 | 334 | 335 | 336 | /* 337 | * @function : Set_Position_Gain 338 | * @version : 1 339 | * @date : 14-07-2022 340 | * @parameter : 1. Axis 341 | * @Type: Axis (struct) 342 | * @brief: Defines Axis Instance 343 | * 2. pos_gain 344 | * @Type: float 345 | * @brief: Sets the desired position gain 346 | * @return type : none 347 | * @brief : Sends a CAN Data Packet with the required Axis ID and Command ID to set 348 | * the desired position gain 349 | */ 350 | 351 | void Set_Position_Gain(Axis Axis, float pos_gain); 352 | 353 | 354 | 355 | /* 356 | * @function : Set_Position_Gain 357 | * @version : 1 358 | * @date : 14-07-2022 359 | * @parameter : 1. Axis 360 | * @Type: Axis (struct) 361 | * @brief: Defines Axis Instance 362 | * 2. Vel_Gain 363 | * @Type: float 364 | * @brief: Sets the desired velocity gain 365 | * 3. Vel_Int_Gain 366 | * @Type: float 367 | * @brief: Sets the desired velocity integrator gain 368 | * @return type : none 369 | * @brief : Sends a CAN Data Packet with the required Axis ID and Command ID to set 370 | * the desired velocity gain and velocity integrator gain 371 | */ 372 | 373 | void Set_Vel_Gains(Axis Axis, float Vel_Gain, float Vel_Int_Gain); 374 | 375 | 376 | 377 | /* 378 | * @function : Set_Position_Gain 379 | * @version : 1 380 | * @date : 14-07-2022 381 | * @parameter : 1. Axis 382 | * @Type: Axis (struct) 383 | * @brief: Defines Axis Instance 384 | * 2. node_id 385 | * @Type: uint32_t 386 | * @brief: Updated Node Id 387 | * @return type : none 388 | * @brief : Sends a CAN Data Packet with the required Axis ID and Command ID to update 389 | * the given axis' Node Id 390 | */ 391 | 392 | void Set_Axis_Node_ID(Axis Axis, uint32_t node_id); 393 | 394 | 395 | 396 | /* 397 | * @function : Set_Limits 398 | * @version : 1 399 | * @date : 14-07-2022 400 | * @parameter : 1. Axis 401 | * @Type: Axis (struct) 402 | * @brief: Defines Axis Instance 403 | * 2. vel_lim 404 | * @Type: float 405 | * @brief: Sets the velocity limit 406 | * 3. curr_lim 407 | * @Type: float 408 | * @brief: Sets the current limit 409 | * @return type : none 410 | * @brief : Sends a CAN Data Packet with the required Axis ID and Command ID to update 411 | * the given axis' Node Id 412 | */ 413 | 414 | void Set_Limits(Axis Axis, float vel_lim, float curr_lim); 415 | 416 | 417 | 418 | /* 419 | * @function : ODrive_RX_CallBack 420 | * @version : 1 421 | * @date : 14-07-2022 422 | * @parameter : 1. AXIS 423 | * @Type: Axis * (pointer to struct) 424 | * @brief: Pointer to Axis Instance 425 | * @return type : none 426 | * @brief : This function is used as a callback function whenever an CAN RX interrupt occurs. 427 | * It is used to receive data from the ODrive when an RTR frame is sent to it as well 428 | * as the heartbeat message and Encoder Count sent at a set frequency. The data is used 429 | * to update the required variables in the Axis struct. 430 | */ 431 | 432 | void ODrive_RX_CallBack(Axis *AXIS); 433 | 434 | 435 | 436 | #endif /* ODRIVE_ODRIVE_H_ */ 437 | -------------------------------------------------------------------------------- /ODrive_CAN_Test.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/siddarthiyer/ODrive-STM32-CAN-Driver/392b65a2aca4b6e4255cec8cd7f92f5e3404baf6/ODrive_CAN_Test.zip -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ODrive CAN Driver(STM32) 2 | 3 | Library written by me to control ODrive Motors with STM32 MCU via CAN

4 | [Reference](https://docs.odriverobotics.com/v/beta/can-protocol.html) 5 |

Functions:

6 | 7 | ```C 8 | void CAN_Setup(CAN_TypeDef *CAN_INSTANCE, int32_t baudrate); 9 | void Set_Axis_Requested_State(Axis Axis, Axis_State state); 10 | void Set_Input_Vel(Axis Axis, float vel, float torqueff); 11 | void Set_TX_Param(int AXIS_ID, int COMMAND_ID, int id_type, int frame_type, int data_length); 12 | void Clear_Errors(Axis Axis); 13 | void Reboot_ODrive(Axis AXIS_ID); 14 | void Set_Controller_Modes(Axis Axis, Control_Mode ControlMode, Input_Mode InputMode); 15 | void Set_Input_Pos(Axis Axis, float Input_Pos, int Vel_FF, int Torque_FF); 16 | void Get_Encoder_Count(Axis Axis); 17 | void Set_Input_Torque(Axis Axis, float torque); 18 | void Get_Bus_Voltage_Current(Axis Axis); 19 | void Get_IQ(Axis Axis); 20 | void Set_Position_Gain(Axis Axis, float pos_gain); 21 | void Set_Vel_Gains(Axis Axis, float Vel_Gain, float Vel_Int_Gain); 22 | void Set_Axis_Node_ID(Axis Axis, uint32_t node_id); 23 | void Set_Limits(Axis Axis, float vel_lim, float curr_lim); 24 | void ODrive_RX_CallBack(Axis *AXIS); 25 | 26 | ``` 27 | 28 |

Declare a struct of type 'Axis'

29 | 30 | ```C 31 | struct Axis AXIS0; 32 | ``` 33 | 34 |

35 | Struct declaration 36 |

37 | 38 | ```C 39 | typedef struct Axis{ 40 | int AXIS_ID; 41 | float AXIS_Encoder_Pos; 42 | float AXIS_Encoder_Vel; 43 | int32_t AXIS_Encoder_CPR; 44 | int32_t AXIS_Encoder_Shadow; 45 | float AXIS_Bus_Voltage; 46 | float AXIS_Bus_Current; 47 | float AXIS_Iq_Setpoint; 48 | float AXIS_Iq_Measured; 49 | uint32_t AXIS_Error; 50 | uint8_t AXIS_Current_State; 51 | uint8_t Controller_Status; 52 | CAN_TypeDef *CAN_INSTANCE; 53 | }Axis; 54 | 55 | 56 | ``` 57 | --------------------------------------------------------------------------------