/* * @Author: mypx * @Email: mypx_coder@163.com * @Date: 2025-06-19 12:29:17 * @LastEditors: mypx mypx_coder@163.com * @Description: */ #include "pm_board.h" #include "ad7793.h" #include "adc.h" #include "dma.h" #include "et_log.h" #include "gpio.h" #include "i2c.h" #include "rtdef.h" #include "rthw.h" #include "rtthread.h" #include "spi.h" #include "tim.h" #include "usart.h" #include #include #define AT24C128_I2C_ADDR 0xA0 #if (DEBUG_MB_ENABLE == 1) #define DBG_MB(...) ET_DBG("[MB] " __VA_ARGS__) #else #define DBG_MB(...) #endif volatile uint64_t timestamp_tim_overflow_count = 0; #if (USING_SOFT_SPI == 1) soft_spi_t soft_spi = { .sck_port = GPIOB, .sck_pin = GPIO_PIN_5, .mosi_port = GPIOB, .mosi_pin = GPIO_PIN_6, .miso_port = GPIOB, .miso_pin = GPIO_PIN_4, .cs_port = GPIOB, .cs_pin = GPIO_PIN_7, .mode = SOFT_SPI_MODE0, .bit_order = SOFT_SPI_MSB_FIRST, .lock = RT_NULL, // 使用 RT_NULL,初始化时会创建 .delay_us = 1, // 每半个 SPI 时钟周期延时 1 微秒 }; void pm_ad7793_spi_transfer(uint8_t *tx_buf, uint8_t *rx_buf, uint16_t len) { soft_spi_transfer_buffer(&soft_spi, tx_buf, rx_buf, len); } void pm_ad7793_spi_write(uint8_t cmd, uint8_t *data, uint16_t len) { soft_spi_write(&soft_spi, &cmd, 1, data, len); } void pm_ad7793_spi_read(uint8_t cmd, uint8_t *rx_buf, uint16_t len) { soft_spi_read(&soft_spi, &cmd, 1, rx_buf, len); } void pm_ad7793_gpio_set(uint8_t pin, bool state) { if (pin == soft_spi.cs_pin) { HAL_GPIO_WritePin(soft_spi.cs_port, soft_spi.cs_pin, state); } } bool pm_ad7793_gpio_get(uint8_t pin) { if (pin == soft_spi.miso_pin) { return HAL_GPIO_ReadPin(soft_spi.miso_port, soft_spi.miso_pin) == GPIO_PIN_SET; } return false; } #else #define AD7793_CS_LOW() HAL_GPIO_WritePin(AD7793_CS_GPIO_Port, AD7793_CS_Pin, GPIO_PIN_RESET) #define AD7793_CS_HIGH() HAL_GPIO_WritePin(AD7793_CS_GPIO_Port, AD7793_CS_Pin, GPIO_PIN_SET) void pm_ad7793_spi_transfer(uint8_t *tx_buf, uint8_t *rx_buf, uint16_t len) { HAL_StatusTypeDef status; status = HAL_SPI_TransmitReceive(&AD7793_SPI, tx_buf, rx_buf, len, 1000); if (status != HAL_OK) { ET_ERR("SPI transfer error:%d!", status); } } void pm_ad7793_spi_write(uint8_t cmd, uint8_t *data, uint16_t len) { uint8_t tx_buffer[256]; HAL_StatusTypeDef status; tx_buffer[0] = cmd; if (data && len > 0) { for (uint16_t i = 0; i < len; i++) { tx_buffer[i + 1] = data[i]; } } status = HAL_SPI_Transmit(&AD7793_SPI, tx_buffer, len + 1, 1000); if (status != HAL_OK) { ET_ERR("SPI write error:%d!", status); } } void pm_ad7793_spi_read(uint8_t cmd, uint8_t *rx_buf, uint16_t len) { uint8_t tx_buffer[1] = {cmd}; HAL_StatusTypeDef status; status = HAL_SPI_Transmit(&AD7793_SPI, tx_buffer, 1, 1000); if (status != HAL_OK) { ET_ERR("SPI write error:%d!", status); } status = HAL_SPI_Receive(&AD7793_SPI, rx_buf, len, 1000); if (status != HAL_OK) { ET_ERR("SPI read error:%d!", status); } } void pm_ad7793_gpio_set(uint8_t pin, bool state) { if (pin == SPI3_CS_AD7793_Pin) { HAL_GPIO_WritePin(SPI3_CS_AD7793_GPIO_Port, SPI3_CS_AD7793_Pin, state); } } bool pm_ad7793_gpio_get(uint8_t pin) { if (pin == SPI3_MISO_AD7793_Pin) { return HAL_GPIO_ReadPin(SPI3_MISO_AD7793_GPIO_Port, SPI3_MISO_AD7793_Pin) == GPIO_PIN_SET; } return false; } #endif void pm_ad7793_delay_ms(uint16_t ms) { rt_thread_mdelay(ms); // 使用 RT-Thread 的延时函数 } ad7793_hw_if_t ad7793_hw_if = { .spi_transfer = pm_ad7793_spi_transfer, .spi_write = pm_ad7793_spi_write, .spi_read = pm_ad7793_spi_read, .gpio_set = pm_ad7793_gpio_set, .gpio_get = pm_ad7793_gpio_get, .delay_ms = pm_ad7793_delay_ms, }; #if (ENABLE_SV630P == 1) struct rt_messagequeue servo_mq; static char mq_pool[SERVO_RX_QUEUE_SIZE]; #endif // USING_SOFT_SPI void pm_system_led_toggle(void) { HAL_GPIO_TogglePin(PE5_LED1_GPIO_Port, PE5_LED1_Pin); } void pm_system_led_on(void) { HAL_GPIO_WritePin(PE5_LED1_GPIO_Port, PE5_LED1_Pin, GPIO_PIN_SET); } void pm_system_led_off(void) { HAL_GPIO_WritePin(PE5_LED1_GPIO_Port, PE5_LED1_Pin, GPIO_PIN_RESET); } void pm_error_led_on(void) { HAL_GPIO_WritePin(PE6_LED2_GPIO_Port, PE6_LED2_Pin, GPIO_PIN_SET); } void pm_error_led_off(void) { HAL_GPIO_WritePin(PE6_LED2_GPIO_Port, PE6_LED2_Pin, GPIO_PIN_RESET); } void pm_error_led_toggle(void) { HAL_GPIO_TogglePin(PE6_LED2_GPIO_Port, PE6_LED2_Pin); } int pm_i2c_write_bytes(uint16_t dev_addr, uint16_t mem_addr, uint8_t *data, uint16_t len) { HAL_StatusTypeDef res; // AT24C128 单页为 64 字节,写入时建议不要跨页,否则需要拆包 if (len > 64) return HAL_ERROR; res = HAL_I2C_Mem_Write(&hi2c2, dev_addr, mem_addr, I2C_MEMADD_SIZE_16BIT, data, len, HAL_MAX_DELAY); HAL_Delay(5); // EEPROM写入周期,典型为5ms return res; } int pm_i2c_read_bytes(uint16_t dev_addr, uint16_t mem_addr, uint8_t *data, uint16_t len) { return HAL_I2C_Mem_Read(&hi2c2, dev_addr, mem_addr, I2C_MEMADD_SIZE_16BIT, data, len, HAL_MAX_DELAY); } void pm_uart_print_send(const uint8_t *data, uint16_t len) { #ifdef USING_RTT_AS_CONSOLE #warning "USING_RTT_AS_CONSOLE defined, use uart1 as hmi interface" #else HAL_UART_Transmit(&huart1, data, len, 1000); #endif } void pm_lcd_cmd_send(const uint8_t *data, uint16_t len) { //#ifdef USING_RTT_AS_CONSOLE HAL_UART_Transmit(&huart1, data, strlen(data), 1000); // #else // HAL_UART_Transmit(&huart2, data, strlen(data), 1000); // #endif } struct rt_messagequeue mb_hmi_mq; static char mq_pool[MB_HMI_RX_QUEUE_SIZE]; int pm_mb_hmi_init(void) { MX_USART1_UART_Init(); // used tx MX_USART2_UART_Init(); // used rx rt_err_t result = rt_mq_init(&mb_hmi_mq, "mb_hmi_mq", mq_pool, 1, MB_HMI_RX_QUEUE_SIZE, RT_IPC_FLAG_FIFO); if (result != RT_EOK) { ET_ERR("mb_hmi mq init failed\n"); return -1; } //__HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE); __HAL_UART_ENABLE_IT(&HMI_COM, UART_IT_RXNE); return 0; } int32_t pm_hmi_uart_read(uint8_t *buf, uint16_t count, int32_t byte_timeout_ms, void *arg) { UNUSED(arg); uint16_t bytes_read = 0; uint8_t byte; rt_tick_t timeout_ticks = rt_tick_from_millisecond(byte_timeout_ms); DBG_MB("start read:count:%d, timeout:%d\n", count, byte_timeout_ms); while (bytes_read < count) { rt_err_t result = rt_mq_recv(&mb_hmi_mq, &byte, sizeof(byte), timeout_ticks); if (result == RT_EOK) { DBG_MB("rx: %02X\n", byte); buf[bytes_read++] = byte; } else { if (bytes_read > 0) { DBG_MB("Modbus read finished %d\n", bytes_read); return bytes_read; } DBG_MB("HMI read timeout, no data received\n"); return 0; } } DBG_MB("Actually read:%d, count:%d\r\n", bytes_read, count); return bytes_read; } int32_t pm_hmi_uart_write(const uint8_t *buf, uint16_t count, int32_t byte_timeout_ms, void *arg) { UNUSED(arg); rt_thread_mdelay(2); //#ifdef USING_RTT_AS_CONSOLE if (HAL_UART_Transmit(&huart1, buf, count, byte_timeout_ms) == HAL_OK) // #else // if (HAL_UART_Transmit(&HMI_COM, buf, count, byte_timeout_ms) == HAL_OK) // #endif { ET_DBG("HMI write:%d", count); return count; } else { return 0; } } #if (ENABLE_SV630P == 1) int pm_servo_init(void) { MX_USART3_UART_Init(); rt_err_t result = rt_mq_init(&servo_mq, "servo_mq", mq_pool, 1, SERVO_RX_QUEUE_SIZE, RT_IPC_FLAG_FIFO); if (result != RT_EOK) { ET_ERR("servo mq init failed\n"); return -1; } __HAL_UART_ENABLE_IT(&SERVO_COM, UART_IT_RXNE); return 0; } int32_t pm_servo_uart_read(uint8_t *buf, uint16_t count, int32_t byte_timeout_ms, void *arg) { UNUSED(arg); uint16_t bytes_read = 0; uint8_t byte; rt_tick_t timeout_ticks = rt_tick_from_millisecond(byte_timeout_ms); DBG_MB("start read:count:%d, timeout:%d\n", count, byte_timeout_ms); while (bytes_read < count) { rt_err_t result = rt_mq_recv(&servo_mq, &byte, sizeof(byte), timeout_ticks); if (result == RT_EOK) { DBG_MB("rx: %02X\n", byte); buf[bytes_read++] = byte; } else { if (bytes_read > 0) { DBG_MB("Modbus read finished %d\n", bytes_read); return bytes_read; } DBG_MB("Servo read timeout, no data received\n"); return 0; } } DBG_MB("Actually read:%d, count:%d\r\n", bytes_read, count); return bytes_read; } int32_t pm_servo_uart_write(const uint8_t *buf, uint16_t count, int32_t byte_timeout_ms, void *arg) { UNUSED(arg); rt_thread_mdelay(2); if (HAL_UART_Transmit(&SERVO_COM, buf, count, byte_timeout_ms) == HAL_OK) { return count; } else { return 0; } } #endif // ENABLE_SV630P #if (ENABLE_TEC == 1) void pm_tec_init(void) { #if (USING_SOFT_SPI == 0) MX_SPI3_Init(); #endif MX_TIM1_Init(); } void pm_tec_start(void) { HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1); HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_1); } void pm_tec_stop(void) { HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_1); HAL_TIMEx_PWMN_Stop(&htim1, TIM_CHANNEL_1); } void pm_tec_set_duty(float pid_output) { uint32_t period = htim1.Init.Period; // 限制PID输出范围 const float MIN_POWER = 2.0f; // 最小有效功率(%) if (pid_output > 100.0f) pid_output = 100.0f; if (pid_output < -100.0f) pid_output = -100.0f; // 应用最小功率限制 if (pid_output > 0 && pid_output < MIN_POWER) pid_output = MIN_POWER; if (pid_output < 0 && pid_output > -MIN_POWER) pid_output = -MIN_POWER; // 计算占空比 uint32_t compare_value; if (pid_output >= 0) { // 制热:占空比50%~0% compare_value = period / 2 + (uint32_t)(period * pid_output / 200.0f); } else { // 制热:占空比50%~0% compare_value = period / 2 - (uint32_t)(period * fabs(pid_output) / 200.0f); } ET_DBG("PWM COMAPRE: %d", compare_value); // 设置PWM占空比 __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, compare_value); //__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, 2); } void pm_fan_start(void) { HAL_GPIO_WritePin(FAN_CONTROL_GPIO_Port, FAN_CONTROL_Pin, GPIO_PIN_SET); } void pm_fan_stop(void) { HAL_GPIO_WritePin(FAN_CONTROL_GPIO_Port, FAN_CONTROL_Pin, GPIO_PIN_RESET); } #endif // ENABLE_TEC void pm_timestamp_tim_init(void) { MX_TIM4_Init(); } void pm_timestamp_start(void) { __HAL_TIM_SET_COUNTER(&TIMESTAMP_TIM, 0); timestamp_tim_overflow_count = 0; HAL_TIM_Base_Start_IT(&TIMESTAMP_TIM); } void pm_timestamp_stop(void) { HAL_TIM_Base_Stop_IT(&TIMESTAMP_TIM); } uint64_t pm_get_timestamp_us(void) { uint16_t current_cnt = __HAL_TIM_GET_COUNTER(&TIMESTAMP_TIM); return (uint64_t)timestamp_tim_overflow_count * 65536 + current_cnt; } void pm_adc_init(void) { MX_DMA_Init(); MX_ADC1_Init(); } uint32_t pm_adc_get_value(void) { if (HAL_ADC_PollForConversion(&LIGHT_ADC, 10) != HAL_OK) { ET_ERR("ADC read should not wait!"); pm_error_led_on(); return 0; } return HAL_ADC_GetValue(&LIGHT_ADC); } void pm_sampling_tim_init(void) { MX_TIM3_Init(); } void pm_sampling_tim_start(void) { HAL_TIM_Base_Start_IT(&SAMPLING_TIM); } void pm_sampling_tim_stop(void) { HAL_TIM_Base_Stop_IT(&SAMPLING_TIM); } void pm_sampling_adc_start(uint16_t *buffer, uint32_t length) { if (HAL_ADC_Start_DMA(&LIGHT_ADC, (uint32_t *)buffer, length) != HAL_OK) { ET_ERR("ADC start DMA error!"); pm_error_led_on(); } //HAL_ADC_Start(&LIGHT_ADC); } void pm_sampling_adc_stop(void) { //HAL_ADC_Stop(&hadc1); HAL_ADC_Stop_DMA(&LIGHT_ADC); } float pm_sampling_tim_get_freq(void) { uint32_t pclk1 = HAL_RCC_GetPCLK1Freq(); uint32_t timer_clk; // 获取APB1预分频系数(来自RCC配置寄存器) uint32_t apb1_prescaler = (RCC->CFGR & RCC_CFGR_PPRE1) >> RCC_CFGR_PPRE1_Pos; // 根据APB1预分频计算定时器时钟源 if (apb1_prescaler == RCC_HCLK_DIV1) { // APB1预分频=1,定时器时钟=PCLK1 timer_clk = pclk1; } else { // APB1预分频>1,定时器时钟=2×PCLK1 timer_clk = pclk1 * 2; } // 计算定时器计数频率(经过PSC分频后) uint32_t counter_freq = timer_clk / (SAMPLING_TIM.Init.Prescaler + 1); // 计算最终输出频率(周期触发频率 = 计数频率 / (Period + 1)) // 注意:如果是向上计数模式,完整周期是从0到Period,共Period+1个计数 return (float)counter_freq / (SAMPLING_TIM.Init.Period + 1); } int pm_board_init(void) { MX_GPIO_Init(); // MX_USART1_UART_Init(); #if (USING_SOFT_SPI == 1) soft_spi_init(&soft_spi); soft_spi_set_mode(&soft_spi, SOFT_SPI_MODE3); // 设置 SPI 模式 soft_spi_set_bit_order(&soft_spi, SOFT_SPI_MSB_FIRST); // 设置位序 soft_spi_set_delay(&soft_spi, 1); // 设置延时为 1 微秒 soft_spi_select(&soft_spi); // 选择 SPI 设备 #endif return 0; }