Files
CCU621M/BSP/adc/adc_spi5_batVoltCurr.c
T

475 lines
15 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*!
\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;
}