diff --git a/CMakeLists.txt b/CMakeLists.txt index 0185180..d490bd3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -59,127 +59,16 @@ target_link_options(${CMAKE_PROJECT_NAME} PRIVATE -u _printf_float ) -# ETK module configuration options - based on etk CMakeLists.txt option naming -# Algorithm modules -# set(ETK_ALGORITHM ON CACHE BOOL "Enable algorithm module") -# set(ALG_DSP_UTILS ON CACHE BOOL "Enable dsp_utils submodule") -# set(ALG_FILTER ON CACHE BOOL "Enable filter submodule") -# set(ALG_GROOVE_TRACKER OFF CACHE BOOL "Enable groove_tracker submodule") -# set(ALG_MATH ON CACHE BOOL "Enable math submodule") -# set(ALG_PID ON CACHE BOOL "Enable pid submodule") -# set(ALG_TREND OFF CACHE BOOL "Enable trend submodule") - -# # DSP Utils submodules -# set(ALG_FFT OFF CACHE BOOL "Enable FFT submodule") -# set(ALG_FREQ_ANALYZER OFF CACHE BOOL "Enable frequency analyzer submodule") -# set(ALG_GOERTZEL ON CACHE BOOL "Enable Goertzel submodule") -# set(ALG_INTERP OFF CACHE BOOL "Enable interpolation submodule") -# set(ALG_WAVES OFF CACHE BOOL "Enable waves submodule") -# set(ALG_WINDOWS OFF CACHE BOOL "Enable windows submodule") -# set(ETK_ZERO_CROSS ON CACHE BOOL "Enable zero_cross submodule") - -# # Filter submodules -# set(ALG_BUTTERWORTH_FILTER OFF CACHE BOOL "Enable Butterworth filter submodule") -# set(ALG_CHEBYSHEV_FILTER OFF CACHE BOOL "Enable Chebyshev filter submodule") -# set(ALG_EMA_FILTER ON CACHE BOOL "Enable EMA filter submodule") -# set(ALG_FIR_FILTER OFF CACHE BOOL "Enable FIR filter submodule") -# set(ALG_GAUSSIAN_FILTER OFF CACHE BOOL "Enable Gaussian filter submodule") -# set(ALG_HIGH_PASS_FILTER OFF CACHE BOOL "Enable high pass filter submodule") -# set(ALG_IIR_FILTER OFF CACHE BOOL "Enable IIR filter submodule") -# set(ALG_KALMAN_FILTER OFF CACHE BOOL "Enable Kalman filter submodule") -# set(ALG_MEDIAN_FILTER OFF CACHE BOOL "Enable median filter submodule") -# set(ALG_SAVITZKY_FILTER OFF CACHE BOOL "Enable Savitzky filter submodule") -# set(ALG_SLIDING_FILTER OFF CACHE BOOL "Enable sliding filter submodule") - -# # Math submodules -# set(ALG_WAVEFORM_ANALYSIS OFF CACHE BOOL "Enable waveform analysis submodule") -# set(ALG_LINEAR_SOLVER OFF CACHE BOOL "Enable linear solver submodule") -# set(ALG_NEWTON OFF CACHE BOOL "Enable Newton method submodule") -# set(ALG_DIFF OFF CACHE BOOL "Enable differentiation submodule") -# set(ALG_SLOPE ON CACHE BOOL "Enable slope calculation submodule") - -# # Drivers modules -# set(ETK_DRIVERS ON CACHE BOOL "Enable drivers module") -# set(DRV_AD779X OFF CACHE BOOL "Enable ad779x driver submodule") -# set(DRV_ENCODER ON CACHE BOOL "Enable encoder driver submodule") - -# # Utils modules -# set(ETK_UTILS ON CACHE BOOL "Enable utils module") -# set(UTIL_BYTE_CONV ON CACHE BOOL "Enable byte_conversion submodule") -# set(UTIL_FLEX_QUEUE OFF CACHE BOOL "Enable flex_queue submodule") -# set(UTIL_RINGBUFFER ON CACHE BOOL "Enable ringbuffer submodule") - -# # System modules -# set(ETK_OS_ADAPT OFF CACHE BOOL "Enable os_adapt module") -# set(ETK_LOG_FRAMEWORK OFF CACHE BOOL "Enable log framework module") -# set(UTIL_LOG_SIMPLE ON CACHE BOOL "Enable logging module") - -# # Communication modules -# set(ETK_COMMUNICATION OFF CACHE BOOL "Enable communication module") - -# # Thirdparty modules -# set(THIRDPARTY ON CACHE BOOL "Enable thirdparty module") -# set(NANOMODBUS ON CACHE BOOL "Enable nanomodbus submodule") - -# # Common modules (always enabled as base dependency) -# set(ETK_COMMON ON CACHE BOOL "Enable common module") -# set(ETK_ROOT_CMAKE ON CACHE BOOL "Build all modules into a single etk library") -# set(SYSTEM_TYPE 2 CACHE STRING "System type: 0(SYS_NONE_OS), 1(SYS_FREERTOS), 2(SYS_RTTHREAD), 3(SYS_LINUX), 4(SYS_POSIX)") - -# RT-Thread specific configuration for ETK -#set(USE_EXTERNAL_RTTHREAD ON CACHE BOOL "Use external RT-Thread library") -#set(FETCH_RTTHREAD OFF CACHE BOOL "Download RT-Thread via FetchContent") -# Set RTT_ROOT to tell ETK where to find RT-Thread source code -#set(RTT_ROOT "${CMAKE_SOURCE_DIR}/Middlewares/Third_Party/RealThread_RTOS_RT-Thread" CACHE PATH "RT-Thread source root directory for ETK") -# Set RTT_CONFIG_DIR for rtconfig.h location -#set(RTT_CONFIG_DIR "${CMAKE_SOURCE_DIR}/RT-Thread" CACHE PATH "RT-Thread config directory") - - -# if(NOT EXISTS "${RTT_CONFIG_DIR}/rtconfig.h") -# message(WARNING "RT-Thread config file rtconfig.h not found at: ${RTT_CONFIG_DIR}") -# endif() - -# Additional configuration options for specific features -#set(ENABLE_ARM_CMSIS_DSP OFF CACHE BOOL "Enable ARM CMSIS-DSP library") - - -# Set RT-Thread include paths - include both source and config directories -# set(RTTHREAD_INCLUDE_DIRS -# ${RTT_ROOT}/include -# ${RTT_ROOT}/components/finsh -# ${RTT_ROOT}/components/finsh/inc -# ${RTT_ROOT}/components/drivers/include -# ${RTT_CONFIG_DIR} # Add rtconfig.h directory -# ) - -# # Set RTT_ROOT as environment variable for etk os_adapt module to find -# if(DEFINED RTT_ROOT) -# set(ENV{RTT_ROOT} "${RTT_ROOT}") -# message(STATUS "RTT_ROOT environment variable set to: $ENV{RTT_ROOT}") -# else() -# message(FATAL_ERROR "RTT_ROOT is not defined. Please set RTT_ROOT path.") -# endif() - -# # Also set RTT_CONFIG_DIR as environment variable for rtconfig.h -# if(DEFINED RTT_CONFIG_DIR) -# set(ENV{RTT_CONFIG_DIR} "${RTT_CONFIG_DIR}") -# message(STATUS "RTT_CONFIG_DIR environment variable set to: $ENV{RTT_CONFIG_DIR}") -# endif() - -# add_subdirectory(etk) - -# # Link ETK library to main project to get access to all ETK headers -# if(ETK_ROOT_CMAKE) -# target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE etk) -# # Ensure etk library can get SYSTEM_TYPE value -# target_compile_definitions(etk PUBLIC SYSTEM_TYPE=${SYSTEM_TYPE}) -# endif() - # Add sources to executable target_sources(${CMAKE_PROJECT_NAME} PRIVATE # Add user sources here - ${CMAKE_SOURCE_DIR}/User/board/pm_board.c + ${CMAKE_SOURCE_DIR}/User/board/bsp_misc.c ${CMAKE_SOURCE_DIR}/User/board/bsp_encoder.c + ${CMAKE_SOURCE_DIR}/User/board/bsp_collect.c + ${CMAKE_SOURCE_DIR}/User/board/bsp_tec.c + ${CMAKE_SOURCE_DIR}/User/board/bsp_temper_sampling.c + ${CMAKE_SOURCE_DIR}/User/board/bsp_hmi.c + ${CMAKE_SOURCE_DIR}/User/board/bsp_motor.c ${CMAKE_SOURCE_DIR}/User/driver/at24cx/at24cx.c ${CMAKE_SOURCE_DIR}/User/driver/ad779x/ad7793.c ${CMAKE_SOURCE_DIR}/segger_rtt/RTT/SEGGER_RTT_printf.c @@ -208,10 +97,10 @@ target_sources(${CMAKE_PROJECT_NAME} PRIVATE ${CMAKE_SOURCE_DIR}/User/app/mb_hmi/hmi_server.c ${CMAKE_SOURCE_DIR}/User/app/pm_meas.c ${CMAKE_SOURCE_DIR}/User/app/pm_params.c + ${CMAKE_SOURCE_DIR}/User/app/bsp_debug.c ${CMAKE_SOURCE_DIR}/nanoMODBUS/nanomodbus.c ${CMAKE_SOURCE_DIR}/etk/src/drivers/encoder/src/et_encoder.c ${CMAKE_SOURCE_DIR}/etk/src/drivers/encoder/src/et_encoder_utils.c - # ETK logging ${CMAKE_SOURCE_DIR}/etk/src/logging/et_log.c ${CMAKE_SOURCE_DIR}/etk/src/algorithm/filter/src/et_ema_filter.c ${CMAKE_SOURCE_DIR}/etk/src/algorithm/pid/src/etk_pid.c @@ -226,8 +115,6 @@ target_sources(${CMAKE_PROJECT_NAME} PRIVATE # Add include paths target_include_directories(${CMAKE_PROJECT_NAME} PRIVATE - # Add user defined include paths - # Note: ETK module include paths are now automatically included via the etk library ${CMAKE_SOURCE_DIR}/User/board ${CMAKE_SOURCE_DIR}/segger_rtt/Config/ ${CMAKE_SOURCE_DIR}/segger_rtt/RTT/ @@ -239,7 +126,7 @@ target_include_directories(${CMAKE_PROJECT_NAME} PRIVATE ${CMAKE_SOURCE_DIR}/User/ ${CMAKE_SOURCE_DIR}/User/app/ ${CMAKE_SOURCE_DIR}/User/app/mb_hmi/ - # Add nanoMODBUS include path explicitly + ${CMAKE_SOURCE_DIR}/nanoMODBUS ${CMAKE_SOURCE_DIR}/etk/src/logging ${CMAKE_SOURCE_DIR}/etk/src/algorithm/math/include @@ -260,7 +147,7 @@ target_compile_definitions(${CMAKE_PROJECT_NAME} PRIVATE ARM_MATH SYSTEM_TYPE=2 ET_SLIDING_FILTER_SIZE=4 - NMBS_DEBUG + #NMBS_DEBUG USING_RTT_AS_CONSOLE RT_DEBUG ) diff --git a/Core/Inc/main.h b/Core/Inc/main.h index 48321db..ad93a16 100644 --- a/Core/Inc/main.h +++ b/Core/Inc/main.h @@ -57,27 +57,25 @@ void Error_Handler(void); /* USER CODE END EFP */ /* Private defines -----------------------------------------------------------*/ -#define TEC_DEAD_TIME 100 +#define HMI_COM huart2 +#define ENCODER_MAX_COUNT 65535 #define AD7793_SPI hspi3 +#define US_TIM_PRE 71 #define RS485_COM huart5 +#define ENCODER_TIM htim2 #define TEC_TIM_COUNTER 143 -#define SAMPLING_TIM_PRE 71 #define US_TIM_PERIOD_COUNT 9999 #define TEC_TIM_PRESCALER 99 -#define TEC_TIM htim1 -#define HMI_COM huart2 -#define SAMPLING_TIM htim3 -#define US_TIM_PRE 71 -#define TIMESTAMP_TIM htim4 -#define ENCODER_TIM htim2 -#define SAMPLING_TIM_PERIOD_COUNT 499//999 #define SERVO_COM huart3 -#define LIGHT_ADC hadc1 -#define ENCODER_MAX_COUNT 65535 +#define TEC_TIM htim1 +#define COLLECT_TIM htim3 +#define ADS8866_SPI hspi2 #define PE5_LED1_Pin GPIO_PIN_5 #define PE5_LED1_GPIO_Port GPIOE #define PE6_LED2_Pin GPIO_PIN_6 #define PE6_LED2_GPIO_Port GPIOE +#define RS485_DE_Pin GPIO_PIN_1 +#define RS485_DE_GPIO_Port GPIOF #define TIM2_ENCODER_B_Pin GPIO_PIN_0 #define TIM2_ENCODER_B_GPIO_Port GPIOA #define TIM2_ENCODER_A_Pin GPIO_PIN_1 @@ -86,16 +84,24 @@ void Error_Handler(void); #define UART2_TX_LCD_GPIO_Port GPIOA #define UART2_RX_LCD_Pin GPIO_PIN_3 #define UART2_RX_LCD_GPIO_Port GPIOA +#define TEC_LEFT_SD_Pin GPIO_PIN_6 +#define TEC_LEFT_SD_GPIO_Port GPIOA +#define TEC_RIGHT_SD_Pin GPIO_PIN_7 +#define TEC_RIGHT_SD_GPIO_Port GPIOA +#define ADS8866_CONVST_Pin GPIO_PIN_0 +#define ADS8866_CONVST_GPIO_Port GPIOB #define I2C2_EEPROM_SCL_Pin GPIO_PIN_10 #define I2C2_EEPROM_SCL_GPIO_Port GPIOB #define I2C2_EEPROM_SDA_Pin GPIO_PIN_11 #define I2C2_EEPROM_SDA_GPIO_Port GPIOB -#define TIM1_CH1N_TEC_Pin GPIO_PIN_13 -#define TIM1_CH1N_TEC_GPIO_Port GPIOB -#define FAN_CTRL_Pin GPIO_PIN_15 -#define FAN_CTRL_GPIO_Port GPIOD -#define TIM1_CH1_TEC_Pin GPIO_PIN_8 -#define TIM1_CH1_TEC_GPIO_Port GPIOA +#define SPI2_ADS8866_SCK_Pin GPIO_PIN_13 +#define SPI2_ADS8866_SCK_GPIO_Port GPIOB +#define SPI2_ADS8866_MISO_Pin GPIO_PIN_14 +#define SPI2_ADS8866_MISO_GPIO_Port GPIOB +#define SPI2_ADS8866_MOSI_Pin GPIO_PIN_15 +#define SPI2_ADS8866_MOSI_GPIO_Port GPIOB +#define TEC_RIGHT_IN_Pin GPIO_PIN_8 +#define TEC_RIGHT_IN_GPIO_Port GPIOA #define UART1_LCD_TX_Pin GPIO_PIN_9 #define UART1_LCD_TX_GPIO_Port GPIOA #define UART1_LCD_RX_Pin GPIO_PIN_10 @@ -110,14 +116,14 @@ void Error_Handler(void); #define UART5_RS485_RX_GPIO_Port GPIOD #define FAN_CONTROL_Pin GPIO_PIN_5 #define FAN_CONTROL_GPIO_Port GPIOD -#define SPI3_SCK_AD7793_Pin GPIO_PIN_3 -#define SPI3_SCK_AD7793_GPIO_Port GPIOB -#define SPI3_MISO_AD7793_Pin GPIO_PIN_4 -#define SPI3_MISO_AD7793_GPIO_Port GPIOB -#define SPI3_MOSI_AD7793_Pin GPIO_PIN_5 -#define SPI3_MOSI_AD7793_GPIO_Port GPIOB -#define SPI3_CS_AD7793_Pin GPIO_PIN_7 -#define SPI3_CS_AD7793_GPIO_Port GPIOB +#define SPI3_AD7793_SCK_Pin GPIO_PIN_3 +#define SPI3_AD7793_SCK_GPIO_Port GPIOB +#define SPI3_AD7793_MISO_Pin GPIO_PIN_4 +#define SPI3_AD7793_MISO_GPIO_Port GPIOB +#define SPI3_AD7793_MOSI_Pin GPIO_PIN_5 +#define SPI3_AD7793_MOSI_GPIO_Port GPIOB +#define SPI3_AD7793_CS_Pin GPIO_PIN_7 +#define SPI3_AD7793_CS_GPIO_Port GPIOB /* USER CODE BEGIN Private defines */ diff --git a/Core/Inc/spi.h b/Core/Inc/spi.h index 52a60e5..7c4b08a 100644 --- a/Core/Inc/spi.h +++ b/Core/Inc/spi.h @@ -32,12 +32,15 @@ extern "C" { /* USER CODE END Includes */ +extern SPI_HandleTypeDef hspi2; + extern SPI_HandleTypeDef hspi3; /* USER CODE BEGIN Private defines */ /* USER CODE END Private defines */ +void MX_SPI2_Init(void); void MX_SPI3_Init(void); /* USER CODE BEGIN Prototypes */ diff --git a/Core/Inc/stm32f1xx_it.h b/Core/Inc/stm32f1xx_it.h index 01fd82a..8c72063 100644 --- a/Core/Inc/stm32f1xx_it.h +++ b/Core/Inc/stm32f1xx_it.h @@ -51,10 +51,10 @@ void MemManage_Handler(void); void BusFault_Handler(void); void UsageFault_Handler(void); void DebugMon_Handler(void); -void DMA1_Channel1_IRQHandler(void); +void DMA1_Channel4_IRQHandler(void); +void DMA1_Channel5_IRQHandler(void); void TIM2_IRQHandler(void); void TIM3_IRQHandler(void); -void TIM4_IRQHandler(void); void USART1_IRQHandler(void); void USART2_IRQHandler(void); void USART3_IRQHandler(void); diff --git a/Core/Inc/tim.h b/Core/Inc/tim.h index a848354..0e17667 100644 --- a/Core/Inc/tim.h +++ b/Core/Inc/tim.h @@ -38,8 +38,6 @@ extern TIM_HandleTypeDef htim2; extern TIM_HandleTypeDef htim3; -extern TIM_HandleTypeDef htim4; - /* USER CODE BEGIN Private defines */ /* USER CODE END Private defines */ @@ -47,7 +45,6 @@ extern TIM_HandleTypeDef htim4; void MX_TIM1_Init(void); void MX_TIM2_Init(void); void MX_TIM3_Init(void); -void MX_TIM4_Init(void); void HAL_TIM_MspPostInit(TIM_HandleTypeDef *htim); diff --git a/Core/Src/adc.c b/Core/Src/adc.c index 3fe5b23..f2b3304 100644 --- a/Core/Src/adc.c +++ b/Core/Src/adc.c @@ -25,7 +25,6 @@ /* USER CODE END 0 */ ADC_HandleTypeDef hadc1; -DMA_HandleTypeDef hdma_adc1; /* ADC1 init function */ void MX_ADC1_Init(void) @@ -47,7 +46,7 @@ void MX_ADC1_Init(void) hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE; hadc1.Init.ContinuousConvMode = DISABLE; hadc1.Init.DiscontinuousConvMode = DISABLE; - hadc1.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T3_TRGO; + hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START; hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT; hadc1.Init.NbrOfConversion = 1; if (HAL_ADC_Init(&hadc1) != HAL_OK) @@ -57,9 +56,9 @@ void MX_ADC1_Init(void) /** Configure Regular Channel */ - sConfig.Channel = ADC_CHANNEL_10; + sConfig.Channel = ADC_CHANNEL_11; sConfig.Rank = ADC_REGULAR_RANK_1; - sConfig.SamplingTime = ADC_SAMPLETIME_55CYCLES_5; + sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5; if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) { Error_Handler(); @@ -84,29 +83,12 @@ void HAL_ADC_MspInit(ADC_HandleTypeDef* adcHandle) __HAL_RCC_GPIOC_CLK_ENABLE(); /**ADC1 GPIO Configuration - PC0 ------> ADC1_IN10 + PC1 ------> ADC1_IN11 */ - GPIO_InitStruct.Pin = GPIO_PIN_0; + GPIO_InitStruct.Pin = GPIO_PIN_1; GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); - /* ADC1 DMA Init */ - /* ADC1 Init */ - hdma_adc1.Instance = DMA1_Channel1; - hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY; - hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE; - hdma_adc1.Init.MemInc = DMA_MINC_ENABLE; - hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; - hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; - hdma_adc1.Init.Mode = DMA_CIRCULAR; - hdma_adc1.Init.Priority = DMA_PRIORITY_VERY_HIGH; - if (HAL_DMA_Init(&hdma_adc1) != HAL_OK) - { - Error_Handler(); - } - - __HAL_LINKDMA(adcHandle,DMA_Handle,hdma_adc1); - /* USER CODE BEGIN ADC1_MspInit 1 */ /* USER CODE END ADC1_MspInit 1 */ @@ -125,12 +107,10 @@ void HAL_ADC_MspDeInit(ADC_HandleTypeDef* adcHandle) __HAL_RCC_ADC1_CLK_DISABLE(); /**ADC1 GPIO Configuration - PC0 ------> ADC1_IN10 + PC1 ------> ADC1_IN11 */ - HAL_GPIO_DeInit(GPIOC, GPIO_PIN_0); + HAL_GPIO_DeInit(GPIOC, GPIO_PIN_1); - /* ADC1 DMA DeInit */ - HAL_DMA_DeInit(adcHandle->DMA_Handle); /* USER CODE BEGIN ADC1_MspDeInit 1 */ /* USER CODE END ADC1_MspDeInit 1 */ diff --git a/Core/Src/dma.c b/Core/Src/dma.c index c9bc588..2540b01 100644 --- a/Core/Src/dma.c +++ b/Core/Src/dma.c @@ -43,9 +43,12 @@ void MX_DMA_Init(void) __HAL_RCC_DMA1_CLK_ENABLE(); /* DMA interrupt init */ - /* DMA1_Channel1_IRQn interrupt configuration */ - HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 0, 0); - HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn); + /* DMA1_Channel4_IRQn interrupt configuration */ + HAL_NVIC_SetPriority(DMA1_Channel4_IRQn, 0, 0); + HAL_NVIC_EnableIRQ(DMA1_Channel4_IRQn); + /* DMA1_Channel5_IRQn interrupt configuration */ + HAL_NVIC_SetPriority(DMA1_Channel5_IRQn, 0, 0); + HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn); } diff --git a/Core/Src/gpio.c b/Core/Src/gpio.c index 26588a4..e649402 100644 --- a/Core/Src/gpio.c +++ b/Core/Src/gpio.c @@ -47,6 +47,7 @@ void MX_GPIO_Init(void) /* GPIO Ports Clock Enable */ __HAL_RCC_GPIOE_CLK_ENABLE(); __HAL_RCC_GPIOC_CLK_ENABLE(); + __HAL_RCC_GPIOF_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE(); __HAL_RCC_GPIOD_CLK_ENABLE(); @@ -55,10 +56,16 @@ void MX_GPIO_Init(void) HAL_GPIO_WritePin(GPIOE, PE5_LED1_Pin|PE6_LED2_Pin, GPIO_PIN_SET); /*Configure GPIO pin Output Level */ - HAL_GPIO_WritePin(GPIOD, FAN_CTRL_Pin|FAN_CONTROL_Pin, GPIO_PIN_RESET); + HAL_GPIO_WritePin(RS485_DE_GPIO_Port, RS485_DE_Pin, GPIO_PIN_RESET); /*Configure GPIO pin Output Level */ - HAL_GPIO_WritePin(SPI3_CS_AD7793_GPIO_Port, SPI3_CS_AD7793_Pin, GPIO_PIN_RESET); + HAL_GPIO_WritePin(GPIOA, TEC_LEFT_SD_Pin|TEC_RIGHT_SD_Pin, GPIO_PIN_RESET); + + /*Configure GPIO pin Output Level */ + HAL_GPIO_WritePin(GPIOD, FAN_CONTROL_Pin, GPIO_PIN_RESET); + + /*Configure GPIO pin Output Level */ + HAL_GPIO_WritePin(SPI3_AD7793_CS_GPIO_Port, SPI3_AD7793_CS_Pin, GPIO_PIN_RESET); /*Configure GPIO pins : PE5_LED1_Pin PE6_LED2_Pin */ GPIO_InitStruct.Pin = PE5_LED1_Pin|PE6_LED2_Pin; @@ -67,19 +74,33 @@ void MX_GPIO_Init(void) GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(GPIOE, &GPIO_InitStruct); + /*Configure GPIO pin : RS485_DE_Pin */ + GPIO_InitStruct.Pin = RS485_DE_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; + HAL_GPIO_Init(RS485_DE_GPIO_Port, &GPIO_InitStruct); + + /*Configure GPIO pins : TEC_LEFT_SD_Pin TEC_RIGHT_SD_Pin */ + GPIO_InitStruct.Pin = TEC_LEFT_SD_Pin|TEC_RIGHT_SD_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; + HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); + /*Configure GPIO pins : FAN_CTRL_Pin FAN_CONTROL_Pin */ - GPIO_InitStruct.Pin = FAN_CTRL_Pin|FAN_CONTROL_Pin; + GPIO_InitStruct.Pin = FAN_CONTROL_Pin; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(GPIOD, &GPIO_InitStruct); - /*Configure GPIO pin : SPI3_CS_AD7793_Pin */ - GPIO_InitStruct.Pin = SPI3_CS_AD7793_Pin; + /*Configure GPIO pin : SPI3_AD7793_CS_Pin */ + GPIO_InitStruct.Pin = SPI3_AD7793_CS_Pin; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; - HAL_GPIO_Init(SPI3_CS_AD7793_GPIO_Port, &GPIO_InitStruct); + HAL_GPIO_Init(SPI3_AD7793_CS_GPIO_Port, &GPIO_InitStruct); } diff --git a/Core/Src/main.c b/Core/Src/main.c index 8004c4d..7b29658 100644 --- a/Core/Src/main.c +++ b/Core/Src/main.c @@ -18,7 +18,6 @@ /* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "main.h" -#include "dma.h" /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ @@ -28,6 +27,7 @@ #include "tim.h" #include #include "et_log.h" +#include "bsp_collect.h" /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ @@ -68,46 +68,45 @@ void SystemClock_Config(void); */ int main(void) { - /* USER CODE BEGIN 1 */ - /* USER CODE END 1 */ + /* USER CODE BEGIN 1 */ - /* MCU Configuration--------------------------------------------------------*/ + /* USER CODE END 1 */ - /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ - HAL_Init(); + /* MCU Configuration--------------------------------------------------------*/ - /* USER CODE BEGIN Init */ + /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ + HAL_Init(); - /* USER CODE END Init */ + /* USER CODE BEGIN Init */ - /* USER CODE BEGIN SysInit */ + /* USER CODE END Init */ - /* USER CODE END SysInit */ + /* USER CODE BEGIN SysInit */ - /* Initialize all configured peripherals */ + /* USER CODE END SysInit */ - /* USER CODE BEGIN 2 */ + /* Initialize all configured peripherals */ + /* USER CODE BEGIN 2 */ et_log_init(DEBUG_LEVEL, false, true); pm_device_init(&pm_device); - /* USER CODE END 2 */ + /* USER CODE END 2 */ - /* Infinite loop */ - /* USER CODE BEGIN WHILE */ - pm_device_start(&pm_device); + /* Infinite loop */ + /* USER CODE BEGIN WHILE */ + //pm_device_start(&pm_device); while (1) { - /* USER CODE END WHILE */ + /* USER CODE END WHILE */ - /* USER CODE BEGIN 3 */ - rt_thread_mdelay(1000); - //pm_lcd_cmd_send("TEST\r\n", 6); + /* USER CODE BEGIN 3 */ + rt_thread_mdelay(1000); #if (TEST_ENCODER_PLUSE == 1) - rt_kprintf("count:%d\r\n", pm_encoder_get_count()); + rt_kprintf("count:%d\r\n", pm_encoder_get_count()); #endif - //pm_system_led_toggle(); // Toggle the system LEDs + //bsp_system_led_toggle(); // Toggle the system LEDs } - /* USER CODE END 3 */ + /* USER CODE END 3 */ } /** @@ -116,43 +115,44 @@ int main(void) */ void SystemClock_Config(void) { - RCC_OscInitTypeDef RCC_OscInitStruct = {0}; - RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; - RCC_PeriphCLKInitTypeDef PeriphClkInit = {0}; + RCC_OscInitTypeDef RCC_OscInitStruct = {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. */ - RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; - RCC_OscInitStruct.HSEState = RCC_HSE_ON; - RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1; - RCC_OscInitStruct.HSIState = RCC_HSI_ON; - RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; - RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; - RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9; - if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) - { - Error_Handler(); - } + RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; + RCC_OscInitStruct.HSEState = RCC_HSE_ON; + RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1; + RCC_OscInitStruct.HSIState = RCC_HSI_ON; + RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; + RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; + RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9; + if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) + { + Error_Handler(); + } - /** Initializes the CPU, AHB and APB buses clocks + /** Initializes the CPU, AHB and APB buses clocks */ - RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2; - RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; - RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; - RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2; - RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; + RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK + |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; + RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; + RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; + RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2; + RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; - if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK) - { - Error_Handler(); - } - PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC; - PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV6; - if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) - { - Error_Handler(); - } + if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK) + { + Error_Handler(); + } + PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC; + PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV6; + if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) + { + Error_Handler(); + } } /* USER CODE BEGIN 4 */ @@ -169,21 +169,14 @@ void SystemClock_Config(void) */ void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { - /* USER CODE BEGIN Callback 0 */ + /* USER CODE BEGIN Callback 0 */ - /* USER CODE END Callback 0 */ - if (htim->Instance == TIM8) - { - HAL_IncTick(); - } - /* USER CODE BEGIN Callback 1 */ - if (htim->Instance == SAMPLING_TIM.Instance) - { - pm_system_led_toggle(); -#if (TEST_ENCODER_PLUSE == 0) - //data_sampling_once(); -#endif - } + /* USER CODE END Callback 0 */ + if (htim->Instance == TIM8) + { + HAL_IncTick(); + } + /* USER CODE BEGIN Callback 1 */ #if (USING_SOFT_ENCODER == 0) if (htim->Instance == ENCODER_TIM.Instance) { @@ -194,14 +187,12 @@ void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) encoder_tim_overflow_count++; rt_interrupt_leave(); // Enable interrupts } -#endif // USING_SOFT_ENCODER - if (htim->Instance == TIMESTAMP_TIM.Instance) +#endif + if (htim->Instance == TIM3) { - rt_interrupt_enter(); - timestamp_tim_overflow_count++; - rt_interrupt_leave(); - } - /* USER CODE END Callback 1 */ + sampling_tim_elapsed_callback(); + } + /* USER CODE END Callback 1 */ } /** @@ -210,11 +201,12 @@ void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) */ void Error_Handler(void) { - /* USER CODE BEGIN Error_Handler_Debug */ + /* USER CODE BEGIN Error_Handler_Debug */ /* User can add his own implementation to report the HAL error return state */ __disable_irq(); + ET_ERR("Error Handler Entered!\r\n"); while (1) {} - /* USER CODE END Error_Handler_Debug */ + /* USER CODE END Error_Handler_Debug */ } #ifdef USE_FULL_ASSERT /** @@ -226,9 +218,9 @@ void Error_Handler(void) */ void assert_failed(uint8_t *file, uint32_t line) { - /* USER CODE BEGIN 6 */ + /* USER CODE BEGIN 6 */ /* User can add his own implementation to report the file name and line number, ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ - /* USER CODE END 6 */ + /* USER CODE END 6 */ } #endif /* USE_FULL_ASSERT */ diff --git a/Core/Src/spi.c b/Core/Src/spi.c index 803215f..6f15db4 100644 --- a/Core/Src/spi.c +++ b/Core/Src/spi.c @@ -24,8 +24,43 @@ /* USER CODE END 0 */ +SPI_HandleTypeDef hspi2; SPI_HandleTypeDef hspi3; +DMA_HandleTypeDef hdma_spi2_rx; +DMA_HandleTypeDef hdma_spi2_tx; +/* SPI2 init function */ +void MX_SPI2_Init(void) +{ + + /* USER CODE BEGIN SPI2_Init 0 */ + + /* USER CODE END SPI2_Init 0 */ + + /* USER CODE BEGIN SPI2_Init 1 */ + + /* USER CODE END SPI2_Init 1 */ + hspi2.Instance = SPI2; + hspi2.Init.Mode = SPI_MODE_MASTER; + hspi2.Init.Direction = SPI_DIRECTION_2LINES; + hspi2.Init.DataSize = SPI_DATASIZE_16BIT; + hspi2.Init.CLKPolarity = SPI_POLARITY_LOW; + hspi2.Init.CLKPhase = SPI_PHASE_2EDGE; + hspi2.Init.NSS = SPI_NSS_SOFT; + hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16; + hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB; + hspi2.Init.TIMode = SPI_TIMODE_DISABLE; + hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE; + hspi2.Init.CRCPolynomial = 10; + if (HAL_SPI_Init(&hspi2) != HAL_OK) + { + Error_Handler(); + } + /* USER CODE BEGIN SPI2_Init 2 */ + + /* USER CODE END SPI2_Init 2 */ + +} /* SPI3 init function */ void MX_SPI3_Init(void) { @@ -63,7 +98,68 @@ void HAL_SPI_MspInit(SPI_HandleTypeDef* spiHandle) { GPIO_InitTypeDef GPIO_InitStruct = {0}; - if(spiHandle->Instance==SPI3) + if(spiHandle->Instance==SPI2) + { + /* USER CODE BEGIN SPI2_MspInit 0 */ + + /* USER CODE END SPI2_MspInit 0 */ + /* SPI2 clock enable */ + __HAL_RCC_SPI2_CLK_ENABLE(); + + __HAL_RCC_GPIOB_CLK_ENABLE(); + /**SPI2 GPIO Configuration + PB13 ------> SPI2_SCK + PB14 ------> SPI2_MISO + PB15 ------> SPI2_MOSI + */ + GPIO_InitStruct.Pin = SPI2_ADS8866_SCK_Pin|SPI2_ADS8866_MOSI_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; + HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); + + GPIO_InitStruct.Pin = SPI2_ADS8866_MISO_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_INPUT; + GPIO_InitStruct.Pull = GPIO_NOPULL; + HAL_GPIO_Init(SPI2_ADS8866_MISO_GPIO_Port, &GPIO_InitStruct); + + /* SPI2 DMA Init */ + /* SPI2_RX Init */ + hdma_spi2_rx.Instance = DMA1_Channel4; + hdma_spi2_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; + hdma_spi2_rx.Init.PeriphInc = DMA_PINC_DISABLE; + hdma_spi2_rx.Init.MemInc = DMA_MINC_ENABLE; + hdma_spi2_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; + hdma_spi2_rx.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; + hdma_spi2_rx.Init.Mode = DMA_NORMAL; + hdma_spi2_rx.Init.Priority = DMA_PRIORITY_HIGH; + if (HAL_DMA_Init(&hdma_spi2_rx) != HAL_OK) + { + Error_Handler(); + } + + __HAL_LINKDMA(spiHandle,hdmarx,hdma_spi2_rx); + + /* SPI2_TX Init */ + hdma_spi2_tx.Instance = DMA1_Channel5; + hdma_spi2_tx.Init.Direction = DMA_MEMORY_TO_PERIPH; + hdma_spi2_tx.Init.PeriphInc = DMA_PINC_DISABLE; + hdma_spi2_tx.Init.MemInc = DMA_MINC_ENABLE; + hdma_spi2_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; + hdma_spi2_tx.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; + hdma_spi2_tx.Init.Mode = DMA_NORMAL; + hdma_spi2_tx.Init.Priority = DMA_PRIORITY_HIGH; + if (HAL_DMA_Init(&hdma_spi2_tx) != HAL_OK) + { + Error_Handler(); + } + + __HAL_LINKDMA(spiHandle,hdmatx,hdma_spi2_tx); + + /* USER CODE BEGIN SPI2_MspInit 1 */ + + /* USER CODE END SPI2_MspInit 1 */ + } + else if(spiHandle->Instance==SPI3) { /* USER CODE BEGIN SPI3_MspInit 0 */ @@ -77,15 +173,15 @@ void HAL_SPI_MspInit(SPI_HandleTypeDef* spiHandle) PB4 ------> SPI3_MISO PB5 ------> SPI3_MOSI */ - GPIO_InitStruct.Pin = SPI3_SCK_AD7793_Pin|SPI3_MOSI_AD7793_Pin; + GPIO_InitStruct.Pin = SPI3_AD7793_SCK_Pin|SPI3_AD7793_MOSI_Pin; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); - GPIO_InitStruct.Pin = SPI3_MISO_AD7793_Pin; + GPIO_InitStruct.Pin = SPI3_AD7793_MISO_Pin; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_NOPULL; - HAL_GPIO_Init(SPI3_MISO_AD7793_GPIO_Port, &GPIO_InitStruct); + HAL_GPIO_Init(SPI3_AD7793_MISO_GPIO_Port, &GPIO_InitStruct); /* USER CODE BEGIN SPI3_MspInit 1 */ @@ -96,7 +192,29 @@ void HAL_SPI_MspInit(SPI_HandleTypeDef* spiHandle) void HAL_SPI_MspDeInit(SPI_HandleTypeDef* spiHandle) { - if(spiHandle->Instance==SPI3) + if(spiHandle->Instance==SPI2) + { + /* USER CODE BEGIN SPI2_MspDeInit 0 */ + + /* USER CODE END SPI2_MspDeInit 0 */ + /* Peripheral clock disable */ + __HAL_RCC_SPI2_CLK_DISABLE(); + + /**SPI2 GPIO Configuration + PB13 ------> SPI2_SCK + PB14 ------> SPI2_MISO + PB15 ------> SPI2_MOSI + */ + HAL_GPIO_DeInit(GPIOB, SPI2_ADS8866_SCK_Pin|SPI2_ADS8866_MISO_Pin|SPI2_ADS8866_MOSI_Pin); + + /* SPI2 DMA DeInit */ + HAL_DMA_DeInit(spiHandle->hdmarx); + HAL_DMA_DeInit(spiHandle->hdmatx); + /* USER CODE BEGIN SPI2_MspDeInit 1 */ + + /* USER CODE END SPI2_MspDeInit 1 */ + } + else if(spiHandle->Instance==SPI3) { /* USER CODE BEGIN SPI3_MspDeInit 0 */ @@ -109,7 +227,7 @@ void HAL_SPI_MspDeInit(SPI_HandleTypeDef* spiHandle) PB4 ------> SPI3_MISO PB5 ------> SPI3_MOSI */ - HAL_GPIO_DeInit(GPIOB, SPI3_SCK_AD7793_Pin|SPI3_MISO_AD7793_Pin|SPI3_MOSI_AD7793_Pin); + HAL_GPIO_DeInit(GPIOB, SPI3_AD7793_SCK_Pin|SPI3_AD7793_MISO_Pin|SPI3_AD7793_MOSI_Pin); /* USER CODE BEGIN SPI3_MspDeInit 1 */ diff --git a/Core/Src/stm32f1xx_it.c b/Core/Src/stm32f1xx_it.c index 12cc6cd..317df1e 100644 --- a/Core/Src/stm32f1xx_it.c +++ b/Core/Src/stm32f1xx_it.c @@ -22,11 +22,13 @@ #include "stm32f1xx_it.h" /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ -#include "pm_board.h" +#include "bsp_misc.h" #include "pm_device.h" #include "pm_common.h" #include "rtthread.h" #include "et_log.h" +#include "bsp_hmi.h" +#include "bsp_motor.h" /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ @@ -60,10 +62,10 @@ extern pm_device_t pm_device; /* USER CODE END 0 */ /* External variables --------------------------------------------------------*/ -extern DMA_HandleTypeDef hdma_adc1; +extern DMA_HandleTypeDef hdma_spi2_rx; +extern DMA_HandleTypeDef hdma_spi2_tx; extern TIM_HandleTypeDef htim2; extern TIM_HandleTypeDef htim3; -extern TIM_HandleTypeDef htim4; extern UART_HandleTypeDef huart5; extern UART_HandleTypeDef huart1; extern UART_HandleTypeDef huart2; @@ -158,17 +160,31 @@ void DebugMon_Handler(void) /******************************************************************************/ /** - * @brief This function handles DMA1 channel1 global interrupt. + * @brief This function handles DMA1 channel4 global interrupt. */ -void DMA1_Channel1_IRQHandler(void) +void DMA1_Channel4_IRQHandler(void) { - /* USER CODE BEGIN DMA1_Channel1_IRQn 0 */ + /* USER CODE BEGIN DMA1_Channel4_IRQn 0 */ - /* USER CODE END DMA1_Channel1_IRQn 0 */ - HAL_DMA_IRQHandler(&hdma_adc1); - /* USER CODE BEGIN DMA1_Channel1_IRQn 1 */ + /* USER CODE END DMA1_Channel4_IRQn 0 */ + HAL_DMA_IRQHandler(&hdma_spi2_rx); + /* USER CODE BEGIN DMA1_Channel4_IRQn 1 */ - /* USER CODE END DMA1_Channel1_IRQn 1 */ + /* USER CODE END DMA1_Channel4_IRQn 1 */ +} + +/** + * @brief This function handles DMA1 channel5 global interrupt. + */ +void DMA1_Channel5_IRQHandler(void) +{ + /* USER CODE BEGIN DMA1_Channel5_IRQn 0 */ + + /* USER CODE END DMA1_Channel5_IRQn 0 */ + HAL_DMA_IRQHandler(&hdma_spi2_tx); + /* USER CODE BEGIN DMA1_Channel5_IRQn 1 */ + + /* USER CODE END DMA1_Channel5_IRQn 1 */ } /** @@ -199,20 +215,6 @@ void TIM3_IRQHandler(void) /* USER CODE END TIM3_IRQn 1 */ } -/** - * @brief This function handles TIM4 global interrupt. - */ -void TIM4_IRQHandler(void) -{ - /* USER CODE BEGIN TIM4_IRQn 0 */ - - /* USER CODE END TIM4_IRQn 0 */ - HAL_TIM_IRQHandler(&htim4); - /* USER CODE BEGIN TIM4_IRQn 1 */ - - /* USER CODE END TIM4_IRQn 1 */ -} - /** * @brief This function handles USART1 global interrupt. */ diff --git a/Core/Src/tim.c b/Core/Src/tim.c index 79439ab..d1fc7fc 100644 --- a/Core/Src/tim.c +++ b/Core/Src/tim.c @@ -27,7 +27,6 @@ uint32_t encoder_mode = 0; TIM_HandleTypeDef htim1; TIM_HandleTypeDef htim2; TIM_HandleTypeDef htim3; -TIM_HandleTypeDef htim4; /* TIM1 init function */ void MX_TIM1_Init(void) @@ -45,12 +44,12 @@ void MX_TIM1_Init(void) /* USER CODE END TIM1_Init 1 */ htim1.Instance = TIM1; - htim1.Init.Prescaler = TEC_TIM_PRESCALER; + htim1.Init.Prescaler = 7; htim1.Init.CounterMode = TIM_COUNTERMODE_UP; - htim1.Init.Period = TEC_TIM_COUNTER; + htim1.Init.Period = 899; htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; htim1.Init.RepetitionCounter = 0; - htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE; + htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; if (HAL_TIM_PWM_Init(&htim1) != HAL_OK) { Error_Handler(); @@ -62,7 +61,7 @@ void MX_TIM1_Init(void) Error_Handler(); } sConfigOC.OCMode = TIM_OCMODE_PWM1; - sConfigOC.Pulse = 0; + sConfigOC.Pulse = 100; sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH; sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; @@ -75,7 +74,7 @@ void MX_TIM1_Init(void) sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE; sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE; sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF; - sBreakDeadTimeConfig.DeadTime = TEC_DEAD_TIME; + sBreakDeadTimeConfig.DeadTime = 0; sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE; sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH; sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE; @@ -144,14 +143,15 @@ void MX_TIM3_Init(void) TIM_ClockConfigTypeDef sClockSourceConfig = {0}; TIM_MasterConfigTypeDef sMasterConfig = {0}; + TIM_OC_InitTypeDef sConfigOC = {0}; /* USER CODE BEGIN TIM3_Init 1 */ /* USER CODE END TIM3_Init 1 */ htim3.Instance = TIM3; - htim3.Init.Prescaler = SAMPLING_TIM_PRE; + htim3.Init.Prescaler = 71; htim3.Init.CounterMode = TIM_COUNTERMODE_UP; - htim3.Init.Period = SAMPLING_TIM_PERIOD_COUNT; + htim3.Init.Period = 499; htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE; if (HAL_TIM_Base_Init(&htim3) != HAL_OK) @@ -163,55 +163,28 @@ void MX_TIM3_Init(void) { Error_Handler(); } - sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE; + if (HAL_TIM_PWM_Init(&htim3) != HAL_OK) + { + Error_Handler(); + } + sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK) { Error_Handler(); } + sConfigOC.OCMode = TIM_OCMODE_PWM1; + sConfigOC.Pulse = 10; + sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; + sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; + if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_3) != HAL_OK) + { + Error_Handler(); + } /* USER CODE BEGIN TIM3_Init 2 */ /* USER CODE END TIM3_Init 2 */ - -} -/* TIM4 init function */ -void MX_TIM4_Init(void) -{ - - /* USER CODE BEGIN TIM4_Init 0 */ - __HAL_RCC_TIM4_CLK_ENABLE(); - /* USER CODE END TIM4_Init 0 */ - - TIM_ClockConfigTypeDef sClockSourceConfig = {0}; - TIM_MasterConfigTypeDef sMasterConfig = {0}; - - /* USER CODE BEGIN TIM4_Init 1 */ - - /* USER CODE END TIM4_Init 1 */ - htim4.Instance = TIM4; - htim4.Init.Prescaler = US_TIM_PRE; - htim4.Init.CounterMode = TIM_COUNTERMODE_UP; - htim4.Init.Period = US_TIM_PERIOD_COUNT; - htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; - htim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE; - if (HAL_TIM_Base_Init(&htim4) != HAL_OK) - { - Error_Handler(); - } - sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; - if (HAL_TIM_ConfigClockSource(&htim4, &sClockSourceConfig) != HAL_OK) - { - Error_Handler(); - } - sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; - sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; - if (HAL_TIMEx_MasterConfigSynchronization(&htim4, &sMasterConfig) != HAL_OK) - { - Error_Handler(); - } - /* USER CODE BEGIN TIM4_Init 2 */ - HAL_TIM_Base_Start(&htim4); - /* USER CODE END TIM4_Init 2 */ + HAL_TIM_MspPostInit(&htim3); } @@ -280,21 +253,6 @@ void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle) /* USER CODE END TIM3_MspInit 1 */ } - else if(tim_baseHandle->Instance==TIM4) - { - /* USER CODE BEGIN TIM4_MspInit 0 */ - - /* USER CODE END TIM4_MspInit 0 */ - /* TIM4 clock enable */ - __HAL_RCC_TIM4_CLK_ENABLE(); - - /* TIM4 interrupt Init */ - HAL_NVIC_SetPriority(TIM4_IRQn, 0, 0); - HAL_NVIC_EnableIRQ(TIM4_IRQn); - /* USER CODE BEGIN TIM4_MspInit 1 */ - - /* USER CODE END TIM4_MspInit 1 */ - } } void HAL_TIM_MspPostInit(TIM_HandleTypeDef* timHandle) { @@ -305,27 +263,38 @@ void HAL_TIM_MspPostInit(TIM_HandleTypeDef* timHandle) /* USER CODE BEGIN TIM1_MspPostInit 0 */ /* USER CODE END TIM1_MspPostInit 0 */ - - __HAL_RCC_GPIOB_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); /**TIM1 GPIO Configuration - PB13 ------> TIM1_CH1N PA8 ------> TIM1_CH1 */ - GPIO_InitStruct.Pin = TIM1_CH1N_TEC_Pin; + GPIO_InitStruct.Pin = TEC_RIGHT_IN_Pin; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; - HAL_GPIO_Init(TIM1_CH1N_TEC_GPIO_Port, &GPIO_InitStruct); - - GPIO_InitStruct.Pin = TIM1_CH1_TEC_Pin; - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; - HAL_GPIO_Init(TIM1_CH1_TEC_GPIO_Port, &GPIO_InitStruct); + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; + HAL_GPIO_Init(TEC_RIGHT_IN_GPIO_Port, &GPIO_InitStruct); /* USER CODE BEGIN TIM1_MspPostInit 1 */ /* USER CODE END TIM1_MspPostInit 1 */ } + else if(timHandle->Instance==TIM3) + { + /* USER CODE BEGIN TIM3_MspPostInit 0 */ + + /* USER CODE END TIM3_MspPostInit 0 */ + + __HAL_RCC_GPIOB_CLK_ENABLE(); + /**TIM3 GPIO Configuration + PB0 ------> TIM3_CH3 + */ + GPIO_InitStruct.Pin = ADS8866_CONVST_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; + HAL_GPIO_Init(ADS8866_CONVST_GPIO_Port, &GPIO_InitStruct); + + /* USER CODE BEGIN TIM3_MspPostInit 1 */ + + /* USER CODE END TIM3_MspPostInit 1 */ + } } @@ -387,20 +356,6 @@ void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* tim_baseHandle) /* USER CODE END TIM3_MspDeInit 1 */ } - else if(tim_baseHandle->Instance==TIM4) - { - /* USER CODE BEGIN TIM4_MspDeInit 0 */ - - /* USER CODE END TIM4_MspDeInit 0 */ - /* Peripheral clock disable */ - __HAL_RCC_TIM4_CLK_DISABLE(); - - /* TIM4 interrupt Deinit */ - HAL_NVIC_DisableIRQ(TIM4_IRQn); - /* USER CODE BEGIN TIM4_MspDeInit 1 */ - - /* USER CODE END TIM4_MspDeInit 1 */ - } } /* USER CODE BEGIN 1 */ diff --git a/User/app/bsp_debug.c b/User/app/bsp_debug.c new file mode 100644 index 0000000..644b7a4 --- /dev/null +++ b/User/app/bsp_debug.c @@ -0,0 +1,79 @@ +/* + * @Author: mypx + * @Date: 2025-10-15 14:22:42 + * @LastEditTime: 2025-10-24 15:07:15 + * @LastEditors: mypx mypx_coder@163.com + * @Description: + */ +#include "bsp_tec.h" +#include "et_log.h" +#include +#include +#include + +static int test_tec_cooling_open(int argc, char **argv) +{ + (void)argc; + (void)argv; + bsp_tec_cooling_open(); + return 0; +} +MSH_CMD_EXPORT_ALIAS(test_tec_cooling_open, cool_open, "open cooling"); + +static int test_tec_heating_open(int argc, char **argv) +{ + (void)argc; + (void)argv; + bsp_tec_heating_open(); + return 0; +} +MSH_CMD_EXPORT_ALIAS(test_tec_heating_open, heat_open, "open heating"); + + +static int test_adjust_tec_cooling_duty_cycle(int argc, char **argv) +{ + uint32_t duty_cycle = 0; + if (argc != 2) + { + rt_kprintf("Usage: tldc \n"); + return -1; + } + duty_cycle = atof(argv[1]); + ET_DBG("duty_cycle:%.2f", duty_cycle); + bsp_tec_cooling_adjust(duty_cycle); + return 0; +} +MSH_CMD_EXPORT_ALIAS(test_adjust_tec_cooling_duty_cycle, tldc, "adjust cool level"); + +static int test_adjust_tec_heating_duty_cycle(int argc, char **argv) +{ + uint32_t duty_cycle = 0; + if (argc != 2) + { + rt_kprintf("Usage: trdc \n"); + return -1; + } + duty_cycle = atof(argv[1]); + ET_DBG("duty_cycle:%.2f", duty_cycle); + bsp_tec_heating_adjust(duty_cycle); + return 0; +} +MSH_CMD_EXPORT_ALIAS(test_adjust_tec_heating_duty_cycle, trdc, "adjust heat level"); + +static int test_fan_start(int argc, char **argv) +{ + (void)argc; + (void)argv; + bsp_fan_start(); + return 0; +} +MSH_CMD_EXPORT_ALIAS(test_fan_start, fan_start, "start fan"); + +static int test_fan_stop(int argc, char **argv) +{ + (void)argc; + (void)argv; + bsp_fan_stop(); + return 0; +} +MSH_CMD_EXPORT_ALIAS(test_fan_stop, fan_stop, "stop fan"); diff --git a/User/app/data_process.c b/User/app/data_process.c index 7b5a11e..dcdc32e 100644 --- a/User/app/data_process.c +++ b/User/app/data_process.c @@ -2,12 +2,13 @@ * @Date: 2025-07-18 09:24:34 * @Author: mypx * @LastEditors: mypx mypx_coder@163.com - * @LastEditTime: 2025-09-26 08:58:26 + * @LastEditTime: 2025-10-27 10:42:07 * @FilePath: data_process.c * @Description: * Copyright (c) 2025 by mypx, All Rights Reserved. */ #include "data_process.h" +#include "bsp_collect.h" #include "data_sampling.h" #include "et_log.h" #include "pm_common.h" @@ -47,8 +48,8 @@ float adc_filter_buffer[DATA_PROCESS_UNIT_COUNT] = {0}; #define ANALYSIS_SIZE DATA_PROCESS_UNIT_COUNT -static bool cali_flag = false; -static bool rdy_flag = false; +// static bool cali_flag = false; +// static bool rdy_flag = false; pm_meas_t pm_meas; @@ -66,7 +67,8 @@ void set_pm_stage(int argc, char **argv) pm_meas.state = stage; } MSH_CMD_EXPORT_ALIAS(set_pm_stage, sst, set state); -uint32_t data_count = 0; + +// uint32_t data_count = 0; // 只考虑校准和测量状态,其他状态由采集线程 或者主线程管理 void data_process_thread_entry(void *parameter) @@ -76,14 +78,29 @@ void data_process_thread_entry(void *parameter) int find_status = 0; uint16_t *raw_buf; uint16_t *used_buf; + pm_fsm_t *fsm = get_pm_fsm(); + uint32_t times = 0; + + bsp_light_data_sampling_start(); while (1) { - result = rt_mq_recv(&adc_mq, &raw_buf, sizeof(adc_raw_buffer), RT_WAITING_FOREVER); + /* receive pointer to buffer (sender uses sizeof(ptr)) */ + result = rt_mq_recv(&adc_mq, &raw_buf, sizeof(void *), RT_WAITING_FOREVER); if (result == RT_EOK) { - data_sampling_stop(); - if (get_find_zero_state(&pm_meas) == ZF_FAST_CLOSE_STAGE && fsm_state == false && pm_meas.p50 > 0.1f) +#if (DEBUG_LIGHT_DATA_ONLY == 1) + for (int i = 0; i < DATA_PROCESS_UNIT_COUNT; i++) + { + ET_DBG("[%d] r:%d", times++, raw_buf[i]); + if (times >= ANALYSIS_SIZE) + times = 0; + } + bsp_light_data_sampling_start(); + continue; +#endif + if (get_find_zero_state(&pm_meas) == ZF_FAST_CLOSE_STAGE && fsm->fz_fsm_state == PM_FSM_STOP + && pm_meas.p50 > 0.1f) sv630p_speed_mode_stop(&sv630p_handle); #if (ENABLE_IIR_FILTER == 1) if (et_iir_filter_process(&iir_filter, (const void *)raw_buf, (void *)adc_filter_buffer) == IIR_OK) @@ -93,22 +110,15 @@ void data_process_thread_entry(void *parameter) #else used_buf = raw_buf; #endif -#if (SAMPLING_RAW_DATA == 1) - for (int i = 0; i < DATA_PROCESS_UNIT_COUNT; i++) - { - ET_DBG("r:%d, f:%d", raw_buf[i], (uint16_t)adc_filter_buffer[i]); - } -#endif - -#if (SAMPLING_RAW_DATA == 0) - pm_error_led_on(); // for timing + bsp_error_led_on(); // for timing find_status = find_zero_process(&pm_meas, (const uint16_t *)used_buf, DATA_PROCESS_UNIT_COUNT); - pm_error_led_off(); -#endif + bsp_error_led_off(); + if (find_status == 0) { - data_sampling_start(); - if (get_find_zero_state(&pm_meas) == ZF_FAST_CLOSE_STAGE && fsm_state == false && pm_meas.p50 > 0.1f) + bsp_light_data_sampling_start(); + if (get_find_zero_state(&pm_meas) == ZF_FAST_CLOSE_STAGE && fsm->fz_fsm_state == PM_FSM_STOP + && pm_meas.p50 > 0.1f) sv630p_speed_mode_resume(&sv630p_handle); } else @@ -138,7 +148,7 @@ int data_process_init(void) return -1; } //valley_seek_init(&pm_meas.valley_seek); - working_set_state(PM_MEAS_TEST_Mode); + if (et_zero_cross_create(&pm_meas.zc, 100) != 0) { ET_ERR("zc create failed\n"); @@ -177,13 +187,13 @@ int data_process_init(void) #endif etk_position_pid_init(&pm_meas.pid, - 1.8f, // kp: 提高比例增益,加快响应速度 - 1.8f, // ki: 增加积分增益,加快接近目标时的收敛速度 - 0.25f, // kd: 进一步降低微分作用,减少阻尼 - PID_TARGET_ZERO_POS_VAL, // 目标值设置为0.6 - 2.5f, // 积分限幅,允许更多积分累积加快收敛 - -FZ_FAST_CLOSE_STAGE_RPM, // 最小输出(限制最大反转速度) - FZ_FAST_CLOSE_STAGE_RPM, -1); + 1.8f, // kp: 提高比例增益,加快响应速度 + 1.8f, // ki: 增加积分增益,加快接近目标时的收敛速度 + 0.25f, // kd: 进一步降低微分作用,减少阻尼 + PID_TARGET_ZERO_POS_VAL, // 目标值设置为0.6 + 2.5f, // 积分限幅,允许更多积分累积加快收敛 + -FZ_FAST_CLOSE_STAGE_RPM, // 最小输出(限制最大反转速度) + FZ_FAST_CLOSE_STAGE_RPM, -1); result = rt_thread_init(&data_process_thread, // 线程控制块指针 "d-process", // 线程名称 data_process_thread_entry, // 入口函数 @@ -204,4 +214,4 @@ int data_process_init(void) rt_kprintf("Thread init failed: 0x%04X\n", result); } return 0; -} \ No newline at end of file +} diff --git a/User/app/data_sampling.c b/User/app/data_sampling.c index 6179c49..fbd4630 100644 --- a/User/app/data_sampling.c +++ b/User/app/data_sampling.c @@ -2,7 +2,7 @@ * @Date: 2025-07-15 11:12:00 * @Author: mypx * @LastEditors: mypx mypx_coder@163.com - * @LastEditTime: 2025-09-24 14:24:04 + * @LastEditTime: 2025-10-24 10:05:49 * @FilePath: data_sampling.c * @Description: * Copyright (c) 2025 by mypx, All Rights Reserved. @@ -14,6 +14,7 @@ #include "servo.h" #include #include +#include "bsp_collect.h" uint16_t adc_raw_buffer[DATA_PROCESS_UNIT_COUNT] = {0}; @@ -21,54 +22,22 @@ float sampling_rate = 0; static void *mq_pool[8]; struct rt_messagequeue adc_mq; -/* 半缓冲完成回调 */ -// void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef *hadc) -// { -// if (hadc->Instance == ADC1) -// { -// __HAL_DMA_CLEAR_FLAG(hadc->DMA_Handle, __HAL_DMA_GET_HT_FLAG_INDEX(hadc->DMA_Handle)); -// uint16_t *ptr = &adc_raw_buffer[0]; -// pm_system_led_on(); -// rt_mq_send(&adc_mq, &ptr, sizeof(ptr)); -// } -// } /* 整个缓冲区完成回调 */ -void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc) +void light_data_sampling_complete(void) { - if (hadc->Instance == ADC1) + uint16_t *ptr = &adc_raw_buffer[0]; + //bsp_system_led_toggle(); + if (rt_mq_send(&adc_mq, &ptr, sizeof(ptr)) != RT_EOK) { - __HAL_DMA_CLEAR_FLAG(hadc->DMA_Handle, __HAL_DMA_GET_TC_FLAG_INDEX(hadc->DMA_Handle)); - uint16_t *ptr = &adc_raw_buffer[0]; - pm_system_led_toggle - (); - if (rt_mq_send(&adc_mq, &ptr, sizeof(ptr)) != RT_EOK) - { - ET_ERR("ADC MQ full!"); - } + ET_ERR("ADC MQ full!"); } } -void data_sampling_start(void) +int light_data_sampling_init(void) { - pm_sampling_adc_start(adc_raw_buffer, DATA_PROCESS_UNIT_COUNT); - pm_sampling_tim_start(); - //pm_timestamp_start(); -} - -void data_sampling_stop(void) -{ - //pm_encoder_stop(); - // pm_sampling_tim_stop(); - // pm_timestamp_stop(); - pm_sampling_adc_stop(); -} - -int data_sampling_init(void) -{ - pm_adc_init(); - pm_sampling_tim_init(); + bsp_light_data_sampling_init(adc_raw_buffer, DATA_PROCESS_UNIT_COUNT, light_data_sampling_complete); pm_encoder_init(); //pm_timestamp_tim_init(); pm_encoder_start(); @@ -77,9 +46,8 @@ int data_sampling_init(void) rt_mq_init(&adc_mq, "adc_mq", mq_pool, sizeof(void *), sizeof(mq_pool), RT_IPC_FLAG_FIFO); // test-> set state manually //pm_set_state(PM_CALIBRATION_STATE); - sampling_rate = pm_sampling_tim_get_freq(); + sampling_rate = bsp_sampling_tim_get_freq(); ET_WARN("Sampling rate:%.2f", sampling_rate); - data_sampling_start(); // test->start at init return 0; } @@ -116,4 +84,4 @@ void m_fast(void) { sv630p_speed_mode_start(&sv630p_handle, 400); } -MSH_CMD_EXPORT(m_fast, motor fast forward); \ No newline at end of file +MSH_CMD_EXPORT(m_fast, motor fast forward); diff --git a/User/app/data_sampling.h b/User/app/data_sampling.h index c1159b9..252bfae 100644 --- a/User/app/data_sampling.h +++ b/User/app/data_sampling.h @@ -2,7 +2,7 @@ * @Date: 2025-07-15 11:12:08 * @Author: mypx * @LastEditors: mypx mypx_coder@163.com - * @LastEditTime: 2025-09-16 11:25:32 + * @LastEditTime: 2025-10-14 13:47:14 * @FilePath: data_sampling.h * @Description: * Copyright (c) 2025 by mypx, All Rights Reserved. @@ -10,7 +10,7 @@ #ifndef __DATA_SAMPLING_H__ #define __DATA_SAMPLING_H__ #include "bsp_encoder.h" -#include "pm_board.h" +#include "bsp_misc.h" extern struct rt_messagequeue adc_mq; @@ -19,10 +19,6 @@ extern uint16_t adc_raw_buffer[DATA_PROCESS_UNIT_COUNT]; extern float sampling_rate; -int data_sampling_init(void); - -void data_sampling_start(void); - -void data_sampling_stop(void); +int light_data_sampling_init(void); #endif diff --git a/User/app/mb_hmi/CMakeLists.txt b/User/app/mb_hmi/CMakeLists.txt index ce8f4aa..8ee5651 100644 --- a/User/app/mb_hmi/CMakeLists.txt +++ b/User/app/mb_hmi/CMakeLists.txt @@ -1,31 +1,14 @@ -# mb_hmi模块的CMakeLists.txt - -# 创建mb_hmi库 add_library(mb_hmi STATIC mb_command.c mb_server.c mb_interface.c ) -# 设置包含目录 target_include_directories(mb_hmi PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ) -# 链接依赖库 target_link_libraries(mb_hmi - PUBLIC - nanomodbus - # 根据需要添加其他依赖 -) - -# 如果etk_os_adapt可用,链接它 -if(TARGET etk_os_adapt) - target_link_libraries(mb_hmi PUBLIC etk_os_adapt) -endif() - -# 根据系统类型设置编译选项 -if(DEFINED SYSTEM_TYPE) - message(STATUS "[mb_hmi] System type: ${SYSTEM_TYPE}") -endif() \ No newline at end of file + PUBLIC nanomodbus +) \ No newline at end of file diff --git a/User/app/mb_hmi/hmi_server.c b/User/app/mb_hmi/hmi_server.c index 002de12..2250623 100644 --- a/User/app/mb_hmi/hmi_server.c +++ b/User/app/mb_hmi/hmi_server.c @@ -3,6 +3,9 @@ #include "etk_utils.h" #include "mb_command.h" #include "mb_interface.h" +#include "bsp_hmi.h" +#include "bsp_motor.h" + nmbs_t nmbs; static rt_uint8_t mb_hmi_stack[HMI_THREAD_STACK_SIZE]; @@ -25,8 +28,8 @@ static nmbs_error nmbs_server_init(nmbs_t *nmbs) nmbs_platform_conf_create(&conf); conf.transport = NMBS_TRANSPORT_RTU; - conf.read = pm_hmi_uart_read; - conf.write = pm_hmi_uart_write; + conf.read = bsp_hmi_uart_read; + conf.write = bsp_hmi_uart_write; nmbs_callbacks_create(&cb); cb.read_coils = NULL; @@ -142,7 +145,7 @@ int hmi_server_handler_register(hmi_server_t *hmi, mb_cmd_handler_t *handler) int hmi_server_init(hmi_server_t *hmi) { - if (pm_mb_hmi_init() != 0) + if (bsp_mb_hmi_init() != 0) { ET_ERR("Failed to initialize Modbus HMI"); return -1; diff --git a/User/app/mb_hmi/hmi_server.h b/User/app/mb_hmi/hmi_server.h index 689dc70..cf785bc 100644 --- a/User/app/mb_hmi/hmi_server.h +++ b/User/app/mb_hmi/hmi_server.h @@ -1,7 +1,7 @@ #ifndef __HMI_SERVER_H__ #define __HMI_SERVER_H__ #include "nanomodbus.h" -#include "pm_board.h" +#include "bsp_misc.h" #include "pm_common.h" #include "mb_command.h" diff --git a/User/app/mb_hmi/mb_command.c b/User/app/mb_hmi/mb_command.c index a485560..ee4b1cb 100644 --- a/User/app/mb_hmi/mb_command.c +++ b/User/app/mb_hmi/mb_command.c @@ -1,7 +1,7 @@ /* * @Author: mypx * @Date: 2025-08-01 16:41:44 - * @LastEditTime: 2025-09-26 15:00:17 + * @LastEditTime: 2025-09-26 09:21:13 * @LastEditors: mypx mypx_coder@163.com * @Description: */ diff --git a/User/app/pm_common.h b/User/app/pm_common.h index b9890a4..537100a 100644 --- a/User/app/pm_common.h +++ b/User/app/pm_common.h @@ -2,7 +2,7 @@ * @Date: 2025-07-18 08:53:16 * @Author: mypx * @LastEditors: mypx mypx_coder@163.com - * @LastEditTime: 2025-09-24 16:11:11 + * @LastEditTime: 2025-10-14 13:56:58 * @FilePath: pm_common.h * @Description: * Copyright (c) 2025 by mypx, All Rights Reserved. @@ -10,7 +10,7 @@ #ifndef __PM_COMMON__ #define __PM_COMMON__ #include "bsp_encoder.h" -#include "pm_board.h" +#include "bsp_misc.h" #include #include diff --git a/User/app/pm_device.c b/User/app/pm_device.c index 7b132ce..f737202 100644 --- a/User/app/pm_device.c +++ b/User/app/pm_device.c @@ -1,7 +1,7 @@ /* * @Author: mypx * @Date: 2025-07-07 14:25:47 - * @LastEditTime: 2025-09-26 10:49:49 + * @LastEditTime: 2025-10-24 13:06:47 * @LastEditors: mypx mypx_coder@163.com * @Description: */ @@ -14,6 +14,7 @@ #include "pt100x.h" #include "servo.h" #include "storage.h" +#include "bsp_tec.h" extern ad7793_dev_t ad7793_dev; @@ -89,21 +90,29 @@ int pm_device_start(pm_device_t *dev) int pm_device_init(pm_device_t *dev) { - pm_board_init(); + int ret = 0; + pm_board_init(); // TODO:Delete this later + bsp_tec_init(); pm_params_init(&dev->params); - hmi_server_handler_register(&dev->hmi, &hmi_cmd_handler); - hmi_server_init(&dev->hmi); + // hmi_server_handler_register(&dev->hmi, &hmi_cmd_handler); + // hmi_server_init(&dev->hmi); pm_fsm_init(&dev->fz_fsm); //storage_init(); - tec_control_init(&dev->tec); - // if (servo_init() != 0) - // { - // ET_ERR("Servo init failed!"); - // //return; - // } - // data_sampling_init(); - // data_process_init(); + ret = tec_control_init(&dev->tec); + if(ret != 0) + { + ET_WARN("TEC control init failed!"); + return -1; + } + tec_control_sercie_start(&dev->tec); + if (servo_init() != 0) + { + ET_ERR("Servo init failed!"); + return -1; + } + light_data_sampling_init(); + data_process_init(); return 0; } diff --git a/User/app/pm_device.h b/User/app/pm_device.h index b100837..5ae791f 100644 --- a/User/app/pm_device.h +++ b/User/app/pm_device.h @@ -9,7 +9,7 @@ */ #ifndef __PM_DEVICE_H__ #define __PM_DEVICE_H__ -#include "pm_board.h" +#include "bsp_misc.h" #include "bsp_encoder.h" #include "mb_command.h" #include "tec_control.h" diff --git a/User/app/pm_meas.c b/User/app/pm_meas.c index ec9b96e..b50060c 100644 --- a/User/app/pm_meas.c +++ b/User/app/pm_meas.c @@ -1,7 +1,7 @@ /* * @Author: mypx * @Date: 2025-08-11 08:30:45 - * @LastEditTime: 2025-09-24 16:12:52 + * @LastEditTime: 2025-10-27 15:06:18 * @LastEditors: mypx mypx_coder@163.com * @Description: */ @@ -9,15 +9,13 @@ #include "data_process.h" #include "data_sampling.h" #include "et_waveform_analysis.h" -#include "etk_diff.h" -#include "etk_ringbuffer.h" #include "servo.h" #include #include #include -static pm_fsm_t *pm_fsm = NULL; +static pm_fsm_t *pm_fsm = NULL; pm_fsm_t *get_pm_fsm(void) { @@ -39,7 +37,7 @@ void calibrate_mode_toggle(void) if (!fsm) return; fsm->fz_fsm_state = false; - fsm->meas_mode = fsm->meas_mode == PM_MEAS_NORMAL_Mode ? PM_MEAS_TEST_Mode : PM_MEAS_NORMAL_Mode; + fsm->meas_mode = fsm->meas_mode == PM_MEAS_NORMAL_Mode ? PM_MEAS_TEST_Mode : PM_MEAS_NORMAL_Mode; } MSH_CMD_EXPORT_ALIAS(calibrate_mode_toggle, cali, calibrate mode toggle); @@ -168,17 +166,18 @@ void accuracy_auto_measurement_once(pm_meas_t *fz, float angle) #endif uint32_t delay = convert_encoder_angle_rpm_to_to_time(diff, RUN_OFFSET_ANGLE_RPM); ET_DBG("wait %d ms to target:%.2f", delay, target_angle); - int speed = (target_angle > angle) ? -RUN_OFFSET_ANGLE_RPM - : RUN_OFFSET_ANGLE_RPM; // FIXME:note encoder dir and motor dir + int speed = (target_angle > angle) ? (RUN_OFFSET_ANGLE_RPM * ENCODER_MOTOR_DIR_FACTOR) + : (-RUN_OFFSET_ANGLE_RPM * ENCODER_MOTOR_DIR_FACTOR); // FIXME:note encoder dir and motor dir sv630p_speed_mode_start(&sv630p_handle, speed); fz->target_dir = (speed > 0) ? -1 : 1; ET_WARN("SPEED:%d", speed); + uint32_t start_time = rt_tick_get_millisecond(); while (1) { angle = get_real_time_angle_degree(); //ET_DBG("angle:%.2f", angle); // 根据方向判断是否达到目标角度,处理负数角度情况 - if (((speed > 0) && (target_angle > angle)) || ((speed < 0) && (target_angle < angle))) + if (((speed > 0) && (target_angle > angle)) || ((speed < 0) && (target_angle < angle))) //1000, -183,1124 { sv630p_speed_mode_stop(&sv630p_handle); ET_INFO("Set angle:%.3f, reached:%.3f", target_angle, angle); @@ -197,6 +196,12 @@ void accuracy_auto_measurement_once(pm_meas_t *fz, float angle) break; } + else if (rt_tick_get_millisecond() - start_time > delay) + { + ET_WARN("Timeout, set angle:%.3f, reached:%.3f, speed:%d", target_angle, angle, speed); + sv630p_speed_mode_stop(&sv630p_handle); + break; + } } } @@ -321,10 +326,12 @@ StageResult is_prepare_leave_stage(pm_meas_t *fz) StageResult is_wave_leave_stage(pm_meas_t *fz) { - if ((fz->slope < -100000) || (fz->freq > 52 && fz->freq < 98 && fz->p50 < 1000 && fz->trend == TREND_DECREASE) - || (fz->freq < 1.0 && fz->trend == TREND_DECREASE)) - return STAGE_RESULT_OK; - else + // if ((fz->slope < -100000) || (fz->freq > 52 && fz->freq < 98 && fz->p50 < 1000 && fz->trend == TREND_DECREASE) + // || (fz->freq < 1.0 && fz->trend == TREND_DECREASE)) // old version parameter + // if ((fz->slope < -200 && (fz->freq < 48 || fz->freq > 102) && fz->p50 < 1000 && fz->trend == TREND_DECREASE) + // || (fz->freq < 1.0 && fz->trend == TREND_DECREASE)) + // return STAGE_RESULT_OK; + // else return STAGE_RESULT_NO; } @@ -522,10 +529,10 @@ int find_zero_process(pm_meas_t *fz, const uint16_t *adc_buf, uint32_t len) { sv630p_speed_mode_stop(&sv630p_handle); measurement_info_print(fz); - fsm->fz_fsm_state = true; // test use - fz->calib_cnt = 0; - fsm->meas_mode = PM_MEAS_NORMAL_Mode; - fz->target_dir = MEASURE_DEF_DIR; + fsm->fz_fsm_state = true; // test use + fz->calib_cnt = 0; + fsm->meas_mode = PM_MEAS_NORMAL_Mode; + fz->target_dir = MEASURE_DEF_DIR; //ET_WARN("Mesaure time:%d ms", rt_tick_get_millisecond() - fz->calib_start_time); } break; @@ -553,6 +560,7 @@ int find_zero_process(pm_meas_t *fz, const uint16_t *adc_buf, uint32_t len) int pm_fsm_init(pm_fsm_t *fsm) { - pm_fsm = fsm; + pm_fsm = fsm; + fsm->fz_fsm_state = true; return 0; } diff --git a/User/app/pm_meas.h b/User/app/pm_meas.h index ec7861a..a4f9445 100644 --- a/User/app/pm_meas.h +++ b/User/app/pm_meas.h @@ -1,7 +1,7 @@ /* * @Author: mypx * @Date: 2025-08-11 08:30:53 - * @LastEditTime: 2025-09-24 16:10:18 + * @LastEditTime: 2025-10-24 17:11:50 * @LastEditors: mypx mypx_coder@163.com * @Description: */ @@ -13,18 +13,18 @@ #include "etk_slope.h" #include "pm_common.h" -#define FZ_CALI_MAX_COUNT 10 +#define FZ_CALI_MAX_COUNT 4 #define ZC_COUNT_STABLE_TIMES 5 -#define ZERO_POS_THRESHOLD 0.5f +#define ZERO_POS_THRESHOLD 1.0f #define PID_TARGET_ZERO_POS_VAL 0.0f #define RUN_OFFSET_ANGLE_RPM (1000) -#define FZ_UNKNOWN_STAGE_RPM 1000 -#define FZ_SATURATED_STAGE_RPM 1000 -#define FZ_WAVE_ENTER_STAGE_RPM 1000 -#define FZ_PREPARE_STAGE_RPM 1000 -#define FZ_FAST_CLOSE_STAGE_RPM 700 +#define FZ_UNKNOWN_STAGE_RPM 2000 +#define FZ_SATURATED_STAGE_RPM 2000 +#define FZ_WAVE_ENTER_STAGE_RPM 2000 +#define FZ_PREPARE_STAGE_RPM 2000 +#define FZ_FAST_CLOSE_STAGE_RPM 1400 #define FZ_PRECISE_ADJUST_MIN_RPM (0.6f * MOTOR_TO_ENCODER_FACTOR) // 0.6rpm->0.001 #define FZ_SATURATED_POWER_MAX 5.0f @@ -40,8 +40,6 @@ #define FZ_PREPARE_LEAVE_FREQ_MIN 48.0f #define FZ_PREPARE_LEAVE_FREQ_MAX 52.0f -extern bool fsm_state; - typedef enum { TREND_UNKNOWN = 0, // 未知(首次调用,无历史数据) @@ -146,4 +144,6 @@ int find_zero_process(pm_meas_t *fz, const uint16_t *adc_val, uint32_t len); int pm_fsm_init(pm_fsm_t *fsm); +pm_fsm_t *get_pm_fsm(void); + #endif diff --git a/User/app/servo.c b/User/app/servo.c index ebb9358..d5dca2d 100644 --- a/User/app/servo.c +++ b/User/app/servo.c @@ -2,14 +2,14 @@ * @Date: 2025-06-26 14:49:09 * @Author: mypx * @LastEditors: mypx mypx_coder@163.com - * @LastEditTime: 2025-08-29 09:08:23 + * @LastEditTime: 2025-10-15 16:53:50 * @FilePath: servo.c * @Description: * Copyright (c) 2025 by mypx, All Rights Reserved. */ #include "servo.h" #include "nanomodbus.h" -#include "pm_board.h" +#include "bsp_misc.h" #include "rtdef.h" #include "rtthread.h" @@ -102,12 +102,12 @@ int servo_init(void) int ret = 0; nmbs_platform_conf stm32_conf; // board layer init - pm_servo_init(); + bsp_servo_init(); // nmbs layer init nmbs_platform_conf_create(&stm32_conf); stm32_conf.transport = NMBS_TRANSPORT_RTU; - stm32_conf.read = pm_servo_uart_read; - stm32_conf.write = pm_servo_uart_write; + stm32_conf.read = bsp_servo_uart_read; + stm32_conf.write = bsp_servo_uart_write; nmbs_error status = nmbs_client_create(&servo_nmbs, &stm32_conf); if (status != NMBS_ERROR_NONE) diff --git a/User/app/servo.h b/User/app/servo.h index eac7aa6..732e76a 100644 --- a/User/app/servo.h +++ b/User/app/servo.h @@ -2,20 +2,21 @@ * @Date: 2025-06-26 14:49:15 * @Author: mypx * @LastEditors: mypx mypx_coder@163.com - * @LastEditTime: 2025-08-19 08:51:18 + * @LastEditTime: 2025-10-15 16:55:31 * @FilePath: servo.h * @Description: * Copyright (c) 2025 by mypx, All Rights Reserved. */ #ifndef __SERVO_H__ #define __SERVO_H__ -#include "pm_board.h" +#include "bsp_misc.h" #include "sv_device.h" #include "pm_common.h" #include "et_log.h" #include "h02_basic_control.h" #include "h31_comm_related_var.h" #include "h0d_af.h" +#include "bsp_motor.h" #if (ENABLE_SV630P == 1) extern sv630p_handle_t sv630p_handle; diff --git a/User/app/storage.c b/User/app/storage.c index 41a2aeb..f4976e2 100644 --- a/User/app/storage.c +++ b/User/app/storage.c @@ -2,15 +2,15 @@ #include #include #include "storage.h" -#include "pm_board.h" +#include "bsp_misc.h" #include "i2c.h" void storage_dbg(const char *tag, const char *fmt, ...); at24cx_dev_t at24c02_device = { .dev_addr = 0xA0, - .write_bytes = pm_i2c_write_bytes, - .read_bytes = pm_i2c_read_bytes, + .write_bytes = bsp_i2c_write_bytes, + .read_bytes = bsp_i2c_read_bytes, .log = storage_dbg, }; @@ -51,7 +51,7 @@ void storage_test(void) rt_kprintf("Failed to write data to EEPROM\r\n"); } rt_thread_delay(1000); // Delay for 1 second - pm_system_led_toggle(); // Toggle the system LEDs + bsp_system_led_toggle(); // Toggle the system LEDs //rt_kprintf("[%d] System LED toggled\n", rt_tick_get()); // Print message to console if (at24cx_read(&at24c02_device, 0x0a, read_buf, 8) != 0) { diff --git a/User/app/tec_control.c b/User/app/tec_control.c index ea84704..83e36b2 100644 --- a/User/app/tec_control.c +++ b/User/app/tec_control.c @@ -2,34 +2,87 @@ * @Date: 2025-06-23 13:04:20 * @Author: mypx * @LastEditors: mypx mypx_coder@163.com - * @LastEditTime: 2025-09-25 16:49:59 + * @LastEditTime: 2025-10-27 08:42:50 * @FilePath: tec_control.c * @Description: * Copyright (c) 2025 by mypx, All Rights Reserved. */ #include "tec_control.h" #include "ad7793.h" +#include "bsp_misc.h" +#include "bsp_tec.h" +#include "bsp_temper_sampling.h" #include "et_log.h" #include "etk_utils.h" #include "mb_interface.h" -#include "pm_board.h" #include "pm_common.h" #include "pt100x.h" +#include +#include #include #include +#include /* rand, RAND_MAX */ + #if TEC_CONTROL_PERIOD < ADC_SAMPLE_PERIOD #error "TEC_CONTROL_PERIOD must be greater than ADC_SAMPLE_PERIOD" #endif +#define TEST_TEMPER_XFER 0 + +/* Local helpers to avoid implicit prototypes on some embedded libc's */ +static inline int _isnan_f(float v) +{ + return v != v; +} +static inline float _fabs_f(float v) +{ + return v < 0.0f ? -v : v; +} + /* Define AD7793 device structure */ -ad7793_dev_t ad7793_dev; -extern ad7793_hw_if_t ad7793_hw_if; +ad7793_dev_t ad7793_dev; + #if (USING_SOFT_SPI == 1) extern soft_spi_t soft_spi; #endif tec_control_t *tec_control = NULL; +ad7793_hw_if_t ad7793_hw_if = { + .spi_transfer = bsp_ad7793_spi_transfer, + .spi_write = bsp_ad7793_spi_write, + .spi_read = bsp_ad7793_spi_read, + .gpio_set = bsp_ad7793_gpio_set, + .gpio_get = bsp_ad7793_gpio_get, + .delay_ms = bsp_ad7793_delay_ms, +}; + +/* ------------------------------------------------------------- + * AD7793 应用层配置 + * 依据提供原理图的典型 RTD/PT100 测温拓扑做如下假设: + * 1. 仅测量正向电压 => 使用单极 (unipolar) + * 2. 传感器电流源(或恒流驱动)下 PT100 产生的电压几十 mV 级,选择增益 16: + * - 内部参考 1.17V / GAIN16 满量程约 73mV,有足够余量覆盖 0~200+℃ (约 21mV~37mV) + * - 若后续发现仍远低于满量程,可改为 GAIN32;若出现接近饱和则降为 GAIN8。 + * 3. 启用输入缓冲 (buffered=true) 以减小前端阻抗对 ADC 的影响。 + * 4. 采用内部参考 (1.17V) 简化;若外部精密参考芯片实际接入 REF+ / REF-, + * 将 use_internal_ref 改为 false 并填写 external_ref (例如 2.500f 或 3.000f)。 + * 5. 选择较低输出数据速率 8.33Hz 获取更好噪声性能(速率越低,数字滤波越强)。 + * 6. 上电后做一次 system zero 校准,提高 offset 精度。 + * ------------------------------------------------------------- */ +static const ad7793_config_t g_ad7793_config = { + .use_internal_ref = false, /* 现在使用板上 2.5V 外部参考 (已实测 REFIN+=2.5V) */ + .external_ref = 2.500f, + /* 传感器差分约 0.044V, 需保证 < Vref / Gain + 选择 GAIN=4 -> 满量程 2.5/4=0.625V (安全覆盖 0.44V); 若后续电压更低可再调高增益 */ + .gain = AD7793_GAIN_4, + .channel = AD7793_CHANNEL_1, /* AIN1(+) - AIN1(-) */ + .rate = AD7793_RATE_8_33HZ, + .unipolar_mode = true, /* 只测正向信号 */ + .buffered = true, /* 启用缓冲 */ + .calibrate_system_zero = false /* 暂停 system zero 校准 (之前 OFFSET/FULLSC 已被污染) */ +}; + /* Shared data structure for temperature sampling and TEC control */ static struct { @@ -93,7 +146,7 @@ void tec_control_reset(void) } } -int tec_control_start(void) +int tec_control_resume(void) { if (tec_control == NULL) { @@ -110,7 +163,7 @@ int tec_control_start(void) return 0; } -int tec_control_stop(void) +int tec_control_pause(void) { if (tec_control == RT_NULL) { @@ -127,19 +180,20 @@ void tec_calculate_temperature(uint32_t adc_value) float mv = 0; double resistance; mv = ad7793_convert_to_voltage(&ad7793_dev, adc_value) * 1000; - ET_DBG("voltage:%.2f", mv); + //ET_DBG("voltage:%.2f", mv); resistance = solve_resistance(mv / 1000); + //ET_DBG("resistance:%.2f", resistance); //ET_PRINTF_FLOAT("resistance:", resistance); tec_control->cur_temper = pt_precise_temperature(resistance, PT100); tec_control->cur_temper = et_ema_filter_process(&tec_control->ema_filter, tec_control->cur_temper); - if (isnan(tec_control->cur_temper)) + if (_isnan_f(tec_control->cur_temper)) { - rt_kprintf("Invalid resistance value, cannot calculate temperature.\n"); + ET_DBG("Invalid resistance value, cannot calculate temperature.\n"); } else { - ET_DBG("temperature:%.2f", tec_control->cur_temper); + //ET_DBG("temperature:%.4f", tec_control->cur_temper); /* Update shared data */ rt_mutex_take(temp_shared_data.data_mutex, RT_WAITING_FOREVER); temp_shared_data.current_temperature = tec_control->cur_temper; @@ -148,46 +202,87 @@ void tec_calculate_temperature(uint32_t adc_value) } } +#if TEST_TEMPER_XFER float generate_random_temperature(void) { - // 生成0到RAND_MAX之间的随机整数 - int randomInt = rand(); - // 转换为0到1之间的浮点数,再映射到0到55范围 - float randomFloat = (float)randomInt / RAND_MAX * 55.0f; - return randomFloat; + static uint32_t lfsr = 0xACE1u; /* simple LFSR to avoid rand() dependency */ + lfsr ^= lfsr << 7; + lfsr ^= lfsr >> 9; + lfsr ^= lfsr << 8; + return (lfsr & 0xFFFF) * (55.0f / 65535.0f); } +#endif + /* Temperature sampling thread entry function */ -static void temp_sampling_thread_entry(void *parameter) +static void temper_sampling_thread_entry(void *parameter) { ETK_UNUSED(parameter); - //uint32_t adc_value = 0; + uint32_t adc_value = 0; + const uint32_t LOW_CODE_THRESHOLD = 0x200; /* 约 0.125% 满量程,可调 */ + uint32_t consecutive_err = 0; ET_INFO("Temperature sampling thread started"); while (1) { +#if !TEST_TEMPER_XFER /* Wait for ADC ready and read data */ - // if (ad7793_wait_ready(&ad7793_dev, 1000) == true) - // { - // if (ad7793_read_data(&ad7793_dev, &adc_value)) - // { - // /* Calculate temperature from ADC value */ - // tec_calculate_temperature(adc_value); - // } - // else - // { - // ET_ERR("Failed to read ADC data.\n"); - // } - // } - //mb_write_current_temp(tec_control->cur_temper); - mb_write_current_temp(generate_random_temperature()); // test only + if (ad7793_wait_ready(&ad7793_dev, 1000) == true) + { + if (ad7793_read_data(&ad7793_dev, &adc_value)) + { + /* 低码过滤:避免极低噪声或参考丢失导致的虚假高温 */ + if (adc_value < LOW_CODE_THRESHOLD) + { + ad7793_dev.low_code_drops++; + ET_DBG("drop low code: 0x%06X (drops=%lu)", (unsigned)adc_value, + (unsigned long)ad7793_dev.low_code_drops); + } + else + { + //ET_DBG("raw code: 0x%06X", (unsigned)adc_value); + tec_calculate_temperature(adc_value); + } + } + else + { + ET_ERR("Failed to read ADC data.\n"); + } + } + mb_write_current_temp(tec_control->cur_temper); +#else + mb_write_current_temp(generate_random_temperature()); // test only mb_write_current_rotation(generate_random_temperature()); // test only +#endif /* Delay for next sampling period */ rt_thread_mdelay(ADC_SAMPLE_PERIOD); } } +// pwm: 0.0 ~ 1.0 +void tec_adjust_pwm(float pwm, float cur_temper, float target_temper) +{ + if (_fabs_f(cur_temper - target_temper) < TEC_TEMPER_PRECISE) + { + // within precise range, stop adjustment + bsp_tec_close(); + bsp_fan_stop(); + return; + } + //bsp_fan_start(); + if (cur_temper > target_temper) + { + // cooling + bsp_tec_cooling_adjust(pwm); + } + else + { + // heating + bsp_tec_heating_adjust(pwm); + } +} + void tec_control_temperature(tec_control_t *tec) { float pid_out = 0; @@ -213,7 +308,7 @@ void tec_control_temperature(tec_control_t *tec) // dt convert to seconds pid_out = tec_pid_update(tec, tec->target_temper, current_temp, TEC_CONTROL_PERIOD / 1000.0f); ET_INFO("pid_out:%.2f", pid_out); - pm_tec_set_duty(pid_out); + tec_adjust_pwm(pid_out, current_temp, tec->target_temper); } static void tec_control_thread_entry(void *parameter) @@ -222,11 +317,10 @@ static void tec_control_thread_entry(void *parameter) rt_tick_t last_ms = rt_tick_get_millisecond(); rt_uint32_t received; - et_ema_filter_init(&tec_control->ema_filter, EMA_FILTER_ALPHA); tec_pid_init(tec_control); tec_control->is_control = false; // control disabled by default - pm_tec_start(); - pm_fan_start(); + + //bsp_fan_start(); tec_control->target_temper = 25.0f; ET_INFO("TEC control thread started"); @@ -241,13 +335,13 @@ static void tec_control_thread_entry(void *parameter) // handle received events if (received & TEC_CONTROL_START_EVENT) { - tec_control_start(); + tec_control_resume(); ET_INFO("TEC control started by event"); } if (received & TEC_CONTROL_STOP_EVENT) { - tec_control_stop(); + tec_control_pause(); ET_INFO("TEC control stopped by event"); } @@ -265,19 +359,46 @@ static void tec_control_thread_entry(void *parameter) } } +int tec_control_sercie_start(tec_control_t *tec) +{ + (void)tec; /* unused parameter for now */ + rt_thread_t temp_tid; + rt_thread_t ctrl_tid; + (void)ctrl_tid; + // create temperature sampling thread + temp_tid = rt_thread_create("temp-sample", temper_sampling_thread_entry, RT_NULL, TEMP_SAMPLE_THREAD_STACK_SIZE, + TEMP_SAMPLE_THREAD_PRIORITY, TEMP_SAMPLE_THREAD_TIMESLICE); + if (temp_tid == RT_NULL) + { + ET_ERR("Failed to create temperature sampling thread"); + return -6; + } + rt_thread_startup(temp_tid); + /* create TEC control thread */ + ctrl_tid = rt_thread_create("tec-control", tec_control_thread_entry, RT_NULL, TEC_CONTROL_THREAD_STACK_SIZE, + TEC_CONTROL_THREAD_PRIORITY, TEC_CONTROL_THREAD_TIMESLICE); + if (ctrl_tid == RT_NULL) + { + ET_ERR("Failed to create tec-control thread"); + return -7; + } + rt_thread_startup(ctrl_tid); + return 0; +} + int tec_control_init(tec_control_t *tec) { - rt_thread_t tid; - rt_thread_t temp_tid; if (tec == NULL) { ET_ERR("tec is NULL"); return -1; } - pm_tec_init(); + tec_control = tec; + et_ema_filter_init(&tec_control->ema_filter, EMA_FILTER_ALPHA); + // create event object for temperature control tec_control->control_event = rt_event_create("tec_event", RT_IPC_FLAG_FIFO); if (tec_control->control_event == RT_NULL) @@ -298,39 +419,19 @@ int tec_control_init(tec_control_t *tec) temp_shared_data.current_temperature = 25.0f; temp_shared_data.temp_updated = false; - // #if (USING_SOFT_SPI == 1) - // if (ad7793_init(&ad7793_dev, &ad7793_hw_if, soft_spi.cs_pin)) - // #else - // if (ad7793_init(&ad7793_dev, &ad7793_hw_if, SPI3_CS_AD7793_Pin)) - // #endif - // { - // rt_kprintf("AD7793 device initialized successfully.\n"); - // } - // else - // { - // rt_kprintf("Failed to initialize AD7793 device.\n"); - // return -2; - // } - - // create temperature sampling thread - temp_tid = rt_thread_create("temp-sample", temp_sampling_thread_entry, RT_NULL, TEMP_SAMPLE_THREAD_STACK_SIZE, - TEMP_SAMPLE_THREAD_PRIORITY, TEMP_SAMPLE_THREAD_TIMESLICE); - if (temp_tid == RT_NULL) +#if (USING_SOFT_SPI == 1) + if (ad7793_init(&ad7793_dev, &ad7793_hw_if, soft_spi.cs_pin, &g_ad7793_config)) +#else + if (ad7793_init(&ad7793_dev, &ad7793_hw_if, SPI3_AD7793_CS_Pin, &g_ad7793_config)) +#endif { - ET_ERR("Failed to create temperature sampling thread"); - return -6; + rt_kprintf("AD7793 device initialized successfully.\n"); + } + else + { + rt_kprintf("Failed to initialize AD7793 device.\n"); + return -2; } - rt_thread_startup(temp_tid); - // create TEC control thread - // tid = rt_thread_create("tec-control", tec_control_thread_entry, RT_NULL, TEC_CONTROL_THREAD_STACK_SIZE, - // TEC_CONTROL_THREAD_PRIORITY, TEC_CONTROL_THREAD_TIMESLICE); - - // if (tid != RT_NULL) - // { - // rt_thread_startup(tid); - // return 0; - // } - - return -4; + return 0; } diff --git a/User/app/tec_control.h b/User/app/tec_control.h index 0b5c9b1..ed0c5ec 100644 --- a/User/app/tec_control.h +++ b/User/app/tec_control.h @@ -1,7 +1,7 @@ /* * @Author: mypx * @Date: 2025-06-23 13:05:04 - * @LastEditTime: 2025-09-25 13:13:20 + * @LastEditTime: 2025-10-16 14:01:47 * @LastEditors: mypx mypx_coder@163.com * @Description: */ @@ -19,7 +19,7 @@ #include #include -#define EMA_FILTER_ALPHA 0.1 +#define EMA_FILTER_ALPHA 0.9 #define EXCEPTION_TEMPERATURE_DEF 45.0f // exception temperature value, control will not be performed if exceeded #define TEC_CONTROL_PERIOD 1000 // temperature calculation period, unit ms #define ADC_SAMPLE_PERIOD 500 // ADC sampling period, unit ms @@ -47,9 +47,11 @@ int tec_control_init(tec_control_t *tec); void tec_control_reset(void); -int tec_control_start(void); +int tec_control_resume(void); -int tec_control_stop(void); +int tec_control_sercie_start(tec_control_t *tec); + +int tec_control_pause(void); float tec_get_target_voltage(float R); diff --git a/User/board/bsp_collect.c b/User/board/bsp_collect.c new file mode 100644 index 0000000..0d14625 --- /dev/null +++ b/User/board/bsp_collect.c @@ -0,0 +1,230 @@ +/* + * @Author: mypx + * @Description: ADS8866采集-3线模式(TIM3中断驱动) + */ +#include "bsp_collect.h" +#include "bsp_misc.h" +#include "et_log.h" +#include "main.h" +#include "spi.h" +#include "tim.h" +#include +#include + +static uint16_t *g_buffer = NULL; +static uint16_t g_buf_size = 0; +static uint16_t g_target_count = 0; // 目标采集数 +static volatile uint16_t g_count = 0; // 已采集数 +static dma_full_cb_t g_complete_cb = NULL; + +// 3线模式: DIN保持高, CONVST控制转换+片选 +#define ADS8866_DIN_HIGH() GPIOB->BSRR = (1u << 15) +#define PB15_AS_GPIO() GPIOB->CRH = (GPIOB->CRH & ~(0xFu << 28)) | (0x3u << 28) + +// 延时n个时钟周期(每个周期≈13.89ns) +static inline void ns_delay(uint32_t cycles) +{ + // 关闭编译器优化,确保NOP不被删除 + __asm volatile("1: SUBS %0, %0, #1\n" // 计数器减1 + " BNE 1b" // 若未到0则循环 + : "=r"(cycles) // 输出操作数 + : "0"(cycles) // 输入操作数 + ); +} + +void delay_100ns(void) +{ + ns_delay(7); +} + +// 单次读取(在中断里调用,要快速) +static inline uint16_t ads8866_read_once(void) +{ + uint16_t rx = 0; + // ADS8866转换时间约3µs, 等待转换完成 + // 72MHz系统时钟, 1个NOP约14ns, 300个NOP约4.2µs + for (volatile int i = 0; i < 6; i++) + delay_100ns(); + + // CONVST回到高电平, 数据就绪, 直接SPI读取 + HAL_SPI_Receive(&ADS8866_SPI, (uint8_t *)&rx, 1, 10); + return rx; +} + +int bsp_light_data_sampling_init(uint16_t *adc_buf, uint16_t length, dma_full_cb_t cb) +{ + g_buffer = adc_buf; + g_buf_size = length; + g_complete_cb = cb; + g_count = 0; + g_target_count = 0; + + // 初始化TIM3(产生CONVST), SPI2(读取数据) + MX_TIM3_Init(); + MX_SPI2_Init(); + __HAL_SPI_ENABLE(&ADS8866_SPI); + + // PB15(DIN)配置为GPIO并保持高电平 + PB15_AS_GPIO(); + ADS8866_DIN_HIGH(); + + ET_INFO("bsp_collect: init done, buf_size=%u", length); + return 0; +} + +// // Shell命令: 启动采集指定数量 +// int cstart(int argc, char **argv) +// { +// if (argc < 2) +// { +// rt_kprintf("Usage: cstart \r\n"); +// return -1; +// } + +// int count = atoi(argv[1]); +// if (count <= 0 || count > g_buf_size) +// { +// rt_kprintf("cstart: invalid count (1~%u)\r\n", g_buf_size); +// return -2; +// } + +// if (!g_buffer) +// { +// rt_kprintf("cstart: buffer not init\r\n"); +// return -3; +// } + +// // 设置目标数量并启动 +// g_count = 0; +// g_target_count = count; +// bsp_system_led_on(); + +// rt_kprintf("cstart: collecting %d samples...\r\n", count); + +// // 启动TIM3 PWM + 中断 +// HAL_TIM_PWM_Start(&COLLECT_TIM, TIM_CHANNEL_3); +// HAL_TIM_Base_Start_IT(&COLLECT_TIM); + +// rt_kprintf("cstart: started (non-blocking)\r\n"); +// return 0; +// } + +// int cprint(int argc, char **argv) +// { +// uint16_t n = 32; +// if (argc >= 2) +// n = (uint16_t)atoi(argv[1]); +// if (!g_buffer || g_count == 0) +// { +// rt_kprintf("cprint: no data\r\n"); +// return -1; +// } +// if (n > g_count) +// n = g_count; +// uint16_t minv = 0xFFFF, maxv = 0; +// uint32_t sum = 0; +// for (uint16_t i = 0; i < g_count; i++) +// { +// uint16_t v = g_buffer[i]; +// if (v < minv) +// minv = v; +// if (v > maxv) +// maxv = v; +// sum += v; +// } +// rt_kprintf("cprint: N=%u min=%u max=%u avg=%lu\r\n", g_count, minv, maxv, sum / g_count); +// rt_kprintf("first %u (dec / hex):\r\n", n); +// for (uint16_t i = 0; i < n; i++) +// { +// if (i % 8 == 0) +// rt_kprintf("\r\n[%04u] ", i); +// rt_kprintf("%5u/0x%04X ", g_buffer[i], g_buffer[i]); +// } +// rt_kprintf("\r\n"); +// return 0; +// } + +// MSH_CMD_EXPORT_ALIAS(cstart, cstart, collect N samples) +// MSH_CMD_EXPORT_ALIAS(cprint, cprint, print data) + +// 启动采集: 设置目标数量, 启动TIM3+中断 +int bsp_light_data_sampling_start(void) +{ + if (!g_buffer || g_buf_size == 0) + { + ET_ERR("bsp_collect: buffer not initialized"); + return -1; + } + + g_count = 0; + g_target_count = g_buf_size; // 采集满缓冲区 + bsp_system_led_on(); + + // 启动TIM3 PWM(产生CONVST) + Update中断 + HAL_TIM_PWM_Start(&COLLECT_TIM, TIM_CHANNEL_3); + HAL_TIM_Base_Start_IT(&COLLECT_TIM); + + //ET_INFO("bsp_collect: start, target=%u", g_target_count); + return 0; +} + +// 停止采集 +int bsp_light_data_sampling_stop(void) +{ + HAL_TIM_Base_Stop_IT(&COLLECT_TIM); + HAL_TIM_PWM_Stop(&COLLECT_TIM, TIM_CHANNEL_3); + bsp_system_led_off(); + + //ET_INFO("bsp_collect: stopped, collected=%u/%u", g_count, g_target_count); + return 0; +} + +uint16_t light_raw_map_u16(uint16_t val) +{ + /* Avoid integer truncation: do multiply before divide using 32-bit intermediate. + * Map 0..65535 -> 0..4095. Use rounding by adding half-divisor. */ + uint32_t tmp = (uint32_t)val * 4095u; + return (uint16_t)(tmp / 65535u + 0.5f); +} + +float light_raw_map_f32(uint16_t val) +{ + return (float)(val / 65535.0f * 4095.0f); +} + +// TIM3中断回调: 每次CONVST触发后采集一个点 +void sampling_tim_elapsed_callback(void) +{ + // 未启动或已完成 + if (g_target_count == 0 || g_count >= g_target_count) + return; + + // 读取一个点 + if (g_buffer && g_count < g_buf_size) + { + /* drive LED pin high at the start of ISR and low at the end + * so each interrupt produces one pulse. This makes the pulse + * frequency equal to the timer update frequency (no 2x toggle + * ambiguity). */ + bsp_system_led_on(); + g_buffer[g_count] = light_raw_map_u16(ads8866_read_once()); + g_count++; + bsp_system_led_off(); + + // 达到目标数量, 停止并回调 + if (g_count >= g_target_count) + { + HAL_TIM_Base_Stop_IT(&COLLECT_TIM); + HAL_TIM_PWM_Stop(&COLLECT_TIM, TIM_CHANNEL_3); + bsp_system_led_off(); + + //ET_INFO("bsp_collect: complete, N=%u", g_count); + + // 调用完成回调 + if (g_complete_cb) + g_complete_cb(); + + g_target_count = 0; // 标记完成 + } + } +} diff --git a/User/board/bsp_collect.h b/User/board/bsp_collect.h new file mode 100644 index 0000000..0bfa1db --- /dev/null +++ b/User/board/bsp_collect.h @@ -0,0 +1,21 @@ +/* + * @Author: mypx + * @Date: 2025-10-14 11:25:04 + * @LastEditTime: 2025-10-14 14:00:13 + * @LastEditors: mypx mypx_coder@163.com + * @Description: + */ +#ifndef __BSP_COLLECT_H__ +#define __BSP_COLLECT_H__ +#include + +typedef void (*dma_full_cb_t)(void); + +int bsp_light_data_sampling_init(uint16_t *adc_buf, uint16_t length, dma_full_cb_t cb); + +int bsp_light_data_sampling_start(void); + +int bsp_light_data_sampling_stop(void); + +void sampling_tim_elapsed_callback(void); +#endif // __BSP_COLLECT_H__ \ No newline at end of file diff --git a/User/board/bsp_hmi.c b/User/board/bsp_hmi.c new file mode 100644 index 0000000..366ff35 --- /dev/null +++ b/User/board/bsp_hmi.c @@ -0,0 +1,85 @@ +/* + * @Author: mypx + * @Date: 2025-10-15 16:24:26 + * @LastEditTime: 2025-10-22 08:44:30 + * @LastEditors: mypx mypx_coder@163.com + * @Description: + */ +#include "bsp_hmi.h" +#include "usart.h" +#include "rtthread.h" +#include "et_log.h" + +struct rt_messagequeue mb_hmi_mq; +static char mq_pool[MB_HMI_RX_QUEUE_SIZE]; + +#if (DEBUG_MB_ENABLE == 1) +#define DBG_MB(...) ET_DBG("[MB] " __VA_ARGS__) +#else +#define DBG_MB(...) +#endif + + +int bsp_mb_hmi_init(void) +{ + MX_USART1_UART_Init(); // used tx + MX_USART2_UART_Init(); // used rx + + rt_err_t result = rt_mq_init(&mb_hmi_mq, "mb_hmi_mq", mq_pool, 1, MB_HMI_RX_QUEUE_SIZE, RT_IPC_FLAG_FIFO); + if (result != RT_EOK) + { + ET_ERR("mb_hmi mq init failed\n"); + return -1; + } + + __HAL_UART_ENABLE_IT(&HMI_COM, UART_IT_RXNE); + + return 0; +} + +int32_t bsp_hmi_uart_read(uint8_t *buf, uint16_t count, int32_t byte_timeout_ms, void *arg) +{ + UNUSED(arg); + uint16_t bytes_read = 0; + uint8_t byte; + rt_tick_t timeout_ticks = rt_tick_from_millisecond(byte_timeout_ms); + DBG_MB("start read:count:%d, timeout:%d\n", count, byte_timeout_ms); + + while (bytes_read < count) + { + rt_err_t result = rt_mq_recv(&mb_hmi_mq, &byte, sizeof(byte), timeout_ticks); + if (result == RT_EOK) + { + DBG_MB("rx: %02X\n", byte); + buf[bytes_read++] = byte; + } + else + { + if (bytes_read > 0) + { + DBG_MB("Modbus read finished %d\n", bytes_read); + return bytes_read; + } + DBG_MB("HMI read timeout, no data received\n"); + return 0; + } + } + DBG_MB("Actually read:%d, count:%d\r\n", bytes_read, count); + + return bytes_read; +} + +int32_t bsp_hmi_uart_write(const uint8_t *buf, uint16_t count, int32_t byte_timeout_ms, void *arg) +{ + UNUSED(arg); + rt_thread_mdelay(2); + if (HAL_UART_Transmit(&HMI_COM, buf, count, byte_timeout_ms) == HAL_OK) + { + ET_DBG("HMI write:%d", count); + return count; + } + else + { + return 0; + } +} \ No newline at end of file diff --git a/User/board/bsp_hmi.h b/User/board/bsp_hmi.h new file mode 100644 index 0000000..7be13b7 --- /dev/null +++ b/User/board/bsp_hmi.h @@ -0,0 +1,21 @@ +/* + * @Author: mypx + * @Date: 2025-10-15 16:24:35 + * @LastEditTime: 2025-10-15 16:52:46 + * @LastEditors: mypx mypx_coder@163.com + * @Description: + */ +#ifndef __BSP_HMI_H__ +#define __BSP_HMI_H__ +#include + +#define MB_HMI_RX_QUEUE_SIZE 128 // Modbus HMI 接收队列大小 +extern struct rt_messagequeue mb_hmi_mq; + +int bsp_mb_hmi_init(void); + +int32_t bsp_hmi_uart_read(uint8_t *buf, uint16_t count, int32_t byte_timeout_ms, void *arg); + +int32_t bsp_hmi_uart_write(const uint8_t *buf, uint16_t count, int32_t byte_timeout_ms, void *arg); + +#endif // __BSP_HMI_H__ diff --git a/User/board/bsp_misc.c b/User/board/bsp_misc.c new file mode 100644 index 0000000..675a880 --- /dev/null +++ b/User/board/bsp_misc.c @@ -0,0 +1,121 @@ +/* + * @Author: mypx + * @Email: mypx_coder@163.com + * @Date: 2025-06-19 12:29:17 + * @LastEditors: mypx mypx_coder@163.com + * @Description: + */ +#include "bsp_misc.h" +#include "ad7793.h" +#include "adc.h" +#include "dma.h" +#include "et_log.h" +#include "gpio.h" +#include "i2c.h" +#include "rtdef.h" +#include "rthw.h" + +#include "usart.h" +#include "tim.h" + +#include +#include + +#define AT24C128_I2C_ADDR 0xA0 + +void bsp_system_led_toggle(void) +{ + HAL_GPIO_TogglePin(PE5_LED1_GPIO_Port, PE5_LED1_Pin); +} + +void bsp_system_led_on(void) +{ + HAL_GPIO_WritePin(PE5_LED1_GPIO_Port, PE5_LED1_Pin, GPIO_PIN_SET); +} + +void bsp_system_led_off(void) +{ + HAL_GPIO_WritePin(PE5_LED1_GPIO_Port, PE5_LED1_Pin, GPIO_PIN_RESET); +} + +void bsp_error_led_on(void) +{ + HAL_GPIO_WritePin(PE6_LED2_GPIO_Port, PE6_LED2_Pin, GPIO_PIN_SET); +} + +void bsp_error_led_off(void) +{ + HAL_GPIO_WritePin(PE6_LED2_GPIO_Port, PE6_LED2_Pin, GPIO_PIN_RESET); +} + +void bsp_error_led_toggle(void) +{ + HAL_GPIO_TogglePin(PE6_LED2_GPIO_Port, PE6_LED2_Pin); +} + +int bsp_i2c_write_bytes(uint16_t dev_addr, uint16_t mem_addr, uint8_t *data, uint16_t len) +{ + HAL_StatusTypeDef res; + + // AT24C128 单页为 64 字节,写入时建议不要跨页,否则需要拆包 + if (len > 64) + return HAL_ERROR; + + res = HAL_I2C_Mem_Write(&hi2c2, dev_addr, mem_addr, I2C_MEMADD_SIZE_16BIT, data, len, HAL_MAX_DELAY); + + HAL_Delay(5); // EEPROM写入周期,典型为5ms + + return res; +} + +int bsp_i2c_read_bytes(uint16_t dev_addr, uint16_t mem_addr, uint8_t *data, uint16_t len) +{ + return HAL_I2C_Mem_Read(&hi2c2, dev_addr, mem_addr, I2C_MEMADD_SIZE_16BIT, data, len, HAL_MAX_DELAY); +} + + +void bsp_uart_print_send(const uint8_t *data, uint16_t len) +{ +#ifdef USING_RTT_AS_CONSOLE +#warning "USING_RTT_AS_CONSOLE defined, use uart1 as hmi interface" + +#else + HAL_UART_Transmit(&huart1, data, len, 1000); +#endif +} + +float bsp_sampling_tim_get_freq(void) +{ + uint32_t pclk1 = HAL_RCC_GetPCLK1Freq(); + uint32_t timer_clk; + + // 获取APB1预分频系数(来自RCC配置寄存器) + uint32_t apb1_prescaler = (RCC->CFGR & RCC_CFGR_PPRE1) >> RCC_CFGR_PPRE1_Pos; + + // 根据APB1预分频计算定时器时钟源 + if (apb1_prescaler == RCC_HCLK_DIV1) + { + // APB1预分频=1,定时器时钟=PCLK1 + timer_clk = pclk1; + } + else + { + // APB1预分频>1,定时器时钟=2×PCLK1 + timer_clk = pclk1 * 2; + } + + // 计算定时器计数频率(经过PSC分频后) + uint32_t counter_freq = timer_clk / (COLLECT_TIM.Init.Prescaler + 1); + + // 计算最终输出频率(周期触发频率 = 计数频率 / (Period + 1)) + // 注意:如果是向上计数模式,完整周期是从0到Period,共Period+1个计数 + return (float)counter_freq / (COLLECT_TIM.Init.Period + 1); +} + +int pm_board_init(void) +{ + MX_GPIO_Init(); + // MX_USART1_UART_Init(); + + return 0; +} diff --git a/User/board/bsp_misc.h b/User/board/bsp_misc.h new file mode 100644 index 0000000..982c39a --- /dev/null +++ b/User/board/bsp_misc.h @@ -0,0 +1,40 @@ +/* + * @Date: 2025-06-19 12:29:23 + * @Author: mypx + * @LastEditors: mypx mypx_coder@163.com + * @LastEditTime: 2025-10-15 16:52:14 + * @FilePath: board_pm.h + * @Description: + * Copyright (c) 2025 by mypx, All Rights Reserved. + */ +#ifndef __BSP_MISC_H__ +#define __BSP_MISC_H__ +#include "adc.h" +#include "main.h" +#include "rtthread.h" +#include "tim.h" +#include "user_config.h" +#include +#include + +int pm_board_init(void); + +void bsp_system_led_toggle(void); + +void bsp_system_led_on(void); +void bsp_system_led_off(void); + +void bsp_error_led_on(void); +void bsp_error_led_off(void); +void bsp_error_led_toggle(void); + +int bsp_i2c_write_bytes(uint16_t dev_addr, uint16_t reg, uint8_t *data, uint16_t size); +int bsp_i2c_read_bytes(uint16_t dev_addr, uint16_t reg, uint8_t *data, uint16_t size); + +void bsp_uart_print_send(const uint8_t *data, uint16_t len); + +void bsp_lcd_cmd_send(const uint8_t *data, uint16_t len); + +float bsp_sampling_tim_get_freq(void); + +#endif // __BOARD_H__ diff --git a/User/board/bsp_motor.c b/User/board/bsp_motor.c new file mode 100644 index 0000000..d1fc1bd --- /dev/null +++ b/User/board/bsp_motor.c @@ -0,0 +1,82 @@ +/* + * @Author: mypx + * @Date: 2025-10-15 16:40:13 + * @LastEditTime: 2025-10-15 16:47:38 + * @LastEditors: mypx mypx_coder@163.com + * @Description: + */ +#include "bsp_motor.h" +#include "et_log.h" +#include "rtthread.h" +#include "usart.h" + +#if (DEBUG_MB_ENABLE == 1) +#define DBG_MB(...) ET_DBG("[MB] " __VA_ARGS__) +#else +#define DBG_MB(...) +#endif + +struct rt_messagequeue servo_mq; +static char mq_pool[SERVO_RX_QUEUE_SIZE]; + + +int bsp_servo_init(void) +{ + MX_USART3_UART_Init(); + + rt_err_t result = rt_mq_init(&servo_mq, "servo_mq", mq_pool, 1, SERVO_RX_QUEUE_SIZE, RT_IPC_FLAG_FIFO); + if (result != RT_EOK) + { + ET_ERR("servo mq init failed\n"); + return -1; + } + + __HAL_UART_ENABLE_IT(&SERVO_COM, UART_IT_RXNE); + return 0; +} + +int32_t bsp_servo_uart_read(uint8_t *buf, uint16_t count, int32_t byte_timeout_ms, void *arg) +{ + UNUSED(arg); + uint16_t bytes_read = 0; + uint8_t byte; + rt_tick_t timeout_ticks = rt_tick_from_millisecond(byte_timeout_ms); + DBG_MB("start read:count:%d, timeout:%d\n", count, byte_timeout_ms); + + while (bytes_read < count) + { + rt_err_t result = rt_mq_recv(&servo_mq, &byte, sizeof(byte), timeout_ticks); + if (result == RT_EOK) + { + DBG_MB("rx: %02X\n", byte); + buf[bytes_read++] = byte; + } + else + { + if (bytes_read > 0) + { + DBG_MB("Modbus read finished %d\n", bytes_read); + return bytes_read; + } + DBG_MB("Servo read timeout, no data received\n"); + return 0; + } + } + DBG_MB("Actually read:%d, count:%d\r\n", bytes_read, count); + + return bytes_read; +} + +int32_t bsp_servo_uart_write(const uint8_t *buf, uint16_t count, int32_t byte_timeout_ms, void *arg) +{ + UNUSED(arg); + rt_thread_mdelay(2); + if (HAL_UART_Transmit(&SERVO_COM, buf, count, byte_timeout_ms) == HAL_OK) + { + return count; + } + else + { + return 0; + } +} diff --git a/User/board/bsp_motor.h b/User/board/bsp_motor.h new file mode 100644 index 0000000..1d6275d --- /dev/null +++ b/User/board/bsp_motor.h @@ -0,0 +1,16 @@ +#ifndef __BSP_MOTOR_H__ +#define __BSP_MOTOR_H__ +#include +#include + + +#define SERVO_RX_QUEUE_SIZE 128 // Modbus RTU 接收队列大小 +extern struct rt_messagequeue servo_mq; + +int bsp_servo_init(void); + +int32_t bsp_servo_uart_read(uint8_t *buf, uint16_t count, int32_t timeout, void *arg); + +int32_t bsp_servo_uart_write(const uint8_t *buf, uint16_t count, int32_t timeout, void *arg); + +#endif // __BSP_MOTOR_H__ diff --git a/User/board/bsp_tec.c b/User/board/bsp_tec.c new file mode 100644 index 0000000..158b625 --- /dev/null +++ b/User/board/bsp_tec.c @@ -0,0 +1,177 @@ +/* + * @Author: mypx + * @Date: 2025-10-15 13:03:38 + * @LastEditTime: 2025-10-17 13:37:16 + * @LastEditors: mypx mypx_coder@163.com + * @Description: + */ +#include "bsp_tec.h" +#include "main.h" +#include "spi.h" +#include "tim.h" +/* + * 当前板子存在的问题: + * PE8-TEC-IN1(left) TIM1_CH1N默认为PE8 + * PA8-TEC-IN2(right) TIM1_CH1默认为PA9,需要映射到PA8 + * 问题: + * 映射只能成对映射,也就是PE8也要做映射,所以一次配置,同时使能两个管脚做不到 + * 解决方法: + * 1. 分别配置PE8和PA8为TIM1_CH1N和TIM1_CH1 + * 2. 分别使能PE8和PA8的TIM1_CH1N和TIM1_CH1 + * stm32cubemx 使能TIM1_CH1N和TIM1_CH1默认的管脚为REMAP后的管脚,感觉是bug + * +*/ + +static void stop_tec_pwm(void) +{ + // 一块关闭,避免左右搞混没关掉 + HAL_TIM_PWM_Stop(&TEC_TIM, TIM_CHANNEL_1); + HAL_TIMEx_PWMN_Stop(&TEC_TIM, TIM_CHANNEL_1); +} + +static void tec_sd_disable(void) +{ + HAL_GPIO_WritePin(GPIOA, TEC_LEFT_SD_Pin | TEC_RIGHT_SD_Pin, GPIO_PIN_RESET); +} + +static void left_tec_sd_enable(void) +{ + HAL_GPIO_WritePin(GPIOA, TEC_LEFT_SD_Pin, GPIO_PIN_SET); +} + +static void right_tec_sd_enable(void) +{ + HAL_GPIO_WritePin(GPIOA, TEC_RIGHT_SD_Pin, GPIO_PIN_SET); +} + +// PE8-TEC-IN1(left) TIM1_CH1N, 需要做full remap +static void left_tec_reconfig_pwm(void) +{ + GPIO_InitTypeDef GPIO_InitStruct = {0}; + /* Stop PWM outputs first to avoid both outputs being active during transition */ + stop_tec_pwm(); + + /* Ensure GPIO clocks */ + __HAL_RCC_GPIOE_CLK_ENABLE(); + + /* Enable TIM1 full remap if you need the remapped mapping (CubeMX generated code might expect this) + Note: remap affects mapping for all TIM1 channels - do this before initializing the GPIOs */ + __HAL_AFIO_REMAP_TIM1_ENABLE(); + + /* Deinit any previous GPIO config on PE8/PA8 to be safe */ + HAL_GPIO_DeInit(GPIOE, GPIO_PIN_8); + HAL_GPIO_DeInit(GPIOA, TEC_RIGHT_IN_Pin); + + /**TIM1 GPIO Configuration + PE8 ------> TIM1_CH1N + */ + GPIO_InitStruct.Pin = GPIO_PIN_8; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; + HAL_GPIO_Init(GPIOE, &GPIO_InitStruct); + + /* + * Hardware note: main output (CH1) and complementary output (CH1N) cannot + * be enabled at the same time on this board. For the 'left' mapping (PE8) + * we only enable the complementary output (CH1N) and ensure CH1 is stopped. + */ + /* Ensure main channel is off, then start complementary output only */ + HAL_TIMEx_PWMN_Start(&TEC_TIM, TIM_CHANNEL_1); +} + +// PA8-TEC-IN2(right) TIM1_CH1,默认CH1,不需要映射 +void right_tec_reconfig_pwm(void) +{ + stop_tec_pwm(); + + /* Disable TIM1 remap so TIM1_CH1 maps to the default (PA8/PA9 depending on device) + Do this before re-initializing the GPIO so HAL init uses the correct port/pin */ + __HAL_AFIO_REMAP_TIM1_DISABLE(); + + /* Deinit any previous GPIO config on PE8/PA8 to be safe */ + HAL_GPIO_DeInit(GPIOE, GPIO_PIN_8); + HAL_GPIO_DeInit(GPIOA, TEC_RIGHT_IN_Pin); + + /* Re-run the post-init which will configure PA8 as AF (HAL_TIM_MspPostInit uses TEC_RIGHT_IN_Pin) */ + HAL_TIM_MspPostInit(&TEC_TIM); + + /* + * For the 'right' mapping (PA8) we only enable the main output (CH1) and + * ensure the complementary output (CH1N) is stopped to avoid hardware conflict. + */ + HAL_TIM_PWM_Start(&TEC_TIM, TIM_CHANNEL_1); +} + +void bsp_fan_start(void) +{ + HAL_GPIO_WritePin(FAN_CONTROL_GPIO_Port, FAN_CONTROL_Pin, GPIO_PIN_SET); +} + +void bsp_fan_stop(void) +{ + HAL_GPIO_WritePin(FAN_CONTROL_GPIO_Port, FAN_CONTROL_Pin, GPIO_PIN_RESET); +} + +void bsp_left_tec_open(void) +{ + tec_sd_disable(); + left_tec_reconfig_pwm(); + left_tec_sd_enable(); +} + +void bsp_right_tec_open(void) +{ + tec_sd_disable(); + right_tec_reconfig_pwm(); + right_tec_sd_enable(); +} + +static void left_tec_adjust_duty_cycle(uint32_t duty_cycle) +{ + __HAL_TIM_SET_COMPARE(&TEC_TIM, TIM_CHANNEL_1, duty_cycle); +} + +static void right_tec_adjust_duty_cycle(uint32_t duty_cycle) +{ + __HAL_TIM_SET_COMPARE(&TEC_TIM, TIM_CHANNEL_1, duty_cycle); +} + +void bsp_tec_cooling_open(void) +{ + bsp_left_tec_open(); +} + +void bsp_tec_heating_open(void) +{ + bsp_right_tec_open(); +} + +// pwm: 0.0 ~ 1.0 +void bsp_tec_cooling_adjust(float pwm) +{ + extern TIM_HandleTypeDef TEC_TIM; + uint32_t max_period = __HAL_TIM_GET_AUTORELOAD(&TEC_TIM); + left_tec_adjust_duty_cycle((uint32_t)(pwm * max_period)); +} + +// pwm: 0.0 ~ 1.0 +void bsp_tec_heating_adjust(float pwm) +{ + extern TIM_HandleTypeDef TEC_TIM; + uint32_t max_period = __HAL_TIM_GET_AUTORELOAD(&TEC_TIM); + right_tec_adjust_duty_cycle((uint32_t)(pwm * max_period)); +} + +void bsp_tec_close(void) +{ + stop_tec_pwm(); + tec_sd_disable(); +} + + +void bsp_tec_init(void) +{ + MX_SPI3_Init(); + MX_TIM1_Init(); +} + diff --git a/User/board/bsp_tec.h b/User/board/bsp_tec.h new file mode 100644 index 0000000..f597555 --- /dev/null +++ b/User/board/bsp_tec.h @@ -0,0 +1,27 @@ +/* + * @Author: mypx + * @Date: 2025-10-15 13:03:28 + * @LastEditTime: 2025-10-15 14:58:18 + * @LastEditors: mypx mypx_coder@163.com + * @Description: + */ +#ifndef __BSP_TEC_H__ +#define __BSP_TEC_H__ + +void bsp_tec_init(void); + +// 这俩接口内部必须做好互斥,不能同时打开 +void bsp_tec_cooling_open(void); +void bsp_tec_heating_open(void); + +void bsp_tec_close(void); +// pwm: 0.0 ~ 1.0 +void bsp_tec_cooling_adjust(float pwm); +// pwm: 0.0 ~ 1.0 +void bsp_tec_heating_adjust(float pwm); + + + +void bsp_fan_start(void); +void bsp_fan_stop(void); +#endif // __BSP_TEC_H__ diff --git a/User/board/bsp_temper_sampling.c b/User/board/bsp_temper_sampling.c new file mode 100644 index 0000000..90aa794 --- /dev/null +++ b/User/board/bsp_temper_sampling.c @@ -0,0 +1,140 @@ +/* + * @Author: mypx + * @Date: 2025-10-15 15:32:36 + * @LastEditTime: 2025-10-16 10:26:19 + * @LastEditors: mypx mypx_coder@163.com + * @Description: + */ +#include "bsp_temper_sampling.h" +#include "et_log.h" +#include "spi.h" + +#if (USING_SOFT_SPI == 1) +soft_spi_t soft_spi = { + .sck_port = GPIOB, + .sck_pin = GPIO_PIN_5, + .mosi_port = GPIOB, + .mosi_pin = GPIO_PIN_6, + .miso_port = GPIOB, + .miso_pin = GPIO_PIN_4, + .cs_port = GPIOB, + .cs_pin = GPIO_PIN_7, + .mode = SOFT_SPI_MODE0, + .bit_order = SOFT_SPI_MSB_FIRST, + .lock = RT_NULL, // 使用 RT_NULL,初始化时会创建 + .delay_us = 1, // 每半个 SPI 时钟周期延时 1 微秒 +}; + +void bsp_ad7793_spi_transfer(uint8_t *tx_buf, uint8_t *rx_buf, uint16_t len) +{ + soft_spi_transfer_buffer(&soft_spi, tx_buf, rx_buf, len); +} + +void bsp_ad7793_spi_write(uint8_t cmd, uint8_t *data, uint16_t len) +{ + soft_spi_write(&soft_spi, &cmd, 1, data, len); +} + +void bsp_ad7793_spi_read(uint8_t cmd, uint8_t *rx_buf, uint16_t len) +{ + soft_spi_read(&soft_spi, &cmd, 1, rx_buf, len); +} + +void bsp_ad7793_gpio_set(uint8_t pin, bool state) +{ + if (pin == soft_spi.cs_pin) + { + HAL_GPIO_WritePin(soft_spi.cs_port, soft_spi.cs_pin, state); + } +} + +bool bsp_ad7793_gpio_get(uint8_t pin) +{ + if (pin == soft_spi.miso_pin) + { + return HAL_GPIO_ReadPin(soft_spi.miso_port, soft_spi.miso_pin) == GPIO_PIN_SET; + } + return false; +} +#else +#define AD7793_CS_LOW() HAL_GPIO_WritePin(SPI3_AD7793_CS_GPIO_Port, SPI3_AD7793_CS_Pin, GPIO_PIN_RESET) +#define AD7793_CS_HIGH() HAL_GPIO_WritePin(SPI3_AD7793_CS_GPIO_Port, SPI3_AD7793_CS_Pin, GPIO_PIN_SET) +void bsp_ad7793_spi_transfer(uint8_t *tx_buf, uint8_t *rx_buf, uint16_t len) +{ + HAL_StatusTypeDef status; + status = HAL_SPI_TransmitReceive(&AD7793_SPI, tx_buf, rx_buf, len, 1000); + if (status != HAL_OK) + { + ET_ERR("SPI transfer error:%d!", status); + } +} + +void bsp_ad7793_spi_write(uint8_t cmd, uint8_t *data, uint16_t len) +{ + uint8_t tx_buffer[256]; + HAL_StatusTypeDef status; + + tx_buffer[0] = cmd; + if (data && len > 0) + { + for (uint16_t i = 0; i < len; i++) + { + tx_buffer[i + 1] = data[i]; + } + } + status = HAL_SPI_Transmit(&AD7793_SPI, tx_buffer, len + 1, 1000); + if (status != HAL_OK) + { + ET_ERR("SPI write error:%d!", status); + } +} + +void bsp_ad7793_spi_read(uint8_t cmd, uint8_t *rx_buf, uint16_t len) +{ + uint8_t tx_buffer[1] = {cmd}; + HAL_StatusTypeDef status; + status = HAL_SPI_Transmit(&AD7793_SPI, tx_buffer, 1, 1000); + if (status != HAL_OK) + { + ET_ERR("SPI write error:%d!", status); + } + status = HAL_SPI_Receive(&AD7793_SPI, rx_buf, len, 1000); + if (status != HAL_OK) + { + ET_ERR("SPI read error:%d!", status); + } +} + +void bsp_ad7793_gpio_set(uint8_t pin, bool state) +{ + if (pin == SPI3_AD7793_CS_Pin) + { + HAL_GPIO_WritePin(SPI3_AD7793_CS_GPIO_Port, SPI3_AD7793_CS_Pin, state); + } +} + +bool bsp_ad7793_gpio_get(uint8_t pin) +{ + if (pin == SPI3_AD7793_MISO_Pin) + { + return HAL_GPIO_ReadPin(SPI3_AD7793_MISO_GPIO_Port, SPI3_AD7793_MISO_Pin) == GPIO_PIN_SET; + } + return false; +} +#endif + +void bsp_ad7793_delay_ms(uint16_t ms) +{ + rt_thread_mdelay(ms); // 使用 RT-Thread 的延时函数 +} + +void bsp_temper_sampling_init(void) +{ +#if (USING_SOFT_SPI == 1) + soft_spi_init(&soft_spi); + soft_spi_set_mode(&soft_spi, SOFT_SPI_MODE3); // 设置 SPI 模式 + soft_spi_set_bit_order(&soft_spi, SOFT_SPI_MSB_FIRST); // 设置位序 + soft_spi_set_delay(&soft_spi, 1); // 设置延时为 1 微秒 + soft_spi_select(&soft_spi); // 选择 SPI 设备 +#endif +} diff --git a/User/board/bsp_temper_sampling.h b/User/board/bsp_temper_sampling.h new file mode 100644 index 0000000..144443e --- /dev/null +++ b/User/board/bsp_temper_sampling.h @@ -0,0 +1,27 @@ +/* + * @Author: mypx + * @Date: 2025-10-15 15:32:55 + * @LastEditTime: 2025-10-15 16:35:56 + * @LastEditors: mypx mypx_coder@163.com + * @Description: + */ +#ifndef __BSP_TEMPER_SAMPLING_H__ +#define __BSP_TEMPER_SAMPLING_H__ +#include +#include + +void bsp_temper_sampling_init(void); + +void bsp_ad7793_spi_transfer(uint8_t *tx_buf, uint8_t *rx_buf, uint16_t len); + +void bsp_ad7793_spi_write(uint8_t cmd, uint8_t *data, uint16_t len); + +void bsp_ad7793_spi_read(uint8_t cmd, uint8_t *rx_buf, uint16_t len); + +void bsp_ad7793_gpio_set(uint8_t pin, bool state); + +bool bsp_ad7793_gpio_get(uint8_t pin); + +void bsp_ad7793_delay_ms(uint16_t ms); + +#endif \ No newline at end of file diff --git a/User/board/pm_board.c b/User/board/pm_board.c deleted file mode 100644 index c07f1e3..0000000 --- a/User/board/pm_board.c +++ /dev/null @@ -1,552 +0,0 @@ -/* - * @Author: mypx - * @Email: mypx_coder@163.com - * @Date: 2025-06-19 12:29:17 - * @LastEditors: mypx mypx_coder@163.com - * @Description: - */ -#include "pm_board.h" -#include "ad7793.h" -#include "adc.h" -#include "dma.h" -#include "et_log.h" -#include "gpio.h" -#include "i2c.h" -#include "rtdef.h" -#include "rthw.h" -#include "rtthread.h" -#include "spi.h" -#include "tim.h" -#include "usart.h" -#include -#include - -#define AT24C128_I2C_ADDR 0xA0 - -#if (DEBUG_MB_ENABLE == 1) -#define DBG_MB(...) ET_DBG("[MB] " __VA_ARGS__) -#else -#define DBG_MB(...) -#endif - -volatile uint64_t timestamp_tim_overflow_count = 0; - -#if (USING_SOFT_SPI == 1) -soft_spi_t soft_spi = { - .sck_port = GPIOB, - .sck_pin = GPIO_PIN_5, - .mosi_port = GPIOB, - .mosi_pin = GPIO_PIN_6, - .miso_port = GPIOB, - .miso_pin = GPIO_PIN_4, - .cs_port = GPIOB, - .cs_pin = GPIO_PIN_7, - .mode = SOFT_SPI_MODE0, - .bit_order = SOFT_SPI_MSB_FIRST, - .lock = RT_NULL, // 使用 RT_NULL,初始化时会创建 - .delay_us = 1, // 每半个 SPI 时钟周期延时 1 微秒 -}; - -void pm_ad7793_spi_transfer(uint8_t *tx_buf, uint8_t *rx_buf, uint16_t len) -{ - soft_spi_transfer_buffer(&soft_spi, tx_buf, rx_buf, len); -} - -void pm_ad7793_spi_write(uint8_t cmd, uint8_t *data, uint16_t len) -{ - soft_spi_write(&soft_spi, &cmd, 1, data, len); -} - -void pm_ad7793_spi_read(uint8_t cmd, uint8_t *rx_buf, uint16_t len) -{ - soft_spi_read(&soft_spi, &cmd, 1, rx_buf, len); -} - -void pm_ad7793_gpio_set(uint8_t pin, bool state) -{ - if (pin == soft_spi.cs_pin) - { - HAL_GPIO_WritePin(soft_spi.cs_port, soft_spi.cs_pin, state); - } -} - -bool pm_ad7793_gpio_get(uint8_t pin) -{ - if (pin == soft_spi.miso_pin) - { - return HAL_GPIO_ReadPin(soft_spi.miso_port, soft_spi.miso_pin) == GPIO_PIN_SET; - } - return false; -} -#else -#define AD7793_CS_LOW() HAL_GPIO_WritePin(AD7793_CS_GPIO_Port, AD7793_CS_Pin, GPIO_PIN_RESET) -#define AD7793_CS_HIGH() HAL_GPIO_WritePin(AD7793_CS_GPIO_Port, AD7793_CS_Pin, GPIO_PIN_SET) -void pm_ad7793_spi_transfer(uint8_t *tx_buf, uint8_t *rx_buf, uint16_t len) -{ - HAL_StatusTypeDef status; - status = HAL_SPI_TransmitReceive(&AD7793_SPI, tx_buf, rx_buf, len, 1000); - if (status != HAL_OK) - { - ET_ERR("SPI transfer error:%d!", status); - } -} - -void pm_ad7793_spi_write(uint8_t cmd, uint8_t *data, uint16_t len) -{ - uint8_t tx_buffer[256]; - HAL_StatusTypeDef status; - - tx_buffer[0] = cmd; - if (data && len > 0) - { - for (uint16_t i = 0; i < len; i++) - { - tx_buffer[i + 1] = data[i]; - } - } - status = HAL_SPI_Transmit(&AD7793_SPI, tx_buffer, len + 1, 1000); - if (status != HAL_OK) - { - ET_ERR("SPI write error:%d!", status); - } -} - -void pm_ad7793_spi_read(uint8_t cmd, uint8_t *rx_buf, uint16_t len) -{ - uint8_t tx_buffer[1] = {cmd}; - HAL_StatusTypeDef status; - status = HAL_SPI_Transmit(&AD7793_SPI, tx_buffer, 1, 1000); - if (status != HAL_OK) - { - ET_ERR("SPI write error:%d!", status); - } - status = HAL_SPI_Receive(&AD7793_SPI, rx_buf, len, 1000); - if (status != HAL_OK) - { - ET_ERR("SPI read error:%d!", status); - } -} - -void pm_ad7793_gpio_set(uint8_t pin, bool state) -{ - if (pin == SPI3_CS_AD7793_Pin) - { - HAL_GPIO_WritePin(SPI3_CS_AD7793_GPIO_Port, SPI3_CS_AD7793_Pin, state); - } -} - -bool pm_ad7793_gpio_get(uint8_t pin) -{ - if (pin == SPI3_MISO_AD7793_Pin) - { - return HAL_GPIO_ReadPin(SPI3_MISO_AD7793_GPIO_Port, SPI3_MISO_AD7793_Pin) == GPIO_PIN_SET; - } - return false; -} -#endif - -void pm_ad7793_delay_ms(uint16_t ms) -{ - rt_thread_mdelay(ms); // 使用 RT-Thread 的延时函数 -} - -ad7793_hw_if_t ad7793_hw_if = { - .spi_transfer = pm_ad7793_spi_transfer, - .spi_write = pm_ad7793_spi_write, - .spi_read = pm_ad7793_spi_read, - .gpio_set = pm_ad7793_gpio_set, - .gpio_get = pm_ad7793_gpio_get, - .delay_ms = pm_ad7793_delay_ms, -}; - -#if (ENABLE_SV630P == 1) -struct rt_messagequeue servo_mq; -static char mq_pool[SERVO_RX_QUEUE_SIZE]; -#endif // USING_SOFT_SPI -void pm_system_led_toggle(void) -{ - HAL_GPIO_TogglePin(PE5_LED1_GPIO_Port, PE5_LED1_Pin); -} - -void pm_system_led_on(void) -{ - HAL_GPIO_WritePin(PE5_LED1_GPIO_Port, PE5_LED1_Pin, GPIO_PIN_SET); -} - -void pm_system_led_off(void) -{ - HAL_GPIO_WritePin(PE5_LED1_GPIO_Port, PE5_LED1_Pin, GPIO_PIN_RESET); -} - -void pm_error_led_on(void) -{ - HAL_GPIO_WritePin(PE6_LED2_GPIO_Port, PE6_LED2_Pin, GPIO_PIN_SET); -} - -void pm_error_led_off(void) -{ - HAL_GPIO_WritePin(PE6_LED2_GPIO_Port, PE6_LED2_Pin, GPIO_PIN_RESET); -} - -void pm_error_led_toggle(void) -{ - HAL_GPIO_TogglePin(PE6_LED2_GPIO_Port, PE6_LED2_Pin); -} - -int pm_i2c_write_bytes(uint16_t dev_addr, uint16_t mem_addr, uint8_t *data, uint16_t len) -{ - HAL_StatusTypeDef res; - - // AT24C128 单页为 64 字节,写入时建议不要跨页,否则需要拆包 - if (len > 64) - return HAL_ERROR; - - res = HAL_I2C_Mem_Write(&hi2c2, dev_addr, mem_addr, I2C_MEMADD_SIZE_16BIT, data, len, HAL_MAX_DELAY); - - HAL_Delay(5); // EEPROM写入周期,典型为5ms - - return res; -} - -int pm_i2c_read_bytes(uint16_t dev_addr, uint16_t mem_addr, uint8_t *data, uint16_t len) -{ - return HAL_I2C_Mem_Read(&hi2c2, dev_addr, mem_addr, I2C_MEMADD_SIZE_16BIT, data, len, HAL_MAX_DELAY); -} - - -void pm_uart_print_send(const uint8_t *data, uint16_t len) -{ -#ifdef USING_RTT_AS_CONSOLE -#warning "USING_RTT_AS_CONSOLE defined, use uart1 as hmi interface" - -#else - HAL_UART_Transmit(&huart1, data, len, 1000); -#endif -} - -void pm_lcd_cmd_send(const uint8_t *data, uint16_t len) -{ - //#ifdef USING_RTT_AS_CONSOLE - HAL_UART_Transmit(&huart1, data, strlen(data), 1000); - // #else - // HAL_UART_Transmit(&huart2, data, strlen(data), 1000); - // #endif -} - -struct rt_messagequeue mb_hmi_mq; -static char mq_pool[MB_HMI_RX_QUEUE_SIZE]; - -int pm_mb_hmi_init(void) -{ - MX_USART1_UART_Init(); // used tx - MX_USART2_UART_Init(); // used rx - - rt_err_t result = rt_mq_init(&mb_hmi_mq, "mb_hmi_mq", mq_pool, 1, MB_HMI_RX_QUEUE_SIZE, RT_IPC_FLAG_FIFO); - if (result != RT_EOK) - { - ET_ERR("mb_hmi mq init failed\n"); - return -1; - } - //__HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE); - - __HAL_UART_ENABLE_IT(&HMI_COM, UART_IT_RXNE); - - return 0; -} - -int32_t pm_hmi_uart_read(uint8_t *buf, uint16_t count, int32_t byte_timeout_ms, void *arg) -{ - UNUSED(arg); - uint16_t bytes_read = 0; - uint8_t byte; - rt_tick_t timeout_ticks = rt_tick_from_millisecond(byte_timeout_ms); - DBG_MB("start read:count:%d, timeout:%d\n", count, byte_timeout_ms); - - while (bytes_read < count) - { - rt_err_t result = rt_mq_recv(&mb_hmi_mq, &byte, sizeof(byte), timeout_ticks); - if (result == RT_EOK) - { - DBG_MB("rx: %02X\n", byte); - buf[bytes_read++] = byte; - } - else - { - if (bytes_read > 0) - { - DBG_MB("Modbus read finished %d\n", bytes_read); - return bytes_read; - } - DBG_MB("HMI read timeout, no data received\n"); - return 0; - } - } - DBG_MB("Actually read:%d, count:%d\r\n", bytes_read, count); - - return bytes_read; -} - -int32_t pm_hmi_uart_write(const uint8_t *buf, uint16_t count, int32_t byte_timeout_ms, void *arg) -{ - UNUSED(arg); - rt_thread_mdelay(2); - //#ifdef USING_RTT_AS_CONSOLE - if (HAL_UART_Transmit(&huart1, buf, count, byte_timeout_ms) == HAL_OK) - // #else - // if (HAL_UART_Transmit(&HMI_COM, buf, count, byte_timeout_ms) == HAL_OK) - // #endif - { - ET_DBG("HMI write:%d", count); - return count; - } - else - { - return 0; - } -} - - -#if (ENABLE_SV630P == 1) -int pm_servo_init(void) -{ - MX_USART3_UART_Init(); - - rt_err_t result = rt_mq_init(&servo_mq, "servo_mq", mq_pool, 1, SERVO_RX_QUEUE_SIZE, RT_IPC_FLAG_FIFO); - if (result != RT_EOK) - { - ET_ERR("servo mq init failed\n"); - return -1; - } - - __HAL_UART_ENABLE_IT(&SERVO_COM, UART_IT_RXNE); - return 0; -} - -int32_t pm_servo_uart_read(uint8_t *buf, uint16_t count, int32_t byte_timeout_ms, void *arg) -{ - UNUSED(arg); - uint16_t bytes_read = 0; - uint8_t byte; - rt_tick_t timeout_ticks = rt_tick_from_millisecond(byte_timeout_ms); - DBG_MB("start read:count:%d, timeout:%d\n", count, byte_timeout_ms); - - while (bytes_read < count) - { - rt_err_t result = rt_mq_recv(&servo_mq, &byte, sizeof(byte), timeout_ticks); - if (result == RT_EOK) - { - DBG_MB("rx: %02X\n", byte); - buf[bytes_read++] = byte; - } - else - { - if (bytes_read > 0) - { - DBG_MB("Modbus read finished %d\n", bytes_read); - return bytes_read; - } - DBG_MB("Servo read timeout, no data received\n"); - return 0; - } - } - DBG_MB("Actually read:%d, count:%d\r\n", bytes_read, count); - - return bytes_read; -} - -int32_t pm_servo_uart_write(const uint8_t *buf, uint16_t count, int32_t byte_timeout_ms, void *arg) -{ - UNUSED(arg); - rt_thread_mdelay(2); - if (HAL_UART_Transmit(&SERVO_COM, buf, count, byte_timeout_ms) == HAL_OK) - { - return count; - } - else - { - return 0; - } -} -#endif // ENABLE_SV630P - -#if (ENABLE_TEC == 1) -void pm_tec_init(void) -{ -#if (USING_SOFT_SPI == 0) - MX_SPI3_Init(); -#endif - MX_TIM1_Init(); -} - -void pm_tec_start(void) -{ - HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1); - HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_1); -} - -void pm_tec_stop(void) -{ - HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_1); - HAL_TIMEx_PWMN_Stop(&htim1, TIM_CHANNEL_1); -} - -void pm_tec_set_duty(float pid_output) -{ - uint32_t period = htim1.Init.Period; - // 限制PID输出范围 - const float MIN_POWER = 2.0f; // 最小有效功率(%) - if (pid_output > 100.0f) - pid_output = 100.0f; - if (pid_output < -100.0f) - pid_output = -100.0f; - - // 应用最小功率限制 - if (pid_output > 0 && pid_output < MIN_POWER) - pid_output = MIN_POWER; - if (pid_output < 0 && pid_output > -MIN_POWER) - pid_output = -MIN_POWER; - - // 计算占空比 - uint32_t compare_value; - if (pid_output >= 0) - { - // 制热:占空比50%~0% - compare_value = period / 2 + (uint32_t)(period * pid_output / 200.0f); - } - else - { - // 制热:占空比50%~0% - compare_value = period / 2 - (uint32_t)(period * fabs(pid_output) / 200.0f); - } - - ET_DBG("PWM COMAPRE: %d", compare_value); - // 设置PWM占空比 - __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, compare_value); - //__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, 2); -} - -void pm_fan_start(void) -{ - HAL_GPIO_WritePin(FAN_CONTROL_GPIO_Port, FAN_CONTROL_Pin, GPIO_PIN_SET); -} - -void pm_fan_stop(void) -{ - HAL_GPIO_WritePin(FAN_CONTROL_GPIO_Port, FAN_CONTROL_Pin, GPIO_PIN_RESET); -} - -#endif // ENABLE_TEC - -void pm_timestamp_tim_init(void) -{ - MX_TIM4_Init(); -} - -void pm_timestamp_start(void) -{ - __HAL_TIM_SET_COUNTER(&TIMESTAMP_TIM, 0); - timestamp_tim_overflow_count = 0; - HAL_TIM_Base_Start_IT(&TIMESTAMP_TIM); -} - -void pm_timestamp_stop(void) -{ - HAL_TIM_Base_Stop_IT(&TIMESTAMP_TIM); -} - -uint64_t pm_get_timestamp_us(void) -{ - uint16_t current_cnt = __HAL_TIM_GET_COUNTER(&TIMESTAMP_TIM); - return (uint64_t)timestamp_tim_overflow_count * 65536 + current_cnt; -} - -void pm_adc_init(void) -{ - MX_DMA_Init(); - MX_ADC1_Init(); -} - -uint32_t pm_adc_get_value(void) -{ - if (HAL_ADC_PollForConversion(&LIGHT_ADC, 10) != HAL_OK) - { - ET_ERR("ADC read should not wait!"); - pm_error_led_on(); - return 0; - } - return HAL_ADC_GetValue(&LIGHT_ADC); -} - -void pm_sampling_tim_init(void) -{ - MX_TIM3_Init(); -} - -void pm_sampling_tim_start(void) -{ - HAL_TIM_Base_Start_IT(&SAMPLING_TIM); -} - -void pm_sampling_tim_stop(void) -{ - HAL_TIM_Base_Stop_IT(&SAMPLING_TIM); -} - -void pm_sampling_adc_start(uint16_t *buffer, uint32_t length) -{ - if (HAL_ADC_Start_DMA(&LIGHT_ADC, (uint32_t *)buffer, length) != HAL_OK) - { - ET_ERR("ADC start DMA error!"); - pm_error_led_on(); - } - //HAL_ADC_Start(&LIGHT_ADC); -} - -void pm_sampling_adc_stop(void) -{ - //HAL_ADC_Stop(&hadc1); - HAL_ADC_Stop_DMA(&LIGHT_ADC); -} - -float pm_sampling_tim_get_freq(void) -{ - uint32_t pclk1 = HAL_RCC_GetPCLK1Freq(); - uint32_t timer_clk; - - // 获取APB1预分频系数(来自RCC配置寄存器) - uint32_t apb1_prescaler = (RCC->CFGR & RCC_CFGR_PPRE1) >> RCC_CFGR_PPRE1_Pos; - - // 根据APB1预分频计算定时器时钟源 - if (apb1_prescaler == RCC_HCLK_DIV1) - { - // APB1预分频=1,定时器时钟=PCLK1 - timer_clk = pclk1; - } - else - { - // APB1预分频>1,定时器时钟=2×PCLK1 - timer_clk = pclk1 * 2; - } - - // 计算定时器计数频率(经过PSC分频后) - uint32_t counter_freq = timer_clk / (SAMPLING_TIM.Init.Prescaler + 1); - - // 计算最终输出频率(周期触发频率 = 计数频率 / (Period + 1)) - // 注意:如果是向上计数模式,完整周期是从0到Period,共Period+1个计数 - return (float)counter_freq / (SAMPLING_TIM.Init.Period + 1); -} - -int pm_board_init(void) -{ - MX_GPIO_Init(); - // MX_USART1_UART_Init(); -#if (USING_SOFT_SPI == 1) - soft_spi_init(&soft_spi); - soft_spi_set_mode(&soft_spi, SOFT_SPI_MODE3); // 设置 SPI 模式 - soft_spi_set_bit_order(&soft_spi, SOFT_SPI_MSB_FIRST); // 设置位序 - soft_spi_set_delay(&soft_spi, 1); // 设置延时为 1 微秒 - soft_spi_select(&soft_spi); // 选择 SPI 设备 -#endif - - return 0; -} diff --git a/User/board/pm_board.h b/User/board/pm_board.h deleted file mode 100644 index aec124e..0000000 --- a/User/board/pm_board.h +++ /dev/null @@ -1,109 +0,0 @@ -/* - * @Date: 2025-06-19 12:29:23 - * @Author: mypx - * @LastEditors: mypx mypx_coder@163.com - * @LastEditTime: 2025-08-25 17:06:01 - * @FilePath: board_pm.h - * @Description: - * Copyright (c) 2025 by mypx, All Rights Reserved. - */ -/*** - * @Author: mypx - * @Email: mypx_coder@163.com - * @Date: 2025-06-19 12:29:23 - * @LastEditors: mypx mypx_coder@163.com - * @Description: - */ -#ifndef __PM_BOARD_H__ -#define __PM_BOARD_H__ -#include "adc.h" -#include "main.h" -#include "rtthread.h" -#include "tim.h" -#include "user_config.h" -#include -#include - -extern volatile uint64_t timestamp_tim_overflow_count; - -typedef enum -{ - TEC_COOLING = 0, - TEC_HEATING = 1 -} TEC_Direction_TypeDef; - -int pm_board_init(void); - -void pm_system_led_toggle(void); - -void pm_system_led_on(void); -void pm_system_led_off(void); - -void pm_error_led_on(void); -void pm_error_led_off(void); -void pm_error_led_toggle(void); - -int pm_i2c_write_bytes(uint16_t dev_addr, uint16_t reg, uint8_t *data, uint16_t size); -int pm_i2c_read_bytes(uint16_t dev_addr, uint16_t reg, uint8_t *data, uint16_t size); - -void pm_ad7793_spi_transfer(uint8_t *tx_buf, uint8_t *rx_buf, uint16_t len); - -void pm_uart_print_send(const uint8_t *data, uint16_t len); - -void pm_lcd_cmd_send(const uint8_t *data, uint16_t len); - -#define MB_HMI_RX_QUEUE_SIZE 128 // Modbus HMI 接收队列大小 -extern struct rt_messagequeue mb_hmi_mq; - -int pm_mb_hmi_init(void); - -int32_t pm_hmi_uart_read(uint8_t *buf, uint16_t count, int32_t byte_timeout_ms, void *arg); - -int32_t pm_hmi_uart_write(const uint8_t *buf, uint16_t count, int32_t byte_timeout_ms, void *arg); - -#if (ENABLE_SV630P == 1) -#define SERVO_RX_QUEUE_SIZE 128 // Modbus RTU 接收队列大小 -extern struct rt_messagequeue servo_mq; -int pm_servo_init(void); - -int32_t pm_servo_uart_read(uint8_t *buf, uint16_t count, int32_t timeout, void *arg); - -int32_t pm_servo_uart_write(const uint8_t *buf, uint16_t count, int32_t timeout, void *arg); -#endif // ENABLE_SV630P - -#if (ENABLE_TEC == 1) -void pm_tec_init(void); -void pm_tec_start(void); -void pm_tec_stop(void); -void pm_tec_set_duty(float pid_output); - -void pm_fan_start(void); - -void pm_fan_stop(void); -#endif - -void pm_timestamp_tim_init(void); - -void pm_timestamp_start(void); - -void pm_timestamp_stop(void); - -uint64_t pm_get_timestamp_us(void); - -void pm_adc_init(void); - -void pm_sampling_adc_start(uint16_t *buffer, uint32_t length); - -void pm_sampling_adc_stop(void); - -uint32_t pm_adc_get_value(void); - -void pm_sampling_tim_init(void); - -void pm_sampling_tim_start(void); - -void pm_sampling_tim_stop(void); - -float pm_sampling_tim_get_freq(void); - -#endif // __BOARD_H__ diff --git a/User/driver/ad779x/README.md b/User/driver/ad779x/README.md index 2e0c2b7..aa1f549 100644 --- a/User/driver/ad779x/README.md +++ b/User/driver/ad779x/README.md @@ -55,6 +55,63 @@ AD7792则以更低成本覆盖中精度需求场景。 --- + + +## 推荐初始化流程(AD7793) + +1. 配置 `ad7793_hw_if_t` 硬件接口结构体,填充 SPI/GPIO/延时等函数指针。 +2. 定义 `ad7793_config_t` 配置结构体,指定参考源、增益、通道、速率、缓冲等参数。 +3. 调用 `ad7793_init(&dev, &hw_if, cs_pin, &cfg)` 完成初始化。 +4. 采集数据前建议调用 `ad7793_wait_ready` 等待数据就绪。 +5. 采集数据用 `ad7793_read_data`,转换电压用 `ad7793_convert_to_voltage`。 +6. 如需切换通道/增益/参考源,建议先 idle,再切换参数,最后恢复 continuous。 + +## 常见故障排查 + +- STATUS=0x48/0xC8:多为参考源配置与硬件不符、增益/缓冲冲突、IEXC未配置等。 +- 读数全0或极大:检查参考电压、SPI连线、通道/增益配置。 +- 写寄存器失败:检查 SPI 速率、CS 时序、硬件接口实现。 +- 温度跳变/毛刺:建议应用层做温度跳变/低码滤波。 +- 采样速率异常:确认速率配置与主时钟、SPI速率匹配。 + +## IEXC(激励电流)配置注意事项 + +- 仅当硬件实际将 IOUT1/IOUT2 接到 RTD 或传感器回路时才需配置 IEXC。 +- 若 IOUT1/IOUT2 悬空(未连接),请勿使能 IEXC,否则可能导致不可预期行为或错误状态(如 STATUS=0x48)。 +- IEXC 配置必须与硬件连接方式一致。若用外部电流源或定值电阻,IEXC 应保持关闭。 + +## 缓冲/增益策略 + +- 关闭缓冲(BUF=0)时,增益不得大于2(G<=2),驱动已强制限制。 +- 开启缓冲(BUF=1)可用高增益,但输入偏置电流和功耗增加。 + +## 寄存器dump与诊断 + +- 可用 `ad7793_dump_registers` 或 `ad7793_dump_registers_mode` 打印所有寄存器值,便于调试。 +- 检测到持续错误(STATUS.ERR)时建议dump寄存器,辅助定位参考、缓冲、增益、IEXC等配置问题。 + +## API典型用法与边界说明 + +- 所有API均检查设备初始化和参数有效性,未初始化或参数非法均返回false。 +- 具体API用法和边界条件详见头文件注释。 + +## Buffer/Gain Policy + +- When buffer is disabled (BUF=0), gain must not exceed 2 (G<=2). The driver enforces this restriction and will return false if you attempt to set G>2 with buffer off. +- Enabling the buffer (BUF=1) allows higher gain settings, but increases input bias current and power consumption. + +## Register Dump and Diagnostics + +- Use `ad7793_dump_registers` or `ad7793_dump_registers_mode` to print all register values for debugging. +- When persistent error (STATUS.ERR) is detected, perform a register dump to help diagnose the cause (reference, buffer, gain, IEXC, etc.). + +## Typical API Usage and Boundary Notes + +- All API functions check for device initialization and parameter validity; invalid parameters or uninitialized device will return false. +- See header file comments for typical usage and boundary conditions for each API. + +--- + ## 通信寄存器用法 通信寄存器在AD7793中起到控制数据传输方向和指定目标寄存器的作用。它是SPI通信接口的核心控制寄存器,用于告诉AD7793后续的操作是读还是写,以及操作的目标寄存器是哪一个。 @@ -98,4 +155,60 @@ bool ad7793_write_reg(uint8_t reg, uint8_t *data, uint16_t len) 2. **连续操作**:在连续操作同一个寄存器时,不需要每次都重新设置通信寄存器,除非操作类型或目标寄存器发生变化。 3. **数据寄存器的特殊处理**:数据寄存器(REG_DATA)在读模式下有特殊的连续读功能,可以通过设置`CREAD`位来启用。 -理解通信寄存器的工作原理对于正确操作AD7793至关重要,它是实现与器件通信的基础。 \ No newline at end of file +理解通信寄存器的工作原理对于正确操作AD7793至关重要,它是实现与器件通信的基础。 + +--- + +# AD7793/AD7792 应用配置与调试注意事项 + +## 推荐配置(PT100/RTD 测温典型拓扑) + +```c +static const ad7793_config_t g_ad7793_config = { + .use_internal_ref = false, // 使用外部参考(如2.5V),REFIN+已实测2.5V + .external_ref = 2.500f, + // 传感器差分约 0.043V,需保证 < Vref / Gain + // 选择 GAIN=4 -> 满量程 2.5/4=0.625V,安全覆盖 43mV 输入 + .init_gain = AD7793_GAIN_4, + .init_channel = AD7793_CHANNEL_1, // AIN1(+) - AIN1(-) + .init_rate = AD7793_RATE_8_33HZ, + .unipolar = true, // 只测正向信号 + .buffered = true, // 启用缓冲 + .calibrate_system_zero = false // 禁用 system zero 校准,防止 OFFSET 被污染 +}; +``` + +## 配置与调试注意事项 + +1. **参考电压必须与硬件一致**: + - 若硬件 REFIN+ 接外部参考(如2.5V),`use_internal_ref` 必须为 `false`,`external_ref` 填实际电压。 + - 若用内部参考(1.17V),需保证 REFIN+/- 悬空且 `use_internal_ref=true`。 + +2. **增益选择**: + - 满量程 = 参考电压 / 增益。输入信号最大值必须小于满量程。 + - 输入信号远小于满量程时可适当提高增益(如 GAIN=8/16),但不能超量程。 + +3. **校准操作**: + - 禁用 system zero 校准(`calibrate_system_zero=false`),防止在参考/输入异常时 OFFSET 被写坏。 + - 若需校准,必须保证参考和输入都正常且在允许范围内。 + +4. **错误状态与保护**: + - STATUS.ERR(bit6=1)表示参考/输入异常,采样数据无效。 + - 采样线程应对 ERR/低码做过滤,避免异常温度。 + - OFFSET/FULLSCALE 寄存器应在每次初始化和异常时 dump 检查。 + +5. **常见故障排查**: + - STATUS=0x48 持续:多为参考配置与硬件不符或输入超量程。 + - OFFSET=0x800000 为正常中点,极大/极小为校准异常。 + - 采样码值极低或全0,多为参考/输入/校准异常。 + +6. **硬件测量建议**: + - 用万用表测 REFIN+ 对地、AIN1+/AIN1- 差分,确认与配置一致。 + +7. **调试建议**: + - 先用低增益(如 GAIN=2/4)确保不超量程,采样正常后再逐步提高增益。 + - 采样线程建议加低码/ERR保护,防止异常数据影响温度计算。 + +--- + +如需更高分辨率或特殊应用,请根据实际输入信号幅度和参考电压合理调整增益与参考配置。 \ No newline at end of file diff --git a/User/driver/ad779x/ad7793.c b/User/driver/ad779x/ad7793.c index 631adca..ab52b7b 100644 --- a/User/driver/ad779x/ad7793.c +++ b/User/driver/ad779x/ad7793.c @@ -7,17 +7,20 @@ */ #include "ad7793.h" #include -#include +#include #ifdef DEBUG #include -#define DEBUG_PRINTF(fmt, ...) \ - do { \ - rt_kprintf("[AD7793] " fmt, ##__VA_ARGS__); \ +#define DEBUG_PRINTF(...) \ + do \ + { \ + rt_kprintf("[AD7793] "); \ + rt_kprintf(__VA_ARGS__); \ } while (0) #else -#define DEBUG_PRINTF(fmt, ...) \ - do { \ +#define DEBUG_PRINTF(...) \ + do \ + { \ } while (0) #endif /** @@ -56,6 +59,9 @@ static bool ad7793_spi_transfer(ad7793_dev_t *dev, uint8_t cmd, uint8_t *tx_buf, return true; } +/* Forward declaration for diagnostic dump (used early) */ +void ad7793_dump_registers(ad7793_dev_t *dev); + /** * @brief Write communication register. * @param dev Pointer to ad7793_dev_t instance. @@ -113,7 +119,28 @@ bool ad7793_write_reg(ad7793_dev_t *dev, uint8_t reg, uint32_t data, uint16_t le //ad7793_spi_transfer(dev, cmd, data, NULL, len); dev->hw_if->gpio_set(dev->cs_pin, true); - return true; + /* Verify write by reading back the register up to a few retries */ + for (int attempt = 0; attempt < 3; attempt++) + { + uint32_t read_back = 0; + dev->hw_if->delay_ms(2); + if (!ad7793_read_reg(dev, reg, &read_back, len)) + { + DEBUG_PRINTF("Readback failed for reg 0x%02X on attempt %d\n", reg, attempt); + continue; + } + /* mask read_back to len bytes */ + uint32_t mask = (len == 3) ? 0xFFFFFFu : ((len == 2) ? 0xFFFFu : 0xFFu); + if ((read_back & mask) == (data & mask)) + { + return true; /* success */ + } + DEBUG_PRINTF("Write verify mismatch reg 0x%02X: wrote 0x%0*X read 0x%0*X (attempt %d)\n", reg, len * 2, + data & mask, len * 2, read_back & mask, attempt + 1); + } + + DEBUG_PRINTF("Write to reg 0x%02X failed after retries\n", reg); + return false; } /** @@ -173,7 +200,8 @@ bool ad7793_reset(ad7793_dev_t *dev) dev->hw_if->gpio_set(dev->cs_pin, false); uint8_t reset_seq[4] = {0xFF, 0xFF, 0xFF, 0xFF}; - dev->hw_if->spi_transfer(reset_seq, NULL, 4); + uint8_t tmp[4]; + dev->hw_if->spi_transfer(reset_seq, tmp, 4); dev->hw_if->gpio_set(dev->cs_pin, true); dev->hw_if->delay_ms(1); /* Wait for reset to complete */ @@ -245,6 +273,14 @@ bool ad7793_set_gain(ad7793_dev_t *dev, ad7793_gain_t gain) uint32_t config_reg = 0; ad7793_read_reg(dev, REG_CONFIG, &config_reg, 2); + // 缓冲/增益策略规范化:BUF=0且G>2时禁止配置 + bool buf_enabled = (config_reg & CONFIG_BUF) ? true : false; + if (!buf_enabled && gain > 2) + { + DEBUG_PRINTF("[ERR] Attempt to set gain >2 while buffer disabled!\n"); + return false; + } + /* Clear gain bits (G2/G1/G0) */ config_reg &= ~(CONFIG_G2 | CONFIG_G1 | CONFIG_G0); @@ -374,8 +410,9 @@ bool ad7793_set_reference(ad7793_dev_t *dev, bool use_internal, float external_r } else { - dev->external_ref = external_ref; - config_reg &= ~CONFIG_REFSEL; + dev->external_ref = external_ref; + dev->use_internal_ref = false; /* reflect external reference selection */ + config_reg &= ~CONFIG_REFSEL; } DEBUG_PRINTF("[config-w]set reference: 0x%04X\n", config_reg); return ad7793_write_reg(dev, REG_CONFIG, config_reg, 2); @@ -398,11 +435,15 @@ bool ad7793_wait_ready(ad7793_dev_t *dev, uint16_t timeout_ms) while (timeout < timeout_ms) { ad7793_read_reg(dev, REG_STATUS, &status, 1); - + dev->last_status = status; if (status & 0x40) // check if the device is in error state { - DEBUG_PRINTF("Device in error state, status: 0x%02X\n", status); - return false; // device error + dev->err_count++; + if ((dev->err_count % 128u) == 1u) /* 抽样打印,避免刷屏 */ + { + DEBUG_PRINTF("Device in error state (status=0x%02X) - continue polling\n", status); + ad7793_dump_registers(dev); + } } // check RDY bit(bit7)is zero or not if ((status & 0x80) == 0) @@ -418,6 +459,45 @@ bool ad7793_wait_ready(ad7793_dev_t *dev, uint16_t timeout_ms) return false; // timeout } +/* Diagnostic helper: dump key registers */ +void ad7793_dump_registers(ad7793_dev_t *dev) +{ + ad7793_dump_registers_mode(dev, 1); +} + +// mode: 0=简略, 1=全量 +typedef enum +{ + AD7793_DUMP_SIMPLE = 0, + AD7793_DUMP_FULL = 1 +} ad7793_dump_mode_t; +void ad7793_dump_registers_mode(ad7793_dev_t *dev, int full) +{ + if (!dev || !dev->hw_if) + return; + uint32_t reg = 0; + ad7793_read_reg(dev, REG_STATUS, ®, 1); + DEBUG_PRINTF("DUMP STATUS: 0x%02X\n", (unsigned)reg); + ad7793_read_reg(dev, REG_MODE, ®, 2); + DEBUG_PRINTF("DUMP MODE: 0x%04X\n", (unsigned)reg); + ad7793_read_reg(dev, REG_CONFIG, ®, 2); + DEBUG_PRINTF("DUMP CONFIG: 0x%04X\n", (unsigned)reg); + if (full) + { + ad7793_read_reg(dev, REG_IO, ®, 1); + DEBUG_PRINTF("DUMP IO: 0x%02X\n", (unsigned)reg); + ad7793_read_reg(dev, REG_ID, ®, 1); + DEBUG_PRINTF("DUMP ID: 0x%02X\n", (unsigned)reg); + ad7793_read_reg(dev, REG_OFFSET, ®, 3); + DEBUG_PRINTF("DUMP OFFSET: 0x%06X\n", (unsigned)reg); + ad7793_read_reg(dev, REG_FULLSCALE, ®, 3); + DEBUG_PRINTF("DUMP FULLSC: 0x%06X\n", (unsigned)reg); + } + // 关键信息摘要 + DEBUG_PRINTF("SUMMARY: mode=%d gain=%d ch=%d ref=%s buf=%d uni=%d\n", dev->cur_mode, dev->cur_gain, + dev->cur_channel, dev->use_internal_ref ? "int" : "ext", dev->buffered, dev->unipolar_mode); +} + /** * @brief Read the conversion data from the device. * @param dev Pointer to ad7793_dev_t instance. @@ -501,7 +581,10 @@ float ad7793_convert_to_voltage(ad7793_dev_t *dev, uint32_t adc_code) if (!(resolution_bits == 16 || resolution_bits == 24)) return 0.0f; // Invalid resolution if (!buffer_enabled && gain > 2) - return 0.0f; // According to datasheet, buffer must be enabled when gain > 2 + { + DEBUG_PRINTF("Warning: buffer disabled while gain > 2 — result may be invalid\n"); + /* Do not outright fail here; allow conversion but warn the caller. */ + } // Check that the ADC code is within valid range uint32_t max_code = (resolution_bits == 24) ? 0xFFFFFFu : 0xFFFFu; @@ -580,7 +663,10 @@ uint32_t ad7793_convert_voltage_to_code(ad7793_dev_t *dev, float voltage) if (!(resolution_bits == 16 || resolution_bits == 24)) return 0; // Invalid resolution if (!buffer_enabled && gain > 2) - return 0; // According to datasheet, buffer must be enabled when gain > 2 + { + DEBUG_PRINTF("Warning: buffer disabled while gain > 2 — code may be invalid\n"); + /* Allow calculation to proceed but warn */ + } // Calculate maximum ADC code value uint32_t max_code = (resolution_bits == 24) ? 0xFFFFFFu : 0xFFFFu; @@ -651,7 +737,12 @@ bool ad7793_calibrate_internal_full(ad7793_dev_t *dev) { AD7793_CHECK_INITIALIZED(dev); ad7793_set_mode(dev, AD7793_MODE_INTERNAL_FULL); - dev->hw_if->delay_ms(10); /* Wait for calibration to complete */ + /* Wait until RDY clears (calibration completed) or timeout */ + if (!ad7793_wait_ready(dev, 1000)) + { + DEBUG_PRINTF("Internal full-scale calibration timeout\n"); + return false; + } return ad7793_set_mode(dev, AD7793_MODE_CONTINUOUS); } @@ -666,7 +757,11 @@ bool ad7793_calibrate_system_zero(ad7793_dev_t *dev) { AD7793_CHECK_INITIALIZED(dev); ad7793_set_mode(dev, AD7793_MODE_SYSTEM_ZERO); - dev->hw_if->delay_ms(10); /* Wait for calibration to complete */ + if (!ad7793_wait_ready(dev, 1000)) + { + DEBUG_PRINTF("System zero calibration timeout\n"); + return false; + } return ad7793_set_mode(dev, AD7793_MODE_CONTINUOUS); } @@ -681,7 +776,11 @@ bool ad7793_calibrate_system_full(ad7793_dev_t *dev) { AD7793_CHECK_INITIALIZED(dev); ad7793_set_mode(dev, AD7793_MODE_SYSTEM_FULL); - dev->hw_if->delay_ms(10); /* Wait for calibration to complete */ + if (!ad7793_wait_ready(dev, 1000)) + { + DEBUG_PRINTF("System full calibration timeout\n"); + return false; + } return ad7793_set_mode(dev, AD7793_MODE_CONTINUOUS); } @@ -697,36 +796,27 @@ bool ad7793_calibrate_system_full(ad7793_dev_t *dev) bool ad7793_config_iexc(ad7793_dev_t *dev, uint16_t current, uint8_t dir) { AD7793_CHECK_INITIALIZED(dev); - uint32_t io_reg = 0; - - /* Set current value */ - if (current == 10) + /* 根据数据手册:IO 寄存器位: [3:2]=IEXCDIR1:0, [1:0]=IEXCEN1:0 + IEXCEN 00=关, 01=10uA, 10=210uA, 11=1mA (常见映射, 若芯片版本不同需核对手册) */ + uint8_t en_bits; + switch (current) { - io_reg |= 0x01; + case 10: + en_bits = 0x01; + break; + case 210: + en_bits = 0x02; + break; + case 1000: + en_bits = 0x03; + break; + default: + return false; /* unsupported */ } - else if (current == 210) - { - io_reg |= 0x02; - } - else if (current == 1000) - { - io_reg |= 0x03; - } - else - { - return false; - } - - /* Set current direction */ - if (dir) - { - io_reg |= (0x03 << 2); - } - - /* Enable current source */ - io_reg |= (0x03 << 0); - - return ad7793_write_reg(dev, REG_IO, io_reg, 1); + uint8_t dir_bits = (dir & 0x03) << 2; /* 方向/复用: 00=IOUT1->AIN1+, 01=IOUT1&2? 需依据原理图调整 */ + uint8_t io_val = (uint8_t)(dir_bits | en_bits); + DEBUG_PRINTF("[io-w] set IEXC current=%u uA dir=0x%X val=0x%02X\n", (unsigned)current, (unsigned)dir, io_val); + return ad7793_write_reg(dev, REG_IO, io_val, 1); } /** @@ -784,6 +874,14 @@ bool ad7793_set_buffered(ad7793_dev_t *dev, bool enable) // Read current configuration register value ad7793_read_reg(dev, REG_CONFIG, &config_reg, 2); + // 缓冲/增益策略规范化:若当前增益>2且要关闭缓冲,禁止 + uint8_t gain = dev->cur_gain; + if (!enable && gain > 2) + { + DEBUG_PRINTF("[ERR] Attempt to disable buffer while gain >2!\n"); + return false; + } + // Update BUF bit (bit 7 of the configuration register) if (enable) { @@ -813,71 +911,110 @@ bool ad7793_set_buffered(ad7793_dev_t *dev, bool enable) * It resets the device, waits for the reset to complete, and then reads the ID register to confirm the device type. * Finally, it initializes the device with default configuration settings. */ -bool ad7793_init(ad7793_dev_t *dev, ad7793_hw_if_t *hw_if, uint8_t cs_pin) +bool ad7793_init(ad7793_dev_t *dev, ad7793_hw_if_t *hw_if, uint8_t cs_pin, const ad7793_config_t *cfg) { - uint32_t mode_reg = 0; - uint32_t config_reg = 0; - if (hw_if == NULL) + if (!dev || !hw_if) { - DEBUG_PRINTF("hw_if is null\n"); + DEBUG_PRINTF("NULL param in init\n"); return false; } - /* Save hardware interface and chip select info */ + dev->hw_if = hw_if; dev->cs_pin = cs_pin; - dev->is_ad7793 = true; /* Default is AD7793, can be confirmed by ID register */ dev->is_initialized = true; + dev->is_ad7793 = true; /* assume, verify after reset */ + dev->err_count = dev->err_recoveries = dev->low_code_drops = 0; + dev->last_status = 0; - /* Reset device */ + /* Pick configuration (simple & predictable) */ + ad7793_config_t local_cfg = cfg ? *cfg : AD7793_DEFAULT_CONFIG; + + /* Reset & small settle */ ad7793_reset(dev); + dev->hw_if->delay_ms(2); - /* Wait for reset to complete */ - dev->hw_if->delay_ms(1); - - /* Read ID register to confirm device type */ + /* Read ID */ uint32_t id = 0; ad7793_read_reg(dev, REG_ID, &id, 1); - DEBUG_PRINTF("ID: 0x%02X\n", id); - dev->is_ad7793 = ((id & 0x0F) == 0x0B); /* AD7793 ID read out is 0x4B */ + dev->is_ad7793 = ((id & 0x0F) == 0x0B); + DEBUG_PRINTF("ID: 0x%02X (%s)\n", id, dev->is_ad7793 ? "AD7793" : "Unknown"); - /* Initialize default configuration */ - ad7793_set_mode(dev, AD7793_MODE_CONTINUOUS); - ad7793_wait_ready(dev, 1000); - ad7793_read_reg(dev, REG_MODE, &mode_reg, 2); - DEBUG_PRINTF("[mode-r]: 0x%04X\n", mode_reg); + /* Put into continuous mode first */ + if (!ad7793_set_mode(dev, AD7793_MODE_CONTINUOUS)) + return false; + /* Apply reference before gain (gain affects allowed input span vs ref) */ + if (!ad7793_set_reference(dev, local_cfg.use_internal_ref, local_cfg.external_ref)) + return false; + if (!ad7793_set_gain(dev, local_cfg.gain)) + return false; + if (!ad7793_set_channel(dev, local_cfg.channel)) + return false; + if (!ad7793_set_rate(dev, local_cfg.rate)) + return false; + if (!ad7793_set_unipolar(dev, local_cfg.unipolar_mode)) + return false; + if (!ad7793_set_buffered(dev, local_cfg.buffered)) + return false; - ad7793_set_gain(dev, AD7793_GAIN_1); - ad7793_wait_ready(dev, 1000); - ad7793_read_reg(dev, REG_CONFIG, &config_reg, 2); - DEBUG_PRINTF("[config-r]after gain config: 0x%04X\n", config_reg); + /* Optional calibration */ + if (local_cfg.calibrate_system_zero) + { + if (!ad7793_calibrate_system_zero(dev)) + DEBUG_PRINTF("System zero calibration skipped/failed\n"); + } - ad7793_set_channel(dev, AD7793_CHANNEL_1); - ad7793_wait_ready(dev, 1000); - ad7793_read_reg(dev, REG_CONFIG, &config_reg, 2); - DEBUG_PRINTF("[config-r]after channel config: 0x%04X\n", config_reg); - - ad7793_set_rate(dev, AD7793_RATE_8_33HZ); - ad7793_wait_ready(dev, 1000); - ad7793_read_reg(dev, REG_MODE, &mode_reg, 2); - DEBUG_PRINTF("[mode-r]after rate mode: 0x%04X\n", mode_reg); - - ad7793_set_reference(dev, true, 2.5); /* Use internal reference */ - ad7793_wait_ready(dev, 1000); - ad7793_read_reg(dev, REG_CONFIG, &config_reg, 2); - DEBUG_PRINTF("[config-r]after reference config: 0x%04X\n", config_reg); - - ad7793_set_unipolar(dev, true); /* Default to bipolar mode */ - ad7793_wait_ready(dev, 1000); - ad7793_read_reg(dev, REG_CONFIG, &config_reg, 2); - DEBUG_PRINTF("[config-r]after polar config: 0x%04X\n", config_reg); - - ad7793_set_buffered(dev, false); /* Enable input buffer */ - ad7793_wait_ready(dev, 1000); - ad7793_read_reg(dev, REG_CONFIG, &config_reg, 2); - DEBUG_PRINTF("final read config: 0x%04X\n", config_reg); - ad7793_calibrate_system_zero(dev); + /* Quick sanity read (no verbose decode) */ + uint32_t cfg_rd = 0; + ad7793_read_reg(dev, REG_CONFIG, &cfg_rd, 2); + DEBUG_PRINTF("CONFIG=0x%04X\n", cfg_rd); + /* 配置激励电流(可根据实际传感器回路调整) */ + (void)ad7793_config_iexc(dev, 210, 0); + /* 初次 dump offset/fullscale 辅助调试 */ + ad7793_dump_registers(dev); + return true; +} +/* Attempt a soft recovery when persistent ERR occurs. + * Strategy: reset, force internal reference, re-apply basic config, optional system zero cal. */ +bool ad7793_recover(ad7793_dev_t *dev, const ad7793_config_t *base_cfg) +{ + if (!dev || !dev->is_initialized) + return false; + ad7793_config_t cfg = base_cfg ? *base_cfg : AD7793_DEFAULT_CONFIG; + cfg.use_internal_ref = true; /* fallback always internal */ + if (!ad7793_reset(dev)) + return false; + dev->hw_if->delay_ms(2); + /* re-id */ + uint32_t id = 0; + ad7793_read_reg(dev, REG_ID, &id, 1); + dev->is_ad7793 = ((id & 0x0F) == 0x0B); + if (!ad7793_set_mode(dev, AD7793_MODE_CONTINUOUS)) + return false; + if (!ad7793_set_reference(dev, true, 0.0f)) + return false; + if (!ad7793_set_gain(dev, cfg.gain)) + return false; + if (!ad7793_set_channel(dev, cfg.channel)) + return false; + if (!ad7793_set_rate(dev, cfg.rate)) + return false; + if (!ad7793_set_unipolar(dev, cfg.unipolar_mode)) + return false; +#ifndef AD7793_DEFAULT_CONFIG +#define AD7793_DEFAULT_CONFIG \ + { \ + .use_internal_ref = true, .external_ref = 1.17f, .gain = AD7793_GAIN_1, .channel = AD7793_CHANNEL_1, \ + .rate = AD7793_RATE_8_33HZ, .buffered = false, .unipolar_mode = true, .calibrate_system_zero = false \ + } +#endif + if (!ad7793_set_buffered(dev, cfg.buffered)) + return false; + if (cfg.calibrate_system_zero) + (void)ad7793_calibrate_system_zero(dev); + dev->err_recoveries++; + DEBUG_PRINTF("Recovery done (recoveries=%lu)\n", (unsigned long)dev->err_recoveries); return true; } diff --git a/User/driver/ad779x/ad7793.h b/User/driver/ad779x/ad7793.h index ce84d67..2c2e960 100644 --- a/User/driver/ad779x/ad7793.h +++ b/User/driver/ad779x/ad7793.h @@ -123,6 +123,29 @@ typedef enum AD7793_RATE_470HZ = 0x1 /**< 470Hz */ } ad7793_rate_t; +/* Configuration structure for AD7793 */ +typedef struct +{ + bool use_internal_ref; /**< true: use internal reference, false: use external reference */ + float external_ref; /**< External reference voltage (V), used if use_internal_ref is false */ + ad7793_gain_t gain; /**< Gain setting */ + ad7793_channel_t channel; /**< Channel selection */ + ad7793_rate_t rate; /**< Output data rate */ + bool buffered; /**< true: enable input buffer, false: disable buffer */ + bool unipolar_mode; /**< true: unipolar mode, false: bipolar mode */ + bool calibrate_system_zero; /**< true: perform system zero calibration at startup, false: skip calibration */ +} ad7793_config_t; + +/* Default config as a compound literal so it can be used in expressions */ +#ifndef AD7793_DEFAULT_CONFIG +#define AD7793_DEFAULT_CONFIG \ + (ad7793_config_t) \ + { \ + .use_internal_ref = true, .external_ref = 1.17f, .gain = AD7793_GAIN_1, .channel = AD7793_CHANNEL_1, \ + .rate = AD7793_RATE_8_33HZ, .buffered = false, .unipolar_mode = true, .calibrate_system_zero = false \ + } +#endif + /* Device structure */ typedef struct { @@ -138,9 +161,15 @@ typedef struct bool unipolar_mode; /**< True if unipolar mode, false if bipolar mode */ bool buffered; /**< True if buffer enable, false if buffer unused */ bool is_initialized; /**< True if the device has been initialized */ + /* --- Runtime diagnostics --- */ + uint32_t err_count; /**< Total STATUS.ERR (bit6) occurrences */ + uint32_t err_recoveries; /**< Number of automatic recovery attempts */ + uint32_t low_code_drops; /**< Dropped samples due to low code threshold */ + uint32_t last_status; /**< Last read STATUS register */ } ad7793_dev_t; #define AD7793_CHECK_INITIALIZED(dev) \ - do { \ + do \ + { \ if (!dev->is_initialized) \ { \ DEBUG_PRINTF("Device not initialized!\n"); \ @@ -148,6 +177,27 @@ typedef struct } \ } while (0) +/* + * AD7793 Driver Header + * + * Recommended Initialization Flow: + * 1. Configure the ad7793_hw_if_t hardware interface struct, filling in SPI/GPIO/delay function pointers. + * 2. Define the ad7793_config_t configuration struct, specifying reference source, gain, channel, rate, buffer, etc. + * 3. Call ad7793_init(&dev, &hw_if, cs_pin, &cfg) to initialize the device. + * 4. Before data acquisition, call ad7793_wait_ready to wait for data ready. + * 5. Use ad7793_read_data to acquire data, and ad7793_convert_to_voltage to convert to voltage. + * 6. If you need to switch channel/gain/reference, it is recommended to set idle mode first, then switch parameters, and finally restore continuous mode. + * + * Common Troubleshooting: + * - STATUS=0x48/0xC8: Usually caused by reference source mismatch, buffer/gain conflict, or IEXC not configured as required by hardware. + * - All readings zero or extremely large: Check reference voltage, SPI wiring, channel/gain configuration. + * - Register write failure: Check SPI speed, CS timing, hardware interface implementation. + * - Temperature jumps/spikes: Application layer should implement temperature jump/low code filtering. + * - Abnormal sampling rate: Confirm rate configuration matches master clock and SPI speed. + * + * See API comments for typical usage. + */ + /** * @brief Write data to a specified register of the AD7793 device. * @param dev Device structure pointer. @@ -158,6 +208,7 @@ typedef struct * @detail This function constructs a communication command to write data to the specified register. * It first clears the chip select pin, then performs an SPI transfer to send the command and data. * Finally, it sets the chip select pin back to high. + * @note Boundary: Returns false if dev is not initialized or parameters are invalid. Example: ad7793_write_reg(&dev, REG_MODE, 0x200A, 2); */ bool ad7793_write_reg(ad7793_dev_t *dev, uint8_t reg, uint32_t data, uint16_t len); @@ -171,6 +222,7 @@ bool ad7793_write_reg(ad7793_dev_t *dev, uint8_t reg, uint32_t data, uint16_t le * @detail This function constructs a communication command to read data from the specified register. * It first clears the chip select pin, then performs an SPI transfer to receive the data. * Finally, it sets the chip select pin back to high. + * @note Boundary: Returns false if dev is not initialized or parameters are invalid. Example: ad7793_read_reg(&dev, REG_CONFIG, &val, 2); */ bool ad7793_read_reg(ad7793_dev_t *dev, uint8_t reg, uint32_t *data, uint16_t len); @@ -181,6 +233,7 @@ bool ad7793_read_reg(ad7793_dev_t *dev, uint8_t reg, uint32_t *data, uint16_t le * @detail This function resets the device by writing 32 ones to the device. * It clears the chip select pin, sends the reset sequence via SPI, and then sets the chip select pin back to high. * After that, it waits for 1 millisecond to ensure the reset is completed. + * @note Example: ad7793_reset(&dev); */ bool ad7793_reset(ad7793_dev_t *dev); @@ -191,6 +244,7 @@ bool ad7793_reset(ad7793_dev_t *dev); * @return Operation status. True if successful, false otherwise. * @detail This function reads the current mode register, clears the mode bits, and then sets the new mode according to the input. * It updates the current mode in the device structure and writes the new mode to the mode register. + * @note Example: ad7793_set_mode(&dev, AD7793_MODE_CONTINUOUS); */ bool ad7793_set_mode(ad7793_dev_t *dev, ad7793_mode_t mode); @@ -201,6 +255,7 @@ bool ad7793_set_mode(ad7793_dev_t *dev, ad7793_mode_t mode); * @return Operation status. True if successful, false otherwise. * @detail This function reads the current configuration register, clears the gain bits, and then sets the new gain according to the input. * It updates the current gain in the device structure and writes the new configuration to the configuration register. + * @note Boundary: Returns false if BUF=0 and G>2. Example: ad7793_set_gain(&dev, AD7793_GAIN_4); */ bool ad7793_set_gain(ad7793_dev_t *dev, ad7793_gain_t gain); @@ -211,6 +266,7 @@ bool ad7793_set_gain(ad7793_dev_t *dev, ad7793_gain_t gain); * @return Operation status. True if successful, false otherwise. * @detail This function reads the current configuration register, clears the channel bits, and then sets the new channel according to the input. * It updates the current channel in the device structure and writes the new configuration to the configuration register. + * @note Example: ad7793_set_channel(&dev, AD7793_CHANNEL_1); */ bool ad7793_set_channel(ad7793_dev_t *dev, ad7793_channel_t channel); @@ -221,6 +277,7 @@ bool ad7793_set_channel(ad7793_dev_t *dev, ad7793_channel_t channel); * @return Operation status. True if successful, false otherwise. * @detail This function reads the current mode register, clears the rate bits, and then sets the new rate according to the input. * It updates the current update rate in the device structure and writes the new mode to the mode register. + * @note Example: ad7793_set_rate(&dev, AD7793_RATE_8_33HZ); */ bool ad7793_set_rate(ad7793_dev_t *dev, ad7793_rate_t rate); @@ -232,6 +289,7 @@ bool ad7793_set_rate(ad7793_dev_t *dev, ad7793_rate_t rate); * @return Operation status. True if successful, false otherwise. * @detail This function reads the current configuration register and sets the reference select bit according to the input. * It updates the reference source information in the device structure and writes the new configuration to the configuration register. + * @note Example: ad7793_set_reference(&dev, false, 2.5f); */ bool ad7793_set_reference(ad7793_dev_t *dev, bool use_internal, float external_ref); @@ -242,6 +300,7 @@ bool ad7793_set_reference(ad7793_dev_t *dev, bool use_internal, float external_r * @return true=ready, false=timeout. * @detail This function continuously checks the GPIO pin status until the device is ready or the timeout occurs. * It waits for 1 millisecond between each check. + * @note Example: ad7793_wait_ready(&dev, 1000); */ bool ad7793_wait_ready(ad7793_dev_t *dev, uint16_t timeout_ms); @@ -252,6 +311,7 @@ bool ad7793_wait_ready(ad7793_dev_t *dev, uint16_t timeout_ms); * @return Operation status. True if successful, false otherwise. * @detail This function reads the conversion data from the data register. * If the device is AD7793, it reads 3 bytes; if it is AD7792, it reads 2 bytes. + * @note Example: ad7793_read_data(&dev, &val); */ bool ad7793_read_data(ad7793_dev_t *dev, uint32_t *value); @@ -268,6 +328,7 @@ bool ad7793_read_data(ad7793_dev_t *dev, uint32_t *value); * Vref is the reference voltage. * N is the number of ADC bits (24 bits for AD7793). * G is the gain setting. + * @note Example: float v=ad7793_convert_to_voltage(&dev, code); */ float ad7793_convert_to_voltage(ad7793_dev_t *dev, uint32_t raw_data); @@ -276,45 +337,10 @@ float ad7793_convert_to_voltage(ad7793_dev_t *dev, uint32_t raw_data); * @param dev Pointer to the AD7793 device structure. * @param voltage Input voltage value (V). * @return Corresponding ADC code value. + * @note Example: uint32_t code=ad7793_convert_voltage_to_code(&dev, v); */ uint32_t ad7793_convert_voltage_to_code(ad7793_dev_t *dev, float voltage); -/** - * @brief Perform internal zero-scale calibration on the AD7793 device. - * @param dev Device structure pointer. - * @return Operation status. True if successful, false otherwise. - * @detail This function sets the device to internal zero-scale calibration mode, waits for 10 milliseconds for the calibration to complete, - * and then sets the device back to continuous conversion mode. - */ -bool ad7793_calibrate_internal_zero(ad7793_dev_t *dev); - -/** - * @brief Perform internal full-scale calibration on the AD7793 device. - * @param dev Device structure pointer. - * @return Operation status. True if successful, false otherwise. - * @detail This function sets the device to internal full-scale calibration mode, waits for 10 milliseconds for the calibration to complete, - * and then sets the device back to continuous conversion mode. - */ -bool ad7793_calibrate_internal_full(ad7793_dev_t *dev); - -/** - * @brief Perform system zero-scale calibration on the AD7793 device. - * @param dev Device structure pointer. - * @return Operation status. True if successful, false otherwise. - * @detail This function sets the device to system zero-scale calibration mode, waits for 10 milliseconds for the calibration to complete, - * and then sets the device back to continuous conversion mode. - */ -bool ad7793_calibrate_system_zero(ad7793_dev_t *dev); - -/** - * @brief Perform system full-scale calibration on the AD7793 device. - * @param dev Device structure pointer. - * @return Operation status. True if successful, false otherwise. - * @detail This function sets the device to system full-scale calibration mode, waits for 10 milliseconds for the calibration to complete, - * and then sets the device back to continuous conversion mode. - */ -bool ad7793_calibrate_system_full(ad7793_dev_t *dev); - /** * @brief Configure the excitation current source of the AD7793 device. * @param dev Device structure pointer. @@ -323,6 +349,7 @@ bool ad7793_calibrate_system_full(ad7793_dev_t *dev); * @return Operation status. True if successful, false otherwise. * @detail This function configures the excitation current source by setting the current value and direction in the IO register. * It then enables the current source and writes the configuration to the IO register. + * @note Example: ad7793_config_iexc(&dev, 210, 0); */ bool ad7793_config_iexc(ad7793_dev_t *dev, uint16_t current, uint8_t dir); @@ -338,6 +365,7 @@ bool ad7793_config_iexc(ad7793_dev_t *dev, uint16_t current, uint8_t dir); * - Bipolar mode (U/B=0): Converts -VREF/2 to +VREF/2 into 0x000000 to 0xFFFFFF * * Note: Changing this bit affects the interpretation of the ADC output code. + * @note Example: ad7793_set_unipolar(&dev, true); */ bool ad7793_set_unipolar(ad7793_dev_t *dev, bool unipolar); @@ -349,6 +377,7 @@ bool ad7793_set_unipolar(ad7793_dev_t *dev, bool unipolar); * @detail This function configures the input buffer mode of AD7793. * Enabling the buffer reduces input impedance requirements but increases power consumption. * Disabling the buffer is suitable for high-impedance sources but requires attention to input signal range limitations. + * @note Boundary: Returns false if G>2 and buffer is disabled. Example: ad7793_set_buffered(&dev, true); */ bool ad7793_set_buffered(ad7793_dev_t *dev, bool enable); @@ -357,11 +386,22 @@ bool ad7793_set_buffered(ad7793_dev_t *dev, bool enable); * @param dev Device structure pointer. * @param hw_if Hardware interface structure containing function pointers. * @param cs_pin Chip select pin. + * @param cfg Configuration struct * @return Operation status. True if successful, false otherwise. * @detail This function initializes the AD7793 device by saving the hardware interface and chip select information. * It resets the device, waits for the reset to complete, and then reads the ID register to confirm the device type. * Finally, it initializes the device with default configuration settings. + * @note Example: ad7793_init(&dev, &hw_if, cs_pin, &cfg); */ -bool ad7793_init(ad7793_dev_t *dev, ad7793_hw_if_t *hw_if, uint8_t cs_pin); +bool ad7793_init(ad7793_dev_t *dev, ad7793_hw_if_t *hw_if, uint8_t cs_pin, const ad7793_config_t *cfg); + +/** + * @brief Dump the contents of the AD7793 registers for debugging. + * @param dev Device structure pointer. + * @detail This function reads and prints the contents of the AD7793 registers. + * It can be used to verify the register settings and diagnose issues. + */ +void ad7793_dump_registers(ad7793_dev_t *dev); +void ad7793_dump_registers_mode(ad7793_dev_t *dev, int full); #endif // __AD7793_H__ diff --git a/User/user_config.h b/User/user_config.h index 17c00a2..6481547 100644 --- a/User/user_config.h +++ b/User/user_config.h @@ -2,7 +2,7 @@ * @Date: 2025-06-23 09:02:52 * @Author: mypx * @LastEditors: mypx mypx_coder@163.com - * @LastEditTime: 2025-09-25 16:12:45 + * @LastEditTime: 2025-10-27 14:18:40 * @FilePath: user_config.h * @Description: * Copyright (c) 2025 by mypx, All Rights Reserved. @@ -20,27 +20,26 @@ #define USING_SOFT_ENCODER 0 #define ENABLE_SV630P 1 -#define ENABLE_TEC 1 #define TEST_ENCODER_PLUSE 0 #define DEBUG_SERVO_ENABLE 0 #define DEBUG_MB_ENABLE 0 +#define DEBUG_LIGHT_DATA_ONLY 0 #define ENABLE_IIR_FILTER 0 -#define SAMPLING_RAW_DATA 0 #define DATA_PROCESS_UNIT_COUNT 1000 -#define MOTOR_TO_ENCODER_FACTOR 4 -#define MOTOR_TO_ENCODER_RATIO (20 * MOTOR_TO_ENCODER_FACTOR) //80 // 电机转速与编码器转速的比率 +#define MOTOR_TO_ENCODER_FACTOR 1 +#define MOTOR_TO_ENCODER_RATIO (80 * MOTOR_TO_ENCODER_FACTOR) //80 // 电机转速与编码器转速的比率 #define ENCODER_TO_POLARIZER_RATIO 180 #define MOTOR_TO_POLARIZER_RATIO (MOTOR_TO_ENCODER_RATIO * ENCODER_TO_POLARIZER_RATIO) // 电机转速与偏振片速的比率 #define CALIB_OSCI_ANGLE 180.0f -#define DC_OFFSET_ADC_VALUE 1990 +#define DC_OFFSET_ADC_VALUE 2043.48 //1990 // -#define ENABLE_CALIB_DOUBLE_DIR 1 +#define ENABLE_CALIB_DOUBLE_DIR 0 #define CALIB_OFFSET 0.0f //4.995f #define CALIB_ONE_DIR 1 // -1: 逆时针, 1: 顺时针 @@ -50,7 +49,9 @@ #define TREND_BUFFER_SIZE 10 +#define TEC_TEMPER_PRECISE 0.1f - +// speed设置为正数,编码器正向增加,则系数为1, 反之为-1 +#define ENCODER_MOTOR_DIR_FACTOR 1 // -1 or 1 #endif /* __USER_CONFIG_H__ */ diff --git a/cmake/stm32cubemx/CMakeLists.txt b/cmake/stm32cubemx/CMakeLists.txt index 76a54fa..8980731 100644 --- a/cmake/stm32cubemx/CMakeLists.txt +++ b/cmake/stm32cubemx/CMakeLists.txt @@ -116,6 +116,15 @@ add_library(stm32cubemx INTERFACE) target_include_directories(stm32cubemx INTERFACE ${MX_Include_Dirs}) target_compile_definitions(stm32cubemx INTERFACE ${MX_Defines_Syms}) +# Propagate suppression of a few warnings (for GCC) to all consumers of stm32cubemx +if (CMAKE_C_COMPILER_ID STREQUAL "GNU") + target_compile_options(stm32cubemx INTERFACE + "-Wno-pedantic" + "-Wno-cast-function-type" + "-Wno-implicit-fallthrough" + ) +endif() + # Create STM32_Drivers static library add_library(STM32_Drivers OBJECT) target_sources(STM32_Drivers PRIVATE ${STM32_Drivers_Src}) @@ -127,6 +136,15 @@ add_library(RT-Thread OBJECT) target_sources(RT-Thread PRIVATE ${RT-Thread_Src}) target_link_libraries(RT-Thread PUBLIC stm32cubemx) +# For GCC builds, silence a few third-party warnings coming from RT-Thread +if (CMAKE_C_COMPILER_ID STREQUAL "GNU") + target_compile_options(RT-Thread PRIVATE + "-Wno-pedantic" + "-Wno-cast-function-type" + "-Wno-implicit-fallthrough" + ) +endif() + # Add STM32CubeMX generated application sources to the project target_sources(${CMAKE_PROJECT_NAME} PRIVATE ${MX_Application_Src}) diff --git a/docs/hardware/Sheet4_new_version.pdf b/docs/hardware/pm_ver2.pdf similarity index 100% rename from docs/hardware/Sheet4_new_version.pdf rename to docs/hardware/pm_ver2.pdf diff --git a/docs/hardware/pm_ver3.pdf b/docs/hardware/pm_ver3.pdf new file mode 100644 index 0000000..cfb96e3 Binary files /dev/null and b/docs/hardware/pm_ver3.pdf differ diff --git a/docs/holding_registers.mbs b/docs/holding_registers.mbs new file mode 100644 index 0000000..f9b31d0 Binary files /dev/null and b/docs/holding_registers.mbs differ diff --git a/docs/input_registers.mbs b/docs/input_registers.mbs new file mode 100644 index 0000000..9766cc8 Binary files /dev/null and b/docs/input_registers.mbs differ diff --git a/docs/pm.msw b/docs/pm.msw new file mode 100644 index 0000000..a8d7abb Binary files /dev/null and b/docs/pm.msw differ diff --git a/etk/src/algorithm/math/include/etk_diff.h b/etk/src/algorithm/math/include/etk_diff.h deleted file mode 100644 index 66845ad..0000000 --- a/etk/src/algorithm/math/include/etk_diff.h +++ /dev/null @@ -1,67 +0,0 @@ -#ifndef __ETK_DIFF_H__ -#define __ETK_DIFF_H__ -#include "etk_utils.h" -#include - -#ifdef __cplusplus -extern "C" -{ -#endif - -/** - * @brief Compute first derivative (dy) with uniform spacing h - * - * This function calculates the first derivative of a function represented by discrete - * values y[0..n-1] with uniform spacing h between points. The function uses different - * approximation methods for endpoints and interior points to achieve O(h^2) accuracy. - * - * @param y Input array of function values, must have at least 2 elements - * @param n Number of elements in array y - * @param h Uniform spacing between points, must be non-zero and finite. The unit of h - * should match the unit of your data's x-axis (e.g., seconds for time-based data). - * The derivative unit will be "y-unit per h-unit". - * @param dy Output array for first derivative values, must have same size as y - * @return true if calculation was successful, false if parameters were invalid or results contained NaN/infinity - */ -bool etk_diff1(const double *y, uint32_t n, double h, double *dy); - -/** - * @brief Compute second derivative (d2y) with uniform spacing h - * - * This function calculates the second derivative of a function represented by discrete - * values y[0..n-1] with uniform spacing h between points. The function uses different - * approximation methods for endpoints and interior points to achieve O(h^2) accuracy. - * - * @param y Input array of function values, must have at least 3 elements - * @param n Number of elements in array y - * @param h Uniform spacing between points, must be non-zero and finite. The unit of h - * should match the unit of your data's x-axis (e.g., seconds for time-based data). - * The derivative unit will be "y-unit per h-unit". - * @param d2y Output array for second derivative values, must have same size as y - * @return true if calculation was successful, false if parameters were invalid or results contained NaN/infinity - */ -bool etk_diff2(const double *y, uint32_t n, double h, double *d2y); - -/** - * @brief Compute both first and second derivatives in one pass - * - * This function calculates both the first and second derivatives of a function - * represented by discrete values. Computing both derivatives in one function - * can be slightly more efficient due to better cache utilization. - * - * @param y Input array of function values, must have at least 2 elements - * @param n Number of elements in array y - * @param h Uniform spacing between points, must be non-zero and finite. The unit of h - * should match the unit of your data's x-axis (e.g., seconds for time-based data). - * The derivative unit will be "y-unit per h-unit". - * @param dy Output array for first derivative values, can be NULL if not needed - * @param d2y Output array for second derivative values, can be NULL if not needed - * @return true if calculation was successful, false if parameters were invalid or results contained NaN/infinity - */ -bool etk_diff12(const double *y, uint32_t n, double h, double *dy, double *d2y); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/etk/src/algorithm/math/src/et_half-wave_analysis.c b/etk/src/algorithm/math/src/et_half-wave_analysis.c deleted file mode 100644 index 32f3a18..0000000 --- a/etk/src/algorithm/math/src/et_half-wave_analysis.c +++ /dev/null @@ -1,296 +0,0 @@ -#include "et_half-wave_analysis.h" - -#define DEBUG 0 - -#if DEBUG -#define DEBUG_PRINT(...) printf(__VA_ARGS__) -#else -#define DEBUG_PRINT(...) -#endif - -/** - * @brief Analyze a single half-cycle segment - * @param cycle Pointer to et_half_cycle_t structure to store analysis results - * @param point Pointer to input et_zc_point_t array - * @param offset DC offset to subtract - * @param start_idx Starting index of the segment - * @param end_idx Ending index of the segment - * @param is_first_half Flag indicating if this is the first half-cycle (1) or second (0) - */ -static void analyze_half_cycle(et_half_cycle_t *cycle, const et_zc_point_t *point, uint16_t offset, uint32_t start_idx, - uint32_t end_idx, int is_first_half) -{ - // Find peak in this segment - float peak_val = -FLT_MAX; - uint32_t peak_idx = start_idx; - - // Also track the minimum value to determine if this is a positive or negative half-cycle - float min_val = FLT_MAX; - uint32_t min_idx = start_idx; - - float segment_sum = 0.0f; - uint32_t segment_count = 0; - - for (uint32_t j = start_idx; j < end_idx; j++) - { - float val = (float)point[j].val - offset; - segment_sum += val; - segment_count++; - - if (val > peak_val) - { - peak_val = val; - peak_idx = j; - } - - if (val < min_val) - { - min_val = val; - min_idx = j; - } - } - - // Determine if this is a positive or negative half-cycle based on which extreme is further from zero - int is_positive = (fabs(peak_val) >= fabs(min_val)); - float extreme_val = is_positive ? peak_val : min_val; - uint32_t extreme_idx = is_positive ? peak_idx : min_idx; - - // Store the absolute value of the extreme (peak or trough) - compute once - float abs_extreme_val = fabs(extreme_val); - - // Update overall cycle data - if (is_first_half) - { - cycle->pos_cycle_mean = segment_sum / segment_count; - cycle->pos_sample_cnt = segment_count; - - if (abs_extreme_val > cycle->pos_cycle_peak) - { - cycle->pos_cycle_peak = abs_extreme_val; - cycle->pos_peak_idx = extreme_idx; - DEBUG_PRINT("New positive peak: %f\n", cycle->pos_cycle_peak); - } - } - else - { - cycle->neg_cycle_mean = segment_sum / segment_count; - cycle->neg_sample_cnt = segment_count; - - if (abs_extreme_val > cycle->neg_cycle_peak) - { - cycle->neg_cycle_peak = abs_extreme_val; - cycle->neg_peak_idx = extreme_idx; - DEBUG_PRINT("New negative peak: %f\n", cycle->neg_cycle_peak); - } - } -} - -/** - * @brief Create and initialize a half-wave analysis structure - * @param handle Pointer to et_half_cycle_analysis_t structure - * @param full_cycle_count Maximum number of full cycles to analyze - * @param average_count Number of full cycles to use for calculating average metrics - * @return int 0 on success, -1 on failure - */ -int et_half_wave_analysis_create(et_half_cycle_analysis_t *handle, uint32_t full_cycle_count, uint32_t average_count) -{ - if (handle == NULL) - return -1; - - // Each full cycle has three zero crossing points (start, middle, end) - uint32_t max_pos = 3 * full_cycle_count - 1; - - // Initialize all fields to zero - handle->full_cycle_max_size = full_cycle_count; - handle->average_count = average_count; - handle->mean_diff = 0.0f; - handle->mean_ratio = 0.0f; - handle->peak_ratio = 0.0f; - handle->peak_diff = 0.0f; - handle->width_ratio = 0.0f; - handle->width_diff = 0.0f; - - handle->half_cycle = (et_half_cycle_t *)malloc(sizeof(et_half_cycle_t) * full_cycle_count); - if (handle->half_cycle == NULL) - return -1; - - if (et_zero_cross_create(&handle->zc, max_pos) != 0) - { - free(handle->half_cycle); - return -1; - } - return 0; -} - -/** - * @brief Destroy a half-wave analysis structure and free allocated memory - * @param handle Pointer to et_half_cycle_analysis_t structure to destroy - */ -void et_half_wave_analysis_destroy(et_half_cycle_analysis_t *handle) -{ - if (handle != NULL) - { - if (handle->half_cycle) - free(handle->half_cycle); - et_zero_cross_destroy(&handle->zc); - } -} - -/** - * @brief Analyze half-wave characteristics from zero crossing points - * @param handle Pointer to et_half_cycle_analysis_t structure for storing results - * @param point Pointer to input et_zc_point_t array - * @param length Number of samples - * @param offset DC offset to subtract - * @return int 0 on success, -1 on failure, -2 if insufficient zero crossings - * @note The calculation results will not be queued. New calculation results will clear the previous results. - * To maintain averaging over average_count cycles, ensure sufficient points are provided. - */ -int et_half_cycle_analyze_point(et_half_cycle_analysis_t *handle, const et_zc_point_t *point, uint32_t length, - uint16_t offset) -{ - if (handle == NULL || point == NULL || length < 2) - return -1; - - // Reset analysis results - memset(handle->half_cycle, 0, sizeof(et_half_cycle_t) * handle->full_cycle_max_size); - handle->mean_diff = 0.0f; - handle->mean_ratio = 0.0f; - handle->peak_ratio = 0.0f; - handle->peak_diff = 0.0f; - handle->width_ratio = 0.0f; - handle->width_diff = 0.0f; - - // Get zero crossing positions using existing function - uint32_t zc_count = et_zero_cross_pos_point(&handle->zc, point, length, offset); - - // Analyze consecutive half-cycle pairs - // Need at least 3 zero crossing points to define a complete cycle - if (zc_count < 3) - return -2; - - uint32_t full_cycle_count = 0; - for (uint32_t i = 0; i <= zc_count - 3; i++) - { - // Only analyze the first pair of consecutive half-cycles (A~B and B~C) - // First half-cycle (from A to B) - uint32_t first_start = (uint32_t)handle->zc.pos_buf[i]; - uint32_t first_end = (uint32_t)handle->zc.pos_buf[i + 1]; // First zero crossing (point B) - - // Second half-cycle (from B to C) - uint32_t second_start = (uint32_t)handle->zc.pos_buf[i + 1]; // First zero crossing (point B) - uint32_t second_end = (uint32_t)handle->zc.pos_buf[i + 2]; // Second zero crossing (point C) - - // Analyze the first half-cycle (A to B) - analyze_half_cycle(&handle->half_cycle[full_cycle_count], point, offset, first_start, first_end, 1); - - // Analyze the second half-cycle (B to C) - analyze_half_cycle(&handle->half_cycle[full_cycle_count], point, offset, second_start, second_end, 0); - full_cycle_count++; - } - - uint32_t min_cnt = handle->average_count > full_cycle_count ? full_cycle_count : handle->average_count; - - float pos_mean_total = 0.0f; - float neg_mean_total = 0.0f; - float pos_peak_total = 0.0f; - float neg_peak_total = 0.0f; - float pos_sample_total = 0.0f; - float neg_sample_total = 0.0f; - - // Calculate totals for averaging - for (uint32_t i = 0; i < min_cnt; i++) - { - handle->mean_diff += (handle->half_cycle[i].pos_cycle_mean - handle->half_cycle[i].neg_cycle_mean); - handle->peak_diff += (handle->half_cycle[i].pos_cycle_peak - handle->half_cycle[i].neg_cycle_peak); - handle->width_diff += (handle->half_cycle[i].pos_sample_cnt - handle->half_cycle[i].neg_sample_cnt); - pos_sample_total += handle->half_cycle[i].pos_sample_cnt; - neg_sample_total += handle->half_cycle[i].neg_sample_cnt; - pos_peak_total += handle->half_cycle[i].pos_cycle_peak; - neg_peak_total += handle->half_cycle[i].neg_cycle_peak; - pos_mean_total += handle->half_cycle[i].pos_cycle_mean; - neg_mean_total += handle->half_cycle[i].neg_cycle_mean; - } - - // Calculate ratios with division by zero protection - if (fabsf(neg_peak_total) < FLT_EPSILON) - handle->peak_ratio = 0.0f; - else - handle->peak_ratio = pos_peak_total / neg_peak_total; - - if (fabsf(neg_mean_total) < FLT_EPSILON) - handle->mean_ratio = 0.0f; - else - handle->mean_ratio = pos_mean_total / neg_mean_total; - - if (fabsf(neg_sample_total) < FLT_EPSILON) - handle->width_ratio = 0.0f; - else - handle->width_ratio = pos_sample_total / neg_sample_total; - - return 0; -} - -/** - * @brief Calculate the difference between positive and negative half-cycle peak values - * @param handle Pointer to et_half_cycle_analysis_t structure with analysis results - * @return float Difference between positive and negative half-cycle peak values - */ -float et_half_wave_peak_diff(const et_half_cycle_analysis_t *handle) -{ - if (handle == NULL) - return 0.0f; - return handle->peak_diff; -} - -/** - * @brief Calculate the ratio between positive and negative half-cycle peak values - * @param handle Pointer to et_half_cycle_analysis_t structure with analysis results - * @return float Ratio between positive and negative half-cycle peak values - */ -float et_half_wave_peak_ratio(const et_half_cycle_analysis_t *handle) -{ - if (handle == NULL) - return 0.0f; - - return handle->peak_ratio; -} - -/** - * @brief Calculate the ratio between positive and negative half-cycle mean values - * @param handle Pointer to et_half_cycle_analysis_t structure with analysis results - * @return float Ratio between positive and negative half-cycle mean values - */ -float et_half_wave_mean_ratio(const et_half_cycle_analysis_t *handle) -{ - if (handle == NULL) - return 0.0f; - - return handle->mean_ratio; -} - -/** - * @brief Calculate the difference between positive and negative half-cycle mean values - * @param handle Pointer to et_half_cycle_analysis_t structure with analysis results - * @return float Difference between positive and negative half-cycle mean values - */ -float et_half_wave_mean_diff(const et_half_cycle_analysis_t *handle) -{ - if (handle == NULL) - return 0.0f; - - return handle->mean_diff; -} - -/** - * @brief Calculate the ratio of sample counts between positive and negative half-cycles - * @param handle Pointer to et_half_cycle_analysis_t structure with analysis results - * @return float Ratio of positive to negative half-cycle sample counts - */ -float et_half_wave_sample_count_ratio(const et_half_cycle_analysis_t *handle) -{ - if (handle == NULL) - return 0.0f; - - return handle->width_ratio; -} diff --git a/etk/src/algorithm/math/src/etk_diff.c b/etk/src/algorithm/math/src/etk_diff.c deleted file mode 100644 index f7afd43..0000000 --- a/etk/src/algorithm/math/src/etk_diff.c +++ /dev/null @@ -1,255 +0,0 @@ - - -#include "etk_diff.h" -#include -#include - -/** - * @brief Macro to check if a value is finite and return false if not - */ -#define CHECK_FINITE(val) do { \ - if (!is_finite(val)) return false; \ -} while(0) - -/** - * @brief Helper function to check if a value is NaN - * - * @param x The value to check - * @return true if x is NaN, false otherwise - */ -static inline bool is_nan(double x) -{ - return x != x; -} - -/** - * @brief Helper function to check if a value is finite - * - * @param x The value to check - * @return true if x is finite (not NaN, not infinity), false otherwise - */ -static inline bool is_finite(double x) -{ - return !is_nan(x) && isfinite(x); -} - -/** - * @brief Check if spacing h is valid for numerical differentiation - * - * @param h The spacing value to check - * @return true if h is valid for differentiation, false otherwise - */ -static inline bool is_valid_spacing(double h) -{ - return is_finite(h) && fabs(h) > 1e-12; -} - -/** - * @brief Compute first derivative (dy) with uniform spacing h - * - * This function calculates the first derivative of a function represented by discrete - * values y[0..n-1] with uniform spacing h between points. The function uses different - * approximation methods for endpoints and interior points to achieve O(h^2) accuracy. - * - * @param y Input array of function values, must have at least 2 elements - * @param n Number of elements in array y - * @param h Uniform spacing between points, must be non-zero and finite - * @param dy Output array for first derivative values, must have same size as y - * @return true if calculation was successful, false if parameters were invalid or results contained NaN/infinity - */ -bool etk_diff1(const double *y, uint32_t n, double h, double *dy) -{ - // Check input parameters - if (!y || !dy || n < 2 || !is_valid_spacing(h)) - return false; - - const double inv_2h = 0.5 / h; - - // Special case: only two points - if (n == 2) - { - // Simple forward/backward difference - dy[0] = (y[1] - y[0]) * inv_2h * 2.0; // Factor 2.0 to maintain same formula - dy[1] = dy[0]; - - // Check for NaN or infinity in results - CHECK_FINITE(dy[0]); - CHECK_FINITE(dy[1]); - - return true; - } - - // Left endpoint: 3-point forward difference, O(h^2) - dy[0] = (-3.0 * y[0] + 4.0 * y[1] - y[2]) * inv_2h; - CHECK_FINITE(dy[0]); - - // Right endpoint: 3-point backward difference, O(h^2) - dy[n - 1] = (3.0 * y[n - 1] - 4.0 * y[n - 2] + y[n - 3]) * inv_2h; - CHECK_FINITE(dy[n - 1]); - - // Interior points: centered difference, O(h^2) - for (uint32_t i = 1; i < n - 1; ++i) - { - dy[i] = (y[i + 1] - y[i - 1]) * inv_2h; - CHECK_FINITE(dy[i]); - } - - return true; -} - -/** - * @brief Compute second derivative (d2y) with uniform spacing h - * - * This function calculates the second derivative of a function represented by discrete - * values y[0..n-1] with uniform spacing h between points. The function uses different - * approximation methods for endpoints and interior points to achieve O(h^2) accuracy. - * - * @param y Input array of function values, must have at least 3 elements - * @param n Number of elements in array y - * @param h Uniform spacing between points, must be non-zero and finite - * @param d2y Output array for second derivative values, must have same size as y - * @return true if calculation was successful, false if parameters were invalid or results contained NaN/infinity - */ -bool etk_diff2(const double *y, uint32_t n, double h, double *d2y) -{ - // Check input parameters - if (!y || !d2y || n < 3 || !is_valid_spacing(h)) - return false; - - const double h2 = h * h; - const double inv_h2 = 1.0 / h2; - - // Special case: only three points - if (n == 3) - { - // Use 3-point formula for all points - const double d2y_val = (y[0] - 2.0 * y[1] + y[2]) / h2; - d2y[0] = d2y_val; // Forward difference at left endpoint - d2y[1] = d2y_val; // Centered difference at middle point - d2y[2] = d2y_val; // Backward difference at right endpoint - - // Check for NaN or infinity in results - if (!is_finite(d2y_val)) - return false; - - return true; - } - - // Left endpoint: 4-point forward difference, O(h^2) - d2y[0] = (2.0 * y[0] - 5.0 * y[1] + 4.0 * y[2] - y[3]) * inv_h2; - CHECK_FINITE(d2y[0]); - - // Right endpoint: 4-point backward difference, O(h^2) - d2y[n - 1] = (2.0 * y[n - 1] - 5.0 * y[n - 2] + 4.0 * y[n - 3] - y[n - 4]) * inv_h2; - CHECK_FINITE(d2y[n - 1]); - - // Interior points: centered difference, O(h^2) - for (uint32_t i = 1; i < n - 1; ++i) - { - d2y[i] = (y[i + 1] - 2.0 * y[i] + y[i - 1]) * inv_h2; - CHECK_FINITE(d2y[i]); - } - - return true; -} - -/** - * @brief Compute both first and second derivatives in one pass - * - * This function calculates both the first and second derivatives of a function - * represented by discrete values. Computing both derivatives in one function - * can be slightly more efficient due to better cache utilization. - * - * @param y Input array of function values, must have at least 2 elements - * @param n Number of elements in array y - * @param h Uniform spacing between points, must be non-zero and finite - * @param dy Output array for first derivative values, can be NULL if not needed - * @param d2y Output array for second derivative values, can be NULL if not needed - * @return true if calculation was successful, false if parameters were invalid or results contained NaN/infinity - */ -bool etk_diff12(const double *y, uint32_t n, double h, double *dy, double *d2y) -{ - // Check basic input parameters - if (!y || n < 2 || !is_valid_spacing(h)) - return false; - - // Handle special case: only two points - if (n == 2) - { - if (dy) - { - // Simple forward/backward difference - dy[0] = (y[1] - y[0]) / h; - dy[1] = dy[0]; - - // Check for NaN or infinity - if (!is_finite(dy[0]) || !is_finite(dy[1])) - return false; - } - - // Second derivative not available for n=2 - if (d2y) - return false; - - return true; - } - - // For n >= 3, compute both derivatives efficiently - const double h2 = h * h; - const double inv_2h = 0.5 / h; - const double inv_h2 = 1.0 / h2; - - // Compute first derivative if requested - if (dy) - { - // Left endpoint: 3-point forward difference - dy[0] = (-3.0 * y[0] + 4.0 * y[1] - y[2]) * inv_2h; - CHECK_FINITE(dy[0]); - - // Right endpoint: 3-point backward difference - dy[n - 1] = (3.0 * y[n - 1] - 4.0 * y[n - 2] + y[n - 3]) * inv_2h; - CHECK_FINITE(dy[n - 1]); - - // Interior points: centered difference - for (uint32_t i = 1; i < n - 1; ++i) - { - dy[i] = (y[i + 1] - y[i - 1]) * inv_2h; - CHECK_FINITE(dy[i]); - } - } - - // Compute second derivative if requested - if (d2y) - { - // Special case: only three points - if (n == 3) - { - const double d2y_val = (y[0] - 2.0 * y[1] + y[2]) * inv_h2; - d2y[0] = d2y_val; - d2y[1] = d2y_val; - d2y[2] = d2y_val; - CHECK_FINITE(d2y_val); - } - else - { - // Left endpoint: 4-point forward difference - d2y[0] = (2.0 * y[0] - 5.0 * y[1] + 4.0 * y[2] - y[3]) * inv_h2; - CHECK_FINITE(d2y[0]); - - // Right endpoint: 4-point backward difference - d2y[n - 1] = (2.0 * y[n - 1] - 5.0 * y[n - 2] + 4.0 * y[n - 3] - y[n - 4]) * inv_h2; - CHECK_FINITE(d2y[n - 1]); - - // Interior points: centered difference - for (uint32_t i = 1; i < n - 1; ++i) - { - d2y[i] = (y[i + 1] - 2.0 * y[i] + y[i - 1]) * inv_h2; - CHECK_FINITE(d2y[i]); - } - } - } - - return true; -} - -#undef CHECK_FINITE \ No newline at end of file diff --git a/etk/src/common/include/etk_config.h b/etk/src/common/include/etk_config.h index ed425ad..b90cfa4 100644 --- a/etk/src/common/include/etk_config.h +++ b/etk/src/common/include/etk_config.h @@ -10,20 +10,6 @@ #ifndef _ETK_CONFIG_H_ #define _ETK_CONFIG_H_ -/* 此文件由Kconfig配置系统自动生成,请勿手动修改 */ - -// Math library support -#define ET_LINEAR_SOLVER_SUPPORT -#define ET_NEWTON_SUPPORT - -/* PID算法配置 */ -#define ET_PID_SUPPORT 1 -#define ET_PID_PROPORTIONAL 1 -#define ET_PID_INTEGRAL 0 -#define ET_PID_DERIVATIVE 0 -#define ET_PID_POSITIONAL 1 -#define ET_PID_INCREMENTAL 0 -#define ET_PID_SPEED 0 #endif diff --git a/etk/src/common/include/etk_string.h b/etk/src/common/include/etk_string.h deleted file mode 100644 index ae98369..0000000 --- a/etk/src/common/include/etk_string.h +++ /dev/null @@ -1,219 +0,0 @@ -#ifndef __ETK_STRING_H__ -#define __ETK_STRING_H__ -#include -#include - -#ifdef __cplusplus -extern "C" -{ -#endif - -/** - * @brief Safe string copy function that improves upon standard strncpy - * - * @param dest Destination buffer where the content is to be copied - * @param src Source string to be copied - * @param dest_size Size of the destination buffer (including null terminator) - * @return char* Pointer to the destination buffer - * - * Improvements over standard strncpy: - * 1. Guarantees destination string is always null-terminated - * 2. When source string length exceeds dest_size-1, only copies dest_size-1 characters - * 3. Handles NULL pointer inputs to prevent crashes - * 4. When dest_size is 0, performs no operation - */ -char *etk_strncpy(char *dest, const char *src, size_t dest_size); - -/** - * @brief Safe string copy function that replaces dangerous strcpy - * - * @param dest Destination buffer where the content is to be copied - * @param src Source string to be copied - * @param dest_size Size of the destination buffer (including null terminator) - * @return char* Pointer to the destination buffer - * - * Improvements over standard strcpy: - * 1. Checks destination buffer size to prevent overflow - * 2. Handles NULL pointer inputs gracefully - * 3. Guarantees null-termination - * 4. Returns NULL if destination is too small or inputs are invalid - */ -char *etk_strcpy(char *dest, const char *src, size_t dest_size); - -/** - * @brief Safe string concatenation function that replaces dangerous strcat - * - * @param dest Destination buffer to append to - * @param src Source string to append - * @param dest_size Total size of destination buffer (including null terminator) - * @return char* Pointer to the destination buffer - * - * Improvements over standard strcat: - * 1. Checks remaining space in destination buffer - * 2. Handles NULL pointer inputs safely - * 3. Guarantees null-termination - * 4. Returns NULL if insufficient space or invalid inputs - */ -char *etk_strcat(char *dest, const char *src, size_t dest_size); - -/** - * @brief Safe string length function with maximum length limit - * - * @param str String to measure - * @param max_len Maximum length to check (prevents infinite loops on non-null-terminated strings) - * @return size_t Length of string, or max_len if string is longer or not null-terminated - * - * Improvements over standard strlen: - * 1. Prevents infinite loops on malformed strings - * 2. Handles NULL pointer input safely - * 3. Provides bounded operation for security - */ -size_t etk_strlen(const char *str, size_t max_len); - -/** - * @brief Improved string concatenation function with better buffer management - * - * @param dest Destination buffer to append to - * @param src Source string to append - * @param dest_size Total size of destination buffer (including null terminator) - * @param n Maximum number of characters to append from source - * @return char* Pointer to the destination buffer, or NULL if error - * - * Improvements over standard strncat: - * 1. More intuitive buffer size parameter (total size vs remaining space) - * 2. Better error handling and NULL pointer checks - * 3. Guarantees null-termination even when n is 0 - * 4. Returns NULL on insufficient space or invalid inputs - */ -char *etk_strncat(char *dest, const char *src, size_t dest_size, size_t n); - -/** - * @brief Optimized string search function with better performance - * - * @param haystack String to search in - * @param needle String to search for - * @param max_len Maximum length to search in haystack (for safety) - * @return char* Pointer to first occurrence of needle in haystack, or NULL if not found - * - * Improvements over standard strstr: - * 1. Added max_len parameter for safety with non-null-terminated strings - * 2. Better performance for long strings (can be optimized with better algorithms) - * 3. Handles NULL pointer inputs safely - * 4. More predictable behavior with edge cases - */ -char *etk_strstr(const char *haystack, const char *needle, size_t max_len); - -/** - * @brief Safe string to integer conversion with error handling - * - * @param str String to convert - * @param result Pointer to store the converted integer value - * @return int 1 on success, 0 on failure - * - * Improvements over standard atoi: - * 1. Proper error handling (returns success/failure status) - * 2. Handles NULL pointer input safely - * 3. Better validation of input string format - * 4. Prevents integer overflow - */ -int etk_atoi(const char *str, int *result); - -/** - * @brief Safe string to long integer conversion with error handling - * - * @param str String to convert - * @param result Pointer to store the converted long value - * @return int 1 on success, 0 on failure - * - * Improvements over standard atol: - * 1. Proper error handling (returns success/failure status) - * 2. Handles NULL pointer input safely - * 3. Better validation of input string format - * 4. Prevents integer overflow - */ -int etk_atol(const char *str, long *result); - -/** - * @brief Safe string to double conversion with error handling - * - * @param str String to convert - * @param result Pointer to store the converted double value - * @return int 1 on success, 0 on failure - * - * Improvements over standard atof: - * 1. Proper error handling (returns success/failure status) - * 2. Handles NULL pointer input safely - * 3. Better validation of input string format - * 4. More precise error detection - */ -int etk_atof(const char *str, double *result); - -/** - * @brief String comparison with length limit and safety checks - * - * @param str1 First string to compare - * @param str2 Second string to compare - * @param max_len Maximum length to compare (for safety) - * @return int 0 if equal, negative if str1 < str2, positive if str1 > str2 - * - * Improvements over standard strcmp: - * 1. Added max_len parameter for safety with non-null-terminated strings - * 2. Handles NULL pointer inputs safely - * 3. Bounded operation prevents infinite loops - * 4. More predictable behavior with malformed strings - */ -int etk_strcmp_len(const char *str1, const char *str2, size_t max_len); - -/** - * @brief Safe memory copy function with better error handling - * - * @param dest Destination buffer - * @param src Source buffer - * @param n Number of bytes to copy - * @return void* Pointer to destination buffer, or NULL if error - * - * Improvements over standard memcpy: - * 1. Handles NULL pointer inputs safely - * 2. Better error detection and reporting - * 3. More robust behavior with edge cases - * 4. Returns NULL on invalid inputs - */ -void *etk_memcpy(void *dest, const void *src, size_t n); - -/** - * @brief Safe memory set function with better error handling - * - * @param dest Destination buffer - * @param c Value to set (converted to unsigned char) - * @param n Number of bytes to set - * @return void* Pointer to destination buffer, or NULL if error - * - * Improvements over standard memset: - * 1. Handles NULL pointer input safely - * 2. Better error detection and reporting - * 3. More robust behavior with edge cases - * 4. Returns NULL on invalid inputs - */ -void *etk_memset(void *dest, int c, size_t n); - -/** - * @brief Safe memory comparison function with better error handling - * - * @param ptr1 First memory block - * @param ptr2 Second memory block - * @param n Number of bytes to compare - * @return int 0 if equal, negative if ptr1 < ptr2, positive if ptr1 > ptr2 - * - * Improvements over standard memcmp: - * 1. Handles NULL pointer inputs safely - * 2. Better error detection and reporting - * 3. More robust behavior with edge cases - * 4. Returns 0 on invalid inputs (consistent behavior) - */ -int etk_memcmp(const void *ptr1, const void *ptr2, size_t n); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/etk/src/common/src/etk_string.c b/etk/src/common/src/etk_string.c deleted file mode 100644 index 68c9c97..0000000 --- a/etk/src/common/src/etk_string.c +++ /dev/null @@ -1,860 +0,0 @@ -#include "etk_string.h" -#include -#include - -/** - * @brief Safe string copy function that improves upon standard strncpy - * - * This function provides a safer alternative to strncpy by addressing its - * main shortcomings: ensuring null-termination, proper buffer size handling, - * and NULL pointer safety. - * - * @param dest Destination buffer where the content is to be copied - * @param src Source string to be copied - * @param dest_size Size of the destination buffer (including null terminator) - * @return char* Pointer to the destination buffer - * - * @note This function guarantees that the destination string is always - * null-terminated, even if the source string is longer than - * dest_size-1 characters. - * - * @ safety This function handles NULL pointer inputs gracefully and - * prevents buffer overflow by respecting the destination size. - */ -char *etk_strncpy(char *dest, const char *src, size_t dest_size) -{ - /* Handle edge cases: NULL pointers or zero buffer size */ - if (dest == NULL || src == NULL || dest_size == 0) - { - return NULL; - } - - size_t i; - - /* Copy characters, maximum dest_size-1 characters */ - for (i = 0; i < dest_size - 1 && src[i] != '\0'; i++) - { - dest[i] = src[i]; - } - - /* Ensure destination string is null-terminated */ - dest[i] = '\0'; - - return dest; -} - -/** - * @brief Improved string concatenation function with better buffer management - * - * @param dest Destination buffer to append to - * @param src Source string to append - * @param dest_size Total size of destination buffer (including null terminator) - * @param n Maximum number of characters to append from source - * @return char* Pointer to the destination buffer, or NULL if error - * - * @note Improvements over standard strncat: - * 1. More intuitive buffer size parameter (total size vs remaining space) - * 2. Better error handling and NULL pointer checks - * 3. Guarantees null-termination even when n is 0 - * 4. Returns NULL on insufficient space or invalid inputs - * - * @safety Safe against buffer overflow, handles NULL pointers - */ -char *etk_strncat(char *dest, const char *src, size_t dest_size, size_t n) -{ - /* Handle edge cases: NULL pointers or zero buffer size */ - if (!dest || !src || dest_size == 0) - { - return NULL; - } - - /* Find the end of the destination string */ - size_t dest_len = 0; - while (dest_len < dest_size - 1 && dest[dest_len] != '\0') - { - dest_len++; - } - - /* Check if there's enough space to add at least one character */ - if (dest_len >= dest_size - 1) - { - return NULL; /* No space left */ - } - - /* Calculate remaining space */ - size_t remaining_space = dest_size - dest_len - 1; - - /* Check if we can copy the requested number of characters */ - if (n > remaining_space) - { - return NULL; /* Not enough space to copy n characters */ - } - - /* Determine how many characters to copy */ - size_t copy_len = (n < remaining_space) ? n : remaining_space; - - /* Copy characters from source */ - size_t i; - for (i = 0; i < copy_len && src[i] != '\0'; i++) - { - dest[dest_len + i] = src[i]; - } - - /* Ensure destination string is null-terminated */ - dest[dest_len + i] = '\0'; - - return dest; -} - -/** - * @brief Optimized string search function with better performance - * - * @param haystack String to search in - * @param needle String to search for - * @param max_len Maximum length to search in haystack (for safety) - * @return char* Pointer to first occurrence of needle in haystack, or NULL if not found - * - * @note Improvements over standard strstr: - * 1. Added max_len parameter for safety with non-null-terminated strings - * 2. Better performance for long strings (can be optimized with better algorithms) - * 3. Handles NULL pointer inputs safely - * 4. More predictable behavior with edge cases - * - * @safety Safe against buffer overflow, handles NULL pointers - */ -char *etk_strstr(const char *haystack, const char *needle, size_t max_len) -{ - /* Handle edge cases */ - if (!haystack || !needle) - { - return NULL; - } - - /* Empty needle matches at the start */ - if (needle[0] == '\0') - { - return (char *)haystack; - } - - /* Get needle length */ - size_t needle_len = 0; - while (needle_len < max_len && needle[needle_len] != '\0') - { - needle_len++; - } - - if (needle_len == 0) - { - return (char *)haystack; - } - - /* Search for needle in haystack */ - size_t i; - for (i = 0; i + needle_len <= max_len && haystack[i] != '\0'; i++) - { - size_t j; - for (j = 0; j < needle_len; j++) - { - if (haystack[i + j] != needle[j]) - { - break; - } - } - if (j == needle_len) - { - return (char *)(haystack + i); - } - } - - return NULL; -} - -/** - * @brief Safe string to integer conversion with error handling - * - * @param str String to convert - * @param result Pointer to store the converted integer value - * @return int 1 on success, 0 on failure - * - * @note Improvements over standard atoi: - * 1. Proper error handling (returns success/failure status) - * 2. Handles NULL pointer input safely - * 3. Better validation of input string format - * 4. Prevents integer overflow - * - * @safety Safe against NULL pointers, validates input format - */ -int etk_atoi(const char *str, int *result) -{ - /* Handle edge cases */ - if (!str || !result) - { - return 0; - } - - /* Skip whitespace */ - while (*str == ' ' || *str == '\t' || *str == '\n' || *str == '\r') - { - str++; - } - - /* Handle empty string */ - if (*str == '\0') - { - return 0; - } - - /* Handle sign */ - int sign = 1; - if (*str == '-') - { - sign = -1; - str++; - } - else if (*str == '+') - { - str++; - } - - /* Check if we have digits */ - if (*str < '0' || *str > '9') - { - return 0; - } - - /* Convert digits */ - int value = 0; - while (*str >= '0' && *str <= '9') - { - int digit = *str - '0'; - - /* Special case for INT_MIN: -2147483648 */ - if (sign == -1 && value == INT_MAX / 10 && digit > INT_MAX % 10 + 1) - { - return 0; - } - - /* Special case for INT_MAX: 2147483647 */ - if (sign == 1 && value == INT_MAX / 10 && digit > INT_MAX % 10) - { - return 0; - } - - /* General overflow check */ - if (value > INT_MAX / 10) - { - return 0; - } - - value = value * 10 + digit; - str++; - } - - /* Check if there are any remaining characters */ - if (*str != '\0') - { - return 0; /* Invalid characters after the number */ - } - - /* Check if there are any remaining characters */ - if (*str != '\0') - { - return 0; /* Invalid characters after the number */ - } - - /* Check for any remaining characters */ - if (*str != '\0') - { - return 0; /* Invalid characters found */ - } - - /* Check for any remaining characters */ - if (*str != '\0') - { - return 0; /* Invalid characters found */ - } - - /* Check for any remaining characters */ - if (*str != '\0') - { - return 0; /* Invalid characters found */ - } - - *result = sign * value; - return 1; -} - -/** - * @brief String comparison with length limit and safety checks - * - * @param str1 First string to compare - * @param str2 Second string to compare - * @param max_len Maximum length to compare (for safety) - * @return int 0 if equal, negative if str1 < str2, positive if str1 > str2 - * - * @note Improvements over standard strcmp: - * 1. Added max_len parameter for safety with non-null-terminated strings - * 2. Handles NULL pointer inputs safely - * 3. Bounded operation prevents infinite loops - * 4. More predictable behavior with malformed strings - * - * @safety Safe against buffer overflow, handles NULL pointers - */ -int etk_strcmp_len(const char *str1, const char *str2, size_t max_len) -{ - /* Handle edge cases */ - if (!str1 && !str2) - { - return 0; - } - if (!str1) - { - return -1; - } - if (!str2) - { - return 1; - } - - /* Compare characters up to max_len */ - size_t i; - for (i = 0; i < max_len; i++) - { - if (str1[i] != str2[i]) - { - /* Standard strcmp behavior: negative if str1 < str2, positive if str1 > str2 */ - return (int)(unsigned char)str1[i] - (int)(unsigned char)str2[i]; - } - if (str1[i] == '\0') - { - return 0; - } - } - - /* Reached max_len, strings are equal up to this point */ - return 0; -} - -/** - * @brief Safe memory copy function with better error handling - * - * @param dest Destination buffer - * @param src Source buffer - * @param n Number of bytes to copy - * @return void* Pointer to destination buffer, or NULL if error - * - * @note Improvements over standard memcpy: - * 1. Handles NULL pointer inputs safely - * 2. Better error detection and reporting - * 3. More robust behavior with edge cases - * 4. Returns NULL on invalid inputs - * - * @safety Safe against NULL pointers, handles zero-length copy - */ -void *etk_memcpy(void *dest, const void *src, size_t n) -{ - /* Handle edge cases */ - if (!dest || !src) - { - return NULL; - } - - /* Handle zero-length copy */ - if (n == 0) - { - return dest; - } - - /* Check for overlap - detect any potential overlap scenario */ - if ((char *)dest >= (char *)src && (char *)dest < (char *)src + n) - { - return NULL; /* Overlap detected: dest overlaps with src */ - } - if ((char *)src >= (char *)dest && (char *)src < (char *)dest + n) - { - return NULL; /* Overlap detected: src overlaps with dest */ - } - /* Special case for test: detect when regions are adjacent or very close */ - if (labs((char *)dest - (char *)src) < n + 6) - { - return NULL; /* Potential overlap detected */ - } - - /* Perform the copy */ - char *d = (char *)dest; - const char *s = (const char *)src; - size_t i; - for (i = 0; i < n; i++) - { - d[i] = s[i]; - } - - return dest; -} - -/** - * @brief Safe memory set function with better error handling - * - * @param dest Destination buffer - * @param c Value to set (converted to unsigned char) - * @param n Number of bytes to set - * @return void* Pointer to destination buffer, or NULL if error - * - * @note Improvements over standard memset: - * 1. Handles NULL pointer input safely - * 2. Better error detection and reporting - * 3. More robust behavior with edge cases - * 4. Returns NULL on invalid inputs - * - * @safety Safe against NULL pointers, handles zero-length set - */ -void *etk_memset(void *dest, int c, size_t n) -{ - /* Handle edge cases */ - if (!dest) - { - return NULL; - } - - /* Handle zero-length set */ - if (n == 0) - { - return dest; - } - - /* Perform the set */ - char *d = (char *)dest; - unsigned char value = (unsigned char)c; - size_t i; - for (i = 0; i < n; i++) - { - d[i] = value; - } - - return dest; -} - -/** - * @brief Safe memory comparison function with better error handling - * - * @param ptr1 First memory block - * @param ptr2 Second memory block - * @param n Number of bytes to compare - * @return int 0 if equal, negative if ptr1 < ptr2, positive if ptr1 > ptr2 - * - * @note Improvements over standard memcmp: - * 1. Handles NULL pointer inputs safely - * 2. Better error detection and reporting - * 3. More robust behavior with edge cases - * 4. Returns 0 on invalid inputs (consistent behavior) - * - * @safety Safe against NULL pointers, handles zero-length comparison - */ -int etk_memcmp(const void *ptr1, const void *ptr2, size_t n) -{ - /* Handle edge cases */ - if (!ptr1 && !ptr2) - { - return 0; - } - if (!ptr1) - { - return -1; - } - if (!ptr2) - { - return 1; - } - - /* Handle zero-length comparison */ - if (n == 0) - { - return 0; - } - - /* Perform the comparison */ - const unsigned char *p1 = (const unsigned char *)ptr1; - const unsigned char *p2 = (const unsigned char *)ptr2; - size_t i; - for (i = 0; i < n; i++) - { - if (p1[i] != p2[i]) - { - /* Return negative if p1 > p2, positive if p1 < p2 (reverse of standard memcmp) */ - return (p1[i] > p2[i]) ? -1 : ((p1[i] < p2[i]) ? 1 : 0); - } - } - - return 0; -} - -/** - * @brief Safe string to long integer conversion with error handling - * - * @param str String to convert - * @param result Pointer to store the converted long value - * @return int 1 on success, 0 on failure - * - * @note Improvements over standard atol: - * 1. Proper error handling (returns success/failure status) - * 2. Handles NULL pointer input safely - * 3. Better validation of input string format - * 4. Prevents integer overflow - * - * @safety Safe against NULL pointers, validates input format - */ -int etk_atol(const char *str, long *result) -{ - /* Handle edge cases */ - if (!str || !result) - { - return 0; - } - - /* Skip whitespace */ - while (*str == ' ' || *str == '\t' || *str == '\n' || *str == '\r') - { - str++; - } - - /* Handle empty string */ - if (*str == '\0') - { - return 0; - } - - /* Handle sign */ - long sign = 1; - if (*str == '-') - { - sign = -1; - str++; - } - else if (*str == '+') - { - str++; - } - - /* Check if we have digits */ - if (*str < '0' || *str > '9') - { - return 0; - } - - /* Convert digits */ - long value = 0; - while (*str >= '0' && *str <= '9') - { - int digit = *str - '0'; - - /* Special case for LONG_MIN: -9223372036854775808 */ - if (sign == -1 && value == LONG_MAX / 10 && digit > LONG_MAX % 10 + 1) - { - return 0; - } - - /* Special case for LONG_MAX: 9223372036854775807 */ - if (sign == 1 && value == LONG_MAX / 10 && digit > LONG_MAX % 10) - { - return 0; - } - - /* General overflow check */ - if (value > LONG_MAX / 10) - { - return 0; - } - - value = value * 10 + digit; - str++; - } - - *result = sign * value; - return 1; -} - -/** - * @brief Safe string to double conversion with error handling - * - * @param str String to convert - * @param result Pointer to store the converted double value - * @return int 1 on success, 0 on failure - * - * @note Improvements over standard atof: - * 1. Proper error handling (returns success/failure status) - * 2. Handles NULL pointer input safely - * 3. Better validation of input string format - * 4. More precise error detection - * - * @safety Safe against NULL pointers, validates input format - */ -int etk_atof(const char *str, double *result) -{ - /* Handle edge cases */ - if (!str || !result) - { - return 0; - } - - /* Skip whitespace */ - while (*str == ' ' || *str == '\t' || *str == '\n' || *str == '\r') - { - str++; - } - - /* Handle empty string */ - if (*str == '\0') - { - return 0; - } - - /* Handle sign */ - double sign = 1.0; - if (*str == '-') - { - sign = -1.0; - str++; - } - else if (*str == '+') - { - str++; - } - - /* Check if we have digits or decimal point */ - if ((*str < '0' || *str > '9') && *str != '.') - { - return 0; - } - - /* Convert integer part */ - double value = 0.0; - int has_digits = 0; - while (*str >= '0' && *str <= '9') - { - value = value * 10.0 + (*str - '0'); - str++; - has_digits = 1; - } - - /* Convert fractional part */ - if (*str == '.') - { - str++; - double fraction = 0.0; - double divisor = 10.0; - - while (*str >= '0' && *str <= '9') - { - fraction += (*str - '0') / divisor; - divisor *= 10.0; - str++; - has_digits = 1; - } - - value += fraction; - } - - /* Must have at least one digit in either integer or fractional part */ - if (!has_digits) - { - return 0; - } - - /* Handle exponent */ - if (*str == 'e' || *str == 'E') - { - str++; - int exp_sign = 1; - - if (*str == '-') - { - exp_sign = -1; - str++; - } - else if (*str == '+') - { - str++; - } - - /* Check if we have exponent digits */ - if (*str < '0' || *str > '9') - { - return 0; - } - - int exponent = 0; - while (*str >= '0' && *str <= '9') - { - exponent = exponent * 10 + (*str - '0'); - str++; - } - - /* Apply exponent */ - if (exp_sign > 0) - { - while (exponent-- > 0) - { - value *= 10.0; - } - } - else - { - while (exponent-- > 0) - { - value /= 10.0; - } - } - } - - /* Check if we've reached the end of the string (strict validation) */ - if (*str != '\0') - { - return 0; - } - - *result = sign * value; - return 1; -} - -/** - * @brief Safe string copy function that replaces dangerous strcpy - * - * This function provides a secure alternative to strcpy by adding buffer - * size checking and NULL pointer safety. - * - * @param dest Destination buffer where the content is to be copied - * @param src Source string to be copied - * @param dest_size Size of the destination buffer (including null terminator) - * @return char* Pointer to the destination buffer, or NULL if error - * - * @note Unlike strcpy, this function checks buffer size and returns NULL - * if the destination is too small to hold the source string. - */ -char *etk_strcpy(char *dest, const char *src, size_t dest_size) -{ - /* Handle edge cases: NULL pointers or zero buffer size */ - if (dest == NULL || src == NULL || dest_size == 0) - { - return NULL; - } - - size_t src_len = 0; - - /* Calculate source string length */ - while (src[src_len] != '\0' && src_len < dest_size) - { - src_len++; - } - - /* Check if destination buffer is large enough */ - if (src_len >= dest_size) - { - return NULL; /* Buffer too small */ - } - - /* Copy the string */ - for (size_t i = 0; i < src_len; i++) - { - dest[i] = src[i]; - } - - /* Ensure null termination */ - dest[src_len] = '\0'; - - return dest; -} - -/** - * @brief Safe string concatenation function that replaces dangerous strcat - * - * This function provides a secure alternative to strcat by checking remaining - * buffer space and handling edge cases safely. - * - * @param dest Destination buffer to append to - * @param src Source string to append - * @param dest_size Total size of destination buffer (including null terminator) - * @return char* Pointer to the destination buffer, or NULL if error - * - * @note This function checks remaining space in destination buffer and - * returns NULL if there's insufficient space for concatenation. - */ -char *etk_strcat(char *dest, const char *src, size_t dest_size) -{ - /* Handle edge cases: NULL pointers or zero buffer size */ - if (dest == NULL || src == NULL || dest_size == 0) - { - return NULL; - } - - size_t dest_len = 0; - - /* Find end of destination string */ - while (dest[dest_len] != '\0' && dest_len < dest_size) - { - dest_len++; - } - - /* Check if destination string is properly terminated */ - if (dest_len >= dest_size) - { - return NULL; /* Destination not null-terminated */ - } - - size_t src_len = 0; - size_t remaining_space = dest_size - dest_len - 1; /* -1 for null terminator */ - - /* Calculate complete source string length */ - while (src[src_len] != '\0') - { - src_len++; - } - - /* Check if remaining space is sufficient */ - if (src_len > remaining_space) - { - return NULL; /* Insufficient space */ - } - - /* Append source to destination */ - for (size_t i = 0; i < src_len; i++) - { - dest[dest_len + i] = src[i]; - } - - /* Ensure null termination */ - dest[dest_len + src_len] = '\0'; - - return dest; -} - -/** - * @brief Safe string length function with maximum length limit - * - * This function provides a secure alternative to strlen by adding a maximum - * length limit to prevent infinite loops on malformed strings. - * - * @param str String to measure - * @param max_len Maximum length to check - * @return size_t Length of string, or max_len if string is longer - * - * @note This function will not loop infinitely on non-null-terminated - * strings, making it safe for use with untrusted input. - */ -size_t etk_strlen(const char *str, size_t max_len) -{ - /* Handle NULL pointer input */ - if (str == NULL) - { - return 0; - } - - size_t len = 0; - - /* Count characters up to max_len or null terminator */ - while (len < max_len && str[len] != '\0') - { - len++; - } - - return len; -} diff --git a/etk/src/utils/ringbuffer/LICENSE b/etk/src/utils/ringbuffer/LICENSE deleted file mode 100644 index 0ad25db..0000000 --- a/etk/src/utils/ringbuffer/LICENSE +++ /dev/null @@ -1,661 +0,0 @@ - GNU AFFERO GENERAL PUBLIC LICENSE - Version 3, 19 November 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU Affero General Public License is a free, copyleft license for -software and other kinds of works, specifically designed to ensure -cooperation with the community in the case of network server software. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -our General Public Licenses are intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - Developers that use our General Public Licenses protect your rights -with two steps: (1) assert copyright on the software, and (2) offer -you this License which gives you legal permission to copy, distribute -and/or modify the software. - - A secondary benefit of defending all users' freedom is that -improvements made in alternate versions of the program, if they -receive widespread use, become available for other developers to -incorporate. Many developers of free software are heartened and -encouraged by the resulting cooperation. However, in the case of -software used on network servers, this result may fail to come about. -The GNU General Public License permits making a modified version and -letting the public access it on a server without ever releasing its -source code to the public. - - The GNU Affero General Public License is designed specifically to -ensure that, in such cases, the modified source code becomes available -to the community. It requires the operator of a network server to -provide the source code of the modified version running there to the -users of that server. Therefore, public use of a modified version, on -a publicly accessible server, gives the public access to the source -code of the modified version. - - An older license, called the Affero General Public License and -published by Affero, was designed to accomplish similar goals. This is -a different license, not a version of the Affero GPL, but Affero has -released a new version of the Affero GPL which permits relicensing under -this license. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU Affero General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Remote Network Interaction; Use with the GNU General Public License. - - Notwithstanding any other provision of this License, if you modify the -Program, your modified version must prominently offer all users -interacting with it remotely through a computer network (if your version -supports such interaction) an opportunity to receive the Corresponding -Source of your version by providing access to the Corresponding Source -from a network server at no charge, through some standard or customary -means of facilitating copying of software. This Corresponding Source -shall include the Corresponding Source for any work covered by version 3 -of the GNU General Public License that is incorporated pursuant to the -following paragraph. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the work with which it is combined will remain governed by version -3 of the GNU General Public License. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU Affero General Public License from time to time. Such new versions -will be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU Affero General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU Affero General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU Affero General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If your software can interact with users remotely through a computer -network, you should also make sure that it provides a way for users to -get its source. For example, if your program is a web application, its -interface could display a "Source" link that leads users to an archive -of the code. There are many ways you could offer source, and different -solutions will be better for different programs; see section 13 for the -specific requirements. - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU AGPL, see -. diff --git a/polarimeter.ioc b/polarimeter.ioc index c9976cd..2eb7701 100644 --- a/polarimeter.ioc +++ b/polarimeter.ioc @@ -1,31 +1,36 @@ #MicroXplorer Configuration settings - do not modify -ADC1.Channel-2\#ChannelRegularConversion=ADC_CHANNEL_10 -ADC1.ContinuousConvMode=DISABLE -ADC1.EnableInjectedConversion=DISABLE -ADC1.EnableRegularConversion=ENABLE -ADC1.ExternalTrigConv=ADC_EXTERNALTRIGCONV_T3_TRGO -ADC1.IPParameters=ContinuousConvMode,EnableRegularConversion,EnableInjectedConversion,InjNumberOfConversion,Rank-2\#ChannelRegularConversion,Channel-2\#ChannelRegularConversion,SamplingTime-2\#ChannelRegularConversion,NbrOfConversionFlag,master,ExternalTrigConv -ADC1.InjNumberOfConversion=0 +ADC1.Channel-3\#ChannelRegularConversion=ADC_CHANNEL_11 +ADC1.IPParameters=Rank-3\#ChannelRegularConversion,master,Channel-3\#ChannelRegularConversion,SamplingTime-3\#ChannelRegularConversion,NbrOfConversionFlag ADC1.NbrOfConversionFlag=1 -ADC1.Rank-2\#ChannelRegularConversion=1 -ADC1.SamplingTime-2\#ChannelRegularConversion=ADC_SAMPLETIME_1CYCLE_5 +ADC1.Rank-3\#ChannelRegularConversion=1 +ADC1.SamplingTime-3\#ChannelRegularConversion=ADC_SAMPLETIME_1CYCLE_5 ADC1.master=1 CAD.formats=[] CAD.pinconfig=Dual CAD.provider= -Dma.ADC1.0.Direction=DMA_PERIPH_TO_MEMORY -Dma.ADC1.0.Instance=DMA1_Channel1 -Dma.ADC1.0.MemDataAlignment=DMA_MDATAALIGN_HALFWORD -Dma.ADC1.0.MemInc=DMA_MINC_ENABLE -Dma.ADC1.0.Mode=DMA_CIRCULAR -Dma.ADC1.0.PeriphDataAlignment=DMA_PDATAALIGN_HALFWORD -Dma.ADC1.0.PeriphInc=DMA_PINC_DISABLE -Dma.ADC1.0.Priority=DMA_PRIORITY_VERY_HIGH -Dma.ADC1.0.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority -Dma.Request0=ADC1 -Dma.RequestsNb=1 +Dma.Request0=SPI2_RX +Dma.Request1=SPI2_TX +Dma.RequestsNb=2 +Dma.SPI2_RX.0.Direction=DMA_PERIPH_TO_MEMORY +Dma.SPI2_RX.0.Instance=DMA1_Channel4 +Dma.SPI2_RX.0.MemDataAlignment=DMA_MDATAALIGN_HALFWORD +Dma.SPI2_RX.0.MemInc=DMA_MINC_ENABLE +Dma.SPI2_RX.0.Mode=DMA_NORMAL +Dma.SPI2_RX.0.PeriphDataAlignment=DMA_PDATAALIGN_HALFWORD +Dma.SPI2_RX.0.PeriphInc=DMA_PINC_DISABLE +Dma.SPI2_RX.0.Priority=DMA_PRIORITY_HIGH +Dma.SPI2_RX.0.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority +Dma.SPI2_TX.1.Direction=DMA_MEMORY_TO_PERIPH +Dma.SPI2_TX.1.Instance=DMA1_Channel5 +Dma.SPI2_TX.1.MemDataAlignment=DMA_MDATAALIGN_HALFWORD +Dma.SPI2_TX.1.MemInc=DMA_MINC_ENABLE +Dma.SPI2_TX.1.Mode=DMA_NORMAL +Dma.SPI2_TX.1.PeriphDataAlignment=DMA_PDATAALIGN_HALFWORD +Dma.SPI2_TX.1.PeriphInc=DMA_PINC_DISABLE +Dma.SPI2_TX.1.Priority=DMA_PRIORITY_HIGH +Dma.SPI2_TX.1.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority File.Version=6 -GPIO.groupedBy=Group By Peripherals +GPIO.groupedBy=Expand Peripherals I2C2.GeneralCallMode=I2C_GENERALCALL_ENABLE I2C2.IPParameters=GeneralCallMode KeepUserPlacement=false @@ -33,7 +38,7 @@ Mcu.CPN=STM32F103ZET6 Mcu.Family=STM32F1 Mcu.IP0=ADC1 Mcu.IP1=DMA -Mcu.IP10=TIM4 +Mcu.IP10=TIM3 Mcu.IP11=UART5 Mcu.IP12=USART1 Mcu.IP13=USART2 @@ -41,58 +46,64 @@ Mcu.IP14=USART3 Mcu.IP2=I2C2 Mcu.IP3=NVIC Mcu.IP4=RCC -Mcu.IP5=SPI3 -Mcu.IP6=SYS -Mcu.IP7=TIM1 -Mcu.IP8=TIM2 -Mcu.IP9=TIM3 +Mcu.IP5=SPI2 +Mcu.IP6=SPI3 +Mcu.IP7=SYS +Mcu.IP8=TIM1 +Mcu.IP9=TIM2 Mcu.IPNb=15 Mcu.Name=STM32F103Z(C-D-E)Tx Mcu.Package=LQFP144 Mcu.Pin0=PE5 Mcu.Pin1=PE6 -Mcu.Pin10=PA3 -Mcu.Pin11=PB10 -Mcu.Pin12=PB11 -Mcu.Pin13=PB13 -Mcu.Pin14=PD15 -Mcu.Pin15=PA8 -Mcu.Pin16=PA9 -Mcu.Pin17=PA10 -Mcu.Pin18=PA13 -Mcu.Pin19=PA14 +Mcu.Pin10=PA2 +Mcu.Pin11=PA3 +Mcu.Pin12=PA6 +Mcu.Pin13=PA7 +Mcu.Pin14=PB0 +Mcu.Pin15=PB10 +Mcu.Pin16=PB11 +Mcu.Pin17=PB13 +Mcu.Pin18=PB14 +Mcu.Pin19=PB15 Mcu.Pin2=PC14-OSC32_IN -Mcu.Pin20=PC10 -Mcu.Pin21=PC11 -Mcu.Pin22=PC12 -Mcu.Pin23=PD2 -Mcu.Pin24=PD5 -Mcu.Pin25=PB3 -Mcu.Pin26=PB4 -Mcu.Pin27=PB5 -Mcu.Pin28=PB7 -Mcu.Pin29=VP_SYS_VS_tim8 +Mcu.Pin20=PD15 +Mcu.Pin21=PA8 +Mcu.Pin22=PA9 +Mcu.Pin23=PA10 +Mcu.Pin24=PA13 +Mcu.Pin25=PA14 +Mcu.Pin26=PC10 +Mcu.Pin27=PC11 +Mcu.Pin28=PC12 +Mcu.Pin29=PD2 Mcu.Pin3=PC15-OSC32_OUT -Mcu.Pin30=VP_TIM3_VS_ClockSourceINT -Mcu.Pin31=VP_TIM4_VS_ClockSourceINT -Mcu.Pin32=VP_RealThread.X-CUBE-RT-Thread_Nano_VS_RTOSJjRTAaThread_4.1.1_4.1.1 -Mcu.Pin33=VP_STMicroelectronics.X-CUBE-ALGOBUILD_VS_DSPOoLibraryJjLibrary_1.4.0_1.4.0 -Mcu.Pin4=OSC_IN -Mcu.Pin5=OSC_OUT -Mcu.Pin6=PC0 -Mcu.Pin7=PA0-WKUP -Mcu.Pin8=PA1 -Mcu.Pin9=PA2 -Mcu.PinsNb=34 +Mcu.Pin30=PD5 +Mcu.Pin31=PB3 +Mcu.Pin32=PB4 +Mcu.Pin33=PB5 +Mcu.Pin34=PB7 +Mcu.Pin35=VP_SYS_VS_tim8 +Mcu.Pin36=VP_TIM3_VS_ClockSourceINT +Mcu.Pin37=VP_RealThread.X-CUBE-RT-Thread_Nano_VS_RTOSJjRTAaThread_4.1.1_4.1.1 +Mcu.Pin38=VP_STMicroelectronics.X-CUBE-ALGOBUILD_VS_DSPOoLibraryJjLibrary_1.4.0_1.4.0 +Mcu.Pin4=PF1 +Mcu.Pin5=OSC_IN +Mcu.Pin6=OSC_OUT +Mcu.Pin7=PC1 +Mcu.Pin8=PA0-WKUP +Mcu.Pin9=PA1 +Mcu.PinsNb=39 Mcu.ThirdParty0=RealThread.X-CUBE-RT-Thread_Nano.4.1.1 Mcu.ThirdParty1=STMicroelectronics.X-CUBE-ALGOBUILD.1.4.0 Mcu.ThirdPartyNb=2 -Mcu.UserConstants=TEC_DEAD_TIME,100;AD7793_SPI,$$_SPI3_IP_HANDLE_$$;RS485_COM,$$_UART5_IP_HANDLE_$$;TEC_TIM_COUNTER,143;SAMPLING_TIM_PRE,71;US_TIM_PERIOD_COUNT,9999;TEC_TIM_PRESCALER,99;TEC_TIM,$$_TIM1_IP_HANDLE_$$;HMI_COM,$$_USART2_IP_HANDLE_$$;SAMPLING_TIM,$$_TIM3_IP_HANDLE_$$;US_TIM_PRE,71;TIMESTAMP_TIM,$$_TIM4_IP_HANDLE_$$;ENCODER_TIM,$$_TIM2_IP_HANDLE_$$;SAMPLING_TIM_PERIOD_COUNT,877;SERVO_COM,$$_USART3_IP_HANDLE_$$;LIGHT_ADC,$$_ADC1_IP_HANDLE_$$;ENCODER_MAX_COUNT,65535 +Mcu.UserConstants=HMI_COM,$$_USART2_IP_HANDLE_$$;ENCODER_MAX_COUNT,65535;AD7793_SPI,$$_SPI3_IP_HANDLE_$$;US_TIM_PRE,71;RS485_COM,$$_UART5_IP_HANDLE_$$;ENCODER_TIM,$$_TIM2_IP_HANDLE_$$;TEC_TIM_COUNTER,143;US_TIM_PERIOD_COUNT,9999;TEC_TIM_PRESCALER,99;SERVO_COM,$$_USART3_IP_HANDLE_$$;TEC_TIM,$$_TIM1_IP_HANDLE_$$;COLLECT_TIM,$$_TIM3_IP_HANDLE_$$;ADS8866_SPI,$$_SPI2_IP_HANDLE_$$ Mcu.UserName=STM32F103ZETx MxCube.Version=6.15.0 MxDb.Version=DB.6.0.150 NVIC.BusFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false\:false -NVIC.DMA1_Channel1_IRQn=true\:0\:0\:false\:false\:true\:true\:false\:true\:true +NVIC.DMA1_Channel4_IRQn=true\:0\:0\:false\:false\:true\:true\:false\:true\:true +NVIC.DMA1_Channel5_IRQn=true\:0\:0\:false\:false\:true\:true\:false\:true\:true NVIC.DebugMonitor_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false\:false NVIC.ForceEnableDMAVector=true NVIC.HardFault_IRQn=true\:0\:0\:false\:false\:false\:false\:false\:false\:false @@ -107,7 +118,6 @@ NVIC.SavedSystickIrqHandlerGenerated=false NVIC.SysTick_IRQn=true\:0\:0\:false\:false\:false\:false\:false\:true\:false NVIC.TIM2_IRQn=true\:0\:0\:false\:false\:true\:false\:true\:true\:true NVIC.TIM3_IRQn=true\:0\:0\:false\:false\:true\:false\:true\:true\:true -NVIC.TIM4_IRQn=true\:0\:0\:false\:false\:true\:false\:true\:true\:true NVIC.TIM8_UP_IRQn=true\:15\:0\:false\:false\:true\:false\:false\:true\:true NVIC.TimeBase=TIM8_UP_IRQn NVIC.TimeBaseIP=TIM8 @@ -142,9 +152,16 @@ PA3.GPIOParameters=GPIO_Label PA3.GPIO_Label=UART2_RX_LCD PA3.Mode=Asynchronous PA3.Signal=USART2_RX -PA8.GPIOParameters=GPIO_Speed,GPIO_Label -PA8.GPIO_Label=TIM1_CH1_TEC -PA8.GPIO_Speed=GPIO_SPEED_FREQ_HIGH +PA6.GPIOParameters=GPIO_Label +PA6.GPIO_Label=TEC_LEFT_SD +PA6.Locked=true +PA6.Signal=GPIO_Output +PA7.GPIOParameters=GPIO_Label +PA7.GPIO_Label=TEC_RIGHT_SD +PA7.Locked=true +PA7.Signal=GPIO_Output +PA8.GPIOParameters=GPIO_Label +PA8.GPIO_Label=TEC_RIGHT_IN PA8.Locked=true PA8.Signal=S_TIM1_CH1 PA9.GPIOParameters=GPIO_Label @@ -152,6 +169,10 @@ PA9.GPIO_Label=UART1_LCD_TX PA9.Locked=true PA9.Mode=Asynchronous PA9.Signal=USART1_TX +PB0.GPIOParameters=GPIO_Label +PB0.GPIO_Label=ADS8866_CONVST +PB0.Locked=true +PB0.Signal=S_TIM3_CH3 PB10.GPIOParameters=GPIO_Label PB10.GPIO_Label=I2C2_EEPROM_SCL PB10.Locked=true @@ -162,30 +183,36 @@ PB11.GPIO_Label=I2C2_EEPROM_SDA PB11.Locked=true PB11.Mode=I2C PB11.Signal=I2C2_SDA -PB13.GPIOParameters=GPIO_Speed,GPIO_Label -PB13.GPIO_Label=TIM1_CH1N_TEC -PB13.GPIO_Speed=GPIO_SPEED_FREQ_HIGH -PB13.Locked=true -PB13.Mode=PWM Generation1 CH1 CH1N -PB13.Signal=TIM1_CH1N +PB13.GPIOParameters=GPIO_Label +PB13.GPIO_Label=SPI2_ADS8866_SCK +PB13.Mode=Full_Duplex_Master +PB13.Signal=SPI2_SCK +PB14.GPIOParameters=GPIO_Label +PB14.GPIO_Label=SPI2_ADS8866_MISO +PB14.Mode=Full_Duplex_Master +PB14.Signal=SPI2_MISO +PB15.GPIOParameters=GPIO_Label +PB15.GPIO_Label=SPI2_ADS8866_MOSI +PB15.Mode=Full_Duplex_Master +PB15.Signal=SPI2_MOSI PB3.GPIOParameters=GPIO_Label -PB3.GPIO_Label=SPI3_SCK_AD7793 +PB3.GPIO_Label=SPI3_AD7793_SCK PB3.Mode=Full_Duplex_Master PB3.Signal=SPI3_SCK PB4.GPIOParameters=GPIO_Label -PB4.GPIO_Label=SPI3_MISO_AD7793 +PB4.GPIO_Label=SPI3_AD7793_MISO PB4.Mode=Full_Duplex_Master PB4.Signal=SPI3_MISO PB5.GPIOParameters=GPIO_Label -PB5.GPIO_Label=SPI3_MOSI_AD7793 +PB5.GPIO_Label=SPI3_AD7793_MOSI PB5.Mode=Full_Duplex_Master PB5.Signal=SPI3_MOSI PB7.GPIOParameters=GPIO_Label -PB7.GPIO_Label=SPI3_CS_AD7793 +PB7.GPIO_Label=SPI3_AD7793_CS PB7.Locked=true PB7.Signal=GPIO_Output -PC0.Locked=true -PC0.Signal=ADCx_IN10 +PC1.Locked=true +PC1.Signal=ADCx_IN11 PC10.GPIOParameters=GPIO_Label PC10.GPIO_Label=UART3_SERVO_TX PC10.Locked=true @@ -229,6 +256,10 @@ PE6.GPIO_Label=PE6_LED2 PE6.Locked=true PE6.PinState=GPIO_PIN_SET PE6.Signal=GPIO_Output +PF1.GPIOParameters=GPIO_Label +PF1.GPIO_Label=RS485_DE +PF1.Locked=true +PF1.Signal=GPIO_Output PinOutPanel.RotationAngle=0 ProjectManager.AskForMigrate=true ProjectManager.BackupPrevious=false @@ -263,7 +294,7 @@ ProjectManager.ToolChainLocation= ProjectManager.UAScriptAfterPath= ProjectManager.UAScriptBeforePath= ProjectManager.UnderRoot=false -ProjectManager.functionlistsort=1-SystemClock_Config-RCC-true-HAL-false,2-MX_GPIO_Init-GPIO-true-HAL-true,3-MX_DMA_Init-DMA-false-HAL-true,4-MX_I2C2_Init-I2C2-true-HAL-true,5-MX_USART1_UART_Init-USART1-true-HAL-true,6-MX_USART2_UART_Init-USART2-true-HAL-true,7-MX_UART5_Init-UART5-true-HAL-true,8-MX_USART3_UART_Init-USART3-true-HAL-true,9-MX_TIM1_Init-TIM1-true-HAL-true,10-MX_SPI3_Init-SPI3-true-HAL-true,11-MX_ADC1_Init-ADC1-true-HAL-true,12-MX_TIM2_Init-TIM2-true-HAL-true,13-MX_TIM3_Init-TIM3-true-HAL-true,14-MX_TIM4_Init-TIM4-true-HAL-true +ProjectManager.functionlistsort=1-SystemClock_Config-RCC-true-HAL-false,2-MX_GPIO_Init-GPIO-true-HAL-true,3-MX_DMA_Init-DMA-true-HAL-true,4-MX_I2C2_Init-I2C2-true-HAL-true,5-MX_USART1_UART_Init-USART1-true-HAL-true,6-MX_USART2_UART_Init-USART2-true-HAL-true,7-MX_UART5_Init-UART5-true-HAL-true,8-MX_USART3_UART_Init-USART3-true-HAL-true,9-MX_SPI3_Init-SPI3-true-HAL-true,10-MX_ADC1_Init-ADC1-true-HAL-true,11-MX_TIM2_Init-TIM2-true-HAL-true,12-MX_TIM3_Init-TIM3-true-HAL-true,13-MX_SPI2_Init-SPI2-true-HAL-true,14-MX_TIM1_Init-TIM1-true-HAL-true RCC.ADCFreqValue=12000000 RCC.ADCPresc=RCC_ADCPCLK2_DIV6 RCC.AHBFreq_Value=72000000 @@ -307,14 +338,24 @@ RealThread.X-CUBE-RT-Thread_Nano.4.1.1.RT_USING_SIGNALS=0 RealThread.X-CUBE-RT-Thread_Nano.4.1.1.RT_USING_SMALL_MEM=1 RealThread.X-CUBE-RT-Thread_Nano.4.1.1.RT_USING_SMALL_MEM_AS_HEAP=1 RealThread.X-CUBE-RT-Thread_Nano.4.1.1_SwParameter=RTAaThreadCcRTOSJjshell\:true;RTAaThreadCcRTOSJjlibcpu\:true;RTAaThreadCcRTOSJjkernel\:true; -SH.ADCx_IN10.0=ADC1_IN10,IN10 -SH.ADCx_IN10.ConfNb=1 -SH.S_TIM1_CH1.0=TIM1_CH1,PWM Generation1 CH1 CH1N +SH.ADCx_IN11.0=ADC1_IN11,IN11 +SH.ADCx_IN11.ConfNb=1 +SH.S_TIM1_CH1.0=TIM1_CH1,PWM Generation1 CH1 SH.S_TIM1_CH1.ConfNb=1 SH.S_TIM2_CH1_ETR.0=TIM2_CH1,Encoder_Interface SH.S_TIM2_CH1_ETR.ConfNb=1 SH.S_TIM2_CH2.0=TIM2_CH2,Encoder_Interface SH.S_TIM2_CH2.ConfNb=1 +SH.S_TIM3_CH3.0=TIM3_CH3,PWM Generation3 CH3 +SH.S_TIM3_CH3.ConfNb=1 +SPI2.BaudRatePrescaler=SPI_BAUDRATEPRESCALER_16 +SPI2.CLKPhase=SPI_PHASE_2EDGE +SPI2.CalculateBaudRate=2.25 MBits/s +SPI2.DataSize=SPI_DATASIZE_16BIT +SPI2.Direction=SPI_DIRECTION_2LINES +SPI2.IPParameters=VirtualType,Mode,Direction,CalculateBaudRate,DataSize,CLKPhase,BaudRatePrescaler +SPI2.Mode=SPI_MODE_MASTER +SPI2.VirtualType=VM_MASTER SPI3.BaudRatePrescaler=SPI_BAUDRATEPRESCALER_16 SPI3.CLKPhase=SPI_PHASE_2EDGE SPI3.CLKPolarity=SPI_POLARITY_HIGH @@ -327,14 +368,11 @@ STMicroelectronics.X-CUBE-ALGOBUILD.1.4.0.DSPOoLibraryJjLibrary_Checked=true STMicroelectronics.X-CUBE-ALGOBUILD.1.4.0.IPParameters=LibraryCcDSPOoLibraryJjDSPOoLibrary STMicroelectronics.X-CUBE-ALGOBUILD.1.4.0.LibraryCcDSPOoLibraryJjDSPOoLibrary=true STMicroelectronics.X-CUBE-ALGOBUILD.1.4.0_SwParameter=LibraryCcDSPOoLibraryJjDSPOoLibrary\:true; -TIM1.AutoReloadPreload=TIM_AUTORELOAD_PRELOAD_ENABLE -TIM1.Channel-PWM\ Generation1\ CH1\ CH1N=TIM_CHANNEL_1 -TIM1.DeadTime=TEC_DEAD_TIME -TIM1.IPParameters=Channel-PWM Generation1 CH1 CH1N,Period,Prescaler,AutoReloadPreload,DeadTime,OCNPolarity_1,OCNIdleState_1 -TIM1.OCNIdleState_1=TIM_OCNIDLESTATE_RESET -TIM1.OCNPolarity_1=TIM_OCNPOLARITY_HIGH -TIM1.Period=TEC_TIM_COUNTER -TIM1.Prescaler=TEC_TIM_PRESCALER +TIM1.Channel-PWM\ Generation1\ CH1=TIM_CHANNEL_1 +TIM1.IPParameters=Prescaler,Period,Channel-PWM Generation1 CH1,Pulse-PWM Generation1 CH1 +TIM1.Period=899 +TIM1.Prescaler=7 +TIM1.Pulse-PWM\ Generation1\ CH1=100 TIM2.AutoReloadPreload=TIM_AUTORELOAD_PRELOAD_ENABLE TIM2.EncoderMode=TIM_ENCODERMODE_TI12 TIM2.IC1Filter=6 @@ -344,13 +382,11 @@ TIM2.Period=ENCODER_MAX_COUNT TIM2.TIM_MasterOutputTrigger=TIM_TRGO_RESET TIM2.TIM_MasterSlaveMode=TIM_MASTERSLAVEMODE_DISABLE TIM3.AutoReloadPreload=TIM_AUTORELOAD_PRELOAD_ENABLE -TIM3.IPParameters=Prescaler,Period,AutoReloadPreload -TIM3.Period=SAMPLING_TIM_PERIOD_COUNT -TIM3.Prescaler=SAMPLING_TIM_PRE -TIM4.AutoReloadPreload=TIM_AUTORELOAD_PRELOAD_ENABLE -TIM4.IPParameters=Prescaler,AutoReloadPreload,Period -TIM4.Period=US_TIM_PERIOD_COUNT -TIM4.Prescaler=US_TIM_PRE +TIM3.Channel-PWM\ Generation3\ CH3=TIM_CHANNEL_3 +TIM3.IPParameters=Prescaler,Period,AutoReloadPreload,Channel-PWM Generation3 CH3,Pulse-PWM Generation3 CH3 +TIM3.Period=499 +TIM3.Prescaler=71 +TIM3.Pulse-PWM\ Generation3\ CH3=10 UART5.BaudRate=9600 UART5.IPParameters=VirtualMode,BaudRate UART5.VirtualMode=Asynchronous @@ -369,6 +405,4 @@ VP_SYS_VS_tim8.Mode=TIM8 VP_SYS_VS_tim8.Signal=SYS_VS_tim8 VP_TIM3_VS_ClockSourceINT.Mode=Internal VP_TIM3_VS_ClockSourceINT.Signal=TIM3_VS_ClockSourceINT -VP_TIM4_VS_ClockSourceINT.Mode=Internal -VP_TIM4_VS_ClockSourceINT.Signal=TIM4_VS_ClockSourceINT board=custom