polarimeter_software/User/board/pm_board.c

553 lines
14 KiB
C
Raw Permalink Normal View History

2025-09-30 02:37:23 +00:00
/*
* @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;
}