generated from hulk/gd32e23x_template_cmake_vscode
sync: 合并内网 LDC1612_last_version 代码变更
- 覆盖 Src/Inc/SDK/LD/doc 等源码文件 - 保留 cmake 构建配置和 Git 历史不变 - 来源: 内网 LDC1612_last_version
This commit is contained in:
+52
-52
@@ -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
File diff suppressed because it is too large
Load Diff
+117
-117
@@ -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(); // 通过函数指针调用对应的处理函数
|
||||
}
|
||||
}
|
||||
|
||||
+245
-334
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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_TX,PA3 为 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_TX,PA3 为 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
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user