spu stuff
This commit is contained in:
2
SW/spu/.vscode/c_cpp_properties.json
vendored
2
SW/spu/.vscode/c_cpp_properties.json
vendored
@@ -3,7 +3,7 @@
|
||||
"configurations": [
|
||||
{
|
||||
"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",
|
||||
"compilerPath": "/usr/bin/arm-none-eabi-gcc"
|
||||
}
|
||||
|
||||
8
SW/spu/.vscode/launch.json
vendored
8
SW/spu/.vscode/launch.json
vendored
@@ -5,13 +5,13 @@
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Debug blinky (J-Link)",
|
||||
"name": "Debug motor_control (J-Link)",
|
||||
"cwd": "${workspaceFolder}",
|
||||
"executable": "${workspaceFolder}/app/blinky/stm32f030/build/blinky.elf",
|
||||
"preLaunchTask": "Build blinky stm32f030",
|
||||
"executable": "${workspaceFolder}/app/motor_control/stm32f030/build/motor_control.elf",
|
||||
"preLaunchTask": "Build motor_control stm32f030",
|
||||
"request": "launch",
|
||||
"type": "cortex-debug",
|
||||
"runToEntryPoint": "app_main",
|
||||
// "runToEntryPoint": "app_main",
|
||||
"servertype": "jlink",
|
||||
"device": "STM32F030C8",
|
||||
"interface": "swd",
|
||||
|
||||
12
SW/spu/.vscode/tasks.json
vendored
12
SW/spu/.vscode/tasks.json
vendored
@@ -2,14 +2,14 @@
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "Configure blinky stm32f030",
|
||||
"label": "Configure motor_control stm32f030",
|
||||
"type": "shell",
|
||||
"command": "cmake",
|
||||
"args": [
|
||||
"-S",
|
||||
"${workspaceFolder}/app/blinky/stm32f030",
|
||||
"${workspaceFolder}/app/motor_control/stm32f030",
|
||||
"-B",
|
||||
"${workspaceFolder}/app/blinky/stm32f030/build",
|
||||
"${workspaceFolder}/app/motor_control/stm32f030/build",
|
||||
"-DCMAKE_BUILD_TYPE=Debug"
|
||||
],
|
||||
"options": {
|
||||
@@ -18,18 +18,18 @@
|
||||
"problemMatcher": []
|
||||
},
|
||||
{
|
||||
"label": "Build blinky stm32f030",
|
||||
"label": "Build motor_control stm32f030",
|
||||
"type": "shell",
|
||||
"command": "cmake",
|
||||
"args": [
|
||||
"--build",
|
||||
"${workspaceFolder}/app/blinky/stm32f030/build"
|
||||
"${workspaceFolder}/app/motor_control/stm32f030/build"
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}"
|
||||
},
|
||||
"dependsOn": [
|
||||
"Configure blinky stm32f030"
|
||||
"Configure motor_control stm32f030"
|
||||
],
|
||||
"group": {
|
||||
"kind": "build",
|
||||
|
||||
@@ -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
@@ -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 */
|
||||
@@ -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
|
||||
207
SW/spu/app/motor_control/src/app_main.c
Normal file
207
SW/spu/app/motor_control/src/app_main.c
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
14
SW/spu/app/motor_control/stm32f030/.mxproject
Normal file
14
SW/spu/app/motor_control/stm32f030/.mxproject
Normal file
File diff suppressed because one or more lines are too long
@@ -10,7 +10,7 @@ endif()
|
||||
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS TRUE)
|
||||
set(CMAKE_TOOLCHAIN_FILE ${CMAKE_CURRENT_SOURCE_DIR}/cmake/gcc-arm-none-eabi.cmake)
|
||||
project(blinky)
|
||||
project(motor_control)
|
||||
enable_language(C ASM)
|
||||
|
||||
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_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_uart.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../../vendor/STM32CubeF0/Drivers/STM32F0xx_HAL_Driver/Src/stm32f0xx_hal_uart_ex.c
|
||||
)
|
||||
|
||||
set(CUBE_inc
|
||||
@@ -50,14 +52,14 @@ set(CUBE_inc
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../../vendor/STM32CubeF0/Drivers/CMSIS/Include
|
||||
)
|
||||
|
||||
add_executable(blinky
|
||||
add_executable(motor_control
|
||||
${CUBE_src}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../src/app_main.c
|
||||
)
|
||||
target_include_directories(blinky PUBLIC
|
||||
target_include_directories(motor_control PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../src
|
||||
${CUBE_inc}
|
||||
)
|
||||
target_compile_definitions(blinky PUBLIC
|
||||
target_compile_definitions(motor_control PUBLIC
|
||||
${CUBE_def}
|
||||
)
|
||||
)
|
||||
@@ -61,16 +61,36 @@ void Error_Handler(void);
|
||||
/* Private defines -----------------------------------------------------------*/
|
||||
#define LED_0_Pin GPIO_PIN_13
|
||||
#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_GPIO_Port GPIOA
|
||||
#define MotRRev_Pin GPIO_PIN_7
|
||||
#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_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 */
|
||||
#define MotPwmTimerHandle htim3
|
||||
extern TIM_HandleTypeDef htim3;
|
||||
|
||||
#define UartHandle huart1
|
||||
extern UART_HandleTypeDef huart1;
|
||||
/* USER CODE END Private defines */
|
||||
|
||||
#ifdef __cplusplus
|
||||
@@ -50,7 +50,7 @@
|
||||
/*#define HAL_RTC_MODULE_ENABLED */
|
||||
/*#define HAL_SPI_MODULE_ENABLED */
|
||||
#define HAL_TIM_MODULE_ENABLED
|
||||
/*#define HAL_UART_MODULE_ENABLED */
|
||||
#define HAL_UART_MODULE_ENABLED
|
||||
/*#define HAL_USART_MODULE_ENABLED */
|
||||
/*#define HAL_IRDA_MODULE_ENABLED */
|
||||
/*#define HAL_SMARTCARD_MODULE_ENABLED */
|
||||
@@ -52,6 +52,8 @@ void SVC_Handler(void);
|
||||
void PendSV_Handler(void);
|
||||
void SysTick_Handler(void);
|
||||
void EXTI4_15_IRQHandler(void);
|
||||
void DMA1_Channel2_3_IRQHandler(void);
|
||||
void USART1_IRQHandler(void);
|
||||
/* USER CODE BEGIN EFP */
|
||||
|
||||
/* USER CODE END EFP */
|
||||
@@ -41,6 +41,12 @@
|
||||
|
||||
/* Private variables ---------------------------------------------------------*/
|
||||
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 */
|
||||
|
||||
@@ -49,7 +55,11 @@ TIM_HandleTypeDef htim3;
|
||||
/* Private function prototypes -----------------------------------------------*/
|
||||
void SystemClock_Config(void);
|
||||
static void MX_GPIO_Init(void);
|
||||
static void MX_DMA_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 END PFP */
|
||||
@@ -88,7 +98,11 @@ int main(void)
|
||||
|
||||
/* Initialize all configured peripherals */
|
||||
MX_GPIO_Init();
|
||||
MX_DMA_Init();
|
||||
MX_TIM3_Init();
|
||||
MX_USART1_UART_Init();
|
||||
MX_TIM15_Init();
|
||||
MX_TIM14_Init();
|
||||
/* USER CODE BEGIN 2 */
|
||||
extern void app_main();
|
||||
app_main();
|
||||
@@ -113,6 +127,7 @@ void SystemClock_Config(void)
|
||||
{
|
||||
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
|
||||
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
|
||||
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
|
||||
|
||||
/** Initializes the RCC Oscillators according to the specified parameters
|
||||
* in the RCC_OscInitTypeDef structure.
|
||||
@@ -141,6 +156,12 @@ void SystemClock_Config(void)
|
||||
{
|
||||
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.Init.Prescaler = 0;
|
||||
htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
|
||||
htim3.Init.Period = 1600;
|
||||
htim3.Init.Period = 3200;
|
||||
htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
|
||||
htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
|
||||
if (HAL_TIM_Base_Init(&htim3) != HAL_OK)
|
||||
@@ -199,6 +220,14 @@ static void MX_TIM3_Init(void)
|
||||
{
|
||||
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 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
|
||||
* @param None
|
||||
@@ -233,6 +438,12 @@ static void MX_GPIO_Init(void)
|
||||
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
|
||||
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 */
|
||||
GPIO_InitStruct.Pin = MotRSpd_Pin;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
|
||||
361
SW/spu/app/motor_control/stm32f030/Src/stm32f0xx_hal_msp.c
Normal file
361
SW/spu/app/motor_control/stm32f030/Src/stm32f0xx_hal_msp.c
Normal 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 */
|
||||
@@ -55,7 +55,9 @@
|
||||
/* USER CODE END 0 */
|
||||
|
||||
/* External variables --------------------------------------------------------*/
|
||||
|
||||
extern DMA_HandleTypeDef hdma_usart1_rx;
|
||||
extern DMA_HandleTypeDef hdma_usart1_tx;
|
||||
extern UART_HandleTypeDef huart1;
|
||||
/* USER CODE BEGIN EV */
|
||||
|
||||
/* USER CODE END EV */
|
||||
@@ -148,12 +150,41 @@ void EXTI4_15_IRQHandler(void)
|
||||
/* USER CODE BEGIN 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 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 END 1 */
|
||||
296
SW/spu/app/motor_control/stm32f030/stm32f030.ioc
Normal file
296
SW/spu/app/motor_control/stm32f030/stm32f030.ioc
Normal 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
|
||||
357
SW/spu/scripts/plot_motor_ticks.py
Normal file
357
SW/spu/scripts/plot_motor_ticks.py
Normal 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())
|
||||
Reference in New Issue
Block a user