Initial commit: CCU621_M firmware project with BLE debug link support.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,474 @@
|
||||
/*!
|
||||
\file spi5_analog.c
|
||||
\brief SPI5 for analog data acquisition
|
||||
|
||||
\version 2026-03-09, V1.4.0, firmware for GD32H7xx
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2025, GigaDevice Semiconductor Inc.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
3. Neither the name of the copyright holder nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "adc_spi5_batVoltCurr.h"
|
||||
#include <stdio.h>
|
||||
#include "gd32h7xx.h"
|
||||
#include "sgm51652hx.h"
|
||||
#include "spi_if.h"
|
||||
//#include "task.h"
|
||||
#define V_REF 4.096 //芯片基准电压
|
||||
#define N 50 //ADC采样次数
|
||||
float adc_ref = 0.0; //基准电压值
|
||||
/* 私有变量 */
|
||||
static uint8_t spi5_initialized = 0;
|
||||
static spi_dev_t spi5_dev; // SPI5设备
|
||||
static sgm51652hx_dev_t sgm51652hx_chip; // SGM51652HX芯片
|
||||
|
||||
/* 私有函数声明 */
|
||||
static void spi5_gpio_config(void);
|
||||
static void spi5_config(void);
|
||||
//static float spi5_convert_adc_value(uint16_t raw_value, uint8_t channel);
|
||||
static uint8_t spi5_validate_channel(uint8_t channel);
|
||||
|
||||
/*!
|
||||
\brief configure SPI5 GPIO peripheral for analog acquisition
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
\note SPI5引脚配置 for analog acquisition:
|
||||
- SPI5_CS -> PG12 (片选)
|
||||
- SPI5_SCK -> PG13 (时钟)
|
||||
- SPI5_MISO -> PG14 (数据输入)
|
||||
- SPI5_MOSI -> PA6 (数据输出)
|
||||
*/
|
||||
void spi5_gpio_config(void)
|
||||
{
|
||||
/* 使能GPIO时钟 */
|
||||
rcu_periph_clock_enable(RCU_GPIOA);
|
||||
rcu_periph_clock_enable(RCU_GPIOG);
|
||||
|
||||
/* 使能SPI5时钟 */
|
||||
rcu_periph_clock_enable(RCU_SPI5);
|
||||
|
||||
/* 配置SPI5时钟源 */
|
||||
rcu_spi_clock_config(IDX_SPI5, RCU_SPISRC_APB2);
|
||||
|
||||
/* 配置CS引脚 (PG12) - 软件控制 */
|
||||
gpio_mode_set(GPIOG, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_12);
|
||||
gpio_output_options_set(GPIOG, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_12);
|
||||
/* 默认拉高,不选中模拟芯片 */
|
||||
gpio_bit_set(GPIOG, GPIO_PIN_12);
|
||||
|
||||
/* 配置SPI5引脚复用功能 */
|
||||
gpio_af_set(GPIOG, GPIO_AF_5, GPIO_PIN_13 | GPIO_PIN_14); // SCK, MOSI
|
||||
gpio_af_set(GPIOA, GPIO_AF_8, GPIO_PIN_6); // MISO,复用AF8
|
||||
|
||||
/* 配置SCK引脚 (PG13) - 复用功能输出 */
|
||||
gpio_mode_set(GPIOG, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_13);
|
||||
gpio_output_options_set(GPIOG, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_13);
|
||||
|
||||
/* 配置MOSI引脚 (PG14) - 复用功能输出 */
|
||||
gpio_mode_set(GPIOG, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_14);
|
||||
gpio_output_options_set(GPIOG, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_14);
|
||||
|
||||
/* 配置MISO引脚 (PA6) - 复用功能输入 */
|
||||
gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_6);
|
||||
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_6);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configure SPI5 peripheral for analog acquisition
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
\note SPI5基本配置,针对模拟量采集优化
|
||||
*/
|
||||
void spi5_config(void)
|
||||
{
|
||||
spi_parameter_struct spi_init_struct;
|
||||
|
||||
/* 去初始化SPI5 */
|
||||
spi_i2s_deinit(SPI5);
|
||||
|
||||
/* 初始化SPI参数结构体 */
|
||||
spi_struct_para_init(&spi_init_struct);
|
||||
|
||||
/* SPI5参数配置 for analog acquisition */
|
||||
spi_init_struct.trans_mode = SPI_TRANSMODE_FULLDUPLEX; // 全双工模式
|
||||
spi_init_struct.device_mode = SPI_MASTER; // 主模式
|
||||
spi_init_struct.data_size = SPI_DATASIZE_8BIT; // 8位数据帧
|
||||
spi_init_struct.clock_polarity_phase = SPI_CK_PL_HIGH_PH_1EDGE; // 时钟极性低,第一边沿采样 (Mode 0)
|
||||
spi_init_struct.nss = SPI_NSS_SOFT; // 软件NSS控制
|
||||
spi_init_struct.prescale = SPI_PSC_32; // 分频系数
|
||||
spi_init_struct.endian = SPI_ENDIAN_MSB; // MSB先行
|
||||
|
||||
/* 初始化SPI5 */
|
||||
spi_init(SPI5, &spi_init_struct);
|
||||
|
||||
/* 使能字节访问 */
|
||||
spi_byte_access_enable(SPI5);
|
||||
|
||||
/* 使能NSS输出 (兼容性) */
|
||||
spi_nss_output_enable(SPI5);
|
||||
}
|
||||
#if 0
|
||||
static uint8_t spi5_transmit_receive(uint8_t data)
|
||||
{
|
||||
/* 等待发送缓冲区为空 */
|
||||
while(RESET == spi_i2s_flag_get(SPI5, SPI_FLAG_TP));
|
||||
|
||||
/* 发送数据 */
|
||||
spi_i2s_data_transmit(SPI5, data);
|
||||
|
||||
/* 等待接收缓冲区非空 */
|
||||
while(RESET == spi_i2s_flag_get(SPI5, SPI_FLAG_RP));
|
||||
|
||||
/* 接收数据 */
|
||||
return (uint8_t)spi_i2s_data_receive(SPI5);
|
||||
}
|
||||
static void spi5_send_data(uint8_t data)
|
||||
{
|
||||
/* 等待发送缓冲区为空 */
|
||||
while(RESET == spi_i2s_flag_get(SPI5, SPI_FLAG_TP));
|
||||
|
||||
/* 发送数据 */
|
||||
spi_i2s_data_transmit(SPI5, data);
|
||||
}
|
||||
int spi5_write_range(sgm51652hxReg_e reg, sgm51652hxRngVlu_e rangVlu) //设置指定通道量程
|
||||
{
|
||||
//uint8_t txbuf[3] = {0x01, };
|
||||
uint8_t cmd = 0;
|
||||
uint8_t rxbuf[4] = {0};
|
||||
if(!spi5_initialized) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
spi5_cs_control(1); //选中
|
||||
|
||||
cmd = (((uint8_t)reg)<<1) | 1; //寄存器地址+写指令1
|
||||
//rxbuf[0] = spi5_transmit_receive(0x01); //写命令
|
||||
//rxbuf[1] = spi5_transmit_receive((uint8_t)reg); //关键程序寄存器地址
|
||||
rxbuf[0] = spi5_transmit_receive(cmd);
|
||||
rxbuf[1] = spi5_transmit_receive((uint8_t)rangVlu); //写量程,返回的值应该是写入的值
|
||||
rxbuf[2] = spi5_transmit_receive(0x00);
|
||||
rxbuf[3] = spi5_transmit_receive(0x00);
|
||||
|
||||
spi5_cs_control(0); //取消选中
|
||||
|
||||
printf("spi5 regAddr[%d]: set value = %x -- %x %x %x %x \n", reg, rangVlu, rxbuf[0], rxbuf[1], rxbuf[2], rxbuf[3]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int spi5_read_range(sgm51652hxReg_e reg) //设置指定通道量程
|
||||
{
|
||||
//uint8_t txbuf[3] = {0x01, };
|
||||
uint8_t cmd = 0;
|
||||
uint8_t rxbuf[3] = {0};
|
||||
if(!spi5_initialized) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
spi5_cs_control(1); //选中
|
||||
|
||||
cmd = (((uint8_t)reg)<<1); //寄存器地址+读指令0
|
||||
rxbuf[0] = spi5_transmit_receive(cmd); //
|
||||
rxbuf[1] = spi5_transmit_receive(0x00); //返回值
|
||||
rxbuf[2] = spi5_transmit_receive(0x00);
|
||||
|
||||
spi5_cs_control(0); //取消选中
|
||||
|
||||
printf("spi5 regAddr[%d]: read value -- %x %x %x\n", reg, rxbuf[0], rxbuf[1], rxbuf[2]);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
#if 0 //调试
|
||||
int sgm51652hx_write_reg_test1(sgm51652hx_dev_t *dev, uint8_t reg, uint8_t value)
|
||||
{
|
||||
uint8_t rxbuf[4] = {0};
|
||||
|
||||
if (!dev || !dev->initialized) {
|
||||
return ERR_INVALIDPARAMETER;
|
||||
}
|
||||
|
||||
/* 选中芯片 */
|
||||
spi_cs_control(&dev->spi_dev, 1);
|
||||
//spi5_cs_control(1); //选中
|
||||
|
||||
/* 开启发送 */
|
||||
spi_master_transfer_start(dev->spi_dev.spi, SPI_TRANS_START);
|
||||
|
||||
/* 发送写命令:寄存器地址 << 1 | 1 */
|
||||
uint8_t cmd = (reg << 1) | 1;
|
||||
#if 0
|
||||
spi5_send_data(cmd);
|
||||
/* 发送数据 */
|
||||
spi5_send_data(value);
|
||||
/* 发送两个空字节 */
|
||||
spi5_send_data(0x00);
|
||||
spi5_send_data(0x00);
|
||||
#endif
|
||||
#if 0
|
||||
spi_transmit_byte(dev->spi_dev.spi, cmd);
|
||||
/* 发送数据 */
|
||||
spi_transmit_byte(dev->spi_dev.spi, value);
|
||||
/* 发送两个空字节 */
|
||||
spi_transmit_byte(dev->spi_dev.spi, 0x00);
|
||||
spi_transmit_byte(dev->spi_dev.spi, 0x00);
|
||||
#endif
|
||||
#if 1
|
||||
rxbuf[0] = spi_transmit_receive_byte(dev->spi_dev.spi, cmd);/* 发送数据 */
|
||||
rxbuf[1] = spi_transmit_receive_byte(dev->spi_dev.spi, value);/* 发送两个空字节 */
|
||||
rxbuf[2] = spi_transmit_receive_byte(dev->spi_dev.spi, 0x00);
|
||||
rxbuf[3] = spi_transmit_receive_byte(dev->spi_dev.spi, 0x00);
|
||||
#endif
|
||||
#if 0
|
||||
rxbuf[0] = spi5_transmit_receive(cmd);/* 发送数据 */
|
||||
rxbuf[1] = spi5_transmit_receive(value);/* 发送两个空字节 */
|
||||
rxbuf[2] = spi5_transmit_receive(0x00);
|
||||
rxbuf[3] = spi5_transmit_receive(0x00);
|
||||
#endif
|
||||
/* 取消片选 */
|
||||
spi_cs_control(&dev->spi_dev, 0);
|
||||
//spi5_cs_control(0); //选中
|
||||
|
||||
printf("spi5 regAddr[%d]: set value = %x %x %x %x \n", reg, rxbuf[0], rxbuf[1], rxbuf[2], rxbuf[3]);
|
||||
|
||||
return ERR_OK_SGM;
|
||||
}
|
||||
|
||||
int sgm51652hx_set_range_test1(sgm51652hx_dev_t *dev, uint8_t channel, sgm51652hxRngVlu_e range)
|
||||
{
|
||||
if (!dev || !dev->initialized || channel > 7) {
|
||||
return ERR_INVALIDPARAMETER;
|
||||
}
|
||||
|
||||
/* 计算量程寄存器地址 */
|
||||
uint8_t reg = 0x05 + channel; /* RANGE_CH0 = 0x05 */
|
||||
|
||||
/* 写入量程配置 */
|
||||
return sgm51652hx_write_reg_test1(dev, reg, (uint8_t)range);
|
||||
}
|
||||
|
||||
#endif
|
||||
/*!
|
||||
\brief SPI5完整初始化 for analog acquisition
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval 0: 成功, -1: 失败
|
||||
\note 专门为模拟量采集优化
|
||||
*/
|
||||
int adc_spi5_batVoltCurr_init(void)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
if(spi5_initialized) {
|
||||
return 0; // 已初始化
|
||||
}
|
||||
|
||||
/* 配置GPIO */
|
||||
spi5_gpio_config();
|
||||
|
||||
/* 配置SPI外设 */
|
||||
spi5_config();
|
||||
|
||||
/* 使能SPI5 */
|
||||
spi_enable(SPI5);
|
||||
|
||||
/* 初始化SPI设备 */
|
||||
spi_init_dev(&spi5_dev, SPI5, GPIOG, GPIO_PIN_12, 0, 0);
|
||||
|
||||
/* 初始化SGM51652HX芯片 */
|
||||
sgm51652hx_init(&sgm51652hx_chip, &spi5_dev);
|
||||
|
||||
spi5_initialized = 1;
|
||||
|
||||
// for(i=0; i<ANALOG_MAX_CHANNELS; i++)
|
||||
// spi5_write_range(RANGE_CH0+i, RGVL_UP_512); //8个通道都设置为单极性,0~5.26V量程
|
||||
|
||||
/* 设置通道量程 */
|
||||
for(i=0; i<ANALOG_MAX_CHANNELS; i++)
|
||||
sgm51652hx_set_range(&sgm51652hx_chip, i, RGVL_UP_512); //所有通道都设置为单极性,0~5.26V量程
|
||||
|
||||
// printf("SPI5 analog acquisition initialized successfully, supporting %d channels with %d-bit resolution\n",
|
||||
// ANALOG_MAX_CHANNELS, analog_state.resolution); //SPI5模拟采集初始化成功,支持%d通道,分辨率%d位
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*!
|
||||
\brief SPI5去初始化
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void spi5_analog_deinit(void)
|
||||
{
|
||||
/* 去初始化芯片 */
|
||||
sgm51652hx_deinit(&sgm51652hx_chip);
|
||||
|
||||
/* 去初始化SPI设备 */
|
||||
spi_deinit_dev(&spi5_dev);
|
||||
|
||||
/* 禁用SPI5 */
|
||||
spi_disable(SPI5);
|
||||
|
||||
/* 去初始化SPI5 */
|
||||
spi_i2s_deinit(SPI5);
|
||||
|
||||
/* CS引脚拉高 */
|
||||
gpio_bit_set(GPIOG, GPIO_PIN_12);
|
||||
|
||||
spi5_initialized = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static uint8_t spi5_validate_channel(uint8_t channel)
|
||||
{
|
||||
return (channel < ANALOG_MAX_CHANNELS) ? 1 : 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief 读取模拟量通道原始值
|
||||
\param[in] channel: 通道号 (0-7)
|
||||
\param[out] none
|
||||
\retval 16位原始ADC值
|
||||
*/
|
||||
uint16_t spi5_read_analog_raw(uint8_t channel)
|
||||
{
|
||||
uint16_t raw_value = 0;
|
||||
if(!spi5_initialized || !spi5_validate_channel(channel)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 检查通道是否启用 */
|
||||
if(0 == spi5_validate_channel(channel)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 读取通道数据 */
|
||||
if(sgm51652hx_read_channel(&sgm51652hx_chip, channel, &raw_value) != ERR_OK_SGM) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return raw_value;
|
||||
}
|
||||
|
||||
float f_read_spi5_to_Vol(float read_data)
|
||||
{
|
||||
float data = 0.0f;
|
||||
|
||||
data = (1.25 * V_REF * read_data / 65535) ;
|
||||
|
||||
return data;
|
||||
}
|
||||
/**************************************************************
|
||||
* 函数名称: 计算采集电流
|
||||
* 参 数: float vol 芯片采集电压值
|
||||
* 计算公式:U=1000*UADC/16; U为分流器两端电压,单位mV;
|
||||
* I=1000*UADC/16R; I为分流器两端电流,R为分流器两端电阻;
|
||||
* 返 回 值: 计算出的采集电流
|
||||
* 描 述:
|
||||
***************************************************************/
|
||||
float f_cal_curr(float vol)
|
||||
{
|
||||
float ret = 0.0,data = 0.0;
|
||||
data = f_read_spi5_to_Vol(vol);
|
||||
ret = (1000 * data)/16; //分流器两端电压,单位mV
|
||||
|
||||
ret = ret * 300 /75; //计算电流,分流器规格,300A 75mV
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
//获取实际电压值(将这个值取平均值 50 次,调整系数1013)
|
||||
float f_actual_voltage_data(float read_data )
|
||||
{
|
||||
float data = 0.0,actVol = 0.0;
|
||||
data = f_read_spi5_to_Vol(read_data);
|
||||
actVol = (data - 0.686f) / 8.2f / 270.0f * 2000270.0f;
|
||||
//1013为系数,可自行调整以趋近实际值
|
||||
return actVol * 1013 /1000;
|
||||
}
|
||||
//读取基准电压
|
||||
float f_read_reference_voltage(float read_data)
|
||||
{
|
||||
float data = 0.0;
|
||||
data = f_read_spi5_to_Vol(read_data);
|
||||
return data ;
|
||||
}
|
||||
/*!
|
||||
\brief 读取模拟量通道电压值
|
||||
\param[in] channel: 通道号 (0-7)
|
||||
channel 0: A枪CC1
|
||||
channel 1: B枪CC1
|
||||
channel 2: B枪外侧电压
|
||||
channel 3: B枪外侧基准电压
|
||||
channel 4: A枪外侧电压
|
||||
channel 5: A枪外侧基准电压
|
||||
channel 6: B枪电流
|
||||
channel 7: A枪电流
|
||||
\param[out] none
|
||||
\retval 电压值 (V)
|
||||
*/
|
||||
float spi5_read_analog_voltage(uint8_t channel)
|
||||
{
|
||||
float f_actua_data; //实际数据值
|
||||
if(!spi5_initialized || !spi5_validate_channel(channel))
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
/* 读取原始值 */
|
||||
uint16_t raw_value = spi5_read_analog_raw(channel);
|
||||
if(channel == 0) /* A枪CC1电压 */
|
||||
f_actua_data = f_read_spi5_to_Vol(raw_value)*4;
|
||||
else if(channel == 1) /* B枪CC1电压 */
|
||||
f_actua_data = f_read_spi5_to_Vol(raw_value)*4;
|
||||
else if(channel == 2) /* B枪外侧电压值*/
|
||||
f_actua_data = f_actual_voltage_data(raw_value);
|
||||
else if(channel == 3) /* B枪基准电压 */
|
||||
{
|
||||
f_actua_data = f_read_reference_voltage(raw_value);
|
||||
}
|
||||
else if(channel == 4) /* A枪外侧电压值 */
|
||||
{
|
||||
f_actua_data = f_actual_voltage_data(raw_value);
|
||||
}
|
||||
else if(channel == 5) /* A枪基准电压值 */
|
||||
{
|
||||
f_actua_data = f_read_reference_voltage(raw_value);
|
||||
}
|
||||
else if(channel == 6) /*B枪电流值*/
|
||||
f_actua_data = f_cal_curr(raw_value);
|
||||
else if(channel == 7) /*A枪电流值*/
|
||||
f_actua_data = f_cal_curr(raw_value);
|
||||
//printf("SPI5 channel(%d): raw=%d, realU=%.2f \n", channel, raw_value, f_actua_data);
|
||||
return f_actua_data;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user