移植适配新硬件ver3,做了一些优化喝结构调整
This commit is contained in:
parent
03497abc7f
commit
003e11c96a
131
CMakeLists.txt
131
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
|
||||
)
|
||||
|
||||
@ -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 */
|
||||
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -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);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -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 <rtthread.h>
|
||||
#include "et_log.h"
|
||||
#include "bsp_collect.h"
|
||||
/* USER CODE END Includes */
|
||||
|
||||
/* Private typedef -----------------------------------------------------------*/
|
||||
@ -68,6 +68,7 @@ void SystemClock_Config(void);
|
||||
*/
|
||||
int main(void)
|
||||
{
|
||||
|
||||
/* USER CODE BEGIN 1 */
|
||||
|
||||
/* USER CODE END 1 */
|
||||
@ -86,7 +87,6 @@ int main(void)
|
||||
/* USER CODE END SysInit */
|
||||
|
||||
/* Initialize all configured peripherals */
|
||||
|
||||
/* USER CODE BEGIN 2 */
|
||||
et_log_init(DEBUG_LEVEL, false, true);
|
||||
pm_device_init(&pm_device);
|
||||
@ -94,18 +94,17 @@ int main(void)
|
||||
|
||||
/* Infinite loop */
|
||||
/* USER CODE BEGIN WHILE */
|
||||
pm_device_start(&pm_device);
|
||||
//pm_device_start(&pm_device);
|
||||
while (1)
|
||||
{
|
||||
/* USER CODE END WHILE */
|
||||
|
||||
/* USER CODE BEGIN 3 */
|
||||
rt_thread_mdelay(1000);
|
||||
//pm_lcd_cmd_send("TEST\r\n", 6);
|
||||
#if (TEST_ENCODER_PLUSE == 1)
|
||||
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 */
|
||||
}
|
||||
@ -137,7 +136,8 @@ void SystemClock_Config(void)
|
||||
|
||||
/** 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.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;
|
||||
@ -177,13 +177,6 @@ void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
|
||||
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
|
||||
}
|
||||
#if (USING_SOFT_ENCODER == 0)
|
||||
if (htim->Instance == ENCODER_TIM.Instance)
|
||||
{
|
||||
@ -194,12 +187,10 @@ 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();
|
||||
sampling_tim_elapsed_callback();
|
||||
}
|
||||
/* USER CODE END Callback 1 */
|
||||
}
|
||||
@ -213,6 +204,7 @@ void Error_Handler(void)
|
||||
/* 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 */
|
||||
}
|
||||
|
||||
130
Core/Src/spi.c
130
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 */
|
||||
|
||||
|
||||
@ -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.
|
||||
*/
|
||||
|
||||
133
Core/Src/tim.c
133
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 */
|
||||
|
||||
79
User/app/bsp_debug.c
Normal file
79
User/app/bsp_debug.c
Normal file
@ -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 <rtthread.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
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 <duty_cycle>\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 <duty_cycle>\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");
|
||||
@ -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");
|
||||
|
||||
@ -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 <stdlib.h>
|
||||
#include <string.h>
|
||||
#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)
|
||||
{
|
||||
__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
|
||||
();
|
||||
//bsp_system_led_toggle();
|
||||
if (rt_mq_send(&adc_mq, &ptr, sizeof(ptr)) != RT_EOK)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
# 根据需要添加其他依赖
|
||||
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()
|
||||
@ -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;
|
||||
|
||||
@ -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"
|
||||
|
||||
|
||||
@ -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:
|
||||
*/
|
||||
|
||||
@ -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 <rtthread.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -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,8 +9,6 @@
|
||||
#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 <float.h>
|
||||
#include <rtthread.h>
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -554,5 +561,6 @@ 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;
|
||||
fsm->fz_fsm_state = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -2,15 +2,15 @@
|
||||
#include <stdarg.h>
|
||||
#include <rthw.h>
|
||||
#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)
|
||||
{
|
||||
|
||||
@ -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 <math.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h> /* 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;
|
||||
|
||||
#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);
|
||||
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;
|
||||
}
|
||||
|
||||
@ -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 <rtthread.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#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);
|
||||
|
||||
|
||||
230
User/board/bsp_collect.c
Normal file
230
User/board/bsp_collect.c
Normal file
@ -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 <rtthread.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
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 <count>\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; // 标记完成
|
||||
}
|
||||
}
|
||||
}
|
||||
21
User/board/bsp_collect.h
Normal file
21
User/board/bsp_collect.h
Normal file
@ -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 <stdint.h>
|
||||
|
||||
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__
|
||||
85
User/board/bsp_hmi.c
Normal file
85
User/board/bsp_hmi.c
Normal file
@ -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;
|
||||
}
|
||||
}
|
||||
21
User/board/bsp_hmi.h
Normal file
21
User/board/bsp_hmi.h
Normal file
@ -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 <stdint.h>
|
||||
|
||||
#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__
|
||||
121
User/board/bsp_misc.c
Normal file
121
User/board/bsp_misc.c
Normal file
@ -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 <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
40
User/board/bsp_misc.h
Normal file
40
User/board/bsp_misc.h
Normal file
@ -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 <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
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__
|
||||
82
User/board/bsp_motor.c
Normal file
82
User/board/bsp_motor.c
Normal file
@ -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;
|
||||
}
|
||||
}
|
||||
16
User/board/bsp_motor.h
Normal file
16
User/board/bsp_motor.h
Normal file
@ -0,0 +1,16 @@
|
||||
#ifndef __BSP_MOTOR_H__
|
||||
#define __BSP_MOTOR_H__
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
#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__
|
||||
177
User/board/bsp_tec.c
Normal file
177
User/board/bsp_tec.c
Normal file
@ -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();
|
||||
}
|
||||
|
||||
27
User/board/bsp_tec.h
Normal file
27
User/board/bsp_tec.h
Normal file
@ -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__
|
||||
140
User/board/bsp_temper_sampling.c
Normal file
140
User/board/bsp_temper_sampling.c
Normal file
@ -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
|
||||
}
|
||||
27
User/board/bsp_temper_sampling.h
Normal file
27
User/board/bsp_temper_sampling.h
Normal file
@ -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 <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
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
|
||||
@ -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 <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
@ -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 <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
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__
|
||||
@ -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后续的操作是读还是写,以及操作的目标寄存器是哪一个。
|
||||
@ -99,3 +156,59 @@ bool ad7793_write_reg(uint8_t reg, uint8_t *data, uint16_t len)
|
||||
3. **数据寄存器的特殊处理**:数据寄存器(REG_DATA)在读模式下有特殊的连续读功能,可以通过设置`CREAD`位来启用。
|
||||
|
||||
理解通信寄存器的工作原理对于正确操作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保护,防止异常数据影响温度计算。
|
||||
|
||||
---
|
||||
|
||||
如需更高分辨率或特殊应用,请根据实际输入信号幅度和参考电压合理调整增益与参考配置。
|
||||
@ -7,17 +7,20 @@
|
||||
*/
|
||||
#include "ad7793.h"
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef DEBUG
|
||||
#include <rtthread.h>
|
||||
#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);
|
||||
|
||||
@ -375,6 +411,7 @@ bool ad7793_set_reference(ad7793_dev_t *dev, bool use_internal, float external_r
|
||||
else
|
||||
{
|
||||
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);
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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__
|
||||
|
||||
@ -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__ */
|
||||
|
||||
@ -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})
|
||||
|
||||
|
||||
BIN
docs/hardware/pm_ver3.pdf
Normal file
BIN
docs/hardware/pm_ver3.pdf
Normal file
Binary file not shown.
BIN
docs/holding_registers.mbs
Normal file
BIN
docs/holding_registers.mbs
Normal file
Binary file not shown.
BIN
docs/input_registers.mbs
Normal file
BIN
docs/input_registers.mbs
Normal file
Binary file not shown.
BIN
docs/pm.msw
Normal file
BIN
docs/pm.msw
Normal file
Binary file not shown.
@ -1,67 +0,0 @@
|
||||
#ifndef __ETK_DIFF_H__
|
||||
#define __ETK_DIFF_H__
|
||||
#include "etk_utils.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#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
|
||||
@ -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;
|
||||
}
|
||||
@ -1,255 +0,0 @@
|
||||
|
||||
|
||||
#include "etk_diff.h"
|
||||
#include <math.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/**
|
||||
* @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
|
||||
@ -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
|
||||
|
||||
|
||||
@ -1,219 +0,0 @@
|
||||
#ifndef __ETK_STRING_H__
|
||||
#define __ETK_STRING_H__
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#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
|
||||
@ -1,860 +0,0 @@
|
||||
#include "etk_string.h"
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/**
|
||||
* @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;
|
||||
}
|
||||
@ -1,661 +0,0 @@
|
||||
GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
Version 3, 19 November 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
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.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
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
|
||||
<https://www.gnu.org/licenses/>.
|
||||
228
polarimeter.ioc
228
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
|
||||
|
||||
Loading…
Reference in New Issue
Block a user