/*! \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 #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