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,484 @@
|
||||
/*!
|
||||
\file spi3_charger.c
|
||||
\brief SPI3 for A&B gun charger voltage acquisition and insulation detection
|
||||
|
||||
\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_spi3_insuVolt.h"
|
||||
#include <stdio.h>
|
||||
#include "gd32h7xx.h"
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "spi_if.h"
|
||||
#include "sgm51652hx.h"
|
||||
#include <string.h>
|
||||
#include "sys_drv_init.h"
|
||||
// ======== 配置 =========
|
||||
#define NUM_CHS 4 //通道数:芯片1(CH0、CH1)+芯片2(CH0、CH1)
|
||||
#define NUM_COLL 5 //每个通道采集次数
|
||||
|
||||
#define V_REF 4.096f //芯片基准电压
|
||||
|
||||
int16_t adc3_final[NUM_CHS][NUM_COLL];
|
||||
//uint8_t dma_buf[ADC_CHANNELS][BYTES_PER_CH]; //临时接收缓存
|
||||
|
||||
/* 私有变量 */
|
||||
static uint8_t spi3_initialized = 0;
|
||||
static spi_dev_t spi3_dev1; // SPI3设备(A枪)
|
||||
static spi_dev_t spi3_dev2; // SPI3设备(B枪)
|
||||
static sgm51652hx_dev_t sgm51652hx_chip1; // 芯片1(A枪)
|
||||
static sgm51652hx_dev_t sgm51652hx_chip2; // 芯片2(B枪)
|
||||
|
||||
/* 私有函数声明 */
|
||||
static void spi3_gpio_config(void);
|
||||
static void spi3_config(void);
|
||||
|
||||
/*!
|
||||
\brief configure SPI3 GPIO peripheral for charger
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
\note SPI3引脚配置 for SGM51652H4XTS38G/T:
|
||||
- SPI3_CSA -> PA4 (A枪片选)
|
||||
- SPI3_CSB -> PA3 (B枪片选)
|
||||
- SPI3_SCK -> PE12 (时钟)
|
||||
- SPI3_MISO -> PE13 (数据输入)
|
||||
- SPI3_MOSI -> PE14 (数据输出)
|
||||
*/
|
||||
void spi3_gpio_config(void)
|
||||
{
|
||||
/* 使能GPIO时钟 */
|
||||
rcu_periph_clock_enable(SPI3_RCU_CS);
|
||||
rcu_periph_clock_enable(SPI3_RCU_SCK_MSIO);
|
||||
|
||||
/* 使能SPI3时钟 */
|
||||
rcu_periph_clock_enable(RCU_SPI3);
|
||||
|
||||
/* 使能DMA时钟 */
|
||||
// rcu_periph_clock_enable(RCU_DMA0);
|
||||
// rcu_periph_clock_enable(RCU_DMAMUX);
|
||||
|
||||
/* 配置SPI3时钟源 */
|
||||
rcu_spi_clock_config(IDX_SPI3, RCU_SPISRC_APB2); //RCU_SPISRC_PLL0Q
|
||||
|
||||
/* 配置A枪片选引脚 (PA4) - 软件控制 */
|
||||
gpio_mode_set(SPI3_CS1_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, SPI3_CS1_PIN);
|
||||
gpio_output_options_set(SPI3_CS1_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, SPI3_CS1_PIN);
|
||||
/* 默认拉高,不选中 */
|
||||
SPI3_CS1_HIGH(); //gpio_bit_set(GPIOA, GPIO_PIN_4);
|
||||
|
||||
/* 配置B枪片选引脚 (PA3) - 软件控制 */
|
||||
gpio_mode_set(SPI3_CS2_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, SPI3_CS2_PIN);
|
||||
gpio_output_options_set(SPI3_CS2_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, SPI3_CS2_PIN);
|
||||
/* 默认拉高,不选中B枪 */
|
||||
SPI3_CS2_HIGH(); //gpio_bit_set(GPIOA, GPIO_PIN_3);
|
||||
|
||||
/* 配置SPI3引脚复用功能 */
|
||||
//spi_related_ios_af_en(SPI3); //SPI标准库函数,一键配置SPIx所有引脚复用(SCK/MOSI/MISO/NSS)lyn260401
|
||||
gpio_af_set(GPIOE, GPIO_AF_5, GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14);
|
||||
|
||||
/* 配置SCK引脚 (PE12) - 复用功能输出 */
|
||||
gpio_mode_set(GPIOE, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_12);
|
||||
gpio_output_options_set(GPIOE, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_12);
|
||||
|
||||
/* 配置MISO引脚 (PE13) - 复用功能输入 */
|
||||
gpio_mode_set(GPIOE, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_13);
|
||||
gpio_output_options_set(GPIOE, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_13);
|
||||
|
||||
/* 配置MOSI引脚 (PE14) - 复用功能输出 */
|
||||
gpio_mode_set(GPIOE, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_14);
|
||||
gpio_output_options_set(GPIOE, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_14);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configure SPI3 peripheral for charger
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
\note SPI3基本配置,针对SGM51652H4XTS38G/T优化
|
||||
*/
|
||||
void spi3_config(void)
|
||||
{
|
||||
spi_parameter_struct spi_init_struct;
|
||||
|
||||
/* 去初始化SPI3 */
|
||||
spi_i2s_deinit(SPI3);
|
||||
|
||||
/* 初始化SPI参数结构体 */
|
||||
spi_struct_para_init(&spi_init_struct);
|
||||
|
||||
/* SPI3参数配置 for SGM51652H4XTS38G/T */
|
||||
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; // 模式3,sgm51652只能工作在Model
|
||||
spi_init_struct.nss = SPI_NSS_SOFT; // 软件NSS控制:soft-自己用GPIO控制CS1/CS2
|
||||
spi_init_struct.prescale = SPI_PSC_32; // 分频系数,sgm51652最高时钟10Mhz~10Mhz,SPI3在APB2(300Mhz)
|
||||
spi_init_struct.endian = SPI_ENDIAN_MSB; // MSB先行 sgm51652规定必须高位先传
|
||||
|
||||
/* 初始化SPI3 */
|
||||
spi_init(SPI3, &spi_init_struct);
|
||||
|
||||
/* 使能字节访问 */
|
||||
spi_byte_access_enable(SPI3);
|
||||
|
||||
/* 使能NSS输出 (兼容性) */
|
||||
spi_nss_output_enable(SPI3);
|
||||
}
|
||||
|
||||
|
||||
#if 0 //DMA相关配置,未调通 lyn20260410
|
||||
/*!
|
||||
\brief configure the DMA peripheral
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void adc_read_single(uint8_t chip, uint8_t cmd, uint8_t index)
|
||||
{
|
||||
dma_single_data_parameter_struct dma_init_struct;
|
||||
uint8_t buf[2];
|
||||
|
||||
//选中芯片
|
||||
if(chip == CHIP_1)
|
||||
{
|
||||
SPI3_CS1_LOW();
|
||||
SPI3_CS2_HIGH();
|
||||
}
|
||||
else
|
||||
{
|
||||
SPI3_CS2_LOW();
|
||||
SPI3_CS1_HIGH();
|
||||
}
|
||||
|
||||
//DMA配置
|
||||
/* deinitialize DMA registers of a channel */
|
||||
dma_deinit(DMA0, DMA_CH0);
|
||||
|
||||
dma_single_data_para_struct_init(&dma_init_struct);
|
||||
|
||||
/* SPI0 receive DMA config: DMA_CH0 */
|
||||
dma_init_struct.request = DMA_REQUEST_SPI3_RX; //选哪个外设:SPI3-RX
|
||||
dma_init_struct.periph_addr = (uint32_t)&SPI_RDATA(SPI3); //外设地址:SPI3
|
||||
dma_init_struct.periph_inc = DMA_MEMORY_INCREASE_DISABLE; //禁止外设自增
|
||||
dma_init_struct.memory0_addr = (uint32_t)buf; //内存地址:定义的数组
|
||||
dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE; //内存地址自增
|
||||
dma_init_struct.periph_memory_width = DMA_PERIPH_WIDTH_8BIT; //数据位宽:8/16/32位
|
||||
dma_init_struct.circular_mode = DMA_CIRCULAR_MODE_ENABLE; //是否循环模式:是
|
||||
dma_init_struct.direction = DMA_PERIPH_TO_MEMORY; //方向:外设->内存
|
||||
dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH; //优先级
|
||||
dma_init_struct.number = 2; //SPI一次DMA收多少字节,与数据位宽对应 1路ADC=2字节
|
||||
|
||||
dma_single_data_mode_init(DMA0, DMA_CH0, &dma_init_struct); //初始化
|
||||
|
||||
/* enable DMA channel */
|
||||
dma_channel_enable(DMA0, DMA_CH0);
|
||||
|
||||
//开启SPI3 DMA接收
|
||||
spi_dma_enable(SPI3, SPI_DMA_RECEIVE);
|
||||
#if 0
|
||||
//发通道命令 = 软件启动转换
|
||||
if(spi3_charger_read_data(CHARGER_GUN_A, cmd, data, 2) != 0) {
|
||||
return -1.0f;
|
||||
}
|
||||
|
||||
//等待DMA完成
|
||||
// 等待 DMA 完成
|
||||
while(!dma_flag_get(DMA0, DMA_CH0, DMA_INTF_FTFIF));
|
||||
dma_flag_clear(DMA0, DMA_CH0, DMA_INTF_FTFIF);
|
||||
|
||||
// 关闭
|
||||
spi_dma_disable(SPI3, SPI_DMA_RECEIVE);
|
||||
dma_channel_disable(DMA0, DMA_CH0);
|
||||
|
||||
SPI3_CS1_HIGH();
|
||||
SPI3_CS2_HIGH();
|
||||
|
||||
// 合并 16 位 ADC 数据
|
||||
adc_result[index] = (int16_t)(buf[0] << 8 | buf[1]);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
/*!
|
||||
\brief SPI3完整初始化 for charger
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval 0: 成功, -1: 失败
|
||||
\note 专门为A&B枪充电电压采集和绝缘检测优化
|
||||
*/
|
||||
int adc_spi3_insuVolt_init(void)
|
||||
{
|
||||
if(spi3_initialized) {
|
||||
return 0; // 已初始化
|
||||
}
|
||||
|
||||
/* 配置GPIO */
|
||||
spi3_gpio_config();
|
||||
|
||||
/* 配置SPI外设 */
|
||||
spi3_config();
|
||||
|
||||
/* 使能SPI3 */
|
||||
spi_enable(SPI3);
|
||||
|
||||
/* 初始化SPI设备。注意:芯片1/2使用不同的片选引脚,需要单独处理*/
|
||||
/* 初始化芯片1(A枪) */
|
||||
spi_init_dev(&spi3_dev1, SPI3, GPIOA, GPIO_PIN_4, 0, 0);
|
||||
sgm51652hx_init(&sgm51652hx_chip1, &spi3_dev1);
|
||||
|
||||
/* 初始化芯片2(B枪) */
|
||||
spi_init_dev(&spi3_dev2, SPI3, GPIOA, GPIO_PIN_3, 0, 0);
|
||||
sgm51652hx_init(&sgm51652hx_chip2, &spi3_dev2);
|
||||
|
||||
/* 设置通道量程 */
|
||||
for (uint8_t i = 0; i < 2; i++) {
|
||||
sgm51652hx_set_range(&sgm51652hx_chip1, i, RGVL_BP_256); // ±2.56V
|
||||
sgm51652hx_set_range(&sgm51652hx_chip2, i, RGVL_BP_256); // ±2.56V
|
||||
}
|
||||
|
||||
spi3_initialized = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief SPI3去初始化
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void adc_spi3_batVoltCurr_deinit(void)
|
||||
{
|
||||
/* 去初始化芯片 */
|
||||
sgm51652hx_deinit(&sgm51652hx_chip1);
|
||||
sgm51652hx_deinit(&sgm51652hx_chip2);
|
||||
|
||||
/* 去初始化SPI设备 */
|
||||
spi_deinit_dev(&spi3_dev1);
|
||||
spi_deinit_dev(&spi3_dev2);
|
||||
|
||||
/* 禁用SPI3 */
|
||||
spi_disable(SPI3);
|
||||
|
||||
/* 去初始化SPI3 */
|
||||
spi_i2s_deinit(SPI3);
|
||||
|
||||
/* 所有片选拉高 */
|
||||
gpio_bit_set(GPIOA, GPIO_PIN_3);
|
||||
gpio_bit_set(GPIOA, GPIO_PIN_4);
|
||||
|
||||
spi3_initialized = 0;
|
||||
}
|
||||
/*
|
||||
函数功能:将MCU通过SPI接收到的数据转换为控制器端口采到的电压
|
||||
输入: uint16_t read_data MCU通过SPI接收到的数据
|
||||
uint8_t adc_zf 正负极区分,0正极,1负级
|
||||
uint8_t flag 绝缘检测光电继电器闭合标志位,0:未闭合,1:已经闭合
|
||||
float data 转换后的电压
|
||||
备注:V_REF:芯片基准电压
|
||||
芯片采集到的电压计算方式:
|
||||
每个LSB代表的电压值 = 芯片输入范围(±0.625,即0.625 * 2) * 基准电压(V_REF) / 2^16;
|
||||
ADC读到的电压值 = 每个LSB代表的电压值 * read_data;
|
||||
0V对应点ADC读到电压值为0.625 * V_REF,ADC读到的电压值减去 0.625 * V_REF即为当前芯片采集电压值。
|
||||
芯片采集到电压到控制器端口采集电压转换关系如下:
|
||||
绝缘检测光电继电器闭合前:控制器端口电压 = 芯片采集电压值 * 1376.89/(0.625 *V_REF)
|
||||
绝缘检测光电继电器闭合后:控制器端口电压:
|
||||
正极电压 = 芯片采集电压值 * 689 /(0.625 *V_REF)
|
||||
负极电压 = 芯片采集电压值 * 1380 /(0.625 *V_REF)
|
||||
*/
|
||||
float f_read_to_Vol(float read_data, uint8_t adc_zf, uint8_t flag)
|
||||
{
|
||||
float data = 0.0f;
|
||||
|
||||
//data = chip_volt; //等同于gm51652hx_calc_voltage(raw_value, RGVL_BP_256)
|
||||
data = (0.625f * 2.0f * V_REF * read_data / 65535.0f) - (0.625f * V_REF);
|
||||
|
||||
if(flag == 0)
|
||||
{
|
||||
data = data * 1376.89f / (0.625f * V_REF);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(adc_zf == 0) //正负极计算方式不同,分开计算
|
||||
{
|
||||
data = data * 689.0f / (0.625f * V_REF);
|
||||
}
|
||||
else
|
||||
{
|
||||
data = data * 1380.0f / (0.625f * V_REF);
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
//==================== 单通道读取 (核心函数) ====================
|
||||
uint16_t sgm51652hx_spiReadBytes(uint8_t chip, uint8_t channel) //读取芯片chip通道channel的返回原始ADC值
|
||||
{
|
||||
uint16_t raw_value = 0;
|
||||
sgm51652hx_dev_t *dev = NULL;
|
||||
|
||||
if(chip == CHIP_1)
|
||||
dev = &sgm51652hx_chip1; //芯片1-A枪绝缘电压检测
|
||||
else
|
||||
dev = &sgm51652hx_chip2; //芯片2-B枪绝缘电压检测
|
||||
|
||||
/* 设置通道量程(TBD:上电初始化设置一次就行,还是需要每次发送都要设置?) */
|
||||
//sgm51652hx_set_range(dev, channel, RGVL_BP_256);
|
||||
|
||||
/* 读取原始值 */
|
||||
if(sgm51652hx_read_channel(dev, channel, &raw_value) != ERR_OK_SGM)
|
||||
return 0;
|
||||
|
||||
//printf("spi3 chip=%d,channel=%d: %d\n", chip, channel, raw_value);
|
||||
|
||||
return raw_value;
|
||||
}
|
||||
|
||||
/*
|
||||
函数功能:获取指定控制器端口采集电压
|
||||
输入:uint8_t chip 芯片号,等同于枪号,1 对应A枪,2 对应B枪
|
||||
uint8_t channel 通道号,等同于正负级,channel_0对应正极,channel_1对应负级
|
||||
uint8_t relayOnOff 绝缘检测光电继电器闭合标志位,0:未闭合,1:已经闭合
|
||||
*/
|
||||
float spi3_read_analog_voltage(uint8_t chip, uint8_t channel)
|
||||
{
|
||||
uint16_t raw_value[NUM_COLL] = {0};
|
||||
uint16_t i = 0, j = 0;
|
||||
uint32_t raw_sum_avg = 0;
|
||||
uint8_t relayOnOff;
|
||||
|
||||
float real_voltage = 0;
|
||||
if(chip == 1)
|
||||
relayOnOff = GUN1_INS_KM_READ;
|
||||
else
|
||||
relayOnOff = GUN2_INS_KM_READ;
|
||||
// printf("chip = %d,relayOnOff = %d\n",chip,relayOnOff);
|
||||
//读取指定端口与通道数据NUM_COLL次
|
||||
for(i=0; i<NUM_COLL; i++)
|
||||
raw_value[i] = sgm51652hx_spiReadBytes(chip, channel);
|
||||
|
||||
for(j=0; j<NUM_COLL; j++)
|
||||
raw_sum_avg += raw_value[j];
|
||||
raw_sum_avg /= NUM_COLL;
|
||||
|
||||
/* 转换为芯片引脚电压值 --> 融合进f_read_to_vol() */
|
||||
//chip_voltage = sgm51652hx_calc_voltage(raw_sum_avg, RGVL_BP_256);
|
||||
#if 1
|
||||
/* 根据绝缘回路,将芯片引脚电压转换为控制器端口电压数据 */
|
||||
real_voltage = f_read_to_Vol(raw_sum_avg, channel, relayOnOff); //TODO: 参考DCU606
|
||||
|
||||
if(channel == 1) //通道1-负级
|
||||
real_voltage = -real_voltage;
|
||||
|
||||
if(relayOnOff == 0) //光电继电器闭合标志,闭合前后,数据分开校准
|
||||
{
|
||||
if(channel == 0) //校准系数
|
||||
{
|
||||
real_voltage = real_voltage / 1000 * 993; //997(100欧/V);300V-990 ,400V-997 ,500V-997 ,600V-
|
||||
//997(500欧/V);400V-997
|
||||
}
|
||||
else if(channel == 1)
|
||||
{
|
||||
real_voltage = real_voltage / 1000 * 997; //1004(100欧/V);300V-1007 ,500V-
|
||||
//1004(500欧/V);400V-1007 ,
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(channel == 0) //校准系数
|
||||
{
|
||||
real_voltage = real_voltage / 1000 * 998; //997(100欧/V);300V-990 ,400V-997 ,500V-997 ,600V
|
||||
//997(500欧/V);400V-997
|
||||
}
|
||||
else if(channel == 1)
|
||||
{
|
||||
real_voltage = real_voltage / 1000 * 995; //1004(100欧/V);300V-1007 ,500V-
|
||||
//1004(500欧/V);400V-1007 ,
|
||||
}
|
||||
}
|
||||
#endif
|
||||
// printf("SPI3 chip(%d)-channel(%d): raw=%d, realU=%.2f \n", chip, channel, raw_sum_avg, real_voltage);
|
||||
return real_voltage;
|
||||
}
|
||||
|
||||
//==================== 读取全部4通道 - TODO:改为对应用层接口函数 ====================
|
||||
void sgm51652_read_all_channels(void)
|
||||
{
|
||||
float adc_result[4] = {0};
|
||||
|
||||
// 芯片1 CH0
|
||||
adc_result[0] = spi3_read_analog_voltage(CHIP_1, CHNL_0);
|
||||
|
||||
// 芯片1 CH1
|
||||
adc_result[1] = spi3_read_analog_voltage(CHIP_1, CHNL_1);
|
||||
|
||||
// 芯片2 CH0
|
||||
adc_result[2] = spi3_read_analog_voltage(CHIP_2, CHNL_0);
|
||||
|
||||
// 芯片2 CH1
|
||||
adc_result[3] = spi3_read_analog_voltage(CHIP_2, CHNL_1);
|
||||
(void)adc_result;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief 充电器自检
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval 0: 正常, -1: 故障
|
||||
*/
|
||||
void spi3_charger_self_test(void)
|
||||
{
|
||||
printf("spi3 adc-insuvolt test started...\n");
|
||||
|
||||
/* 检查SPI3初始化状态 */
|
||||
if(!spi3_initialized) {
|
||||
printf("SPI3 not initialized\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// spi3_charger_write_command(1, 0, 0, 0);
|
||||
//
|
||||
// vTaskDelay(50);
|
||||
// spi3_charger_read_command(1, 0, 0, 0);
|
||||
|
||||
while(1)
|
||||
{
|
||||
//sgm51652hx_spiReadBytes(1, 0);
|
||||
//spi3_read_analog_voltage(1, 0, 5);
|
||||
// spi3_charger_read_data_A_0(); //
|
||||
sgm51652_read_all_channels();
|
||||
|
||||
vTaskDelay(250);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
/*!
|
||||
\file spi3_charger.h
|
||||
\brief header file of SPI3 for A&B gun charger voltage acquisition and insulation detection
|
||||
|
||||
\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.
|
||||
*/
|
||||
|
||||
#ifndef SPI3_CHARGER_H
|
||||
#define SPI3_CHARGER_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* SPI3引脚定义 for SGM51652H4XTS38G/T */
|
||||
#define SPI3_SCK_PORT GPIOE // PE12 - 时钟
|
||||
#define SPI3_SCK_PIN GPIO_PIN_12
|
||||
|
||||
#define SPI3_MISO_PORT GPIOE // PE13 - 数据输入
|
||||
#define SPI3_MISO_PIN GPIO_PIN_13
|
||||
|
||||
#define SPI3_MOSI_PORT GPIOE // PE14 - 数据输出
|
||||
#define SPI3_MOSI_PIN GPIO_PIN_14
|
||||
|
||||
/* SPI3复用功能编号 */
|
||||
#define SPI3_AF GPIO_AF_5
|
||||
|
||||
/* 双芯片片选 */
|
||||
#define SPI3_CS1_PORT GPIOA // PA4 - 芯片1片选
|
||||
#define SPI3_CS1_PIN GPIO_PIN_4
|
||||
|
||||
#define SPI3_CS2_PORT GPIOA // PA3 - 芯片2片选
|
||||
#define SPI3_CS2_PIN GPIO_PIN_3
|
||||
|
||||
/* SPIC3 时钟 */
|
||||
#define SPI3_RCU_CS RCU_GPIOA
|
||||
#define SPI3_RCU_SCK_MSIO RCU_GPIOE
|
||||
|
||||
/* 芯片/通道选择 */
|
||||
#define CHIP_1 1 //芯片1-CSA
|
||||
#define CHIP_2 2 //芯片2-CSB
|
||||
|
||||
#define CHNL_0 0 //通道0
|
||||
#define CHNL_1 1 //通道1
|
||||
|
||||
/* 引脚宏操作 */
|
||||
#define SPI3_CS1_LOW() gpio_bit_reset(SPI3_CS1_PORT, SPI3_CS1_PIN)
|
||||
#define SPI3_CS1_HIGH() gpio_bit_set(SPI3_CS1_PORT, SPI3_CS1_PIN)
|
||||
|
||||
#define SPI3_CS2_LOW() gpio_bit_reset(SPI3_CS2_PORT, SPI3_CS2_PIN)
|
||||
#define SPI3_CS2_HIGH() gpio_bit_set(SPI3_CS2_PORT, SPI3_CS2_PIN)
|
||||
|
||||
/* 完整初始化和去初始化 */
|
||||
int adc_spi3_insuVolt_init(void);
|
||||
void adc_spi3_insuVolt_deinit(void);
|
||||
void spi3_charger_self_test(void);
|
||||
float spi3_read_analog_voltage(uint8_t chip, uint8_t channel);
|
||||
#endif /* SPI3_CHARGER_H */
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
/*!
|
||||
\file spi5_analog.h
|
||||
\brief header file of 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.
|
||||
*/
|
||||
|
||||
#ifndef SPI5_ANALOG_H
|
||||
#define SPI5_ANALOG_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* SPI5引脚定义 for analog acquisition */
|
||||
#define SPI5_CS_PIN GPIO_PIN_12 // PG12 - 片选
|
||||
#define SPI5_SCK_PIN GPIO_PIN_13 // PG13 - 时钟
|
||||
#define SPI5_MISO_PIN GPIO_PIN_14 // PG14 - 数据输入
|
||||
#define SPI5_MOSI_PIN GPIO_PIN_6 // PA6 - 数据输出
|
||||
|
||||
#define SPI5_CS_PORT GPIOG
|
||||
#define SPI5_SCK_PORT GPIOG
|
||||
#define SPI5_MISO_PORT GPIOG
|
||||
#define SPI5_MOSI_PORT GPIOA
|
||||
|
||||
/* SPI5复用功能编号 */
|
||||
#define SPI5_AF GPIO_AF_5
|
||||
|
||||
/* 本项目启用通道数 */
|
||||
#define ANALOG_MAX_CHANNELS 8
|
||||
|
||||
/* 函数声明 */
|
||||
/* GPIO配置 */
|
||||
int adc_spi5_batVoltCurr_init(void);
|
||||
|
||||
/* 完整初始化和去初始化 */
|
||||
int spi5_analog_init(void);
|
||||
void spi5_analog_deinit(void);
|
||||
|
||||
/* 状态检查 */
|
||||
uint8_t spi5_analog_is_initialized(void);
|
||||
|
||||
/* 基本读取操作 */
|
||||
uint16_t spi5_read_analog_raw(uint8_t channel);
|
||||
float spi5_read_analog_voltage(uint8_t channel);
|
||||
uint8_t spi5_read_all_channels(float *voltages, uint8_t max_channels);
|
||||
|
||||
void spi5_analog_self_test(void);
|
||||
|
||||
#endif /* SPI5_ANALOG_H */
|
||||
|
||||
@@ -0,0 +1,303 @@
|
||||
#include "gd32h7xx.h"
|
||||
#include "adc_temp.h"
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include "usart.h"
|
||||
#include "sys_drv_init.h"
|
||||
#include "gd32h7xx_dma.h"
|
||||
/* 忙等待延时函数 */
|
||||
static void delay_ms(uint32_t ms)
|
||||
{
|
||||
/* 使用固定的时钟频率 600MHz 来计算延时,避免 SystemCoreClock 未初始化的问题 */
|
||||
for(volatile uint32_t i = 0; i < (600000000 / 4000) * ms; i++)
|
||||
{
|
||||
__NOP();
|
||||
}
|
||||
}
|
||||
/* ADC2 DMA连续采样缓冲:DMA中断只负责“完成标记”,数据处理放在 get_adc_data()。 */
|
||||
#define ADC_TEMP_DMA_PERIPH DMA1
|
||||
#define ADC_TEMP_DMA_CH DMA_CH0
|
||||
#define ADC_TEMP_DMA_IRQN DMA1_Channel0_IRQn
|
||||
#define ADC_TEMP_DMA_SAMPLE_CNT (16U)
|
||||
|
||||
static __IO uint32_t g_adc_dma_buf[ADC_TEMP_DMA_SAMPLE_CNT];
|
||||
static volatile uint32_t g_adc_dma_frame_cnt;
|
||||
|
||||
__IO uint32_t adc_value[4];
|
||||
|
||||
void init_adc(void)
|
||||
{
|
||||
dma_single_data_parameter_struct dma_init_struct;
|
||||
|
||||
/* GPIO时钟使能 */
|
||||
rcu_periph_clock_enable(RCU_GPIOC);
|
||||
/* ADC时钟使能 */
|
||||
rcu_periph_clock_enable(RCU_ADC2);
|
||||
/* DMA时钟使能 */
|
||||
rcu_periph_clock_enable(RCU_DMA1);
|
||||
/* GPIO参数配置*/
|
||||
gpio_mode_set(GPIOC, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO_PIN_2);
|
||||
/* ADC初始化 -- 根据数据手册,ADC2_IN0--PC2端子仅能使用ADC2第0个通道 */
|
||||
adc_deinit(ADC2);
|
||||
/* ADC时钟配置 */
|
||||
adc_clock_config(ADC2, ADC_CLK_SYNC_HCLK_DIV6);
|
||||
/* 单通道连续转换 + DMA */
|
||||
adc_special_function_config(ADC2, ADC_SCAN_MODE, DISABLE);
|
||||
adc_special_function_config(ADC2, ADC_CONTINUOUS_MODE, ENABLE);
|
||||
/* 转换结果(12/14位)存放在 32 位寄存器的低 16 位中 */
|
||||
adc_data_alignment_config(ADC2, ADC_DATAALIGN_RIGHT);
|
||||
/* ADC 通道配置(规则通道组,单通道) */
|
||||
adc_channel_length_config(ADC2, ADC_REGULAR_CHANNEL, 1);
|
||||
/* 配置规则通道序列,决定 ADC 在转换时,对 PC2 引脚电压进行采样的时间长度*/
|
||||
adc_regular_channel_config(ADC2, 0, ADC_CHANNEL_0, 240);
|
||||
/* 禁用外部触发*/
|
||||
adc_external_trigger_config(ADC2, ADC_REGULAR_CHANNEL, EXTERNAL_TRIGGER_DISABLE);
|
||||
|
||||
/* DMA配置:ADC2 regular data -> g_adc_dma_buf[] (循环) */
|
||||
dma_deinit(ADC_TEMP_DMA_PERIPH, ADC_TEMP_DMA_CH);
|
||||
dma_single_data_para_struct_init(&dma_init_struct);
|
||||
dma_init_struct.request = DMA_REQUEST_ADC2;
|
||||
dma_init_struct.periph_addr = (uint32_t)&ADC_RDATA(ADC2);
|
||||
dma_init_struct.periph_inc = DMA_MEMORY_INCREASE_DISABLE;
|
||||
dma_init_struct.memory0_addr = (uint32_t)g_adc_dma_buf;
|
||||
dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
|
||||
dma_init_struct.periph_memory_width = DMA_PERIPH_WIDTH_32BIT;
|
||||
dma_init_struct.circular_mode = DMA_CIRCULAR_MODE_ENABLE;
|
||||
dma_init_struct.direction = DMA_PERIPH_TO_MEMORY;
|
||||
dma_init_struct.priority = DMA_PRIORITY_HIGH;
|
||||
dma_init_struct.number = ADC_TEMP_DMA_SAMPLE_CNT;
|
||||
dma_single_data_mode_init(ADC_TEMP_DMA_PERIPH, ADC_TEMP_DMA_CH, &dma_init_struct);
|
||||
dma_interrupt_enable(ADC_TEMP_DMA_PERIPH, ADC_TEMP_DMA_CH, DMA_INT_HTF);
|
||||
dma_interrupt_enable(ADC_TEMP_DMA_PERIPH, ADC_TEMP_DMA_CH, DMA_INT_FTF);
|
||||
nvic_irq_enable(ADC_TEMP_DMA_IRQN, 6U, 0U);
|
||||
/* 使能 ADC2 模块 */
|
||||
adc_enable(ADC2);
|
||||
/* wait for ADC stability */
|
||||
delay_ms(1);
|
||||
/* 配置校准模式,偏移量校准,用于纠正 ADC 自身的零点误差 */
|
||||
adc_calibration_mode_config(ADC2, ADC_CALIBRATION_OFFSET);
|
||||
/* 配置校准次数 */
|
||||
adc_calibration_number(ADC2, ADC_CALIBRATION_NUM1);
|
||||
/*执行校准 */
|
||||
adc_calibration_enable(ADC2);
|
||||
|
||||
/* 启动DMA与ADC连续转换 */
|
||||
memset((void *)g_adc_dma_buf, 0, sizeof(g_adc_dma_buf));
|
||||
g_adc_dma_frame_cnt = 0U;
|
||||
dma_channel_enable(ADC_TEMP_DMA_PERIPH, ADC_TEMP_DMA_CH);
|
||||
adc_dma_mode_enable(ADC2);
|
||||
adc_dma_request_after_last_enable(ADC2);
|
||||
adc_software_trigger_enable(ADC2, ADC_REGULAR_CHANNEL);
|
||||
}
|
||||
|
||||
|
||||
uint32_t adc_channel_sample(uint8_t channel)
|
||||
{
|
||||
uint32_t timeout = 1000000U;
|
||||
/* 重新配置规则通道 */
|
||||
adc_regular_channel_config(ADC2, 0U, channel, 240);
|
||||
/* 软件触发转换 */
|
||||
adc_software_trigger_enable(ADC2, ADC_REGULAR_CHANNEL);
|
||||
/* 等待转换结束 */
|
||||
while(!adc_flag_get(ADC2, ADC_FLAG_EOC)){
|
||||
if (timeout-- == 0U) {
|
||||
return 0U;
|
||||
}
|
||||
}
|
||||
/* 清除标志 */
|
||||
adc_flag_clear(ADC2, ADC_FLAG_EOC);
|
||||
/* 读取结果并返回 */
|
||||
return (adc_regular_data_read(ADC2));
|
||||
}
|
||||
|
||||
void DMA1_Channel0_IRQHandler(void)
|
||||
{
|
||||
if (SET == dma_interrupt_flag_get(ADC_TEMP_DMA_PERIPH, ADC_TEMP_DMA_CH, DMA_INT_FLAG_HTF)) {
|
||||
dma_interrupt_flag_clear(ADC_TEMP_DMA_PERIPH, ADC_TEMP_DMA_CH, DMA_INT_FLAG_HTF);
|
||||
g_adc_dma_frame_cnt++;
|
||||
}
|
||||
|
||||
if (SET == dma_interrupt_flag_get(ADC_TEMP_DMA_PERIPH, ADC_TEMP_DMA_CH, DMA_INT_FLAG_FTF)) {
|
||||
dma_interrupt_flag_clear(ADC_TEMP_DMA_PERIPH, ADC_TEMP_DMA_CH, DMA_INT_FLAG_FTF);
|
||||
g_adc_dma_frame_cnt++;
|
||||
}
|
||||
}
|
||||
|
||||
void select_temp_channel(uint8_t flag_set)
|
||||
{
|
||||
//温度采集选通,
|
||||
/*
|
||||
OUT8、OUT7设置为高电平,A枪正温度
|
||||
OUT8设置为高电平,OUT7设置为低电平,A枪负温度
|
||||
OUT8设置为低电平,OUT7设置为高电平,B枪正温度
|
||||
OUT8、OUT7设置为低电平,B枪负温度
|
||||
*/
|
||||
if(flag_set == 0)
|
||||
{
|
||||
TEMP_MULT_CTRA(1);
|
||||
TEMP_MULT_CTRB(1);
|
||||
TEMP_MULT_CTRC(1);
|
||||
}
|
||||
else if(flag_set == 1)
|
||||
{
|
||||
TEMP_MULT_CTRA(0);
|
||||
TEMP_MULT_CTRB(1);
|
||||
TEMP_MULT_CTRC(1);
|
||||
}
|
||||
else if(flag_set == 2)
|
||||
{
|
||||
TEMP_MULT_CTRA(1);
|
||||
TEMP_MULT_CTRB(0);
|
||||
TEMP_MULT_CTRC(1);
|
||||
}
|
||||
else if(flag_set == 3)
|
||||
{
|
||||
TEMP_MULT_CTRA(0);
|
||||
TEMP_MULT_CTRB(0);
|
||||
TEMP_MULT_CTRC(1);
|
||||
}
|
||||
else if(flag_set == 4)
|
||||
{
|
||||
TEMP_MULT_CTRA(1);
|
||||
TEMP_MULT_CTRB(1);
|
||||
TEMP_MULT_CTRC(0);
|
||||
}
|
||||
else if(flag_set == 5)
|
||||
{
|
||||
TEMP_MULT_CTRA(0);
|
||||
TEMP_MULT_CTRB(1);
|
||||
TEMP_MULT_CTRC(0);
|
||||
}
|
||||
else if(flag_set == 6)
|
||||
{
|
||||
TEMP_MULT_CTRA(1);
|
||||
TEMP_MULT_CTRB(0);
|
||||
TEMP_MULT_CTRC(0);
|
||||
}
|
||||
else if(flag_set == 7)
|
||||
{
|
||||
TEMP_MULT_CTRA(0);
|
||||
TEMP_MULT_CTRB(0);
|
||||
TEMP_MULT_CTRC(0);
|
||||
}
|
||||
}
|
||||
double double_Vol_to_resistance(double vol)
|
||||
{
|
||||
double ret = 0;
|
||||
//BL1117-50CX输出+5V_Tem,可通过测量VOL_Vin2校准+5V_Tem,Rt=3kΩ*Vo/(+5V_Tem-Vo)
|
||||
|
||||
ret = (3000 * vol) / (5.04 - vol);
|
||||
|
||||
return ret / 1000.0;
|
||||
}
|
||||
|
||||
double PT1000_Vol_To_Temperature(double vol)
|
||||
{
|
||||
// 定义PT1000常数
|
||||
double R;
|
||||
const double R0 = 1000.0; // 0°C时的电阻值
|
||||
const double A = 3.9083e-3; // IEC751系数
|
||||
const double B = -5.775e-7;
|
||||
const double C = -4.183e-12; // 负温度区系数
|
||||
|
||||
// 计算电阻值(kΩ单位)
|
||||
R = double_Vol_to_resistance(vol);
|
||||
|
||||
/* 校准系数(保持kΩ单位) */
|
||||
if (R > 1.219)
|
||||
{
|
||||
R = R * 1.01778; // 高温区补偿
|
||||
}
|
||||
else if (R > 1)
|
||||
{
|
||||
R = R * 1.00395; // 常温区补偿
|
||||
}
|
||||
else
|
||||
{
|
||||
R = R * 0.98884; // 低温区补偿
|
||||
}
|
||||
|
||||
// 转换为Ω单位
|
||||
double R_ohm = R * 1000.0;
|
||||
|
||||
// 计算温度
|
||||
if (R_ohm >= R0)
|
||||
{
|
||||
// 正温度区使用二次方程
|
||||
double discriminant = A * A - 4 * B * (1 - R_ohm / R0);
|
||||
return (-A + sqrt(discriminant)) / (2 * B);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 负温度区使用牛顿迭代法
|
||||
const int max_iter = 100; // 最大迭代次数
|
||||
const double tol = 1e-6; // 收敛误差
|
||||
double T = -50.0; // 初始温度估计值
|
||||
|
||||
for (int i = 0; i < max_iter; i++)
|
||||
{
|
||||
double T2 = T * T;
|
||||
double T3 = T2 * T;
|
||||
|
||||
// Callendar-Van Dusen方程
|
||||
double f = R0 * (1 + A * T + B * T2 + C * (T - 100) * T3) - R_ohm;
|
||||
|
||||
// 检查是否收敛
|
||||
if (fabs(f) < tol)
|
||||
{
|
||||
return T;
|
||||
}
|
||||
|
||||
// 导数计算
|
||||
double df = R0 * (A + 2 * B * T + C * (4 * T3 - 300 * T2));
|
||||
|
||||
// 避免除零错误
|
||||
if (fabs(df) < 1e-10)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// 牛顿迭代法更新
|
||||
T -= f / df;
|
||||
}
|
||||
|
||||
// 返回收敛值
|
||||
return T;
|
||||
}
|
||||
}
|
||||
uint32_t get_adc_data(void)
|
||||
{
|
||||
uint64_t sum = 0U;
|
||||
uint32_t i;
|
||||
|
||||
/* 仅处理DMA中断已写入的采样数据,不触发硬件采样。 */
|
||||
for (i = 0U; i < ADC_TEMP_DMA_SAMPLE_CNT; i++)
|
||||
{
|
||||
sum += g_adc_dma_buf[i];
|
||||
// printf("data = %d\n", g_adc_dma_buf[i]);
|
||||
}
|
||||
|
||||
return (uint32_t)(sum / ADC_TEMP_DMA_SAMPLE_CNT);
|
||||
|
||||
}
|
||||
uint32_t adc_readval(void)
|
||||
{
|
||||
float ret, temp_data = 0.0f;
|
||||
|
||||
ret = (get_adc_data() * 3.0f) / 4095.0f;
|
||||
|
||||
temp_data = PT1000_Vol_To_Temperature(ret);
|
||||
|
||||
return temp_data;
|
||||
|
||||
}
|
||||
void adc_test(uint8_t i)
|
||||
{
|
||||
float val_value;
|
||||
(void)i;
|
||||
delay_ms(1000);
|
||||
adc_value[0] = adc_channel_sample(ADC_CHANNEL_0);
|
||||
val_value = (adc_value[0] * 3.0f) / 4095.0f;
|
||||
(void)val_value;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
/*!
|
||||
\file adc_temp.h
|
||||
\brief ADC温度采集头文件
|
||||
|
||||
\version 2026-03-09, V1.4.0, firmware for GD32H7xx
|
||||
*/
|
||||
|
||||
#ifndef __ADC_TEMP_H
|
||||
#define __ADC_TEMP_H
|
||||
|
||||
#include <stdint.h>
|
||||
//#include <math.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
void select_temp_channel(uint8_t flag_set);
|
||||
void init_adc(void);
|
||||
uint32_t get_adc_data(void);
|
||||
uint32_t adc_readval(void);
|
||||
|
||||
#endif /* __ADC_TEMP_H */
|
||||
|
||||
@@ -0,0 +1,230 @@
|
||||
#include "sgm51652hx.h"
|
||||
#include "gd32h7xx_gpio.h"
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
|
||||
/*!
|
||||
\brief 初始化SGM51652HX芯片
|
||||
\param[in] dev: 芯片设备结构体指针
|
||||
\param[in] spi_dev: SPI设备结构体指针
|
||||
\param[out] none
|
||||
\retval 0: 成功, -1: 失败
|
||||
*/
|
||||
int sgm51652hx_init(sgm51652hx_dev_t *dev, spi_dev_t *spi_dev)
|
||||
{
|
||||
if (!dev || !spi_dev || !spi_dev->initialized) {
|
||||
return ERR_INVALIDPARAMETER;
|
||||
}
|
||||
|
||||
/* 初始化设备结构体 */
|
||||
dev->spi_dev = *spi_dev;
|
||||
dev->initialized = 1;
|
||||
|
||||
return ERR_OK_SGM;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief 去初始化SGM51652HX芯片
|
||||
\param[in] dev: 芯片设备结构体指针
|
||||
\param[out] none
|
||||
\retval 0: 成功, -1: 失败
|
||||
*/
|
||||
int sgm51652hx_deinit(sgm51652hx_dev_t *dev)
|
||||
{
|
||||
if (!dev || !dev->initialized) {
|
||||
return ERR_INVALIDPARAMETER;
|
||||
}
|
||||
|
||||
/* 复位芯片 */
|
||||
spi_rst_control(&dev->spi_dev, 1);
|
||||
|
||||
dev->initialized = 0;
|
||||
return ERR_OK_SGM;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief 向SGM51652HX芯片写入寄存器
|
||||
\param[in] dev: 芯片设备结构体指针
|
||||
\param[in] reg: 寄存器地址
|
||||
\param[in] value: 要写入的值
|
||||
\param[out] none
|
||||
\retval 0: 成功, -1: 失败
|
||||
*/
|
||||
int sgm51652hx_write_reg(sgm51652hx_dev_t *dev, uint8_t reg, uint8_t value)
|
||||
{
|
||||
if (!dev || !dev->initialized) {
|
||||
return ERR_INVALIDPARAMETER;
|
||||
}
|
||||
|
||||
/* 选中芯片 */
|
||||
spi_cs_control(&dev->spi_dev, 1);
|
||||
|
||||
/* 开启发送 */
|
||||
spi_master_transfer_start(dev->spi_dev.spi, SPI_TRANS_START);
|
||||
|
||||
/* 发送写命令:寄存器地址 << 1 | 1 */
|
||||
uint8_t cmd = (reg << 1) | 1;
|
||||
spi_transmit_receive_byte(dev->spi_dev.spi, cmd); //TBD:经测试,调用发送接收函数,后续采样正常,如果只调用发送函数,后续采样不正常;但另一版程序没有此问题,原因待定 lyn260411
|
||||
/* 发送数据 */
|
||||
spi_transmit_receive_byte(dev->spi_dev.spi, value);
|
||||
/* 发送两个空字节 */
|
||||
spi_transmit_receive_byte(dev->spi_dev.spi, 0x00);
|
||||
spi_transmit_receive_byte(dev->spi_dev.spi, 0x00);
|
||||
|
||||
/* 取消片选 */
|
||||
spi_cs_control(&dev->spi_dev, 0);
|
||||
|
||||
return ERR_OK_SGM;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief 从SGM51652HX芯片读取寄存器
|
||||
\param[in] dev: 芯片设备结构体指针
|
||||
\param[in] reg: 寄存器地址
|
||||
\param[out] value: 读取的值
|
||||
\retval 0: 成功, -1: 失败
|
||||
*/
|
||||
int sgm51652hx_read_reg(sgm51652hx_dev_t *dev, uint8_t reg, uint8_t *value)
|
||||
{
|
||||
if (!dev || !dev->initialized || !value) {
|
||||
return ERR_INVALIDPARAMETER;
|
||||
}
|
||||
|
||||
/* 选中芯片 */
|
||||
spi_cs_control(&dev->spi_dev, 1);
|
||||
|
||||
/* 开启发送 */
|
||||
spi_master_transfer_start(dev->spi_dev.spi, SPI_TRANS_START);
|
||||
|
||||
/* 发送读命令:寄存器地址 << 1 | 0 */
|
||||
uint8_t cmd = (reg << 1) | 0;
|
||||
spi_transmit_byte(dev->spi_dev.spi, cmd);
|
||||
/* 发送空字节 */
|
||||
spi_transmit_byte(dev->spi_dev.spi, 0x00);
|
||||
/* 读取数据 */
|
||||
*value = spi_receive_byte(dev->spi_dev.spi);
|
||||
/* 读取最后一个空字节 */
|
||||
spi_receive_byte(dev->spi_dev.spi);
|
||||
|
||||
/* 取消片选 */
|
||||
spi_cs_control(&dev->spi_dev, 0);
|
||||
|
||||
return ERR_OK_SGM;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief 设置SGM51652HX芯片通道量程
|
||||
\param[in] dev: 芯片设备结构体指针
|
||||
\param[in] channel: 通道号 (0-7)
|
||||
\param[in] range: 量程配置值
|
||||
\param[out] none
|
||||
\retval 0: 成功, -1: 失败
|
||||
*/
|
||||
int sgm51652hx_set_range(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(dev, reg, (uint8_t)range);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief 从SGM51652HX芯片读取通道数据
|
||||
\param[in] dev: 芯片设备结构体指针
|
||||
\param[in] channel: 通道号 (0-7)
|
||||
\param[out] value: 读取的16位ADC值
|
||||
\retval 0: 成功, -1: 失败
|
||||
*/
|
||||
int sgm51652hx_read_channel(sgm51652hx_dev_t *dev, uint8_t channel, uint16_t *value)
|
||||
{
|
||||
if (!dev || !dev->initialized || !value || channel > 7) {
|
||||
return ERR_INVALIDPARAMETER;
|
||||
}
|
||||
|
||||
/* 计算通道命令 */
|
||||
uint16_t cmd = 0xC000 + (channel * 0x400); /* MAN_CH_0 = 0xC000 */
|
||||
|
||||
/* 选中芯片 */
|
||||
spi_cs_control(&dev->spi_dev, 1);
|
||||
|
||||
/* 开启发送 */
|
||||
spi_master_transfer_start(dev->spi_dev.spi, SPI_TRANS_START);
|
||||
|
||||
/* 发送命令 */
|
||||
spi_transmit_receive_byte(dev->spi_dev.spi, (cmd >> 8) & 0xFF); //cmd高
|
||||
spi_transmit_receive_byte(dev->spi_dev.spi, cmd & 0xFF); //
|
||||
spi_transmit_receive_byte(dev->spi_dev.spi, 0x00); //MSB格式,接收高8位
|
||||
spi_transmit_receive_byte(dev->spi_dev.spi, 0x00); //接收低8位
|
||||
|
||||
/* 取消片选 */
|
||||
spi_cs_control(&dev->spi_dev, 0); //
|
||||
|
||||
/* ADC芯片需要转换时间,添加延时确保数据就绪 */
|
||||
vTaskDelay(pdMS_TO_TICKS(1)); // 延时1毫秒
|
||||
|
||||
/* 再次选中芯片,读取数据 */
|
||||
spi_cs_control(&dev->spi_dev, 1);
|
||||
|
||||
/* 发送四个空字节,同时读取数据 */
|
||||
uint8_t rxbuf[4] = {0};
|
||||
rxbuf[0] = spi_transmit_receive_byte(dev->spi_dev.spi, 0x00);
|
||||
rxbuf[1] = spi_transmit_receive_byte(dev->spi_dev.spi, 0x00);
|
||||
rxbuf[2] = spi_transmit_receive_byte(dev->spi_dev.spi, 0x00);
|
||||
rxbuf[3] = spi_transmit_receive_byte(dev->spi_dev.spi, 0x00);
|
||||
|
||||
/* 取消片选 */
|
||||
spi_cs_control(&dev->spi_dev, 0);
|
||||
|
||||
/* 合并16位数据 */
|
||||
*value = (rxbuf[2] << 8) | rxbuf[3];
|
||||
|
||||
//printf("spix recv:%d %d %d %d\n", rxbuf[0], rxbuf[1], rxbuf[2], rxbuf[3]);
|
||||
|
||||
return ERR_OK_SGM;
|
||||
}
|
||||
/*!
|
||||
\brief 根据原始ADC值和量程配置计算电压 芯片引脚真实电压
|
||||
\param[in] adc_val: 原始ADC值
|
||||
\param[in] range: 量程配置值
|
||||
\param[out] none
|
||||
\retval 计算后的电压值 (V)
|
||||
*/
|
||||
float sgm51652hx_calc_voltage(uint16_t adc_val, sgm51652hxRngVlu_e range)
|
||||
{
|
||||
float voltage = 0.0f;
|
||||
|
||||
switch(range)
|
||||
{
|
||||
// ==================== 双极性 Bipolar ====================
|
||||
case RGVL_BP_1024: // ±10.24V
|
||||
voltage = (int16_t)adc_val * 10.24f / 32768.0f;
|
||||
break;
|
||||
|
||||
case RGVL_BP_512: // ±5.12V
|
||||
voltage = (int16_t)adc_val * 5.12f / 32768.0f;
|
||||
break;
|
||||
|
||||
case RGVL_BP_256: // ±2.56V
|
||||
voltage = (int16_t)adc_val * 2.56f / 32768.0f;
|
||||
break;
|
||||
|
||||
// ==================== 单极性 Unipolar ====================
|
||||
case RGVL_UP_1024: // 0~10.24V
|
||||
voltage = (float)adc_val * 10.24f / 65535.0f;
|
||||
break;
|
||||
|
||||
case RGVL_UP_512: // 0~5.12V
|
||||
voltage = (float)adc_val * 5.12f / 65535.0f;
|
||||
break;
|
||||
|
||||
default: // 错误配置
|
||||
voltage = 0.0f;
|
||||
break;
|
||||
}
|
||||
return voltage;
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
/*!
|
||||
\file sgm51652hx
|
||||
\brief
|
||||
|
||||
1. 芯片基本信息:
|
||||
1)型号:sgm51652H4(4通道)、sgm51652H8(8通道)
|
||||
2)类型:16位500kSPS单电源 SAR ADC
|
||||
3)基准:片内4.096V高精度基准(温漂9ppm/℃)
|
||||
4)供电:AVDD:4.75~5.25(典型5V),DVDD:1.65~AVDD(典型3.3V)
|
||||
2. 模拟输入特性
|
||||
1)支持输入类型:双极性单端、单极性单端、双极性差分
|
||||
2)量程配置(软件独立设置)
|
||||
量程配置值 -- 输入范围 -- 对应VREF倍数
|
||||
0000 ±10.24V ±2.5 * VREF
|
||||
0001 ±5.12V ±1.25 * VREF
|
||||
0010 ±2.56V ±0.625 * VREF
|
||||
0101 0~10.24V 0~2.5 * VREF
|
||||
0110 0~5.12V 0~1.25 * VREF
|
||||
3. 数字接口与时序
|
||||
1)通信接口:SPI,模式Mode3(CPOL=1 时钟空闲时为高电平、CPHA=1 数据在时钟下降沿采样)
|
||||
2)SCLK最高频率:17Mhz。(GD32H759芯片SPI3/SPI5挂在APB2总线,当前APB2时钟300Mhz,按32预分频设置)
|
||||
3)转换时间1μs,采集时间1μs
|
||||
4)帧结构:寄存器读写24个SCLK,数据读取32个SCLK
|
||||
***每个通道读数,是CS拉低后【此句很重要,查看芯片数据手册波形图】,后面16个时钟读出的数据才是。虽然这个图是auto的,但跟手动是一样的。***
|
||||
5)支持拓扑:菊花链,最多挂4片
|
||||
4. 寄存器与命令系统
|
||||
1)命令寄存器(16位,只写),详见 sgm51652hxCmd_e
|
||||
2)关键程序寄存器,详见 sgm51652hxReg_e
|
||||
5. 工作模式
|
||||
1)自动扫描模式(AUTO_SCAN):按使能通道升序循环采集
|
||||
2)手动通道模式(MAN_CH_n):固定采集指定单通道
|
||||
3)待机模式(STDBY):低功耗,唤醒约20μs,保留配置
|
||||
4)掉电模式(PWR_DOWN):极低功耗,唤醒需15ms
|
||||
5)复位模式(RST):寄存器恢复默认值
|
||||
*/
|
||||
|
||||
#ifndef _SGM51652HX_H_
|
||||
#define _SGM51652HX_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include "spi_if.h"
|
||||
|
||||
|
||||
/******* Macro Definitions *******************/
|
||||
#define __SGM51652H8__ 1 //SPI3-H4、SPI5-H8
|
||||
|
||||
#define ERR_OK_SGM 0
|
||||
#define ERR_INVALIDPARAMETER -1
|
||||
#define ERR_TIMEOUT_SGM -2
|
||||
|
||||
typedef struct {
|
||||
spi_dev_t spi_dev; // SPI设备
|
||||
uint8_t initialized; // 初始化状态
|
||||
} sgm51652hx_dev_t;
|
||||
|
||||
// 兼容旧结构体名称
|
||||
typedef sgm51652hx_dev_t sgm51652hxDevice_t;
|
||||
|
||||
//命令寄存器映射(命令寄存器是1个 16 位的只写寄存器,用于设置SGM51652H4/SGM51652H8 的工作模式。)
|
||||
typedef enum{
|
||||
NO_OP = 0x0000, //保持当前模式
|
||||
STDBY = 0x8200, //进入待机模式
|
||||
PWR_DN = 0x8300, //进入断电模式
|
||||
RST = 0x8500, //重置程序寄存器
|
||||
AUTO_RST = 0xA000, //启用通道自动扫描模式
|
||||
MAN_CH_0 = 0xC000, //选择通道0手动读取模式
|
||||
MAN_CH_1 = 0xC400, //选择通道1手动读取模式
|
||||
MAN_CH_2 = 0xC800, //选择通道2手动读取模式
|
||||
MAN_CH_3 = 0xCC00, //选择通道3手动读取模式
|
||||
#if __SGM51652H8__ == 1
|
||||
MAN_CH_4 = 0xD000,
|
||||
MAN_CH_5 = 0xD400,
|
||||
MAN_CH_6 = 0xD800,
|
||||
MAN_CH_7 = 0xDC00,
|
||||
#endif
|
||||
MAN_AUX = 0xE000, //特殊功能,手动采辅助通道Aux,纯差分输入,无PGA/滤波,范围-VREF~+VREF
|
||||
MAX_CMD_NUM
|
||||
}sgm51652hxCmd_e;
|
||||
|
||||
//程序寄存器映射(程序寄存器是 16 位的可读写寄存器,用于设置SGM51652H4/SGM51652H8 的工作状态。)
|
||||
/*
|
||||
数据位 DB[15:9]是寄存器地址。数据位 DB[8]是写或读指令位。
|
||||
在写操作周期中,SDI 引脚上的 DIN[7:0]是写入目标寄存器的数据,SDO 引脚上的 DIN[7:0]是从目标寄存器读回的数据。读回数据可用于验证写入是否成功。
|
||||
在1个读周期中,SDI 数据位 DB[8]是读指令位。SDO DOUT[7:0]上的数据是来自目标地址程序寄存器的读回数据。
|
||||
读回数据是MSB(高位优先)模式
|
||||
*/
|
||||
typedef enum{
|
||||
AUTO_SEQ_EN = 0x01, // 自动扫描通道使能。通道自扫描模式下,扫描通道的选定,数据bit7-bit0代表通道7-通道9,0:不选定该通道,1:选定该通道
|
||||
CHANNEL_PD = 0x02, // 通道独立断电。通道自扫描模式下,通道电源控制,数据bit7-bit0代表通道7-通道9,0:通道开启电源,1:通道电源关闭
|
||||
FEATURE_SEL, // 菊花链/输出格式
|
||||
RANGE_CH0 = 0x05, // 0x05~0x0C:CH0-CH7量程配置。 RANGE_CHn 通道 n 选择输入范围位,数据bit7-bit4补0,数据bit3-bit0定义如下
|
||||
RANGE_CH1, // 0000 = 输入范围设置为±2.5 × V(默认)
|
||||
RANGE_CH2, // 0001 = 输入范围设置为±1.25 × V
|
||||
RANGE_CH3, // 0010 = 输入范围设置为±0.625 × V
|
||||
#if __SGM51652H4__ == 0 // 0101 = 输入范围设置为 0 到 2.5 × V
|
||||
RANGE_CH4, // 0110 = 输入范围设置为 0 到 1.25 × V
|
||||
RANGE_CH5,
|
||||
RANGE_CH6,
|
||||
RANGE_CH7,
|
||||
#endif
|
||||
FLOATING_DETECTION_EN = 0x0D, //悬空检测使能。输入浮动检测启用控制,数据bit7:0 = 禁用,1 = 启用,bit6-bit0 保留,补0
|
||||
FLOATING_DETECTION_STATUS, //悬空检测状态。查询输入浮动状态,数据bit7-bit0代表通道7-1,0=通道未处于浮动状态(默认)1=通道处于浮动状态
|
||||
CMD_READ_BK = 0x3F, //命令回读(只读),查询前1个数据帧中执行的命令
|
||||
|
||||
}sgm51652hxReg_e;
|
||||
|
||||
/* 量程配置值(写进CHx量程寄存器的配置值)
|
||||
* 详见本文件顶部2.2。 双极性bipolar,单极性unipolar
|
||||
*/
|
||||
typedef enum{
|
||||
RGVL_BP_1024 = 0x00, //类型:双极性,输入范围:±10.24V
|
||||
RGVL_BP_512,
|
||||
RGVL_BP_256,
|
||||
RGVL_UP_1024 = 0x05, //类型:单极性,输入范围:0~10.24V
|
||||
RGVL_UP_512,
|
||||
}sgm51652hxRngVlu_e;
|
||||
|
||||
// 芯片操作函数
|
||||
int sgm51652hx_init(sgm51652hx_dev_t *dev, spi_dev_t *spi_dev);
|
||||
int sgm51652hx_deinit(sgm51652hx_dev_t *dev);
|
||||
int sgm51652hx_write_reg(sgm51652hx_dev_t *dev, uint8_t reg, uint8_t value);
|
||||
int sgm51652hx_read_reg(sgm51652hx_dev_t *dev, uint8_t reg, uint8_t *value);
|
||||
int sgm51652hx_set_range(sgm51652hx_dev_t *dev, uint8_t channel, sgm51652hxRngVlu_e range);
|
||||
int sgm51652hx_read_channel(sgm51652hx_dev_t *dev, uint8_t channel, uint16_t *value);
|
||||
float sgm51652hx_calc_voltage(uint16_t adc_val, sgm51652hxRngVlu_e range);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
#include "spi_if.h"
|
||||
#include <gd32h7xx_spi.h>
|
||||
#include <gd32h7xx_gpio.h>
|
||||
|
||||
|
||||
|
||||
/*!
|
||||
\brief SPIx发送数据 (私有函数)
|
||||
\param[in] spi_periph: SPIx(x=0,1,2,3,4,5)
|
||||
\param[in] data: 要发送的数据(uint8_t,一次发送1个字节!!)
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void spi_transmit_byte(uint32_t spi_periph, uint8_t data)
|
||||
{
|
||||
/* 等待发送缓冲区有空间 */
|
||||
while(RESET == spi_i2s_flag_get(spi_periph, SPI_FLAG_TP));
|
||||
|
||||
/* 发送数据 */
|
||||
spi_i2s_data_transmit(spi_periph, data);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief SPIx接收数据 (私有函数)
|
||||
\param[in] spi_periph: SPIx(x=0,1,2,3,4,5)
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval 接收到的数据(uint8_t 一次接收1个字节)
|
||||
*/
|
||||
uint8_t spi_receive_byte(uint32_t spi_periph)
|
||||
{
|
||||
/* 等待接收缓冲区非空 */
|
||||
while(RESET == spi_i2s_flag_get(spi_periph, SPI_FLAG_RP));
|
||||
|
||||
/* 接收数据 */
|
||||
return (uint8_t)spi_i2s_data_receive(spi_periph);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief SPIx发送接收数据 (私有函数)
|
||||
\param[in] spi_periph: SPIx(x=0,1,2,3,4,5)
|
||||
\param[in] tx_data: 要发送的数据
|
||||
\param[out] none
|
||||
\retval 接收到的数据
|
||||
*/
|
||||
uint8_t spi_transmit_receive_byte(uint32_t spi_periph, uint8_t tx_data)
|
||||
{
|
||||
/* 等待发送缓冲区有空间 */
|
||||
while(RESET == spi_i2s_flag_get(spi_periph, SPI_FLAG_TP));
|
||||
|
||||
/* 发送数据 */
|
||||
spi_i2s_data_transmit(spi_periph, tx_data);
|
||||
|
||||
/* 等待接收缓冲区非空 */
|
||||
while(RESET == spi_i2s_flag_get(spi_periph, SPI_FLAG_RP));
|
||||
|
||||
/* 接收数据 */
|
||||
return (uint8_t)spi_i2s_data_receive(spi_periph);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief 控制SPI设备的片选引脚
|
||||
\param[in] dev: SPI设备结构体指针
|
||||
\param[in] enable: 1-选中设备, 0-取消选中
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void spi_cs_control(spi_dev_t *dev, uint8_t enable)
|
||||
{
|
||||
if (dev && dev->csPort) {
|
||||
if (enable) {
|
||||
/* 拉低片选引脚,选中设备 */
|
||||
gpio_bit_reset((uint32_t)dev->csPort, dev->csPin);
|
||||
} else {
|
||||
/* 拉高片选引脚,取消选中设备 */
|
||||
gpio_bit_set((uint32_t)dev->csPort, dev->csPin);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief 控制SPI设备的复位引脚
|
||||
\param[in] dev: SPI设备结构体指针
|
||||
\param[in] enable: 1-复位, 0-正常
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void spi_rst_control(spi_dev_t *dev, uint8_t enable)
|
||||
{
|
||||
if (dev && dev->rstPort) {
|
||||
if (enable) {
|
||||
/* 拉低复位引脚,复位设备 */
|
||||
gpio_bit_reset((uint32_t)dev->rstPort, dev->rstPin);
|
||||
} else {
|
||||
/* 拉高复位引脚,设备正常工作 */
|
||||
gpio_bit_set((uint32_t)dev->rstPort, dev->rstPin);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief 初始化SPI设备
|
||||
\param[in] dev: SPI设备结构体指针
|
||||
\param[in] spi_periph: SPI外设
|
||||
\param[in] csPort: 片选GPIO端口
|
||||
\param[in] csPin: 片选GPIO引脚
|
||||
\param[in] rstPort: 复位GPIO端口
|
||||
\param[in] rstPin: 复位GPIO引脚
|
||||
\param[out] none
|
||||
\retval 0: 成功, -1: 失败
|
||||
*/
|
||||
int spi_init_dev(spi_dev_t *dev, uint32_t spi_periph, uint32_t csPort, uint16_t csPin, uint32_t rstPort, uint16_t rstPin)
|
||||
{
|
||||
if (!dev) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* 初始化设备结构体 */
|
||||
dev->spi = spi_periph;
|
||||
dev->csPort = csPort;
|
||||
dev->csPin = csPin;
|
||||
dev->rstPort = rstPort;
|
||||
dev->rstPin = rstPin;
|
||||
dev->initialized = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief 去初始化SPI设备
|
||||
\param[in] dev: SPI设备结构体指针
|
||||
\param[out] none
|
||||
\retval 0: 成功, -1: 失败
|
||||
*/
|
||||
int spi_deinit_dev(spi_dev_t *dev)
|
||||
{
|
||||
if (!dev || !dev->initialized) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
dev->initialized = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
/*!
|
||||
\file spi_if.h
|
||||
\brief spi接收发送统一接口函数
|
||||
|
||||
\version firmware for GD32H7xx
|
||||
*/
|
||||
|
||||
#ifndef _SPI_IF_H_
|
||||
#define _SPI_IF_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint32_t spi; // MCU对应的SPI口
|
||||
uint32_t rstPort; // 复位GPIO引脚
|
||||
uint16_t rstPin; // 复位pin引脚
|
||||
uint32_t csPort; // 片选GPIO引脚
|
||||
uint16_t csPin; // 片选pin引脚
|
||||
uint8_t initialized; // 初始化状态
|
||||
} spi_dev_t;
|
||||
|
||||
// 兼容旧结构体名称
|
||||
typedef spi_dev_t spi_t;
|
||||
|
||||
/* 对外接口函数 */
|
||||
void spi_transmit_byte(uint32_t spi_periph, uint8_t data);
|
||||
uint8_t spi_receive_byte(uint32_t spi_periph);
|
||||
uint8_t spi_transmit_receive_byte(uint32_t spi_periph, uint8_t tx_data);
|
||||
|
||||
// GPIO控制函数
|
||||
void spi_cs_control(spi_dev_t *dev, uint8_t enable);
|
||||
void spi_rst_control(spi_dev_t *dev, uint8_t enable);
|
||||
|
||||
// SPI初始化函数
|
||||
int spi_init_dev(spi_dev_t *dev, uint32_t spi_periph, uint32_t csPort, uint16_t csPin, uint32_t rstPort, uint16_t rstPin);
|
||||
int spi_deinit_dev(spi_dev_t *dev);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
Reference in New Issue
Block a user