spu stuff

This commit is contained in:
2026-07-18 16:58:49 +02:00
parent 76eaf96b7b
commit 543f3f9b1b
27 changed files with 1523 additions and 338 deletions

View File

@@ -3,7 +3,7 @@
"configurations": [ "configurations": [
{ {
"name": "STM32F030", "name": "STM32F030",
"compileCommands": "${workspaceFolder}/app/blinky/stm32f030/build/compile_commands.json", "compileCommands": "${workspaceFolder}/app/motor_control/stm32f030/build/compile_commands.json",
"intelliSenseMode": "linux-gcc-arm", "intelliSenseMode": "linux-gcc-arm",
"compilerPath": "/usr/bin/arm-none-eabi-gcc" "compilerPath": "/usr/bin/arm-none-eabi-gcc"
} }

View File

@@ -5,13 +5,13 @@
"version": "0.2.0", "version": "0.2.0",
"configurations": [ "configurations": [
{ {
"name": "Debug blinky (J-Link)", "name": "Debug motor_control (J-Link)",
"cwd": "${workspaceFolder}", "cwd": "${workspaceFolder}",
"executable": "${workspaceFolder}/app/blinky/stm32f030/build/blinky.elf", "executable": "${workspaceFolder}/app/motor_control/stm32f030/build/motor_control.elf",
"preLaunchTask": "Build blinky stm32f030", "preLaunchTask": "Build motor_control stm32f030",
"request": "launch", "request": "launch",
"type": "cortex-debug", "type": "cortex-debug",
"runToEntryPoint": "app_main", // "runToEntryPoint": "app_main",
"servertype": "jlink", "servertype": "jlink",
"device": "STM32F030C8", "device": "STM32F030C8",
"interface": "swd", "interface": "swd",

View File

@@ -2,14 +2,14 @@
"version": "2.0.0", "version": "2.0.0",
"tasks": [ "tasks": [
{ {
"label": "Configure blinky stm32f030", "label": "Configure motor_control stm32f030",
"type": "shell", "type": "shell",
"command": "cmake", "command": "cmake",
"args": [ "args": [
"-S", "-S",
"${workspaceFolder}/app/blinky/stm32f030", "${workspaceFolder}/app/motor_control/stm32f030",
"-B", "-B",
"${workspaceFolder}/app/blinky/stm32f030/build", "${workspaceFolder}/app/motor_control/stm32f030/build",
"-DCMAKE_BUILD_TYPE=Debug" "-DCMAKE_BUILD_TYPE=Debug"
], ],
"options": { "options": {
@@ -18,18 +18,18 @@
"problemMatcher": [] "problemMatcher": []
}, },
{ {
"label": "Build blinky stm32f030", "label": "Build motor_control stm32f030",
"type": "shell", "type": "shell",
"command": "cmake", "command": "cmake",
"args": [ "args": [
"--build", "--build",
"${workspaceFolder}/app/blinky/stm32f030/build" "${workspaceFolder}/app/motor_control/stm32f030/build"
], ],
"options": { "options": {
"cwd": "${workspaceFolder}" "cwd": "${workspaceFolder}"
}, },
"dependsOn": [ "dependsOn": [
"Configure blinky stm32f030" "Configure motor_control stm32f030"
], ],
"group": { "group": {
"kind": "build", "kind": "build",

View File

@@ -1,23 +0,0 @@
#include "main.h"
#include "stm32f0xx_hal_gpio.h"
#include "stm32f0xx_hal_tim.h"
#include "stm32f0xx_hal_tim_ex.h"
extern TIM_HandleTypeDef htim3;
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin){
if(GPIO_Pin == MotRSpd_Pin){
HAL_GPIO_TogglePin(LED_0_GPIO_Port, LED_0_Pin);
}
}
void app_main(){
HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1);
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, 800);
for(;;){
// HAL_GPIO_TogglePin(LED_0_GPIO_Port, LED_0_Pin);
HAL_Delay(500);
}
}

File diff suppressed because one or more lines are too long

View File

@@ -1,155 +0,0 @@
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file stm32f0xx_hal_msp.c
* @brief This file provides code for the MSP Initialization
* and de-Initialization codes.
******************************************************************************
* @attention
*
* Copyright (c) 2026 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN TD */
/* USER CODE END TD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN Define */
/* USER CODE END Define */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN Macro */
/* USER CODE END Macro */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* External functions --------------------------------------------------------*/
/* USER CODE BEGIN ExternalFunctions */
/* USER CODE END ExternalFunctions */
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
void HAL_TIM_MspPostInit(TIM_HandleTypeDef *htim);
/**
* Initializes the Global MSP.
*/
void HAL_MspInit(void)
{
/* USER CODE BEGIN MspInit 0 */
/* USER CODE END MspInit 0 */
__HAL_RCC_SYSCFG_CLK_ENABLE();
__HAL_RCC_PWR_CLK_ENABLE();
/* System interrupt init*/
/* USER CODE BEGIN MspInit 1 */
/* USER CODE END MspInit 1 */
}
/**
* @brief TIM_Base MSP Initialization
* This function configures the hardware resources used in this example
* @param htim_base: TIM_Base handle pointer
* @retval None
*/
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* htim_base)
{
if(htim_base->Instance==TIM3)
{
/* USER CODE BEGIN TIM3_MspInit 0 */
/* USER CODE END TIM3_MspInit 0 */
/* Peripheral clock enable */
__HAL_RCC_TIM3_CLK_ENABLE();
/* USER CODE BEGIN TIM3_MspInit 1 */
/* USER CODE END TIM3_MspInit 1 */
}
}
void HAL_TIM_MspPostInit(TIM_HandleTypeDef* htim)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(htim->Instance==TIM3)
{
/* USER CODE BEGIN TIM3_MspPostInit 0 */
/* USER CODE END TIM3_MspPostInit 0 */
__HAL_RCC_GPIOA_CLK_ENABLE();
/**TIM3 GPIO Configuration
PA6 ------> TIM3_CH1
PA7 ------> TIM3_CH2
*/
GPIO_InitStruct.Pin = MotRFwd_Pin|MotRRev_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF1_TIM3;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* USER CODE BEGIN TIM3_MspPostInit 1 */
/* USER CODE END TIM3_MspPostInit 1 */
}
}
/**
* @brief TIM_Base MSP De-Initialization
* This function freeze the hardware resources used in this example
* @param htim_base: TIM_Base handle pointer
* @retval None
*/
void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* htim_base)
{
if(htim_base->Instance==TIM3)
{
/* USER CODE BEGIN TIM3_MspDeInit 0 */
/* USER CODE END TIM3_MspDeInit 0 */
/* Peripheral clock disable */
__HAL_RCC_TIM3_CLK_DISABLE();
/* USER CODE BEGIN TIM3_MspDeInit 1 */
/* USER CODE END TIM3_MspDeInit 1 */
}
}
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */

View File

@@ -1,124 +0,0 @@
#MicroXplorer Configuration settings - do not modify
CAD.formats=
CAD.pinconfig=
CAD.provider=
File.Version=6
GPIO.groupedBy=Group By Peripherals
KeepUserPlacement=false
Mcu.CPN=STM32F030C8T6
Mcu.Family=STM32F0
Mcu.IP0=NVIC
Mcu.IP1=RCC
Mcu.IP2=SYS
Mcu.IP3=TIM3
Mcu.IPNb=4
Mcu.Name=STM32F030C8Tx
Mcu.Package=LQFP48
Mcu.Pin0=PC13
Mcu.Pin1=PA6
Mcu.Pin2=PA7
Mcu.Pin3=PB8
Mcu.Pin4=VP_SYS_VS_Systick
Mcu.Pin5=VP_TIM3_VS_ClockSourceINT
Mcu.PinsNb=6
Mcu.ThirdPartyNb=0
Mcu.UserConstants=
Mcu.UserName=STM32F030C8Tx
MxCube.Version=6.17.0
MxDb.Version=DB.6.0.170
NVIC.EXTI4_15_IRQn=true\:0\:0\:false\:false\:true\:true\:true\:true
NVIC.ForceEnableDMAVector=true
NVIC.HardFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
NVIC.NonMaskableInt_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
NVIC.PendSV_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
NVIC.SVC_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:true
NVIC.SysTick_IRQn=true\:3\:0\:false\:false\:true\:false\:true\:false
PA6.GPIOParameters=GPIO_Label
PA6.GPIO_Label=MotRFwd
PA6.Locked=true
PA6.Signal=S_TIM3_CH1
PA7.GPIOParameters=GPIO_Label
PA7.GPIO_Label=MotRRev
PA7.Locked=true
PA7.Signal=S_TIM3_CH2
PB8.GPIOParameters=GPIO_Label
PB8.GPIO_Label=MotRSpd
PB8.Locked=true
PB8.Signal=GPXTI8
PC13.GPIOParameters=GPIO_Label
PC13.GPIO_Label=LED_0
PC13.Locked=true
PC13.Signal=GPIO_Output
PCC.Checker=false
PCC.Display=Plot\: All Steps
PCC.Line=STM32F0x0 Value Line
PCC.MCU=STM32F030C8Tx
PCC.PartNumber=STM32F030C8Tx
PCC.Series=STM32F0
PCC.Temperature=25
PCC.Vdd=3.6
PinOutPanel.RotationAngle=0
ProjectManager.AskForMigrate=true
ProjectManager.BackupPrevious=false
ProjectManager.CompilerLinker=GCC
ProjectManager.CompilerOptimize=6
ProjectManager.ComputerToolchain=false
ProjectManager.CoupleFile=false
ProjectManager.CustomerFirmwarePackage=../../../vendor/STM32CubeF0
ProjectManager.DefaultFWLocation=false
ProjectManager.DeletePrevious=true
ProjectManager.DeviceId=STM32F030C8Tx
ProjectManager.FirmwarePackage=STM32Cube FW_F0 V1.11.6
ProjectManager.FreePins=false
ProjectManager.FreePinsContext=
ProjectManager.HalAssertFull=false
ProjectManager.HeapSize=0x80
ProjectManager.KeepUserCode=true
ProjectManager.LastFirmware=true
ProjectManager.LibraryCopy=2
ProjectManager.MainLocation=Src
ProjectManager.NoMain=false
ProjectManager.PreviousToolchain=
ProjectManager.ProjectBuild=false
ProjectManager.ProjectFileName=stm32f030.ioc
ProjectManager.ProjectName=stm32f030
ProjectManager.ProjectStructure=
ProjectManager.RegisterCallBack=
ProjectManager.StackSize=0x400
ProjectManager.TargetToolchain=CMake
ProjectManager.ToolChainLocation=
ProjectManager.UAScriptAfterPath=
ProjectManager.UAScriptBeforePath=
ProjectManager.UnderRoot=false
ProjectManager.functionlistsort=1-SystemClock_Config-RCC-false-HAL-false,2-MX_GPIO_Init-GPIO-false-HAL-true,3-MX_TIM3_Init-TIM3-false-HAL-true
RCC.AHBFreq_Value=48000000
RCC.APB1Freq_Value=48000000
RCC.APB1TimFreq_Value=48000000
RCC.FCLKCortexFreq_Value=48000000
RCC.FamilyName=M
RCC.HCLKFreq_Value=48000000
RCC.IPParameters=AHBFreq_Value,APB1Freq_Value,APB1TimFreq_Value,FCLKCortexFreq_Value,FamilyName,HCLKFreq_Value,MCOFreq_Value,PLLCLKFreq_Value,PLLMCOFreq_Value,PLLMUL,SYSCLKFreq_VALUE,SYSCLKSource,TimSysFreq_Value,USART1Freq_Value
RCC.MCOFreq_Value=48000000
RCC.PLLCLKFreq_Value=48000000
RCC.PLLMCOFreq_Value=24000000
RCC.PLLMUL=RCC_PLL_MUL12
RCC.SYSCLKFreq_VALUE=48000000
RCC.SYSCLKSource=RCC_SYSCLKSOURCE_PLLCLK
RCC.TimSysFreq_Value=48000000
RCC.USART1Freq_Value=48000000
SH.GPXTI8.0=GPIO_EXTI8
SH.GPXTI8.ConfNb=1
SH.S_TIM3_CH1.0=TIM3_CH1,PWM Generation1 CH1
SH.S_TIM3_CH1.ConfNb=1
SH.S_TIM3_CH2.0=TIM3_CH2,PWM Generation2 CH2
SH.S_TIM3_CH2.ConfNb=1
TIM3.AutoReloadPreload=TIM_AUTORELOAD_PRELOAD_ENABLE
TIM3.Channel-PWM\ Generation1\ CH1=TIM_CHANNEL_1
TIM3.Channel-PWM\ Generation2\ CH2=TIM_CHANNEL_2
TIM3.IPParameters=Channel-PWM Generation1 CH1,Channel-PWM Generation2 CH2,Period,AutoReloadPreload
TIM3.Period=1600
VP_SYS_VS_Systick.Mode=SysTick
VP_SYS_VS_Systick.Signal=SYS_VS_Systick
VP_TIM3_VS_ClockSourceINT.Mode=Internal
VP_TIM3_VS_ClockSourceINT.Signal=TIM3_VS_ClockSourceINT
board=custom

View File

@@ -0,0 +1,207 @@
#include "main.h"
#include "stm32f0xx_hal_tim.h"
#include "stm32f0xx_hal_tim_ex.h"
#include "stm32f0xx_hal_uart.h"
#define PWM_MAX 3200
#define CONTROL_PERIOD_MS 20
#define SPEED_TIMEOUT_MS 500
#define SPEED_FILTER_SHIFT 2
#define TICKS_PER_REV 400
#define UART_PRINT_PERIOD_MS 25
/* Simple PI gains. Output unit is PWM counts. */
#define KP_PWM_PER_RPM 60
#define KI_Q8 800
/* Positive drives CH1, negative drives CH2. */
#define TARGET_RPM 20
typedef struct {
volatile uint32_t last_edge_ms;
volatile uint32_t last_period_ms;
volatile uint32_t tick_count;
} MotorFeedback;
static volatile uint8_t uart_tx_busy;
static uint8_t uart_tx_buf[20];
static MotorFeedback motor_r;
static MotorFeedback motor_l;
static void uart_send_status(
uint32_t now_ms,
uint32_t tick_r,
uint32_t target_r,
uint32_t tick_l,
uint32_t target_l
){
if (uart_tx_busy) {
return;
}
((uint32_t*)uart_tx_buf)[0] = now_ms;
((uint32_t*)uart_tx_buf)[1] = tick_r;
((uint32_t*)uart_tx_buf)[2] = target_r;
((uint32_t*)uart_tx_buf)[3] = tick_l;
((uint32_t*)uart_tx_buf)[4] = target_l;
uart_tx_busy = 1U;
if (HAL_UART_Transmit_DMA(&huart1, uart_tx_buf, sizeof(uart_tx_buf)) != HAL_OK) {
uart_tx_busy = 0U;
}
}
static void motor_set_output(
uint32_t ch_fwd,
uint32_t ch_rev,
int32_t pwm
){
uint32_t duty = (pwm >= 0) ? (uint32_t)pwm : (uint32_t)(-pwm);
if (duty > PWM_MAX) {
duty = PWM_MAX;
}
if (pwm >= 0) {
__HAL_TIM_SET_COMPARE(&htim3, ch_fwd, duty);
__HAL_TIM_SET_COMPARE(&htim3, ch_rev, 0);
} else {
__HAL_TIM_SET_COMPARE(&htim3, ch_fwd, 0);
__HAL_TIM_SET_COMPARE(&htim3, ch_rev, duty);
}
}
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin){
if (GPIO_Pin == MotRSpd_Pin) {
uint32_t now = HAL_GetTick();
if (motor_r.last_edge_ms != 0U) {
motor_r.last_period_ms = now - motor_r.last_edge_ms;
}
motor_r.last_edge_ms = now;
motor_r.tick_count++;
} else if (GPIO_Pin == MotLSpd_Pin) {
uint32_t now = HAL_GetTick();
if (motor_l.last_edge_ms != 0U) {
motor_l.last_period_ms = now - motor_l.last_edge_ms;
}
motor_l.last_edge_ms = now;
motor_l.tick_count++;
}
}
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart){
if (huart->Instance == USART1) {
uart_tx_busy = 0U;
}
}
void app_main(void){
int32_t speed_r_q8 = 0;
int32_t speed_l_q8 = 0;
int32_t integral_r_q8 = 0;
int32_t integral_l_q8 = 0;
uint32_t next_control_ms = HAL_GetTick();
uint32_t next_uart_ms = next_control_ms;
uint32_t target_ticks_per_s = TARGET_RPM * TICKS_PER_REV / 60;
HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_2);
HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_3);
HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_4);
motor_set_output(TIM_CHANNEL_1, TIM_CHANNEL_2, 0);
motor_set_output(TIM_CHANNEL_3, TIM_CHANNEL_4, 0);
for (;;) {
uint32_t now = HAL_GetTick();
if ((uint32_t)(now - next_control_ms) < CONTROL_PERIOD_MS) {
continue;
}
next_control_ms += CONTROL_PERIOD_MS;
uint32_t edge_r_ms;
uint32_t period_r_ms;
uint32_t tick_r;
uint32_t edge_l_ms;
uint32_t period_l_ms;
uint32_t tick_l;
__disable_irq();
edge_r_ms = motor_r.last_edge_ms;
period_r_ms = motor_r.last_period_ms;
tick_r = motor_r.tick_count;
edge_l_ms = motor_l.last_edge_ms;
period_l_ms = motor_l.last_period_ms;
tick_l = motor_l.tick_count;
__enable_irq();
int32_t inst_r_rpm_q8 = 0;
int32_t inst_l_rpm_q8 = 0;
/*
* One rising edge is 1/TICKS_PER_REV revolution:
* rpm = 60000 / (TICKS_PER_REV * period_ms)
*/
if ((edge_r_ms != 0U) &&
((now - edge_r_ms) < SPEED_TIMEOUT_MS) &&
(period_r_ms != 0U)) {
inst_r_rpm_q8 = ((60000 / TICKS_PER_REV) << 8) / (int32_t)period_r_ms;
}
if ((edge_l_ms != 0U) &&
((now - edge_l_ms) < SPEED_TIMEOUT_MS) &&
(period_l_ms != 0U)) {
inst_l_rpm_q8 = ((60000 / TICKS_PER_REV) << 8) / (int32_t)period_l_ms;
}
speed_r_q8 += (inst_r_rpm_q8 - speed_r_q8) >> SPEED_FILTER_SHIFT;
speed_l_q8 += (inst_l_rpm_q8 - speed_l_q8) >> SPEED_FILTER_SHIFT;
int32_t error_r_q8 = (TARGET_RPM << 8) - speed_r_q8;
int32_t error_l_q8 = (TARGET_RPM << 8) - speed_l_q8;
integral_r_q8 += (error_r_q8 * KI_Q8) >> 8;
integral_l_q8 += (error_l_q8 * KI_Q8) >> 8;
if (integral_r_q8 > (PWM_MAX << 8)) {
integral_r_q8 = PWM_MAX << 8;
} else if (integral_r_q8 < -(PWM_MAX << 8)) {
integral_r_q8 = -(PWM_MAX << 8);
}
if (integral_l_q8 > (PWM_MAX << 8)) {
integral_l_q8 = PWM_MAX << 8;
} else if (integral_l_q8 < -(PWM_MAX << 8)) {
integral_l_q8 = -(PWM_MAX << 8);
}
int32_t pwm_r = (error_r_q8 * KP_PWM_PER_RPM + integral_r_q8) >> 8;
int32_t pwm_l = (error_l_q8 * KP_PWM_PER_RPM + integral_l_q8) >> 8;
if (pwm_r > PWM_MAX) {
pwm_r = PWM_MAX;
} else if (pwm_r < -PWM_MAX) {
pwm_r = -PWM_MAX;
}
if (pwm_l > PWM_MAX) {
pwm_l = PWM_MAX;
} else if (pwm_l < -PWM_MAX) {
pwm_l = -PWM_MAX;
}
motor_set_output(TIM_CHANNEL_1, TIM_CHANNEL_2, pwm_r);
motor_set_output(TIM_CHANNEL_3, TIM_CHANNEL_4, pwm_l);
if ((uint32_t)(now - next_uart_ms) >= UART_PRINT_PERIOD_MS) {
next_uart_ms += UART_PRINT_PERIOD_MS;
uart_send_status(now, tick_r, target_ticks_per_s, tick_l, target_ticks_per_s);
HAL_GPIO_TogglePin(LED_0_GPIO_Port, LED_0_Pin);
}
}
}

File diff suppressed because one or more lines are too long

View File

@@ -10,7 +10,7 @@ endif()
set(CMAKE_EXPORT_COMPILE_COMMANDS TRUE) set(CMAKE_EXPORT_COMPILE_COMMANDS TRUE)
set(CMAKE_TOOLCHAIN_FILE ${CMAKE_CURRENT_SOURCE_DIR}/cmake/gcc-arm-none-eabi.cmake) set(CMAKE_TOOLCHAIN_FILE ${CMAKE_CURRENT_SOURCE_DIR}/cmake/gcc-arm-none-eabi.cmake)
project(blinky) project(motor_control)
enable_language(C ASM) enable_language(C ASM)
set(CUBE_def set(CUBE_def
@@ -40,6 +40,8 @@ set(CUBE_src
${CMAKE_CURRENT_SOURCE_DIR}/../../../vendor/STM32CubeF0/Drivers/STM32F0xx_HAL_Driver/Src/stm32f0xx_hal_flash.c ${CMAKE_CURRENT_SOURCE_DIR}/../../../vendor/STM32CubeF0/Drivers/STM32F0xx_HAL_Driver/Src/stm32f0xx_hal_flash.c
${CMAKE_CURRENT_SOURCE_DIR}/../../../vendor/STM32CubeF0/Drivers/STM32F0xx_HAL_Driver/Src/stm32f0xx_hal_flash_ex.c ${CMAKE_CURRENT_SOURCE_DIR}/../../../vendor/STM32CubeF0/Drivers/STM32F0xx_HAL_Driver/Src/stm32f0xx_hal_flash_ex.c
${CMAKE_CURRENT_SOURCE_DIR}/../../../vendor/STM32CubeF0/Drivers/STM32F0xx_HAL_Driver/Src/stm32f0xx_hal_exti.c ${CMAKE_CURRENT_SOURCE_DIR}/../../../vendor/STM32CubeF0/Drivers/STM32F0xx_HAL_Driver/Src/stm32f0xx_hal_exti.c
${CMAKE_CURRENT_SOURCE_DIR}/../../../vendor/STM32CubeF0/Drivers/STM32F0xx_HAL_Driver/Src/stm32f0xx_hal_uart.c
${CMAKE_CURRENT_SOURCE_DIR}/../../../vendor/STM32CubeF0/Drivers/STM32F0xx_HAL_Driver/Src/stm32f0xx_hal_uart_ex.c
) )
set(CUBE_inc set(CUBE_inc
@@ -50,14 +52,14 @@ set(CUBE_inc
${CMAKE_CURRENT_SOURCE_DIR}/../../../vendor/STM32CubeF0/Drivers/CMSIS/Include ${CMAKE_CURRENT_SOURCE_DIR}/../../../vendor/STM32CubeF0/Drivers/CMSIS/Include
) )
add_executable(blinky add_executable(motor_control
${CUBE_src} ${CUBE_src}
${CMAKE_CURRENT_SOURCE_DIR}/../src/app_main.c ${CMAKE_CURRENT_SOURCE_DIR}/../src/app_main.c
) )
target_include_directories(blinky PUBLIC target_include_directories(motor_control PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/../src ${CMAKE_CURRENT_SOURCE_DIR}/../src
${CUBE_inc} ${CUBE_inc}
) )
target_compile_definitions(blinky PUBLIC target_compile_definitions(motor_control PUBLIC
${CUBE_def} ${CUBE_def}
) )

View File

@@ -61,16 +61,36 @@ void Error_Handler(void);
/* Private defines -----------------------------------------------------------*/ /* Private defines -----------------------------------------------------------*/
#define LED_0_Pin GPIO_PIN_13 #define LED_0_Pin GPIO_PIN_13
#define LED_0_GPIO_Port GPIOC #define LED_0_GPIO_Port GPIOC
#define LED_BLUE_Pin GPIO_PIN_2
#define LED_BLUE_GPIO_Port GPIOA
#define LED_RED_Pin GPIO_PIN_3
#define LED_RED_GPIO_Port GPIOA
#define MotLRBrush_Pin GPIO_PIN_4
#define MotLRBrush_GPIO_Port GPIOA
#define MotLSpd_Pin GPIO_PIN_5
#define MotLSpd_GPIO_Port GPIOA
#define MotLSpd_EXTI_IRQn EXTI4_15_IRQn
#define MotRFwd_Pin GPIO_PIN_6 #define MotRFwd_Pin GPIO_PIN_6
#define MotRFwd_GPIO_Port GPIOA #define MotRFwd_GPIO_Port GPIOA
#define MotRRev_Pin GPIO_PIN_7 #define MotRRev_Pin GPIO_PIN_7
#define MotRRev_GPIO_Port GPIOA #define MotRRev_GPIO_Port GPIOA
#define MotRSpd_Pin GPIO_PIN_8 #define MotLFwd_Pin GPIO_PIN_0
#define MotLFwd_GPIO_Port GPIOB
#define MotLRev_Pin GPIO_PIN_1
#define MotLRev_GPIO_Port GPIOB
#define MotRSpd_Pin GPIO_PIN_2
#define MotRSpd_GPIO_Port GPIOB #define MotRSpd_GPIO_Port GPIOB
#define MotRSpd_EXTI_IRQn EXTI4_15_IRQn #define TX_Pin GPIO_PIN_9
#define TX_GPIO_Port GPIOA
#define RX_Pin GPIO_PIN_10
#define RX_GPIO_Port GPIOA
/* USER CODE BEGIN Private defines */ /* USER CODE BEGIN Private defines */
#define MotPwmTimerHandle htim3
extern TIM_HandleTypeDef htim3;
#define UartHandle huart1
extern UART_HandleTypeDef huart1;
/* USER CODE END Private defines */ /* USER CODE END Private defines */
#ifdef __cplusplus #ifdef __cplusplus

View File

@@ -50,7 +50,7 @@
/*#define HAL_RTC_MODULE_ENABLED */ /*#define HAL_RTC_MODULE_ENABLED */
/*#define HAL_SPI_MODULE_ENABLED */ /*#define HAL_SPI_MODULE_ENABLED */
#define HAL_TIM_MODULE_ENABLED #define HAL_TIM_MODULE_ENABLED
/*#define HAL_UART_MODULE_ENABLED */ #define HAL_UART_MODULE_ENABLED
/*#define HAL_USART_MODULE_ENABLED */ /*#define HAL_USART_MODULE_ENABLED */
/*#define HAL_IRDA_MODULE_ENABLED */ /*#define HAL_IRDA_MODULE_ENABLED */
/*#define HAL_SMARTCARD_MODULE_ENABLED */ /*#define HAL_SMARTCARD_MODULE_ENABLED */

View File

@@ -52,6 +52,8 @@ void SVC_Handler(void);
void PendSV_Handler(void); void PendSV_Handler(void);
void SysTick_Handler(void); void SysTick_Handler(void);
void EXTI4_15_IRQHandler(void); void EXTI4_15_IRQHandler(void);
void DMA1_Channel2_3_IRQHandler(void);
void USART1_IRQHandler(void);
/* USER CODE BEGIN EFP */ /* USER CODE BEGIN EFP */
/* USER CODE END EFP */ /* USER CODE END EFP */

View File

@@ -41,6 +41,12 @@
/* Private variables ---------------------------------------------------------*/ /* Private variables ---------------------------------------------------------*/
TIM_HandleTypeDef htim3; TIM_HandleTypeDef htim3;
TIM_HandleTypeDef htim14;
TIM_HandleTypeDef htim15;
UART_HandleTypeDef huart1;
DMA_HandleTypeDef hdma_usart1_rx;
DMA_HandleTypeDef hdma_usart1_tx;
/* USER CODE BEGIN PV */ /* USER CODE BEGIN PV */
@@ -49,7 +55,11 @@ TIM_HandleTypeDef htim3;
/* Private function prototypes -----------------------------------------------*/ /* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void); void SystemClock_Config(void);
static void MX_GPIO_Init(void); static void MX_GPIO_Init(void);
static void MX_DMA_Init(void);
static void MX_TIM3_Init(void); static void MX_TIM3_Init(void);
static void MX_USART1_UART_Init(void);
static void MX_TIM15_Init(void);
static void MX_TIM14_Init(void);
/* USER CODE BEGIN PFP */ /* USER CODE BEGIN PFP */
/* USER CODE END PFP */ /* USER CODE END PFP */
@@ -88,7 +98,11 @@ int main(void)
/* Initialize all configured peripherals */ /* Initialize all configured peripherals */
MX_GPIO_Init(); MX_GPIO_Init();
MX_DMA_Init();
MX_TIM3_Init(); MX_TIM3_Init();
MX_USART1_UART_Init();
MX_TIM15_Init();
MX_TIM14_Init();
/* USER CODE BEGIN 2 */ /* USER CODE BEGIN 2 */
extern void app_main(); extern void app_main();
app_main(); app_main();
@@ -113,6 +127,7 @@ void SystemClock_Config(void)
{ {
RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
/** Initializes the RCC Oscillators according to the specified parameters /** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure. * in the RCC_OscInitTypeDef structure.
@@ -141,6 +156,12 @@ void SystemClock_Config(void)
{ {
Error_Handler(); Error_Handler();
} }
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART1;
PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK1;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
{
Error_Handler();
}
} }
/** /**
@@ -165,7 +186,7 @@ static void MX_TIM3_Init(void)
htim3.Instance = TIM3; htim3.Instance = TIM3;
htim3.Init.Prescaler = 0; htim3.Init.Prescaler = 0;
htim3.Init.CounterMode = TIM_COUNTERMODE_UP; htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
htim3.Init.Period = 1600; htim3.Init.Period = 3200;
htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE; htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
if (HAL_TIM_Base_Init(&htim3) != HAL_OK) if (HAL_TIM_Base_Init(&htim3) != HAL_OK)
@@ -199,6 +220,14 @@ static void MX_TIM3_Init(void)
{ {
Error_Handler(); Error_Handler();
} }
if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_3) != HAL_OK)
{
Error_Handler();
}
if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_4) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN TIM3_Init 2 */ /* USER CODE BEGIN TIM3_Init 2 */
/* USER CODE END TIM3_Init 2 */ /* USER CODE END TIM3_Init 2 */
@@ -206,6 +235,182 @@ static void MX_TIM3_Init(void)
} }
/**
* @brief TIM14 Initialization Function
* @param None
* @retval None
*/
static void MX_TIM14_Init(void)
{
/* USER CODE BEGIN TIM14_Init 0 */
/* USER CODE END TIM14_Init 0 */
TIM_OC_InitTypeDef sConfigOC = {0};
/* USER CODE BEGIN TIM14_Init 1 */
/* USER CODE END TIM14_Init 1 */
htim14.Instance = TIM14;
htim14.Init.Prescaler = 0;
htim14.Init.CounterMode = TIM_COUNTERMODE_UP;
htim14.Init.Period = 1600;
htim14.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim14.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
if (HAL_TIM_Base_Init(&htim14) != HAL_OK)
{
Error_Handler();
}
if (HAL_TIM_PWM_Init(&htim14) != HAL_OK)
{
Error_Handler();
}
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 0;
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
if (HAL_TIM_PWM_ConfigChannel(&htim14, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN TIM14_Init 2 */
/* USER CODE END TIM14_Init 2 */
HAL_TIM_MspPostInit(&htim14);
}
/**
* @brief TIM15 Initialization Function
* @param None
* @retval None
*/
static void MX_TIM15_Init(void)
{
/* USER CODE BEGIN TIM15_Init 0 */
/* USER CODE END TIM15_Init 0 */
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
TIM_OC_InitTypeDef sConfigOC = {0};
TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};
/* USER CODE BEGIN TIM15_Init 1 */
/* USER CODE END TIM15_Init 1 */
htim15.Instance = TIM15;
htim15.Init.Prescaler = 0;
htim15.Init.CounterMode = TIM_COUNTERMODE_UP;
htim15.Init.Period = 1600;
htim15.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim15.Init.RepetitionCounter = 0;
htim15.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
if (HAL_TIM_Base_Init(&htim15) != HAL_OK)
{
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim15, &sClockSourceConfig) != HAL_OK)
{
Error_Handler();
}
if (HAL_TIM_PWM_Init(&htim15) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim15, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 0;
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;
if (HAL_TIM_PWM_ConfigChannel(&htim15, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
{
Error_Handler();
}
if (HAL_TIM_PWM_ConfigChannel(&htim15, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
{
Error_Handler();
}
sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE;
sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE;
sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF;
sBreakDeadTimeConfig.DeadTime = 0;
sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE;
sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE;
if (HAL_TIMEx_ConfigBreakDeadTime(&htim15, &sBreakDeadTimeConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN TIM15_Init 2 */
/* USER CODE END TIM15_Init 2 */
HAL_TIM_MspPostInit(&htim15);
}
/**
* @brief USART1 Initialization Function
* @param None
* @retval None
*/
static void MX_USART1_UART_Init(void)
{
/* USER CODE BEGIN USART1_Init 0 */
/* USER CODE END USART1_Init 0 */
/* USER CODE BEGIN USART1_Init 1 */
/* USER CODE END USART1_Init 1 */
huart1.Instance = USART1;
huart1.Init.BaudRate = 115200;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
if (HAL_UART_Init(&huart1) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN USART1_Init 2 */
/* USER CODE END USART1_Init 2 */
}
/**
* Enable DMA controller clock
*/
static void MX_DMA_Init(void)
{
/* DMA controller clock enable */
__HAL_RCC_DMA1_CLK_ENABLE();
/* DMA interrupt init */
/* DMA1_Channel2_3_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA1_Channel2_3_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Channel2_3_IRQn);
}
/** /**
* @brief GPIO Initialization Function * @brief GPIO Initialization Function
* @param None * @param None
@@ -233,6 +438,12 @@ static void MX_GPIO_Init(void)
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(LED_0_GPIO_Port, &GPIO_InitStruct); HAL_GPIO_Init(LED_0_GPIO_Port, &GPIO_InitStruct);
/*Configure GPIO pin : MotLSpd_Pin */
GPIO_InitStruct.Pin = MotLSpd_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(MotLSpd_GPIO_Port, &GPIO_InitStruct);
/*Configure GPIO pin : MotRSpd_Pin */ /*Configure GPIO pin : MotRSpd_Pin */
GPIO_InitStruct.Pin = MotRSpd_Pin; GPIO_InitStruct.Pin = MotRSpd_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING; GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;

View File

@@ -0,0 +1,361 @@
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file stm32f0xx_hal_msp.c
* @brief This file provides code for the MSP Initialization
* and de-Initialization codes.
******************************************************************************
* @attention
*
* Copyright (c) 2026 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
extern DMA_HandleTypeDef hdma_usart1_rx;
extern DMA_HandleTypeDef hdma_usart1_tx;
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN TD */
/* USER CODE END TD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN Define */
/* USER CODE END Define */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN Macro */
/* USER CODE END Macro */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* External functions --------------------------------------------------------*/
/* USER CODE BEGIN ExternalFunctions */
/* USER CODE END ExternalFunctions */
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
void HAL_TIM_MspPostInit(TIM_HandleTypeDef *htim);
/**
* Initializes the Global MSP.
*/
void HAL_MspInit(void)
{
/* USER CODE BEGIN MspInit 0 */
/* USER CODE END MspInit 0 */
__HAL_RCC_SYSCFG_CLK_ENABLE();
__HAL_RCC_PWR_CLK_ENABLE();
/* System interrupt init*/
/* USER CODE BEGIN MspInit 1 */
/* USER CODE END MspInit 1 */
}
/**
* @brief TIM_Base MSP Initialization
* This function configures the hardware resources used in this example
* @param htim_base: TIM_Base handle pointer
* @retval None
*/
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* htim_base)
{
if(htim_base->Instance==TIM3)
{
/* USER CODE BEGIN TIM3_MspInit 0 */
/* USER CODE END TIM3_MspInit 0 */
/* Peripheral clock enable */
__HAL_RCC_TIM3_CLK_ENABLE();
/* USER CODE BEGIN TIM3_MspInit 1 */
/* USER CODE END TIM3_MspInit 1 */
}
else if(htim_base->Instance==TIM14)
{
/* USER CODE BEGIN TIM14_MspInit 0 */
/* USER CODE END TIM14_MspInit 0 */
/* Peripheral clock enable */
__HAL_RCC_TIM14_CLK_ENABLE();
/* USER CODE BEGIN TIM14_MspInit 1 */
/* USER CODE END TIM14_MspInit 1 */
}
else if(htim_base->Instance==TIM15)
{
/* USER CODE BEGIN TIM15_MspInit 0 */
/* USER CODE END TIM15_MspInit 0 */
/* Peripheral clock enable */
__HAL_RCC_TIM15_CLK_ENABLE();
/* USER CODE BEGIN TIM15_MspInit 1 */
/* USER CODE END TIM15_MspInit 1 */
}
}
void HAL_TIM_MspPostInit(TIM_HandleTypeDef* htim)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(htim->Instance==TIM3)
{
/* USER CODE BEGIN TIM3_MspPostInit 0 */
/* USER CODE END TIM3_MspPostInit 0 */
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/**TIM3 GPIO Configuration
PA6 ------> TIM3_CH1
PA7 ------> TIM3_CH2
PB0 ------> TIM3_CH3
PB1 ------> TIM3_CH4
*/
GPIO_InitStruct.Pin = MotRFwd_Pin|MotRRev_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF1_TIM3;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.Pin = MotLFwd_Pin|MotLRev_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF1_TIM3;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* USER CODE BEGIN TIM3_MspPostInit 1 */
/* USER CODE END TIM3_MspPostInit 1 */
}
else if(htim->Instance==TIM14)
{
/* USER CODE BEGIN TIM14_MspPostInit 0 */
/* USER CODE END TIM14_MspPostInit 0 */
__HAL_RCC_GPIOA_CLK_ENABLE();
/**TIM14 GPIO Configuration
PA4 ------> TIM14_CH1
*/
GPIO_InitStruct.Pin = MotLRBrush_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF4_TIM14;
HAL_GPIO_Init(MotLRBrush_GPIO_Port, &GPIO_InitStruct);
/* USER CODE BEGIN TIM14_MspPostInit 1 */
/* USER CODE END TIM14_MspPostInit 1 */
}
else if(htim->Instance==TIM15)
{
/* USER CODE BEGIN TIM15_MspPostInit 0 */
/* USER CODE END TIM15_MspPostInit 0 */
__HAL_RCC_GPIOA_CLK_ENABLE();
/**TIM15 GPIO Configuration
PA2 ------> TIM15_CH1
PA3 ------> TIM15_CH2
*/
GPIO_InitStruct.Pin = LED_BLUE_Pin|LED_RED_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF0_TIM15;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* USER CODE BEGIN TIM15_MspPostInit 1 */
/* USER CODE END TIM15_MspPostInit 1 */
}
}
/**
* @brief TIM_Base MSP De-Initialization
* This function freeze the hardware resources used in this example
* @param htim_base: TIM_Base handle pointer
* @retval None
*/
void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* htim_base)
{
if(htim_base->Instance==TIM3)
{
/* USER CODE BEGIN TIM3_MspDeInit 0 */
/* USER CODE END TIM3_MspDeInit 0 */
/* Peripheral clock disable */
__HAL_RCC_TIM3_CLK_DISABLE();
/* USER CODE BEGIN TIM3_MspDeInit 1 */
/* USER CODE END TIM3_MspDeInit 1 */
}
else if(htim_base->Instance==TIM14)
{
/* USER CODE BEGIN TIM14_MspDeInit 0 */
/* USER CODE END TIM14_MspDeInit 0 */
/* Peripheral clock disable */
__HAL_RCC_TIM14_CLK_DISABLE();
/* USER CODE BEGIN TIM14_MspDeInit 1 */
/* USER CODE END TIM14_MspDeInit 1 */
}
else if(htim_base->Instance==TIM15)
{
/* USER CODE BEGIN TIM15_MspDeInit 0 */
/* USER CODE END TIM15_MspDeInit 0 */
/* Peripheral clock disable */
__HAL_RCC_TIM15_CLK_DISABLE();
/* USER CODE BEGIN TIM15_MspDeInit 1 */
/* USER CODE END TIM15_MspDeInit 1 */
}
}
/**
* @brief UART MSP Initialization
* This function configures the hardware resources used in this example
* @param huart: UART handle pointer
* @retval None
*/
void HAL_UART_MspInit(UART_HandleTypeDef* huart)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(huart->Instance==USART1)
{
/* USER CODE BEGIN USART1_MspInit 0 */
/* USER CODE END USART1_MspInit 0 */
/* Peripheral clock enable */
__HAL_RCC_USART1_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
/**USART1 GPIO Configuration
PA9 ------> USART1_TX
PA10 ------> USART1_RX
*/
GPIO_InitStruct.Pin = TX_Pin|RX_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF1_USART1;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* USART1 DMA Init */
/* USART1_RX Init */
hdma_usart1_rx.Instance = DMA1_Channel3;
hdma_usart1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_usart1_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_usart1_rx.Init.MemInc = DMA_MINC_ENABLE;
hdma_usart1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_usart1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_usart1_rx.Init.Mode = DMA_NORMAL;
hdma_usart1_rx.Init.Priority = DMA_PRIORITY_LOW;
if (HAL_DMA_Init(&hdma_usart1_rx) != HAL_OK)
{
Error_Handler();
}
__HAL_LINKDMA(huart,hdmarx,hdma_usart1_rx);
/* USART1_TX Init */
hdma_usart1_tx.Instance = DMA1_Channel2;
hdma_usart1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_usart1_tx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_usart1_tx.Init.MemInc = DMA_MINC_ENABLE;
hdma_usart1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_usart1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_usart1_tx.Init.Mode = DMA_NORMAL;
hdma_usart1_tx.Init.Priority = DMA_PRIORITY_LOW;
if (HAL_DMA_Init(&hdma_usart1_tx) != HAL_OK)
{
Error_Handler();
}
__HAL_LINKDMA(huart,hdmatx,hdma_usart1_tx);
/* USART1 interrupt Init */
HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(USART1_IRQn);
/* USER CODE BEGIN USART1_MspInit 1 */
/* USER CODE END USART1_MspInit 1 */
}
}
/**
* @brief UART MSP De-Initialization
* This function freeze the hardware resources used in this example
* @param huart: UART handle pointer
* @retval None
*/
void HAL_UART_MspDeInit(UART_HandleTypeDef* huart)
{
if(huart->Instance==USART1)
{
/* USER CODE BEGIN USART1_MspDeInit 0 */
/* USER CODE END USART1_MspDeInit 0 */
/* Peripheral clock disable */
__HAL_RCC_USART1_CLK_DISABLE();
/**USART1 GPIO Configuration
PA9 ------> USART1_TX
PA10 ------> USART1_RX
*/
HAL_GPIO_DeInit(GPIOA, TX_Pin|RX_Pin);
/* USART1 DMA DeInit */
HAL_DMA_DeInit(huart->hdmarx);
HAL_DMA_DeInit(huart->hdmatx);
/* USART1 interrupt DeInit */
HAL_NVIC_DisableIRQ(USART1_IRQn);
/* USER CODE BEGIN USART1_MspDeInit 1 */
/* USER CODE END USART1_MspDeInit 1 */
}
}
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */

View File

@@ -55,7 +55,9 @@
/* USER CODE END 0 */ /* USER CODE END 0 */
/* External variables --------------------------------------------------------*/ /* External variables --------------------------------------------------------*/
extern DMA_HandleTypeDef hdma_usart1_rx;
extern DMA_HandleTypeDef hdma_usart1_tx;
extern UART_HandleTypeDef huart1;
/* USER CODE BEGIN EV */ /* USER CODE BEGIN EV */
/* USER CODE END EV */ /* USER CODE END EV */
@@ -148,12 +150,41 @@ void EXTI4_15_IRQHandler(void)
/* USER CODE BEGIN EXTI4_15_IRQn 0 */ /* USER CODE BEGIN EXTI4_15_IRQn 0 */
/* USER CODE END EXTI4_15_IRQn 0 */ /* USER CODE END EXTI4_15_IRQn 0 */
HAL_GPIO_EXTI_IRQHandler(MotRSpd_Pin); HAL_GPIO_EXTI_IRQHandler(MotLSpd_Pin);
/* USER CODE BEGIN EXTI4_15_IRQn 1 */ /* USER CODE BEGIN EXTI4_15_IRQn 1 */
/* USER CODE END EXTI4_15_IRQn 1 */ /* USER CODE END EXTI4_15_IRQn 1 */
} }
/**
* @brief This function handles DMA1 channel 2 and 3 interrupts.
*/
void DMA1_Channel2_3_IRQHandler(void)
{
/* USER CODE BEGIN DMA1_Channel2_3_IRQn 0 */
/* USER CODE END DMA1_Channel2_3_IRQn 0 */
HAL_DMA_IRQHandler(&hdma_usart1_tx);
HAL_DMA_IRQHandler(&hdma_usart1_rx);
/* USER CODE BEGIN DMA1_Channel2_3_IRQn 1 */
/* USER CODE END DMA1_Channel2_3_IRQn 1 */
}
/**
* @brief This function handles USART1 global interrupt.
*/
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
/* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1);
/* USER CODE BEGIN USART1_IRQn 1 */
/* USER CODE END USART1_IRQn 1 */
}
/* USER CODE BEGIN 1 */ /* USER CODE BEGIN 1 */
/* USER CODE END 1 */ /* USER CODE END 1 */

View File

@@ -0,0 +1,296 @@
#MicroXplorer Configuration settings - do not modify
CAD.formats=
CAD.pinconfig=
CAD.provider=
Dma.Request0=USART1_RX
Dma.Request1=USART1_TX
Dma.RequestsNb=2
Dma.USART1_RX.0.Direction=DMA_PERIPH_TO_MEMORY
Dma.USART1_RX.0.Instance=DMA1_Channel3
Dma.USART1_RX.0.MemDataAlignment=DMA_MDATAALIGN_BYTE
Dma.USART1_RX.0.MemInc=DMA_MINC_ENABLE
Dma.USART1_RX.0.Mode=DMA_NORMAL
Dma.USART1_RX.0.PeriphDataAlignment=DMA_PDATAALIGN_BYTE
Dma.USART1_RX.0.PeriphInc=DMA_PINC_DISABLE
Dma.USART1_RX.0.Priority=DMA_PRIORITY_LOW
Dma.USART1_RX.0.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority
Dma.USART1_TX.1.Direction=DMA_MEMORY_TO_PERIPH
Dma.USART1_TX.1.Instance=DMA1_Channel2
Dma.USART1_TX.1.MemDataAlignment=DMA_MDATAALIGN_BYTE
Dma.USART1_TX.1.MemInc=DMA_MINC_ENABLE
Dma.USART1_TX.1.Mode=DMA_NORMAL
Dma.USART1_TX.1.PeriphDataAlignment=DMA_PDATAALIGN_BYTE
Dma.USART1_TX.1.PeriphInc=DMA_PINC_DISABLE
Dma.USART1_TX.1.Priority=DMA_PRIORITY_LOW
Dma.USART1_TX.1.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority
File.Version=6
GPIO.groupedBy=Group By Peripherals
KeepUserPlacement=false
Mcu.CPN=STM32F030C8T6
Mcu.Family=STM32F0
Mcu.IP0=ADC
Mcu.IP1=DMA
Mcu.IP10=USART1
Mcu.IP2=NVIC
Mcu.IP3=RCC
Mcu.IP4=SYS
Mcu.IP5=TIM3
Mcu.IP6=TIM14
Mcu.IP7=TIM15
Mcu.IP8=TIM16
Mcu.IP9=TIM17
Mcu.IPNb=11
Mcu.Name=STM32F030C8Tx
Mcu.Package=LQFP48
Mcu.Pin0=PC13
Mcu.Pin1=PA0
Mcu.Pin10=PB1
Mcu.Pin11=PB2
Mcu.Pin12=PB13
Mcu.Pin13=PA8
Mcu.Pin14=PA9
Mcu.Pin15=PA10
Mcu.Pin16=PA11
Mcu.Pin17=PA13
Mcu.Pin18=PA14
Mcu.Pin19=PB6
Mcu.Pin2=PA1
Mcu.Pin20=PB7
Mcu.Pin21=PB8
Mcu.Pin22=PB9
Mcu.Pin23=VP_SYS_VS_Systick
Mcu.Pin24=VP_TIM3_VS_ClockSourceINT
Mcu.Pin25=VP_TIM14_VS_ClockSourceINT
Mcu.Pin26=VP_TIM15_VS_ClockSourceINT
Mcu.Pin27=VP_TIM16_VS_ClockSourceINT
Mcu.Pin28=VP_TIM17_VS_ClockSourceINT
Mcu.Pin3=PA2
Mcu.Pin4=PA3
Mcu.Pin5=PA4
Mcu.Pin6=PA5
Mcu.Pin7=PA6
Mcu.Pin8=PA7
Mcu.Pin9=PB0
Mcu.PinsNb=29
Mcu.ThirdPartyNb=0
Mcu.UserConstants=
Mcu.UserName=STM32F030C8Tx
MxCube.Version=6.17.0
MxDb.Version=DB.6.0.170
NVIC.DMA1_Channel2_3_IRQn=true\:0\:0\:false\:false\:true\:false\:true\:true
NVIC.EXTI4_15_IRQn=true\:0\:0\:false\:false\:true\:true\:true\:true
NVIC.ForceEnableDMAVector=true
NVIC.HardFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
NVIC.NonMaskableInt_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
NVIC.PendSV_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
NVIC.SVC_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:true
NVIC.SysTick_IRQn=true\:3\:0\:false\:false\:true\:false\:true\:false
NVIC.USART1_IRQn=true\:0\:0\:false\:false\:true\:true\:true\:true
PA0.Locked=true
PA0.Mode=IN0
PA0.Signal=ADC_IN0
PA1.Locked=true
PA1.Mode=IN1
PA1.Signal=ADC_IN1
PA10.GPIOParameters=GPIO_Label
PA10.GPIO_Label=IRMR
PA10.Locked=true
PA10.Signal=GPIO_Input
PA11.GPIOParameters=GPIO_Label
PA11.GPIO_Label=IRR
PA11.Locked=true
PA11.Signal=GPIO_Input
PA13.Mode=Serial_Wire
PA13.Signal=SYS_SWDIO
PA14.Locked=true
PA14.Mode=Serial_Wire
PA14.Signal=SYS_SWCLK
PA2.GPIOParameters=GPIO_Label
PA2.GPIO_Label=LED_BLUE
PA2.Locked=true
PA2.Signal=S_TIM15_CH1
PA3.GPIOParameters=GPIO_Label
PA3.GPIO_Label=LED_RED
PA3.Locked=true
PA3.Signal=S_TIM15_CH2
PA4.GPIOParameters=GPIO_Label
PA4.GPIO_Label=MotLRBrush
PA4.Locked=true
PA4.Signal=S_TIM14_CH1
PA5.GPIOParameters=GPIO_Label
PA5.GPIO_Label=MotLSpd
PA5.Locked=true
PA5.Signal=GPXTI5
PA6.GPIOParameters=GPIO_Label
PA6.GPIO_Label=MotLFwd
PA6.Locked=true
PA6.Signal=S_TIM3_CH1
PA7.GPIOParameters=GPIO_Label
PA7.GPIO_Label=MotLRev
PA7.Locked=true
PA7.Signal=S_TIM3_CH2
PA8.GPIOParameters=GPIO_Label
PA8.GPIO_Label=IRL
PA8.Locked=true
PA8.Signal=GPIO_Input
PA9.GPIOParameters=GPIO_Label
PA9.GPIO_Label=IRML
PA9.Locked=true
PA9.Signal=GPIO_Input
PB0.GPIOParameters=GPIO_Label
PB0.GPIO_Label=MotRFwd
PB0.Locked=true
PB0.Signal=S_TIM3_CH3
PB1.GPIOParameters=GPIO_Label
PB1.GPIO_Label=MotRRev
PB1.Locked=true
PB1.Signal=S_TIM3_CH4
PB13.GPIOParameters=GPIO_Label
PB13.GPIO_Label=LED_Bumper
PB13.Locked=true
PB13.Signal=GPIO_Output
PB2.GPIOParameters=GPIO_Label
PB2.GPIO_Label=MotRSpd
PB2.Locked=true
PB2.Signal=GPXTI2
PB6.GPIOParameters=GPIO_Label
PB6.GPIO_Label=TX
PB6.Locked=true
PB6.Mode=Asynchronous
PB6.Signal=USART1_TX
PB7.GPIOParameters=GPIO_Label
PB7.GPIO_Label=RX
PB7.Locked=true
PB7.Mode=Asynchronous
PB7.Signal=USART1_RX
PB8.GPIOParameters=GPIO_Label
PB8.GPIO_Label=MotBBrush
PB8.Locked=true
PB8.Signal=S_TIM16_CH1
PB9.GPIOParameters=GPIO_Label
PB9.GPIO_Label=MotBlower
PB9.Locked=true
PB9.Signal=S_TIM17_CH1
PC13.GPIOParameters=GPIO_Label
PC13.GPIO_Label=LED_0
PC13.Locked=true
PC13.Signal=GPIO_Output
PCC.Checker=false
PCC.Display=Plot\: All Steps
PCC.Line=STM32F0x0 Value Line
PCC.MCU=STM32F030C8Tx
PCC.PartNumber=STM32F030C8Tx
PCC.Series=STM32F0
PCC.Temperature=25
PCC.Vdd=3.6
PinOutPanel.RotationAngle=0
ProjectManager.AskForMigrate=true
ProjectManager.BackupPrevious=false
ProjectManager.CompilerLinker=GCC
ProjectManager.CompilerOptimize=6
ProjectManager.ComputerToolchain=false
ProjectManager.CoupleFile=false
ProjectManager.CustomerFirmwarePackage=../../../vendor/STM32CubeF0
ProjectManager.DefaultFWLocation=false
ProjectManager.DeletePrevious=true
ProjectManager.DeviceId=STM32F030C8Tx
ProjectManager.FirmwarePackage=STM32Cube FW_F0 V1.11.6
ProjectManager.FreePins=false
ProjectManager.FreePinsContext=
ProjectManager.HalAssertFull=false
ProjectManager.HeapSize=0x80
ProjectManager.KeepUserCode=true
ProjectManager.LastFirmware=true
ProjectManager.LibraryCopy=2
ProjectManager.MainLocation=Src
ProjectManager.NoMain=false
ProjectManager.PreviousToolchain=
ProjectManager.ProjectBuild=false
ProjectManager.ProjectFileName=stm32f030.ioc
ProjectManager.ProjectName=stm32f030
ProjectManager.ProjectStructure=
ProjectManager.RegisterCallBack=
ProjectManager.StackSize=0x400
ProjectManager.TargetToolchain=CMake
ProjectManager.ToolChainLocation=
ProjectManager.UAScriptAfterPath=
ProjectManager.UAScriptBeforePath=
ProjectManager.UnderRoot=false
ProjectManager.functionlistsort=1-SystemClock_Config-RCC-false-HAL-false,2-MX_GPIO_Init-GPIO-false-HAL-true,3-MX_DMA_Init-DMA-false-HAL-true,4-MX_TIM3_Init-TIM3-false-HAL-true,5-MX_USART1_UART_Init-USART1-false-HAL-true,6-MX_TIM15_Init-TIM15-false-HAL-true,7-MX_TIM14_Init-TIM14-false-HAL-true,8-MX_ADC_Init-ADC-false-HAL-true,9-MX_TIM16_Init-TIM16-false-HAL-true,10-MX_TIM17_Init-TIM17-false-HAL-true
RCC.AHBFreq_Value=48000000
RCC.APB1Freq_Value=48000000
RCC.APB1TimFreq_Value=48000000
RCC.FCLKCortexFreq_Value=48000000
RCC.FamilyName=M
RCC.HCLKFreq_Value=48000000
RCC.IPParameters=AHBFreq_Value,APB1Freq_Value,APB1TimFreq_Value,FCLKCortexFreq_Value,FamilyName,HCLKFreq_Value,MCOFreq_Value,PLLCLKFreq_Value,PLLMCOFreq_Value,PLLMUL,SYSCLKFreq_VALUE,SYSCLKSource,TimSysFreq_Value,USART1Freq_Value
RCC.MCOFreq_Value=48000000
RCC.PLLCLKFreq_Value=48000000
RCC.PLLMCOFreq_Value=24000000
RCC.PLLMUL=RCC_PLL_MUL12
RCC.SYSCLKFreq_VALUE=48000000
RCC.SYSCLKSource=RCC_SYSCLKSOURCE_PLLCLK
RCC.TimSysFreq_Value=48000000
RCC.USART1Freq_Value=48000000
SH.GPXTI2.0=GPIO_EXTI2
SH.GPXTI2.ConfNb=1
SH.GPXTI5.0=GPIO_EXTI5
SH.GPXTI5.ConfNb=1
SH.S_TIM14_CH1.0=TIM14_CH1,PWM Generation1 CH1
SH.S_TIM14_CH1.ConfNb=1
SH.S_TIM15_CH1.0=TIM15_CH1,PWM Generation1 CH1
SH.S_TIM15_CH1.ConfNb=1
SH.S_TIM15_CH2.0=TIM15_CH2,PWM Generation2 CH2
SH.S_TIM15_CH2.ConfNb=1
SH.S_TIM16_CH1.0=TIM16_CH1,PWM Generation1 CH1
SH.S_TIM16_CH1.ConfNb=1
SH.S_TIM17_CH1.0=TIM17_CH1,Output Compare1 CH1
SH.S_TIM17_CH1.ConfNb=1
SH.S_TIM3_CH1.0=TIM3_CH1,PWM Generation1 CH1
SH.S_TIM3_CH1.ConfNb=1
SH.S_TIM3_CH2.0=TIM3_CH2,PWM Generation2 CH2
SH.S_TIM3_CH2.ConfNb=1
SH.S_TIM3_CH3.0=TIM3_CH3,PWM Generation3 CH3
SH.S_TIM3_CH3.ConfNb=1
SH.S_TIM3_CH4.0=TIM3_CH4,PWM Generation4 CH4
SH.S_TIM3_CH4.ConfNb=1
TIM14.AutoReloadPreload=TIM_AUTORELOAD_PRELOAD_ENABLE
TIM14.Channel=TIM_CHANNEL_1
TIM14.IPParameters=Channel,Period,AutoReloadPreload
TIM14.Period=1600
TIM15.AutoReloadPreload=TIM_AUTORELOAD_PRELOAD_ENABLE
TIM15.Channel-PWM\ Generation1\ CH1=TIM_CHANNEL_1
TIM15.Channel-PWM\ Generation2\ CH2=TIM_CHANNEL_2
TIM15.IPParameters=Channel-PWM Generation1 CH1,Channel-PWM Generation2 CH2,AutoReloadPreload,Period
TIM15.Period=1600
TIM16.AutoReloadPreload=TIM_AUTORELOAD_PRELOAD_ENABLE
TIM16.Channel=TIM_CHANNEL_1
TIM16.IPParameters=Channel,Period,AutoReloadPreload
TIM16.Period=1600
TIM17.AutoReloadPreload=TIM_AUTORELOAD_PRELOAD_ENABLE
TIM17.Channel=TIM_CHANNEL_1
TIM17.IPParameters=Channel,Period,AutoReloadPreload
TIM17.Period=1600
TIM3.AutoReloadPreload=TIM_AUTORELOAD_PRELOAD_ENABLE
TIM3.Channel-PWM\ Generation1\ CH1=TIM_CHANNEL_1
TIM3.Channel-PWM\ Generation2\ CH2=TIM_CHANNEL_2
TIM3.Channel-PWM\ Generation3\ CH3=TIM_CHANNEL_3
TIM3.Channel-PWM\ Generation4\ CH4=TIM_CHANNEL_4
TIM3.IPParameters=Channel-PWM Generation1 CH1,Channel-PWM Generation2 CH2,Period,AutoReloadPreload,Channel-PWM Generation3 CH3,Channel-PWM Generation4 CH4
TIM3.Period=3200
USART1.BaudRate=115200
USART1.IPParameters=VirtualMode-Asynchronous,BaudRate
USART1.VirtualMode-Asynchronous=VM_ASYNC
VP_SYS_VS_Systick.Mode=SysTick
VP_SYS_VS_Systick.Signal=SYS_VS_Systick
VP_TIM14_VS_ClockSourceINT.Mode=Enable_Timer
VP_TIM14_VS_ClockSourceINT.Signal=TIM14_VS_ClockSourceINT
VP_TIM15_VS_ClockSourceINT.Mode=Internal
VP_TIM15_VS_ClockSourceINT.Signal=TIM15_VS_ClockSourceINT
VP_TIM16_VS_ClockSourceINT.Mode=Enable_Timer
VP_TIM16_VS_ClockSourceINT.Signal=TIM16_VS_ClockSourceINT
VP_TIM17_VS_ClockSourceINT.Mode=Enable_Timer
VP_TIM17_VS_ClockSourceINT.Signal=TIM17_VS_ClockSourceINT
VP_TIM3_VS_ClockSourceINT.Mode=Internal
VP_TIM3_VS_ClockSourceINT.Signal=TIM3_VS_ClockSourceINT
board=custom

View File

@@ -0,0 +1,357 @@
#!/usr/bin/env python3
import argparse
import struct
import threading
import time
from collections import deque
from queue import Empty, Queue
try:
import pygame
except ImportError as exc:
raise SystemExit(
"Missing dependency: pygame. Install with `pip install pygame pyserial`."
) from exc
try:
import serial
except ImportError as exc:
raise SystemExit(
"Missing dependency: pyserial. Install with `pip install pygame pyserial`."
) from exc
RECORD_STRUCT = struct.Struct("<IIIII")
RECORD_FIELDS = ("ms", "ticks_r", "target_r", "ticks_l", "target_l")
BACKGROUND = (18, 20, 24)
GRID = (48, 54, 64)
AXIS = (140, 148, 160)
TEXT = (230, 235, 240)
ERROR = (255, 110, 110)
TRACE_DEFS = [
{
"name": "speed_r",
"label": "SPEED_R",
"color": (80, 220, 140),
"unit": "ticks/s",
"kind": "derived",
"compute": lambda window: compute_speed(window, "ticks_r"),
},
{
"name": "target_r",
"label": "TARGET_R",
"color": (220, 80, 140),
"unit": "ticks/s",
"kind": "field",
"field": "target_r",
},
{
"name": "speed_l",
"label": "SPEED_L",
"color": (80, 170, 255),
"unit": "ticks/s",
"kind": "derived",
"compute": lambda window: compute_speed(window, "ticks_l"),
},
{
"name": "target_l",
"label": "TARGET_L",
"color": (255, 190, 80),
"unit": "ticks/s",
"kind": "field",
"field": "target_l",
},
]
def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(
description="Read binary motor samples from a serial port and draw traces live."
)
parser.add_argument("port", help="Serial port, for example /dev/ttyUSB0 or COM3")
parser.add_argument(
"-b",
"--baudrate",
type=int,
default=115200,
help="Serial baudrate (default: 115200)",
)
parser.add_argument(
"--history-seconds",
type=float,
default=10.0,
help="Initial visible history window in seconds (default: 10)",
)
parser.add_argument(
"--avg-window",
type=int,
default=5,
help="Sliding average window in samples for derived traces (default: 5)",
)
parser.add_argument(
"--max-samples",
type=int,
default=30000,
help="Maximum number of samples to keep in memory (default: 30000)",
)
parser.add_argument(
"--width",
type=int,
default=1200,
help="Window width in pixels (default: 1200)",
)
parser.add_argument(
"--height",
type=int,
default=700,
help="Window height in pixels (default: 700)",
)
return parser.parse_args()
def serial_reader(port: str, baudrate: int, output: Queue) -> None:
try:
with serial.Serial(port, baudrate=baudrate, timeout=1) as ser:
while True:
raw = ser.read(RECORD_STRUCT.size)
if len(raw) != RECORD_STRUCT.size:
continue
values = RECORD_STRUCT.unpack(raw)
sample = dict(zip(RECORD_FIELDS, values))
sample["wall_time"] = time.monotonic()
output.put(sample)
except serial.SerialException as exc:
output.put({"error": f"Serial error: {exc}"})
def compute_speed(
raw_window: list[dict[str, float | int]],
tick_field: str,
) -> float | None:
if len(raw_window) < 2:
return None
first = raw_window[0]
last = raw_window[-1]
dt_ms = int(last["ms"]) - int(first["ms"])
if dt_ms <= 0:
return None
dt_ticks = int(last[tick_field]) - int(first[tick_field])
return (1000.0 * dt_ticks) / dt_ms
def update_traces(
raw_samples: deque[dict[str, float | int]],
trace_samples: dict[str, deque[tuple[float, float, dict[str, float | int]]]],
avg_window: int,
) -> None:
window = list(raw_samples)[-max(avg_window, 2):]
sample = raw_samples[-1]
for trace in TRACE_DEFS:
value = None
if trace["kind"] == "field":
value = float(sample[trace["field"]])
elif trace["kind"] == "derived":
value = trace["compute"](window)
if value is not None:
trace_samples[trace["name"]].append(
(float(sample["wall_time"]), float(value), sample)
)
def drain_queue(
queue: Queue,
raw_samples: deque[dict[str, float | int]],
trace_samples: dict[str, deque[tuple[float, float, dict[str, float | int]]]],
avg_window: int,
) -> str | None:
error_message = None
while True:
try:
item = queue.get_nowait()
except Empty:
return error_message
if "error" in item:
error_message = str(item["error"])
continue
raw_samples.append(item)
update_traces(raw_samples, trace_samples, avg_window)
def draw_grid(
surface: pygame.Surface,
rect: pygame.Rect,
font: pygame.font.Font,
view_span: float,
y_max: float,
) -> None:
pygame.draw.rect(surface, GRID, rect, width=1)
for fraction in (0.0, 0.25, 0.5, 0.75, 1.0):
y = rect.top + round(fraction * rect.height)
pygame.draw.line(surface, GRID, (rect.left, y), (rect.right, y), 1)
value = (1.0 - fraction) * y_max
text = font.render(f"{value:.1f}", True, AXIS)
surface.blit(text, (10, y - text.get_height() // 2))
for fraction in (0.0, 0.25, 0.5, 0.75, 1.0):
x = rect.left + round(fraction * rect.width)
pygame.draw.line(surface, GRID, (x, rect.top), (x, rect.bottom), 1)
seconds_ago = view_span * (1.0 - fraction)
label = f"-{seconds_ago:.1f}s" if seconds_ago > 0.05 else "now"
text = font.render(label, True, AXIS)
surface.blit(text, (x - text.get_width() // 2, rect.bottom + 8))
def draw_trace(
surface: pygame.Surface,
rect: pygame.Rect,
samples: deque[tuple[float, float, dict[str, float | int]]],
view_span: float,
now: float,
color: tuple[int, int, int],
y_max: float,
) -> tuple[float | None, dict[str, float | int] | None]:
visible_points = []
latest_value = None
latest_sample = None
for timestamp, value, sample in samples:
age = now - timestamp
if age < 0 or age > view_span:
continue
x = rect.right - (age / view_span) * rect.width
y = rect.bottom - (value / y_max) * rect.height
visible_points.append((round(x), round(y)))
latest_value = value
latest_sample = sample
if len(visible_points) >= 2:
pygame.draw.lines(surface, color, False, visible_points, 2)
elif len(visible_points) == 1:
pygame.draw.circle(surface, color, visible_points[0], 2)
return latest_value, latest_sample
def zoom(view_span: float, direction: int, initial_span: float) -> float:
if direction > 0:
return max(1.0, view_span / 1.2)
return min(max(initial_span * 20.0, 60.0), view_span * 1.2)
def main() -> int:
args = parse_args()
raw_samples: deque[dict[str, float | int]] = deque(maxlen=args.max_samples)
trace_samples = {
trace["name"]: deque(maxlen=args.max_samples) for trace in TRACE_DEFS
}
queue: Queue = Queue()
thread = threading.Thread(
target=serial_reader, args=(args.port, args.baudrate, queue), daemon=True
)
thread.start()
pygame.init()
pygame.display.set_caption(f"Motor traces: {args.port} @ {args.baudrate}")
screen = pygame.display.set_mode((args.width, args.height), pygame.RESIZABLE)
font = pygame.font.SysFont("monospace", 18)
small_font = pygame.font.SysFont("monospace", 14)
clock = pygame.time.Clock()
view_span = max(args.history_seconds, 1.0)
error_message = None
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.MOUSEWHEEL:
view_span = zoom(view_span, event.y, args.history_seconds)
elif event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 4:
view_span = zoom(view_span, 1, args.history_seconds)
elif event.button == 5:
view_span = zoom(view_span, -1, args.history_seconds)
queued_error = drain_queue(queue, raw_samples, trace_samples, args.avg_window)
if queued_error is not None:
error_message = queued_error
width, height = screen.get_size()
plot_rect = pygame.Rect(70, 40, max(100, width - 100), max(100, height - 100))
now = time.monotonic()
y_max = 1.0
for trace in TRACE_DEFS:
for timestamp, value, _sample in trace_samples[trace["name"]]:
age = now - timestamp
if 0 <= age <= view_span and value > y_max:
y_max = value
y_max = max(10.0, y_max * 1.2)
screen.fill(BACKGROUND)
draw_grid(screen, plot_rect, small_font, view_span, y_max)
latest_values: dict[str, float] = {}
latest_sample: dict[str, float | int] | None = None
for trace in TRACE_DEFS:
value, sample = draw_trace(
screen,
plot_rect,
trace_samples[trace["name"]],
view_span,
now,
trace["color"],
y_max,
)
if value is not None:
latest_values[trace["name"]] = value
if sample is not None:
latest_sample = sample
header = (
f"port={args.port} baud={args.baudrate} zoom={view_span:.1f}s "
f"avg_window={args.avg_window}"
)
screen.blit(font.render(header, True, TEXT), (10, 8))
screen.blit(
small_font.render("mouse wheel: zoom horizontal axis", True, AXIS),
(10, height - 24),
)
legend_x = 10
for trace in TRACE_DEFS:
pygame.draw.line(
screen,
trace["color"],
(legend_x, 43),
(legend_x + 24, 43),
3,
)
screen.blit(small_font.render(trace["label"], True, TEXT), (legend_x + 30, 34))
legend_x += 120
if error_message:
error_surface = font.render(error_message, True, ERROR)
screen.blit(error_surface, (10, 56))
pygame.display.flip()
clock.tick(60)
pygame.quit()
return 0
if __name__ == "__main__":
raise SystemExit(main())