553 lines
14 KiB
C
553 lines
14 KiB
C
/*
|
||
* @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;
|
||
}
|