├── .vscode ├── launch.json └── tasks.json ├── Board └── v3 │ ├── Inc │ ├── FreeRTOSConfig.h │ ├── adc.h │ ├── board.h │ ├── can.h │ ├── dma.h │ ├── gpio.h │ ├── i2c.h │ ├── main.h │ ├── mxconstants.h │ ├── spi.h │ ├── stm32f4xx_hal_conf.h │ ├── stm32f4xx_it.h │ ├── tim.h │ ├── usart.h │ ├── usb_device.h │ ├── usbd_cdc_if.h │ ├── usbd_conf.h │ └── usbd_desc.h │ ├── Odrive.ioc │ ├── STM32F405RGTx_FLASH.ld │ ├── STM32F40x.svd │ ├── Src │ ├── adc.c │ ├── can.c │ ├── dma.c │ ├── freertos.c │ ├── gpio.c │ ├── i2c.c │ ├── main.c │ ├── spi.c │ ├── stm32f4xx_hal_msp.c │ ├── stm32f4xx_hal_timebase_TIM.c │ ├── stm32f4xx_it.c │ ├── system_stm32f4xx.c │ ├── tim.c │ ├── usart.c │ ├── usb_device.c │ ├── usbd_cdc_if.c │ ├── usbd_conf.c │ └── usbd_desc.c │ ├── board.cpp │ └── startup_stm32f405xx.s ├── Display ├── oled.cpp ├── oled.hpp └── oledfont.hpp ├── Drivers ├── DRV8301 │ ├── drv8301.cpp │ └── drv8301.hpp ├── STM32 │ ├── stm32_gpio.cpp │ ├── stm32_gpio.hpp │ ├── stm32_nvm.c │ ├── stm32_nvm.h │ ├── stm32_spi_arbiter.cpp │ ├── stm32_spi_arbiter.hpp │ ├── stm32_system.cpp │ ├── stm32_system.h │ └── stm32_timer.hpp └── gate_driver.hpp ├── FreeRTOS-openocd.c ├── Makefile ├── MotorControl ├── acim_estimator.cpp ├── acim_estimator.hpp ├── arm_cos_f32.c ├── arm_sin_f32.c ├── axis.cpp ├── axis.hpp ├── component.hpp ├── controller.cpp ├── controller.hpp ├── current_limiter.hpp ├── encoder.cpp ├── encoder.hpp ├── endstop.cpp ├── endstop.hpp ├── example.json ├── foc.cpp ├── foc.hpp ├── low_level.cpp ├── low_level.h ├── main.cpp ├── mechanical_brake.cpp ├── mechanical_brake.hpp ├── motor.cpp ├── motor.hpp ├── nvm_config.hpp ├── odrive_main.h ├── open_loop_controller.cpp ├── open_loop_controller.hpp ├── oscilloscope.cpp ├── oscilloscope.hpp ├── phase_control_law.hpp ├── pwm_input.cpp ├── pwm_input.hpp ├── sensorless_estimator.cpp ├── sensorless_estimator.hpp ├── task_timer.hpp ├── thermistor.cpp ├── thermistor.hpp ├── timer.hpp ├── trapTraj.cpp ├── trapTraj.hpp ├── utils.cpp └── utils.hpp ├── ThirdParty ├── CMSIS │ ├── Device │ │ └── ST │ │ │ └── STM32F4xx │ │ │ └── Include │ │ │ ├── stm32f405xx.h │ │ │ ├── stm32f4xx.h │ │ │ └── system_stm32f4xx.h │ ├── Include │ │ ├── arm_common_tables.h │ │ ├── arm_const_structs.h │ │ ├── arm_math.h │ │ ├── cmsis_armcc.h │ │ ├── cmsis_armclang.h │ │ ├── cmsis_compiler.h │ │ ├── cmsis_gcc.h │ │ ├── cmsis_iccarm.h │ │ ├── cmsis_version.h │ │ ├── core_armv8mbl.h │ │ ├── core_armv8mml.h │ │ ├── core_cm0.h │ │ ├── core_cm0plus.h │ │ ├── core_cm1.h │ │ ├── core_cm23.h │ │ ├── core_cm3.h │ │ ├── core_cm33.h │ │ ├── core_cm4.h │ │ ├── core_cm7.h │ │ ├── core_sc000.h │ │ ├── core_sc300.h │ │ ├── mpu_armv7.h │ │ ├── mpu_armv8.h │ │ └── tz_context.h │ └── Lib │ │ └── GCC │ │ └── libarm_cortexM4lf_math.a ├── FreeRTOS │ └── Source │ │ ├── CMSIS_RTOS │ │ ├── cmsis_os.c │ │ └── cmsis_os.h │ │ ├── croutine.c │ │ ├── event_groups.c │ │ ├── include │ │ ├── FreeRTOS.h │ │ ├── StackMacros.h │ │ ├── croutine.h │ │ ├── deprecated_definitions.h │ │ ├── event_groups.h │ │ ├── list.h │ │ ├── message_buffer.h │ │ ├── mpu_prototypes.h │ │ ├── mpu_wrappers.h │ │ ├── portable.h │ │ ├── projdefs.h │ │ ├── queue.h │ │ ├── semphr.h │ │ ├── stack_macros.h │ │ ├── stream_buffer.h │ │ ├── task.h │ │ └── timers.h │ │ ├── list.c │ │ ├── portable │ │ ├── GCC │ │ │ ├── ARM_CM4F │ │ │ │ ├── port.c │ │ │ │ └── portmacro.h │ │ │ └── ARM_CM7 │ │ │ │ └── r0p1 │ │ │ │ ├── port.c │ │ │ │ └── portmacro.h │ │ └── MemMang │ │ │ └── heap_4.c │ │ ├── queue.c │ │ ├── stream_buffer.c │ │ ├── tasks.c │ │ └── timers.c ├── STM32F4xx_HAL_Driver │ ├── Inc │ │ ├── Legacy │ │ │ └── stm32_hal_legacy.h │ │ ├── stm32f4xx_hal.h │ │ ├── stm32f4xx_hal_adc.h │ │ ├── stm32f4xx_hal_adc_ex.h │ │ ├── stm32f4xx_hal_can.h │ │ ├── stm32f4xx_hal_cortex.h │ │ ├── stm32f4xx_hal_def.h │ │ ├── stm32f4xx_hal_dma.h │ │ ├── stm32f4xx_hal_dma_ex.h │ │ ├── stm32f4xx_hal_flash.h │ │ ├── stm32f4xx_hal_flash_ex.h │ │ ├── stm32f4xx_hal_flash_ramfunc.h │ │ ├── stm32f4xx_hal_gpio.h │ │ ├── stm32f4xx_hal_gpio_ex.h │ │ ├── stm32f4xx_hal_i2c.h │ │ ├── stm32f4xx_hal_i2c_ex.h │ │ ├── stm32f4xx_hal_pcd.h │ │ ├── stm32f4xx_hal_pcd_ex.h │ │ ├── stm32f4xx_hal_pwr.h │ │ ├── stm32f4xx_hal_pwr_ex.h │ │ ├── stm32f4xx_hal_rcc.h │ │ ├── stm32f4xx_hal_rcc_ex.h │ │ ├── stm32f4xx_hal_spi.h │ │ ├── stm32f4xx_hal_tim.h │ │ ├── stm32f4xx_hal_tim_ex.h │ │ ├── stm32f4xx_hal_uart.h │ │ └── stm32f4xx_ll_usb.h │ └── Src │ │ ├── stm32f4xx_hal.c │ │ ├── stm32f4xx_hal_adc.c │ │ ├── stm32f4xx_hal_adc_ex.c │ │ ├── stm32f4xx_hal_can.c │ │ ├── stm32f4xx_hal_cortex.c │ │ ├── stm32f4xx_hal_dma.c │ │ ├── stm32f4xx_hal_dma_ex.c │ │ ├── stm32f4xx_hal_flash.c │ │ ├── stm32f4xx_hal_flash_ex.c │ │ ├── stm32f4xx_hal_flash_ramfunc.c │ │ ├── stm32f4xx_hal_gpio.c │ │ ├── stm32f4xx_hal_i2c.c │ │ ├── stm32f4xx_hal_i2c_ex.c │ │ ├── stm32f4xx_hal_pcd.c │ │ ├── stm32f4xx_hal_pcd_ex.c │ │ ├── stm32f4xx_hal_pwr.c │ │ ├── stm32f4xx_hal_pwr_ex.c │ │ ├── stm32f4xx_hal_rcc.c │ │ ├── stm32f4xx_hal_rcc_ex.c │ │ ├── stm32f4xx_hal_spi.c │ │ ├── stm32f4xx_hal_tim.c │ │ ├── stm32f4xx_hal_tim_ex.c │ │ ├── stm32f4xx_hal_uart.c │ │ └── stm32f4xx_ll_usb.c └── STM32_USB_Device_Library │ ├── Class │ └── CDC │ │ ├── Inc │ │ └── usbd_cdc.h │ │ └── Src │ │ └── usbd_cdc.c │ └── Core │ ├── Inc │ ├── usbd_core.h │ ├── usbd_ctlreq.h │ ├── usbd_def.h │ └── usbd_ioreq.h │ └── Src │ ├── usbd_core.c │ ├── usbd_ctlreq.c │ └── usbd_ioreq.c ├── autogen ├── endpoints.hpp ├── function_stubs.hpp ├── interfaces.hpp ├── type_info.hpp └── version.c ├── communication ├── ascii_protocol.cpp ├── ascii_protocol.hpp ├── can │ ├── can_helpers.hpp │ ├── can_simple.cpp │ ├── can_simple.hpp │ ├── canbus.hpp │ ├── odrive_can.cpp │ └── odrive_can.hpp ├── communication.cpp ├── communication.h ├── interface_can.hpp ├── interface_i2c.cpp ├── interface_i2c.h ├── interface_uart.cpp ├── interface_uart.h ├── interface_usb.cpp └── interface_usb.h ├── fibre-cpp ├── channel_discoverer.cpp ├── crc.hpp ├── endpoints_template.j2 ├── fibre.cpp ├── function_stubs_template.j2 ├── include │ └── fibre │ │ ├── async_stream.hpp │ │ ├── bufptr.hpp │ │ ├── callback.hpp │ │ ├── channel_discoverer.hpp │ │ ├── cpp_utils.hpp │ │ ├── event_loop.hpp │ │ ├── fibre.hpp │ │ ├── introspection.hpp │ │ ├── libfibre.h │ │ ├── simple_serdes.hpp │ │ └── status.hpp ├── interfaces_template.j2 ├── legacy_object_client.hpp ├── legacy_protocol.cpp ├── legacy_protocol.hpp ├── logging.hpp ├── package.lua ├── print_utils.hpp ├── protocol.hpp ├── stream_utils.hpp └── type_info_template.j2 ├── freertos_vars.h ├── interface_generator_stub.py ├── odrive-interface.yaml ├── readme_please.txt ├── syscalls.c ├── tools ├── fibre-tools │ └── interface_generator.py └── odrive │ └── version.py └── version.c /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "cwd": "${workspaceRoot}", 9 | "executable": "./build/odrive_min.elf", 10 | "name": "Debug with OpenOCD", 11 | "request": "launch", 12 | "type": "cortex-debug", 13 | "servertype": "openocd", 14 | "configFiles": [ 15 | "interface/stlink.cfg", 16 | "target/stm32f4x.cfg" 17 | ], 18 | "searchDir": ["/usr/share/openocd/scripts"], 19 | "runToEntryPoint": "main", 20 | "showDevDebugOutput": "none", 21 | }, 22 | ] 23 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "label": "Build", 8 | "type": "shell", 9 | "command": "make", 10 | "problemMatcher": [], 11 | "group": { 12 | "kind": "build", 13 | "isDefault": true 14 | } 15 | }, 16 | { 17 | "dependsOn":"Build", //task labal name, here is Build 18 | "label": "Build and Download", 19 | "type": "shell", 20 | "command": "openocd", 21 | "args": [ 22 | "-s", 23 | "/usr/share/openocd/scripts", 24 | "-f", 25 | "interface/stlink.cfg", 26 | "-f", 27 | "target/stm32f4x.cfg", 28 | "-c", 29 | "init", 30 | "-c", 31 | "reset halt", 32 | "-c", 33 | "flash write_image erase build/odrive_min.elf", 34 | "-c", 35 | "reset run", 36 | "-c", 37 | "exit" 38 | ], 39 | "problemMatcher": [] 40 | } 41 | ] 42 | } -------------------------------------------------------------------------------- /Board/v3/Inc/adc.h: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * File Name : ADC.h 4 | * Description : This file provides code for the configuration 5 | * of the ADC instances. 6 | ****************************************************************************** 7 | * This notice applies to any and all portions of this file 8 | * that are not between comment pairs USER CODE BEGIN and 9 | * USER CODE END. Other portions of this file, whether 10 | * inserted by the user or by software development tools 11 | * are owned by their respective copyright owners. 12 | * 13 | * Copyright (c) 2018 STMicroelectronics International N.V. 14 | * All rights reserved. 15 | * 16 | * Redistribution and use in source and binary forms, with or without 17 | * modification, are permitted, provided that the following conditions are met: 18 | * 19 | * 1. Redistribution of source code must retain the above copyright notice, 20 | * this list of conditions and the following disclaimer. 21 | * 2. Redistributions in binary form must reproduce the above copyright notice, 22 | * this list of conditions and the following disclaimer in the documentation 23 | * and/or other materials provided with the distribution. 24 | * 3. Neither the name of STMicroelectronics nor the names of other 25 | * contributors to this software may be used to endorse or promote products 26 | * derived from this software without specific written permission. 27 | * 4. This software, including modifications and/or derivative works of this 28 | * software, must execute solely and exclusively on microcontroller or 29 | * microprocessor devices manufactured by or for STMicroelectronics. 30 | * 5. Redistribution and use of this software other than as permitted under 31 | * this license is void and will automatically terminate your rights under 32 | * this license. 33 | * 34 | * THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS" 35 | * AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT 36 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 37 | * PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY 38 | * RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT 39 | * SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 40 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 41 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 42 | * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 43 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 44 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 45 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 46 | * 47 | ****************************************************************************** 48 | */ 49 | /* Define to prevent recursive inclusion -------------------------------------*/ 50 | #ifndef __adc_H 51 | #define __adc_H 52 | #ifdef __cplusplus 53 | extern "C" { 54 | #endif 55 | 56 | /* Includes ------------------------------------------------------------------*/ 57 | #include "stm32f4xx_hal.h" 58 | #include "main.h" 59 | 60 | /* USER CODE BEGIN Includes */ 61 | 62 | /* USER CODE END Includes */ 63 | 64 | extern ADC_HandleTypeDef hadc1; 65 | extern ADC_HandleTypeDef hadc2; 66 | extern ADC_HandleTypeDef hadc3; 67 | 68 | /* USER CODE BEGIN Private defines */ 69 | 70 | /* USER CODE END Private defines */ 71 | 72 | extern void _Error_Handler(char *, int); 73 | 74 | void MX_ADC1_Init(void); 75 | void MX_ADC2_Init(void); 76 | void MX_ADC3_Init(void); 77 | 78 | /* USER CODE BEGIN Prototypes */ 79 | 80 | /* USER CODE END Prototypes */ 81 | 82 | #ifdef __cplusplus 83 | } 84 | #endif 85 | #endif /*__ adc_H */ 86 | 87 | /** 88 | * @} 89 | */ 90 | 91 | /** 92 | * @} 93 | */ 94 | 95 | /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ 96 | -------------------------------------------------------------------------------- /Board/v3/Inc/can.h: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * File Name : CAN.h 4 | * Description : This file provides code for the configuration 5 | * of the CAN instances. 6 | ****************************************************************************** 7 | * This notice applies to any and all portions of this file 8 | * that are not between comment pairs USER CODE BEGIN and 9 | * USER CODE END. Other portions of this file, whether 10 | * inserted by the user or by software development tools 11 | * are owned by their respective copyright owners. 12 | * 13 | * Copyright (c) 2018 STMicroelectronics International N.V. 14 | * All rights reserved. 15 | * 16 | * Redistribution and use in source and binary forms, with or without 17 | * modification, are permitted, provided that the following conditions are met: 18 | * 19 | * 1. Redistribution of source code must retain the above copyright notice, 20 | * this list of conditions and the following disclaimer. 21 | * 2. Redistributions in binary form must reproduce the above copyright notice, 22 | * this list of conditions and the following disclaimer in the documentation 23 | * and/or other materials provided with the distribution. 24 | * 3. Neither the name of STMicroelectronics nor the names of other 25 | * contributors to this software may be used to endorse or promote products 26 | * derived from this software without specific written permission. 27 | * 4. This software, including modifications and/or derivative works of this 28 | * software, must execute solely and exclusively on microcontroller or 29 | * microprocessor devices manufactured by or for STMicroelectronics. 30 | * 5. Redistribution and use of this software other than as permitted under 31 | * this license is void and will automatically terminate your rights under 32 | * this license. 33 | * 34 | * THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS" 35 | * AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT 36 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 37 | * PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY 38 | * RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT 39 | * SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 40 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 41 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 42 | * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 43 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 44 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 45 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 46 | * 47 | ****************************************************************************** 48 | */ 49 | /* Define to prevent recursive inclusion -------------------------------------*/ 50 | #ifndef __can_H 51 | #define __can_H 52 | #ifdef __cplusplus 53 | extern "C" { 54 | #endif 55 | 56 | /* Includes ------------------------------------------------------------------*/ 57 | #include "stm32f4xx_hal.h" 58 | #include "main.h" 59 | 60 | /* USER CODE BEGIN Includes */ 61 | 62 | /* USER CODE END Includes */ 63 | 64 | extern CAN_HandleTypeDef hcan1; 65 | 66 | /* USER CODE BEGIN Private defines */ 67 | 68 | /* USER CODE END Private defines */ 69 | 70 | extern void _Error_Handler(char *, int); 71 | 72 | void MX_CAN1_Init(void); 73 | 74 | /* USER CODE BEGIN Prototypes */ 75 | 76 | /* USER CODE END Prototypes */ 77 | 78 | #ifdef __cplusplus 79 | } 80 | #endif 81 | #endif /*__ can_H */ 82 | 83 | /** 84 | * @} 85 | */ 86 | 87 | /** 88 | * @} 89 | */ 90 | 91 | /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ 92 | -------------------------------------------------------------------------------- /Board/v3/Inc/dma.h: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * File Name : dma.h 4 | * Description : This file contains all the function prototypes for 5 | * the dma.c file 6 | ****************************************************************************** 7 | * This notice applies to any and all portions of this file 8 | * that are not between comment pairs USER CODE BEGIN and 9 | * USER CODE END. Other portions of this file, whether 10 | * inserted by the user or by software development tools 11 | * are owned by their respective copyright owners. 12 | * 13 | * Copyright (c) 2018 STMicroelectronics International N.V. 14 | * All rights reserved. 15 | * 16 | * Redistribution and use in source and binary forms, with or without 17 | * modification, are permitted, provided that the following conditions are met: 18 | * 19 | * 1. Redistribution of source code must retain the above copyright notice, 20 | * this list of conditions and the following disclaimer. 21 | * 2. Redistributions in binary form must reproduce the above copyright notice, 22 | * this list of conditions and the following disclaimer in the documentation 23 | * and/or other materials provided with the distribution. 24 | * 3. Neither the name of STMicroelectronics nor the names of other 25 | * contributors to this software may be used to endorse or promote products 26 | * derived from this software without specific written permission. 27 | * 4. This software, including modifications and/or derivative works of this 28 | * software, must execute solely and exclusively on microcontroller or 29 | * microprocessor devices manufactured by or for STMicroelectronics. 30 | * 5. Redistribution and use of this software other than as permitted under 31 | * this license is void and will automatically terminate your rights under 32 | * this license. 33 | * 34 | * THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS" 35 | * AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT 36 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 37 | * PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY 38 | * RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT 39 | * SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 40 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 41 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 42 | * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 43 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 44 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 45 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 46 | * 47 | ****************************************************************************** 48 | */ 49 | /* Define to prevent recursive inclusion -------------------------------------*/ 50 | #ifndef __dma_H 51 | #define __dma_H 52 | 53 | #ifdef __cplusplus 54 | extern "C" { 55 | #endif 56 | 57 | /* Includes ------------------------------------------------------------------*/ 58 | #include "stm32f4xx_hal.h" 59 | #include "main.h" 60 | 61 | /* DMA memory to memory transfer handles -------------------------------------*/ 62 | extern void _Error_Handler(char*, int); 63 | 64 | /* USER CODE BEGIN Includes */ 65 | 66 | /* USER CODE END Includes */ 67 | 68 | /* USER CODE BEGIN Private defines */ 69 | 70 | /* USER CODE END Private defines */ 71 | 72 | void MX_DMA_Init(void); 73 | 74 | /* USER CODE BEGIN Prototypes */ 75 | 76 | /* USER CODE END Prototypes */ 77 | 78 | #ifdef __cplusplus 79 | } 80 | #endif 81 | 82 | #endif /* __dma_H */ 83 | 84 | /** 85 | * @} 86 | */ 87 | 88 | /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ 89 | -------------------------------------------------------------------------------- /Board/v3/Inc/gpio.h: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * File Name : gpio.h 4 | * Description : This file contains all the functions prototypes for 5 | * the gpio 6 | ****************************************************************************** 7 | * This notice applies to any and all portions of this file 8 | * that are not between comment pairs USER CODE BEGIN and 9 | * USER CODE END. Other portions of this file, whether 10 | * inserted by the user or by software development tools 11 | * are owned by their respective copyright owners. 12 | * 13 | * Copyright (c) 2018 STMicroelectronics International N.V. 14 | * All rights reserved. 15 | * 16 | * Redistribution and use in source and binary forms, with or without 17 | * modification, are permitted, provided that the following conditions are met: 18 | * 19 | * 1. Redistribution of source code must retain the above copyright notice, 20 | * this list of conditions and the following disclaimer. 21 | * 2. Redistributions in binary form must reproduce the above copyright notice, 22 | * this list of conditions and the following disclaimer in the documentation 23 | * and/or other materials provided with the distribution. 24 | * 3. Neither the name of STMicroelectronics nor the names of other 25 | * contributors to this software may be used to endorse or promote products 26 | * derived from this software without specific written permission. 27 | * 4. This software, including modifications and/or derivative works of this 28 | * software, must execute solely and exclusively on microcontroller or 29 | * microprocessor devices manufactured by or for STMicroelectronics. 30 | * 5. Redistribution and use of this software other than as permitted under 31 | * this license is void and will automatically terminate your rights under 32 | * this license. 33 | * 34 | * THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS" 35 | * AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT 36 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 37 | * PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY 38 | * RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT 39 | * SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 40 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 41 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 42 | * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 43 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 44 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 45 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 46 | * 47 | ****************************************************************************** 48 | */ 49 | 50 | /* Define to prevent recursive inclusion -------------------------------------*/ 51 | #ifndef __gpio_H 52 | #define __gpio_H 53 | #ifdef __cplusplus 54 | extern "C" { 55 | #endif 56 | 57 | /* Includes ------------------------------------------------------------------*/ 58 | #include "stm32f4xx_hal.h" 59 | #include "main.h" 60 | 61 | /* USER CODE BEGIN Includes */ 62 | /* USER CODE END Includes */ 63 | 64 | /* USER CODE BEGIN Private defines */ 65 | 66 | /* USER CODE END Private defines */ 67 | 68 | void MX_GPIO_Init(void); 69 | 70 | /* USER CODE BEGIN Prototypes */ 71 | 72 | /* USER CODE END Prototypes */ 73 | 74 | #ifdef __cplusplus 75 | } 76 | #endif 77 | #endif /*__ pinoutConfig_H */ 78 | 79 | /** 80 | * @} 81 | */ 82 | 83 | /** 84 | * @} 85 | */ 86 | 87 | /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ 88 | -------------------------------------------------------------------------------- /Board/v3/Inc/i2c.h: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * File Name : I2C.h 4 | * Description : This file provides code for the configuration 5 | * of the I2C instances. 6 | ****************************************************************************** 7 | * This notice applies to any and all portions of this file 8 | * that are not between comment pairs USER CODE BEGIN and 9 | * USER CODE END. Other portions of this file, whether 10 | * inserted by the user or by software development tools 11 | * are owned by their respective copyright owners. 12 | * 13 | * Copyright (c) 2018 STMicroelectronics International N.V. 14 | * All rights reserved. 15 | * 16 | * Redistribution and use in source and binary forms, with or without 17 | * modification, are permitted, provided that the following conditions are met: 18 | * 19 | * 1. Redistribution of source code must retain the above copyright notice, 20 | * this list of conditions and the following disclaimer. 21 | * 2. Redistributions in binary form must reproduce the above copyright notice, 22 | * this list of conditions and the following disclaimer in the documentation 23 | * and/or other materials provided with the distribution. 24 | * 3. Neither the name of STMicroelectronics nor the names of other 25 | * contributors to this software may be used to endorse or promote products 26 | * derived from this software without specific written permission. 27 | * 4. This software, including modifications and/or derivative works of this 28 | * software, must execute solely and exclusively on microcontroller or 29 | * microprocessor devices manufactured by or for STMicroelectronics. 30 | * 5. Redistribution and use of this software other than as permitted under 31 | * this license is void and will automatically terminate your rights under 32 | * this license. 33 | * 34 | * THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS" 35 | * AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT 36 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 37 | * PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY 38 | * RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT 39 | * SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 40 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 41 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 42 | * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 43 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 44 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 45 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 46 | * 47 | ****************************************************************************** 48 | */ 49 | /* Define to prevent recursive inclusion -------------------------------------*/ 50 | #ifndef __i2c_H 51 | #define __i2c_H 52 | #ifdef __cplusplus 53 | extern "C" { 54 | #endif 55 | 56 | /* Includes ------------------------------------------------------------------*/ 57 | #include "stm32f4xx_hal.h" 58 | #include "main.h" 59 | 60 | /* USER CODE BEGIN Includes */ 61 | 62 | /* USER CODE END Includes */ 63 | 64 | extern I2C_HandleTypeDef hi2c1; 65 | 66 | /* USER CODE BEGIN Private defines */ 67 | 68 | /* USER CODE END Private defines */ 69 | 70 | extern void _Error_Handler(char *, int); 71 | 72 | void MX_I2C1_Init(uint8_t addr); 73 | 74 | /* USER CODE BEGIN Prototypes */ 75 | 76 | /* USER CODE END Prototypes */ 77 | 78 | #ifdef __cplusplus 79 | } 80 | #endif 81 | #endif /*__ i2c_H */ 82 | 83 | /** 84 | * @} 85 | */ 86 | 87 | /** 88 | * @} 89 | */ 90 | 91 | /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ 92 | -------------------------------------------------------------------------------- /Board/v3/Inc/spi.h: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * File Name : SPI.h 4 | * Description : This file provides code for the configuration 5 | * of the SPI instances. 6 | ****************************************************************************** 7 | * This notice applies to any and all portions of this file 8 | * that are not between comment pairs USER CODE BEGIN and 9 | * USER CODE END. Other portions of this file, whether 10 | * inserted by the user or by software development tools 11 | * are owned by their respective copyright owners. 12 | * 13 | * Copyright (c) 2018 STMicroelectronics International N.V. 14 | * All rights reserved. 15 | * 16 | * Redistribution and use in source and binary forms, with or without 17 | * modification, are permitted, provided that the following conditions are met: 18 | * 19 | * 1. Redistribution of source code must retain the above copyright notice, 20 | * this list of conditions and the following disclaimer. 21 | * 2. Redistributions in binary form must reproduce the above copyright notice, 22 | * this list of conditions and the following disclaimer in the documentation 23 | * and/or other materials provided with the distribution. 24 | * 3. Neither the name of STMicroelectronics nor the names of other 25 | * contributors to this software may be used to endorse or promote products 26 | * derived from this software without specific written permission. 27 | * 4. This software, including modifications and/or derivative works of this 28 | * software, must execute solely and exclusively on microcontroller or 29 | * microprocessor devices manufactured by or for STMicroelectronics. 30 | * 5. Redistribution and use of this software other than as permitted under 31 | * this license is void and will automatically terminate your rights under 32 | * this license. 33 | * 34 | * THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS" 35 | * AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT 36 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 37 | * PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY 38 | * RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT 39 | * SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 40 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 41 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 42 | * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 43 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 44 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 45 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 46 | * 47 | ****************************************************************************** 48 | */ 49 | /* Define to prevent recursive inclusion -------------------------------------*/ 50 | #ifndef __spi_H 51 | #define __spi_H 52 | #ifdef __cplusplus 53 | extern "C" { 54 | #endif 55 | 56 | /* Includes ------------------------------------------------------------------*/ 57 | #include "stm32f4xx_hal.h" 58 | #include "main.h" 59 | 60 | /* USER CODE BEGIN Includes */ 61 | 62 | /* USER CODE END Includes */ 63 | 64 | extern SPI_HandleTypeDef hspi3; 65 | 66 | /* USER CODE BEGIN Private defines */ 67 | 68 | /* USER CODE END Private defines */ 69 | 70 | extern void _Error_Handler(char *, int); 71 | 72 | void MX_SPI3_Init(void); 73 | 74 | /* USER CODE BEGIN Prototypes */ 75 | 76 | /* USER CODE END Prototypes */ 77 | 78 | #ifdef __cplusplus 79 | } 80 | #endif 81 | #endif /*__ spi_H */ 82 | 83 | /** 84 | * @} 85 | */ 86 | 87 | /** 88 | * @} 89 | */ 90 | 91 | /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ 92 | -------------------------------------------------------------------------------- /Board/v3/Inc/stm32f4xx_it.h: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * @file stm32f4xx_it.h 4 | * @brief This file contains the headers of the interrupt handlers. 5 | ****************************************************************************** 6 | * 7 | * COPYRIGHT(c) 2018 STMicroelectronics 8 | * 9 | * Redistribution and use in source and binary forms, with or without modification, 10 | * are permitted provided that the following conditions are met: 11 | * 1. Redistributions of source code must retain the above copyright notice, 12 | * this list of conditions and the following disclaimer. 13 | * 2. Redistributions in binary form must reproduce the above copyright notice, 14 | * this list of conditions and the following disclaimer in the documentation 15 | * and/or other materials provided with the distribution. 16 | * 3. Neither the name of STMicroelectronics nor the names of its contributors 17 | * may be used to endorse or promote products derived from this software 18 | * without specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | * 31 | ****************************************************************************** 32 | */ 33 | 34 | /* Define to prevent recursive inclusion -------------------------------------*/ 35 | #ifndef __STM32F4xx_IT_H 36 | #define __STM32F4xx_IT_H 37 | 38 | #ifdef __cplusplus 39 | extern "C" { 40 | #endif 41 | 42 | /* Includes ------------------------------------------------------------------*/ 43 | #include "stm32f4xx_hal.h" 44 | #include "main.h" 45 | /* Exported types ------------------------------------------------------------*/ 46 | /* Exported constants --------------------------------------------------------*/ 47 | /* Exported macro ------------------------------------------------------------*/ 48 | /* Exported functions ------------------------------------------------------- */ 49 | 50 | void NMI_Handler(void); 51 | void HardFault_Handler(void); 52 | void MemManage_Handler(void); 53 | void BusFault_Handler(void); 54 | void UsageFault_Handler(void); 55 | void DebugMon_Handler(void); 56 | void SysTick_Handler(void); 57 | void DMA1_Stream0_IRQHandler(void); 58 | void DMA1_Stream2_IRQHandler(void); 59 | void DMA1_Stream4_IRQHandler(void); 60 | void DMA1_Stream5_IRQHandler(void); 61 | void DMA1_Stream6_IRQHandler(void); 62 | void DMA1_Stream7_IRQHandler(void); 63 | //void ADC_IRQHandler(void); 64 | void CAN1_TX_IRQHandler(void); 65 | void CAN1_RX0_IRQHandler(void); 66 | void CAN1_RX1_IRQHandler(void); 67 | void CAN1_SCE_IRQHandler(void); 68 | void USART2_IRQHandler(void); 69 | void TIM8_TRG_COM_TIM14_IRQHandler(void); 70 | void TIM5_IRQHandler(void); 71 | void SPI3_IRQHandler(void); 72 | void UART4_IRQHandler(void); 73 | void OTG_FS_IRQHandler(void); 74 | 75 | #ifdef __cplusplus 76 | } 77 | #endif 78 | 79 | #endif /* __STM32F4xx_IT_H */ 80 | 81 | /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ 82 | -------------------------------------------------------------------------------- /Board/v3/Inc/tim.h: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * File Name : TIM.h 4 | * Description : This file provides code for the configuration 5 | * of the TIM instances. 6 | ****************************************************************************** 7 | * This notice applies to any and all portions of this file 8 | * that are not between comment pairs USER CODE BEGIN and 9 | * USER CODE END. Other portions of this file, whether 10 | * inserted by the user or by software development tools 11 | * are owned by their respective copyright owners. 12 | * 13 | * Copyright (c) 2018 STMicroelectronics International N.V. 14 | * All rights reserved. 15 | * 16 | * Redistribution and use in source and binary forms, with or without 17 | * modification, are permitted, provided that the following conditions are met: 18 | * 19 | * 1. Redistribution of source code must retain the above copyright notice, 20 | * this list of conditions and the following disclaimer. 21 | * 2. Redistributions in binary form must reproduce the above copyright notice, 22 | * this list of conditions and the following disclaimer in the documentation 23 | * and/or other materials provided with the distribution. 24 | * 3. Neither the name of STMicroelectronics nor the names of other 25 | * contributors to this software may be used to endorse or promote products 26 | * derived from this software without specific written permission. 27 | * 4. This software, including modifications and/or derivative works of this 28 | * software, must execute solely and exclusively on microcontroller or 29 | * microprocessor devices manufactured by or for STMicroelectronics. 30 | * 5. Redistribution and use of this software other than as permitted under 31 | * this license is void and will automatically terminate your rights under 32 | * this license. 33 | * 34 | * THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS" 35 | * AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT 36 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 37 | * PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY 38 | * RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT 39 | * SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 40 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 41 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 42 | * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 43 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 44 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 45 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 46 | * 47 | ****************************************************************************** 48 | */ 49 | /* Define to prevent recursive inclusion -------------------------------------*/ 50 | #ifndef __tim_H 51 | #define __tim_H 52 | #ifdef __cplusplus 53 | extern "C" { 54 | #endif 55 | 56 | /* Includes ------------------------------------------------------------------*/ 57 | #include "stm32f4xx_hal.h" 58 | #include "main.h" 59 | 60 | /* USER CODE BEGIN Includes */ 61 | 62 | /* USER CODE END Includes */ 63 | 64 | extern TIM_HandleTypeDef htim1; 65 | extern TIM_HandleTypeDef htim2; 66 | extern TIM_HandleTypeDef htim3; 67 | extern TIM_HandleTypeDef htim4; 68 | extern TIM_HandleTypeDef htim5; 69 | extern TIM_HandleTypeDef htim8; 70 | extern TIM_HandleTypeDef htim13; 71 | 72 | /* USER CODE BEGIN Private defines */ 73 | 74 | /* USER CODE END Private defines */ 75 | 76 | extern void _Error_Handler(char *, int); 77 | 78 | void MX_TIM1_Init(void); 79 | void MX_TIM2_Init(void); 80 | void MX_TIM3_Init(void); 81 | void MX_TIM4_Init(void); 82 | void MX_TIM5_Init(void); 83 | void MX_TIM8_Init(void); 84 | void MX_TIM13_Init(void); 85 | 86 | void HAL_TIM_MspPostInit(TIM_HandleTypeDef *htim); 87 | 88 | /* USER CODE BEGIN Prototypes */ 89 | 90 | /* USER CODE END Prototypes */ 91 | 92 | #ifdef __cplusplus 93 | } 94 | #endif 95 | #endif /*__ tim_H */ 96 | 97 | /** 98 | * @} 99 | */ 100 | 101 | /** 102 | * @} 103 | */ 104 | 105 | /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ 106 | -------------------------------------------------------------------------------- /Board/v3/Inc/usart.h: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * File Name : USART.h 4 | * Description : This file provides code for the configuration 5 | * of the USART instances. 6 | ****************************************************************************** 7 | * This notice applies to any and all portions of this file 8 | * that are not between comment pairs USER CODE BEGIN and 9 | * USER CODE END. Other portions of this file, whether 10 | * inserted by the user or by software development tools 11 | * are owned by their respective copyright owners. 12 | * 13 | * Copyright (c) 2018 STMicroelectronics International N.V. 14 | * All rights reserved. 15 | * 16 | * Redistribution and use in source and binary forms, with or without 17 | * modification, are permitted, provided that the following conditions are met: 18 | * 19 | * 1. Redistribution of source code must retain the above copyright notice, 20 | * this list of conditions and the following disclaimer. 21 | * 2. Redistributions in binary form must reproduce the above copyright notice, 22 | * this list of conditions and the following disclaimer in the documentation 23 | * and/or other materials provided with the distribution. 24 | * 3. Neither the name of STMicroelectronics nor the names of other 25 | * contributors to this software may be used to endorse or promote products 26 | * derived from this software without specific written permission. 27 | * 4. This software, including modifications and/or derivative works of this 28 | * software, must execute solely and exclusively on microcontroller or 29 | * microprocessor devices manufactured by or for STMicroelectronics. 30 | * 5. Redistribution and use of this software other than as permitted under 31 | * this license is void and will automatically terminate your rights under 32 | * this license. 33 | * 34 | * THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS" 35 | * AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT 36 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 37 | * PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY 38 | * RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT 39 | * SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 40 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 41 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 42 | * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 43 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 44 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 45 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 46 | * 47 | ****************************************************************************** 48 | */ 49 | /* Define to prevent recursive inclusion -------------------------------------*/ 50 | #ifndef __usart_H 51 | #define __usart_H 52 | #ifdef __cplusplus 53 | extern "C" { 54 | #endif 55 | 56 | /* Includes ------------------------------------------------------------------*/ 57 | #include "stm32f4xx_hal.h" 58 | #include "main.h" 59 | 60 | /* USER CODE BEGIN Includes */ 61 | 62 | /* USER CODE END Includes */ 63 | 64 | extern UART_HandleTypeDef huart4; 65 | extern UART_HandleTypeDef huart2; 66 | 67 | /* USER CODE BEGIN Private defines */ 68 | 69 | /* USER CODE END Private defines */ 70 | 71 | extern void _Error_Handler(char *, int); 72 | 73 | void MX_UART4_Init(void); 74 | void MX_USART2_UART_Init(void); 75 | 76 | /* USER CODE BEGIN Prototypes */ 77 | 78 | /* USER CODE END Prototypes */ 79 | 80 | #ifdef __cplusplus 81 | } 82 | #endif 83 | #endif /*__ usart_H */ 84 | 85 | /** 86 | * @} 87 | */ 88 | 89 | /** 90 | * @} 91 | */ 92 | 93 | /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ 94 | -------------------------------------------------------------------------------- /Board/v3/Inc/usb_device.h: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * @file : usb_device.h 4 | * @version : v1.0_Cube 5 | * @brief : Header for usb_device.c file. 6 | ****************************************************************************** 7 | * This notice applies to any and all portions of this file 8 | * that are not between comment pairs USER CODE BEGIN and 9 | * USER CODE END. Other portions of this file, whether 10 | * inserted by the user or by software development tools 11 | * are owned by their respective copyright owners. 12 | * 13 | * Copyright (c) 2018 STMicroelectronics International N.V. 14 | * All rights reserved. 15 | * 16 | * Redistribution and use in source and binary forms, with or without 17 | * modification, are permitted, provided that the following conditions are met: 18 | * 19 | * 1. Redistribution of source code must retain the above copyright notice, 20 | * this list of conditions and the following disclaimer. 21 | * 2. Redistributions in binary form must reproduce the above copyright notice, 22 | * this list of conditions and the following disclaimer in the documentation 23 | * and/or other materials provided with the distribution. 24 | * 3. Neither the name of STMicroelectronics nor the names of other 25 | * contributors to this software may be used to endorse or promote products 26 | * derived from this software without specific written permission. 27 | * 4. This software, including modifications and/or derivative works of this 28 | * software, must execute solely and exclusively on microcontroller or 29 | * microprocessor devices manufactured by or for STMicroelectronics. 30 | * 5. Redistribution and use of this software other than as permitted under 31 | * this license is void and will automatically terminate your rights under 32 | * this license. 33 | * 34 | * THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS" 35 | * AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT 36 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 37 | * PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY 38 | * RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT 39 | * SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 40 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 41 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 42 | * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 43 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 44 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 45 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 46 | * 47 | ****************************************************************************** 48 | */ 49 | 50 | /* Define to prevent recursive inclusion -------------------------------------*/ 51 | #ifndef __USB_DEVICE__H__ 52 | #define __USB_DEVICE__H__ 53 | 54 | #ifdef __cplusplus 55 | extern "C" { 56 | #endif 57 | 58 | /* Includes ------------------------------------------------------------------*/ 59 | #include "stm32f4xx.h" 60 | #include "stm32f4xx_hal.h" 61 | #include "usbd_def.h" 62 | 63 | /* USER CODE BEGIN INCLUDE */ 64 | 65 | /* USER CODE END INCLUDE */ 66 | 67 | /** @addtogroup USBD_OTG_DRIVER 68 | * @{ 69 | */ 70 | 71 | /** @defgroup USBD_DEVICE USBD_DEVICE 72 | * @brief Device file for Usb otg low level driver. 73 | * @{ 74 | */ 75 | 76 | /** @defgroup USBD_DEVICE_Exported_Variables USBD_DEVICE_Exported_Variables 77 | * @brief Public variables. 78 | * @{ 79 | */ 80 | 81 | /** USB device core handle. */ 82 | extern USBD_HandleTypeDef hUsbDeviceFS; 83 | 84 | /** 85 | * @} 86 | */ 87 | 88 | /** @defgroup USBD_DEVICE_Exported_FunctionsPrototype USBD_DEVICE_Exported_FunctionsPrototype 89 | * @brief Declaration of public functions for Usb device. 90 | * @{ 91 | */ 92 | 93 | /** USB Device initialization function. */ 94 | void MX_USB_DEVICE_Init(void); 95 | 96 | /** 97 | * @} 98 | */ 99 | 100 | /** 101 | * @} 102 | */ 103 | 104 | /** 105 | * @} 106 | */ 107 | 108 | #ifdef __cplusplus 109 | } 110 | #endif 111 | 112 | #endif /* __USB_DEVICE__H__ */ 113 | 114 | /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ 115 | -------------------------------------------------------------------------------- /Board/v3/Src/stm32f4xx_hal_msp.c: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * File Name : stm32f4xx_hal_msp.c 4 | * Description : This file provides code for the MSP Initialization 5 | * and de-Initialization codes. 6 | ****************************************************************************** 7 | * This notice applies to any and all portions of this file 8 | * that are not between comment pairs USER CODE BEGIN and 9 | * USER CODE END. Other portions of this file, whether 10 | * inserted by the user or by software development tools 11 | * are owned by their respective copyright owners. 12 | * 13 | * Copyright (c) 2018 STMicroelectronics International N.V. 14 | * All rights reserved. 15 | * 16 | * Redistribution and use in source and binary forms, with or without 17 | * modification, are permitted, provided that the following conditions are met: 18 | * 19 | * 1. Redistribution of source code must retain the above copyright notice, 20 | * this list of conditions and the following disclaimer. 21 | * 2. Redistributions in binary form must reproduce the above copyright notice, 22 | * this list of conditions and the following disclaimer in the documentation 23 | * and/or other materials provided with the distribution. 24 | * 3. Neither the name of STMicroelectronics nor the names of other 25 | * contributors to this software may be used to endorse or promote products 26 | * derived from this software without specific written permission. 27 | * 4. This software, including modifications and/or derivative works of this 28 | * software, must execute solely and exclusively on microcontroller or 29 | * microprocessor devices manufactured by or for STMicroelectronics. 30 | * 5. Redistribution and use of this software other than as permitted under 31 | * this license is void and will automatically terminate your rights under 32 | * this license. 33 | * 34 | * THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS" 35 | * AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT 36 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 37 | * PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY 38 | * RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT 39 | * SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 40 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 41 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 42 | * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 43 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 44 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 45 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 46 | * 47 | ****************************************************************************** 48 | */ 49 | /* Includes ------------------------------------------------------------------*/ 50 | #include "stm32f4xx_hal.h" 51 | extern void _Error_Handler(char *, int); 52 | /* USER CODE BEGIN 0 */ 53 | 54 | /* USER CODE END 0 */ 55 | /** 56 | * Initializes the Global MSP. 57 | */ 58 | void HAL_MspInit(void) 59 | { 60 | /* USER CODE BEGIN MspInit 0 */ 61 | 62 | /* USER CODE END MspInit 0 */ 63 | 64 | __HAL_RCC_SYSCFG_CLK_ENABLE(); 65 | __HAL_RCC_PWR_CLK_ENABLE(); 66 | 67 | HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4); 68 | 69 | /* System interrupt init*/ 70 | /* MemoryManagement_IRQn interrupt configuration */ 71 | HAL_NVIC_SetPriority(MemoryManagement_IRQn, 0, 0); 72 | /* BusFault_IRQn interrupt configuration */ 73 | HAL_NVIC_SetPriority(BusFault_IRQn, 0, 0); 74 | /* UsageFault_IRQn interrupt configuration */ 75 | HAL_NVIC_SetPriority(UsageFault_IRQn, 0, 0); 76 | /* SVCall_IRQn interrupt configuration */ 77 | HAL_NVIC_SetPriority(SVCall_IRQn, 3, 0); 78 | /* DebugMonitor_IRQn interrupt configuration */ 79 | HAL_NVIC_SetPriority(DebugMonitor_IRQn, 0, 0); 80 | /* PendSV_IRQn interrupt configuration */ 81 | HAL_NVIC_SetPriority(PendSV_IRQn, 15, 0); 82 | /* SysTick_IRQn interrupt configuration */ 83 | HAL_NVIC_SetPriority(SysTick_IRQn, 15, 0); 84 | 85 | /* USER CODE BEGIN MspInit 1 */ 86 | 87 | /* USER CODE END MspInit 1 */ 88 | } 89 | 90 | /* USER CODE BEGIN 1 */ 91 | 92 | /* USER CODE END 1 */ 93 | 94 | /** 95 | * @} 96 | */ 97 | 98 | /** 99 | * @} 100 | */ 101 | 102 | /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ 103 | -------------------------------------------------------------------------------- /Board/v3/Src/usb_device.c: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * @file : usb_device.c 4 | * @version : v1.0_Cube 5 | * @brief : This file implements the USB Device 6 | ****************************************************************************** 7 | * This notice applies to any and all portions of this file 8 | * that are not between comment pairs USER CODE BEGIN and 9 | * USER CODE END. Other portions of this file, whether 10 | * inserted by the user or by software development tools 11 | * are owned by their respective copyright owners. 12 | * 13 | * Copyright (c) 2018 STMicroelectronics International N.V. 14 | * All rights reserved. 15 | * 16 | * Redistribution and use in source and binary forms, with or without 17 | * modification, are permitted, provided that the following conditions are met: 18 | * 19 | * 1. Redistribution of source code must retain the above copyright notice, 20 | * this list of conditions and the following disclaimer. 21 | * 2. Redistributions in binary form must reproduce the above copyright notice, 22 | * this list of conditions and the following disclaimer in the documentation 23 | * and/or other materials provided with the distribution. 24 | * 3. Neither the name of STMicroelectronics nor the names of other 25 | * contributors to this software may be used to endorse or promote products 26 | * derived from this software without specific written permission. 27 | * 4. This software, including modifications and/or derivative works of this 28 | * software, must execute solely and exclusively on microcontroller or 29 | * microprocessor devices manufactured by or for STMicroelectronics. 30 | * 5. Redistribution and use of this software other than as permitted under 31 | * this license is void and will automatically terminate your rights under 32 | * this license. 33 | * 34 | * THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS" 35 | * AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT 36 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 37 | * PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY 38 | * RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT 39 | * SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 40 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 41 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 42 | * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 43 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 44 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 45 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 46 | * 47 | ****************************************************************************** 48 | */ 49 | 50 | /* Includes ------------------------------------------------------------------*/ 51 | 52 | #include "usb_device.h" 53 | #include "usbd_core.h" 54 | #include "usbd_desc.h" 55 | #include "usbd_cdc.h" 56 | #include "usbd_cdc_if.h" 57 | 58 | /* USER CODE BEGIN Includes */ 59 | 60 | /* USER CODE END Includes */ 61 | 62 | /* USER CODE BEGIN PV */ 63 | /* Private variables ---------------------------------------------------------*/ 64 | 65 | /* USER CODE END PV */ 66 | 67 | /* USER CODE BEGIN PFP */ 68 | /* Private function prototypes -----------------------------------------------*/ 69 | 70 | /* USER CODE END PFP */ 71 | 72 | /* USB Device Core handle declaration. */ 73 | USBD_HandleTypeDef hUsbDeviceFS; 74 | 75 | /* 76 | * -- Insert your variables declaration here -- 77 | */ 78 | /* USER CODE BEGIN 0 */ 79 | 80 | /* USER CODE END 0 */ 81 | 82 | /* 83 | * -- Insert your external function declaration here -- 84 | */ 85 | /* USER CODE BEGIN 1 */ 86 | 87 | /* USER CODE END 1 */ 88 | 89 | /** 90 | * Init USB device Library, add supported class and start the library 91 | * @retval None 92 | */ 93 | void MX_USB_DEVICE_Init(void) 94 | { 95 | /* USER CODE BEGIN USB_DEVICE_Init_PreTreatment */ 96 | 97 | /* USER CODE END USB_DEVICE_Init_PreTreatment */ 98 | 99 | /* Init Device Library, add supported class and start the library. */ 100 | USBD_Init(&hUsbDeviceFS, &FS_Desc, DEVICE_FS); 101 | 102 | USBD_RegisterClass(&hUsbDeviceFS, &USBD_CDC); 103 | 104 | USBD_CDC_RegisterInterface(&hUsbDeviceFS, &USBD_Interface_fops_FS); 105 | 106 | USBD_Start(&hUsbDeviceFS); 107 | 108 | /* USER CODE BEGIN USB_DEVICE_Init_PostTreatment */ 109 | 110 | /* USER CODE END USB_DEVICE_Init_PostTreatment */ 111 | } 112 | 113 | /** 114 | * @} 115 | */ 116 | 117 | /** 118 | * @} 119 | */ 120 | 121 | /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ 122 | -------------------------------------------------------------------------------- /Display/oled.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __OLED_H 2 | #define __OLED_H 3 | 4 | #include 5 | #include 6 | //-----------------OLED端口定义---------------- 7 | #define OLED_SCL_Clr() HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_RESET) 8 | #define OLED_SCL_Set() HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_SET) 9 | 10 | #define OLED_SDA_Clr() HAL_GPIO_WritePin(GPIOC, GPIO_PIN_4, GPIO_PIN_RESET) 11 | #define OLED_SDA_Set() HAL_GPIO_WritePin(GPIOC, GPIO_PIN_4, GPIO_PIN_SET) 12 | 13 | #define OLED_CMD 0 //写命令 14 | #define OLED_DATA 1 //写数据 15 | 16 | void OLED_ClearPoint(uint8_t x,uint8_t y); 17 | void OLED_ColorTurn(uint8_t i); 18 | void OLED_DisplayTurn(uint8_t i); 19 | void I2C_Start(void); 20 | void I2C_Stop(void); 21 | void I2C_WaitAck(void); 22 | void Send_Byte(uint8_t dat); 23 | void OLED_WR_Byte(uint8_t dat,uint8_t mode); 24 | void OLED_DisPlay_On(void); 25 | void OLED_DisPlay_Off(void); 26 | void OLED_Refresh(void); 27 | void OLED_Clear(void); 28 | void OLED_DrawPoint(uint8_t x,uint8_t y,uint8_t t); 29 | void OLED_DrawLine(uint8_t x1,uint8_t y1,uint8_t x2,uint8_t y2,uint8_t mode); 30 | void OLED_DrawCircle(uint8_t x,uint8_t y,uint8_t r); 31 | void OLED_ShowChar(uint8_t x,uint8_t y,uint8_t chr,uint8_t size1,uint8_t mode); 32 | void OLED_ShowChar6x8(uint8_t x,uint8_t y,uint8_t chr,uint8_t mode); 33 | void OLED_ShowString(uint8_t x,uint8_t y,uint8_t *chr,uint8_t size1,uint8_t mode); 34 | void OLED_ShowNum(uint8_t x,uint8_t y,uint32_t num,uint8_t len,uint8_t size1,uint8_t mode); 35 | void OLED_ShowChinese(uint8_t x,uint8_t y,uint8_t num,uint8_t size1,uint8_t mode); 36 | void OLED_ScrollDisplay(uint8_t num,uint8_t space,uint8_t mode); 37 | void OLED_ShowPicture(uint8_t x,uint8_t y,uint8_t sizex,uint8_t sizey,uint8_t BMP[],uint8_t mode); 38 | void OLED_Init(void); 39 | void start_display_OLED_thread(); 40 | #endif -------------------------------------------------------------------------------- /Drivers/STM32/stm32_gpio.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __STM32_GPIO_HPP 2 | #define __STM32_GPIO_HPP 3 | 4 | #include 5 | 6 | class Stm32Gpio { 7 | public: 8 | static const Stm32Gpio none; 9 | 10 | Stm32Gpio() : port_(nullptr), pin_mask_(0) {} 11 | Stm32Gpio(GPIO_TypeDef* port, uint16_t pin) : port_(port), pin_mask_(pin) {} 12 | 13 | operator bool() const { return port_ && pin_mask_; } 14 | 15 | /** 16 | * @brief Configures the GPIO with the specified parameters. 17 | * 18 | * This can be done regardless of the current state of the GPIO. 19 | * 20 | * If any subscription is in place, it is not disabled by this function. 21 | */ 22 | bool config(uint32_t mode, uint32_t pull, uint32_t speed = GPIO_SPEED_FREQ_LOW); 23 | 24 | void write(bool state) { 25 | if (port_) { 26 | HAL_GPIO_WritePin(port_, pin_mask_, state ? GPIO_PIN_SET : GPIO_PIN_RESET); 27 | } 28 | } 29 | 30 | bool read() { 31 | return port_ && (port_->IDR & pin_mask_); 32 | } 33 | 34 | /** 35 | * @brief Subscribes to external interrupts on the specified GPIO. 36 | * 37 | * Before calling this function the gpio should most likely be configured as 38 | * input (however this is not mandatory, the interrupt works in output mode 39 | * too). 40 | * Also you need to enable the EXTIx_IRQn interrupt vectors in the NVIC, 41 | * otherwise the subscription won't have any effect. 42 | * 43 | * Only one subscription is allowed per pin number. I.e. it is not possible 44 | * to set up a subscription for both PA0 and PB0 at the same time. 45 | * 46 | * This function is thread-safe with respect to all other public functions 47 | * of this class. 48 | * 49 | * Returns true if the subscription was set up successfully or false otherwise. 50 | */ 51 | bool subscribe(bool rising_edge, bool falling_edge, void (*callback)(void*), void* ctx); 52 | 53 | /** 54 | * @brief Unsubscribes from external interrupt on the specified GPIO. 55 | * 56 | * If no subscription was active for this GPIO, calling this function has no 57 | * effect. 58 | * 59 | * This function is thread-safe with respect to all other public functions 60 | * of this class, however it must not be called from an interrupt routine 61 | * running at a higher priority than the interrupt that is being unsubscribed. 62 | * 63 | * After this function returns the callback given to subscribe() will no 64 | * longer be invoked. 65 | */ 66 | void unsubscribe(); 67 | 68 | uint16_t get_pin_number() { 69 | uint16_t pin_number = 0; 70 | uint16_t pin_mask = pin_mask_ >> 1; 71 | while (pin_mask) { 72 | pin_mask >>= 1; 73 | pin_number++; 74 | } 75 | return pin_number; 76 | } 77 | 78 | GPIO_TypeDef* port_; 79 | uint16_t pin_mask_; // TODO: store pin_number_ instead of pin_mask_ 80 | }; 81 | 82 | #endif // __STM32_GPIO_HPP 83 | -------------------------------------------------------------------------------- /Drivers/STM32/stm32_nvm.h: -------------------------------------------------------------------------------- 1 | /* Define to prevent recursive inclusion -------------------------------------*/ 2 | #ifndef __NVM_H 3 | #define __NVM_H 4 | 5 | #ifdef __cplusplus 6 | extern "C" { 7 | #endif 8 | 9 | /* Includes ------------------------------------------------------------------*/ 10 | #include 11 | #include 12 | 13 | /* Exported types ------------------------------------------------------------*/ 14 | /* Exported constants --------------------------------------------------------*/ 15 | /* Exported variables --------------------------------------------------------*/ 16 | /* Exported macro ------------------------------------------------------------*/ 17 | /* Exported functions --------------------------------------------------------*/ 18 | 19 | int NVM_init(void); 20 | int NVM_erase(void); 21 | size_t NVM_get_max_read_length(void); 22 | size_t NVM_get_max_write_length(void); 23 | int NVM_read(size_t offset, uint8_t *data, size_t length); 24 | int NVM_start_write(size_t length); 25 | int NVM_write(size_t offset, uint8_t *data, size_t length); 26 | int NVM_commit(void); 27 | void NVM_demo(void); 28 | 29 | #ifdef __cplusplus 30 | } 31 | #endif 32 | 33 | #endif //__NVM_H -------------------------------------------------------------------------------- /Drivers/STM32/stm32_spi_arbiter.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "stm32_spi_arbiter.hpp" 3 | #include "stm32_system.h" 4 | #include "utils.hpp" 5 | #include 6 | 7 | bool equals(const SPI_InitTypeDef& lhs, const SPI_InitTypeDef& rhs) { 8 | return (lhs.Mode == rhs.Mode) 9 | && (lhs.Direction == rhs.Direction) 10 | && (lhs.DataSize == rhs.DataSize) 11 | && (lhs.CLKPolarity == rhs.CLKPolarity) 12 | && (lhs.CLKPhase == rhs.CLKPhase) 13 | && (lhs.NSS == rhs.NSS) 14 | && (lhs.BaudRatePrescaler == rhs.BaudRatePrescaler) 15 | && (lhs.FirstBit == rhs.FirstBit) 16 | && (lhs.TIMode == rhs.TIMode) 17 | && (lhs.CRCCalculation == rhs.CRCCalculation) 18 | && (lhs.CRCPolynomial == rhs.CRCPolynomial); 19 | } 20 | 21 | bool Stm32SpiArbiter::acquire_task(SpiTask* task) { 22 | return !__atomic_exchange_n(&task->is_in_use, true, __ATOMIC_SEQ_CST); 23 | } 24 | 25 | void Stm32SpiArbiter::release_task(SpiTask* task) { 26 | task->is_in_use = false; 27 | } 28 | 29 | bool Stm32SpiArbiter::start() { 30 | if (!task_list_) { 31 | return false; 32 | } 33 | 34 | SpiTask& task = *task_list_; 35 | if (!equals(task.config, hspi_->Init)) { 36 | HAL_SPI_DeInit(hspi_); 37 | hspi_->Init = task.config; 38 | HAL_SPI_Init(hspi_); 39 | __HAL_SPI_ENABLE(hspi_); 40 | } 41 | task.ncs_gpio.write(false); 42 | 43 | HAL_StatusTypeDef status = HAL_ERROR; 44 | 45 | if (hspi_->hdmatx->State != HAL_DMA_STATE_READY || hspi_->hdmarx->State != HAL_DMA_STATE_READY) { 46 | // This can happen if the DMA or interrupt priorities are not configured properly. 47 | status = HAL_BUSY; 48 | } else if (task.tx_buf && task.rx_buf) { 49 | status = HAL_SPI_TransmitReceive_DMA(hspi_, (uint8_t*)task.tx_buf, task.rx_buf, task.length); 50 | } else if (task.tx_buf) { 51 | status = HAL_SPI_Transmit_DMA(hspi_, (uint8_t*)task.tx_buf, task.length); 52 | } else if (task.rx_buf) { 53 | status = HAL_SPI_Receive_DMA(hspi_, task.rx_buf, task.length); 54 | } 55 | 56 | if (status != HAL_OK) { 57 | task.ncs_gpio.write(true); 58 | } 59 | 60 | return status == HAL_OK; 61 | } 62 | 63 | void Stm32SpiArbiter::transfer_async(SpiTask* task) { 64 | task->next = nullptr; 65 | 66 | // Append new task to task list. 67 | // We could try to do this lock free but we could also use our time for useful things. 68 | SpiTask** ptr = &task_list_; 69 | CRITICAL_SECTION() { 70 | while (*ptr) 71 | ptr = &(*ptr)->next; 72 | *ptr = task; 73 | } 74 | 75 | // If the list was empty before, kick off the SPI arbiter now 76 | if (ptr == &task_list_) { 77 | if (!start()) { 78 | if (task->on_complete) { 79 | (*task->on_complete)(task->on_complete_ctx, false); 80 | } 81 | } 82 | } 83 | } 84 | 85 | // TODO: this currently only works when called in a CMSIS thread. 86 | bool Stm32SpiArbiter::transfer(SPI_InitTypeDef config, Stm32Gpio ncs_gpio, const uint8_t* tx_buf, uint8_t* rx_buf, size_t length, uint32_t timeout_ms) { 87 | volatile uint8_t result = 0xff; 88 | 89 | SpiTask task = { 90 | .config = config, 91 | .ncs_gpio = ncs_gpio, 92 | .tx_buf = tx_buf, 93 | .rx_buf = rx_buf, 94 | .length = length, 95 | .on_complete = [](void* ctx, bool success) { *(volatile uint8_t*)ctx = success ? 1 : 0; }, 96 | .on_complete_ctx = (void*)&result, 97 | .is_in_use = false, 98 | .next = nullptr 99 | }; 100 | 101 | transfer_async(&task); 102 | 103 | while (result == 0xff) { 104 | osDelay(1); // TODO: honor timeout 105 | } 106 | 107 | return result; 108 | } 109 | 110 | void Stm32SpiArbiter::on_complete() { 111 | if (!task_list_) { 112 | return; // this should not happen 113 | } 114 | 115 | // Wrap up transfer 116 | task_list_->ncs_gpio.write(true); 117 | if (task_list_->on_complete) { 118 | (*task_list_->on_complete)(task_list_->on_complete_ctx, true); 119 | } 120 | 121 | // Start next task if any 122 | SpiTask* next = nullptr; 123 | CRITICAL_SECTION() { 124 | next = task_list_ = task_list_->next; 125 | } 126 | if (next) { 127 | start(); 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /Drivers/STM32/stm32_spi_arbiter.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __STM32_SPI_ARBITER_HPP 2 | #define __STM32_SPI_ARBITER_HPP 3 | 4 | #include "stm32_gpio.hpp" 5 | 6 | #include 7 | 8 | class Stm32SpiArbiter { 9 | public: 10 | struct SpiTask { 11 | SPI_InitTypeDef config; 12 | Stm32Gpio ncs_gpio; 13 | const uint8_t* tx_buf; 14 | uint8_t* rx_buf; 15 | size_t length; 16 | void (*on_complete)(void*, bool); 17 | void* on_complete_ctx; 18 | bool is_in_use = false; 19 | struct SpiTask* next; 20 | }; 21 | 22 | Stm32SpiArbiter(SPI_HandleTypeDef* hspi): hspi_(hspi) {} 23 | 24 | /** 25 | * Reserves the task for the caller if it's not in use currently. 26 | * 27 | * This can be used by the caller to ensure that the task structure is not 28 | * overwritten while it's in use in a preceding transfer. 29 | * 30 | * Example: 31 | * 32 | * if (acquire_task(&task)) { 33 | * transfer_async(&task) 34 | * } 35 | * 36 | * A call to release_task() makes the task available for use again. 37 | */ 38 | static bool acquire_task(SpiTask* task); 39 | 40 | /** 41 | * Releases the task so that the next call to `acquire_task()` returns true. 42 | * This should usually be called inside the on_complete() callback after 43 | * the rx buffer has been processed. 44 | */ 45 | static void release_task(SpiTask* task); 46 | 47 | /** 48 | * @brief Enqueues a non-blocking transfer. 49 | * 50 | * Once the transfer completes, fails or is aborted, the callback is invoked. 51 | * 52 | * This function is thread-safe with respect to all other public functions 53 | * of this class. 54 | * 55 | * @param task: Contains all configuration data for this transfer. 56 | * The struct pointed to by this argument must remain valid and 57 | * unmodified until the completion callback is invoked. 58 | */ 59 | void transfer_async(SpiTask* task); 60 | 61 | /** 62 | * @brief Executes a blocking transfer. 63 | * 64 | * If the SPI is busy this function waits until it becomes available or 65 | * the specified timeout passes, whichever comes first. 66 | * 67 | * Returns true on successful transfer or false otherwise. 68 | * 69 | * This function is thread-safe with respect to all other public functions 70 | * of this class. 71 | * 72 | * @param config: The SPI configuration to apply for this transfer. 73 | * @param ncs_gpio: The active low GPIO to actuate during this transfer. 74 | * @param tx_buf: Buffer for the outgoing data to be sent. Can be null unless 75 | * rx_buf is null too. 76 | * @param rx_buf: Buffer for the incoming data to be sent. Can be null unless 77 | * tx_buf is null too. 78 | */ 79 | bool transfer(SPI_InitTypeDef config, Stm32Gpio ncs_gpio, const uint8_t* tx_buf, uint8_t* rx_buf, size_t length, uint32_t timeout_ms); 80 | 81 | /** 82 | * @brief Completion method to be called from HAL_SPI_TxCpltCallback, 83 | * HAL_SPI_RxCpltCallback and HAL_SPI_TxRxCpltCallback. 84 | */ 85 | void on_complete(); 86 | 87 | private: 88 | bool start(); 89 | 90 | SPI_HandleTypeDef* hspi_; 91 | SpiTask* task_list_ = nullptr; 92 | }; 93 | 94 | #endif // __STM32_SPI_ARBITER_HPP -------------------------------------------------------------------------------- /Drivers/STM32/stm32_system.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "stm32_system.h" 3 | 4 | uint32_t irq_counters[254]; // 14 core interrupts, 240 NVIC interrupts 5 | -------------------------------------------------------------------------------- /Drivers/STM32/stm32_system.h: -------------------------------------------------------------------------------- 1 | #ifndef __STM32_SYSTEM_H 2 | #define __STM32_SYSTEM_H 3 | 4 | #if defined(STM32F405xx) 5 | #include 6 | #elif defined(STM32F722xx) 7 | #include 8 | #else 9 | #error "unknown STM32 microcontroller" 10 | #endif 11 | 12 | // C/C++ definitions 13 | 14 | #ifdef __cplusplus 15 | extern "C" { 16 | #endif 17 | 18 | // Uncomment the following line to sacrifice 1kB of RAM for the ability to 19 | // monitor the number of times each interrupt fires. 20 | //#define ENABLE_IRQ_COUNTER 21 | 22 | #ifdef ENABLE_IRQ_COUNTER 23 | extern uint32_t irq_counters[]; 24 | #define COUNT_IRQ(irqn) (++irq_counters[irqn + 14]) 25 | #define GET_IRQ_COUNTER(irqn) irq_counters[irqn + 14] 26 | #else 27 | #define COUNT_IRQ(irqn) ((void)0) 28 | #define GET_IRQ_COUNTER(irqn) 0 29 | #endif 30 | 31 | static inline uint32_t cpu_enter_critical() { 32 | uint32_t primask = __get_PRIMASK(); 33 | __disable_irq(); 34 | return primask; 35 | } 36 | 37 | static inline void cpu_exit_critical(uint32_t priority_mask) { 38 | __set_PRIMASK(priority_mask); 39 | } 40 | 41 | #ifdef __cplusplus 42 | } 43 | #endif 44 | 45 | 46 | // C++ only definitions 47 | 48 | #ifdef __cplusplus 49 | 50 | struct CriticalSectionContext { 51 | CriticalSectionContext(const CriticalSectionContext&) = delete; 52 | CriticalSectionContext(const CriticalSectionContext&&) = delete; 53 | void operator=(const CriticalSectionContext&) = delete; 54 | void operator=(const CriticalSectionContext&&) = delete; 55 | operator bool() { return true; }; 56 | CriticalSectionContext() : mask_(cpu_enter_critical()) {} 57 | ~CriticalSectionContext() { cpu_exit_critical(mask_); } 58 | uint32_t mask_; 59 | bool exit_ = false; 60 | }; 61 | 62 | #ifdef __clang__ 63 | #define CRITICAL_SECTION() for (CriticalSectionContext __critical_section_context; !__critical_section_context.exit_; __critical_section_context.exit_ = true) 64 | #else 65 | #define CRITICAL_SECTION() if (CriticalSectionContext __critical_section_context{}) 66 | #endif 67 | 68 | #endif 69 | 70 | #endif // __STM32_SYSTEM_H -------------------------------------------------------------------------------- /Drivers/STM32/stm32_timer.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __STM32_TIMER_HPP 2 | #define __STM32_TIMER_HPP 3 | 4 | #include "stm32_system.h" 5 | #include 6 | #include 7 | 8 | class Stm32Timer { 9 | public: 10 | /** 11 | * @brief Starts multiple timers deterministically and synchronously from the 12 | * specified offset. 13 | * 14 | * All timers are atomically (*) put into the following state (regardless of 15 | * their previous state/configuration): 16 | * - TIMx_CNT will be initialized according to the corresponding counter[i] parameter. 17 | * - If the timer is in center-aligned mode, it will be set to up-counting direction. 18 | * - The update repetition counter is reset to TIMx_RCR (if applicable). 19 | * - The prescaler counter is reset. 20 | * - Update interrupts are disabled. 21 | * - The counter put into running state. 22 | * 23 | * This function is implemented by generating an update event on all selected timers. 24 | * That means as a side effect all things that are connected to the update event 25 | * except the interrupt routine itself (i.e. ADCs, DMAs, slave timers, etc) will 26 | * be triggered. 27 | * 28 | * Also you probably want to disable any connected PWM outputs to prevent glitches. 29 | * 30 | * (*) Best-effort atomically. There will be skew of a handful of clock cycles 31 | * but it's always the same given the compiler version and configuration. 32 | */ 33 | template 34 | static void start_synchronously(std::array timers, std::array counters) { 35 | start_synchronously_impl(timers, counters, std::make_index_sequence()); 36 | } 37 | 38 | private: 39 | 40 | #pragma GCC push_options 41 | #pragma GCC optimize (3) 42 | 43 | template 44 | static void start_synchronously_impl(std::array timers, std::array counters, std::index_sequence) { 45 | for (size_t i = 0; i < I; ++i) { 46 | TIM_HandleTypeDef* htim = timers[i]; 47 | 48 | // Stop the timer so we can start all of them later more atomically. 49 | htim->Instance->CR1 &= ~TIM_CR1_CEN; 50 | 51 | // Generate update event to force all of the timer's registers into 52 | // a known state. 53 | __HAL_TIM_DISABLE_IT(htim, TIM_IT_UPDATE); 54 | htim->Instance->EGR |= TIM_EGR_UG; 55 | __HAL_TIM_CLEAR_IT(htim, TIM_IT_UPDATE); 56 | 57 | // Load counter with the desired value. 58 | htim->Instance->CNT = counters[i]; 59 | } 60 | 61 | register volatile uint32_t* cr_addr[I]; 62 | register uint32_t cr_val[I]; 63 | for (size_t i = 0; i < I; ++i) { 64 | cr_addr[i] = &timers[i]->Instance->CR1; 65 | cr_val[i] = timers[i]->Instance->CR1 | TIM_CR1_CEN; 66 | } 67 | 68 | // Restart all timers as atomically as possible. 69 | // By inspection we find that this is compiled to the following code: 70 | // f7ff faa0 bl 800bdd0 71 | // f8c9 6000 str.w r6, [r9] 72 | // f8c8 5000 str.w r5, [r8] 73 | // 603c str r4, [r7, #0] 74 | // f7ff fa9d bl 800bdd8 75 | uint32_t mask = cpu_enter_critical(); 76 | int dummy[I] = {(*cr_addr[Is] = cr_val[Is], 0)...}; 77 | (void)dummy; 78 | cpu_exit_critical(mask); 79 | } 80 | #pragma GCC pop_options 81 | }; 82 | 83 | #endif // __STM32_TIMER_HPP -------------------------------------------------------------------------------- /Drivers/gate_driver.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __GATE_DRIVER_HPP 2 | #define __GATE_DRIVER_HPP 3 | 4 | struct GateDriverBase { 5 | /** 6 | * @brief Unlocks or locks the gate signals of the gate driver. 7 | * 8 | * While locked the PWM inputs are ignored and the switches are always in 9 | * OFF state. 10 | * Not all gate drivers implement this function and may return true even if 11 | * the gate driver was not locked. 12 | */ 13 | virtual bool set_enabled(bool enabled) = 0; 14 | 15 | /** 16 | * @brief Returns false if the gate driver is in a state where the output 17 | * drive stages are disarmed or not properly configured (e.g. because they 18 | * are not initialized or there was a fault condition). 19 | */ 20 | virtual bool is_ready() = 0; 21 | }; 22 | 23 | struct OpAmpBase { 24 | /** 25 | * @brief Returns false if the opamp is in a state where it's not operating 26 | * with the latest configured gain (e.g. because it was not initialized or 27 | * there was a fault condition). 28 | */ 29 | virtual bool is_ready() = 0; 30 | 31 | /** 32 | * @brief Returns the neutral voltage of the OpAmp in Volts 33 | */ 34 | virtual float get_midpoint() = 0; 35 | 36 | /** 37 | * @brief Returns the maximum voltage swing away from the midpoint voltage (in Volts) 38 | */ 39 | virtual float get_max_output_swing() = 0; 40 | }; 41 | 42 | #endif // __GATE_DRIVER_HPP -------------------------------------------------------------------------------- /FreeRTOS-openocd.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Since at least FreeRTOS V7.5.3 uxTopUsedPriority is no longer 3 | * present in the kernel, so it has to be supplied by other means for 4 | * OpenOCD's threads awareness. 5 | * 6 | * Add this file to your project, and, if you're using --gc-sections, 7 | * ``--undefined=uxTopUsedPriority'' (or 8 | * ``-Wl,--undefined=uxTopUsedPriority'' when using gcc for final 9 | * linking) to your LDFLAGS; same with all the other symbols you need. 10 | */ 11 | 12 | #include "FreeRTOS.h" 13 | 14 | #ifdef __GNUC__ 15 | #define USED __attribute__((used)) 16 | #else 17 | #define USED 18 | #endif 19 | 20 | const int USED uxTopUsedPriority = configMAX_PRIORITIES - 1; 21 | -------------------------------------------------------------------------------- /MotorControl/acim_estimator.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "acim_estimator.hpp" 3 | #include 4 | 5 | void AcimEstimator::update(uint32_t timestamp) { 6 | std::optional rotor_phase = rotor_phase_src_.present(); 7 | std::optional rotor_phase_vel = rotor_phase_vel_src_.present(); 8 | std::optional idq = idq_src_.present(); 9 | 10 | if (!rotor_phase.has_value() || !rotor_phase_vel.has_value() || !idq.has_value()) { 11 | active_ = false; 12 | return; 13 | } 14 | 15 | auto [id, iq] = *idq; 16 | 17 | float dt = (float)(timestamp - last_timestamp_) / (float)TIM_1_8_CLOCK_HZ; 18 | last_timestamp_ = timestamp; 19 | 20 | if (!active_) { 21 | // Skip first iteration and use it to reset state 22 | rotor_flux_ = 0.0f; 23 | phase_offset_ = 0.0f; 24 | active_ = true; 25 | return; 26 | } 27 | 28 | // Note that the effect of the current commands on the real currents is actually 1.5 PWM cycles later 29 | // However the rotor time constant is (usually) so slow that it doesn't matter 30 | // So we elect to write it as if the effect is immediate, to have cleaner code 31 | 32 | // acim_rotor_flux is normalized to units of [A] tracking Id; rotor inductance is unspecified 33 | float dflux_by_dt = config_.slip_velocity * (id - rotor_flux_); 34 | rotor_flux_ += dflux_by_dt * dt; 35 | float slip_velocity = config_.slip_velocity * (iq / rotor_flux_); 36 | // Check for issues with small denominator. 37 | if (is_nan(slip_velocity) || (std::abs(slip_velocity) > 0.1f / dt)) { 38 | slip_velocity = 0.0f; 39 | } 40 | slip_vel_ = slip_velocity; // reporting only 41 | 42 | stator_phase_vel_ = *rotor_phase_vel + slip_velocity; 43 | phase_offset_ = wrap_pm_pi(phase_offset_ + slip_velocity * dt); 44 | stator_phase_ = wrap_pm_pi(*rotor_phase + phase_offset_); 45 | } 46 | -------------------------------------------------------------------------------- /MotorControl/acim_estimator.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ACIM_ESTIMATOR_HPP 2 | #define __ACIM_ESTIMATOR_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | class AcimEstimator : public ComponentBase { 9 | public: 10 | struct Config_t { 11 | float slip_velocity = 14.706f; // [rad/s electrical] = 1/rotor_tau 12 | }; 13 | 14 | void update(uint32_t timestamp) final; 15 | 16 | // Config 17 | Config_t config_; 18 | 19 | // Inputs 20 | InputPort rotor_phase_src_; 21 | InputPort rotor_phase_vel_src_; 22 | InputPort idq_src_; 23 | 24 | // State variables 25 | bool active_ = false; 26 | uint32_t last_timestamp_ = 0; 27 | float rotor_flux_ = 0.0f; // [A] 28 | float phase_offset_ = 0.0f; // [A] 29 | 30 | // Outputs 31 | OutputPort slip_vel_ = 0.0f; // [rad/s electrical] 32 | OutputPort stator_phase_vel_ = 0.0f; // [rad/s] rotor flux angular velocity estimate 33 | OutputPort stator_phase_ = 0.0f; // [rad] rotor flux phase angle estimate 34 | }; 35 | 36 | #endif // __ACIM_ESTIMATOR_HPP -------------------------------------------------------------------------------- /MotorControl/arm_cos_f32.c: -------------------------------------------------------------------------------- 1 | /* ---------------------------------------------------------------------- 2 | * Project: CMSIS DSP Library 3 | * Title: arm_cos_f32.c 4 | * Description: Fast cosine calculation for floating-point values 5 | * 6 | * $Date: 27. January 2017 7 | * $Revision: V.1.5.1 8 | * 9 | * Target Processor: Cortex-M cores 10 | * -------------------------------------------------------------------- */ 11 | /* 12 | * Copyright (C) 2010-2017 ARM Limited or its affiliates. All rights reserved. 13 | * 14 | * SPDX-License-Identifier: Apache-2.0 15 | * 16 | * Licensed under the Apache License, Version 2.0 (the License); you may 17 | * not use this file except in compliance with the License. 18 | * You may obtain a copy of the License at 19 | * 20 | * www.apache.org/licenses/LICENSE-2.0 21 | * 22 | * Unless required by applicable law or agreed to in writing, software 23 | * distributed under the License is distributed on an AS IS BASIS, WITHOUT 24 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 25 | * See the License for the specific language governing permissions and 26 | * limitations under the License. 27 | */ 28 | 29 | #include 30 | #include "arm_math.h" 31 | #include "arm_common_tables.h" 32 | 33 | /** 34 | * @ingroup groupFastMath 35 | */ 36 | 37 | /** 38 | * @defgroup cos Cosine 39 | * 40 | * Computes the trigonometric cosine function using a combination of table lookup 41 | * and linear interpolation. There are separate functions for 42 | * Q15, Q31, and floating-point data types. 43 | * The input to the floating-point version is in radians and in the range [0 2*pi) while the 44 | * fixed-point Q15 and Q31 have a scaled input with the range 45 | * [0 +0.9999] mapping to [0 2*pi). The fixed-point range is chosen so that a 46 | * value of 2*pi wraps around to 0. 47 | * 48 | * The implementation is based on table lookup using 256 values together with linear interpolation. 49 | * The steps used are: 50 | * -# Calculation of the nearest integer table index 51 | * -# Compute the fractional portion (fract) of the table index. 52 | * -# The final result equals (1.0f-fract)*a + fract*b; 53 | * 54 | * where 55 | *
 56 |  *    b=Table[index+0];
 57 |  *    c=Table[index+1];
 58 |  * 
59 | */ 60 | 61 | /** 62 | * @addtogroup cos 63 | * @{ 64 | */ 65 | 66 | /** 67 | * @brief Fast approximation to the trigonometric cosine function for floating-point data. 68 | * @param[in] x input value in radians. 69 | * @return cos(x). 70 | */ 71 | 72 | float32_t our_arm_cos_f32( 73 | float32_t x) 74 | { 75 | float32_t cosVal, fract, in; /* Temporary variables for input, output */ 76 | uint16_t index; /* Index variable */ 77 | float32_t a, b; /* Two nearest output values */ 78 | int32_t n; 79 | float32_t findex; 80 | 81 | /* input x is in radians */ 82 | /* Scale the input to [0 1] range from [0 2*PI] , divide input by 2*pi, add 0.25 (pi/2) to read sine table */ 83 | in = x * 0.159154943092f + 0.25f; 84 | 85 | /* Calculation of floor value of input */ 86 | n = (int32_t) in; 87 | 88 | /* Make negative values towards -infinity */ 89 | if (in < 0.0f) 90 | { 91 | n--; 92 | } 93 | 94 | /* Map input value to [0 1] */ 95 | in = in - (float32_t) n; 96 | 97 | /* Calculation of index of the table */ 98 | findex = (float32_t)FAST_MATH_TABLE_SIZE * in; 99 | index = (uint16_t)findex; 100 | 101 | /* when "in" is exactly 1, we need to rotate the index down to 0 */ 102 | if (index >= FAST_MATH_TABLE_SIZE) { 103 | index = 0; 104 | findex -= (float32_t)FAST_MATH_TABLE_SIZE; 105 | } 106 | 107 | /* fractional value calculation */ 108 | fract = findex - (float32_t) index; 109 | 110 | /* Read two nearest values of input value from the cos table */ 111 | a = sinTable_f32[index]; 112 | b = sinTable_f32[index+1]; 113 | 114 | /* Linear interpolation process */ 115 | cosVal = (1.0f-fract)*a + fract*b; 116 | 117 | /* Return the output value */ 118 | return (cosVal); 119 | } 120 | 121 | /** 122 | * @} end of cos group 123 | */ 124 | -------------------------------------------------------------------------------- /MotorControl/arm_sin_f32.c: -------------------------------------------------------------------------------- 1 | /* ---------------------------------------------------------------------- 2 | * Project: CMSIS DSP Library 3 | * Title: arm_sin_f32.c 4 | * Description: Fast sine calculation for floating-point values 5 | * 6 | * $Date: 27. January 2017 7 | * $Revision: V.1.5.1 8 | * 9 | * Target Processor: Cortex-M cores 10 | * -------------------------------------------------------------------- */ 11 | /* 12 | * Copyright (C) 2010-2017 ARM Limited or its affiliates. All rights reserved. 13 | * 14 | * SPDX-License-Identifier: Apache-2.0 15 | * 16 | * Licensed under the Apache License, Version 2.0 (the License); you may 17 | * not use this file except in compliance with the License. 18 | * You may obtain a copy of the License at 19 | * 20 | * www.apache.org/licenses/LICENSE-2.0 21 | * 22 | * Unless required by applicable law or agreed to in writing, software 23 | * distributed under the License is distributed on an AS IS BASIS, WITHOUT 24 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 25 | * See the License for the specific language governing permissions and 26 | * limitations under the License. 27 | */ 28 | 29 | #include 30 | #include "arm_math.h" 31 | #include "arm_common_tables.h" 32 | 33 | /** 34 | * @ingroup groupFastMath 35 | */ 36 | 37 | /** 38 | * @defgroup sin Sine 39 | * 40 | * Computes the trigonometric sine function using a combination of table lookup 41 | * and linear interpolation. There are separate functions for 42 | * Q15, Q31, and floating-point data types. 43 | * The input to the floating-point version is in radians and in the range [0 2*pi) while the 44 | * fixed-point Q15 and Q31 have a scaled input with the range 45 | * [0 +0.9999] mapping to [0 2*pi). The fixed-point range is chosen so that a 46 | * value of 2*pi wraps around to 0. 47 | * 48 | * The implementation is based on table lookup using 256 values together with linear interpolation. 49 | * The steps used are: 50 | * -# Calculation of the nearest integer table index 51 | * -# Compute the fractional portion (fract) of the table index. 52 | * -# The final result equals (1.0f-fract)*a + fract*b; 53 | * 54 | * where 55 | *
 56 |  *    b=Table[index+0];
 57 |  *    c=Table[index+1];
 58 |  * 
59 | */ 60 | 61 | /** 62 | * @addtogroup sin 63 | * @{ 64 | */ 65 | 66 | /** 67 | * @brief Fast approximation to the trigonometric sine function for floating-point data. 68 | * @param[in] x input value in radians. 69 | * @return sin(x). 70 | */ 71 | 72 | float32_t our_arm_sin_f32( 73 | float32_t x) 74 | { 75 | float32_t sinVal, fract, in; /* Temporary variables for input, output */ 76 | uint16_t index; /* Index variable */ 77 | float32_t a, b; /* Two nearest output values */ 78 | int32_t n; 79 | float32_t findex; 80 | 81 | /* input x is in radians */ 82 | /* Scale the input to [0 1] range from [0 2*PI] , divide input by 2*pi */ 83 | in = x * 0.159154943092f; 84 | 85 | /* Calculation of floor value of input */ 86 | n = (int32_t) in; 87 | 88 | /* Make negative values towards -infinity */ 89 | if (x < 0.0f) 90 | { 91 | n--; 92 | } 93 | 94 | /* Map input value to [0 1] */ 95 | in = in - (float32_t) n; 96 | 97 | /* Calculation of index of the table */ 98 | findex = (float32_t)FAST_MATH_TABLE_SIZE * in; 99 | index = (uint16_t)findex; 100 | 101 | /* when "in" is exactly 1, we need to rotate the index down to 0 */ 102 | if (index >= FAST_MATH_TABLE_SIZE) { 103 | index = 0; 104 | findex -= (float32_t)FAST_MATH_TABLE_SIZE; 105 | } 106 | 107 | /* fractional value calculation */ 108 | fract = findex - (float32_t) index; 109 | 110 | /* Read two nearest values of input value from the sin table */ 111 | a = sinTable_f32[index]; 112 | b = sinTable_f32[index+1]; 113 | 114 | /* Linear interpolation process */ 115 | sinVal = (1.0f-fract)*a + fract*b; 116 | 117 | /* Return the output value */ 118 | return (sinVal); 119 | } 120 | 121 | /** 122 | * @} end of sin group 123 | */ 124 | -------------------------------------------------------------------------------- /MotorControl/current_limiter.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __CURRENT_LIMITER_HPP 2 | #define __CURRENT_LIMITER_HPP 3 | 4 | class CurrentLimiter { 5 | public: 6 | virtual ~CurrentLimiter() = default; 7 | virtual float get_current_limit(float base_current_lim) const = 0; 8 | }; 9 | 10 | #endif // __CURRENT_LIMITER_HPP 11 | -------------------------------------------------------------------------------- /MotorControl/endstop.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | void Endstop::update() { 5 | debounceTimer_.update(); 6 | last_state_ = endstop_state_; 7 | if (config_.enabled) { 8 | bool last_pin_state = pin_state_; 9 | 10 | pin_state_ = get_gpio(config_.gpio_num).read(); 11 | 12 | // If the pin state has changed, reset the timer 13 | if (pin_state_ != last_pin_state) 14 | debounceTimer_.reset(); 15 | 16 | if (debounceTimer_.expired()) 17 | endstop_state_ = config_.is_active_high ? pin_state_ : !pin_state_; // endstop_state is the logical state 18 | } else { 19 | endstop_state_ = false; 20 | } 21 | } 22 | 23 | bool Endstop::apply_config() { 24 | debounceTimer_.reset(); 25 | if (config_.enabled) { 26 | debounceTimer_.start(); 27 | } else { 28 | debounceTimer_.stop(); 29 | } 30 | debounceTimer_.setIncrement(config_.debounce_ms * 0.001f); 31 | return true; 32 | } 33 | -------------------------------------------------------------------------------- /MotorControl/endstop.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ENDSTOP_HPP 2 | #define __ENDSTOP_HPP 3 | 4 | #include "timer.hpp" 5 | class Endstop { 6 | public: 7 | struct Config_t { 8 | float offset = 0; 9 | uint32_t debounce_ms = 50; 10 | uint16_t gpio_num = 0; 11 | bool enabled = false; 12 | bool is_active_high = false; 13 | 14 | // custom setters 15 | Endstop* parent = nullptr; 16 | void set_gpio_num(uint16_t value) { gpio_num = value; parent->apply_config(); } 17 | void set_enabled(uint32_t value) { enabled = value; parent->apply_config(); } 18 | void set_debounce_ms(uint32_t value) { debounce_ms = value; parent->apply_config(); } 19 | }; 20 | 21 | 22 | Endstop::Config_t config_; 23 | Axis* axis_ = nullptr; 24 | 25 | bool apply_config(); 26 | 27 | void update(); 28 | constexpr bool get_state(){ 29 | return endstop_state_; 30 | } 31 | 32 | constexpr bool rose(){ 33 | return (endstop_state_ != last_state_) && endstop_state_; 34 | } 35 | 36 | constexpr bool fell(){ 37 | return (endstop_state_ != last_state_) && !endstop_state_; 38 | } 39 | 40 | bool endstop_state_ = false; 41 | 42 | private: 43 | bool last_state_ = false; 44 | bool pin_state_ = false; 45 | float pos_when_pressed_ = 0.0f; 46 | Timer debounceTimer_; 47 | }; 48 | #endif -------------------------------------------------------------------------------- /MotorControl/example.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "", 4 | "id": 0, 5 | "type": "json" 6 | }, 7 | { 8 | "name": "subscriptions", 9 | "id": 1, 10 | "type": "int32[]" 11 | }, 12 | { 13 | "name": "motor0", 14 | "id": 2, 15 | "type": "tree", 16 | "content": [ 17 | { 18 | "name": "pos_setpoint", 19 | "id": 3, 20 | "type": "float", 21 | "access": "rw" 22 | }, 23 | { 24 | "name": "pos_gain", 25 | "id": 4, 26 | "type": "float", 27 | "access": "rw" 28 | }, 29 | { 30 | "name": "vel_setpoint", 31 | "id": 5, 32 | "type": "float", 33 | "access": "rw" 34 | } 35 | ] 36 | } 37 | ] -------------------------------------------------------------------------------- /MotorControl/foc.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __FOC_HPP 2 | #define __FOC_HPP 3 | 4 | #include "phase_control_law.hpp" 5 | #include "component.hpp" 6 | 7 | /** 8 | * @brief Field oriented controller. 9 | * 10 | * This controller can run in either current control mode or voltage control 11 | * mode. 12 | */ 13 | class FieldOrientedController : public AlphaBetaFrameController, public ComponentBase { 14 | public: 15 | void update(uint32_t timestamp) final; 16 | 17 | void reset() final; 18 | 19 | ODriveIntf::MotorIntf::Error on_measurement( 20 | std::optional vbus_voltage, 21 | std::optional Ialpha_beta, 22 | uint32_t input_timestamp) final; 23 | 24 | ODriveIntf::MotorIntf::Error get_alpha_beta_output( 25 | uint32_t output_timestamp, 26 | std::optional* mod_alpha_beta, 27 | std::optional* ibus) final; 28 | 29 | // Config - these values are set while this controller is inactive 30 | std::optional pi_gains_; // [V/A, V/As] should be auto set after resistance and inductance measurement 31 | float I_measured_report_filter_k_ = 1.0f; 32 | 33 | // Inputs 34 | bool enable_current_control_src_ = false; 35 | InputPort Idq_setpoint_src_; 36 | InputPort Vdq_setpoint_src_; 37 | InputPort phase_src_; 38 | InputPort phase_vel_src_; 39 | 40 | // These values are set atomically by the update() function and read by the 41 | // calculate() function in an interrupt context. 42 | uint32_t ctrl_timestamp_; // [HCLK ticks] 43 | bool enable_current_control_ = false; // true: FOC runs in current control mode using I{dq}_setpoint, false: FOC runs in voltage control mode using V{dq}_setpoint 44 | std::optional Idq_setpoint_; // [A] only used if enable_current_control_ == true 45 | std::optional Vdq_setpoint_; // [V] feed-forward voltage term (or standalone setpoint if enable_current_control_ == false) 46 | std::optional phase_; // [rad] 47 | std::optional phase_vel_; // [rad/s] 48 | 49 | // These values (or some of them) are updated inside on_measurement() and get_alpha_beta_output() 50 | uint32_t i_timestamp_; 51 | std::optional vbus_voltage_measured_; // [V] 52 | std::optional Ialpha_beta_measured_; // [A, A] 53 | float Id_measured_; // [A] 54 | float Iq_measured_; // [A] 55 | float v_current_control_integral_d_ = 0.0f; // [V] 56 | float v_current_control_integral_q_ = 0.0f; // [V] 57 | //float mod_to_V_ = 0.0f; 58 | //float mod_d_ = 0.0f; 59 | //float mod_q_ = 0.0f; 60 | //float ibus_ = 0.0f; 61 | float final_v_alpha_ = 0.0f; // [V] 62 | float final_v_beta_ = 0.0f; // [V] 63 | float power_ = 0.0f; // [W] dot product of Vdq and Idq 64 | }; 65 | 66 | #endif // __FOC_HPP -------------------------------------------------------------------------------- /MotorControl/low_level.h: -------------------------------------------------------------------------------- 1 | /* Define to prevent recursive inclusion -------------------------------------*/ 2 | #ifndef __LOW_LEVEL_H 3 | #define __LOW_LEVEL_H 4 | 5 | #ifdef __cplusplus 6 | extern "C" { 7 | #endif 8 | 9 | /* Includes ------------------------------------------------------------------*/ 10 | #include 11 | #include 12 | #include 13 | 14 | /* Exported types ------------------------------------------------------------*/ 15 | /* Exported constants --------------------------------------------------------*/ 16 | #define ADC_CHANNEL_COUNT 16 17 | extern const float adc_full_scale; 18 | extern const float adc_ref_voltage; 19 | /* Exported variables --------------------------------------------------------*/ 20 | extern float vbus_voltage; 21 | extern float ibus_; 22 | extern bool brake_resistor_armed; 23 | extern bool brake_resistor_saturated; 24 | extern float brake_resistor_current; 25 | extern uint16_t adc_measurements_[ADC_CHANNEL_COUNT]; 26 | extern osThreadId analog_thread; 27 | extern const uint32_t stack_size_analog_thread; 28 | /* Exported macro ------------------------------------------------------------*/ 29 | /* Exported functions --------------------------------------------------------*/ 30 | 31 | void safety_critical_arm_brake_resistor(); 32 | void safety_critical_disarm_brake_resistor(); 33 | void safety_critical_apply_brake_resistor_timings(uint32_t low_off, uint32_t high_on); 34 | 35 | // called from STM platform code 36 | extern "C" { 37 | void vbus_sense_adc_cb(uint32_t adc_value); 38 | void pwm_in_cb(TIM_HandleTypeDef *htim); 39 | } 40 | 41 | // Initalisation 42 | void start_adc_pwm(); 43 | void start_pwm(TIM_HandleTypeDef* htim); 44 | void sync_timers(TIM_HandleTypeDef* htim_a, TIM_HandleTypeDef* htim_b, 45 | uint16_t TIM_CLOCKSOURCE_ITRx, uint16_t count_offset, 46 | TIM_HandleTypeDef* htim_refbase = nullptr); 47 | void start_general_purpose_adc(); 48 | void pwm_in_init(); 49 | void start_analog_thread(); 50 | 51 | // ADC getters 52 | uint16_t channel_from_gpio(Stm32Gpio gpio); 53 | float get_adc_voltage(Stm32Gpio gpio); 54 | float get_adc_relative_voltage(Stm32Gpio gpio); 55 | float get_adc_relative_voltage_ch(uint16_t channel); 56 | 57 | void update_brake_current(); 58 | 59 | #ifdef __cplusplus 60 | } 61 | #endif 62 | 63 | #endif //__LOW_LEVEL_H 64 | -------------------------------------------------------------------------------- /MotorControl/mechanical_brake.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void MechanicalBrake::engage() { 4 | if (odrv.config_.gpio_modes[config_.gpio_num] == ODriveIntf::GPIO_MODE_MECH_BRAKE){ 5 | get_gpio(config_.gpio_num).write(config_.is_active_low ? 0 : 1); 6 | } 7 | } 8 | 9 | void MechanicalBrake::release() { 10 | if (odrv.config_.gpio_modes[config_.gpio_num] == ODriveIntf::GPIO_MODE_MECH_BRAKE){ 11 | get_gpio(config_.gpio_num).write(config_.is_active_low ? 1 : 0); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /MotorControl/mechanical_brake.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __MECHANICAL_BRAKE_HPP 2 | #define __MECHANICAL_BRAKE_HPP 3 | 4 | #include 5 | 6 | class MechanicalBrake : public ODriveIntf::MechanicalBrakeIntf { 7 | public: 8 | struct Config_t { 9 | uint16_t gpio_num = 0; 10 | bool is_active_low = true; 11 | 12 | // custom setters 13 | MechanicalBrake* parent = nullptr; 14 | void set_gpio_num(uint16_t value) { gpio_num = value; } 15 | }; 16 | 17 | MechanicalBrake() {} 18 | 19 | MechanicalBrake::Config_t config_; 20 | Axis* axis_ = nullptr; 21 | 22 | void release(); 23 | void engage(); 24 | }; 25 | #endif // __MECHANICAL_BRAKE_HPP -------------------------------------------------------------------------------- /MotorControl/open_loop_controller.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "open_loop_controller.hpp" 3 | #include 4 | 5 | void OpenLoopController::update(uint32_t timestamp) { 6 | auto [prev_Id, prev_Iq] = Idq_setpoint_.previous().value_or(float2D{0.0f, 0.0f}); 7 | auto [prev_Vd, prev_Vq] = Vdq_setpoint_.previous().value_or(float2D{0.0f, 0.0f}); 8 | float phase = phase_.previous().value_or(initial_phase_); 9 | float phase_vel = phase_vel_.previous().value_or(0.0f); 10 | 11 | (void)prev_Iq; // unused 12 | (void)prev_Vq; // unused 13 | 14 | float dt = (float)(timestamp - timestamp_) / (float)TIM_1_8_CLOCK_HZ; 15 | 16 | Idq_setpoint_ = { 17 | std::clamp(target_current_, prev_Id - max_current_ramp_ * dt, prev_Id + max_current_ramp_ * dt), 18 | 0.0f 19 | }; 20 | Vdq_setpoint_ = { 21 | std::clamp(target_voltage_, prev_Vd - max_voltage_ramp_ * dt, prev_Vd + max_voltage_ramp_ * dt), 22 | 0.0f 23 | }; 24 | 25 | phase_vel = std::clamp(target_vel_, phase_vel - max_phase_vel_ramp_ * dt, phase_vel + max_phase_vel_ramp_ * dt); 26 | phase_vel_ = phase_vel; 27 | phase_ = wrap_pm_pi(phase + phase_vel * dt); 28 | total_distance_ = total_distance_.previous().value_or(0.0f) + phase_vel * dt; 29 | timestamp_ = timestamp; 30 | } 31 | -------------------------------------------------------------------------------- /MotorControl/open_loop_controller.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __OPEN_LOOP_CONTROLLER_HPP 2 | #define __OPEN_LOOP_CONTROLLER_HPP 3 | 4 | #include "component.hpp" 5 | #include 6 | #include 7 | 8 | class OpenLoopController : public ComponentBase { 9 | public: 10 | void update(uint32_t timestamp) final; 11 | 12 | // Config 13 | float max_current_ramp_ = INFINITY; // [A/s] 14 | float max_voltage_ramp_ = INFINITY; // [V/s] 15 | float max_phase_vel_ramp_ = INFINITY; // [rad/s^2] 16 | 17 | // Inputs 18 | float target_vel_ = 0.0f; 19 | float target_current_ = 0.0f; 20 | float target_voltage_ = 0.0f; 21 | float initial_phase_ = 0.0f; 22 | 23 | // State/Outputs 24 | uint32_t timestamp_ = 0; 25 | OutputPort Idq_setpoint_ = {{0.0f, 0.0f}}; 26 | OutputPort Vdq_setpoint_ = {{0.0f, 0.0f}}; 27 | OutputPort phase_ = 0.0f; 28 | OutputPort phase_vel_ = 0.0f; 29 | OutputPort total_distance_ = 0.0f; 30 | }; 31 | 32 | #endif // __OPEN_LOOP_CONTROLLER_HPP -------------------------------------------------------------------------------- /MotorControl/oscilloscope.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "oscilloscope.hpp" 3 | 4 | // if you use the oscilloscope feature you can bump up this value 5 | #define OSCILLOSCOPE_SIZE 4096 6 | 7 | void Oscilloscope::update() { 8 | float trigger_data = trigger_src_ ? *trigger_src_ : 0.0f; 9 | float trigger_threshold = trigger_threshold_; 10 | float sample_data = data_src_ ? **data_src_ : 0.0f; 11 | 12 | if (trigger_data < trigger_threshold) { 13 | ready_ = true; 14 | } 15 | if (ready_ && trigger_data >= trigger_threshold) { 16 | capturing_ = true; 17 | ready_ = false; 18 | } 19 | if (capturing_) { 20 | if (pos_ < OSCILLOSCOPE_SIZE) { 21 | data_[pos_++] = sample_data; 22 | } else { 23 | pos_ = 0; 24 | capturing_ = false; 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /MotorControl/oscilloscope.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __OSCILLOSCOPE_HPP 2 | #define __OSCILLOSCOPE_HPP 3 | 4 | #include 5 | 6 | // if you use the oscilloscope feature you can bump up this value 7 | #define OSCILLOSCOPE_SIZE 4096 8 | 9 | class Oscilloscope : public ODriveIntf::OscilloscopeIntf { 10 | public: 11 | Oscilloscope(float* trigger_src, float trigger_threshold, float** data_src) 12 | : trigger_src_(trigger_src), trigger_threshold_(trigger_threshold), data_src_(data_src) {} 13 | 14 | float get_val(uint32_t index) override { 15 | return index < OSCILLOSCOPE_SIZE ? data_[index] : NAN; 16 | } 17 | 18 | void update(); 19 | 20 | const uint32_t size_ = OSCILLOSCOPE_SIZE; 21 | const float* trigger_src_; 22 | const float trigger_threshold_; 23 | float* const * data_src_; 24 | 25 | float data_[OSCILLOSCOPE_SIZE] = {0}; 26 | size_t pos_ = 0; 27 | bool ready_ = false; 28 | bool capturing_ = false; 29 | }; 30 | 31 | #endif // __OSCILLOSCOPE_HPP -------------------------------------------------------------------------------- /MotorControl/phase_control_law.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __PHASE_CONTROL_LAW_HPP 2 | #define __PHASE_CONTROL_LAW_HPP 3 | 4 | #include 5 | #include 6 | 7 | template 8 | class PhaseControlLaw { 9 | public: 10 | /** 11 | * @brief Called when this controller becomes the active controller. 12 | */ 13 | virtual void reset() = 0; 14 | 15 | /** 16 | * @brief Informs the control law about a new set of measurements. 17 | * 18 | * This function gets called in a high priority interrupt context and should 19 | * run fast. 20 | * 21 | * Beware that all inputs can be NAN. 22 | * 23 | * @param vbus_voltage: The most recently measured DC link voltage. Can be 24 | * std::nullopt if the measurement is not available or valid for any 25 | * reason. 26 | * @param currents: The most recently measured (or inferred) phase currents 27 | * in Amps. Can be std::nullopt if no valid measurements are available 28 | * (e.g. because the opamp isn't started or because the sensors were 29 | * saturated). 30 | * @param input_timestamp: The timestamp (in HCLK ticks) corresponding to 31 | * the vbus_voltage and current measurement. 32 | */ 33 | virtual ODriveIntf::MotorIntf::Error on_measurement( 34 | std::optional vbus_voltage, 35 | std::optional> currents, 36 | uint32_t input_timestamp) = 0; 37 | 38 | /** 39 | * @brief Shall calculate the PWM timings for the specified target time. 40 | * 41 | * This function gets called in a high priority interrupt context and should 42 | * run fast. 43 | * 44 | * Beware that this function can be called before a call to on_measurement(). 45 | * 46 | * @param output_timestamp: The timestamp (in HCLK ticks) corresponding to 47 | * the middle of the time span during which the output will be 48 | * active. 49 | * @param pwm_timings: This array referenced by this argument shall be 50 | * filled with the desired PWM timings. Each item corresponds to one 51 | * phase and must lie in [0.0f, 1.0f]. 52 | * The function is not required to return valid PWM timings in case 53 | * of an error. 54 | * @param ibus: The variable pointed to by this argument is set to the 55 | * estimated DC current around the output timestamp when the desired 56 | * PWM timings get applied. 57 | * The function is not required to return a valid I_bus estimate in 58 | * case of an error. 59 | * 60 | * @returns: An error code or ERROR_NONE. If the function returns an error 61 | * the motor gets disarmed with one exception: If the controller 62 | * never returned valid PWM timings since it became active then it 63 | * is allowed to return ERROR_CONTROLLER_INITIALIZING without 64 | * triggering a motor disarm. In this phase the PWMs will not yet 65 | * be truly active. 66 | */ 67 | virtual ODriveIntf::MotorIntf::Error get_output( 68 | uint32_t output_timestamp, 69 | float (&pwm_timings)[N_PHASES], 70 | std::optional* ibus) = 0; 71 | }; 72 | 73 | class AlphaBetaFrameController : public PhaseControlLaw<3> { 74 | private: 75 | ODriveIntf::MotorIntf::Error on_measurement( 76 | std::optional vbus_voltage, 77 | std::optional> currents, 78 | uint32_t input_timestamp) final; 79 | 80 | ODriveIntf::MotorIntf::Error get_output( 81 | uint32_t output_timestamp, 82 | float (&pwm_timings)[3], 83 | std::optional* ibus) final; 84 | 85 | protected: 86 | virtual ODriveIntf::MotorIntf::Error on_measurement( 87 | std::optional vbus_voltage, 88 | std::optional Ialpha_beta, 89 | uint32_t input_timestamp) = 0; 90 | 91 | virtual ODriveIntf::MotorIntf::Error get_alpha_beta_output( 92 | uint32_t output_timestamp, 93 | std::optional* mod_alpha_beta, 94 | std::optional* ibus) = 0; 95 | }; 96 | 97 | #endif // __PHASE_CONTROL_LAW_HPP -------------------------------------------------------------------------------- /MotorControl/pwm_input.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "pwm_input.hpp" 3 | #include "odrive_main.h" 4 | 5 | void PwmInput::init() { 6 | TIM_IC_InitTypeDef sConfigIC; 7 | sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_BOTHEDGE; 8 | sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI; 9 | sConfigIC.ICPrescaler = TIM_ICPSC_DIV1; 10 | sConfigIC.ICFilter = 15; 11 | 12 | uint32_t channels[] = {TIM_CHANNEL_1, TIM_CHANNEL_2, TIM_CHANNEL_3, TIM_CHANNEL_4}; 13 | 14 | for (size_t i = 0; i < 4; ++i) { 15 | if (!fibre::is_endpoint_ref_valid(odrv.config_.pwm_mappings[i].endpoint)) 16 | continue; 17 | HAL_TIM_IC_ConfigChannel(htim_, &sConfigIC, channels[i]); 18 | HAL_TIM_IC_Start_IT(htim_, channels[i]); 19 | } 20 | } 21 | 22 | //TODO: These expressions have integer division by 1MHz, so it will be incorrect for clock speeds of not-integer MHz 23 | #define TIM_2_5_CLOCK_HZ TIM_APB1_CLOCK_HZ 24 | #define PWM_MIN_HIGH_TIME ((TIM_2_5_CLOCK_HZ / 1000000UL) * 1000UL) // 1ms high is considered full reverse 25 | #define PWM_MAX_HIGH_TIME ((TIM_2_5_CLOCK_HZ / 1000000UL) * 2000UL) // 2ms high is considered full forward 26 | #define PWM_MIN_LEGAL_HIGH_TIME ((TIM_2_5_CLOCK_HZ / 1000000UL) * 500UL) // ignore high periods shorter than 0.5ms 27 | #define PWM_MAX_LEGAL_HIGH_TIME ((TIM_2_5_CLOCK_HZ / 1000000UL) * 2500UL) // ignore high periods longer than 2.5ms 28 | #define PWM_INVERT_INPUT false 29 | 30 | /** 31 | * @param channel: A channel number in [0, 3] 32 | */ 33 | void handle_pulse(int channel, uint32_t high_time) { 34 | if (high_time < PWM_MIN_LEGAL_HIGH_TIME || high_time > PWM_MAX_LEGAL_HIGH_TIME) 35 | return; 36 | 37 | if (high_time < PWM_MIN_HIGH_TIME) 38 | high_time = PWM_MIN_HIGH_TIME; 39 | if (high_time > PWM_MAX_HIGH_TIME) 40 | high_time = PWM_MAX_HIGH_TIME; 41 | float fraction = (float)(high_time - PWM_MIN_HIGH_TIME) / (float)(PWM_MAX_HIGH_TIME - PWM_MIN_HIGH_TIME); 42 | float value = odrv.config_.pwm_mappings[channel].min + 43 | (fraction * (odrv.config_.pwm_mappings[channel].max - odrv.config_.pwm_mappings[channel].min)); 44 | 45 | fibre::set_endpoint_from_float(odrv.config_.pwm_mappings[channel].endpoint, value); 46 | } 47 | 48 | /** 49 | * @param channel: A channel number in [0, 3] 50 | */ 51 | void PwmInput::on_capture(int channel, uint32_t timestamp) { 52 | static uint32_t last_timestamp[4] = { 0 }; 53 | static bool last_pin_state[4] = { false }; 54 | static bool last_sample_valid[4] = { false }; 55 | 56 | if (channel >= 4) 57 | return; 58 | Stm32Gpio gpio = get_gpio(gpios_[channel]); 59 | if (!gpio) 60 | return; 61 | bool current_pin_state = gpio.read(); 62 | 63 | if (last_sample_valid[channel] 64 | && (last_pin_state[channel] != PWM_INVERT_INPUT) 65 | && (current_pin_state == PWM_INVERT_INPUT)) { 66 | handle_pulse(channel, timestamp - last_timestamp[channel]); 67 | } 68 | 69 | last_timestamp[channel] = timestamp; 70 | last_pin_state[channel] = current_pin_state; 71 | last_sample_valid[channel] = true; 72 | } 73 | 74 | void PwmInput::on_capture() { 75 | if(__HAL_TIM_GET_FLAG(htim_, TIM_FLAG_CC1)) { 76 | __HAL_TIM_CLEAR_IT(htim_, TIM_IT_CC1); 77 | on_capture(0, htim_->Instance->CCR1); 78 | } 79 | if(__HAL_TIM_GET_FLAG(htim_, TIM_FLAG_CC2)) { 80 | __HAL_TIM_CLEAR_IT(htim_, TIM_IT_CC2); 81 | on_capture(1, htim_->Instance->CCR2); 82 | } 83 | if(__HAL_TIM_GET_FLAG(htim_, TIM_FLAG_CC3)) { 84 | __HAL_TIM_CLEAR_IT(htim_, TIM_IT_CC3); 85 | on_capture(2, htim_->Instance->CCR3); 86 | } 87 | if(__HAL_TIM_GET_FLAG(htim_, TIM_FLAG_CC4)) { 88 | __HAL_TIM_CLEAR_IT(htim_, TIM_IT_CC4); 89 | on_capture(3, htim_->Instance->CCR4); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /MotorControl/pwm_input.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __PWM_INPUT_HPP 2 | #define __PWM_INPUT_HPP 3 | 4 | #include 5 | #include 6 | 7 | class PwmInput { 8 | public: 9 | PwmInput(TIM_HandleTypeDef* htim, std::array gpios) 10 | : htim_(htim), gpios_(gpios) {} 11 | 12 | void init(); 13 | void on_capture(); 14 | 15 | private: 16 | void on_capture(int channel, uint32_t timestamp); 17 | 18 | TIM_HandleTypeDef* htim_; 19 | std::array gpios_; 20 | }; 21 | 22 | #endif // __PWM_INPUT_HPP -------------------------------------------------------------------------------- /MotorControl/sensorless_estimator.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __SENSORLESS_ESTIMATOR_HPP 2 | #define __SENSORLESS_ESTIMATOR_HPP 3 | 4 | #include "component.hpp" 5 | 6 | class SensorlessEstimator : public ODriveIntf::SensorlessEstimatorIntf { 7 | public: 8 | struct Config_t { 9 | float observer_gain = 1000.0f; // [rad/s] 10 | float pll_bandwidth = 1000.0f; // [rad/s] 11 | float pm_flux_linkage = 1.58e-3f; // [V / (rad/s)] { 5.51328895422 / ( * ) } 12 | }; 13 | 14 | void reset(); 15 | bool update(); 16 | 17 | Axis* axis_ = nullptr; // set by Axis constructor 18 | Config_t config_; 19 | 20 | // TODO: expose on protocol 21 | Error error_ = ERROR_NONE; 22 | float pll_pos_ = 0.0f; // [rad] 23 | float flux_state_[2] = {0.0f, 0.0f}; // [Vs] 24 | float V_alpha_beta_memory_[2] = {0.0f, 0.0f}; // [V] 25 | 26 | OutputPort phase_ = 0.0f; // [rad] 27 | OutputPort phase_vel_ = 0.0f; // [rad/s] 28 | OutputPort vel_estimate_ = 0.0f; // [turns/s] 29 | }; 30 | 31 | #endif /* __SENSORLESS_ESTIMATOR_HPP */ 32 | -------------------------------------------------------------------------------- /MotorControl/task_timer.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __TASK_TIMER_HPP 2 | #define __TASK_TIMER_HPP 3 | 4 | #include 5 | #include 6 | 7 | #define MEASURE_START_TIME 8 | #define MEASURE_END_TIME 9 | #define MEASURE_LENGTH 10 | #define MEASURE_MAX_LENGTH 11 | 12 | inline uint16_t sample_TIM13() { 13 | constexpr uint16_t clocks_per_cnt = (uint16_t)((float)TIM_1_8_CLOCK_HZ / (float)TIM_APB1_CLOCK_HZ); 14 | return clocks_per_cnt * TIM13->CNT; // TODO: Use a hw_config 15 | } 16 | 17 | struct TaskTimer { 18 | uint32_t start_time_ = 0; 19 | uint32_t end_time_ = 0; 20 | uint32_t length_ = 0; 21 | uint32_t max_length_ = 0; 22 | 23 | static bool enabled; 24 | 25 | uint32_t start() { 26 | return sample_TIM13(); 27 | } 28 | 29 | void stop(uint32_t start_time) { 30 | uint32_t end_time = sample_TIM13(); 31 | uint32_t length = end_time - start_time; 32 | 33 | if (enabled) { 34 | #ifdef MEASURE_START_TIME 35 | start_time_ = start_time; 36 | #endif 37 | #ifdef MEASURE_END_TIME 38 | end_time_ = end_time; 39 | #endif 40 | #ifdef MEASURE_LENGTH 41 | length_ = length; 42 | #endif 43 | } 44 | #ifdef MEASURE_MAX_LENGTH 45 | max_length_ = std::max(max_length_, length); 46 | #endif 47 | } 48 | }; 49 | 50 | struct TaskTimerContext { 51 | TaskTimerContext(const TaskTimerContext&) = delete; 52 | TaskTimerContext(const TaskTimerContext&&) = delete; 53 | void operator=(const TaskTimerContext&) = delete; 54 | void operator=(const TaskTimerContext&&) = delete; 55 | TaskTimerContext(TaskTimer& timer) : timer_(timer), start_time(timer.start()) {} 56 | ~TaskTimerContext() { timer_.stop(start_time); } 57 | 58 | TaskTimer& timer_; 59 | uint32_t start_time; 60 | bool exit_ = false; 61 | }; 62 | 63 | #define MEASURE_TIME(timer) for (TaskTimerContext __task_timer_ctx{timer}; !__task_timer_ctx.exit_; __task_timer_ctx.exit_ = true) 64 | 65 | #endif // __TASK_TIMER_HPP -------------------------------------------------------------------------------- /MotorControl/thermistor.cpp: -------------------------------------------------------------------------------- 1 | #include "odrive_main.h" 2 | 3 | #include "low_level.h" 4 | 5 | ThermistorCurrentLimiter::ThermistorCurrentLimiter(uint16_t adc_channel, 6 | const float* const coefficients, 7 | size_t num_coeffs, 8 | const float& temp_limit_lower, 9 | const float& temp_limit_upper, 10 | const bool& enabled) : 11 | adc_channel_(adc_channel), 12 | coefficients_(coefficients), 13 | num_coeffs_(num_coeffs), 14 | temperature_(NAN), 15 | temp_limit_lower_(temp_limit_lower), 16 | temp_limit_upper_(temp_limit_upper), 17 | enabled_(enabled) 18 | { 19 | } 20 | 21 | void ThermistorCurrentLimiter::update() { 22 | const float normalized_voltage = get_adc_relative_voltage_ch(adc_channel_); 23 | float raw_temperature_ = horner_poly_eval(normalized_voltage, coefficients_, num_coeffs_); 24 | 25 | constexpr float tau = 0.1f; // [sec] 26 | float k = current_meas_period / tau; 27 | float val = raw_temperature_; 28 | for (float& lpf_val : lpf_vals_) { 29 | lpf_val += k * (val - lpf_val); 30 | val = lpf_val; 31 | } 32 | if (is_nan(val)) { 33 | lpf_vals_.fill(0.0f); 34 | } 35 | temperature_ = lpf_vals_.back(); 36 | } 37 | 38 | bool ThermistorCurrentLimiter::do_checks() { 39 | if (enabled_ && temperature_ >= temp_limit_upper_ + 5) { 40 | return false; 41 | } 42 | return true; 43 | } 44 | 45 | float ThermistorCurrentLimiter::get_current_limit(float base_current_lim) const { 46 | if (!enabled_) { 47 | return base_current_lim; 48 | } 49 | 50 | const float temp_margin = temp_limit_upper_ - temperature_; 51 | const float derating_range = temp_limit_upper_ - temp_limit_lower_; 52 | float thermal_current_lim = base_current_lim * (temp_margin / derating_range); 53 | if (thermal_current_lim < 0.0f || is_nan(thermal_current_lim)) { 54 | thermal_current_lim = 0.0f; 55 | } 56 | 57 | return std::min(thermal_current_lim, base_current_lim); 58 | } 59 | 60 | OnboardThermistorCurrentLimiter::OnboardThermistorCurrentLimiter(uint16_t adc_channel, const float* const coefficients, size_t num_coeffs) : 61 | ThermistorCurrentLimiter(adc_channel, 62 | coefficients, 63 | num_coeffs, 64 | config_.temp_limit_lower, 65 | config_.temp_limit_upper, 66 | config_.enabled) 67 | { 68 | } 69 | 70 | OffboardThermistorCurrentLimiter::OffboardThermistorCurrentLimiter() : 71 | ThermistorCurrentLimiter(UINT16_MAX, 72 | &config_.thermistor_poly_coeffs[0], 73 | num_coeffs_, 74 | config_.temp_limit_lower, 75 | config_.temp_limit_upper, 76 | config_.enabled) 77 | { 78 | decode_pin(); 79 | } 80 | 81 | bool OffboardThermistorCurrentLimiter::apply_config() { 82 | config_.parent = this; 83 | decode_pin(); 84 | return true; 85 | } 86 | 87 | void OffboardThermistorCurrentLimiter::decode_pin() { 88 | adc_channel_ = channel_from_gpio(get_gpio(config_.gpio_pin)); 89 | } 90 | -------------------------------------------------------------------------------- /MotorControl/thermistor.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __THERMISTOR_HPP 2 | #define __THERMISTOR_HPP 3 | 4 | class Motor; // declared in motor.hpp 5 | 6 | #include "current_limiter.hpp" 7 | #include 8 | 9 | class ThermistorCurrentLimiter : public CurrentLimiter, public ODriveIntf::ThermistorCurrentLimiterIntf { 10 | public: 11 | virtual ~ThermistorCurrentLimiter() = default; 12 | 13 | ThermistorCurrentLimiter(uint16_t adc_channel, 14 | const float* const coefficients, 15 | size_t num_coeffs, 16 | const float& temp_limit_lower, 17 | const float& temp_limit_upper, 18 | const bool& enabled); 19 | 20 | void update(); 21 | bool do_checks(); 22 | float get_current_limit(float base_current_lim) const override; 23 | 24 | uint16_t adc_channel_; 25 | const float* const coefficients_; 26 | const size_t num_coeffs_; 27 | float temperature_ = NAN; // [°C] NaN while the ODrive is initializing. 28 | const float& temp_limit_lower_; 29 | const float& temp_limit_upper_; 30 | const bool& enabled_; 31 | Motor* motor_ = nullptr; // set by Motor::apply_config() 32 | std::array lpf_vals_ = { 0.0f }; 33 | }; 34 | 35 | class OnboardThermistorCurrentLimiter : public ThermistorCurrentLimiter, public ODriveIntf::OnboardThermistorCurrentLimiterIntf { 36 | public: 37 | struct Config_t { 38 | float temp_limit_lower = 100; 39 | float temp_limit_upper = 120; 40 | bool enabled = true; 41 | }; 42 | 43 | virtual ~OnboardThermistorCurrentLimiter() = default; 44 | OnboardThermistorCurrentLimiter(uint16_t adc_channel, const float* const coefficients, size_t num_coeffs); 45 | 46 | Config_t config_; 47 | }; 48 | 49 | class OffboardThermistorCurrentLimiter : public ThermistorCurrentLimiter, public ODriveIntf::OffboardThermistorCurrentLimiterIntf { 50 | public: 51 | static const size_t num_coeffs_ = 4; 52 | 53 | struct Config_t { 54 | float thermistor_poly_coeffs[num_coeffs_]; 55 | 56 | #if HW_VERSION_MAJOR == 3 57 | uint16_t gpio_pin = 4; 58 | #elif HW_VERSION_MAJOR == 4 59 | uint16_t gpio_pin = 2; 60 | #endif 61 | float temp_limit_lower = 100; 62 | float temp_limit_upper = 120; 63 | bool enabled = false; 64 | 65 | // custom setters 66 | OffboardThermistorCurrentLimiter* parent; 67 | void set_gpio_pin(uint16_t value) { gpio_pin = value; parent->decode_pin(); } 68 | }; 69 | 70 | virtual ~OffboardThermistorCurrentLimiter() = default; 71 | OffboardThermistorCurrentLimiter(); 72 | 73 | Config_t config_; 74 | 75 | bool apply_config(); 76 | 77 | private: 78 | void decode_pin(); 79 | }; 80 | 81 | #endif // __THERMISTOR_HPP 82 | -------------------------------------------------------------------------------- /MotorControl/timer.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | template 5 | class Timer { 6 | public: 7 | void setTimeout(const T timeout) { 8 | timeout_ = timeout; 9 | } 10 | 11 | void setIncrement(const T increment) { 12 | increment_ = increment; 13 | } 14 | 15 | void start() { 16 | running_ = true; 17 | } 18 | 19 | void stop() { 20 | running_ = false; 21 | } 22 | 23 | // If the timer is started, increment the timer 24 | void update() { 25 | if (running_) 26 | timer_ = std::min(timer_ + increment_, timeout_); 27 | } 28 | 29 | void reset() { 30 | timer_ = static_cast(0); 31 | } 32 | 33 | bool expired() { 34 | return timer_ >= timeout_; 35 | } 36 | 37 | private: 38 | T timer_ = static_cast(0); // Current state 39 | T timeout_ = static_cast(0); // Time to count 40 | T increment_ = static_cast(0); // Amount to increment each time update() is called 41 | bool running_ = false; // update() only increments if runing_ is true 42 | }; 43 | -------------------------------------------------------------------------------- /MotorControl/trapTraj.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "odrive_main.h" 3 | #include "utils.hpp" 4 | 5 | // A sign function where input 0 has positive sign (not 0) 6 | float sign_hard(float val) { 7 | return (std::signbit(val)) ? -1.0f : 1.0f; 8 | } 9 | 10 | // Symbol Description 11 | // Ta, Tv and Td Duration of the stages of the AL profile 12 | // Xi and Vi Adapted initial conditions for the AL profile 13 | // Xf Position set-point 14 | // s Direction (sign) of the trajectory 15 | // Vmax, Amax, Dmax and jmax Kinematic bounds 16 | // Ar, Dr and Vr Reached values of acceleration and velocity 17 | 18 | bool TrapezoidalTrajectory::planTrapezoidal(float Xf, float Xi, float Vi, 19 | float Vmax, float Amax, float Dmax) { 20 | float dX = Xf - Xi; // Distance to travel 21 | float stop_dist = (Vi * Vi) / (2.0f * Dmax); // Minimum stopping distance 22 | float dXstop = std::copysign(stop_dist, Vi); // Minimum stopping displacement 23 | float s = sign_hard(dX - dXstop); // Sign of coast velocity (if any) 24 | Ar_ = s * Amax; // Maximum Acceleration (signed) 25 | Dr_ = -s * Dmax; // Maximum Deceleration (signed) 26 | Vr_ = s * Vmax; // Maximum Velocity (signed) 27 | 28 | // If we start with a speed faster than cruising, then we need to decel instead of accel 29 | // aka "double deceleration move" in the paper 30 | if ((s * Vi) > (s * Vr_)) { 31 | Ar_ = -s * Amax; 32 | } 33 | 34 | // Time to accel/decel to/from Vr (cruise speed) 35 | Ta_ = (Vr_ - Vi) / Ar_; 36 | Td_ = -Vr_ / Dr_; 37 | 38 | // Integral of velocity ramps over the full accel and decel times to get 39 | // minimum displacement required to reach cuising speed 40 | float dXmin = 0.5f*Ta_*(Vr_ + Vi) + 0.5f*Td_*Vr_; 41 | 42 | // Are we displacing enough to reach cruising speed? 43 | if (s*dX < s*dXmin) { 44 | // Short move (triangle profile) 45 | Vr_ = s * std::sqrt(std::max((Dr_*SQ(Vi) + 2*Ar_*Dr_*dX) / (Dr_ - Ar_), 0.0f)); 46 | Ta_ = std::max(0.0f, (Vr_ - Vi) / Ar_); 47 | Td_ = std::max(0.0f, -Vr_ / Dr_); 48 | Tv_ = 0.0f; 49 | } else { 50 | // Long move (trapezoidal profile) 51 | Tv_ = (dX - dXmin) / Vr_; 52 | } 53 | 54 | // Fill in the rest of the values used at evaluation-time 55 | Tf_ = Ta_ + Tv_ + Td_; 56 | Xi_ = Xi; 57 | Xf_ = Xf; 58 | Vi_ = Vi; 59 | yAccel_ = Xi + Vi*Ta_ + 0.5f*Ar_*SQ(Ta_); // pos at end of accel phase 60 | 61 | return true; 62 | } 63 | 64 | TrapezoidalTrajectory::Step_t TrapezoidalTrajectory::eval(float t) { 65 | Step_t trajStep; 66 | if (t < 0.0f) { // Initial Condition 67 | trajStep.Y = Xi_; 68 | trajStep.Yd = Vi_; 69 | trajStep.Ydd = 0.0f; 70 | } else if (t < Ta_) { // Accelerating 71 | trajStep.Y = Xi_ + Vi_*t + 0.5f*Ar_*SQ(t); 72 | trajStep.Yd = Vi_ + Ar_*t; 73 | trajStep.Ydd = Ar_; 74 | } else if (t < Ta_ + Tv_) { // Coasting 75 | trajStep.Y = yAccel_ + Vr_*(t - Ta_); 76 | trajStep.Yd = Vr_; 77 | trajStep.Ydd = 0.0f; 78 | } else if (t < Tf_) { // Deceleration 79 | float td = t - Tf_; 80 | trajStep.Y = Xf_ + 0.5f*Dr_*SQ(td); 81 | trajStep.Yd = Dr_*td; 82 | trajStep.Ydd = Dr_; 83 | } else if (t >= Tf_) { // Final Condition 84 | trajStep.Y = Xf_; 85 | trajStep.Yd = 0.0f; 86 | trajStep.Ydd = 0.0f; 87 | } else { 88 | // TODO: report error here 89 | } 90 | 91 | return trajStep; 92 | } -------------------------------------------------------------------------------- /MotorControl/trapTraj.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _TRAP_TRAJ_H 2 | #define _TRAP_TRAJ_H 3 | 4 | class TrapezoidalTrajectory { 5 | public: 6 | struct Config_t { 7 | float vel_limit = 2.0f; // [turn/s] 8 | float accel_limit = 0.5f; // [turn/s^2] 9 | float decel_limit = 0.5f; // [turn/s^2] 10 | }; 11 | 12 | struct Step_t { 13 | float Y; 14 | float Yd; 15 | float Ydd; 16 | }; 17 | 18 | bool planTrapezoidal(float Xf, float Xi, float Vi, 19 | float Vmax, float Amax, float Dmax); 20 | Step_t eval(float t); 21 | 22 | Axis* axis_ = nullptr; // set by Axis constructor 23 | Config_t config_; 24 | 25 | float Xi_; 26 | float Xf_; 27 | float Vi_; 28 | 29 | float Ar_; 30 | float Vr_; 31 | float Dr_; 32 | 33 | float Ta_; 34 | float Tv_; 35 | float Td_; 36 | float Tf_; 37 | 38 | float yAccel_; 39 | 40 | float t_; 41 | }; 42 | 43 | #endif -------------------------------------------------------------------------------- /MotorControl/utils.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | /** 11 | * @brief Flash size register address 12 | */ 13 | #define ID_FLASH_ADDRESS (0x1FFF7A22) 14 | 15 | /** 16 | * @brief Device ID register address 17 | */ 18 | #define ID_DBGMCU_IDCODE (0xE0042000) 19 | 20 | /** 21 | * "Returns" the device signature 22 | * 23 | * Possible returns: 24 | * - 0x0413: STM32F405xx/07xx and STM32F415xx/17xx) 25 | * - 0x0419: STM32F42xxx and STM32F43xxx 26 | * - 0x0423: STM32F401xB/C 27 | * - 0x0433: STM32F401xD/E 28 | * - 0x0431: STM32F411xC/E 29 | * 30 | * Returned data is in 16-bit mode, but only bits 11:0 are valid, bits 15:12 are always 0. 31 | * Defined as macro 32 | */ 33 | #define STM_ID_GetSignature() ((*(uint16_t *)(ID_DBGMCU_IDCODE)) & 0x0FFF) 34 | 35 | /** 36 | * "Returns" the device revision 37 | * 38 | * Revisions possible: 39 | * - 0x1000: Revision A 40 | * - 0x1001: Revision Z 41 | * - 0x1003: Revision Y 42 | * - 0x1007: Revision 1 43 | * - 0x2001: Revision 3 44 | * 45 | * Returned data is in 16-bit mode. 46 | */ 47 | #define STM_ID_GetRevision() (*(uint16_t *)(ID_DBGMCU_IDCODE + 2)) 48 | 49 | /** 50 | * "Returns" the Flash size 51 | * 52 | * Returned data is in 16-bit mode, returned value is flash size in kB (kilo bytes). 53 | */ 54 | #define STM_ID_GetFlashSize() (*(uint16_t *)(ID_FLASH_ADDRESS)) 55 | 56 | #ifdef M_PI 57 | #undef M_PI 58 | #endif 59 | 60 | // Math Constants 61 | constexpr float M_PI = 3.14159265358979323846f; 62 | constexpr float one_by_sqrt3 = 0.57735026919f; 63 | constexpr float two_by_sqrt3 = 1.15470053838f; 64 | constexpr float sqrt3_by_2 = 0.86602540378f; 65 | 66 | // Function prototypes for implementations in utils.cpp 67 | std::tuple SVM(float alpha, float beta); 68 | float fast_atan2(float y, float x); 69 | uint32_t deadline_to_timeout(uint32_t deadline_ms); 70 | uint32_t timeout_to_deadline(uint32_t timeout_ms); 71 | int is_in_the_future(uint32_t time_ms); 72 | uint32_t micros(void); 73 | void delay_us(uint32_t us); 74 | 75 | extern "C" { 76 | float our_arm_sin_f32(float x); 77 | float our_arm_cos_f32(float x); 78 | } 79 | 80 | // ---------------- 81 | // Inline functions 82 | 83 | template 84 | constexpr T SQ(const T& x){ 85 | return x * x; 86 | } 87 | 88 | /** 89 | * @brief Small helper to make array with known size 90 | * in contrast to initializer lists the number of arguments 91 | * has to match exactly. Whereas initializer lists allow 92 | * less arguments. 93 | */ 94 | template 95 | std::array make_array(T head, Tail... tail) { 96 | return std::array({head, tail...}); 97 | } 98 | 99 | // To allow use of -ffast-math we need to have a special check for nan 100 | // that bypasses the "ignore nan" flag 101 | __attribute__((optimize("-fno-finite-math-only"))) 102 | inline bool is_nan(float x) { 103 | return __builtin_isnan(x); 104 | } 105 | 106 | // Round to integer 107 | // Default rounding mode: round to nearest 108 | inline int round_int(float x) { 109 | #ifdef __arm__ 110 | int res; 111 | asm("vcvtr.s32.f32 %[res], %[x]" 112 | : [res] "=X" (res) 113 | : [x] "w" (x) ); 114 | return res; 115 | #else 116 | return (int)nearbyint(x); 117 | #endif 118 | } 119 | 120 | // Wrap value to range. 121 | // With default rounding mode (round to nearest), 122 | // the result will be in range -y/2 to y/2 123 | inline float wrap_pm(float x, float y) { 124 | #ifdef FPU_FPV4 125 | float intval = (float)round_int(x / y); 126 | #else 127 | float intval = nearbyintf(x / y); 128 | #endif 129 | return x - intval * y; 130 | } 131 | 132 | // Same as fmodf but result is positive and y must be positive 133 | inline float fmodf_pos(float x, float y) { 134 | float res = wrap_pm(x, y); 135 | if (res < 0) res += y; 136 | return res; 137 | } 138 | 139 | inline float wrap_pm_pi(float x) { 140 | return wrap_pm(x, 2 * M_PI); 141 | } 142 | 143 | // Evaluate polynomials in an efficient way 144 | // coeffs[0] is highest order, as per numpy.polyfit 145 | // p(x) = coeffs[0] * x^deg + ... + coeffs[deg], for some degree "deg" 146 | inline float horner_poly_eval(float x, const float *coeffs, size_t count) { 147 | float result = 0.0f; 148 | for (size_t idx = 0; idx < count; ++idx) 149 | result = (result * x) + coeffs[idx]; 150 | return result; 151 | } 152 | 153 | // Modulo (as opposed to remainder), per https://stackoverflow.com/a/19288271 154 | inline int mod(const int dividend, const int divisor){ 155 | int r = dividend % divisor; 156 | if (r < 0) r += divisor; 157 | return r; 158 | } 159 | -------------------------------------------------------------------------------- /ThirdParty/CMSIS/Device/ST/STM32F4xx/Include/stm32f4xx.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/embedded-idea/odrive_study/b33df272f51a02015a913ed0b92db2ca193568f0/ThirdParty/CMSIS/Device/ST/STM32F4xx/Include/stm32f4xx.h -------------------------------------------------------------------------------- /ThirdParty/CMSIS/Device/ST/STM32F4xx/Include/system_stm32f4xx.h: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * @file system_stm32f4xx.h 4 | * @author MCD Application Team 5 | * @brief CMSIS Cortex-M4 Device System Source File for STM32F4xx devices. 6 | ****************************************************************************** 7 | * @attention 8 | * 9 | *

© COPYRIGHT(c) 2017 STMicroelectronics

10 | * 11 | * Redistribution and use in source and binary forms, with or without modification, 12 | * are permitted provided that the following conditions are met: 13 | * 1. Redistributions of source code must retain the above copyright notice, 14 | * this list of conditions and the following disclaimer. 15 | * 2. Redistributions in binary form must reproduce the above copyright notice, 16 | * this list of conditions and the following disclaimer in the documentation 17 | * and/or other materials provided with the distribution. 18 | * 3. Neither the name of STMicroelectronics nor the names of its contributors 19 | * may be used to endorse or promote products derived from this software 20 | * without specific prior written permission. 21 | * 22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 23 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 25 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 28 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 29 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | * 33 | ****************************************************************************** 34 | */ 35 | 36 | /** @addtogroup CMSIS 37 | * @{ 38 | */ 39 | 40 | /** @addtogroup stm32f4xx_system 41 | * @{ 42 | */ 43 | 44 | /** 45 | * @brief Define to prevent recursive inclusion 46 | */ 47 | #ifndef __SYSTEM_STM32F4XX_H 48 | #define __SYSTEM_STM32F4XX_H 49 | 50 | #ifdef __cplusplus 51 | extern "C" { 52 | #endif 53 | 54 | /** @addtogroup STM32F4xx_System_Includes 55 | * @{ 56 | */ 57 | 58 | /** 59 | * @} 60 | */ 61 | 62 | 63 | /** @addtogroup STM32F4xx_System_Exported_types 64 | * @{ 65 | */ 66 | /* This variable is updated in three ways: 67 | 1) by calling CMSIS function SystemCoreClockUpdate() 68 | 2) by calling HAL API function HAL_RCC_GetSysClockFreq() 69 | 3) each time HAL_RCC_ClockConfig() is called to configure the system clock frequency 70 | Note: If you use this function to configure the system clock; then there 71 | is no need to call the 2 first functions listed above, since SystemCoreClock 72 | variable is updated automatically. 73 | */ 74 | extern uint32_t SystemCoreClock; /*!< System Clock Frequency (Core Clock) */ 75 | 76 | extern const uint8_t AHBPrescTable[16]; /*!< AHB prescalers table values */ 77 | extern const uint8_t APBPrescTable[8]; /*!< APB prescalers table values */ 78 | 79 | /** 80 | * @} 81 | */ 82 | 83 | /** @addtogroup STM32F4xx_System_Exported_Constants 84 | * @{ 85 | */ 86 | 87 | /** 88 | * @} 89 | */ 90 | 91 | /** @addtogroup STM32F4xx_System_Exported_Macros 92 | * @{ 93 | */ 94 | 95 | /** 96 | * @} 97 | */ 98 | 99 | /** @addtogroup STM32F4xx_System_Exported_Functions 100 | * @{ 101 | */ 102 | 103 | extern void SystemInit(void); 104 | extern void SystemCoreClockUpdate(void); 105 | /** 106 | * @} 107 | */ 108 | 109 | #ifdef __cplusplus 110 | } 111 | #endif 112 | 113 | #endif /*__SYSTEM_STM32F4XX_H */ 114 | 115 | /** 116 | * @} 117 | */ 118 | 119 | /** 120 | * @} 121 | */ 122 | /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ 123 | -------------------------------------------------------------------------------- /ThirdParty/CMSIS/Include/arm_const_structs.h: -------------------------------------------------------------------------------- 1 | /* ---------------------------------------------------------------------- 2 | * Project: CMSIS DSP Library 3 | * Title: arm_const_structs.h 4 | * Description: Constant structs that are initialized for user convenience. 5 | * For example, some can be given as arguments to the arm_cfft_f32() function. 6 | * 7 | * $Date: 27. January 2017 8 | * $Revision: V.1.5.1 9 | * 10 | * Target Processor: Cortex-M cores 11 | * -------------------------------------------------------------------- */ 12 | /* 13 | * Copyright (C) 2010-2017 ARM Limited or its affiliates. All rights reserved. 14 | * 15 | * SPDX-License-Identifier: Apache-2.0 16 | * 17 | * Licensed under the Apache License, Version 2.0 (the License); you may 18 | * not use this file except in compliance with the License. 19 | * You may obtain a copy of the License at 20 | * 21 | * www.apache.org/licenses/LICENSE-2.0 22 | * 23 | * Unless required by applicable law or agreed to in writing, software 24 | * distributed under the License is distributed on an AS IS BASIS, WITHOUT 25 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 26 | * See the License for the specific language governing permissions and 27 | * limitations under the License. 28 | */ 29 | 30 | #ifndef _ARM_CONST_STRUCTS_H 31 | #define _ARM_CONST_STRUCTS_H 32 | 33 | #include "arm_math.h" 34 | #include "arm_common_tables.h" 35 | 36 | extern const arm_cfft_instance_f32 arm_cfft_sR_f32_len16; 37 | extern const arm_cfft_instance_f32 arm_cfft_sR_f32_len32; 38 | extern const arm_cfft_instance_f32 arm_cfft_sR_f32_len64; 39 | extern const arm_cfft_instance_f32 arm_cfft_sR_f32_len128; 40 | extern const arm_cfft_instance_f32 arm_cfft_sR_f32_len256; 41 | extern const arm_cfft_instance_f32 arm_cfft_sR_f32_len512; 42 | extern const arm_cfft_instance_f32 arm_cfft_sR_f32_len1024; 43 | extern const arm_cfft_instance_f32 arm_cfft_sR_f32_len2048; 44 | extern const arm_cfft_instance_f32 arm_cfft_sR_f32_len4096; 45 | 46 | extern const arm_cfft_instance_q31 arm_cfft_sR_q31_len16; 47 | extern const arm_cfft_instance_q31 arm_cfft_sR_q31_len32; 48 | extern const arm_cfft_instance_q31 arm_cfft_sR_q31_len64; 49 | extern const arm_cfft_instance_q31 arm_cfft_sR_q31_len128; 50 | extern const arm_cfft_instance_q31 arm_cfft_sR_q31_len256; 51 | extern const arm_cfft_instance_q31 arm_cfft_sR_q31_len512; 52 | extern const arm_cfft_instance_q31 arm_cfft_sR_q31_len1024; 53 | extern const arm_cfft_instance_q31 arm_cfft_sR_q31_len2048; 54 | extern const arm_cfft_instance_q31 arm_cfft_sR_q31_len4096; 55 | 56 | extern const arm_cfft_instance_q15 arm_cfft_sR_q15_len16; 57 | extern const arm_cfft_instance_q15 arm_cfft_sR_q15_len32; 58 | extern const arm_cfft_instance_q15 arm_cfft_sR_q15_len64; 59 | extern const arm_cfft_instance_q15 arm_cfft_sR_q15_len128; 60 | extern const arm_cfft_instance_q15 arm_cfft_sR_q15_len256; 61 | extern const arm_cfft_instance_q15 arm_cfft_sR_q15_len512; 62 | extern const arm_cfft_instance_q15 arm_cfft_sR_q15_len1024; 63 | extern const arm_cfft_instance_q15 arm_cfft_sR_q15_len2048; 64 | extern const arm_cfft_instance_q15 arm_cfft_sR_q15_len4096; 65 | 66 | #endif 67 | -------------------------------------------------------------------------------- /ThirdParty/CMSIS/Include/cmsis_version.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************//** 2 | * @file cmsis_version.h 3 | * @brief CMSIS Core(M) Version definitions 4 | * @version V5.0.2 5 | * @date 19. April 2017 6 | ******************************************************************************/ 7 | /* 8 | * Copyright (c) 2009-2017 ARM Limited. All rights reserved. 9 | * 10 | * SPDX-License-Identifier: Apache-2.0 11 | * 12 | * Licensed under the Apache License, Version 2.0 (the License); you may 13 | * not use this file except in compliance with the License. 14 | * You may obtain a copy of the License at 15 | * 16 | * www.apache.org/licenses/LICENSE-2.0 17 | * 18 | * Unless required by applicable law or agreed to in writing, software 19 | * distributed under the License is distributed on an AS IS BASIS, WITHOUT 20 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 21 | * See the License for the specific language governing permissions and 22 | * limitations under the License. 23 | */ 24 | 25 | #if defined ( __ICCARM__ ) 26 | #pragma system_include /* treat file as system include file for MISRA check */ 27 | #elif defined (__clang__) 28 | #pragma clang system_header /* treat file as system include file */ 29 | #endif 30 | 31 | #ifndef __CMSIS_VERSION_H 32 | #define __CMSIS_VERSION_H 33 | 34 | /* CMSIS Version definitions */ 35 | #define __CM_CMSIS_VERSION_MAIN ( 5U) /*!< [31:16] CMSIS Core(M) main version */ 36 | #define __CM_CMSIS_VERSION_SUB ( 1U) /*!< [15:0] CMSIS Core(M) sub version */ 37 | #define __CM_CMSIS_VERSION ((__CM_CMSIS_VERSION_MAIN << 16U) | \ 38 | __CM_CMSIS_VERSION_SUB ) /*!< CMSIS Core(M) version number */ 39 | #endif 40 | -------------------------------------------------------------------------------- /ThirdParty/CMSIS/Include/tz_context.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * @file tz_context.h 3 | * @brief Context Management for Armv8-M TrustZone 4 | * @version V1.0.1 5 | * @date 10. January 2018 6 | ******************************************************************************/ 7 | /* 8 | * Copyright (c) 2017-2018 Arm Limited. All rights reserved. 9 | * 10 | * SPDX-License-Identifier: Apache-2.0 11 | * 12 | * Licensed under the Apache License, Version 2.0 (the License); you may 13 | * not use this file except in compliance with the License. 14 | * You may obtain a copy of the License at 15 | * 16 | * www.apache.org/licenses/LICENSE-2.0 17 | * 18 | * Unless required by applicable law or agreed to in writing, software 19 | * distributed under the License is distributed on an AS IS BASIS, WITHOUT 20 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 21 | * See the License for the specific language governing permissions and 22 | * limitations under the License. 23 | */ 24 | 25 | #if defined ( __ICCARM__ ) 26 | #pragma system_include /* treat file as system include file for MISRA check */ 27 | #elif defined (__clang__) 28 | #pragma clang system_header /* treat file as system include file */ 29 | #endif 30 | 31 | #ifndef TZ_CONTEXT_H 32 | #define TZ_CONTEXT_H 33 | 34 | #include 35 | 36 | #ifndef TZ_MODULEID_T 37 | #define TZ_MODULEID_T 38 | /// \details Data type that identifies secure software modules called by a process. 39 | typedef uint32_t TZ_ModuleId_t; 40 | #endif 41 | 42 | /// \details TZ Memory ID identifies an allocated memory slot. 43 | typedef uint32_t TZ_MemoryId_t; 44 | 45 | /// Initialize secure context memory system 46 | /// \return execution status (1: success, 0: error) 47 | uint32_t TZ_InitContextSystem_S (void); 48 | 49 | /// Allocate context memory for calling secure software modules in TrustZone 50 | /// \param[in] module identifies software modules called from non-secure mode 51 | /// \return value != 0 id TrustZone memory slot identifier 52 | /// \return value 0 no memory available or internal error 53 | TZ_MemoryId_t TZ_AllocModuleContext_S (TZ_ModuleId_t module); 54 | 55 | /// Free context memory that was previously allocated with \ref TZ_AllocModuleContext_S 56 | /// \param[in] id TrustZone memory slot identifier 57 | /// \return execution status (1: success, 0: error) 58 | uint32_t TZ_FreeModuleContext_S (TZ_MemoryId_t id); 59 | 60 | /// Load secure context (called on RTOS thread context switch) 61 | /// \param[in] id TrustZone memory slot identifier 62 | /// \return execution status (1: success, 0: error) 63 | uint32_t TZ_LoadContext_S (TZ_MemoryId_t id); 64 | 65 | /// Store secure context (called on RTOS thread context switch) 66 | /// \param[in] id TrustZone memory slot identifier 67 | /// \return execution status (1: success, 0: error) 68 | uint32_t TZ_StoreContext_S (TZ_MemoryId_t id); 69 | 70 | #endif // TZ_CONTEXT_H 71 | -------------------------------------------------------------------------------- /ThirdParty/CMSIS/Lib/GCC/libarm_cortexM4lf_math.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/embedded-idea/odrive_study/b33df272f51a02015a913ed0b92db2ca193568f0/ThirdParty/CMSIS/Lib/GCC/libarm_cortexM4lf_math.a -------------------------------------------------------------------------------- /ThirdParty/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_dma_ex.h: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * @file stm32f4xx_hal_dma_ex.h 4 | * @author MCD Application Team 5 | * @brief Header file of DMA HAL extension module. 6 | ****************************************************************************** 7 | * @attention 8 | * 9 | *

© COPYRIGHT(c) 2017 STMicroelectronics

10 | * 11 | * Redistribution and use in source and binary forms, with or without modification, 12 | * are permitted provided that the following conditions are met: 13 | * 1. Redistributions of source code must retain the above copyright notice, 14 | * this list of conditions and the following disclaimer. 15 | * 2. Redistributions in binary form must reproduce the above copyright notice, 16 | * this list of conditions and the following disclaimer in the documentation 17 | * and/or other materials provided with the distribution. 18 | * 3. Neither the name of STMicroelectronics nor the names of its contributors 19 | * may be used to endorse or promote products derived from this software 20 | * without specific prior written permission. 21 | * 22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 23 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 25 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 28 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 29 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | * 33 | ****************************************************************************** 34 | */ 35 | 36 | /* Define to prevent recursive inclusion -------------------------------------*/ 37 | #ifndef __STM32F4xx_HAL_DMA_EX_H 38 | #define __STM32F4xx_HAL_DMA_EX_H 39 | 40 | #ifdef __cplusplus 41 | extern "C" { 42 | #endif 43 | 44 | /* Includes ------------------------------------------------------------------*/ 45 | #include "stm32f4xx_hal_def.h" 46 | 47 | /** @addtogroup STM32F4xx_HAL_Driver 48 | * @{ 49 | */ 50 | 51 | /** @addtogroup DMAEx 52 | * @{ 53 | */ 54 | 55 | /* Exported types ------------------------------------------------------------*/ 56 | /** @defgroup DMAEx_Exported_Types DMAEx Exported Types 57 | * @brief DMAEx Exported types 58 | * @{ 59 | */ 60 | 61 | /** 62 | * @brief HAL DMA Memory definition 63 | */ 64 | typedef enum 65 | { 66 | MEMORY0 = 0x00U, /*!< Memory 0 */ 67 | MEMORY1 = 0x01U /*!< Memory 1 */ 68 | }HAL_DMA_MemoryTypeDef; 69 | 70 | /** 71 | * @} 72 | */ 73 | 74 | /* Exported functions --------------------------------------------------------*/ 75 | /** @defgroup DMAEx_Exported_Functions DMAEx Exported Functions 76 | * @brief DMAEx Exported functions 77 | * @{ 78 | */ 79 | 80 | /** @defgroup DMAEx_Exported_Functions_Group1 Extended features functions 81 | * @brief Extended features functions 82 | * @{ 83 | */ 84 | 85 | /* IO operation functions *******************************************************/ 86 | HAL_StatusTypeDef HAL_DMAEx_MultiBufferStart(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t SecondMemAddress, uint32_t DataLength); 87 | HAL_StatusTypeDef HAL_DMAEx_MultiBufferStart_IT(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t SecondMemAddress, uint32_t DataLength); 88 | HAL_StatusTypeDef HAL_DMAEx_ChangeMemory(DMA_HandleTypeDef *hdma, uint32_t Address, HAL_DMA_MemoryTypeDef memory); 89 | 90 | /** 91 | * @} 92 | */ 93 | /** 94 | * @} 95 | */ 96 | 97 | /* Private functions ---------------------------------------------------------*/ 98 | /** @defgroup DMAEx_Private_Functions DMAEx Private Functions 99 | * @brief DMAEx Private functions 100 | * @{ 101 | */ 102 | /** 103 | * @} 104 | */ 105 | 106 | /** 107 | * @} 108 | */ 109 | 110 | /** 111 | * @} 112 | */ 113 | 114 | #ifdef __cplusplus 115 | } 116 | #endif 117 | 118 | #endif /*__STM32F4xx_HAL_DMA_EX_H*/ 119 | 120 | /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ 121 | -------------------------------------------------------------------------------- /ThirdParty/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_flash_ramfunc.h: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * @file stm32f4xx_hal_flash_ramfunc.h 4 | * @author MCD Application Team 5 | * @brief Header file of FLASH RAMFUNC driver. 6 | ****************************************************************************** 7 | * @attention 8 | * 9 | *

© COPYRIGHT(c) 2017 STMicroelectronics

10 | * 11 | * Redistribution and use in source and binary forms, with or without modification, 12 | * are permitted provided that the following conditions are met: 13 | * 1. Redistributions of source code must retain the above copyright notice, 14 | * this list of conditions and the following disclaimer. 15 | * 2. Redistributions in binary form must reproduce the above copyright notice, 16 | * this list of conditions and the following disclaimer in the documentation 17 | * and/or other materials provided with the distribution. 18 | * 3. Neither the name of STMicroelectronics nor the names of its contributors 19 | * may be used to endorse or promote products derived from this software 20 | * without specific prior written permission. 21 | * 22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 23 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 25 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 28 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 29 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | * 33 | ****************************************************************************** 34 | */ 35 | 36 | /* Define to prevent recursive inclusion -------------------------------------*/ 37 | #ifndef __STM32F4xx_FLASH_RAMFUNC_H 38 | #define __STM32F4xx_FLASH_RAMFUNC_H 39 | 40 | #ifdef __cplusplus 41 | extern "C" { 42 | #endif 43 | #if defined(STM32F410Tx) || defined(STM32F410Cx) || defined(STM32F410Rx) || defined(STM32F411xE) || defined(STM32F446xx) || defined(STM32F412Zx) ||\ 44 | defined(STM32F412Vx) || defined(STM32F412Rx) || defined(STM32F412Cx) 45 | 46 | /* Includes ------------------------------------------------------------------*/ 47 | #include "stm32f4xx_hal_def.h" 48 | 49 | /** @addtogroup STM32F4xx_HAL_Driver 50 | * @{ 51 | */ 52 | 53 | /** @addtogroup FLASH_RAMFUNC 54 | * @{ 55 | */ 56 | 57 | /* Exported types ------------------------------------------------------------*/ 58 | /* Exported macro ------------------------------------------------------------*/ 59 | /* Exported functions --------------------------------------------------------*/ 60 | /** @addtogroup FLASH_RAMFUNC_Exported_Functions 61 | * @{ 62 | */ 63 | 64 | /** @addtogroup FLASH_RAMFUNC_Exported_Functions_Group1 65 | * @{ 66 | */ 67 | __RAM_FUNC HAL_StatusTypeDef HAL_FLASHEx_StopFlashInterfaceClk(void); 68 | __RAM_FUNC HAL_StatusTypeDef HAL_FLASHEx_StartFlashInterfaceClk(void); 69 | __RAM_FUNC HAL_StatusTypeDef HAL_FLASHEx_EnableFlashSleepMode(void); 70 | __RAM_FUNC HAL_StatusTypeDef HAL_FLASHEx_DisableFlashSleepMode(void); 71 | /** 72 | * @} 73 | */ 74 | 75 | /** 76 | * @} 77 | */ 78 | 79 | /** 80 | * @} 81 | */ 82 | 83 | /** 84 | * @} 85 | */ 86 | 87 | #endif /* STM32F410xx || STM32F411xE || STM32F446xx || STM32F412Zx || STM32F412Vx || STM32F412Rx || STM32F412Cx */ 88 | #ifdef __cplusplus 89 | } 90 | #endif 91 | 92 | 93 | #endif /* __STM32F4xx_FLASH_RAMFUNC_H */ 94 | 95 | /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ 96 | -------------------------------------------------------------------------------- /ThirdParty/STM32_USB_Device_Library/Core/Inc/usbd_ctlreq.h: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * @file usbd_req.h 4 | * @author MCD Application Team 5 | * @brief Header file for the usbd_req.c file 6 | ****************************************************************************** 7 | * @attention 8 | * 9 | *

© Copyright (c) 2015 STMicroelectronics. 10 | * All rights reserved.

11 | * 12 | * This software component is licensed by ST under Ultimate Liberty license 13 | * SLA0044, the "License"; You may not use this file except in compliance with 14 | * the License. You may obtain a copy of the License at: 15 | * www.st.com/SLA0044 16 | * 17 | ****************************************************************************** 18 | */ 19 | 20 | /* Define to prevent recursive inclusion -------------------------------------*/ 21 | #ifndef __USB_REQUEST_H 22 | #define __USB_REQUEST_H 23 | 24 | #ifdef __cplusplus 25 | extern "C" { 26 | #endif 27 | 28 | /* Includes ------------------------------------------------------------------*/ 29 | #include "usbd_def.h" 30 | 31 | 32 | /** @addtogroup STM32_USB_DEVICE_LIBRARY 33 | * @{ 34 | */ 35 | 36 | /** @defgroup USBD_REQ 37 | * @brief header file for the usbd_req.c file 38 | * @{ 39 | */ 40 | 41 | /** @defgroup USBD_REQ_Exported_Defines 42 | * @{ 43 | */ 44 | /** 45 | * @} 46 | */ 47 | 48 | 49 | /** @defgroup USBD_REQ_Exported_Types 50 | * @{ 51 | */ 52 | /** 53 | * @} 54 | */ 55 | 56 | 57 | 58 | /** @defgroup USBD_REQ_Exported_Macros 59 | * @{ 60 | */ 61 | /** 62 | * @} 63 | */ 64 | 65 | /** @defgroup USBD_REQ_Exported_Variables 66 | * @{ 67 | */ 68 | /** 69 | * @} 70 | */ 71 | 72 | /** @defgroup USBD_REQ_Exported_FunctionsPrototype 73 | * @{ 74 | */ 75 | 76 | USBD_StatusTypeDef USBD_StdDevReq(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req); 77 | USBD_StatusTypeDef USBD_StdItfReq(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req); 78 | USBD_StatusTypeDef USBD_StdEPReq(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req); 79 | 80 | void USBD_CtlError(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req); 81 | void USBD_ParseSetupRequest(USBD_SetupReqTypedef *req, uint8_t *pdata); 82 | void USBD_GetString(uint8_t *desc, uint8_t *unicode, uint16_t *len); 83 | 84 | /** 85 | * @} 86 | */ 87 | 88 | #ifdef __cplusplus 89 | } 90 | #endif 91 | 92 | #endif /* __USB_REQUEST_H */ 93 | 94 | /** 95 | * @} 96 | */ 97 | 98 | /** 99 | * @} 100 | */ 101 | 102 | 103 | /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ 104 | -------------------------------------------------------------------------------- /ThirdParty/STM32_USB_Device_Library/Core/Inc/usbd_ioreq.h: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * @file usbd_ioreq.h 4 | * @author MCD Application Team 5 | * @brief Header file for the usbd_ioreq.c file 6 | ****************************************************************************** 7 | * @attention 8 | * 9 | *

© Copyright (c) 2015 STMicroelectronics. 10 | * All rights reserved.

11 | * 12 | * This software component is licensed by ST under Ultimate Liberty license 13 | * SLA0044, the "License"; You may not use this file except in compliance with 14 | * the License. You may obtain a copy of the License at: 15 | * www.st.com/SLA0044 16 | * 17 | ****************************************************************************** 18 | */ 19 | 20 | /* Define to prevent recursive inclusion -------------------------------------*/ 21 | #ifndef __USBD_IOREQ_H 22 | #define __USBD_IOREQ_H 23 | 24 | #ifdef __cplusplus 25 | extern "C" { 26 | #endif 27 | 28 | /* Includes ------------------------------------------------------------------*/ 29 | #include "usbd_def.h" 30 | #include "usbd_core.h" 31 | 32 | /** @addtogroup STM32_USB_DEVICE_LIBRARY 33 | * @{ 34 | */ 35 | 36 | /** @defgroup USBD_IOREQ 37 | * @brief header file for the usbd_ioreq.c file 38 | * @{ 39 | */ 40 | 41 | /** @defgroup USBD_IOREQ_Exported_Defines 42 | * @{ 43 | */ 44 | /** 45 | * @} 46 | */ 47 | 48 | 49 | /** @defgroup USBD_IOREQ_Exported_Types 50 | * @{ 51 | */ 52 | 53 | 54 | /** 55 | * @} 56 | */ 57 | 58 | 59 | 60 | /** @defgroup USBD_IOREQ_Exported_Macros 61 | * @{ 62 | */ 63 | 64 | /** 65 | * @} 66 | */ 67 | 68 | /** @defgroup USBD_IOREQ_Exported_Variables 69 | * @{ 70 | */ 71 | 72 | /** 73 | * @} 74 | */ 75 | 76 | /** @defgroup USBD_IOREQ_Exported_FunctionsPrototype 77 | * @{ 78 | */ 79 | 80 | USBD_StatusTypeDef USBD_CtlSendData(USBD_HandleTypeDef *pdev, 81 | uint8_t *pbuf, uint32_t len); 82 | 83 | USBD_StatusTypeDef USBD_CtlContinueSendData(USBD_HandleTypeDef *pdev, 84 | uint8_t *pbuf, uint32_t len); 85 | 86 | USBD_StatusTypeDef USBD_CtlPrepareRx(USBD_HandleTypeDef *pdev, 87 | uint8_t *pbuf, uint32_t len); 88 | 89 | USBD_StatusTypeDef USBD_CtlContinueRx(USBD_HandleTypeDef *pdev, 90 | uint8_t *pbuf, uint32_t len); 91 | 92 | USBD_StatusTypeDef USBD_CtlSendStatus(USBD_HandleTypeDef *pdev); 93 | USBD_StatusTypeDef USBD_CtlReceiveStatus(USBD_HandleTypeDef *pdev); 94 | 95 | uint32_t USBD_GetRxCount(USBD_HandleTypeDef *pdev, uint8_t ep_addr); 96 | 97 | /** 98 | * @} 99 | */ 100 | 101 | #ifdef __cplusplus 102 | } 103 | #endif 104 | 105 | #endif /* __USBD_IOREQ_H */ 106 | 107 | /** 108 | * @} 109 | */ 110 | 111 | /** 112 | * @} 113 | */ 114 | /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ 115 | -------------------------------------------------------------------------------- /autogen/version.c: -------------------------------------------------------------------------------- 1 | const unsigned char fw_version_major_ = 0; 2 | const unsigned char fw_version_minor_ = 5; 3 | const unsigned char fw_version_revision_ = 6; 4 | const unsigned char fw_version_unreleased_ = 1; 5 | -------------------------------------------------------------------------------- /communication/ascii_protocol.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ASCII_PROTOCOL_HPP 2 | #define __ASCII_PROTOCOL_HPP 3 | 4 | #include 5 | #include 6 | 7 | #define MAX_LINE_LENGTH ((size_t)256) 8 | 9 | class AsciiProtocol { 10 | public: 11 | AsciiProtocol(fibre::AsyncStreamSource* rx_channel, fibre::AsyncStreamSink* tx_channel) 12 | : rx_channel_(rx_channel), sink_(*tx_channel) {} 13 | 14 | void start(); 15 | 16 | private: 17 | void cmd_set_position(char * pStr, bool use_checksum); 18 | void cmd_set_position_wl(char * pStr, bool use_checksum); 19 | void cmd_set_velocity(char * pStr, bool use_checksum); 20 | void cmd_set_torque(char * pStr, bool use_checksum); 21 | void cmd_set_trapezoid_trajectory(char * pStr, bool use_checksum); 22 | void cmd_get_feedback(char * pStr, bool use_checksum); 23 | void cmd_help(char * pStr, bool use_checksum); 24 | void cmd_info_dump(char * pStr, bool use_checksum); 25 | void cmd_system_ctrl(char * pStr, bool use_checksum); 26 | void cmd_read_property(char * pStr, bool use_checksum); 27 | void cmd_write_property(char * pStr, bool use_checksum); 28 | void cmd_update_axis_wdg(char * pStr, bool use_checksum); 29 | void cmd_unknown(char * pStr, bool use_checksum); 30 | void cmd_encoder(char * pStr, bool use_checksum); 31 | 32 | template void respond(bool include_checksum, const char * fmt, TArgs&& ... args); 33 | void process_line(fibre::cbufptr_t buffer); 34 | void on_write_finished(fibre::WriteResult result); 35 | void on_read_finished(fibre::ReadResult result); 36 | 37 | fibre::AsyncStreamSource* rx_channel_ = nullptr; 38 | uint8_t* rx_end_ = nullptr; // non-zero if an RX operation has finished but wasn't handled yet because the TX channel was busy 39 | 40 | uint8_t rx_buf_[MAX_LINE_LENGTH]; 41 | bool read_active_ = true; 42 | 43 | fibre::BufferedStreamSink<512> sink_; 44 | }; 45 | 46 | #endif // __ASCII_PROTOCOL_HPP 47 | -------------------------------------------------------------------------------- /communication/can/can_helpers.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | struct can_Message_t { 9 | uint32_t id = 0x000; // 11-bit max is 0x7ff, 29-bit max is 0x1FFFFFFF 10 | bool isExt = false; 11 | bool rtr = false; 12 | uint8_t len = 8; 13 | uint8_t buf[8] = {0, 0, 0, 0, 0, 0, 0, 0}; 14 | } ; 15 | 16 | struct can_Signal_t { 17 | const uint8_t startBit; 18 | const uint8_t length; 19 | const bool isIntel; 20 | const float factor; 21 | const float offset; 22 | }; 23 | 24 | struct can_Cyclic_t { 25 | uint32_t cycleTime_ms; 26 | uint32_t lastTime_ms; 27 | }; 28 | 29 | #include 30 | template 31 | constexpr T can_getSignal(can_Message_t msg, const uint8_t startBit, const uint8_t length, const bool isIntel) { 32 | uint64_t tempVal = 0; 33 | uint64_t mask = length < 64 ? (1ULL << length) - 1ULL : -1ULL; 34 | 35 | if (isIntel) { 36 | std::memcpy(&tempVal, msg.buf, sizeof(tempVal)); 37 | tempVal = (tempVal >> startBit) & mask; 38 | } else { 39 | std::reverse(std::begin(msg.buf), std::end(msg.buf)); 40 | std::memcpy(&tempVal, msg.buf, sizeof(tempVal)); 41 | tempVal = (tempVal >> (64 - startBit - length)) & mask; 42 | } 43 | 44 | T retVal; 45 | std::memcpy(&retVal, &tempVal, sizeof(T)); 46 | return retVal; 47 | } 48 | 49 | template 50 | constexpr void can_setSignal(can_Message_t& msg, const T& val, const uint8_t startBit, const uint8_t length, const bool isIntel) { 51 | uint64_t valAsBits = 0; 52 | std::memcpy(&valAsBits, &val, sizeof(val)); 53 | 54 | uint64_t mask = length < 64 ? (1ULL << length) - 1ULL : -1ULL; 55 | 56 | if (isIntel) { 57 | uint64_t data = 0; 58 | std::memcpy(&data, msg.buf, sizeof(data)); 59 | 60 | data &= ~(mask << startBit); 61 | data |= valAsBits << startBit; 62 | 63 | std::memcpy(msg.buf, &data, sizeof(data)); 64 | } else { 65 | uint64_t data = 0; 66 | std::reverse(std::begin(msg.buf), std::end(msg.buf)); 67 | std::memcpy(&data, msg.buf, sizeof(data)); 68 | 69 | data &= ~(mask << (64 - startBit - length)); 70 | data |= valAsBits << (64 - startBit - length); 71 | 72 | std::memcpy(msg.buf, &data, sizeof(data)); 73 | std::reverse(std::begin(msg.buf), std::end(msg.buf)); 74 | } 75 | } 76 | 77 | template 78 | void can_setSignal(can_Message_t& msg, const T& val, const uint8_t startBit, const uint8_t length, const bool isIntel, const float factor, const float offset) { 79 | T scaledVal = static_cast((val - offset) / factor); 80 | can_setSignal(msg, scaledVal, startBit, length, isIntel); 81 | } 82 | 83 | template 84 | float can_getSignal(can_Message_t msg, const uint8_t startBit, const uint8_t length, const bool isIntel, const float factor, const float offset) { 85 | T retVal = can_getSignal(msg, startBit, length, isIntel); 86 | return (retVal * factor) + offset; 87 | } 88 | 89 | template 90 | float can_getSignal(can_Message_t msg, const can_Signal_t& signal) { 91 | return can_getSignal(msg, signal.startBit, signal.length, signal.isIntel, signal.factor, signal.offset); 92 | } 93 | 94 | template 95 | void can_setSignal(can_Message_t& msg, const T& val, const can_Signal_t& signal) { 96 | can_setSignal(msg, val, signal.startBit, signal.length, signal.isIntel, signal.factor, signal.offset); 97 | } -------------------------------------------------------------------------------- /communication/can/can_simple.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __CAN_SIMPLE_HPP_ 2 | #define __CAN_SIMPLE_HPP_ 3 | 4 | #include "canbus.hpp" 5 | #include "axis.hpp" 6 | 7 | class CANSimple { 8 | public: 9 | enum { 10 | MSG_CO_NMT_CTRL = 0x000, // CANOpen NMT Message REC 11 | MSG_ODRIVE_HEARTBEAT, 12 | MSG_ODRIVE_ESTOP, 13 | MSG_GET_MOTOR_ERROR, // Errors 14 | MSG_GET_ENCODER_ERROR, 15 | MSG_GET_SENSORLESS_ERROR, 16 | MSG_SET_AXIS_NODE_ID, 17 | MSG_SET_AXIS_REQUESTED_STATE, 18 | MSG_SET_AXIS_STARTUP_CONFIG, 19 | MSG_GET_ENCODER_ESTIMATES, 20 | MSG_GET_ENCODER_COUNT, 21 | MSG_SET_CONTROLLER_MODES, 22 | MSG_SET_INPUT_POS, 23 | MSG_SET_INPUT_VEL, 24 | MSG_SET_INPUT_TORQUE, 25 | MSG_SET_LIMITS, 26 | MSG_START_ANTICOGGING, 27 | MSG_SET_TRAJ_VEL_LIMIT, 28 | MSG_SET_TRAJ_ACCEL_LIMITS, 29 | MSG_SET_TRAJ_INERTIA, 30 | MSG_GET_IQ, 31 | MSG_GET_SENSORLESS_ESTIMATES, 32 | MSG_RESET_ODRIVE, 33 | MSG_GET_BUS_VOLTAGE_CURRENT, 34 | MSG_CLEAR_ERRORS, 35 | MSG_SET_LINEAR_COUNT, 36 | MSG_SET_POS_GAIN, 37 | MSG_SET_VEL_GAINS, 38 | MSG_GET_ADC_VOLTAGE, 39 | MSG_GET_CONTROLLER_ERROR, 40 | MSG_CO_HEARTBEAT_CMD = 0x700, // CANOpen NMT Heartbeat SEND 41 | }; 42 | 43 | CANSimple(CanBusBase* canbus) : canbus_(canbus) {} 44 | 45 | bool init(); 46 | uint32_t service_stack(); 47 | 48 | private: 49 | 50 | bool renew_subscription(size_t i); 51 | bool send_heartbeat(const Axis& axis); 52 | 53 | void handle_can_message(const can_Message_t& msg); 54 | 55 | void do_command(Axis& axis, const can_Message_t& cmd); 56 | 57 | // Get functions (msg.rtr bit must be set) 58 | bool get_motor_error_callback(const Axis& axis); 59 | bool get_encoder_error_callback(const Axis& axis); 60 | bool get_controller_error_callback(const Axis& axis); 61 | bool get_sensorless_error_callback(const Axis& axis); 62 | bool get_encoder_estimates_callback(const Axis& axis); 63 | bool get_encoder_count_callback(const Axis& axis); 64 | bool get_iq_callback(const Axis& axis); 65 | bool get_sensorless_estimates_callback(const Axis& axis); 66 | bool get_bus_voltage_current_callback(const Axis& axis); 67 | // msg.rtr bit must NOT be set 68 | bool get_adc_voltage_callback(const Axis& axis, const can_Message_t& msg); 69 | 70 | // Set functions 71 | static void set_axis_nodeid_callback(Axis& axis, const can_Message_t& msg); 72 | static void set_axis_requested_state_callback(Axis& axis, const can_Message_t& msg); 73 | static void set_axis_startup_config_callback(Axis& axis, const can_Message_t& msg); 74 | static void set_input_pos_callback(Axis& axis, const can_Message_t& msg); 75 | static void set_input_vel_callback(Axis& axis, const can_Message_t& msg); 76 | static void set_input_torque_callback(Axis& axis, const can_Message_t& msg); 77 | static void set_controller_modes_callback(Axis& axis, const can_Message_t& msg); 78 | static void set_limits_callback(Axis& axis, const can_Message_t& msg); 79 | static void set_traj_vel_limit_callback(Axis& axis, const can_Message_t& msg); 80 | static void set_traj_accel_limits_callback(Axis& axis, const can_Message_t& msg); 81 | static void set_traj_inertia_callback(Axis& axis, const can_Message_t& msg); 82 | static void set_linear_count_callback(Axis& axis, const can_Message_t& msg); 83 | static void set_pos_gain_callback(Axis& axis, const can_Message_t& msg); 84 | static void set_vel_gains_callback(Axis& axis, const can_Message_t& msg); 85 | 86 | // Other functions 87 | static void nmt_callback(const Axis& axis, const can_Message_t& msg); 88 | static void estop_callback(Axis& axis, const can_Message_t& msg); 89 | static void clear_errors_callback(Axis& axis, const can_Message_t& msg); 90 | static void start_anticogging_callback(const Axis& axis, const can_Message_t& msg); 91 | 92 | static constexpr uint8_t NUM_NODE_ID_BITS = 6; 93 | static constexpr uint8_t NUM_CMD_ID_BITS = 11 - NUM_NODE_ID_BITS; 94 | 95 | // Utility functions 96 | static constexpr uint32_t get_node_id(uint32_t msgID) { 97 | return (msgID >> NUM_CMD_ID_BITS); // Upper 6 or more bits 98 | }; 99 | 100 | static constexpr uint8_t get_cmd_id(uint32_t msgID) { 101 | return (msgID & 0x01F); // Bottom 5 bits 102 | } 103 | 104 | CanBusBase* canbus_; 105 | CanBusBase::CanSubscription* subscription_handles_[AXIS_COUNT]; 106 | 107 | // TODO: we this is a hack but actually we should use protocol hooks to 108 | // renew our filter when the node ID changes 109 | uint32_t node_ids_[AXIS_COUNT]; 110 | bool extended_node_ids_[AXIS_COUNT]; 111 | }; 112 | 113 | #endif 114 | -------------------------------------------------------------------------------- /communication/can/canbus.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __CANBUS_HPP 2 | #define __CANBUS_HPP 3 | 4 | #include "can_helpers.hpp" 5 | #include 6 | 7 | struct MsgIdFilterSpecs { 8 | std::variant id; 9 | uint32_t mask; 10 | }; 11 | 12 | class CanBusBase { 13 | public: 14 | typedef void(*on_can_message_cb_t)(void* ctx, const can_Message_t& message); 15 | struct CanSubscription {}; 16 | 17 | /** 18 | * @brief Sends the specified CAN message. 19 | * 20 | * @returns: true on success or false otherwise (e.g. if the send queue is 21 | * full). 22 | */ 23 | virtual bool send_message(const can_Message_t& message) = 0; 24 | 25 | /** 26 | * @brief Registers a callback that will be invoked for every incoming CAN 27 | * message that matches the filter. 28 | * 29 | * @param handle: On success this handle is set to an opaque pointer that 30 | * can be used to cancel the subscription. 31 | * 32 | * @returns: true on success or false otherwise (e.g. if the maximum number 33 | * of subscriptions has been reached). 34 | */ 35 | virtual bool subscribe(const MsgIdFilterSpecs& filter, on_can_message_cb_t callback, void* ctx, CanSubscription** handle) = 0; 36 | 37 | /** 38 | * @brief Deregisters a callback that was previously registered with subscribe(). 39 | */ 40 | virtual bool unsubscribe(CanSubscription* handle) = 0; 41 | }; 42 | 43 | #endif // __CANBUS_HPP -------------------------------------------------------------------------------- /communication/can/odrive_can.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ODRIVE_CAN_HPP 2 | #define __ODRIVE_CAN_HPP 3 | 4 | #include 5 | 6 | #include "canbus.hpp" 7 | #include "can_simple.hpp" 8 | #include 9 | 10 | #define CAN_CLK_HZ (42000000) 11 | #define CAN_CLK_MHZ (42) 12 | 13 | // Anonymous enum for defining the most common CAN baud rates 14 | enum { 15 | CAN_BAUD_125K = 125000, 16 | CAN_BAUD_250K = 250000, 17 | CAN_BAUD_500K = 500000, 18 | CAN_BAUD_1000K = 1000000, 19 | CAN_BAUD_1M = 1000000 20 | }; 21 | 22 | class ODriveCAN : public CanBusBase, public ODriveIntf::CanIntf { 23 | public: 24 | struct Config_t { 25 | uint32_t baud_rate = CAN_BAUD_250K; 26 | Protocol protocol = PROTOCOL_SIMPLE; 27 | 28 | ODriveCAN* parent = nullptr; // set in apply_config() 29 | void set_baud_rate(uint32_t value) { parent->set_baud_rate(value); } 30 | }; 31 | 32 | ODriveCAN() {} 33 | 34 | bool apply_config(); 35 | bool start_server(CAN_HandleTypeDef* handle); 36 | 37 | Error error_ = ERROR_NONE; 38 | 39 | Config_t config_; 40 | CANSimple can_simple_{this}; 41 | 42 | osThreadId thread_id_; 43 | const uint32_t stack_size_ = 1024; // Bytes 44 | 45 | private: 46 | static const uint8_t kCanFifoNone = 0xff; 47 | 48 | struct ODriveCanSubscription : CanSubscription { 49 | uint8_t fifo = kCanFifoNone; 50 | on_can_message_cb_t callback; 51 | void* ctx; 52 | }; 53 | 54 | bool reinit(); 55 | void can_server_thread(); 56 | bool set_baud_rate(uint32_t baud_rate); 57 | void process_rx_fifo(uint32_t fifo); 58 | bool send_message(const can_Message_t& message) final; 59 | bool subscribe(const MsgIdFilterSpecs& filter, on_can_message_cb_t callback, void* ctx, CanSubscription** handle) final; 60 | bool unsubscribe(CanSubscription* handle) final; 61 | 62 | // Hardware supports at most 28 filters unless we do optimizations. For now 63 | // we don't need that many. 64 | std::array subscriptions_; 65 | CAN_HandleTypeDef *handle_ = nullptr; 66 | }; 67 | 68 | #endif // __ODRIVE_CAN_HPP 69 | -------------------------------------------------------------------------------- /communication/communication.cpp: -------------------------------------------------------------------------------- 1 | 2 | /* Includes ------------------------------------------------------------------*/ 3 | 4 | #include "communication.h" 5 | 6 | #include "interface_usb.h" 7 | #include "interface_uart.h" 8 | #include "interface_can.hpp" 9 | #include "interface_i2c.h" 10 | 11 | #include "odrive_main.h" 12 | #include "freertos_vars.h" 13 | #include "utils.hpp" 14 | 15 | #include 16 | #include 17 | //#include 18 | //#include 19 | //#include 20 | #include 21 | 22 | #include 23 | 24 | /* Private defines -----------------------------------------------------------*/ 25 | /* Private macros ------------------------------------------------------------*/ 26 | /* Private typedef -----------------------------------------------------------*/ 27 | /* Global constant data ------------------------------------------------------*/ 28 | /* Global variables ----------------------------------------------------------*/ 29 | 30 | uint64_t serial_number; 31 | char serial_number_str[13]; // 12 digits + null termination 32 | 33 | /* Private constant data -----------------------------------------------------*/ 34 | /* Private variables ---------------------------------------------------------*/ 35 | /* Private function prototypes -----------------------------------------------*/ 36 | /* Function implementations --------------------------------------------------*/ 37 | 38 | void init_communication(void) { 39 | //printf("hi!\r\n"); 40 | 41 | // Dual UART operation not supported yet 42 | if (odrv.config_.enable_uart_a && odrv.config_.enable_uart_b) { 43 | odrv.misconfigured_ = true; 44 | } 45 | 46 | if (odrv.config_.enable_uart_a && uart_a) { 47 | start_uart_server(uart_a); 48 | } else if (odrv.config_.enable_uart_b && uart_b) { 49 | start_uart_server(uart_b); 50 | } 51 | 52 | start_usb_server(); 53 | 54 | if (odrv.config_.enable_i2c_a) { 55 | start_i2c_server(); 56 | } 57 | 58 | if (odrv.config_.enable_can_a) { 59 | odrv.can_.start_server(&hcan1); 60 | } 61 | } 62 | 63 | #include 64 | 65 | 66 | extern "C" { 67 | int _write(int file, const char* data, int len) __attribute__((used)); 68 | } 69 | 70 | // @brief This is what printf calls internally 71 | int _write(int file, const char* data, int len) { 72 | fibre::cbufptr_t buf{(const uint8_t*)data, (const uint8_t*)data + len}; 73 | 74 | if (odrv.config_.uart0_protocol == ODrive::STREAM_PROTOCOL_TYPE_STDOUT || 75 | odrv.config_.uart0_protocol == ODrive::STREAM_PROTOCOL_TYPE_ASCII_AND_STDOUT) { 76 | uart0_stdout_sink.write(buf); 77 | if (!uart0_stdout_pending) { 78 | uart0_stdout_pending = true; 79 | osMessagePut(uart_event_queue, 3, 0); 80 | } 81 | } 82 | 83 | // if (odrv.config_.usb_cdc_protocol == ODrive::STREAM_PROTOCOL_TYPE_STDOUT || 84 | // odrv.config_.usb_cdc_protocol == ODrive::STREAM_PROTOCOL_TYPE_ASCII_AND_STDOUT) { 85 | // usb_cdc_stdout_sink.write(buf); 86 | // if (!usb_cdc_stdout_pending) { 87 | // usb_cdc_stdout_pending = true; 88 | // osMessagePut(usb_event_queue, 7, 0); 89 | // } 90 | // } 91 | 92 | return len; // Always pretend that we processed everything 93 | } 94 | 95 | 96 | #include "../autogen/function_stubs.hpp" 97 | 98 | ODrive& ep_root = odrv; 99 | #include "../autogen/endpoints.hpp" 100 | -------------------------------------------------------------------------------- /communication/communication.h: -------------------------------------------------------------------------------- 1 | #ifndef COMMANDS_H 2 | #define COMMANDS_H 3 | 4 | // TODO: resolve assert 5 | #define assert(expr) 6 | 7 | #ifdef __cplusplus 8 | 9 | #include 10 | #include 11 | 12 | extern "C" { 13 | #endif 14 | 15 | #include 16 | 17 | void init_communication(void); 18 | 19 | #ifdef __cplusplus 20 | } 21 | #endif 22 | 23 | #endif /* COMMANDS_H */ 24 | -------------------------------------------------------------------------------- /communication/interface_can.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __INTERFACE_CAN_HPP 2 | #define __INTERFACE_CAN_HPP 3 | 4 | //#include 5 | //#include "odrive_main.h" 6 | //#include "can_helpers.hpp" 7 | //#include 8 | //// Other protocol implementations here 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /communication/interface_i2c.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "interface_i2c.h" 3 | 4 | #include 5 | 6 | #define I2C_RX_BUFFER_SIZE 128 7 | #define I2C_RX_BUFFER_PREAMBLE_SIZE 4 8 | #define I2C_TX_BUFFER_SIZE 128 9 | 10 | I2CStats_t i2c_stats_; 11 | /* 12 | TODO: add support back 13 | 14 | static uint8_t i2c_rx_buffer[I2C_RX_BUFFER_PREAMBLE_SIZE + I2C_RX_BUFFER_SIZE]; 15 | static uint8_t i2c_tx_buffer[I2C_TX_BUFFER_SIZE]; 16 | 17 | class I2CSender : public PacketSink { 18 | public: 19 | int process_packet(const uint8_t* buffer, size_t length) { 20 | if (length >= 2 && (length - 2) <= sizeof(i2c_tx_buffer)) 21 | memcpy(i2c_tx_buffer, buffer + 2, length - 2); 22 | return 0; 23 | } 24 | size_t get_free_space() { return SIZE_MAX; } 25 | } i2c1_packet_output; 26 | BidirectionalPacketBasedChannel i2c1_channel(i2c1_packet_output); 27 | */ 28 | void start_i2c_server() { 29 | // CAN H = SDA 30 | // CAN L = SCL 31 | //HAL_I2C_EnableListen_IT(&hi2c1); 32 | } 33 | /* 34 | void i2c_handle_packet(I2C_HandleTypeDef *hi2c) { 35 | size_t received = sizeof(i2c_rx_buffer) - hi2c->XferCount; 36 | if (received > I2C_RX_BUFFER_PREAMBLE_SIZE) { 37 | i2c_stats_.rx_cnt++; 38 | 39 | write_le(0, i2c_rx_buffer); // hallucinate seq-no (not needed for I2C) 40 | i2c_rx_buffer[2] = i2c_rx_buffer[4]; // endpoint-id = I2C register address 41 | i2c_rx_buffer[3] = i2c_rx_buffer[5] | 0x80; // MSB must be 1 42 | size_t expected_bytes = (TX_BUF_SIZE - 2) < I2C_TX_BUFFER_SIZE ? (TX_BUF_SIZE - 2) : I2C_TX_BUFFER_SIZE; 43 | write_le(expected_bytes, i2c_rx_buffer + 4); // hallucinate maximum number of expected response bytes 44 | 45 | i2c1_channel.process_packet(i2c_rx_buffer, received); 46 | 47 | // reset receive buffer 48 | hi2c->pBuffPtr = I2C_RX_BUFFER_PREAMBLE_SIZE + i2c_rx_buffer; 49 | hi2c->XferCount = sizeof(i2c_rx_buffer) - I2C_RX_BUFFER_PREAMBLE_SIZE; 50 | } 51 | 52 | 53 | if (hi2c->State == HAL_I2C_STATE_BUSY_RX_LISTEN) 54 | hi2c->State = HAL_I2C_STATE_LISTEN; 55 | } 56 | 57 | 58 | void HAL_I2C_ListenCpltCallback(I2C_HandleTypeDef *hi2c) { 59 | i2c_handle_packet(hi2c); 60 | // restart listening for address 61 | HAL_I2C_EnableListen_IT(hi2c); 62 | } 63 | 64 | void HAL_I2C_AddrCallback(I2C_HandleTypeDef *hi2c, uint8_t TransferDirection, uint16_t AddrMatchCode) { 65 | i2c_stats_.addr_match_cnt += 1; 66 | 67 | i2c_handle_packet(hi2c); 68 | 69 | if (TransferDirection == I2C_DIRECTION_TRANSMIT) { 70 | HAL_I2C_Slave_Sequential_Receive_IT(hi2c, 71 | I2C_RX_BUFFER_PREAMBLE_SIZE + i2c_rx_buffer, 72 | sizeof(i2c_rx_buffer) - I2C_RX_BUFFER_PREAMBLE_SIZE, I2C_FIRST_AND_LAST_FRAME); 73 | } else { 74 | HAL_I2C_Slave_Sequential_Transmit_IT(hi2c, i2c_tx_buffer, sizeof(i2c_tx_buffer), I2C_FIRST_AND_LAST_FRAME); 75 | } 76 | } 77 | 78 | void HAL_I2C_ErrorCallback(I2C_HandleTypeDef *hi2c) { 79 | // ignore NACK errors 80 | if (!(hi2c->ErrorCode & (~HAL_I2C_ERROR_AF))) 81 | return; 82 | 83 | i2c_stats_.error_cnt += 1; 84 | 85 | // Continue listening 86 | HAL_I2C_EnableListen_IT(hi2c); 87 | } 88 | */ 89 | -------------------------------------------------------------------------------- /communication/interface_i2c.h: -------------------------------------------------------------------------------- 1 | #ifndef __INTERFACE_I2C_HPP 2 | #define __INTERFACE_I2C_HPP 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | #include 9 | 10 | struct I2CStats_t { 11 | uint8_t addr; 12 | uint32_t addr_match_cnt; 13 | uint32_t rx_cnt; 14 | uint32_t error_cnt; 15 | }; 16 | 17 | extern I2CStats_t i2c_stats_; 18 | 19 | void start_i2c_server(void); 20 | 21 | #ifdef __cplusplus 22 | } 23 | #endif 24 | 25 | #endif // __INTERFACE_I2C_HPP 26 | -------------------------------------------------------------------------------- /communication/interface_uart.h: -------------------------------------------------------------------------------- 1 | #ifndef __INTERFACE_UART_HPP 2 | #define __INTERFACE_UART_HPP 3 | 4 | 5 | #ifdef __cplusplus 6 | extern "C" { 7 | #endif 8 | 9 | #include 10 | #include "usart.h" 11 | 12 | extern osThreadId uart_thread; 13 | extern const uint32_t stack_size_uart_thread; 14 | 15 | void start_uart_server(UART_HandleTypeDef* huart); 16 | void uart_poll(void); 17 | 18 | #ifdef __cplusplus 19 | } 20 | #endif 21 | 22 | 23 | #ifdef __cplusplus 24 | #include 25 | extern fibre::BufferedStreamSink<64> uart0_stdout_sink; 26 | extern bool uart0_stdout_pending; 27 | #endif 28 | 29 | #endif // __INTERFACE_UART_HPP 30 | -------------------------------------------------------------------------------- /communication/interface_usb.h: -------------------------------------------------------------------------------- 1 | #ifndef __INTERFACE_USB_HPP 2 | #define __INTERFACE_USB_HPP 3 | 4 | 5 | #ifdef __cplusplus 6 | extern "C" { 7 | #endif 8 | 9 | #include 10 | #include 11 | 12 | extern osThreadId usb_thread; 13 | extern const uint32_t stack_size_usb_thread; 14 | 15 | typedef struct { 16 | uint32_t rx_cnt; 17 | uint32_t tx_cnt; 18 | uint32_t tx_overrun_cnt; 19 | } USBStats_t; 20 | 21 | extern USBStats_t usb_stats_; 22 | 23 | void usb_rx_process_packet(uint8_t *buf, uint32_t len, uint8_t endpoint_pair); 24 | void start_usb_server(void); 25 | 26 | #ifdef __cplusplus 27 | } 28 | #endif 29 | 30 | 31 | #ifdef __cplusplus 32 | #include 33 | extern fibre::BufferedStreamSink<64> usb_cdc_stdout_sink; 34 | extern bool usb_cdc_stdout_pending; 35 | #endif 36 | 37 | #endif // __INTERFACE_USB_HPP 38 | -------------------------------------------------------------------------------- /fibre-cpp/channel_discoverer.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace fibre; 8 | 9 | bool ChannelDiscoverer::try_parse_key(const char* begin, const char* end, const char* key, const char** val_begin, const char** val_end) { 10 | ssize_t keylen = strlen(key); 11 | 12 | while (begin != end) { 13 | const char* next_delim = std::find(begin, end, ','); 14 | 15 | if ((next_delim - begin >= keylen) && (memcmp(begin, key, keylen) == 0)) { 16 | if (next_delim - begin == keylen) { 17 | // The key exists but has no value 18 | *val_begin = *val_end = next_delim; 19 | return true; 20 | } else if (begin[keylen] == '=') { 21 | *val_begin = begin + keylen + 1; 22 | *val_end = next_delim; 23 | return true; 24 | } 25 | } 26 | 27 | begin = std::min(next_delim + 1, end); 28 | } 29 | 30 | return false; // key not found 31 | } 32 | 33 | bool ChannelDiscoverer::try_parse_key(const char* begin, const char* end, const char* key, int* val) { 34 | const char* val_begin; 35 | const char* val_end; 36 | if (!try_parse_key(begin, end, key, &val_begin, &val_end)) { 37 | return false; 38 | } 39 | 40 | // Copy value to a null-terminated buffer 41 | char buf[val_end - val_begin + 1]; 42 | memcpy(buf, val_begin, val_end - val_begin); 43 | buf[val_end - val_begin] = 0; 44 | 45 | return sscanf(buf, "0x%x", val) == 1 46 | || sscanf(buf, "%d", val) == 1; 47 | } 48 | -------------------------------------------------------------------------------- /fibre-cpp/crc.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __CRC_HPP 2 | #define __CRC_HPP 3 | 4 | #include 5 | #include 6 | 7 | // Calculates an arbitrary CRC for one byte. 8 | // Adapted from https://barrgroup.com/Embedded-Systems/How-To/CRC-Calculation-C-Code 9 | template 10 | static T calc_crc(T remainder, uint8_t value) { 11 | constexpr T BIT_WIDTH = (CHAR_BIT * sizeof(T)); 12 | constexpr T TOPBIT = ((T)1 << (BIT_WIDTH - 1)); 13 | 14 | // Bring the next byte into the remainder. 15 | remainder ^= (value << (BIT_WIDTH - 8)); 16 | 17 | // Perform modulo-2 division, a bit at a time. 18 | for (uint8_t bit = 8; bit; --bit) { 19 | if (remainder & TOPBIT) { 20 | remainder = (remainder << 1) ^ POLYNOMIAL; 21 | } else { 22 | remainder = (remainder << 1); 23 | } 24 | } 25 | 26 | return remainder; 27 | } 28 | 29 | template 30 | static T calc_crc(T remainder, const uint8_t* buffer, size_t length) { 31 | while (length--) 32 | remainder = calc_crc(remainder, *(buffer++)); 33 | return remainder; 34 | } 35 | 36 | template 37 | static uint8_t calc_crc8(uint8_t remainder, uint8_t value) { 38 | return calc_crc(remainder, value); 39 | } 40 | 41 | template 42 | static uint16_t calc_crc16(uint16_t remainder, uint8_t value) { 43 | return calc_crc(remainder, value); 44 | } 45 | 46 | template 47 | static uint8_t calc_crc8(uint8_t remainder, const uint8_t* buffer, size_t length) { 48 | return calc_crc(remainder, buffer, length); 49 | } 50 | 51 | template 52 | static uint16_t calc_crc16(uint16_t remainder, const uint8_t* buffer, size_t length) { 53 | return calc_crc(remainder, buffer, length); 54 | } 55 | 56 | #endif /* __CRC_HPP */ 57 | -------------------------------------------------------------------------------- /fibre-cpp/endpoints_template.j2: -------------------------------------------------------------------------------- 1 | /*[# This is the original template, thus the warning below does not apply to this file #] 2 | * ============================ WARNING ============================ 3 | * ==== This is an autogenerated file. ==== 4 | * ==== Any changes to this file will be lost when recompiling. ==== 5 | * ================================================================= 6 | * 7 | * This file contains the toplevel handler for Fibre v0.1 endpoint operations. 8 | * 9 | * This endpoint-oriented approach will be deprecated in Fibre v0.2 in favor of 10 | * a function-oriented approach and a more powerful object model. 11 | * 12 | */ 13 | #ifndef __FIBRE_ENDPOINTS_HPP 14 | #define __FIBRE_ENDPOINTS_HPP 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | // Note: with -Og the functions with large switch statements reserves a huge amount 21 | // of stack space because they reserves separate space for the stack frame of each 22 | // of the inlined functions. 23 | // The minimum known set of flags to prevent this is `-O1 -fipa-sra`. 24 | // `-O2`, `-O3` and `-Os` are supersets of this. 25 | 26 | #pragma GCC push_options 27 | #pragma GCC optimize ("s") 28 | 29 | namespace fibre { 30 | 31 | const unsigned char embedded_json[] = [[embedded_endpoint_definitions | to_c_string]]; 32 | const size_t embedded_json_length = sizeof(embedded_json) - 1; 33 | const uint16_t json_crc_ = calc_crc16(PROTOCOL_VERSION, embedded_json, embedded_json_length); 34 | const uint32_t json_version_id_ = (json_crc_ << 16) | calc_crc16(json_crc_, embedded_json, embedded_json_length); 35 | 36 | static void get_property(Introspectable& result, size_t idx) { 37 | switch (idx) { 38 | [%- for endpoint in endpoints %] 39 | [%- if endpoint.function.name == 'exchange' and endpoint.in_bindings | list == ['obj'] %] 40 | case [[endpoint.id]]: { [[(endpoint.in_bindings['obj'] + '$') | replace(')$', ', &result.storage_)')]]; result.type_info_ = &FibrePropertyTypeInfo<[[endpoint.function.in['obj'].type.c_name]]>::singleton; } break; 41 | [%- endif %] 42 | [%- endfor %] 43 | default: break; 44 | } 45 | } 46 | 47 | 48 | bool endpoint_handler(int idx, cbufptr_t* input_buffer, bufptr_t* output_buffer) { 49 | //Introspectable property = get_property(idx); 50 | //if property.is_valid() 51 | 52 | switch (idx) { 53 | [%- for endpoint in endpoints %] 54 | [%- if (endpoint.function.name == 'exchange' or endpoint.function.name == 'read') and endpoint.in_bindings | list == ['obj'] %] 55 | case [[endpoint.id]]: { return [[endpoint.function.fullname | to_snake_case]]([% for k, arg in endpoint.function.in.items() %][% if k in endpoint.in_bindings %]static_cast<[[arg.type.c_name]]>([[endpoint.in_bindings[k]]])[% else %]std::nullopt[% endif %], [% endfor %][% for k, arg in endpoint.function.out.items() %][% if k in endpoint.out_bindings %]static_cast<[[arg.type.c_name]]*>([[endpoint.out_bindings[k]]])[% else %]nullptr[% endif %], [% endfor %]input_buffer, output_buffer); } break; 56 | [%- else %] 57 | case [[endpoint.id]]: { return [[endpoint.function.fullname | to_snake_case]]([% for k, arg in endpoint.function.in.items() %][% if k in endpoint.in_bindings %]static_cast<[[arg.type.c_name]]>([[endpoint.in_bindings[k]]])[% else %]std::nullopt[% endif %], [% endfor %][% for k, arg in endpoint.function.out.items() %][% if k in endpoint.out_bindings %]static_cast<[[arg.type.c_name]]*>([[endpoint.out_bindings[k]]])[% else %]nullptr[% endif %], [% endfor %]input_buffer, output_buffer); } break; 58 | [%- endif %] 59 | [%- endfor %] 60 | default: return false; 61 | } 62 | } 63 | 64 | bool is_endpoint_ref_valid(endpoint_ref_t endpoint_ref) { 65 | if (endpoint_ref.json_crc != json_crc_) { 66 | return false; 67 | } 68 | 69 | switch (endpoint_ref.endpoint_id) { 70 | [%- for endpoint in endpoints %] 71 | case [[endpoint.id]]: return true; 72 | [%- endfor %] 73 | default: return false; 74 | } 75 | } 76 | 77 | bool set_endpoint_from_float(endpoint_ref_t endpoint_ref, float value) { 78 | if (endpoint_ref.json_crc != json_crc_) { 79 | return false; 80 | } 81 | 82 | Introspectable property{}; 83 | get_property(property, endpoint_ref.endpoint_id); 84 | const FloatSettableTypeInfo* type_info = dynamic_cast(property.get_type_info()); 85 | return type_info && type_info->set_float(property, value); 86 | } 87 | 88 | } 89 | 90 | #pragma GCC pop_options 91 | 92 | #endif // __FIBRE_ENDPOINTS_HPP -------------------------------------------------------------------------------- /fibre-cpp/function_stubs_template.j2: -------------------------------------------------------------------------------- 1 | /*[# This is the original template, thus the warning below does not apply to this file #] 2 | * ============================ WARNING ============================ 3 | * ==== This is an autogenerated file. ==== 4 | * ==== Any changes to this file will be lost when recompiling. ==== 5 | * ================================================================= 6 | * 7 | * This file contains serializing/deserializing stubs for the functions defined 8 | * in your interface file. 9 | * 10 | */ 11 | 12 | #include 13 | 14 | [% for intf in interfaces.values() %] 15 | [% for func in intf.functions.values() %] 16 | static inline bool [[func.fullname | to_snake_case]]([% for arg in func.in.values() %]std::optional<[[arg.type.c_name]]> in_[[arg.name]], [% endfor %][% for arg in func.out.values() %][[arg.type.c_name]]* out_[[arg.name]], [% endfor %]fibre::cbufptr_t* input_buffer, fibre::bufptr_t* output_buffer) { 17 | [%- if func.in %] 18 | bool success = [% for arg in func.in.values() %](in_[[arg.name]].has_value() || (in_[[arg.name]] = fibre::Codec<[[arg.type.c_name]]>::decode(input_buffer)).has_value()[% if arg.optional %] || true[% endif %])[% if not loop.last %] 19 | && [% endif %][% endfor %]; 20 | [%- else %] 21 | bool success = true; 22 | [%- endif %] 23 | if (!success) { 24 | return false; 25 | } 26 | [%- if func.implementation %] 27 | [% if func.out %]std::tuple<[% for arg in func.out.values() %][[arg.type.c_name]][[', ' if not loop.last]][% endfor %]> ret = [% endif %][[func.implementation]]([% for arg in func.in.values() %](*in_[[arg.name]][% if not arg.optional %])[% endif %][[', ' if not loop.last]][% endfor %]); 28 | [%- else %] 29 | [% if func.out %]std::tuple<[% for arg in func.out.values() %][[arg.type.c_name]][[', ' if not loop.last]][% endfor %]> ret = [% endif %](*in_[[(func.in.values() | first).name]])->[[func.name]]([% for arg in func.in.values() | skip_first %][% if not arg.optional %]*[% endif %]in_[[arg.name]][[', ' if not loop.last]][% endfor %]); 30 | [%- endif %] 31 | [%- if func.out %] 32 | return [% for arg in func.out.values() %]((out_[[arg.name]] && ((*out_[[arg.name]] = std::get<[[loop.index0]]>(ret)), true)) || fibre::Codec<[[arg.type.c_name]]>::encode(std::get<[[loop.index0]]>(ret), output_buffer))[% if not loop.last %] 33 | && [% endif %][% endfor %]; 34 | [%- else %] 35 | return true; 36 | [%- endif %] 37 | } 38 | [% endfor %] 39 | [% endfor %] 40 | 41 | -------------------------------------------------------------------------------- /fibre-cpp/include/fibre/bufptr.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __FIBRE_BUFPTR_HPP 2 | #define __FIBRE_BUFPTR_HPP 3 | 4 | #include 5 | #include 6 | 7 | namespace fibre { 8 | 9 | static inline bool soft_assert(bool expr) { return expr; } // TODO: implement 10 | 11 | /** 12 | * @brief Holds a reference to a buffer and a length. 13 | * Since this class implements begin() and end(), you can use it with many 14 | * standard algorithms that operate on iterable objects. 15 | */ 16 | template 17 | struct generic_bufptr_t { 18 | using iterator = T*; 19 | using const_iterator = const T*; 20 | 21 | generic_bufptr_t(T* begin, size_t length) : begin_(begin), end_(begin + length) {} 22 | 23 | generic_bufptr_t(T* begin, T* end) : begin_(begin), end_(end) {} 24 | 25 | generic_bufptr_t() : begin_(nullptr), end_(nullptr) {} 26 | 27 | template 28 | generic_bufptr_t(T (&begin)[I]) : generic_bufptr_t(begin, I) {} 29 | 30 | generic_bufptr_t(std::vector::type>& vector) 31 | : generic_bufptr_t(vector.data(), vector.size()) {} 32 | 33 | generic_bufptr_t(const std::vector::type>& vector) 34 | : generic_bufptr_t(vector.data(), vector.size()) {} 35 | 36 | generic_bufptr_t(const generic_bufptr_t::type>& other) 37 | : generic_bufptr_t(other.begin(), other.end()) {} 38 | 39 | generic_bufptr_t& operator+=(size_t num) { 40 | if (!soft_assert(num <= size())) { 41 | num = size(); 42 | } 43 | begin_ += num; 44 | return *this; 45 | } 46 | 47 | generic_bufptr_t operator++(int) { 48 | generic_bufptr_t result = *this; 49 | *this += 1; 50 | return result; 51 | } 52 | 53 | T& operator*() { 54 | return *begin_; 55 | } 56 | 57 | generic_bufptr_t take(size_t num) const { 58 | if (!soft_assert(num <= size())) { 59 | num = size(); 60 | } 61 | generic_bufptr_t result = {begin_, num}; 62 | return result; 63 | } 64 | 65 | generic_bufptr_t skip(size_t num, size_t* processed_bytes = nullptr) const { 66 | if (!soft_assert(num <= size())) { 67 | num = size(); 68 | } 69 | if (processed_bytes) 70 | (*processed_bytes) += num; 71 | return {begin_ + num, end_}; 72 | } 73 | 74 | size_t size() const { 75 | return end_ - begin_; 76 | } 77 | 78 | bool empty() const { 79 | return size() == 0; 80 | } 81 | 82 | T*& begin() { return begin_; } 83 | T*& end() { return end_; } 84 | T* const & begin() const { return begin_; } 85 | T* const & end() const { return end_; } 86 | T& front() const { return *begin(); } 87 | T& back() const { return *(end() - 1); } 88 | T& operator[](size_t idx) { return *(begin() + idx); } 89 | 90 | private: 91 | T* begin_; 92 | T* end_; 93 | }; 94 | 95 | using cbufptr_t = generic_bufptr_t; 96 | using bufptr_t = generic_bufptr_t; 97 | 98 | } 99 | 100 | #endif // __FIBRE_BUFPTR_HPP 101 | -------------------------------------------------------------------------------- /fibre-cpp/include/fibre/callback.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __CALLBACK_HPP 2 | #define __CALLBACK_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace fibre { 11 | 12 | namespace detail { 13 | template struct get_default { static T val() { return {}; } }; 14 | template<> struct get_default { static void val() {} }; 15 | } 16 | 17 | template 18 | class Callback { 19 | public: 20 | Callback() : cb_(nullptr), ctx_(nullptr) {} 21 | Callback(std::nullptr_t) : cb_(nullptr), ctx_(nullptr) {} 22 | Callback(TRet(*callback)(void*, TArgs...), void* ctx) : 23 | cb_(callback), ctx_(ctx) {} 24 | 25 | /** 26 | * @brief Creates a copy of another Callback instance. 27 | * 28 | * This is only works it the other callback has identical template parameters. 29 | * This constructor is templated so that construction from an incompatible 30 | * callback gives a useful error message. 31 | */ 32 | //template 33 | //Callback(const Callback& other) : cb_(other.cb_), ctx_(other.ctx_) { 34 | // static_assert(std::is_same, Callback>::value, "incompatible callback type"); 35 | //} 36 | 37 | Callback(const Callback& other) : cb_(other.cb_), ctx_(other.ctx_) {} 38 | 39 | // If you get a compile error "[...] invokes a deleted function" that points 40 | // here then you're probably trying to assign a Callback with incompatible 41 | // template arguments to another Callback. 42 | template 43 | Callback(const Callback& other) = delete; 44 | 45 | /** 46 | * @brief Constructs a callback object from a functor. The functor must 47 | * remain allocated throughout the lifetime of the Callback. 48 | */ 49 | template 50 | Callback(const TFunc& func) : 51 | cb_([](void* ctx, TArgs...args){ 52 | return (*(const TFunc*)ctx)(args...); 53 | }), ctx_((void*)&func) {} 54 | 55 | operator bool() { 56 | return cb_; 57 | } 58 | 59 | TRet invoke(TArgs ... arg) const { 60 | if (cb_) { 61 | return (*cb_)(ctx_, arg...); 62 | } 63 | return detail::get_default::val(); 64 | } 65 | 66 | TRet invoke_and_clear(TArgs ... arg) { 67 | void* ctx = ctx_; 68 | auto cb = cb_; 69 | ctx_ = nullptr; 70 | cb_ = nullptr; 71 | if (cb) { 72 | return (*cb)(ctx, arg...); 73 | } 74 | return detail::get_default::val(); 75 | } 76 | 77 | typedef TRet(*cb_t)(void*, TArgs...); 78 | cb_t get_ptr() { return cb_; } 79 | void* get_ctx() { return ctx_; } 80 | 81 | private: 82 | TRet(*cb_)(void*, TArgs...); 83 | void* ctx_; 84 | }; 85 | 86 | template 87 | struct function_traits { 88 | using TRet = _TRet; 89 | using TArgs = std::tuple<_TArgs...>; 90 | using TObj = _TObj; 91 | }; 92 | 93 | template 94 | function_traits<_TRet, _TObj, _TArgs...> make_function_traits(_TRet (_TObj::*)(_TArgs...)) { 95 | return {}; 96 | } 97 | 98 | template 99 | struct MemberCallback; 100 | 101 | template 102 | struct MemberCallback> { 103 | using cb_t = Callback; 104 | static cb_t with(TObj* obj) { 105 | return cb_t{[](void* obj, TArgs... arg) { 106 | return (((TObj*)obj)->*func)(arg...); 107 | }, obj}; 108 | } 109 | }; 110 | 111 | template> 114 | typename MemCb::cb_t make_callback(typename TTraits::TObj* obj) { 115 | return MemCb::with(obj); 116 | } 117 | 118 | #define MEMBER_CB(obj, func) \ 119 | fibre::make_callback< \ 120 | decltype(&std::remove_reference_t::func), \ 121 | &std::remove_reference_t::func \ 122 | >(obj) 123 | 124 | } 125 | 126 | #endif // __CALLBACK_HPP -------------------------------------------------------------------------------- /fibre-cpp/include/fibre/channel_discoverer.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __FIBRE_CHANNEL_DISCOVERER 2 | #define __FIBRE_CHANNEL_DISCOVERER 3 | 4 | #include "async_stream.hpp" 5 | #include 6 | #include 7 | 8 | namespace fibre { 9 | 10 | struct ChannelDiscoveryResult { 11 | Status status; 12 | AsyncStreamSource* rx_channel; 13 | AsyncStreamSink* tx_channel; 14 | size_t mtu; 15 | }; 16 | 17 | struct ChannelDiscoveryContext {}; 18 | 19 | class Domain; // defined in fibre.hpp 20 | 21 | class ChannelDiscoverer { 22 | public: 23 | // TODO: maybe we should remove "handle" because a discovery can also be 24 | // uniquely identified by domain. 25 | virtual void start_channel_discovery( 26 | Domain* domain, 27 | const char* specs, size_t specs_len, 28 | ChannelDiscoveryContext** handle) = 0; 29 | virtual int stop_channel_discovery(ChannelDiscoveryContext* handle) = 0; 30 | 31 | protected: 32 | bool try_parse_key(const char* begin, const char* end, const char* key, const char** val_begin, const char** val_end); 33 | bool try_parse_key(const char* begin, const char* end, const char* key, int* val); 34 | }; 35 | 36 | } 37 | 38 | #endif // __FIBRE_CHANNEL_DISCOVERER -------------------------------------------------------------------------------- /fibre-cpp/include/fibre/event_loop.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __FIBRE_EVENT_LOOP_HPP 2 | #define __FIBRE_EVENT_LOOP_HPP 3 | 4 | #include "callback.hpp" 5 | #include 6 | 7 | namespace fibre { 8 | 9 | struct EventLoopTimer; 10 | 11 | /** 12 | * @brief Base class for event loops. 13 | * 14 | * Thread-safety: The public functions of this class except for post() must not 15 | * be assumed to be thread-safe. 16 | * Generally the functions of an event loop are only safe to be called from the 17 | * event loop's thread itself. 18 | */ 19 | class EventLoop { 20 | public: 21 | /** 22 | * @brief Registers a callback for immediate execution on the event loop 23 | * thread. 24 | * 25 | * This function must be thread-safe. 26 | */ 27 | virtual bool post(Callback callback) = 0; 28 | 29 | /** 30 | * @brief Registers the given file descriptor on this event loop. 31 | * 32 | * This function is only implemented on Unix-like systems. 33 | * 34 | * @param fd: A waitable Unix file descriptor on which to listen for events. 35 | * @param events: A bitfield that specifies the events to listen for. 36 | * For instance EPOLLIN or EPOLLOUT. 37 | * @param callback: The callback to invoke every time the event triggers. 38 | * A bitfield is passed to the callback to indicate which events were 39 | * triggered. This callback must remain valid until 40 | * deregister_event() is called for the same file descriptor. 41 | */ 42 | virtual bool register_event(int fd, uint32_t events, Callback callback) = 0; 43 | 44 | /** 45 | * @brief Deregisters the given event. 46 | * 47 | * Once this function returns, the associated callback will no longer be 48 | * invoked and its resources can be freed. 49 | */ 50 | virtual bool deregister_event(int fd) = 0; 51 | 52 | /** 53 | * @brief Registers a callback to be called at a later point in time. 54 | * 55 | * This returns an opaque handler which can be used to cancel the timer. 56 | * 57 | * @param delay: The delay from now in seconds. 58 | * TOOD: specify if OS sleep time is counted in. 59 | */ 60 | virtual struct EventLoopTimer* call_later(float delay, Callback callback) = 0; 61 | 62 | /** 63 | * @brief Cancels a timer which was previously started by call_later(). 64 | * 65 | * Must not be called after invokation of the callback has started. 66 | * This also means that cancel_timer() must not be called from within the 67 | * callback of the timer itself. 68 | */ 69 | virtual bool cancel_timer(EventLoopTimer* timer) = 0; 70 | }; 71 | 72 | } 73 | 74 | #endif // __FIBRE_EVENT_LOOP_HPP -------------------------------------------------------------------------------- /fibre-cpp/include/fibre/fibre.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __FIBRE_HPP 2 | #define __FIBRE_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #if FIBRE_ENABLE_LIBUSB_BACKEND 13 | #include "../../platform_support/libusb_transport.hpp" 14 | #endif 15 | 16 | #if FIBRE_ENABLE_TCP_CLIENT_BACKEND 17 | #include "../../platform_support/posix_tcp_backend.hpp" 18 | #endif 19 | 20 | namespace fibre { 21 | 22 | struct CallBuffers { 23 | Status status; 24 | cbufptr_t tx_buf; 25 | bufptr_t rx_buf; 26 | }; 27 | 28 | struct CallBufferRelease { 29 | Status status; 30 | const uint8_t* tx_end; 31 | uint8_t* rx_end; 32 | }; 33 | 34 | struct Function { 35 | virtual std::optional 36 | call(void**, CallBuffers, Callback, CallBufferRelease>) = 0; 37 | }; 38 | 39 | struct Object; 40 | struct Interface; 41 | class Domain; 42 | 43 | template 44 | struct StaticBackend { 45 | std::string name; 46 | T impl; 47 | }; 48 | 49 | struct Context { 50 | size_t n_domains = 0; 51 | EventLoop* event_loop; 52 | 53 | std::tuple< 54 | #if FIBRE_ENABLE_LIBUSB_BACKEND 55 | LibusbDiscoverer 56 | #endif 57 | #if FIBRE_ENABLE_LIBUSB_BACKEND && FIBRE_ENABLE_TCP_CLIENT_BACKEND 58 | , // TODO: find a less awkward way to do this 59 | #endif 60 | #if FIBRE_ENABLE_TCP_CLIENT_BACKEND 61 | PosixTcpClientBackend 62 | #endif 63 | #if FIBRE_ENABLE_TCP_CLIENT_BACKEND && FIBRE_ENABLE_TCP_SERVER_BACKEND 64 | , // TODO: find a less awkward way to do this 65 | #endif 66 | #if FIBRE_ENABLE_TCP_SERVER_BACKEND 67 | PosixTcpServerBackend 68 | #endif 69 | > static_backends; 70 | 71 | #if FIBRE_ALLOW_HEAP 72 | std::unordered_map discoverers; 73 | #endif 74 | 75 | /** 76 | * @brief Creates a domain on which objects can subsequently be published 77 | * and discovered. 78 | * 79 | * This potentially starts looking for channels on this domain. 80 | */ 81 | Domain* create_domain(std::string specs); 82 | void close_domain(Domain* domain); 83 | 84 | void register_backend(std::string name, ChannelDiscoverer* backend); 85 | void deregister_backend(std::string name); 86 | }; 87 | 88 | // TODO: don't declare these types here 89 | struct LegacyProtocolPacketBased; 90 | class LegacyObjectClient; 91 | struct LegacyObject; 92 | 93 | class Domain { 94 | friend struct Context; 95 | public: 96 | #if FIBRE_ENABLE_CLIENT 97 | // TODO: add interface argument 98 | // TODO: support multiple discovery instances 99 | void start_discovery(Callback on_found_object, Callback on_lost_object); 100 | void stop_discovery(); 101 | #endif 102 | 103 | void add_channels(ChannelDiscoveryResult result); 104 | 105 | Context* ctx; 106 | private: 107 | #if FIBRE_ENABLE_CLIENT 108 | void on_found_root_object(LegacyObjectClient* obj_client, std::shared_ptr obj); 109 | void on_lost_root_object(LegacyObjectClient* obj_client, std::shared_ptr obj); 110 | #endif 111 | void on_stopped(LegacyProtocolPacketBased* protocol, StreamStatus status); 112 | 113 | #if FIBRE_ALLOW_HEAP 114 | std::unordered_map channel_discovery_handles; 115 | #endif 116 | #if FIBRE_ENABLE_CLIENT 117 | Callback on_found_object_; 118 | Callback on_lost_object_; 119 | std::unordered_map root_objects_; 120 | #endif 121 | }; 122 | 123 | /** 124 | * @brief Opens and initializes a Fibre context. 125 | * 126 | * If FIBRE_ALLOW_HEAP=0 only one Fibre context can be open at a time. 127 | * 128 | * @returns: A non-null pointer on success, null otherwise. 129 | */ 130 | Context* open(EventLoop* event_loop); 131 | 132 | void close(Context*); 133 | 134 | /** 135 | * @brief Launches an event loop on the current thread. 136 | * 137 | * This function returns when the event loop becomes empty. 138 | * 139 | * If FIBRE_ALLOW_HEAP=0 only one event loop can be running at a time. 140 | * 141 | * This function returns false if Fibre was compiled with 142 | * FIBRE_ENABLE_EVENT_LOOP=0. 143 | * 144 | * @param on_started: This function is the first event that is placed on the 145 | * event loop. This function usually creates further events, for instance 146 | * by calling open(). 147 | * @returns: true if the event loop ran to completion. False if this function is 148 | * not implemented on this operating system or if another error 149 | * occurred. 150 | */ 151 | bool launch_event_loop(Callback on_started); 152 | 153 | } 154 | 155 | #endif // __FIBRE_HPP -------------------------------------------------------------------------------- /fibre-cpp/include/fibre/status.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __FIBRE_STATUS_HPP 2 | #define __FIBRE_STATUS_HPP 3 | 4 | namespace fibre { 5 | 6 | enum Status { 7 | kFibreOk, 8 | kFibreBusy, // 5 | #include 6 | #include 7 | 8 | namespace fibre { 9 | 10 | template 11 | constexpr size_t hex_digits() { 12 | return (std::numeric_limits::digits + 3) / 4; 13 | } 14 | 15 | /* @brief Converts a hexadecimal digit to a uint8_t. 16 | * @param output If not null, the digit's value is stored in this output 17 | * Returns true if the char is a valid hex digit, false otherwise 18 | */ 19 | static inline bool hex_digit_to_byte(char ch, uint8_t* output) { 20 | uint8_t nil_output = 0; 21 | if (!output) 22 | output = &nil_output; 23 | if (ch >= '0' && ch <= '9') 24 | return (*output) = ch - '0', true; 25 | if (ch >= 'a' && ch <= 'f') 26 | return (*output) = ch - 'a' + 10, true; 27 | if (ch >= 'A' && ch <= 'F') 28 | return (*output) = ch - 'A' + 10, true; 29 | return false; 30 | } 31 | 32 | /* @brief Converts a hex string to an integer 33 | * @param output If not null, the result is stored in this output 34 | * Returns true if the string represents a valid hex value, false otherwise. 35 | */ 36 | template 37 | bool hex_string_to_int(const char * str, size_t length, TInt* output) { 38 | constexpr size_t N_DIGITS = hex_digits(); 39 | TInt result = 0; 40 | if (length > N_DIGITS) 41 | length = N_DIGITS; 42 | for (size_t i = 0; i < length && str[i]; i++) { 43 | uint8_t digit = 0; 44 | if (!hex_digit_to_byte(str[i], &digit)) 45 | return false; 46 | result <<= 4; 47 | result += digit; 48 | } 49 | if (output) 50 | *output = result; 51 | return true; 52 | } 53 | 54 | template 55 | bool hex_string_to_int(const char * str, TInt* output) { 56 | return hex_string_to_int(str, hex_digits(), output); 57 | } 58 | 59 | template 60 | bool hex_string_to_int_arr(const char * str, size_t length, TInt (&output)[ICount]) { 61 | for (size_t i = 0; i < ICount; i++) { 62 | if (!hex_string_to_int(&str[i * hex_digits()], &output[i])) 63 | return false; 64 | } 65 | return true; 66 | } 67 | 68 | template 69 | bool hex_string_to_int_arr(const char * str, TInt (&output)[ICount]) { 70 | return hex_string_to_int_arr(str, hex_digits() * ICount, output); 71 | } 72 | 73 | // TODO: move to print_utils.hpp 74 | template 75 | class HexPrinter { 76 | public: 77 | HexPrinter(T val, bool prefix) : val_(val) /*, prefix_(prefix)*/ { 78 | const char digits[] = "0123456789abcdef"; 79 | size_t prefix_length = prefix ? 2 : 0; 80 | if (prefix) { 81 | str[0] = '0'; 82 | str[1] = 'x'; 83 | } 84 | str[prefix_length + hex_digits()] = '\0'; 85 | 86 | for (size_t i = 0; i < hex_digits(); ++i) { 87 | str[prefix_length + hex_digits() - i - 1] = digits[val & 0xf]; 88 | val >>= 4; 89 | } 90 | } 91 | std::string to_string() const { return str; } 92 | void to_string(char* buf) const { 93 | for (size_t i = 0; (i < sizeof(str)) && str[i]; ++i) 94 | buf[i] = str[i]; 95 | } 96 | 97 | T val_; 98 | //bool prefix_; 99 | char str[hex_digits() + 3]; // 3 additional characters 0x and \0 100 | }; 101 | 102 | template 103 | std::ostream& operator<<(std::ostream& stream, const HexPrinter& printer) { 104 | // TODO: specialize for char 105 | return stream << printer.to_string(); 106 | } 107 | 108 | template 109 | HexPrinter as_hex(T val, bool prefix = true) { return HexPrinter(val, prefix); } 110 | 111 | template 112 | class HexArrayPrinter { 113 | public: 114 | HexArrayPrinter(T* ptr, size_t length) : ptr_(ptr), length_(length) {} 115 | T* ptr_; 116 | size_t length_; 117 | }; 118 | 119 | template 120 | TStream& operator<<(TStream& stream, const HexArrayPrinter& printer) { 121 | for (size_t pos = 0; pos < printer.length_; ++pos) { 122 | stream << " " << as_hex(printer.ptr_[pos]); 123 | if (((pos + 1) % 16) == 0) 124 | stream << "\n"; 125 | } 126 | return stream; 127 | } 128 | 129 | template 130 | HexArrayPrinter as_hex(T (&val)[ILength]) { return HexArrayPrinter(val, ILength); } 131 | 132 | template 133 | HexArrayPrinter as_hex(generic_bufptr_t buffer) { return HexArrayPrinter(buffer.begin(), buffer.size()); } 134 | 135 | } 136 | 137 | #endif // __FIBRE_PRINT_UTILS_HPP -------------------------------------------------------------------------------- /fibre-cpp/type_info_template.j2: -------------------------------------------------------------------------------- 1 | /*[# This is the original template, thus the warning below does not apply to this file #] 2 | * ============================ WARNING ============================ 3 | * ==== This is an autogenerated file. ==== 4 | * ==== Any changes to this file will be lost when recompiling. ==== 5 | * ================================================================= 6 | * 7 | * This file contains support functions for the ODrive ASCII protocol. 8 | * 9 | * TODO: might generalize this as an approach to runtime introspection. 10 | */ 11 | 12 | #include 13 | 14 | #pragma GCC push_options 15 | #pragma GCC optimize ("s") 16 | 17 | [% for intf in interfaces.values() %][% if not intf.builtin %] 18 | template 19 | struct [[intf.fullname | to_pascal_case]]TypeInfo : TypeInfo { 20 | using TypeInfo::TypeInfo; 21 | static const PropertyInfo property_table[]; 22 | static const [[intf.fullname | to_pascal_case]]TypeInfo singleton; 23 | static Introspectable make_introspectable(T& obj) { return TypeInfo::make_introspectable(&obj, &singleton); } 24 | 25 | introspectable_storage_t get_child(introspectable_storage_t obj, size_t idx) const override { 26 | T* ptr = *(T**)&obj; 27 | introspectable_storage_t res; 28 | switch (idx) { 29 | [%- for property in intf.get_all_attributes().values() %] 30 | case [[loop.index0]]: *(decltype([[intf.c_name]]::get_[[property.name]](std::declval()))*)(&res) = [[intf.c_name]]::get_[[property.name]](ptr); break; 31 | [%- endfor %] 32 | } 33 | return res; 34 | } 35 | }; 36 | [% endif %][% endfor %] 37 | 38 | [% for intf in interfaces.values() %][% if not intf.builtin %] 39 | template 40 | const PropertyInfo [[intf.fullname | to_pascal_case]]TypeInfo::property_table[] = { 41 | [%- for property in intf.get_all_attributes().values() %] 42 | {"[[property.name]]", &[[(property.type.purename or property.type.fullname) | to_pascal_case]]TypeInfo()))>>::singleton}, 43 | [%- endfor %] 44 | }; 45 | template 46 | const [[intf.fullname | to_pascal_case]]TypeInfo [[intf.fullname | to_pascal_case]]TypeInfo::singleton{[[intf.fullname | to_pascal_case]]TypeInfo::property_table, sizeof([[intf.fullname | to_pascal_case]]TypeInfo::property_table) / sizeof([[intf.fullname | to_pascal_case]]TypeInfo::property_table[0])}; 47 | 48 | [% endif %][% endfor %] 49 | 50 | #pragma GCC pop_options 51 | -------------------------------------------------------------------------------- /freertos_vars.h: -------------------------------------------------------------------------------- 1 | /* Define to prevent recursive inclusion -------------------------------------*/ 2 | #ifndef __FREERTOS_H 3 | #define __FREERTOS_H 4 | 5 | // TODO: this header is weird. Move these declarations to somewhere else. 6 | 7 | // List of semaphores 8 | extern osSemaphoreId sem_usb_irq; 9 | extern osMessageQId uart_event_queue; 10 | extern osMessageQId usb_event_queue; 11 | extern osSemaphoreId sem_can; 12 | 13 | extern osThreadId defaultTaskHandle; 14 | extern const uint32_t stack_size_default_task; 15 | 16 | #endif /* __FREERTOS_H */ -------------------------------------------------------------------------------- /interface_generator_stub.py: -------------------------------------------------------------------------------- 1 | #!/bin/python3 2 | 3 | import sys 4 | import os 5 | 6 | try: 7 | # path = os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), 'tools', 'fibre-tools', 'interface_generator.py') 8 | path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'tools', 'fibre-tools', 'interface_generator.py') 9 | exec(compile(open(path).read(), path, 'exec')) 10 | except ImportError as ex: 11 | print(str(ex), file=sys.stderr) 12 | print("Note that there are new compile-time dependencies since around v0.5.1.", file=sys.stderr) 13 | print("Check out https://github.com/odriverobotics/ODrive/blob/devel/docs/developer-guide.md#prerequisites for details.", file=sys.stderr) 14 | exit(1) 15 | -------------------------------------------------------------------------------- /syscalls.c: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * @file : syscalls.c 4 | * @brief : This file implements printf functionality 5 | ****************************************************************************** 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | 12 | //int _read(int file, char *data, int len) {} 13 | //int _close(int file) {} 14 | //int _lseek(int file, int ptr, int dir) {} 15 | //int _fstat(int file, struct stat *st) {} 16 | //int _isatty(int file) {} 17 | 18 | extern char _end; // provided by the linker script: it's end of statically allocated section, which is where the heap starts. 19 | extern char _heap_end_max; // provided by the linker script 20 | void* _end_ptr = &_end; 21 | void* _heap_end_max_ptr = &_heap_end_max; 22 | void* heap_end_ptr = 0; 23 | 24 | /* @brief Increments the program break (aka heap end) 25 | * 26 | * This is called internally by malloc once it runs out 27 | * of heap space. Malloc might expect a contiguous heap, 28 | * so we don't call the FreeRTOS pvPortMalloc here. 29 | * If this function returns -1, malloc will return NULL. 30 | * Note that if this function returns NULL, malloc does not 31 | * consider this as an error and will return the pointer 0x8. 32 | * 33 | * You should still be careful with using malloc though, 34 | * as it does not guarantee thread safety. 35 | * 36 | * @return A pointer to the newly allocated block on success 37 | * or -1 otherwise. 38 | */ 39 | intptr_t _sbrk(size_t size) { 40 | intptr_t ptr; 41 | { 42 | uint32_t mask = cpu_enter_critical(); 43 | if (!heap_end_ptr) 44 | heap_end_ptr = _end_ptr; 45 | if (heap_end_ptr + size > _heap_end_max_ptr) { 46 | ptr = -1; 47 | } else { 48 | ptr = (intptr_t)heap_end_ptr; 49 | heap_end_ptr += size; 50 | } 51 | cpu_exit_critical(mask); 52 | } 53 | return ptr; 54 | } 55 | 56 | // _write is defined in communication.cpp 57 | 58 | 59 | -------------------------------------------------------------------------------- /tools/odrive/version.py: -------------------------------------------------------------------------------- 1 | 2 | import re 3 | import subprocess 4 | import os 5 | import sys 6 | import platform 7 | 8 | def version_str_to_tuple(version_string): 9 | """ 10 | Converts a version string to a tuple of the form 11 | (major, minor, revision, prerelease) 12 | 13 | Example: "fw-v0.3.6-23" => (0, 3, 6, True) 14 | 15 | If version_string does not match the pattern above, this function throws an 16 | Exception. 17 | """ 18 | regex=r'.*v([0-9]+)\.([0-9]+)\.([0-9]+)(.*)' 19 | if not re.match(regex, version_string): 20 | raise Exception() 21 | return (int(re.sub(regex, r"\1", version_string)), 22 | int(re.sub(regex, r"\2", version_string)), 23 | int(re.sub(regex, r"\3", version_string)), 24 | (re.sub(regex, r"\4", version_string) != "")) 25 | 26 | 27 | def get_version_from_git(): 28 | script_dir = os.path.dirname(os.path.realpath(__file__)) 29 | try: 30 | # Determine the current git commit version 31 | git_tag = subprocess.check_output(["git", "describe", "--always", "--tags", "--match=*fw*", "--dirty=*"], 32 | cwd=script_dir) 33 | git_tag = git_tag.decode(sys.stdout.encoding or 'ascii').rstrip('\n') 34 | 35 | (major, minor, revision, is_prerelease) = version_str_to_tuple(git_tag) 36 | 37 | # if is_prerelease: 38 | # revision += 1 39 | return git_tag, major, minor, revision, is_prerelease 40 | 41 | except Exception as ex: 42 | print(ex) 43 | return "[unknown version]", 0, 0, 0, 1 44 | 45 | def get_version_str(git_only=False, is_post_release=False, bump_rev=False, release_override=False): 46 | """ 47 | Returns the versions of the tools 48 | If git_only is true, the version.txt file is ignored even 49 | if it is present. 50 | """ 51 | script_dir = os.path.dirname(os.path.realpath(__file__)) 52 | 53 | # Try to read the version.txt file that is generated during 54 | # the packaging step 55 | version_file_path = os.path.join(script_dir, 'version.txt') 56 | if os.path.exists(version_file_path) and git_only == False: 57 | with open(version_file_path) as version_file: 58 | return version_file.readline().rstrip('\n') 59 | 60 | _, major, minor, revision, unreleased = get_version_from_git() 61 | if bump_rev: 62 | revision += 1 63 | version = '{}.{}.{}'.format(major, minor, revision) 64 | if is_post_release: 65 | version += ".post" 66 | elif not release_override and unreleased: 67 | version += ".dev" 68 | return version 69 | 70 | if __name__ == '__main__': 71 | import argparse 72 | parser = argparse.ArgumentParser(description='Version Dump\n') 73 | parser.add_argument("--output", type=argparse.FileType('w'), default='-', 74 | help="C header output file") 75 | 76 | args = parser.parse_args() 77 | 78 | git_name, major, minor, revision, unreleased = get_version_from_git() 79 | print('Firmware version {}.{}.{}{} ({})'.format( 80 | major, minor, revision, '-dev' if unreleased else '', 81 | git_name)) 82 | #args.output.write('const unsigned char fw_version = "{}"\n'.format(git_name)) 83 | args.output.write('const unsigned char fw_version_major_ = {};\n'.format(major)) 84 | args.output.write('const unsigned char fw_version_minor_ = {};\n'.format(minor)) 85 | args.output.write('const unsigned char fw_version_revision_ = {};\n'.format(revision)) 86 | args.output.write('const unsigned char fw_version_unreleased_ = {};\n'.format(1 if unreleased else 0)) 87 | 88 | def setup_udev_rules(logger): 89 | if platform.system() != 'Linux': 90 | if logger: logger.error("This command only makes sense on Linux") 91 | return 92 | if os.getuid() != 0: 93 | if logger: logger.warn("you should run this as root, otherwise it will probably not work") 94 | with open('/etc/udev/rules.d/91-odrive.rules', 'w') as file: 95 | file.write('SUBSYSTEM=="usb", ATTR{idVendor}=="1209", ATTR{idProduct}=="0d3[0-9]", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1"\n') 96 | file.write('SUBSYSTEM=="usb", ATTR{idVendor}=="0483", ATTR{idProduct}=="df11", MODE="0666"\n') 97 | subprocess.check_call(["udevadm", "control", "--reload-rules"]) 98 | subprocess.check_call(["udevadm", "trigger"]) 99 | if logger: logger.info('udev rules configured successfully') 100 | -------------------------------------------------------------------------------- /version.c: -------------------------------------------------------------------------------- 1 | const unsigned char fw_version_major_ = 0; 2 | const unsigned char fw_version_minor_ = 5; 3 | const unsigned char fw_version_revision_ = 6; 4 | const unsigned char fw_version_unreleased_ = 1; 5 | --------------------------------------------------------------------------------