sync: 合并内网 LDC1612_last_version 代码变更

- 覆盖 Src/Inc/SDK/LD/doc 等源码文件
- 保留 cmake 构建配置和 Git 历史不变
- 来源: 内网 LDC1612_last_version
This commit is contained in:
2026-06-30 09:46:25 +08:00
parent 1d7afaa382
commit b280589e71
97 changed files with 55304 additions and 56365 deletions
+52 -52
View File
@@ -1,52 +1,52 @@
#include "gd32e23x.h"
#include "board_config.h"
#include "systick.h"
/******************************************************************************/
#define FLASH_SIZE_ADDR (*(const uint8_t *)0x1FFFF7E0) // Flash base address
/******************************************************************************/
/* 前向声明中断处理函数 */
void usart0_irq_handler(void);
void usart1_irq_handler(void);
usart_config_t g_usart_config = {
.rcu_usart = RCU_USART1,
.usart_periph = USART1,
.irq_type = USART1_IRQn,
.irq_handler = usart1_irq_handler // 初始化函数指针
};
uint8_t g_mcu_flash_size = 0;
void mcu_detect_and_config(void) {
g_mcu_flash_size = FLASH_SIZE_ADDR;
switch (g_mcu_flash_size) {
case GD32E23XF4:
g_usart_config.rcu_usart = RCU_USART0;
g_usart_config.usart_periph = USART0;
g_usart_config.irq_type = USART0_IRQn;
g_usart_config.irq_handler = usart0_irq_handler; // 指向USART0处理函数
break;
case GD32E23XF6:
g_usart_config.rcu_usart = RCU_USART1;
g_usart_config.usart_periph = USART1;
g_usart_config.irq_type = USART1_IRQn;
g_usart_config.irq_handler = usart1_irq_handler; // 指向USART1处理函数
break;
default: // Default to GD32E23XF8
g_usart_config.rcu_usart = RCU_USART1;
g_usart_config.usart_periph = USART1;
g_usart_config.irq_type = USART1_IRQn;
g_usart_config.irq_handler = usart1_irq_handler; // 指向USART1处理函数
break;
}
}
uint8_t get_flash_size(void) {
return g_mcu_flash_size;
}
#include "gd32e23x.h"
#include "board_config.h"
#include "systick.h"
/******************************************************************************/
#define FLASH_SIZE_ADDR (*(const uint8_t *)0x1FFFF7E0) // Flash base address
/******************************************************************************/
/* 前向声明中断处理函数 */
void usart0_irq_handler(void);
void usart1_irq_handler(void);
usart_config_t g_usart_config = {
.rcu_usart = RCU_USART1,
.usart_periph = USART1,
.irq_type = USART1_IRQn,
.irq_handler = usart1_irq_handler // 初始化函数指针
};
uint8_t g_mcu_flash_size = 0;
void mcu_detect_and_config(void) {
g_mcu_flash_size = FLASH_SIZE_ADDR;
switch (g_mcu_flash_size) {
case GD32E23XF4:
g_usart_config.rcu_usart = RCU_USART0;
g_usart_config.usart_periph = USART0;
g_usart_config.irq_type = USART0_IRQn;
g_usart_config.irq_handler = usart0_irq_handler; // 指向USART0处理函数
break;
case GD32E23XF6:
g_usart_config.rcu_usart = RCU_USART1;
g_usart_config.usart_periph = USART1;
g_usart_config.irq_type = USART1_IRQn;
g_usart_config.irq_handler = usart1_irq_handler; // 指向USART1处理函数
break;
default: // Default to GD32E23XF8
g_usart_config.rcu_usart = RCU_USART1;
g_usart_config.usart_periph = USART1;
g_usart_config.irq_type = USART1_IRQn;
g_usart_config.irq_handler = usart1_irq_handler; // 指向USART1处理函数
break;
}
}
uint8_t get_flash_size(void) {
return g_mcu_flash_size;
}
+474 -613
View File
File diff suppressed because it is too large Load Diff
+117 -117
View File
@@ -1,117 +1,117 @@
/*!
\file gd32e23x_it.c
\brief interrupt service routines
\version 2025-02-10, V2.4.0, demo for GD32E23x
*/
/*
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 "gd32e23x_it.h"
#include "systick.h"
#include "uart.h"
#include "uart_ring_buffer.h"
#include "led.h"
#include "board_config.h"
/*!
\brief this function handles NMI exception
\param[in] none
\param[out] none
\retval none
*/
void NMI_Handler(void)
{
/* if NMI exception occurs, go to infinite loop */
while(1) {
}
}
/*!
\brief this function handles HardFault exception
\param[in] none
\param[out] none
\retval none
*/
void HardFault_Handler(void)
{
/* if Hard Fault exception occurs, go to infinite loop */
while(1) {
}
}
/*!
\brief this function handles SVC exception
\param[in] none
\param[out] none
\retval none
*/
void SVC_Handler(void)
{
/* if SVC exception occurs, go to infinite loop */
while(1) {
}
}
/*!
\brief this function handles PendSV exception
\param[in] none
\param[out] none
\retval none
*/
void PendSV_Handler(void)
{
/* if PendSV exception occurs, go to infinite loop */
while(1) {
}
}
/*!
\brief this function handles SysTick exception
\param[in] none
\param[out] none
\retval none
*/
void SysTick_Handler(void) {
led_heart_beat(); // LED心跳指示灯
delay_decrement();
}
void USART0_IRQHandler(void) {
// 检查当前配置是否使用USART0,并且函数指针不为空
if(g_usart_config.usart_periph == USART0 && g_usart_config.irq_handler != 0) {
g_usart_config.irq_handler(); // 通过函数指针调用对应的处理函数
}
}
void USART1_IRQHandler(void) {
// 检查当前配置是否使用USART1,并且函数指针不为空
if(g_usart_config.usart_periph == USART1 && g_usart_config.irq_handler != 0) {
g_usart_config.irq_handler(); // 通过函数指针调用对应的处理函数
}
}
/*!
\file gd32e23x_it.c
\brief interrupt service routines
\version 2025-02-10, V2.4.0, demo for GD32E23x
*/
/*
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 "gd32e23x_it.h"
#include "systick.h"
#include "uart.h"
#include "uart_ring_buffer.h"
#include "led.h"
#include "board_config.h"
/*!
\brief this function handles NMI exception
\param[in] none
\param[out] none
\retval none
*/
void NMI_Handler(void)
{
/* if NMI exception occurs, go to infinite loop */
while(1) {
}
}
/*!
\brief this function handles HardFault exception
\param[in] none
\param[out] none
\retval none
*/
void HardFault_Handler(void)
{
/* if Hard Fault exception occurs, go to infinite loop */
while(1) {
}
}
/*!
\brief this function handles SVC exception
\param[in] none
\param[out] none
\retval none
*/
void SVC_Handler(void)
{
/* if SVC exception occurs, go to infinite loop */
while(1) {
}
}
/*!
\brief this function handles PendSV exception
\param[in] none
\param[out] none
\retval none
*/
void PendSV_Handler(void)
{
/* if PendSV exception occurs, go to infinite loop */
while(1) {
}
}
/*!
\brief this function handles SysTick exception
\param[in] none
\param[out] none
\retval none
*/
void SysTick_Handler(void) {
led_heart_beat(); // LED心跳指示灯
delay_decrement();
}
void USART0_IRQHandler(void) {
// 检查当前配置是否使用USART0,并且函数指针不为空
if(g_usart_config.usart_periph == USART0 && g_usart_config.irq_handler != 0) {
g_usart_config.irq_handler(); // 通过函数指针调用对应的处理函数
}
}
void USART1_IRQHandler(void) {
// 检查当前配置是否使用USART1,并且函数指针不为空
if(g_usart_config.usart_periph == USART1 && g_usart_config.irq_handler != 0) {
g_usart_config.irq_handler(); // 通过函数指针调用对应的处理函数
}
}
+677 -1158
View File
File diff suppressed because it is too large Load Diff
+245 -334
View File
@@ -1,335 +1,246 @@
//
// Created by dell on 24-12-3.
//
#include "ldc1612.h"
#ifdef LDC_DEBUG
#include <stdio.h>
#define LDC1612_DEBUG(fmt, ...) printf("[LDC1612] " fmt "\n", ##__VA_ARGS__)
#else
#define LDC1612_DEBUG(fmt, ...)
#endif
/*!
\brief 写入寄存器
\param[in] reg_addr: 寄存器地址
\param[in] value: 写入值
\param[out] none
\retval i2c_result_t
*/
static i2c_result_t ldc1612_write_register(uint8_t reg_addr, uint16_t value) {
uint8_t data[2];
data[0] = (value >> 8) & 0xFF;
data[1] = value & 0xFF;
return LDC1612_IIC_WRITE_16BITS(LDC1612_ADDR, reg_addr, data);
}
/*!
\brief 读取寄存器
\param[in] reg_addr: 寄存器地址
\param[out] value: 读取值指针
\retval i2c_status_t
*/
static i2c_result_t ldc1612_read_register(uint8_t reg_addr, uint16_t *value) {
uint8_t data[2];
i2c_result_t status;
if (value == NULL) {
return I2C_RESULT_INVALID_PARAM;
}
status = LDC1612_IIC_READ_16BITS(LDC1612_ADDR, reg_addr, data);
if (status == I2C_RESULT_SUCCESS) {
*value = ((uint16_t)data[0] << 8) | data[1];
}
return status;
}
/*!
\brief 计算并获取频率分频值
\param[in] channel: 通道号
\param[out] none
\retval 计算得到的频率分频值
*/
static uint16_t ldc1612_calculate_freq_divider(uint8_t channel) {
uint16_t value;
uint16_t fin_div, freq_div;
float sensor_freq;
sensor_freq = 1 / (2 * 3.14 * sqrt(COIL_L_UH * COIL_C_PF * pow(10, -18))) * pow(10, -6);
if (sensor_freq <= 8.75) {
fin_div = LDC1612_FIN_DIV_1;
} else if (sensor_freq <= 17.5) {
fin_div = LDC1612_FIN_DIV_2;
} else if (sensor_freq <= 35.0) {
fin_div = LDC1612_FIN_DIV_4;
} else {
LDC1612_DEBUG("Error: Sensor frequency (%.2f MHz) exceeds maximum limit!", sensor_freq);
return 0;
}
/*
Fref为参考时钟频率,单位MHz,必须小于35MHz,如果输入时钟为外部时钟40MHz,则需要分频
LDC1612_EXT_CLK_MHZ为外部时钟频率,单位MHz
Fin为传感器谐振频率,单位MHz。
必须满足:Fin < Fref / 4
通常高精度应用,采用外部40MHz,2分频,Fin不应超5MHz。
*/
if (LDC1612_EXT_CLK_MHZ >= 35)
{
freq_div = LDC1612_FREF_DIV_2;
} else {
freq_div = LDC1612_FREF_DIV_1;
}
if (sensor_freq >= (LDC1612_EXT_CLK_MHZ / freq_div) / 4)
{
LDC1612_DEBUG("Warning: Sensor frequency (%.2f MHz) is too high for the given reference clock (%.2f MHz)!\n", sensor_freq, (float)(LDC1612_EXT_CLK_MHZ / freq_div));
}
value = LDC1612_CLOCK_DIVIDER_GEN(fin_div, freq_div);
return value;
}
uint16_t ldc1612_get_manufacturer_id(void) {
uint8_t data[2] = {0};
LDC1612_IIC_READ_16BITS(LDC1612_ADDR, READ_MANUFACTURER_ID, data);
return (data[0] << 8) | data[1];
}
uint16_t ldc1612_get_deveice_id(void) {
uint8_t data[2] = {0};
LDC1612_IIC_READ_16BITS(LDC1612_ADDR, READ_DEVICE_ID, data);
return (data[0] << 8) | data[1];
}
/** @brief reset sensor.
* */
ldc1612_status_t ldc1612_reset_sensor(void) {
i2c_result_t state = ldc1612_write_register(SENSOR_RESET_REG, LDC1612_RESET_DEV);
return (state == I2C_RESULT_SUCCESS) ? LDC1612_STATUS_SUCCESS : LDC1612_STATUS_ERROR;
}
ldc1612_status_t ldc1612_init(void) {
i2c_result_t i2c_status;
uint16_t manufacturer_id, device_id;
/* reset LDC1612 sensor */
i2c_status = ldc1612_reset_sensor();
if (i2c_status != I2C_RESULT_SUCCESS) {
return LDC1612_STATUS_ERROR;
}
delay_ms(100);
manufacturer_id = ldc1612_get_manufacturer_id();
device_id = ldc1612_get_deveice_id();
if (manufacturer_id != 0x5449 || device_id != 0x3055) {
return LDC1612_STATUS_ERROR;
}
return LDC1612_STATUS_SUCCESS;
}
/*!
\brief 配置单通道模式
\param[in] channel: 通道号 (0或1)
\param[out] none
\retval ldc1612_status_t
*/
ldc1612_status_t ldc1612_config_single_channel(uint8_t channel) {
i2c_result_t status;
if (channel > 1) {
return LDC1612_STATUS_INVALID_PARAM;
}
/* 配置顺序严格按照TI官方文档要求 */
/* Step 1: 确保传感器处于睡眠模式 - 配置前必须 */
status = ldc1612_write_register(SENSOR_CONFIG_REG, LDC1612_SLEEP_MODE);
if (status != I2C_RESULT_SUCCESS) return LDC1612_STATUS_ERROR;
delay_ms(10);
/* Step 2: 配置频率分频 - 必须在其他配置之前 */
uint16_t freq_divider = ldc1612_calculate_freq_divider(channel);
ldc1612_write_register(SET_FREQ_REG_START + channel, freq_divider);
delay_ms(5);
/* Step 3: 配置LC稳定时间 - 影响测量精度 */
ldc1612_write_register(SET_SETTLECOUNT_REG_START + channel, LDC1612_SETTLECOUNT_CH0);
/* Step 4: 配置转换时间 - 影响测量速度和精度 */
ldc1612_write_register(SET_CONVERSION_TIME_REG_START + channel, LDC1612_RCOUNT_TIME_CH0);
/* Step 5: 配置转换偏移 */
ldc1612_write_register(SET_CONVERSION_OFFSET_REG_START + channel, SET_CONVERSION_OFFSET_CH0);
/* Step 6: 配置驱动电流 - 影响传感器灵敏度 */
ldc1612_write_register(SET_DRIVER_CURRENT_REG + channel, LDC1612_DRIVE_CURRENT);
/* Step 7: 配置多路复用器 - 设置通道选择和滤波 */
// ldc1612_configure_mux_register(LDC1612_MUX_AUTOSCAN_DISABLE, LDC1612_MUX_RR_SEQUENCE_0, LDC1612_MUX_FILTER_ALL_LOW, LDC1612_MUX_FILTER_NONE);
ldc1612_write_register(MUX_CONFIG_REG, LDC1612_MUX_CONFIG);
/* Step 8: 配置错误输出 */
ldc1612_write_register(ERROR_CONFIG_REG, LDC1612_ERROR_CONFIG_DEFAULT);
/* Step 9: 最后启动传感器 - 必须最后一步 */
status = ldc1612_write_register(SENSOR_CONFIG_REG, LDC1612_SENSOR_CONFIG_CH0);
if (status != I2C_RESULT_SUCCESS) return LDC1612_STATUS_ERROR;
/* Step 10: 等待传感器稳定 */
delay_ms(50);
return LDC1612_STATUS_SUCCESS;
}
/** @brief read the raw channel result from register.
@param channel LDC1612 has total two channels.
@param result raw data
* */
uint32_t ldc1612_get_raw_channel_result(uint8_t channel) {
uint32_t raw_value = 0;
uint8_t value[2] = {0};
/* Read MSW */
LDC1612_IIC_READ_16BITS(LDC1612_ADDR, CONVERSION_RESULT_REG_START + (channel * 2), value);
raw_value |= (uint32_t)(((uint16_t)value[0] << 8) | value[1]) << 16;
/* Read LSW */
LDC1612_IIC_READ_16BITS(LDC1612_ADDR, CONVERSION_RESULT_REG_START + 1 + (channel * 2), value);
raw_value |= (uint32_t)(((uint16_t)value[0] << 8) | value[1]);
uint32_t calibration_value = raw_value & 0x0FFFFFFF;
if (calibration_value == 0x0FFFFFFF) {
return 0xF0000000; /* No coil */
}
if (LDC1612_ERROR_CONFIG_DEFAULT & 0xF800) {
uint8_t error_code = (uint8_t)(raw_value >> 24);
if (error_code & 0x80) return 0x80000000; /* Under range */
if (error_code & 0x40) return 0x40000000; /* Over range */
if (error_code & 0x20) return 0x20000000; /* Watchdog */
if (error_code & 0x10) return 0x10000000; /* Amplitude error */
}
return raw_value;
}
void ldc1612_drvie_current_detect(uint8_t channel) {
uint8_t data[2] = {0};
uint16_t init_value = 0 , drive_current = 0;
ldc1612_write_register(SENSOR_CONFIG_REG, LDC1612_SLEEP_MODE);
delay_ms(10);
uint16_t freq_divider = ldc1612_calculate_freq_divider(channel);
ldc1612_write_register(SET_FREQ_REG_START + channel, freq_divider);
delay_ms(5);
LDC1612_IIC_READ_16BITS(LDC1612_ADDR, SENSOR_CONFIG_REG, data);
// ldc1612_set_sensor_config(LDC1612_SLEEP_MODE);
ldc1612_write_register(SENSOR_CONFIG_REG, LDC1612_SLEEP_MODE);
delay_ms(10);
ldc1612_write_register(SENSOR_CONFIG_REG, LDC1612_SENSOR_CONFIG_CH0);
delay_ms(10);
LDC1612_IIC_READ_16BITS(LDC1612_ADDR, SET_DRIVER_CURRENT_REG, data);
init_value = (((data[0] << 8) | data[1]) >> 6) & 0x1F;
drive_current = (init_value << 11) | 0x0000;
LDC1612_DEBUG("init value: 0x%x\tdrive current: 0x%x\n", init_value, drive_current);
}
/** @brief Get sensor status register
@return Status register value
* */
uint16_t ldc1612_get_sensor_status(void) {
uint8_t data[2] = {0};
LDC1612_IIC_READ_16BITS(LDC1612_ADDR, SENSOR_STATUS_REG, data);
return (data[0] << 8) | data[1];
}
/** @brief Check if data is ready for specific channel
@param channel Channel to check (0 or 1)
@return true if data is ready, false otherwise
* */
bool ldc1612_is_data_ready(uint8_t channel) {
uint16_t status = ldc1612_get_sensor_status();
if (channel == 0) {
return (status & 0x0040) != 0; // DRDY_0 bit
} else if (channel == 1) {
return (status & 0x0080) != 0; // DRDY_1 bit
}
return false;
}
/*!
\brief 检查并记录LDC1612的状态和错误
\param[in] none
\param[out] none
\retval 读取到的原始状态寄存器值
*/
uint16_t ldc1612_check_status_and_log_errors(void) {
uint16_t status;
i2c_result_t i2c_status = ldc1612_read_register(SENSOR_STATUS_REG, &status);
if (i2c_status != I2C_RESULT_SUCCESS) {
LDC1612_DEBUG("Failed to read STATUS register!");
return 0;
}
LDC1612_DEBUG("--- LDC1612 Status Check (Value: 0x%04X) ---", status);
// 检查数据就绪状态
if (status & LDC1612_STATUS_DRDY) {
LDC1612_DEBUG(" [OK] Data is ready.");
}
if (status & LDC1612_STATUS_UNREAD_CH0) {
LDC1612_DEBUG(" [INFO] Channel 0 has unread data.");
}
if (status & LDC1612_STATUS_UNREAD_CH1) {
LDC1612_DEBUG(" [INFO] Channel 1 has unread data.");
}
// 检查是否有任何错误标志
if ((status & 0x3F00) == 0) { // 检查所有错误位的掩码
LDC1612_DEBUG(" [OK] No errors detected.");
} else {
uint8_t err_chan = (status & LDC1612_STATUS_ERR_CHAN_MASK) >> 14;
LDC1612_DEBUG(" [ERROR] An error occurred on Channel %d.", err_chan);
if (status & LDC1612_STATUS_ERR_UR) {
LDC1612_DEBUG(" - Underflow Error: Conversion result is less than OFFSET.");
}
if (status & LDC1612_STATUS_ERR_OR) {
LDC1612_DEBUG(" - Overflow Error: Conversion result is at maximum.");
}
if (status & LDC1612_STATUS_ERR_WD) {
LDC1612_DEBUG(" - Watchdog Timeout: Sensor failed to complete conversion in time.");
}
if (status & LDC1612_STATUS_ERR_AHE) {
LDC1612_DEBUG(" - Amplitude High Error: Sensor oscillation amplitude > 1.8V.");
}
if (status & LDC1612_STATUS_ERR_ALE) {
LDC1612_DEBUG(" - Amplitude Low Error: Sensor oscillation amplitude < 1.2V.");
}
if (status & LDC1612_STATUS_ERR_ZC) {
LDC1612_DEBUG(" - Zero-Count Error: Reference count is zero, check clock.");
}
}
LDC1612_DEBUG("-------------------------------------------------");
// 读取STATUS寄存器会自动清除错误标志,但不会清除DRDY和UNREADCONV标志
return status;
//
// Created by dell on 24-12-3.
//
#include "ldc1612.h"
/*!
\brief 写入寄存器
\param[in] reg_addr: 寄存器地址
\param[in] value: 写入值
\param[out] none
\retval i2c_result_t
*/
static i2c_result_t ldc1612_write_register(uint8_t reg_addr, uint16_t value) {
uint8_t data[2];
data[0] = (value >> 8) & 0xFF;
data[1] = value & 0xFF;
return LDC1612_IIC_WRITE_16BITS(LDC1612_ADDR, reg_addr, data);
}
/*!
\brief 读取寄存器
\param[in] reg_addr: 寄存器地址
\param[out] value: 读取值指针
\retval i2c_status_t
*/
static i2c_result_t ldc1612_read_register(uint8_t reg_addr, uint16_t *value) {
uint8_t data[2];
i2c_result_t status;
if (value == NULL) {
return I2C_RESULT_INVALID_PARAM;
}
status = LDC1612_IIC_READ_16BITS(LDC1612_ADDR, reg_addr, data);
if (status == I2C_RESULT_SUCCESS) {
*value = ((uint16_t)data[0] << 8) | data[1];
}
return status;
}
/*!
\brief 计算并获取频率分频值
\param[in] channel: 通道号
\param[out] none
\retval 计算得到的频率分频值
*/
static uint16_t ldc1612_calculate_freq_divider(uint8_t channel) {
uint16_t value;
uint16_t fin_div, freq_div;
float sensor_freq;
sensor_freq = 1 / (2 * 3.14 * sqrt(COIL_L_UH * COIL_C_PF * pow(10, -18))) * pow(10, -6);
fin_div = (uint16_t) (sensor_freq / 8.75 + 1);
if (fin_div * 4 < 40) {
freq_div = 2;
} else {
freq_div = 4;
}
value = fin_div << 12;
value |= freq_div;
return value;
}
uint16_t ldc1612_get_manufacturer_id(void) {
uint8_t data[2] = {0};
LDC1612_IIC_READ_16BITS(LDC1612_ADDR, READ_MANUFACTURER_ID, data);
return (data[0] << 8) | data[1];
}
uint16_t ldc1612_get_deveice_id(void) {
uint8_t data[2] = {0};
LDC1612_IIC_READ_16BITS(LDC1612_ADDR, READ_DEVICE_ID, data);
return (data[0] << 8) | data[1];
}
/** @brief reset sensor.
* */
ldc1612_status_t ldc1612_reset_sensor(void) {
i2c_result_t state = ldc1612_write_register(SENSOR_RESET_REG, LDC1612_RESET_DEV);
return (state == I2C_RESULT_SUCCESS) ? LDC1612_STATUS_SUCCESS : LDC1612_STATUS_ERROR;
}
ldc1612_status_t ldc1612_init(void) {
i2c_result_t i2c_status;
uint16_t manufacturer_id, device_id;
/* reset LDC1612 sensor */
i2c_status = ldc1612_reset_sensor();
if (i2c_status != I2C_RESULT_SUCCESS) {
return LDC1612_STATUS_ERROR;
}
delay_ms(100);
manufacturer_id = ldc1612_get_manufacturer_id();
device_id = ldc1612_get_deveice_id();
if (manufacturer_id != 0x5449 || device_id != 0x3055) {
return LDC1612_STATUS_ERROR;
}
return LDC1612_STATUS_SUCCESS;
}
/*!
\brief 配置单通道模式
\param[in] channel: 通道号 (0或1)
\param[out] none
\retval ldc1612_status_t
*/
ldc1612_status_t ldc1612_config_single_channel(uint8_t channel) {
i2c_result_t status;
if (channel > 1) {
return LDC1612_STATUS_INVALID_PARAM;
}
/* 配置顺序严格按照TI官方文档要求 */
/* Step 1: 确保传感器处于睡眠模式 - 配置前必须 */
status = ldc1612_write_register(SENSOR_CONFIG_REG, LDC1612_SLEEP_MODE);
if (status != I2C_RESULT_SUCCESS) return LDC1612_STATUS_ERROR;
delay_ms(10);
/* Step 2: 配置频率分频 - 必须在其他配置之前 */
uint16_t freq_divider = ldc1612_calculate_freq_divider(channel);
ldc1612_write_register(SET_FREQ_REG_START + channel, freq_divider);
delay_ms(5);
/* Step 3: 配置LC稳定时间 - 影响测量精度 */
ldc1612_write_register(SET_SETTLECOUNT_REG_START + channel, LDC1612_SETTLECOUNT_CH0);
/* Step 4: 配置转换时间 - 影响测量速度和精度 */
ldc1612_write_register(SET_CONVERSION_TIME_REG_START + channel, LDC1612_RCOUNT_TIME_CH0);
/* Step 5: 配置转换偏移 */
ldc1612_write_register(SET_CONVERSION_OFFSET_REG_START + channel, SET_CONVERSION_OFFSET_CH0);
/* Step 6: 配置驱动电流 - 影响传感器灵敏度 */
ldc1612_write_register(SET_DRIVER_CURRENT_REG + channel, LDC1612_DRIVE_CURRENT);
/* Step 7: 配置多路复用器 - 设置通道选择和滤波 */
// ldc1612_configure_mux_register(LDC1612_MUX_AUTOSCAN_DISABLE, LDC1612_MUX_RR_SEQUENCE_0, LDC1612_MUX_FILTER_ALL_LOW, LDC1612_MUX_FILTER_NONE);
ldc1612_write_register(MUX_CONFIG_REG, LDC1612_MUX_CONFIG);
/* Step 8: 配置错误输出 */
ldc1612_write_register(ERROR_CONFIG_REG, LDC1612_ERROR_CONFIG);
/* Step 9: 最后启动传感器 - 必须最后一步 */
status = ldc1612_write_register(SENSOR_CONFIG_REG, LDC1612_SENSOR_CONFIG_CH0);
if (status != I2C_RESULT_SUCCESS) return LDC1612_STATUS_ERROR;
/* Step 10: 等待传感器稳定 */
delay_ms(50);
return LDC1612_STATUS_SUCCESS;
}
/** @brief read the raw channel result from register.
@param channel LDC1612 has total two channels.
@param result raw data
* */
uint32_t ldc1612_get_raw_channel_result(uint8_t channel) {
uint32_t raw_value = 0;
uint8_t value[2] = {0};
/* Read MSW */
LDC1612_IIC_READ_16BITS(LDC1612_ADDR, CONVERTION_RESULT_REG_START + (channel * 2), value);
raw_value |= (uint32_t)(((uint16_t)value[0] << 8) | value[1]) << 16;
/* Read LSW */
LDC1612_IIC_READ_16BITS(LDC1612_ADDR, CONVERTION_RESULT_REG_START + 1 + (channel * 2), value);
raw_value |= (uint32_t)(((uint16_t)value[0] << 8) | value[1]);
uint32_t calibration_value = raw_value & 0x0FFFFFFF;
if (calibration_value == 0x0FFFFFFF) {
return 0xF0000000; /* No coil */
}
if (LDC1612_ERROR_CONFIG & 0xF800) {
uint8_t error_code = (uint8_t)(raw_value >> 24);
if (error_code & 0x80) return 0x80000000; /* Under range */
if (error_code & 0x40) return 0x40000000; /* Over range */
if (error_code & 0x20) return 0x20000000; /* Watchdog */
if (error_code & 0x10) return 0x10000000; /* Amplitude error */
}
return raw_value;
}
void ldc1612_drvie_current_detect(uint8_t channel) {
uint8_t data[2] = {0};
uint16_t init_value = 0 , drive_current = 0;
ldc1612_write_register(SENSOR_CONFIG_REG, LDC1612_SLEEP_MODE);
delay_ms(10);
uint16_t freq_divider = ldc1612_calculate_freq_divider(channel);
ldc1612_write_register(SET_FREQ_REG_START + channel, freq_divider);
delay_ms(5);
LDC1612_IIC_READ_16BITS(LDC1612_ADDR, SENSOR_CONFIG_REG, data);
// ldc1612_set_sensor_config(LDC1612_SLEEP_MODE);
ldc1612_write_register(SENSOR_CONFIG_REG, LDC1612_SLEEP_MODE);
delay_ms(10);
ldc1612_write_register(SENSOR_CONFIG_REG, LDC1612_SENSOR_CONFIG_CH0);
delay_ms(10);
LDC1612_IIC_READ_16BITS(LDC1612_ADDR, SET_DRIVER_CURRENT_REG, data);
init_value = (((data[0] << 8) | data[1]) >> 6) & 0x1F;
drive_current = (init_value << 11) | 0x0000;
printf("init value: 0x%x\tdrive current: 0x%x\n", init_value, drive_current);
}
/** @brief Get sensor status register
@return Status register value
* */
uint16_t ldc1612_get_sensor_status(void) {
uint8_t data[2] = {0};
LDC1612_IIC_READ_16BITS(LDC1612_ADDR, SENSOR_STATUS_REG, data);
return (data[0] << 8) | data[1];
}
/** @brief Check if data is ready for specific channel
@param channel Channel to check (0 or 1)
@return true if data is ready, false otherwise
* */
bool ldc1612_is_data_ready(uint8_t channel) {
uint16_t status = ldc1612_get_sensor_status();
if (channel == 0) {
return (status & 0x0040) != 0; // DRDY_0 bit
} else if (channel == 1) {
return (status & 0x0080) != 0; // DRDY_1 bit
}
return false;
}
+57 -57
View File
@@ -1,57 +1,57 @@
#include "led.h"
/**
* @brief LED心跳指示灯功能
* @details 实现类似心跳的LED闪烁模式:快闪两次然后暂停
* 适合在SysTick中断中调用,通过计数器控制闪烁节拍
* @note 假设SysTick中断频率为1ms,心跳周期约为2秒
* 心跳模式:亮200ms->灭200ms->亮200ms->灭1400ms(循环)
*/
void led_heart_beat(void)
{
static uint16_t heart_beat_counter = 0;
// 心跳周期:2000ms (假设SysTick为1ms中断)
// 模式:亮200ms -> 灭200ms -> 亮200ms -> 灭1400ms
heart_beat_counter++;
if (heart_beat_counter <= 200) {
// 第一次亮:0-200ms
led_on();
}
else if (heart_beat_counter <= 400) {
// 第一次灭:200-400ms
led_off();
}
else if (heart_beat_counter <= 600) {
// 第二次亮:400-600ms
led_on();
}
else if (heart_beat_counter <= 2000) {
// 长时间灭:600-2000ms
led_off();
}
else {
// 重置计数器,开始新的心跳周期
heart_beat_counter = 0;
}
}
void led_init(void) {
rcu_periph_clock_enable(LED_RCU);
gpio_mode_set(LED_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, LED_PIN);
gpio_output_options_set(LED_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, LED_PIN);
gpio_bit_set(LED_PORT, LED_PIN);
}
void led_on(void) {
gpio_bit_reset(LED_PORT, LED_PIN);
}
void led_off(void) {
gpio_bit_set(LED_PORT, LED_PIN);
}
void led_toggle(void) {
gpio_bit_toggle(LED_PORT, LED_PIN);
}
#include "led.h"
/**
* @brief LED心跳指示灯功能
* @details 实现类似心跳的LED闪烁模式:快闪两次然后暂停
* 适合在SysTick中断中调用,通过计数器控制闪烁节拍
* @note 假设SysTick中断频率为1ms,心跳周期约为2秒
* 心跳模式:亮200ms->灭200ms->亮200ms->灭1400ms(循环)
*/
void led_heart_beat(void)
{
static uint16_t heart_beat_counter = 0;
// 心跳周期:2000ms (假设SysTick为1ms中断)
// 模式:亮200ms -> 灭200ms -> 亮200ms -> 灭1400ms
heart_beat_counter++;
if (heart_beat_counter <= 200) {
// 第一次亮:0-200ms
led_on();
}
else if (heart_beat_counter <= 400) {
// 第一次灭:200-400ms
led_off();
}
else if (heart_beat_counter <= 600) {
// 第二次亮:400-600ms
led_on();
}
else if (heart_beat_counter <= 2000) {
// 长时间灭:600-2000ms
led_off();
}
else {
// 重置计数器,开始新的心跳周期
heart_beat_counter = 0;
}
}
void led_init(void) {
rcu_periph_clock_enable(LED_RCU);
gpio_mode_set(LED_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, LED_PIN);
gpio_output_options_set(LED_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, LED_PIN);
gpio_bit_set(LED_PORT, LED_PIN);
}
void led_on(void) {
gpio_bit_reset(LED_PORT, LED_PIN);
}
void led_off(void) {
gpio_bit_set(LED_PORT, LED_PIN);
}
void led_toggle(void) {
gpio_bit_toggle(LED_PORT, LED_PIN);
}
+111 -111
View File
@@ -1,111 +1,111 @@
/*!
\file main.c
\brief running LED
\version 2025-02-10, V2.4.0, demo for GD32E23x
*/
/*
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 "gd32e23x.h"
#include "systick.h"
#include "uart.h"
#include "led.h"
#include "command.h"
#include <stdio.h>
#include "i2c.h"
#include "board_config.h"
#include "ldc1612.h"
#include "tmp112.h"
/*!
\brief main function
\param[in] none
\param[out] none
\retval none
*/
int main(void)
{
// nvic_vector_table_set(NVIC_VECTTAB_FLASH, 0x2000);
led_init();
mcu_detect_and_config();
setbuf(stdout, NULL);
systick_config();
rs485_init();
// led_init();
// printf("Flash size: %d Kbytes\n", get_flash_size());
#ifdef DEBUG_VERBOSE
char hello_world[] = {"Hello World!\r\n"};
for (uint8_t i = 0; i < sizeof(hello_world); i++)
{
while (usart_flag_get(RS485_PHY, USART_FLAG_TBE) == RESET) {}
usart_data_transmit(RS485_PHY, hello_world[i]);
}
while (usart_flag_get(RS485_PHY, USART_FLAG_TC) == RESET) {}
#endif
i2c_config();
#ifdef DEBUG_VERBOSE
i2c_scan();
i2c_bus_reset();
#endif
ldc1612_init();
ldc1612_config_single_channel(CHANNEL_0);
tmp112a_init();
#ifdef EDDY_DRIVE_CURRENT_DETECTION
ldc1612_drvie_current_detect(CHANNEL_0);
#endif
while(1){
#ifndef EDDY_DRIVE_CURRENT_DETECTION
command_process();
delay_ms(10);
if (g_eddy_current_sensor_report_enabled)
eddy_current_report();
#else
ldc1612_drvie_current_detect(CHANNEL_0);
delay_ms(1000);
#endif
}
}
/*!
\file main.c
\brief running LED
\version 2025-02-10, V2.4.0, demo for GD32E23x
*/
/*
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 "gd32e23x.h"
#include "systick.h"
#include "uart.h"
#include "led.h"
#include "command.h"
#include <stdio.h>
#include "i2c.h"
#include "board_config.h"
#include "ldc1612.h"
#include "tmp112.h"
/*!
\brief main function
\param[in] none
\param[out] none
\retval none
*/
int main(void)
{
nvic_vector_table_set(NVIC_VECTTAB_FLASH, 0x2000);
led_init();
mcu_detect_and_config();
setbuf(stdout, NULL);
systick_config();
rs485_init();
// led_init();
// printf("Flash size: %d Kbytes\n", get_flash_size());
#ifdef DEBUG_VERBOSE
char hello_world[] = {"Hello World!\r\n"};
for (uint8_t i = 0; i < sizeof(hello_world); i++)
{
while (usart_flag_get(RS485_PHY, USART_FLAG_TBE) == RESET) {}
usart_data_transmit(RS485_PHY, hello_world[i]);
}
while (usart_flag_get(RS485_PHY, USART_FLAG_TC) == RESET) {}
#endif
i2c_config();
#ifdef DEBUG_VERBOSE
i2c_scan();
i2c_bus_reset();
#endif
ldc1612_init();
ldc1612_config_single_channel(CHANNEL_0);
tmp112a_init();
#ifdef EDDY_DRIVE_CURRENT_DETECTION
ldc1612_drvie_current_detect(CHANNEL_0);
#endif
while(1){
#ifndef EDDY_DRIVE_CURRENT_DETECTION
command_process();
delay_ms(10);
if (g_eddy_current_sensor_report_enabled)
eddy_current_report();
#else
ldc1612_drvie_current_detect(CHANNEL_0);
delay_ms(1000);
#endif
}
}
+233 -233
View File
@@ -1,234 +1,234 @@
//
// Created by dell on 24-12-28.
//
#include "soft_i2c.h"
/*!
\brief delay
\param[in] none
\param[out] none
\retval none
*/
void soft_i2c_delay(void) {
delay_10us(2); // Adjust delay as needed
/* delay to freq
* 15KHz: delay_us(20);
* 65KHz: delay_us(1);
*/
}
/*!
\brief configure the software IIC GPIO
\param[in] none
\param[out] none
\retval none
*/
void soft_i2c_config(void) {
rcu_periph_clock_enable(RCU_GPIO_I2C);
gpio_mode_set(I2C_SCL_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, I2C_SCL_PIN);
gpio_output_options_set(I2C_SCL_PORT, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, I2C_SCL_PIN);
gpio_mode_set(I2C_SDA_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, I2C_SDA_PIN);
gpio_output_options_set(I2C_SDA_PORT, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, I2C_SDA_PIN);
I2C_SCL_HIGH();
I2C_SDA_HIGH();
}
/*!
\brief generate I2C start signal
\param[in] none
\param[out] none
\retval none
*/
void soft_i2c_start(void) {
I2C_SDA_HIGH();
I2C_SCL_HIGH();
soft_i2c_delay();
I2C_SDA_LOW();
soft_i2c_delay();
I2C_SCL_LOW();
}
/*!
\brief generate I2C stop signal
\param[in] none
\param[out] none
\retval none
*/
void soft_i2c_stop(void) {
I2C_SCL_LOW(); // 确保时钟为低
I2C_SDA_LOW(); // 拉低数据线
soft_i2c_delay();
I2C_SCL_HIGH(); // 拉高时钟
soft_i2c_delay();
I2C_SDA_HIGH(); // 在时钟高电平时拉高数据线产生停止条件
soft_i2c_delay(); // 添加缺失的延时
}
/*!
\brief send I2C ACK signal
\param[in] none
\param[out] none
\retval none
*/
void soft_i2c_send_ack(void) {
// sda_out();
I2C_SDA_LOW();
soft_i2c_delay();
I2C_SCL_HIGH();
soft_i2c_delay();
I2C_SCL_LOW();
soft_i2c_delay();
I2C_SDA_HIGH();
}
/*!
\brief send I2C NACK signal
\param[in] none
\param[out] none
\retval none
*/
void soft_i2c_send_nack(void) {
I2C_SDA_HIGH();
soft_i2c_delay();
I2C_SCL_HIGH();
soft_i2c_delay();
I2C_SCL_LOW();
soft_i2c_delay();
I2C_SDA_HIGH();
}
/*!
\brief wait I2C ACK signal
\param[in] none
\param[out] none
\retval 0: ACK received, 1: ACK not received
*/
uint8_t soft_i2c_wait_ack(void) {
I2C_SDA_HIGH(); // 释放SDA线,让从设备控制
soft_i2c_delay();
I2C_SCL_HIGH(); // 拉高时钟
soft_i2c_delay();
uint8_t ack = !I2C_SDA_READ(); // 读取ACK信号(低电平为ACK)
I2C_SCL_LOW(); // 拉低时钟
soft_i2c_delay(); // 添加缺失的延时
return ack;
}
/*!
\brief send a byte via I2C
\param[in] byte: byte to be sent
\param[out] none
\retval none
*/
void soft_i2c_send_byte(uint8_t byte) {
// sda_out();
for (int i = 0; i < 8; i++) {
if (byte & 0x80) {
I2C_SDA_HIGH();
} else {
I2C_SDA_LOW();
}
byte <<= 1;
soft_i2c_delay();
I2C_SCL_HIGH();
soft_i2c_delay();
I2C_SCL_LOW();
soft_i2c_delay();
}
}
/*!
\brief receive a byte via I2C
\param[in] ack: 1: send ACK, 0: send NACK
\param[out] none
\retval received byte
*/
uint8_t soft_i2c_receive_byte(uint8_t ack) {
uint8_t byte = 0;
I2C_SDA_HIGH();
for (int i = 0; i < 8; i++) {
byte <<= 1;
I2C_SCL_HIGH();
soft_i2c_delay();
if (I2C_SDA_READ()) {
byte |= 0x01;
}
I2C_SCL_LOW();
soft_i2c_delay();
}
if (ack) {
soft_i2c_send_ack();
} else {
soft_i2c_send_nack();
}
return byte;
}
uint8_t soft_i2c_write_16bits(uint8_t slave_addr, uint8_t reg_addr, uint8_t data[2]) {
/* 参数验证 */
if (data == NULL || slave_addr > 0x7F) {
return SOFT_I2C_FAIL;
}
soft_i2c_start();
soft_i2c_send_byte(slave_addr << 1); // 修复:左移1位,添加写位
if (!soft_i2c_wait_ack()) {
soft_i2c_stop();
return SOFT_I2C_FAIL;
}
soft_i2c_send_byte(reg_addr);
if (!soft_i2c_wait_ack()) {
soft_i2c_stop();
return SOFT_I2C_FAIL;
}
soft_i2c_send_byte(data[0]);
if (!soft_i2c_wait_ack()) {
soft_i2c_stop();
return SOFT_I2C_FAIL;
}
soft_i2c_send_byte(data[1]);
if (!soft_i2c_wait_ack()) { // 修复:添加错误处理
soft_i2c_stop();
return SOFT_I2C_FAIL;
}
soft_i2c_stop();
return SOFT_I2C_OK;
}
uint8_t soft_i2c_read_16bits(uint8_t slave_addr, uint8_t reg_addr, uint8_t *data)
{
/* 参数验证 */
if (data == NULL || slave_addr > 0x7F) {
return SOFT_I2C_FAIL;
}
/* 写阶段:发送寄存器地址 */
soft_i2c_start();
soft_i2c_send_byte(slave_addr << 1); // 修复:左移1位,写操作
if (!soft_i2c_wait_ack()) {
soft_i2c_stop();
return SOFT_I2C_FAIL;
}
soft_i2c_send_byte(reg_addr);
if (!soft_i2c_wait_ack()) {
soft_i2c_stop();
return SOFT_I2C_FAIL;
}
/* 读阶段:重新开始并读取数据 */
soft_i2c_start(); // 重新开始
soft_i2c_send_byte((slave_addr << 1) | 0x01); // 修复:正确的读地址
if (!soft_i2c_wait_ack()) {
soft_i2c_stop();
return SOFT_I2C_FAIL;
}
soft_i2c_delay();
data[0] = soft_i2c_receive_byte(1); // 第一个字节发送ACK
data[1] = soft_i2c_receive_byte(0); // 最后一个字节发送NACK
soft_i2c_stop();
return SOFT_I2C_OK;
//
// Created by dell on 24-12-28.
//
#include "soft_i2c.h"
/*!
\brief delay
\param[in] none
\param[out] none
\retval none
*/
void soft_i2c_delay(void) {
delay_10us(2); // Adjust delay as needed
/* delay to freq
* 15KHz: delay_us(20);
* 65KHz: delay_us(1);
*/
}
/*!
\brief configure the software IIC GPIO
\param[in] none
\param[out] none
\retval none
*/
void soft_i2c_config(void) {
rcu_periph_clock_enable(RCU_GPIO_I2C);
gpio_mode_set(I2C_SCL_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, I2C_SCL_PIN);
gpio_output_options_set(I2C_SCL_PORT, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, I2C_SCL_PIN);
gpio_mode_set(I2C_SDA_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, I2C_SDA_PIN);
gpio_output_options_set(I2C_SDA_PORT, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, I2C_SDA_PIN);
I2C_SCL_HIGH();
I2C_SDA_HIGH();
}
/*!
\brief generate I2C start signal
\param[in] none
\param[out] none
\retval none
*/
void soft_i2c_start(void) {
I2C_SDA_HIGH();
I2C_SCL_HIGH();
soft_i2c_delay();
I2C_SDA_LOW();
soft_i2c_delay();
I2C_SCL_LOW();
}
/*!
\brief generate I2C stop signal
\param[in] none
\param[out] none
\retval none
*/
void soft_i2c_stop(void) {
I2C_SCL_LOW(); // 确保时钟为低
I2C_SDA_LOW(); // 拉低数据线
soft_i2c_delay();
I2C_SCL_HIGH(); // 拉高时钟
soft_i2c_delay();
I2C_SDA_HIGH(); // 在时钟高电平时拉高数据线产生停止条件
soft_i2c_delay(); // 添加缺失的延时
}
/*!
\brief send I2C ACK signal
\param[in] none
\param[out] none
\retval none
*/
void soft_i2c_send_ack(void) {
// sda_out();
I2C_SDA_LOW();
soft_i2c_delay();
I2C_SCL_HIGH();
soft_i2c_delay();
I2C_SCL_LOW();
soft_i2c_delay();
I2C_SDA_HIGH();
}
/*!
\brief send I2C NACK signal
\param[in] none
\param[out] none
\retval none
*/
void soft_i2c_send_nack(void) {
I2C_SDA_HIGH();
soft_i2c_delay();
I2C_SCL_HIGH();
soft_i2c_delay();
I2C_SCL_LOW();
soft_i2c_delay();
I2C_SDA_HIGH();
}
/*!
\brief wait I2C ACK signal
\param[in] none
\param[out] none
\retval 0: ACK received, 1: ACK not received
*/
uint8_t soft_i2c_wait_ack(void) {
I2C_SDA_HIGH(); // 释放SDA线,让从设备控制
soft_i2c_delay();
I2C_SCL_HIGH(); // 拉高时钟
soft_i2c_delay();
uint8_t ack = !I2C_SDA_READ(); // 读取ACK信号(低电平为ACK)
I2C_SCL_LOW(); // 拉低时钟
soft_i2c_delay(); // 添加缺失的延时
return ack;
}
/*!
\brief send a byte via I2C
\param[in] byte: byte to be sent
\param[out] none
\retval none
*/
void soft_i2c_send_byte(uint8_t byte) {
// sda_out();
for (int i = 0; i < 8; i++) {
if (byte & 0x80) {
I2C_SDA_HIGH();
} else {
I2C_SDA_LOW();
}
byte <<= 1;
soft_i2c_delay();
I2C_SCL_HIGH();
soft_i2c_delay();
I2C_SCL_LOW();
soft_i2c_delay();
}
}
/*!
\brief receive a byte via I2C
\param[in] ack: 1: send ACK, 0: send NACK
\param[out] none
\retval received byte
*/
uint8_t soft_i2c_receive_byte(uint8_t ack) {
uint8_t byte = 0;
I2C_SDA_HIGH();
for (int i = 0; i < 8; i++) {
byte <<= 1;
I2C_SCL_HIGH();
soft_i2c_delay();
if (I2C_SDA_READ()) {
byte |= 0x01;
}
I2C_SCL_LOW();
soft_i2c_delay();
}
if (ack) {
soft_i2c_send_ack();
} else {
soft_i2c_send_nack();
}
return byte;
}
uint8_t soft_i2c_write_16bits(uint8_t slave_addr, uint8_t reg_addr, uint8_t data[2]) {
/* 参数验证 */
if (data == NULL || slave_addr > 0x7F) {
return SOFT_I2C_FAIL;
}
soft_i2c_start();
soft_i2c_send_byte(slave_addr << 1); // 修复:左移1位,添加写位
if (!soft_i2c_wait_ack()) {
soft_i2c_stop();
return SOFT_I2C_FAIL;
}
soft_i2c_send_byte(reg_addr);
if (!soft_i2c_wait_ack()) {
soft_i2c_stop();
return SOFT_I2C_FAIL;
}
soft_i2c_send_byte(data[0]);
if (!soft_i2c_wait_ack()) {
soft_i2c_stop();
return SOFT_I2C_FAIL;
}
soft_i2c_send_byte(data[1]);
if (!soft_i2c_wait_ack()) { // 修复:添加错误处理
soft_i2c_stop();
return SOFT_I2C_FAIL;
}
soft_i2c_stop();
return SOFT_I2C_OK;
}
uint8_t soft_i2c_read_16bits(uint8_t slave_addr, uint8_t reg_addr, uint8_t *data)
{
/* 参数验证 */
if (data == NULL || slave_addr > 0x7F) {
return SOFT_I2C_FAIL;
}
/* 写阶段:发送寄存器地址 */
soft_i2c_start();
soft_i2c_send_byte(slave_addr << 1); // 修复:左移1位,写操作
if (!soft_i2c_wait_ack()) {
soft_i2c_stop();
return SOFT_I2C_FAIL;
}
soft_i2c_send_byte(reg_addr);
if (!soft_i2c_wait_ack()) {
soft_i2c_stop();
return SOFT_I2C_FAIL;
}
/* 读阶段:重新开始并读取数据 */
soft_i2c_start(); // 重新开始
soft_i2c_send_byte((slave_addr << 1) | 0x01); // 修复:正确的读地址
if (!soft_i2c_wait_ack()) {
soft_i2c_stop();
return SOFT_I2C_FAIL;
}
soft_i2c_delay();
data[0] = soft_i2c_receive_byte(1); // 第一个字节发送ACK
data[1] = soft_i2c_receive_byte(0); // 最后一个字节发送NACK
soft_i2c_stop();
return SOFT_I2C_OK;
}
+171 -171
View File
@@ -1,171 +1,171 @@
/* Support files for GNU libc. Files in the system namespace go here.
Files in the C namespace (ie those that do not start with an
underscore) go in .c. */
#include <_ansi.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/fcntl.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <sys/time.h>
#include <sys/times.h>
#include <errno.h>
#include <reent.h>
#include <unistd.h>
#include <sys/wait.h>
#include "gd32e23x_usart.h"
#include "board_config.h"
#undef errno
extern int errno;
extern int __io_putchar(int ch) __attribute__((weak));
extern int __io_getchar(void) __attribute__((weak));
caddr_t _sbrk(int incr)
{
extern char _end[];
static char *curbrk = _end;
if ((curbrk + incr < _end))
return NULL - 1;
curbrk += incr;
return curbrk - incr;
}
/*
* _gettimeofday primitive (Stub function)
* */
int _gettimeofday (struct timeval * tp, struct timezone * tzp)
{
/* Return fixed data for the timezone. */
if (tzp)
{
tzp->tz_minuteswest = 0;
tzp->tz_dsttime = 0;
}
return 0;
}
void initialise_monitor_handles()
{
}
int _getpid(void)
{
return 1;
}
int _kill(int pid, int sig)
{
errno = EINVAL;
return -1;
}
void _exit (int status)
{
_kill(status, -1);
while (1) {}
}
int _write(int file, char *ptr, int len)
{
int DataIdx;
for (DataIdx = 0; DataIdx < len; DataIdx++)
{
__io_putchar( *ptr++ );
}
return len;
}
int _close(int file)
{
return -1;
}
int _fstat(int file, struct stat *st)
{
st->st_mode = S_IFCHR;
return 0;
}
int _isatty(int file)
{
return 1;
}
int _lseek(int file, int ptr, int dir)
{
return 0;
}
int _read(int file, char *ptr, int len)
{
int DataIdx;
for (DataIdx = 0; DataIdx < len; DataIdx++)
{
*ptr++ = __io_getchar();
}
return len;
}
int _open(char *path, int flags, ...)
{
/* Pretend like we always fail */
return -1;
}
int _wait(int *status)
{
errno = ECHILD;
return -1;
}
int _unlink(char *name)
{
errno = ENOENT;
return -1;
}
int _times(struct tms *buf)
{
return -1;
}
int _stat(char *file, struct stat *st)
{
st->st_mode = S_IFCHR;
return 0;
}
int _link(char *old, char *new)
{
errno = EMLINK;
return -1;
}
int _fork(void)
{
errno = EAGAIN;
return -1;
}
int _execve(char *name, char **argv, char **env)
{
errno = ENOMEM;
return -1;
}
// USART0 printf重定向实现
int __io_putchar(int ch) {
// 等待发送缓冲区空
while (usart_flag_get(RS485_PHY, USART_FLAG_TBE) == RESET) {}
usart_data_transmit(RS485_PHY, (uint8_t)ch);
return ch;
}
/* Support files for GNU libc. Files in the system namespace go here.
Files in the C namespace (ie those that do not start with an
underscore) go in .c. */
#include <_ansi.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/fcntl.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <sys/time.h>
#include <sys/times.h>
#include <errno.h>
#include <reent.h>
#include <unistd.h>
#include <sys/wait.h>
#include "gd32e23x_usart.h"
#include "board_config.h"
#undef errno
extern int errno;
extern int __io_putchar(int ch) __attribute__((weak));
extern int __io_getchar(void) __attribute__((weak));
caddr_t _sbrk(int incr)
{
extern char _end[];
static char *curbrk = _end;
if ((curbrk + incr < _end))
return NULL - 1;
curbrk += incr;
return curbrk - incr;
}
/*
* _gettimeofday primitive (Stub function)
* */
int _gettimeofday (struct timeval * tp, struct timezone * tzp)
{
/* Return fixed data for the timezone. */
if (tzp)
{
tzp->tz_minuteswest = 0;
tzp->tz_dsttime = 0;
}
return 0;
}
void initialise_monitor_handles()
{
}
int _getpid(void)
{
return 1;
}
int _kill(int pid, int sig)
{
errno = EINVAL;
return -1;
}
void _exit (int status)
{
_kill(status, -1);
while (1) {}
}
int _write(int file, char *ptr, int len)
{
int DataIdx;
for (DataIdx = 0; DataIdx < len; DataIdx++)
{
__io_putchar( *ptr++ );
}
return len;
}
int _close(int file)
{
return -1;
}
int _fstat(int file, struct stat *st)
{
st->st_mode = S_IFCHR;
return 0;
}
int _isatty(int file)
{
return 1;
}
int _lseek(int file, int ptr, int dir)
{
return 0;
}
int _read(int file, char *ptr, int len)
{
int DataIdx;
for (DataIdx = 0; DataIdx < len; DataIdx++)
{
*ptr++ = __io_getchar();
}
return len;
}
int _open(char *path, int flags, ...)
{
/* Pretend like we always fail */
return -1;
}
int _wait(int *status)
{
errno = ECHILD;
return -1;
}
int _unlink(char *name)
{
errno = ENOENT;
return -1;
}
int _times(struct tms *buf)
{
return -1;
}
int _stat(char *file, struct stat *st)
{
st->st_mode = S_IFCHR;
return 0;
}
int _link(char *old, char *new)
{
errno = EMLINK;
return -1;
}
int _fork(void)
{
errno = EAGAIN;
return -1;
}
int _execve(char *name, char **argv, char **env)
{
errno = ENOMEM;
return -1;
}
// USART0 printf重定向实现
int __io_putchar(int ch) {
// 等待发送缓冲区空
while (usart_flag_get(RS485_PHY, USART_FLAG_TBE) == RESET) {}
usart_data_transmit(RS485_PHY, (uint8_t)ch);
return ch;
}
+451 -451
View File
@@ -1,451 +1,451 @@
/*!
\file system_gd32e23x.c
\brief CMSIS Cortex-M23 Device Peripheral Access Layer Source File for
GD32E23x Device Series
*/
/* Copyright (c) 2012 ARM LIMITED
Copyright (c) 2025, GigaDevice Semiconductor Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- 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.
- Neither the name of ARM 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 COPYRIGHT HOLDERS AND 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.
---------------------------------------------------------------------------*/
/* This file refers the CMSIS standard, some adjustments are made according to GigaDevice chips */
#include "gd32e23x.h"
/* system frequency define */
#define __IRC8M (IRC8M_VALUE) /* internal 8 MHz RC oscillator frequency */
#define __HXTAL (HXTAL_VALUE) /* high speed crystal oscillator frequency */
#define __SYS_OSC_CLK (__IRC8M) /* main oscillator frequency */
#define VECT_TAB_OFFSET (uint32_t)0x00 /* vector table base offset */
/* select a system clock by uncommenting the following line */
//#define __SYSTEM_CLOCK_8M_HXTAL (__HXTAL)
//#define __SYSTEM_CLOCK_8M_IRC8M (__IRC8M)
// #define __SYSTEM_CLOCK_72M_PLL_HXTAL (uint32_t)(72000000)
#define __SYSTEM_CLOCK_72M_PLL_IRC8M_DIV2 (uint32_t)(72000000)
/* The following is to prevent Vcore fluctuations caused by frequency switching.
It is strongly recommended to include it to avoid issues caused by self-removal.
*/
#define RCU_MODIFY(__delay) do{ \
volatile uint32_t i,reg; \
if(0 != __delay){ \
reg = RCU_CFG0; \
reg &= ~(RCU_CFG0_AHBPSC); \
/* CK_AHB = SYSCLK/2 */ \
reg |= RCU_AHB_CKSYS_DIV2; \
RCU_CFG0 = reg; \
for(i=0; i<__delay; i++){ \
} \
reg = RCU_CFG0; \
reg &= ~(RCU_CFG0_AHBPSC); \
reg |= RCU_AHB_CKSYS_DIV4; \
/* CK_AHB = SYSCLK/4 */ \
RCU_CFG0 = reg; \
for(i=0; i<__delay; i++){ \
} \
} \
}while(0)
#define SEL_IRC8M 0x00
#define SEL_HXTAL 0x01
#define SEL_PLL 0x02
/* set the system clock frequency and declare the system clock configuration function */
#ifdef __SYSTEM_CLOCK_8M_HXTAL
uint32_t SystemCoreClock = __SYSTEM_CLOCK_8M_HXTAL;
static void system_clock_8m_hxtal(void);
#elif defined (__SYSTEM_CLOCK_72M_PLL_HXTAL)
uint32_t SystemCoreClock = __SYSTEM_CLOCK_72M_PLL_HXTAL;
static void system_clock_72m_hxtal(void);
#elif defined (__SYSTEM_CLOCK_72M_PLL_IRC8M_DIV2)
uint32_t SystemCoreClock = __SYSTEM_CLOCK_72M_PLL_IRC8M_DIV2;
static void system_clock_72m_irc8m(void);
#else
uint32_t SystemCoreClock = __SYSTEM_CLOCK_8M_IRC8M;
static void system_clock_8m_irc8m(void);
#endif /* __SYSTEM_CLOCK_8M_HXTAL */
/* configure the system clock */
static void system_clock_config(void);
/* software delay to prevent the impact of Vcore fluctuations.
It is strongly recommended to include it to avoid issues caused by self-removal. */
static void _soft_delay_(uint32_t time)
{
__IO uint32_t i;
for(i=0; i<time*10; i++){
}
}
/*!
\brief setup the microcontroller system, initialize the system
\param[in] none
\param[out] none
\retval none
*/
void SystemInit (void)
{
/* enable IRC8M */
RCU_CTL0 |= RCU_CTL0_IRC8MEN;
while(0U == (RCU_CTL0 & RCU_CTL0_IRC8MSTB)){
}
if(((RCU_CFG0 & RCU_CFG0_SCSS) == RCU_SCSS_PLL)){
RCU_MODIFY(0x80);
}
RCU_CFG0 &= ~RCU_CFG0_SCS;
_soft_delay_(100);
RCU_CTL0 &= ~(RCU_CTL0_HXTALEN | RCU_CTL0_CKMEN | RCU_CTL0_PLLEN | RCU_CTL0_HXTALBPS);
/* reset RCU */
RCU_CFG0 &= ~(RCU_CFG0_SCS | RCU_CFG0_AHBPSC | RCU_CFG0_APB1PSC | RCU_CFG0_APB2PSC |\
RCU_CFG0_ADCPSC | RCU_CFG0_CKOUTSEL | RCU_CFG0_CKOUTDIV | RCU_CFG0_PLLDV);
RCU_CFG0 &= ~(RCU_CFG0_PLLSEL | RCU_CFG0_PLLMF | RCU_CFG0_PLLMF4 | RCU_CFG0_PLLDV);
RCU_CFG1 &= ~(RCU_CFG1_PREDV);
RCU_CFG2 &= ~(RCU_CFG2_USART0SEL | RCU_CFG2_ADCSEL);
RCU_CFG2 &= ~RCU_CFG2_IRC28MDIV;
RCU_CFG2 &= ~RCU_CFG2_ADCPSC2;
RCU_CTL1 &= ~RCU_CTL1_IRC28MEN;
RCU_INT = 0x00000000U;
/* configure system clock */
system_clock_config();
#ifdef VECT_TAB_SRAM
nvic_vector_table_set(NVIC_VECTTAB_RAM,VECT_TAB_OFFSET);
#else
nvic_vector_table_set(NVIC_VECTTAB_FLASH,VECT_TAB_OFFSET);
#endif
}
/*!
\brief configure the system clock
\param[in] none
\param[out] none
\retval none
*/
static void system_clock_config(void)
{
#ifdef __SYSTEM_CLOCK_8M_HXTAL
system_clock_8m_hxtal();
#elif defined (__SYSTEM_CLOCK_72M_PLL_HXTAL)
system_clock_72m_hxtal();
#elif defined (__SYSTEM_CLOCK_72M_PLL_IRC8M_DIV2)
system_clock_72m_irc8m();
#elif defined (__SYSTEM_CLOCK_72M_PLL_IRC48M_DIV2)
system_clock_72m_irc48m();
#else
system_clock_8m_irc8m();
#endif /* __SYSTEM_CLOCK_8M_HXTAL */
}
#ifdef __SYSTEM_CLOCK_8M_HXTAL
/*!
\brief configure the system clock to 8M by HXTAL
\param[in] none
\param[out] none
\retval none
*/
static void system_clock_8m_hxtal(void)
{
uint32_t timeout = 0U;
uint32_t stab_flag = 0U;
__IO uint32_t reg_temp;
/* enable HXTAL */
RCU_CTL0 |= RCU_CTL0_HXTALEN;
/* wait until HXTAL is stable or the startup time is longer than HXTAL_STARTUP_TIMEOUT */
do{
timeout++;
stab_flag = (RCU_CTL0 & RCU_CTL0_HXTALSTB);
}
while((0U == stab_flag) && (HXTAL_STARTUP_TIMEOUT != timeout));
/* if fail */
if(0U == (RCU_CTL0 & RCU_CTL0_HXTALSTB)){
while(1){
}
}
/* HXTAL is stable */
/* AHB = SYSCLK */
RCU_CFG0 |= RCU_AHB_CKSYS_DIV1;
/* APB2 = AHB */
RCU_CFG0 |= RCU_APB2_CKAHB_DIV1;
/* APB1 = AHB */
RCU_CFG0 |= RCU_APB1_CKAHB_DIV1;
reg_temp = RCU_CFG0;
/* select HXTAL as system clock */
reg_temp &= ~RCU_CFG0_SCS;
reg_temp |= RCU_CKSYSSRC_HXTAL;
RCU_CFG0 = reg_temp;
/* wait until HXTAL is selected as system clock */
while(RCU_SCSS_HXTAL != (RCU_CFG0 & RCU_CFG0_SCSS)){
}
}
#elif defined (__SYSTEM_CLOCK_72M_PLL_HXTAL)
/*!
\brief configure the system clock to 72M by PLL which selects HXTAL as its clock source
\param[in] none
\param[out] none
\retval none
*/
static void system_clock_72m_hxtal(void)
{
uint32_t timeout = 0U;
uint32_t stab_flag = 0U;
__IO uint32_t reg_temp;
/* enable HXTAL */
RCU_CTL0 |= RCU_CTL0_HXTALEN;
/* wait until HXTAL is stable or the startup time is longer than HXTAL_STARTUP_TIMEOUT */
do{
timeout++;
stab_flag = (RCU_CTL0 & RCU_CTL0_HXTALSTB);
}
while((0U == stab_flag) && (HXTAL_STARTUP_TIMEOUT != timeout));
/* if fail */
if(0U == (RCU_CTL0 & RCU_CTL0_HXTALSTB)){
while(1){
}
}
FMC_WS = (FMC_WS & (~FMC_WS_WSCNT)) | WS_WSCNT_2;
/* HXTAL is stable */
/* AHB = SYSCLK */
RCU_CFG0 |= RCU_AHB_CKSYS_DIV1;
/* APB2 = AHB */
RCU_CFG0 |= RCU_APB2_CKAHB_DIV1;
/* APB1 = AHB */
RCU_CFG0 |= RCU_APB1_CKAHB_DIV1;
/* PLL = HXTAL * 9 = 72 MHz */
RCU_CFG0 &= ~(RCU_CFG0_PLLSEL | RCU_CFG0_PLLMF | RCU_CFG0_PLLDV);
RCU_CFG0 |= (RCU_PLLSRC_HXTAL | RCU_PLL_MUL9);
/* enable PLL */
RCU_CTL0 |= RCU_CTL0_PLLEN;
/* wait until PLL is stable */
while(0U == (RCU_CTL0 & RCU_CTL0_PLLSTB)){
}
reg_temp = RCU_CFG0;
/* select PLL as system clock */
reg_temp &= ~RCU_CFG0_SCS;
reg_temp |= RCU_CKSYSSRC_PLL;
RCU_CFG0 = reg_temp;
/* wait until PLL is selected as system clock */
while(RCU_SCSS_PLL != (RCU_CFG0 & RCU_CFG0_SCSS)){
}
}
#elif defined (__SYSTEM_CLOCK_72M_PLL_IRC8M_DIV2)
/*!
\brief configure the system clock to 72M by PLL which selects IRC8M/2 as its clock source
\param[in] none
\param[out] none
\retval none
*/
static void system_clock_72m_irc8m(void)
{
uint32_t timeout = 0U;
uint32_t stab_flag = 0U;
__IO uint32_t reg_temp;
/* enable IRC8M */
RCU_CTL0 |= RCU_CTL0_IRC8MEN;
/* wait until IRC8M is stable or the startup time is longer than IRC8M_STARTUP_TIMEOUT */
do{
timeout++;
stab_flag = (RCU_CTL0 & RCU_CTL0_IRC8MSTB);
}
while((0U == stab_flag) && (IRC8M_STARTUP_TIMEOUT != timeout));
/* if fail */
if(0U == (RCU_CTL0 & RCU_CTL0_IRC8MSTB)){
while(1){
}
}
FMC_WS = (FMC_WS & (~FMC_WS_WSCNT)) | WS_WSCNT_2;
/* AHB = SYSCLK */
RCU_CFG0 |= RCU_AHB_CKSYS_DIV1;
/* APB2 = AHB */
RCU_CFG0 |= RCU_APB2_CKAHB_DIV1;
/* APB1 = AHB */
RCU_CFG0 |= RCU_APB1_CKAHB_DIV1;
/* PLL = (IRC8M/2) * 18 = 72 MHz */
RCU_CFG0 &= ~(RCU_CFG0_PLLSEL | RCU_CFG0_PLLMF);
RCU_CFG0 |= (RCU_PLLSRC_IRC8M_DIV2 | RCU_PLL_MUL18);
/* enable PLL */
RCU_CTL0 |= RCU_CTL0_PLLEN;
/* wait until PLL is stable */
while(0U == (RCU_CTL0 & RCU_CTL0_PLLSTB)){
}
reg_temp = RCU_CFG0;
/* select PLL as system clock */
reg_temp &= ~RCU_CFG0_SCS;
reg_temp |= RCU_CKSYSSRC_PLL;
RCU_CFG0 = reg_temp;
/* wait until PLL is selected as system clock */
while(RCU_SCSS_PLL != (RCU_CFG0 & RCU_CFG0_SCSS)){
}
}
#else
/*!
\brief configure the system clock to 8M by IRC8M
\param[in] none
\param[out] none
\retval none
*/
static void system_clock_8m_irc8m(void)
{
uint32_t timeout = 0U;
uint32_t stab_flag = 0U;
__IO uint32_t reg_temp;
/* enable IRC8M */
RCU_CTL0 |= RCU_CTL0_IRC8MEN;
/* wait until IRC8M is stable or the startup time is longer than IRC8M_STARTUP_TIMEOUT */
do{
timeout++;
stab_flag = (RCU_CTL0 & RCU_CTL0_IRC8MSTB);
}
while((0U == stab_flag) && (IRC8M_STARTUP_TIMEOUT != timeout));
/* if fail */
if(0U == (RCU_CTL0 & RCU_CTL0_IRC8MSTB)){
while(1){
}
}
/* AHB = SYSCLK */
RCU_CFG0 |= RCU_AHB_CKSYS_DIV1;
/* APB2 = AHB */
RCU_CFG0 |= RCU_APB2_CKAHB_DIV1;
/* APB1 = AHB */
RCU_CFG0 |= RCU_APB1_CKAHB_DIV1;
reg_temp = RCU_CFG0;
/* select IRC8M as system clock */
reg_temp &= ~RCU_CFG0_SCS;
reg_temp |= RCU_CKSYSSRC_IRC8M;
RCU_CFG0 = reg_temp;
/* wait until IRC8M is selected as system clock */
while(RCU_SCSS_IRC8M != (RCU_CFG0 & RCU_CFG0_SCSS)){
}
}
#endif /* __SYSTEM_CLOCK_8M_HXTAL */
/*!
\brief update the SystemCoreClock with current core clock retrieved from cpu registers
\param[in] none
\param[out] none
\retval none
*/
void SystemCoreClockUpdate (void)
{
uint32_t sws = 0U;
uint32_t pllmf = 0U, pllmf4 = 0U, pllsel = 0U, prediv = 0U, idx = 0U, clk_exp = 0U;
/* exponent of AHB clock divider */
const uint8_t ahb_exp[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9};
sws = GET_BITS(RCU_CFG0, 2, 3);
switch(sws){
/* IRC8M is selected as CK_SYS */
case SEL_IRC8M:
SystemCoreClock = IRC8M_VALUE;
break;
/* HXTAL is selected as CK_SYS */
case SEL_HXTAL:
SystemCoreClock = HXTAL_VALUE;
break;
/* PLL is selected as CK_SYS */
case SEL_PLL:
/* get the value of PLLMF[3:0] */
pllmf = GET_BITS(RCU_CFG0, 18, 21);
pllmf4 = GET_BITS(RCU_CFG0, 27, 27);
/* high 16 bits */
if(1U == pllmf4){
pllmf += 17U;
}else if(15U == pllmf){
pllmf = 16U;
} else {
pllmf += 2U;
}
/* PLL clock source selection, HXTAL or IRC8M/2 */
pllsel = GET_BITS(RCU_CFG0, 16, 16);
if(0U != pllsel){
prediv = (GET_BITS(RCU_CFG1, 0, 3) + 1U);
SystemCoreClock = (HXTAL_VALUE / prediv) * pllmf;
} else {
SystemCoreClock = (IRC8M_VALUE >> 1) * pllmf;
}
break;
/* IRC8M is selected as CK_SYS */
default:
SystemCoreClock = IRC8M_VALUE;
break;
}
/* calculate AHB clock frequency */
idx = GET_BITS(RCU_CFG0, 4, 7);
clk_exp = ahb_exp[idx];
SystemCoreClock >>= clk_exp;
}
#ifdef __FIRMWARE_VERSION_DEFINE
/*!
\brief get firmware version
\param[in] none
\param[out] none
\retval firmware version
*/
uint32_t gd32e23x_firmware_version_get(void)
{
return __GD32E23x_STDPERIPH_VERSION;
}
#endif /* __FIRMWARE_VERSION_DEFINE */
/*!
\file system_gd32e23x.c
\brief CMSIS Cortex-M23 Device Peripheral Access Layer Source File for
GD32E23x Device Series
*/
/* Copyright (c) 2012 ARM LIMITED
Copyright (c) 2025, GigaDevice Semiconductor Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- 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.
- Neither the name of ARM 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 COPYRIGHT HOLDERS AND 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.
---------------------------------------------------------------------------*/
/* This file refers the CMSIS standard, some adjustments are made according to GigaDevice chips */
#include "gd32e23x.h"
/* system frequency define */
#define __IRC8M (IRC8M_VALUE) /* internal 8 MHz RC oscillator frequency */
#define __HXTAL (HXTAL_VALUE) /* high speed crystal oscillator frequency */
#define __SYS_OSC_CLK (__IRC8M) /* main oscillator frequency */
#define VECT_TAB_OFFSET (uint32_t)0x00 /* vector table base offset */
/* select a system clock by uncommenting the following line */
//#define __SYSTEM_CLOCK_8M_HXTAL (__HXTAL)
//#define __SYSTEM_CLOCK_8M_IRC8M (__IRC8M)
// #define __SYSTEM_CLOCK_72M_PLL_HXTAL (uint32_t)(72000000)
#define __SYSTEM_CLOCK_72M_PLL_IRC8M_DIV2 (uint32_t)(72000000)
/* The following is to prevent Vcore fluctuations caused by frequency switching.
It is strongly recommended to include it to avoid issues caused by self-removal.
*/
#define RCU_MODIFY(__delay) do{ \
volatile uint32_t i,reg; \
if(0 != __delay){ \
reg = RCU_CFG0; \
reg &= ~(RCU_CFG0_AHBPSC); \
/* CK_AHB = SYSCLK/2 */ \
reg |= RCU_AHB_CKSYS_DIV2; \
RCU_CFG0 = reg; \
for(i=0; i<__delay; i++){ \
} \
reg = RCU_CFG0; \
reg &= ~(RCU_CFG0_AHBPSC); \
reg |= RCU_AHB_CKSYS_DIV4; \
/* CK_AHB = SYSCLK/4 */ \
RCU_CFG0 = reg; \
for(i=0; i<__delay; i++){ \
} \
} \
}while(0)
#define SEL_IRC8M 0x00
#define SEL_HXTAL 0x01
#define SEL_PLL 0x02
/* set the system clock frequency and declare the system clock configuration function */
#ifdef __SYSTEM_CLOCK_8M_HXTAL
uint32_t SystemCoreClock = __SYSTEM_CLOCK_8M_HXTAL;
static void system_clock_8m_hxtal(void);
#elif defined (__SYSTEM_CLOCK_72M_PLL_HXTAL)
uint32_t SystemCoreClock = __SYSTEM_CLOCK_72M_PLL_HXTAL;
static void system_clock_72m_hxtal(void);
#elif defined (__SYSTEM_CLOCK_72M_PLL_IRC8M_DIV2)
uint32_t SystemCoreClock = __SYSTEM_CLOCK_72M_PLL_IRC8M_DIV2;
static void system_clock_72m_irc8m(void);
#else
uint32_t SystemCoreClock = __SYSTEM_CLOCK_8M_IRC8M;
static void system_clock_8m_irc8m(void);
#endif /* __SYSTEM_CLOCK_8M_HXTAL */
/* configure the system clock */
static void system_clock_config(void);
/* software delay to prevent the impact of Vcore fluctuations.
It is strongly recommended to include it to avoid issues caused by self-removal. */
static void _soft_delay_(uint32_t time)
{
__IO uint32_t i;
for(i=0; i<time*10; i++){
}
}
/*!
\brief setup the microcontroller system, initialize the system
\param[in] none
\param[out] none
\retval none
*/
void SystemInit (void)
{
/* enable IRC8M */
RCU_CTL0 |= RCU_CTL0_IRC8MEN;
while(0U == (RCU_CTL0 & RCU_CTL0_IRC8MSTB)){
}
if(((RCU_CFG0 & RCU_CFG0_SCSS) == RCU_SCSS_PLL)){
RCU_MODIFY(0x80);
}
RCU_CFG0 &= ~RCU_CFG0_SCS;
_soft_delay_(100);
RCU_CTL0 &= ~(RCU_CTL0_HXTALEN | RCU_CTL0_CKMEN | RCU_CTL0_PLLEN | RCU_CTL0_HXTALBPS);
/* reset RCU */
RCU_CFG0 &= ~(RCU_CFG0_SCS | RCU_CFG0_AHBPSC | RCU_CFG0_APB1PSC | RCU_CFG0_APB2PSC |\
RCU_CFG0_ADCPSC | RCU_CFG0_CKOUTSEL | RCU_CFG0_CKOUTDIV | RCU_CFG0_PLLDV);
RCU_CFG0 &= ~(RCU_CFG0_PLLSEL | RCU_CFG0_PLLMF | RCU_CFG0_PLLMF4 | RCU_CFG0_PLLDV);
RCU_CFG1 &= ~(RCU_CFG1_PREDV);
RCU_CFG2 &= ~(RCU_CFG2_USART0SEL | RCU_CFG2_ADCSEL);
RCU_CFG2 &= ~RCU_CFG2_IRC28MDIV;
RCU_CFG2 &= ~RCU_CFG2_ADCPSC2;
RCU_CTL1 &= ~RCU_CTL1_IRC28MEN;
RCU_INT = 0x00000000U;
/* configure system clock */
system_clock_config();
#ifdef VECT_TAB_SRAM
nvic_vector_table_set(NVIC_VECTTAB_RAM,VECT_TAB_OFFSET);
#else
nvic_vector_table_set(NVIC_VECTTAB_FLASH,VECT_TAB_OFFSET);
#endif
}
/*!
\brief configure the system clock
\param[in] none
\param[out] none
\retval none
*/
static void system_clock_config(void)
{
#ifdef __SYSTEM_CLOCK_8M_HXTAL
system_clock_8m_hxtal();
#elif defined (__SYSTEM_CLOCK_72M_PLL_HXTAL)
system_clock_72m_hxtal();
#elif defined (__SYSTEM_CLOCK_72M_PLL_IRC8M_DIV2)
system_clock_72m_irc8m();
#elif defined (__SYSTEM_CLOCK_72M_PLL_IRC48M_DIV2)
system_clock_72m_irc48m();
#else
system_clock_8m_irc8m();
#endif /* __SYSTEM_CLOCK_8M_HXTAL */
}
#ifdef __SYSTEM_CLOCK_8M_HXTAL
/*!
\brief configure the system clock to 8M by HXTAL
\param[in] none
\param[out] none
\retval none
*/
static void system_clock_8m_hxtal(void)
{
uint32_t timeout = 0U;
uint32_t stab_flag = 0U;
__IO uint32_t reg_temp;
/* enable HXTAL */
RCU_CTL0 |= RCU_CTL0_HXTALEN;
/* wait until HXTAL is stable or the startup time is longer than HXTAL_STARTUP_TIMEOUT */
do{
timeout++;
stab_flag = (RCU_CTL0 & RCU_CTL0_HXTALSTB);
}
while((0U == stab_flag) && (HXTAL_STARTUP_TIMEOUT != timeout));
/* if fail */
if(0U == (RCU_CTL0 & RCU_CTL0_HXTALSTB)){
while(1){
}
}
/* HXTAL is stable */
/* AHB = SYSCLK */
RCU_CFG0 |= RCU_AHB_CKSYS_DIV1;
/* APB2 = AHB */
RCU_CFG0 |= RCU_APB2_CKAHB_DIV1;
/* APB1 = AHB */
RCU_CFG0 |= RCU_APB1_CKAHB_DIV1;
reg_temp = RCU_CFG0;
/* select HXTAL as system clock */
reg_temp &= ~RCU_CFG0_SCS;
reg_temp |= RCU_CKSYSSRC_HXTAL;
RCU_CFG0 = reg_temp;
/* wait until HXTAL is selected as system clock */
while(RCU_SCSS_HXTAL != (RCU_CFG0 & RCU_CFG0_SCSS)){
}
}
#elif defined (__SYSTEM_CLOCK_72M_PLL_HXTAL)
/*!
\brief configure the system clock to 72M by PLL which selects HXTAL as its clock source
\param[in] none
\param[out] none
\retval none
*/
static void system_clock_72m_hxtal(void)
{
uint32_t timeout = 0U;
uint32_t stab_flag = 0U;
__IO uint32_t reg_temp;
/* enable HXTAL */
RCU_CTL0 |= RCU_CTL0_HXTALEN;
/* wait until HXTAL is stable or the startup time is longer than HXTAL_STARTUP_TIMEOUT */
do{
timeout++;
stab_flag = (RCU_CTL0 & RCU_CTL0_HXTALSTB);
}
while((0U == stab_flag) && (HXTAL_STARTUP_TIMEOUT != timeout));
/* if fail */
if(0U == (RCU_CTL0 & RCU_CTL0_HXTALSTB)){
while(1){
}
}
FMC_WS = (FMC_WS & (~FMC_WS_WSCNT)) | WS_WSCNT_2;
/* HXTAL is stable */
/* AHB = SYSCLK */
RCU_CFG0 |= RCU_AHB_CKSYS_DIV1;
/* APB2 = AHB */
RCU_CFG0 |= RCU_APB2_CKAHB_DIV1;
/* APB1 = AHB */
RCU_CFG0 |= RCU_APB1_CKAHB_DIV1;
/* PLL = HXTAL * 9 = 72 MHz */
RCU_CFG0 &= ~(RCU_CFG0_PLLSEL | RCU_CFG0_PLLMF | RCU_CFG0_PLLDV);
RCU_CFG0 |= (RCU_PLLSRC_HXTAL | RCU_PLL_MUL9);
/* enable PLL */
RCU_CTL0 |= RCU_CTL0_PLLEN;
/* wait until PLL is stable */
while(0U == (RCU_CTL0 & RCU_CTL0_PLLSTB)){
}
reg_temp = RCU_CFG0;
/* select PLL as system clock */
reg_temp &= ~RCU_CFG0_SCS;
reg_temp |= RCU_CKSYSSRC_PLL;
RCU_CFG0 = reg_temp;
/* wait until PLL is selected as system clock */
while(RCU_SCSS_PLL != (RCU_CFG0 & RCU_CFG0_SCSS)){
}
}
#elif defined (__SYSTEM_CLOCK_72M_PLL_IRC8M_DIV2)
/*!
\brief configure the system clock to 72M by PLL which selects IRC8M/2 as its clock source
\param[in] none
\param[out] none
\retval none
*/
static void system_clock_72m_irc8m(void)
{
uint32_t timeout = 0U;
uint32_t stab_flag = 0U;
__IO uint32_t reg_temp;
/* enable IRC8M */
RCU_CTL0 |= RCU_CTL0_IRC8MEN;
/* wait until IRC8M is stable or the startup time is longer than IRC8M_STARTUP_TIMEOUT */
do{
timeout++;
stab_flag = (RCU_CTL0 & RCU_CTL0_IRC8MSTB);
}
while((0U == stab_flag) && (IRC8M_STARTUP_TIMEOUT != timeout));
/* if fail */
if(0U == (RCU_CTL0 & RCU_CTL0_IRC8MSTB)){
while(1){
}
}
FMC_WS = (FMC_WS & (~FMC_WS_WSCNT)) | WS_WSCNT_2;
/* AHB = SYSCLK */
RCU_CFG0 |= RCU_AHB_CKSYS_DIV1;
/* APB2 = AHB */
RCU_CFG0 |= RCU_APB2_CKAHB_DIV1;
/* APB1 = AHB */
RCU_CFG0 |= RCU_APB1_CKAHB_DIV1;
/* PLL = (IRC8M/2) * 18 = 72 MHz */
RCU_CFG0 &= ~(RCU_CFG0_PLLSEL | RCU_CFG0_PLLMF);
RCU_CFG0 |= (RCU_PLLSRC_IRC8M_DIV2 | RCU_PLL_MUL18);
/* enable PLL */
RCU_CTL0 |= RCU_CTL0_PLLEN;
/* wait until PLL is stable */
while(0U == (RCU_CTL0 & RCU_CTL0_PLLSTB)){
}
reg_temp = RCU_CFG0;
/* select PLL as system clock */
reg_temp &= ~RCU_CFG0_SCS;
reg_temp |= RCU_CKSYSSRC_PLL;
RCU_CFG0 = reg_temp;
/* wait until PLL is selected as system clock */
while(RCU_SCSS_PLL != (RCU_CFG0 & RCU_CFG0_SCSS)){
}
}
#else
/*!
\brief configure the system clock to 8M by IRC8M
\param[in] none
\param[out] none
\retval none
*/
static void system_clock_8m_irc8m(void)
{
uint32_t timeout = 0U;
uint32_t stab_flag = 0U;
__IO uint32_t reg_temp;
/* enable IRC8M */
RCU_CTL0 |= RCU_CTL0_IRC8MEN;
/* wait until IRC8M is stable or the startup time is longer than IRC8M_STARTUP_TIMEOUT */
do{
timeout++;
stab_flag = (RCU_CTL0 & RCU_CTL0_IRC8MSTB);
}
while((0U == stab_flag) && (IRC8M_STARTUP_TIMEOUT != timeout));
/* if fail */
if(0U == (RCU_CTL0 & RCU_CTL0_IRC8MSTB)){
while(1){
}
}
/* AHB = SYSCLK */
RCU_CFG0 |= RCU_AHB_CKSYS_DIV1;
/* APB2 = AHB */
RCU_CFG0 |= RCU_APB2_CKAHB_DIV1;
/* APB1 = AHB */
RCU_CFG0 |= RCU_APB1_CKAHB_DIV1;
reg_temp = RCU_CFG0;
/* select IRC8M as system clock */
reg_temp &= ~RCU_CFG0_SCS;
reg_temp |= RCU_CKSYSSRC_IRC8M;
RCU_CFG0 = reg_temp;
/* wait until IRC8M is selected as system clock */
while(RCU_SCSS_IRC8M != (RCU_CFG0 & RCU_CFG0_SCSS)){
}
}
#endif /* __SYSTEM_CLOCK_8M_HXTAL */
/*!
\brief update the SystemCoreClock with current core clock retrieved from cpu registers
\param[in] none
\param[out] none
\retval none
*/
void SystemCoreClockUpdate (void)
{
uint32_t sws = 0U;
uint32_t pllmf = 0U, pllmf4 = 0U, pllsel = 0U, prediv = 0U, idx = 0U, clk_exp = 0U;
/* exponent of AHB clock divider */
const uint8_t ahb_exp[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9};
sws = GET_BITS(RCU_CFG0, 2, 3);
switch(sws){
/* IRC8M is selected as CK_SYS */
case SEL_IRC8M:
SystemCoreClock = IRC8M_VALUE;
break;
/* HXTAL is selected as CK_SYS */
case SEL_HXTAL:
SystemCoreClock = HXTAL_VALUE;
break;
/* PLL is selected as CK_SYS */
case SEL_PLL:
/* get the value of PLLMF[3:0] */
pllmf = GET_BITS(RCU_CFG0, 18, 21);
pllmf4 = GET_BITS(RCU_CFG0, 27, 27);
/* high 16 bits */
if(1U == pllmf4){
pllmf += 17U;
}else if(15U == pllmf){
pllmf = 16U;
} else {
pllmf += 2U;
}
/* PLL clock source selection, HXTAL or IRC8M/2 */
pllsel = GET_BITS(RCU_CFG0, 16, 16);
if(0U != pllsel){
prediv = (GET_BITS(RCU_CFG1, 0, 3) + 1U);
SystemCoreClock = (HXTAL_VALUE / prediv) * pllmf;
} else {
SystemCoreClock = (IRC8M_VALUE >> 1) * pllmf;
}
break;
/* IRC8M is selected as CK_SYS */
default:
SystemCoreClock = IRC8M_VALUE;
break;
}
/* calculate AHB clock frequency */
idx = GET_BITS(RCU_CFG0, 4, 7);
clk_exp = ahb_exp[idx];
SystemCoreClock >>= clk_exp;
}
#ifdef __FIRMWARE_VERSION_DEFINE
/*!
\brief get firmware version
\param[in] none
\param[out] none
\retval firmware version
*/
uint32_t gd32e23x_firmware_version_get(void)
{
return __GD32E23x_STDPERIPH_VERSION;
}
#endif /* __FIRMWARE_VERSION_DEFINE */
+117 -117
View File
@@ -1,118 +1,118 @@
/**
* ************************************************************************
*
* @file systick.c
* @author GD32
* @brief 通过 SysTick 定时器进行微秒级别和毫秒级别的延时函数
*
* ************************************************************************
* @copyright Copyright (c) 2024 GD32
* ************************************************************************
*/
#include "gd32e23x.h"
#include "systick.h"
volatile static uint32_t delay_count = 0;
/**
* ************************************************************************
* @brief 配置 SysTick 定时器
*
*
* ************************************************************************
*/
void systick_config(void)
{
//设置了 SysTick 定时器的时钟源为 HCLK
systick_clksource_set(SYSTICK_CLKSOURCE_HCLK);
// 配置SysTick为1ms周期中断
// 注意:SysTick_Config会自动设置时钟源为HCLK,所以需要使用SystemCoreClock/1000
SysTick_Config(SystemCoreClock / 1000U); // 1ms中断
NVIC_SetPriority(SysTick_IRQn, 0x00U);
}
/**
* ************************************************************************
* @brief delay_ms 毫秒延时函数
*
* @param[in] count 毫秒值
*
* ************************************************************************
*/
void delay_10us(uint32_t count)
{
// 基于系统时钟的简单循环延时
// 这是一个粗略的估计,实际延时可能有偏差 实测10.2us
uint32_t loops_per_10us = SystemCoreClock / 1700000; // 粗略估计,每10微秒的循环次数
for(uint32_t i = 0; i < count; i++) {
for(volatile uint32_t j = 0; j < loops_per_10us; j++);
}
}
/**
* ************************************************************************
* @brief delay_ms 毫秒延时函数
*
* @param[in] count 毫秒值
*
* ************************************************************************
*/
void delay_ms(uint32_t count)
{
delay_count = count; // 设置延时计数
while (delay_count != 0U);
}
/**
* ************************************************************************
* @brief 每个 SysTick 中断调用时,减少延时计数
*
* @param[in] void
*
* ************************************************************************
*/
void delay_decrement(void)
{
if (delay_count != 0U)
{
delay_count--;
}
}
// /**
// * ************************************************************************
// * @brief delay_ms_safe 毫秒延时函数(不干扰SysTick中断)
// * @details 使用简单循环实现延时,不会重新配置SysTick
// * @param[in] count 毫秒值
// * ************************************************************************
// */
// void delay_ms_safe(uint32_t count)
// {
// // 基于系统时钟的简单循环延时
// // 这是一个粗略的估计,实际延时可能有偏差
// uint32_t loops_per_ms = SystemCoreClock / 14000; // 粗略估计
// for(uint32_t i = 0; i < count; i++) {
// for(volatile uint32_t j = 0; j < loops_per_ms; j++);
// }
// }
// /**
// * ************************************************************************
// * @brief delay_us_safe 微秒延时函数(不干扰SysTick中断)
// * @details 使用简单循环实现延时,不会重新配置SysTick
// * @param[in] count 微秒值
// * ************************************************************************
// */
// void delay_us_safe(uint32_t count)
// {
// // 基于系统时钟的简单循环延时
// // 这是一个粗略的估计,实际延时可能有偏差
// uint32_t loops_per_us = SystemCoreClock / 22000000; // 粗略估计,每微秒的循环次数
// for(uint32_t i = 0; i < count; i++) {
// for(volatile uint32_t j = 0; j < loops_per_us; j++);
// }
/**
* ************************************************************************
*
* @file systick.c
* @author GD32
* @brief 通过 SysTick 定时器进行微秒级别和毫秒级别的延时函数
*
* ************************************************************************
* @copyright Copyright (c) 2024 GD32
* ************************************************************************
*/
#include "gd32e23x.h"
#include "systick.h"
volatile static uint32_t delay_count = 0;
/**
* ************************************************************************
* @brief 配置 SysTick 定时器
*
*
* ************************************************************************
*/
void systick_config(void)
{
//设置了 SysTick 定时器的时钟源为 HCLK
systick_clksource_set(SYSTICK_CLKSOURCE_HCLK);
// 配置SysTick为1ms周期中断
// 注意:SysTick_Config会自动设置时钟源为HCLK,所以需要使用SystemCoreClock/1000
SysTick_Config(SystemCoreClock / 1000U); // 1ms中断
NVIC_SetPriority(SysTick_IRQn, 0x00U);
}
/**
* ************************************************************************
* @brief delay_ms 毫秒延时函数
*
* @param[in] count 毫秒值
*
* ************************************************************************
*/
void delay_10us(uint32_t count)
{
// 基于系统时钟的简单循环延时
// 这是一个粗略的估计,实际延时可能有偏差 实测10.2us
uint32_t loops_per_10us = SystemCoreClock / 1700000; // 粗略估计,每10微秒的循环次数
for(uint32_t i = 0; i < count; i++) {
for(volatile uint32_t j = 0; j < loops_per_10us; j++);
}
}
/**
* ************************************************************************
* @brief delay_ms 毫秒延时函数
*
* @param[in] count 毫秒值
*
* ************************************************************************
*/
void delay_ms(uint32_t count)
{
delay_count = count; // 设置延时计数
while (delay_count != 0U);
}
/**
* ************************************************************************
* @brief 每个 SysTick 中断调用时,减少延时计数
*
* @param[in] void
*
* ************************************************************************
*/
void delay_decrement(void)
{
if (delay_count != 0U)
{
delay_count--;
}
}
// /**
// * ************************************************************************
// * @brief delay_ms_safe 毫秒延时函数(不干扰SysTick中断)
// * @details 使用简单循环实现延时,不会重新配置SysTick
// * @param[in] count 毫秒值
// * ************************************************************************
// */
// void delay_ms_safe(uint32_t count)
// {
// // 基于系统时钟的简单循环延时
// // 这是一个粗略的估计,实际延时可能有偏差
// uint32_t loops_per_ms = SystemCoreClock / 14000; // 粗略估计
// for(uint32_t i = 0; i < count; i++) {
// for(volatile uint32_t j = 0; j < loops_per_ms; j++);
// }
// }
// /**
// * ************************************************************************
// * @brief delay_us_safe 微秒延时函数(不干扰SysTick中断)
// * @details 使用简单循环实现延时,不会重新配置SysTick
// * @param[in] count 微秒值
// * ************************************************************************
// */
// void delay_us_safe(uint32_t count)
// {
// // 基于系统时钟的简单循环延时
// // 这是一个粗略的估计,实际延时可能有偏差
// uint32_t loops_per_us = SystemCoreClock / 22000000; // 粗略估计,每微秒的循环次数
// for(uint32_t i = 0; i < count; i++) {
// for(volatile uint32_t j = 0; j < loops_per_us; j++);
// }
// }
+328 -329
View File
@@ -1,329 +1,328 @@
//
// Created by dell on 24-12-20.
// TMP112A Temperature Sensor Driver Implementation
//
#include "tmp112.h"
/* Private function prototypes */
static i2c_result_t tmp112a_write_register(uint8_t reg_addr, uint16_t value);
static i2c_result_t tmp112a_read_register(uint8_t reg_addr, uint16_t *value);
static float tmp112a_raw_to_celsius(uint16_t raw_data);
static uint16_t tmp112a_celsius_to_raw(float temperature);
/*!
\brief 初始化TMP112A传感器
\param[in] none
\param[out] none
\retval tmp112a_status_t
*/
tmp112a_status_t tmp112a_init(void) {
i2c_result_t i2c_status;
/* 配置传感器为默认设置 */
i2c_status = tmp112a_config(TMP112A_CONFIG_DEFAULT);
if (i2c_status != I2C_RESULT_SUCCESS) {
return TMP112A_STATUS_ERROR;
}
/* 等待配置生效 */
delay_ms(1);
return TMP112A_STATUS_SUCCESS;
}
/*!
\brief 配置TMP112A传感器
\param[in] config: 配置值
\param[out] none
\retval tmp112a_status_t
*/
tmp112a_status_t tmp112a_config(uint16_t config) {
i2c_result_t status = tmp112a_write_register(TMP112A_CONFIG_REG, config);
return (status == I2C_RESULT_SUCCESS) ? TMP112A_STATUS_SUCCESS : TMP112A_STATUS_ERROR;
}
/*!
\brief 读取温度
\param[in] none
\param[out] result: 结果结构体指针
\retval tmp112a_status_t
*/
tmp112a_status_t tmp112a_read_temperature(tmp112a_result_t *result) {
uint16_t raw_data;
i2c_result_t status;
if (result == NULL) {
return TMP112A_STATUS_INVALID_PARAM;
}
/* 读取温度寄存器 */
status = tmp112a_read_register(TMP112A_TEMP_REG, &raw_data);
if (status != I2C_RESULT_SUCCESS) {
return TMP112A_STATUS_ERROR;
}
/* 解析温度数据 */
result->raw_data = raw_data;
result->temperature_c = tmp112a_raw_to_celsius(raw_data);
result->temperature_f = result->temperature_c * 9.0f / 5.0f + 32.0f;
/* 检查温度范围 */
if (result->temperature_c < TMP112A_TEMP_MIN || result->temperature_c > TMP112A_TEMP_MAX) {
return TMP112A_STATUS_OUT_OF_RANGE;
}
/* 检查报警标志 */
uint16_t config_reg;
status = tmp112a_read_register(TMP112A_CONFIG_REG, &config_reg);
if (status == I2C_RESULT_SUCCESS) {
result->alert_flag = (config_reg & TMP112A_CONFIG_AL) ? true : false;
} else {
result->alert_flag = false;
}
return TMP112A_STATUS_SUCCESS;
}
void tmp112a_get_raw_temperature_value(uint8_t *value) {
// i2c_read_16bits(TMP112A_ADDR, TMP112A_TEMP_REG, value);
i2c_read(TMP112A_ADDR, TMP112A_TEMP_REG, value, 2);
return;
}
/*!
\brief 设置温度阈值
\param[in] low_temp: 温阈值 (°C)
\param[in] high_temp: 高温阈值 (°C)
\param[out] none
\retval tmp112a_status_t
*/
tmp112a_status_t tmp112a_set_thresholds(float low_temp, float high_temp) {
uint16_t low_raw, high_raw;
i2c_result_t status;
/* 参数验证 */
if (low_temp < TMP112A_TEMP_MIN || low_temp > TMP112A_TEMP_MAX ||
high_temp < TMP112A_TEMP_MIN || high_temp > TMP112A_TEMP_MAX ||
low_temp >= high_temp) {
return TMP112A_STATUS_INVALID_PARAM;
}
/* 转换温度为原始值 */
low_raw = tmp112a_celsius_to_raw(low_temp);
high_raw = tmp112a_celsius_to_raw(high_temp);
/* 写入低温阈值 */
status = tmp112a_write_register(TMP112A_TLOW_REG, low_raw);
if (status != I2C_RESULT_SUCCESS) {
return TMP112A_STATUS_ERROR;
}
/* 写入高温阈值 */
status = tmp112a_write_register(TMP112A_THIGH_REG, high_raw);
if (status != I2C_RESULT_SUCCESS) {
return TMP112A_STATUS_ERROR;
}
return TMP112A_STATUS_SUCCESS;
}
/*!
\brief 进入关机模式
\param[in] none
\param[out] none
\retval tmp112a_status_t
*/
tmp112a_status_t tmp112a_shutdown(void) {
uint16_t config_reg;
i2c_result_t status;
/* 读取当前配置 */
status = tmp112a_read_register(TMP112A_CONFIG_REG, &config_reg);
if (status != I2C_RESULT_SUCCESS) {
return TMP112A_STATUS_ERROR;
}
/* 设置关机位 */
config_reg |= TMP112A_CONFIG_SD;
/* 写回配置 */
status = tmp112a_write_register(TMP112A_CONFIG_REG, config_reg);
return (status == I2C_RESULT_SUCCESS) ? TMP112A_STATUS_SUCCESS : TMP112A_STATUS_ERROR;
}
/*!
\brief 退出关机模式
\param[in] none
\param[out] none
\retval tmp112a_status_t
*/
tmp112a_status_t tmp112a_wakeup(void) {
uint16_t config_reg;
i2c_result_t status;
/* 读取当前配置 */
status = tmp112a_read_register(TMP112A_CONFIG_REG, &config_reg);
if (status != I2C_RESULT_SUCCESS) {
return TMP112A_STATUS_ERROR;
}
/* 清除关机位 */
config_reg &= ~TMP112A_CONFIG_SD;
/* 写回配置 */
status = tmp112a_write_register(TMP112A_CONFIG_REG, config_reg);
if (status != I2C_RESULT_SUCCESS) {
return TMP112A_STATUS_ERROR;
}
/* 等待传感器启动 */
delay_ms(1);
return TMP112A_STATUS_SUCCESS;
}
/*!
\brief 单次转换
\param[in] none
\param[out] result: 结果结构体指针
\retval tmp112a_status_t
*/
tmp112a_status_t tmp112a_one_shot(tmp112a_result_t *result) {
uint16_t config_reg;
i2c_result_t status;
uint8_t timeout = 100; // 100ms超时
if (result == NULL) {
return TMP112A_STATUS_INVALID_PARAM;
}
/* 读取当前配置 */
status = tmp112a_read_register(TMP112A_CONFIG_REG, &config_reg);
if (status != I2C_RESULT_SUCCESS) {
return TMP112A_STATUS_ERROR;
}
/* 启动单次转换 */
config_reg |= TMP112A_CONFIG_OS;
status = tmp112a_write_register(TMP112A_CONFIG_REG, config_reg);
if (status != I2C_RESULT_SUCCESS) {
return TMP112A_STATUS_ERROR;
}
/* 等待转换完成 */
do {
delay_ms(1);
status = tmp112a_read_register(TMP112A_CONFIG_REG, &config_reg);
if (status != I2C_RESULT_SUCCESS) {
return TMP112A_STATUS_ERROR;
}
timeout--;
} while ((config_reg & TMP112A_CONFIG_OS) && timeout > 0);
if (timeout == 0) {
return TMP112A_STATUS_TIMEOUT;
}
/* 读取转换结果 */
return tmp112a_read_temperature(result);
}
/*!
\brief 获取状态字符串
\param[in] status: 状态码
\param[out] none
\retval const char* 状态字符串
*/
const char* tmp112a_get_status_string(tmp112a_status_t status) {
switch (status) {
case TMP112A_STATUS_SUCCESS:
return "SUCCESS";
case TMP112A_STATUS_ERROR:
return "ERROR";
case TMP112A_STATUS_TIMEOUT:
return "TIMEOUT";
case TMP112A_STATUS_INVALID_PARAM:
return "INVALID_PARAM";
case TMP112A_STATUS_OUT_OF_RANGE:
return "OUT_OF_RANGE";
default:
return "UNKNOWN";
}
}
/* Private Functions Implementation */
/*!
\brief 写入寄存器
\param[in] reg_addr: 寄存器地址
\param[in] value: 写入值
\param[out] none
\retval i2c_result_t
*/
static i2c_result_t tmp112a_write_register(uint8_t reg_addr, uint16_t value) {
uint8_t data[2];
data[0] = (value >> 8) & 0xFF;
data[1] = value & 0xFF;
return i2c_write_16bits(TMP112A_ADDR, reg_addr, data);
}
/*!
\brief 读取寄存器
\param[in] reg_addr: 寄存器地址
\param[out] value: 读取值指针
\retval i2c_result_t
*/
static i2c_result_t tmp112a_read_register(uint8_t reg_addr, uint16_t *value) {
uint8_t data[2];
i2c_result_t status;
if (value == NULL) {
return I2C_RESULT_INVALID_PARAM;
}
status = i2c_read_16bits(TMP112A_ADDR, reg_addr, data);
if (status == I2C_RESULT_SUCCESS) {
*value = ((uint16_t)data[0] << 8) | data[1];
}
return status;
}
/*!
\brief 将原始数据转换为摄氏度
\param[in] raw_data: 原始数据
\param[out] none
\retval float 温度值(°C)
*/
static float tmp112a_raw_to_celsius(uint16_t raw_data) {
int16_t temp_raw;
/* TMP112A使用12位分辨率,数据在高12位 */
temp_raw = (int16_t)(raw_data >> 4);
/* 处理负数 */
if (temp_raw & 0x800) {
temp_raw |= 0xF000; // 符号扩展
}
/* 转换为摄氏度 */
return (float)temp_raw * TMP112A_TEMP_RESOLUTION;
}
/*!
\brief 将摄氏度转换为原始数据
\param[in] temperature: 温度值(°C)
\param[out] none
\retval uint16_t 原始数据
*/
static uint16_t tmp112a_celsius_to_raw(float temperature) {
int16_t temp_raw;
/* 转换为原始值 */
temp_raw = (int16_t)(temperature / TMP112A_TEMP_RESOLUTION);
/* 移位到高12位 */
return (uint16_t)(temp_raw << 4);
}
//
// Created by dell on 24-12-20.
// TMP112A Temperature Sensor Driver Implementation
//
#include "tmp112.h"
/* Private function prototypes */
static i2c_result_t tmp112a_write_register(uint8_t reg_addr, uint16_t value);
static i2c_result_t tmp112a_read_register(uint8_t reg_addr, uint16_t *value);
static float tmp112a_raw_to_celsius(uint16_t raw_data);
static uint16_t tmp112a_celsius_to_raw(float temperature);
/*!
\brief 初始化TMP112A传感器
\param[in] none
\param[out] none
\retval tmp112a_status_t
*/
tmp112a_status_t tmp112a_init(void) {
i2c_result_t i2c_status;
/* 配置传感器为默认设置 */
i2c_status = tmp112a_config(TMP112A_CONFIG_DEFAULT);
if (i2c_status != I2C_RESULT_SUCCESS) {
return TMP112A_STATUS_ERROR;
}
/* 等待配置生效 */
delay_ms(1);
return TMP112A_STATUS_SUCCESS;
}
/*!
\brief 配置TMP112A传感器
\param[in] config: 配置值
\param[out] none
\retval tmp112a_status_t
*/
tmp112a_status_t tmp112a_config(uint16_t config) {
i2c_result_t status = tmp112a_write_register(TMP112A_CONFIG_REG, config);
return (status == I2C_RESULT_SUCCESS) ? TMP112A_STATUS_SUCCESS : TMP112A_STATUS_ERROR;
}
/*!
\brief 读取温度
\param[in] none
\param[out] result: 结果结构体指针
\retval tmp112a_status_t
*/
tmp112a_status_t tmp112a_read_temperature(tmp112a_result_t *result) {
uint16_t raw_data;
i2c_result_t status;
if (result == NULL) {
return TMP112A_STATUS_INVALID_PARAM;
}
/* 读取温度寄存器 */
status = tmp112a_read_register(TMP112A_TEMP_REG, &raw_data);
if (status != I2C_RESULT_SUCCESS) {
return TMP112A_STATUS_ERROR;
}
/* 解析温度数据 */
result->raw_data = raw_data;
result->temperature_c = tmp112a_raw_to_celsius(raw_data);
result->temperature_f = result->temperature_c * 9.0f / 5.0f + 32.0f;
/* 检查温度范围 */
if (result->temperature_c < TMP112A_TEMP_MIN || result->temperature_c > TMP112A_TEMP_MAX) {
return TMP112A_STATUS_OUT_OF_RANGE;
}
/* 检查报警标志 */
uint16_t config_reg;
status = tmp112a_read_register(TMP112A_CONFIG_REG, &config_reg);
if (status == I2C_RESULT_SUCCESS) {
result->alert_flag = (config_reg & TMP112A_CONFIG_AL) ? true : false;
} else {
result->alert_flag = false;
}
return TMP112A_STATUS_SUCCESS;
}
void tmp112a_get_raw_temperature_value(uint8_t *value) {
i2c_read_16bits(TMP112A_ADDR, TMP112A_TEMP_REG, value);
return;
}
/*!
\brief 设置温度阈值
\param[in] low_temp: 低温阈值 (°C)
\param[in] high_temp: 温阈值 (°C)
\param[out] none
\retval tmp112a_status_t
*/
tmp112a_status_t tmp112a_set_thresholds(float low_temp, float high_temp) {
uint16_t low_raw, high_raw;
i2c_result_t status;
/* 参数验证 */
if (low_temp < TMP112A_TEMP_MIN || low_temp > TMP112A_TEMP_MAX ||
high_temp < TMP112A_TEMP_MIN || high_temp > TMP112A_TEMP_MAX ||
low_temp >= high_temp) {
return TMP112A_STATUS_INVALID_PARAM;
}
/* 转换温度为原始值 */
low_raw = tmp112a_celsius_to_raw(low_temp);
high_raw = tmp112a_celsius_to_raw(high_temp);
/* 写入低温阈值 */
status = tmp112a_write_register(TMP112A_TLOW_REG, low_raw);
if (status != I2C_RESULT_SUCCESS) {
return TMP112A_STATUS_ERROR;
}
/* 写入高温阈值 */
status = tmp112a_write_register(TMP112A_THIGH_REG, high_raw);
if (status != I2C_RESULT_SUCCESS) {
return TMP112A_STATUS_ERROR;
}
return TMP112A_STATUS_SUCCESS;
}
/*!
\brief 进入关机模式
\param[in] none
\param[out] none
\retval tmp112a_status_t
*/
tmp112a_status_t tmp112a_shutdown(void) {
uint16_t config_reg;
i2c_result_t status;
/* 读取当前配置 */
status = tmp112a_read_register(TMP112A_CONFIG_REG, &config_reg);
if (status != I2C_RESULT_SUCCESS) {
return TMP112A_STATUS_ERROR;
}
/* 设置关机位 */
config_reg |= TMP112A_CONFIG_SD;
/* 写回配置 */
status = tmp112a_write_register(TMP112A_CONFIG_REG, config_reg);
return (status == I2C_RESULT_SUCCESS) ? TMP112A_STATUS_SUCCESS : TMP112A_STATUS_ERROR;
}
/*!
\brief 退出关机模式
\param[in] none
\param[out] none
\retval tmp112a_status_t
*/
tmp112a_status_t tmp112a_wakeup(void) {
uint16_t config_reg;
i2c_result_t status;
/* 读取当前配置 */
status = tmp112a_read_register(TMP112A_CONFIG_REG, &config_reg);
if (status != I2C_RESULT_SUCCESS) {
return TMP112A_STATUS_ERROR;
}
/* 清除关机位 */
config_reg &= ~TMP112A_CONFIG_SD;
/* 写回配置 */
status = tmp112a_write_register(TMP112A_CONFIG_REG, config_reg);
if (status != I2C_RESULT_SUCCESS) {
return TMP112A_STATUS_ERROR;
}
/* 等待传感器启动 */
delay_ms(1);
return TMP112A_STATUS_SUCCESS;
}
/*!
\brief 单次转换
\param[in] none
\param[out] result: 结果结构体指针
\retval tmp112a_status_t
*/
tmp112a_status_t tmp112a_one_shot(tmp112a_result_t *result) {
uint16_t config_reg;
i2c_result_t status;
uint8_t timeout = 100; // 100ms超时
if (result == NULL) {
return TMP112A_STATUS_INVALID_PARAM;
}
/* 读取当前配置 */
status = tmp112a_read_register(TMP112A_CONFIG_REG, &config_reg);
if (status != I2C_RESULT_SUCCESS) {
return TMP112A_STATUS_ERROR;
}
/* 启动单次转换 */
config_reg |= TMP112A_CONFIG_OS;
status = tmp112a_write_register(TMP112A_CONFIG_REG, config_reg);
if (status != I2C_RESULT_SUCCESS) {
return TMP112A_STATUS_ERROR;
}
/* 等待转换完成 */
do {
delay_ms(1);
status = tmp112a_read_register(TMP112A_CONFIG_REG, &config_reg);
if (status != I2C_RESULT_SUCCESS) {
return TMP112A_STATUS_ERROR;
}
timeout--;
} while ((config_reg & TMP112A_CONFIG_OS) && timeout > 0);
if (timeout == 0) {
return TMP112A_STATUS_TIMEOUT;
}
/* 读取转换结果 */
return tmp112a_read_temperature(result);
}
/*!
\brief 获取状态字符串
\param[in] status: 状态码
\param[out] none
\retval const char* 状态字符串
*/
const char* tmp112a_get_status_string(tmp112a_status_t status) {
switch (status) {
case TMP112A_STATUS_SUCCESS:
return "SUCCESS";
case TMP112A_STATUS_ERROR:
return "ERROR";
case TMP112A_STATUS_TIMEOUT:
return "TIMEOUT";
case TMP112A_STATUS_INVALID_PARAM:
return "INVALID_PARAM";
case TMP112A_STATUS_OUT_OF_RANGE:
return "OUT_OF_RANGE";
default:
return "UNKNOWN";
}
}
/* Private Functions Implementation */
/*!
\brief 写入寄存器
\param[in] reg_addr: 寄存器地址
\param[in] value: 写入值
\param[out] none
\retval i2c_result_t
*/
static i2c_result_t tmp112a_write_register(uint8_t reg_addr, uint16_t value) {
uint8_t data[2];
data[0] = (value >> 8) & 0xFF;
data[1] = value & 0xFF;
return i2c_write_16bits(TMP112A_ADDR, reg_addr, data);
}
/*!
\brief 读取寄存器
\param[in] reg_addr: 寄存器地址
\param[out] value: 读取值指针
\retval i2c_result_t
*/
static i2c_result_t tmp112a_read_register(uint8_t reg_addr, uint16_t *value) {
uint8_t data[2];
i2c_result_t status;
if (value == NULL) {
return I2C_RESULT_INVALID_PARAM;
}
status = i2c_read_16bits(TMP112A_ADDR, reg_addr, data);
if (status == I2C_RESULT_SUCCESS) {
*value = ((uint16_t)data[0] << 8) | data[1];
}
return status;
}
/*!
\brief 将原始数据转换为摄氏度
\param[in] raw_data: 原始数据
\param[out] none
\retval float 温度值(°C)
*/
static float tmp112a_raw_to_celsius(uint16_t raw_data) {
int16_t temp_raw;
/* TMP112A使用12位分辨率,数据在高12位 */
temp_raw = (int16_t)(raw_data >> 4);
/* 处理负数 */
if (temp_raw & 0x800) {
temp_raw |= 0xF000; // 符号扩展
}
/* 转换为摄氏度 */
return (float)temp_raw * TMP112A_TEMP_RESOLUTION;
}
/*!
\brief 将摄氏度转换为原始数据
\param[in] temperature: 温度值(°C)
\param[out] none
\retval uint16_t 原始数据
*/
static uint16_t tmp112a_celsius_to_raw(float temperature) {
int16_t temp_raw;
/* 转换为原始值 */
temp_raw = (int16_t)(temperature / TMP112A_TEMP_RESOLUTION);
/* 移位到高12位 */
return (uint16_t)(temp_raw << 4);
}
+107 -107
View File
@@ -1,107 +1,107 @@
#include "uart.h"
#include "gd32e23x_usart.h"
#include "gd32e23x_rcu.h"
#include "gd32e23x_gpio.h"
#include "board_config.h"
#include "uart_ring_buffer.h"
void rs485_init(void) {
#ifndef RS485_MAX13487
/* 使能 GPIOA 和 USART0 时钟 */
rcu_periph_clock_enable(RS485_GPIO_RCU);
rcu_periph_clock_enable(RS485_RCU);
/* 配置 PA2 为 USART0_TXPA3 为 USART0_RX */
gpio_af_set(RS485_GPIO_PORT, GPIO_AF_1, RS485_TX_PIN | RS485_RX_PIN | RS485_EN_PIN);
gpio_mode_set(RS485_GPIO_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, RS485_TX_PIN | RS485_RX_PIN);
gpio_output_options_set(RS485_GPIO_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, RS485_TX_PIN | RS485_RX_PIN);
gpio_mode_set(RS485_GPIO_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, RS485_EN_PIN);
gpio_output_options_set(RS485_GPIO_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, RS485_EN_PIN);
/* 配置波特率、数据位、停止位等 */
usart_deinit(RS485_PHY);
usart_word_length_set(RS485_PHY, USART_WL_8BIT);
usart_stop_bit_set(RS485_PHY, USART_STB_1BIT);
usart_parity_config(RS485_PHY, USART_PM_NONE);
usart_baudrate_set(RS485_PHY, RS485_BAUDRATE);
usart_receive_config(RS485_PHY, USART_RECEIVE_ENABLE);
usart_transmit_config(RS485_PHY, USART_TRANSMIT_ENABLE);
usart_driver_assertime_config(RS485_PHY, 0x01);
usart_driver_deassertime_config(RS485_PHY, 0x10);
usart_rs485_driver_enable(RS485_PHY);
usart_enable(RS485_PHY);
nvic_irq_enable(RS485_IRQ, 0);
usart_interrupt_enable(RS485_PHY, USART_INT_RBNE);
// usart_interrupt_enable(RS485_PHY, USART_INT_IDLE);
#else
rcu_periph_clock_enable(RS485_GPIO_RCU);
rcu_periph_clock_enable(RS485_RCU);
gpio_af_set(RS485_GPIO_PORT, GPIO_AF_1, GPIO_PIN_2 | GPIO_PIN_3);
/* configure USART Tx&Rx as alternate function push-pull */
gpio_mode_set(RS485_GPIO_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, RS485_TX_PIN | RS485_RX_PIN);
gpio_output_options_set(RS485_GPIO_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_10MHZ, RS485_TX_PIN | RS485_RX_PIN);
/* configure RS485 EN Pin */
gpio_mode_set(RS485_GPIO_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, RS485_EN_PIN);
gpio_output_options_set(RS485_GPIO_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, RS485_EN_PIN);
gpio_bit_write(RS485_GPIO_PORT, RS485_EN_PIN, SET);
/* USART configure */
usart_deinit(RS485_PHY);
usart_baudrate_set(RS485_PHY, RS485_BAUDRATE);
usart_receive_config(RS485_PHY, USART_RECEIVE_ENABLE);
usart_transmit_config(RS485_PHY, USART_TRANSMIT_ENABLE);
usart_enable(RS485_PHY);
nvic_irq_enable(USART0_IRQn, 0);
usart_interrupt_enable(RS485_PHY, USART_INT_RBNE);
usart_interrupt_enable(RS485_PHY, USART_INT_IDLE);
#endif // RS485_MAX13487
}
/******************************************************************************/
/* 具体的中断处理函数实现 */
/******************************************************************************/
void usart0_irq_handler(void) {
// 处理USART0的接收中断
if(usart_interrupt_flag_get(USART0, USART_INT_FLAG_RBNE)) {
uint8_t data = usart_data_receive(USART0);
// 使用原有的环形缓冲区处理逻辑
(void)uart_ring_buffer_put(data); // 缓冲满时丢弃,返回值可用于统计
}
// 处理USART0的空闲中断
if(usart_interrupt_flag_get(USART0, USART_INT_FLAG_IDLE)) {
usart_interrupt_flag_clear(USART0, USART_INT_FLAG_IDLE);
// 在这里添加空闲中断处理逻辑
}
}
void usart1_irq_handler(void) {
// 处理USART1的接收中断
if(usart_interrupt_flag_get(USART1, USART_INT_FLAG_RBNE)) {
uint8_t data = usart_data_receive(USART1);
// 使用原有的环形缓冲区处理逻辑
(void)uart_ring_buffer_put(data); // 缓冲满时丢弃,返回值可用于统计
}
// 处理USART1的空闲中断
if(usart_interrupt_flag_get(USART1, USART_INT_FLAG_IDLE)) {
usart_interrupt_flag_clear(USART1, USART_INT_FLAG_IDLE);
// 在这里添加空闲中断处理逻辑
}
}
#include "uart.h"
#include "gd32e23x_usart.h"
#include "gd32e23x_rcu.h"
#include "gd32e23x_gpio.h"
#include "board_config.h"
#include "uart_ring_buffer.h"
void rs485_init(void) {
#ifndef RS485_MAX13487
/* 使能 GPIOA 和 USART0 时钟 */
rcu_periph_clock_enable(RS485_GPIO_RCU);
rcu_periph_clock_enable(RS485_RCU);
/* 配置 PA2 为 USART0_TXPA3 为 USART0_RX */
gpio_af_set(RS485_GPIO_PORT, GPIO_AF_1, RS485_TX_PIN | RS485_RX_PIN | RS485_EN_PIN);
gpio_mode_set(RS485_GPIO_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, RS485_TX_PIN | RS485_RX_PIN);
gpio_output_options_set(RS485_GPIO_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, RS485_TX_PIN | RS485_RX_PIN);
gpio_mode_set(RS485_GPIO_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, RS485_EN_PIN);
gpio_output_options_set(RS485_GPIO_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, RS485_EN_PIN);
/* 配置波特率、数据位、停止位等 */
usart_deinit(RS485_PHY);
usart_word_length_set(RS485_PHY, USART_WL_8BIT);
usart_stop_bit_set(RS485_PHY, USART_STB_1BIT);
usart_parity_config(RS485_PHY, USART_PM_NONE);
usart_baudrate_set(RS485_PHY, RS485_BAUDRATE);
usart_receive_config(RS485_PHY, USART_RECEIVE_ENABLE);
usart_transmit_config(RS485_PHY, USART_TRANSMIT_ENABLE);
usart_driver_assertime_config(RS485_PHY, 0x01);
usart_driver_deassertime_config(RS485_PHY, 0x10);
usart_rs485_driver_enable(RS485_PHY);
usart_enable(RS485_PHY);
nvic_irq_enable(RS485_IRQ, 0);
usart_interrupt_enable(RS485_PHY, USART_INT_RBNE);
// usart_interrupt_enable(RS485_PHY, USART_INT_IDLE);
#else
rcu_periph_clock_enable(RS485_GPIO_RCU);
rcu_periph_clock_enable(RS485_RCU);
gpio_af_set(RS485_GPIO_PORT, GPIO_AF_1, GPIO_PIN_2 | GPIO_PIN_3);
/* configure USART Tx&Rx as alternate function push-pull */
gpio_mode_set(RS485_GPIO_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, RS485_TX_PIN | RS485_RX_PIN);
gpio_output_options_set(RS485_GPIO_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_10MHZ, RS485_TX_PIN | RS485_RX_PIN);
/* configure RS485 EN Pin */
gpio_mode_set(RS485_GPIO_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, RS485_EN_PIN);
gpio_output_options_set(RS485_GPIO_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, RS485_EN_PIN);
gpio_bit_write(RS485_GPIO_PORT, RS485_EN_PIN, SET);
/* USART configure */
usart_deinit(RS485_PHY);
usart_baudrate_set(RS485_PHY, RS485_BAUDRATE);
usart_receive_config(RS485_PHY, USART_RECEIVE_ENABLE);
usart_transmit_config(RS485_PHY, USART_TRANSMIT_ENABLE);
usart_enable(RS485_PHY);
nvic_irq_enable(USART0_IRQn, 0);
usart_interrupt_enable(RS485_PHY, USART_INT_RBNE);
usart_interrupt_enable(RS485_PHY, USART_INT_IDLE);
#endif // RS485_MAX13487
}
/******************************************************************************/
/* 具体的中断处理函数实现 */
/******************************************************************************/
void usart0_irq_handler(void) {
// 处理USART0的接收中断
if(usart_interrupt_flag_get(USART0, USART_INT_FLAG_RBNE)) {
uint8_t data = usart_data_receive(USART0);
// 使用原有的环形缓冲区处理逻辑
(void)uart_ring_buffer_put(data); // 缓冲满时丢弃,返回值可用于统计
}
// 处理USART0的空闲中断
if(usart_interrupt_flag_get(USART0, USART_INT_FLAG_IDLE)) {
usart_interrupt_flag_clear(USART0, USART_INT_FLAG_IDLE);
// 在这里添加空闲中断处理逻辑
}
}
void usart1_irq_handler(void) {
// 处理USART1的接收中断
if(usart_interrupt_flag_get(USART1, USART_INT_FLAG_RBNE)) {
uint8_t data = usart_data_receive(USART1);
// 使用原有的环形缓冲区处理逻辑
(void)uart_ring_buffer_put(data); // 缓冲满时丢弃,返回值可用于统计
}
// 处理USART1的空闲中断
if(usart_interrupt_flag_get(USART1, USART_INT_FLAG_IDLE)) {
usart_interrupt_flag_clear(USART1, USART_INT_FLAG_IDLE);
// 在这里添加空闲中断处理逻辑
}
}
+104 -104
View File
@@ -1,104 +1,104 @@
/**
* @file uart_ring_buffer.c
* @brief 字节环形接收缓冲区的实现。
* @details 适用于中断接收(写)与主循环解析(读)的典型串口场景;
* 采用“预留一格”区分空/满,最大可用容量为 UART_RX_BUFFER_SIZE-1。
* @ingroup RingBuffer
*/
#include "uart_ring_buffer.h"
static volatile uint8_t uart_rx_buffer[UART_RX_BUFFER_SIZE];
static volatile uint8_t write_index = 0;
static volatile uint8_t read_index = 0;
static volatile uint32_t dropped_bytes = 0;
/**
* @brief 重置环形缓冲区状态。
* @details 将读指针、写指针与丢弃计数清零,不清空数据区内容。
* @note 内部工具函数;对外请优先使用 uart_ring_buffer_init()/uart_ring_buffer_clear()。
* @ingroup RingBuffer
*/
static void uart_ring_buffer_reset_state(void) {
write_index = 0;
read_index = 0;
dropped_bytes = 0;
}
/**
* @brief 初始化环形缓冲区。
* @details 调用内部重置逻辑,复位读写索引与丢弃计数,准备接收数据。
* @note 若在中断环境使用,初始化前建议关闭相关接收中断以避免并发竞争。
* @ingroup RingBuffer
*/
void uart_ring_buffer_init(void) {
uart_ring_buffer_reset_state();
}
/**
* @brief 获取当前可读的字节数。
* @details 通过读/写指针的快照计算可读长度,范围为 [0, UART_RX_BUFFER_SIZE-1]。
* @return uint8_t 可读字节数。
* @note 预留一个空槽区分“空/满”,因此满时返回 UART_RX_BUFFER_SIZE-1。
* @ingroup RingBuffer
*/
uint8_t uart_ring_buffer_available(void) {
/* 使用快照减少并发不一致窗口 */
uint8_t w = write_index;
uint8_t r = read_index;
return (uint8_t)((w + UART_RX_BUFFER_SIZE - r) % UART_RX_BUFFER_SIZE);
}
/**
* @brief 从环形缓冲区读取一个字节。
* @details 若缓冲区非空,返回队头字节并推进读指针;若为空,返回 -1。
* @return int 读取到的字节(0..255),或 -1 表示缓冲区为空。
* @ingroup RingBuffer
*/
int uart_ring_buffer_get(void) {
if (read_index == write_index) return -1; // 空
uint8_t data = uart_rx_buffer[read_index];
read_index = (read_index + 1) % UART_RX_BUFFER_SIZE;
return data;
}
/**
* @brief 向环形缓冲区写入一个字节。
* @details 尝试写入一个新字节;若缓冲区已满则丢弃并计数。
* @param data 待写入的字节。
* @return bool 是否写入成功。
* @retval true 写入成功。
* @retval false 写入失败(缓冲区已满,数据被丢弃并计数)。
* @note 如需“覆盖写入”策略,可在满时先推进读指针再写入。
* @ingroup RingBuffer
*/
bool uart_ring_buffer_put(uint8_t data) {
uint8_t next = (write_index + 1) % UART_RX_BUFFER_SIZE;
if (next != read_index) { // 缓冲区未满
uart_rx_buffer[write_index] = data;
write_index = next;
return true;
} else {
/* 缓冲区已满,丢弃新字节并计数 */
dropped_bytes++;
return false;
}
}
/**
* @brief 清空环形缓冲区。
* @details 复位读写索引与丢弃计数,相当于逻辑上丢弃所有已接收数据,不擦除数据区内容。
* @ingroup RingBuffer
*/
void uart_ring_buffer_clear(void) {
uart_ring_buffer_reset_state();
}
/**
* @brief 获取因满而被丢弃的字节累计数量。
* @details 写入时缓冲区满会丢弃新字节并累加计数;该计数在 init/clear 时清零。
* @return uint32_t 丢弃的累计字节数。
* @ingroup RingBuffer
*/
uint32_t uart_ring_buffer_drop_count(void) {
return dropped_bytes;
}
/**
* @file uart_ring_buffer.c
* @brief 字节环形接收缓冲区的实现。
* @details 适用于中断接收(写)与主循环解析(读)的典型串口场景;
* 采用“预留一格”区分空/满,最大可用容量为 UART_RX_BUFFER_SIZE-1。
* @ingroup RingBuffer
*/
#include "uart_ring_buffer.h"
static volatile uint8_t uart_rx_buffer[UART_RX_BUFFER_SIZE];
static volatile uint8_t write_index = 0;
static volatile uint8_t read_index = 0;
static volatile uint32_t dropped_bytes = 0;
/**
* @brief 重置环形缓冲区状态。
* @details 将读指针、写指针与丢弃计数清零,不清空数据区内容。
* @note 内部工具函数;对外请优先使用 uart_ring_buffer_init()/uart_ring_buffer_clear()。
* @ingroup RingBuffer
*/
static void uart_ring_buffer_reset_state(void) {
write_index = 0;
read_index = 0;
dropped_bytes = 0;
}
/**
* @brief 初始化环形缓冲区。
* @details 调用内部重置逻辑,复位读写索引与丢弃计数,准备接收数据。
* @note 若在中断环境使用,初始化前建议关闭相关接收中断以避免并发竞争。
* @ingroup RingBuffer
*/
void uart_ring_buffer_init(void) {
uart_ring_buffer_reset_state();
}
/**
* @brief 获取当前可读的字节数。
* @details 通过读/写指针的快照计算可读长度,范围为 [0, UART_RX_BUFFER_SIZE-1]。
* @return uint8_t 可读字节数。
* @note 预留一个空槽区分“空/满”,因此满时返回 UART_RX_BUFFER_SIZE-1。
* @ingroup RingBuffer
*/
uint8_t uart_ring_buffer_available(void) {
/* 使用快照减少并发不一致窗口 */
uint8_t w = write_index;
uint8_t r = read_index;
return (uint8_t)((w + UART_RX_BUFFER_SIZE - r) % UART_RX_BUFFER_SIZE);
}
/**
* @brief 从环形缓冲区读取一个字节。
* @details 若缓冲区非空,返回队头字节并推进读指针;若为空,返回 -1。
* @return int 读取到的字节(0..255),或 -1 表示缓冲区为空。
* @ingroup RingBuffer
*/
int uart_ring_buffer_get(void) {
if (read_index == write_index) return -1; // 空
uint8_t data = uart_rx_buffer[read_index];
read_index = (read_index + 1) % UART_RX_BUFFER_SIZE;
return data;
}
/**
* @brief 向环形缓冲区写入一个字节。
* @details 尝试写入一个新字节;若缓冲区已满则丢弃并计数。
* @param data 待写入的字节。
* @return bool 是否写入成功。
* @retval true 写入成功。
* @retval false 写入失败(缓冲区已满,数据被丢弃并计数)。
* @note 如需“覆盖写入”策略,可在满时先推进读指针再写入。
* @ingroup RingBuffer
*/
bool uart_ring_buffer_put(uint8_t data) {
uint8_t next = (write_index + 1) % UART_RX_BUFFER_SIZE;
if (next != read_index) { // 缓冲区未满
uart_rx_buffer[write_index] = data;
write_index = next;
return true;
} else {
/* 缓冲区已满,丢弃新字节并计数 */
dropped_bytes++;
return false;
}
}
/**
* @brief 清空环形缓冲区。
* @details 复位读写索引与丢弃计数,相当于逻辑上丢弃所有已接收数据,不擦除数据区内容。
* @ingroup RingBuffer
*/
void uart_ring_buffer_clear(void) {
uart_ring_buffer_reset_state();
}
/**
* @brief 获取因满而被丢弃的字节累计数量。
* @details 写入时缓冲区满会丢弃新字节并累加计数;该计数在 init/clear 时清零。
* @return uint32_t 丢弃的累计字节数。
* @ingroup RingBuffer
*/
uint32_t uart_ring_buffer_drop_count(void) {
return dropped_bytes;
}