generated from hulk/gd32e23x_template
Initial commit
This commit is contained in:
47
src/fwdgt.c
Normal file
47
src/fwdgt.c
Normal file
@@ -0,0 +1,47 @@
|
||||
//
|
||||
// Created by yelv1 on 24-12-29.
|
||||
//
|
||||
|
||||
#include "fwdgt.h"
|
||||
|
||||
/**
|
||||
* @brief Initialize the watchdog
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
void watchdog_init(void) {
|
||||
/* Enable the LSI clock */
|
||||
rcu_osci_on(RCU_IRC40K);
|
||||
rcu_osci_stab_wait(RCU_IRC40K);
|
||||
|
||||
/* Configure FWDGT counter clock: 40KHz(IRC40K) / 64 = 0.625 KHz */
|
||||
fwdgt_config(625, FWDGT_PSC_DIV64); // Set timeout to 1 seconds (625 / 0.625 KHz)
|
||||
|
||||
/* Enable FWDGT */
|
||||
fwdgt_enable();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reset the MCU
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
void fwdgt_reset_mcu(void) {
|
||||
/* Enable the write access to the FWDGT_CTL register */
|
||||
FWDGT_CTL = FWDGT_WRITEACCESS_ENABLE;
|
||||
|
||||
/* Configure FWDGT to trigger a system reset */
|
||||
fwdgt_config(50, FWDGT_PSC_DIV4);
|
||||
|
||||
/* Reload the counter to trigger the reset */
|
||||
fwdgt_counter_reload();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reload the watchdog counter
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
void watchdog_reload(void) {
|
||||
fwdgt_counter_reload();
|
||||
}
|
123
src/gd32e23x_it.c
Normal file
123
src/gd32e23x_it.c
Normal file
@@ -0,0 +1,123 @@
|
||||
/*!
|
||||
\file gd32e23x_it.c
|
||||
\brief interrupt service routines
|
||||
|
||||
\version 2024-02-22, V2.1.0, firmware for GD32E23x
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (c) 2024, 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"
|
||||
|
||||
/*!
|
||||
\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)
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief this function handles TIMER16 interrupt request
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void TIMER16_IRQHandler(void)
|
||||
{
|
||||
if (timer_interrupt_flag_get(LED_BLINK_TIMER, TIMER_INT_FLAG_UP) == SET)
|
||||
{
|
||||
timer_interrupt_flag_clear(LED_BLINK_TIMER, TIMER_INT_FLAG_UP);
|
||||
static uint8_t led_status = 0;
|
||||
if (led_status)
|
||||
{
|
||||
//! turn on led & reconfig timer13 period to 19000(1900ms)
|
||||
gpio_bit_write(LED_PORT, LED_PIN, RESET);
|
||||
timer_autoreload_value_config(LED_BLINK_TIMER, 19200);
|
||||
} else {
|
||||
//! turn off led & reconfig timer13 period to 1000(100ms)
|
||||
gpio_bit_write(LED_PORT, LED_PIN, SET);
|
||||
timer_autoreload_value_config(LED_BLINK_TIMER, 800);
|
||||
}
|
||||
led_status = !led_status;
|
||||
}
|
||||
}
|
476
src/i2c.c
Normal file
476
src/i2c.c
Normal file
@@ -0,0 +1,476 @@
|
||||
//
|
||||
// Created by dell on 24-12-20.
|
||||
//
|
||||
|
||||
#include "i2c.h"
|
||||
|
||||
/*!
|
||||
\brief configure the GPIO ports
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void i2c_gpio_config(void) {
|
||||
/* enable IIC GPIO clock */
|
||||
rcu_periph_clock_enable(I2C_GPIO_RCU);
|
||||
|
||||
/* connect I2C_SCL_PIN to I2C_SCL */
|
||||
gpio_af_set(I2C_SCL_PORT, I2C_GPIO_AF, I2C_SCL_PIN);
|
||||
/* connect I2C_SDA_PIN to I2C_SDA */
|
||||
gpio_af_set(I2C_SDA_PORT, I2C_GPIO_AF, I2C_SDA_PIN);
|
||||
/* configure GPIO pins of I2C */
|
||||
gpio_mode_set(I2C_SCL_PORT, GPIO_MODE_AF, 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_AF, GPIO_PUPD_PULLUP, I2C_SDA_PIN);
|
||||
gpio_output_options_set(I2C_SDA_PORT, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, I2C_SDA_PIN);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configure the I2CX interface
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void i2c_config(void) {
|
||||
/* configure I2C GPIO */
|
||||
i2c_gpio_config();
|
||||
/* enable I2C clock */
|
||||
rcu_periph_clock_enable(I2C_RCU);
|
||||
/* configure I2C clock */
|
||||
i2c_clock_config(I2C_PHY, I2C_SPEED, I2C_DTCY_2);
|
||||
/* configure I2C address */
|
||||
i2c_mode_addr_config(I2C_PHY, I2C_I2CMODE_ENABLE, I2C_ADDFORMAT_7BITS, 0xA0);
|
||||
/* enable I2CX */
|
||||
i2c_enable(I2C_PHY);
|
||||
/* enable acknowledge */
|
||||
i2c_ack_config(I2C_PHY, I2C_ACK_ENABLE);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief reset I2C bus
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void i2c_bus_reset(void) {
|
||||
i2c_deinit(I2C_PHY);
|
||||
/* configure SDA/SCL for GPIO */
|
||||
GPIO_BC(I2C_SCL_PORT) |= I2C_SCL_PIN;
|
||||
GPIO_BC(I2C_SDA_PORT) |= I2C_SDA_PIN;
|
||||
gpio_output_options_set(I2C_SCL_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, I2C_SCL_PIN);
|
||||
gpio_output_options_set(I2C_SDA_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, I2C_SDA_PIN);
|
||||
__NOP();
|
||||
__NOP();
|
||||
__NOP();
|
||||
__NOP();
|
||||
__NOP();
|
||||
GPIO_BOP(I2C_SCL_PORT) |= I2C_SCL_PIN;
|
||||
__NOP();
|
||||
__NOP();
|
||||
__NOP();
|
||||
__NOP();
|
||||
__NOP();
|
||||
GPIO_BOP(I2C_SDA_PORT) |= I2C_SDA_PIN;
|
||||
/* connect I2C_SCL_PIN to I2C_SCL */
|
||||
/* connect I2C_SDA_PIN to I2C_SDA */
|
||||
gpio_output_options_set(I2C_SCL_PORT, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, I2C_SCL_PIN);
|
||||
gpio_output_options_set(I2C_SDA_PORT, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, I2C_SDA_PIN);
|
||||
/* configure the I2CX interface */
|
||||
i2c_config();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 扫描I2C总线,查找连接的设备
|
||||
*
|
||||
* 该函数会扫描I2C总线上的所有地址(1到126),并尝试与每个地址进行通信。
|
||||
* 如果在某个地址上发现了设备,则会打印出该设备的地址。
|
||||
* 最后会打印出找到的设备总数。
|
||||
*/
|
||||
void i2c_scan(void) {
|
||||
uint32_t timeout;
|
||||
uint8_t address;
|
||||
int found_devices = 0;
|
||||
|
||||
printf("Scanning I2C bus...\r\n");
|
||||
|
||||
for (address = 1; address < 127; address++) {
|
||||
timeout = 0;
|
||||
|
||||
// 生成起始条件
|
||||
while (i2c_flag_get(I2C_PHY, I2C_FLAG_I2CBSY) && (timeout < I2C_TIME_OUT))
|
||||
timeout++;
|
||||
if (timeout >= I2C_TIME_OUT) {
|
||||
continue; // 超时,跳过该地址
|
||||
}
|
||||
i2c_start_on_bus(I2C_PHY);
|
||||
timeout = 0;
|
||||
|
||||
// 等待起始条件发送完成
|
||||
while (!i2c_flag_get(I2C_PHY, I2C_FLAG_SBSEND) && (timeout < I2C_TIME_OUT))
|
||||
timeout++;
|
||||
if (timeout >= I2C_TIME_OUT) {
|
||||
continue; // 超时,跳过该地址
|
||||
}
|
||||
i2c_master_addressing(I2C_PHY, (address << 1), I2C_TRANSMITTER);
|
||||
timeout = 0;
|
||||
|
||||
// 等待地址发送完成
|
||||
while (!i2c_flag_get(I2C_PHY, I2C_FLAG_ADDSEND) && (timeout < I2C_TIME_OUT))
|
||||
timeout++;
|
||||
if (timeout < I2C_TIME_OUT) {
|
||||
i2c_flag_clear(I2C_PHY, I2C_FLAG_ADDSEND);
|
||||
printf("Found device at 0x%02X\r\n", address);
|
||||
found_devices++;
|
||||
}
|
||||
|
||||
// 生成停止条件
|
||||
i2c_stop_on_bus(I2C_PHY);
|
||||
|
||||
timeout = 0;
|
||||
|
||||
while (i2c_flag_get(I2C_PHY, I2C_FLAG_STPDET) && (timeout < I2C_TIME_OUT))
|
||||
timeout++;
|
||||
}
|
||||
|
||||
if (found_devices == 0) {
|
||||
printf("No I2C devices found.\r\n");
|
||||
} else {
|
||||
printf("Total %d I2C devices found.\r\n", found_devices);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t i2c_write_16bits(uint8_t slave_addr, uint8_t reg_addr, uint8_t data[2]) {
|
||||
uint8_t state = I2C_START;
|
||||
uint16_t timeout = 0;
|
||||
uint8_t i2c_timeout_flag = 0;
|
||||
|
||||
/* enable acknowledge */
|
||||
i2c_ack_config(I2C_PHY, I2C_ACK_ENABLE);
|
||||
while (!(i2c_timeout_flag)) {
|
||||
switch (state) {
|
||||
case I2C_START:
|
||||
/* i2c master sends start signal only when the bus is idle */
|
||||
while (i2c_flag_get(I2C_PHY, I2C_FLAG_I2CBSY) && (timeout < I2C_TIME_OUT)) {
|
||||
timeout++;
|
||||
}
|
||||
if (timeout < I2C_TIME_OUT) {
|
||||
i2c_start_on_bus(I2C_PHY);
|
||||
timeout = 0;
|
||||
state = I2C_SEND_ADDRESS;
|
||||
} else {
|
||||
timeout = 0;
|
||||
state = I2C_START;
|
||||
#ifdef DEBUG_VERBOES
|
||||
printf("i2c bus is busy in WRITE BYTE!\n");
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case I2C_SEND_ADDRESS:
|
||||
/* i2c master sends START signal successfully */
|
||||
while ((!i2c_flag_get(I2C_PHY, I2C_FLAG_SBSEND)) && (timeout < I2C_TIME_OUT)) {
|
||||
timeout++;
|
||||
}
|
||||
if (timeout < I2C_TIME_OUT) {
|
||||
i2c_master_addressing(I2C_PHY, slave_addr, I2C_TRANSMITTER);
|
||||
timeout = 0;
|
||||
state = I2C_CLEAR_ADDRESS_FLAG;
|
||||
} else {
|
||||
timeout = 0;
|
||||
state = I2C_START;
|
||||
#ifdef DEBUG_VERBOES
|
||||
printf("i2c master sends start signal timeout in WRITE BYTE!\n");
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case I2C_CLEAR_ADDRESS_FLAG:
|
||||
/* address flag set means i2c slave sends ACK */
|
||||
while ((!i2c_flag_get(I2C_PHY, I2C_FLAG_ADDSEND)) && (timeout < I2C_TIME_OUT)) {
|
||||
timeout++;
|
||||
}
|
||||
if (timeout < I2C_TIME_OUT) {
|
||||
i2c_flag_clear(I2C_PHY, I2C_FLAG_ADDSEND);
|
||||
timeout = 0;
|
||||
state = I2C_TRANSMIT_DATA;
|
||||
} else {
|
||||
timeout = 0;
|
||||
state = I2C_START;
|
||||
#ifdef DEBUG_VERBOES
|
||||
printf("i2c master clears address flag timeout in WRITE BYTE!\n");
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case I2C_TRANSMIT_DATA:
|
||||
/* wait until the transmit data buffer is empty */
|
||||
while ((!i2c_flag_get(I2C_PHY, I2C_FLAG_TBE)) && (timeout < I2C_TIME_OUT)) {
|
||||
timeout++;
|
||||
}
|
||||
if (timeout < I2C_TIME_OUT) {
|
||||
/* send IIC register address */
|
||||
i2c_data_transmit(I2C_PHY, reg_addr);
|
||||
timeout = 0;
|
||||
} else {
|
||||
timeout = 0;
|
||||
state = I2C_START;
|
||||
#ifdef DEBUG_VERBOES
|
||||
printf("i2c master sends data timeout in WRITE BYTE!\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
/* wait until BTC bit is set */
|
||||
while ((!i2c_flag_get(I2C_PHY, I2C_FLAG_BTC)) && (timeout < I2C_TIME_OUT)) {
|
||||
timeout++;
|
||||
}
|
||||
if (timeout < I2C_TIME_OUT) {
|
||||
/* send register MSB value */
|
||||
i2c_data_transmit(I2C_PHY, data[0]);
|
||||
timeout = 0;
|
||||
} else {
|
||||
timeout = 0;
|
||||
state = I2C_START;
|
||||
#ifdef DEBUG_VERBOES
|
||||
printf("i2c master sends MSB data timeout in WRITE BYTE!\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
/* wait until BTC bit is set */
|
||||
while ((!i2c_flag_get(I2C_PHY, I2C_FLAG_BTC)) && (timeout < I2C_TIME_OUT)) {
|
||||
timeout++;
|
||||
}
|
||||
if (timeout < I2C_TIME_OUT) {
|
||||
/* send register LSB value */
|
||||
i2c_data_transmit(I2C_PHY, data[1]);
|
||||
timeout = 0;
|
||||
state = I2C_STOP;
|
||||
} else {
|
||||
timeout = 0;
|
||||
state = I2C_START;
|
||||
#ifdef DEBUG_VERBOES
|
||||
printf("i2c master sends LSB data timeout in WRITE BYTE!\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
/* wait until BTC bit is set */
|
||||
while ((!i2c_flag_get(I2C_PHY, I2C_FLAG_BTC)) && (timeout < I2C_TIME_OUT)) {
|
||||
timeout++;
|
||||
}
|
||||
if (timeout < I2C_TIME_OUT) {
|
||||
state = I2C_STOP;
|
||||
timeout = 0;
|
||||
} else {
|
||||
timeout = 0;
|
||||
state = I2C_START;
|
||||
#ifdef DEBUG_VERBOES
|
||||
printf("i2c master sends data timeout in WRITE BYTE!\n");
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case I2C_STOP:
|
||||
/* send a stop condition to I2C bus */
|
||||
i2c_stop_on_bus(I2C_PHY);
|
||||
/* i2c master sends STOP signal successfully */
|
||||
while ((I2C_CTL0(I2C_PHY) & I2C_CTL0_STOP) && (timeout < I2C_TIME_OUT)) {
|
||||
timeout++;
|
||||
}
|
||||
if (timeout < I2C_TIME_OUT) {
|
||||
timeout = 0;
|
||||
state = I2C_END;
|
||||
i2c_timeout_flag = I2C_OK;
|
||||
} else {
|
||||
timeout = 0;
|
||||
state = I2C_START;
|
||||
#ifdef DEBUG_VERBOES
|
||||
printf("i2c master sends stop signal timeout in WRITE BYTE!\n");
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
default:
|
||||
state = I2C_START;
|
||||
i2c_timeout_flag = I2C_OK;
|
||||
timeout = 0;
|
||||
#ifdef DEBUG_VERBOES
|
||||
printf("i2c master sends start signal in WRITE BYTE.\n");
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
return I2C_END;
|
||||
}
|
||||
|
||||
uint8_t i2c_read_16bits(uint8_t slave_addr, uint8_t reg_addr, uint8_t *data) {
|
||||
uint8_t state = I2C_START;
|
||||
uint8_t read_cycle = 0;
|
||||
uint16_t timeout = 0;
|
||||
uint8_t i2c_timeout_flag = 0;
|
||||
uint8_t number_of_byte = 2;
|
||||
|
||||
/* enable acknowledge */
|
||||
i2c_ack_config(I2C_PHY, I2C_ACK_ENABLE);
|
||||
|
||||
while (!(i2c_timeout_flag)) {
|
||||
switch (state) {
|
||||
case I2C_START:
|
||||
if (RESET == read_cycle) {
|
||||
/* i2c master sends start signal only when the bus is idle */
|
||||
while (i2c_flag_get(I2C_PHY, I2C_FLAG_I2CBSY) && (timeout < I2C_TIME_OUT)) {
|
||||
timeout++;
|
||||
}
|
||||
if (timeout < I2C_TIME_OUT) {
|
||||
/* whether to send ACK or not for the next byte */
|
||||
i2c_ackpos_config(I2C_PHY, I2C_ACKPOS_NEXT);
|
||||
} else {
|
||||
// i2c_bus_reset();
|
||||
timeout = 0;
|
||||
state = I2C_START;
|
||||
#ifdef DEBUG_VERBOES
|
||||
printf("i2c bus is busy in READ!\n");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
/* send the start signal */
|
||||
i2c_start_on_bus(I2C_PHY);
|
||||
timeout = 0;
|
||||
state = I2C_SEND_ADDRESS;
|
||||
break;
|
||||
case I2C_SEND_ADDRESS:
|
||||
/* i2c master sends START signal successfully */
|
||||
while ((!i2c_flag_get(I2C_PHY, I2C_FLAG_SBSEND)) && (timeout < I2C_TIME_OUT)) {
|
||||
timeout++;
|
||||
}
|
||||
if (timeout < I2C_TIME_OUT) {
|
||||
if (RESET == read_cycle) {
|
||||
i2c_master_addressing(I2C_PHY, slave_addr, I2C_TRANSMITTER);
|
||||
state = I2C_CLEAR_ADDRESS_FLAG;
|
||||
} else {
|
||||
i2c_master_addressing(I2C_PHY, slave_addr, I2C_RECEIVER);
|
||||
i2c_ack_config(I2C_PHY, I2C_ACK_DISABLE);
|
||||
state = I2C_CLEAR_ADDRESS_FLAG;
|
||||
}
|
||||
timeout = 0;
|
||||
} else {
|
||||
timeout = 0;
|
||||
state = I2C_START;
|
||||
read_cycle = RESET;
|
||||
#ifdef DEBUG_VERBOES
|
||||
printf("i2c master sends start signal timeout in READ!\n");
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case I2C_CLEAR_ADDRESS_FLAG:
|
||||
/* address flag set means i2c slave sends ACK */
|
||||
while ((!i2c_flag_get(I2C_PHY, I2C_FLAG_ADDSEND)) && (timeout < I2C_TIME_OUT)) {
|
||||
timeout++;
|
||||
}
|
||||
if (timeout < I2C_TIME_OUT) {
|
||||
i2c_flag_clear(I2C_PHY, I2C_FLAG_ADDSEND);
|
||||
if ((SET == read_cycle) && (1 == number_of_byte)) {
|
||||
/* send a stop condition to I2C bus */
|
||||
i2c_stop_on_bus(I2C_PHY);
|
||||
}
|
||||
timeout = 0;
|
||||
state = I2C_TRANSMIT_DATA;
|
||||
} else {
|
||||
timeout = 0;
|
||||
state = I2C_START;
|
||||
read_cycle = RESET;
|
||||
#ifdef DEBUG_VERBOES
|
||||
printf("i2c master clears address flag timeout in READ!\n");
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case I2C_TRANSMIT_DATA:
|
||||
if (RESET == read_cycle) {
|
||||
/* wait until the transmit data buffer is empty */
|
||||
while ((!i2c_flag_get(I2C_PHY, I2C_FLAG_TBE)) && (timeout < I2C_TIME_OUT)) {
|
||||
timeout++;
|
||||
}
|
||||
if (timeout < I2C_TIME_OUT) {
|
||||
/* send the EEPROM's internal address to write to : only one byte address */
|
||||
i2c_data_transmit(I2C_PHY, reg_addr);
|
||||
timeout = 0;
|
||||
} else {
|
||||
timeout = 0;
|
||||
state = I2C_START;
|
||||
read_cycle = RESET;
|
||||
#ifdef DEBUG_VERBOES
|
||||
printf("i2c master wait data buffer is empty timeout in READ!\n");
|
||||
#endif
|
||||
}
|
||||
/* wait until BTC bit is set */
|
||||
while ((!i2c_flag_get(I2C_PHY, I2C_FLAG_BTC)) && (timeout < I2C_TIME_OUT)) {
|
||||
timeout++;
|
||||
}
|
||||
if (timeout < I2C_TIME_OUT) {
|
||||
timeout = 0;
|
||||
state = I2C_START;
|
||||
read_cycle = SET;
|
||||
} else {
|
||||
timeout = 0;
|
||||
state = I2C_START;
|
||||
read_cycle = RESET;
|
||||
#ifdef DEBUG_VERBOES
|
||||
printf("i2c master sends register address timeout in READ!\n");
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
while (number_of_byte) {
|
||||
timeout++;
|
||||
if (2 == number_of_byte) {
|
||||
/* wait until BTC bit is set */
|
||||
while (!i2c_flag_get(I2C_PHY, I2C_FLAG_BTC));
|
||||
/* send a stop condition to I2C bus */
|
||||
i2c_stop_on_bus(I2C_PHY);
|
||||
}
|
||||
/* wait until RBNE bit is set */
|
||||
if (i2c_flag_get(I2C_PHY, I2C_FLAG_RBNE)) {
|
||||
/* read a byte from the EEPROM */
|
||||
*data = i2c_data_receive(I2C_PHY);
|
||||
/* point to the next location where the byte read will be saved */
|
||||
data++;
|
||||
/* decrement the read bytes counter */
|
||||
number_of_byte--;
|
||||
timeout = 0;
|
||||
}
|
||||
if (timeout > I2C_TIME_OUT) {
|
||||
timeout = 0;
|
||||
state = I2C_START;
|
||||
read_cycle = 0;
|
||||
#ifdef DEBUG_VERBOES
|
||||
printf("i2c master sends data timeout in READ!\n");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
timeout = 0;
|
||||
state = I2C_STOP;
|
||||
}
|
||||
break;
|
||||
case I2C_STOP:
|
||||
/* i2c master sends STOP signal successfully */
|
||||
while ((I2C_CTL0(I2C_PHY) & I2C_CTL0_STOP) && (timeout < I2C_TIME_OUT)) {
|
||||
timeout++;
|
||||
}
|
||||
if (timeout < I2C_TIME_OUT) {
|
||||
timeout = 0;
|
||||
state = I2C_END;
|
||||
i2c_timeout_flag = I2C_OK;
|
||||
} else {
|
||||
timeout = 0;
|
||||
state = I2C_START;
|
||||
read_cycle = 0;
|
||||
#ifdef DEBUG_VERBOES
|
||||
printf("i2c master sends stop signal timeout in READ!\n");
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
default:
|
||||
state = I2C_START;
|
||||
read_cycle = 0;
|
||||
i2c_timeout_flag = I2C_OK;
|
||||
timeout = 0;
|
||||
#ifdef DEBUG_VERBOES
|
||||
printf("i2c master sends start signal in READ.\n");
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
return I2C_END;
|
||||
}
|
39
src/led.c
Normal file
39
src/led.c
Normal file
@@ -0,0 +1,39 @@
|
||||
//
|
||||
// Created by yelv1 on 24-12-30.
|
||||
//
|
||||
|
||||
#include "led.h"
|
||||
|
||||
/*!
|
||||
\brief led blink configuration
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void led_blink_config(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_OD, GPIO_OSPEED_50MHZ, LED_PIN);
|
||||
gpio_bit_write(LED_PORT, LED_PIN, SET);
|
||||
|
||||
rcu_periph_clock_enable(LED_BLINK_TIMER_RCU);
|
||||
timer_deinit(LED_BLINK_TIMER);
|
||||
|
||||
timer_parameter_struct timer_initpara;
|
||||
timer_struct_para_init(&timer_initpara);
|
||||
timer_initpara.prescaler =7199;
|
||||
timer_initpara.alignedmode =TIMER_COUNTER_EDGE;
|
||||
timer_initpara.counterdirection =TIMER_COUNTER_UP;
|
||||
timer_initpara.period =9999;
|
||||
timer_initpara.clockdivision =TIMER_CKDIV_DIV1;
|
||||
timer_init(LED_BLINK_TIMER, &timer_initpara);
|
||||
|
||||
timer_auto_reload_shadow_enable(LED_BLINK_TIMER);
|
||||
timer_interrupt_enable(LED_BLINK_TIMER, TIMER_INT_UP);
|
||||
|
||||
timer_enable(LED_BLINK_TIMER);
|
||||
|
||||
nvic_irq_enable(LED_BLINK_IRQ, 2);
|
||||
}
|
43
src/main.c
Normal file
43
src/main.c
Normal file
@@ -0,0 +1,43 @@
|
||||
/*!
|
||||
\file main.c
|
||||
\brief led spark with systick, USART print and key example
|
||||
|
||||
\version 2024-02-22, V2.1.0, firmware for GD32E23x
|
||||
*/
|
||||
#include "main.h"
|
||||
|
||||
/*!
|
||||
\brief main function
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
int main(void)
|
||||
{
|
||||
/* configure systick */
|
||||
systick_config();
|
||||
/* configure USART */
|
||||
rs485_config();
|
||||
/* configure LED */
|
||||
led_blink_config();
|
||||
/* configure FWDGT */
|
||||
watchdog_init();
|
||||
|
||||
printf("system start!\r\n");
|
||||
|
||||
while(1){
|
||||
printf("hello world!\r\n");
|
||||
delay_ms(500);
|
||||
|
||||
watchdog_reload();
|
||||
}
|
||||
}
|
||||
|
||||
/* retarget the C library printf function to the USART */
|
||||
int _write(int fd, char *pBuffer, int size) {
|
||||
for (int i = 0; i < size; i++) {
|
||||
usart_data_transmit(USART0, (uint8_t) pBuffer[i]);
|
||||
while (RESET == usart_flag_get(USART0, USART_FLAG_TBE));
|
||||
}
|
||||
return size;
|
||||
}
|
217
src/soft_i2c.c
Normal file
217
src/soft_i2c.c
Normal file
@@ -0,0 +1,217 @@
|
||||
//
|
||||
// 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_us(20); // 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(I2C_GPIO_RCU);
|
||||
|
||||
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) {
|
||||
// sda_out();
|
||||
I2C_SCL_LOW();
|
||||
I2C_SDA_LOW();
|
||||
soft_i2c_delay();
|
||||
I2C_SCL_HIGH();
|
||||
soft_i2c_delay();
|
||||
I2C_SDA_HIGH();
|
||||
}
|
||||
|
||||
/*!
|
||||
\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();
|
||||
soft_i2c_delay();
|
||||
I2C_SCL_HIGH();
|
||||
soft_i2c_delay();
|
||||
uint8_t ack = !I2C_SDA_READ();
|
||||
I2C_SCL_LOW();
|
||||
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]) {
|
||||
soft_i2c_start();
|
||||
soft_i2c_send_byte(slave_addr);
|
||||
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_OK;
|
||||
}
|
||||
|
||||
uint8_t soft_i2c_read_16bits(uint8_t slave_addr, uint8_t reg_addr, uint8_t *data)
|
||||
{
|
||||
soft_i2c_start();
|
||||
soft_i2c_send_byte(slave_addr);
|
||||
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 | 0x01);
|
||||
if (!soft_i2c_wait_ack()) {
|
||||
soft_i2c_stop();
|
||||
return SOFT_I2C_FAIL;
|
||||
}
|
||||
soft_i2c_delay();
|
||||
data[0] = soft_i2c_receive_byte(1);
|
||||
data[1] = soft_i2c_receive_byte(0);
|
||||
soft_i2c_stop();
|
||||
return SOFT_I2C_OK;
|
||||
}
|
91
src/systick.c
Normal file
91
src/systick.c
Normal file
@@ -0,0 +1,91 @@
|
||||
/**
|
||||
* ************************************************************************
|
||||
*
|
||||
* @file systick.c
|
||||
* @author GD32
|
||||
* @brief 通过 SysTick 定时器进行微秒级别和毫秒级别的延时函数
|
||||
*
|
||||
* ************************************************************************
|
||||
* @copyright Copyright (c) 2024 GD32
|
||||
* ************************************************************************
|
||||
*/
|
||||
#include "gd32e23x.h"
|
||||
#include "systick.h"
|
||||
|
||||
volatile static float count_1us = 0;
|
||||
volatile static float count_1ms = 0;
|
||||
|
||||
/**
|
||||
* ************************************************************************
|
||||
* @brief 配置 SysTick 定时器
|
||||
*
|
||||
*
|
||||
* ************************************************************************
|
||||
*/
|
||||
void systick_config(void)
|
||||
{
|
||||
//设置了 SysTick 定时器的时钟源为 HCLK/8
|
||||
systick_clksource_set(SYSTICK_CLKSOURCE_HCLK_DIV8);
|
||||
//计算了每微秒所需的 SysTick 计数值
|
||||
count_1us = (float)SystemCoreClock/8000000;
|
||||
//计算了每毫秒所需的 SysTick 计数值
|
||||
count_1ms = (float)count_1us * 1000;
|
||||
}
|
||||
|
||||
/**
|
||||
* ************************************************************************
|
||||
* @brief delay_us 微秒延时函数
|
||||
*
|
||||
* @param[in] count 微秒值
|
||||
*
|
||||
* ************************************************************************
|
||||
*/
|
||||
void delay_us(uint32_t count)
|
||||
{
|
||||
uint32_t ctl;
|
||||
|
||||
//设置 SysTick 计数器的装载值
|
||||
SysTick->LOAD = (uint32_t)(count * count_1us);
|
||||
//清零 SysTick 计数器,以确保计数器从零开始计数
|
||||
SysTick->VAL = 0x0000U;
|
||||
//使能 SysTick 定时器,开始进行计数
|
||||
SysTick->CTRL = SysTick_CTRL_ENABLE_Msk;
|
||||
//等待 SysTick 计数器的计数值达到装载值时退出
|
||||
do
|
||||
{
|
||||
ctl = SysTick->CTRL; //读取 CTRL 寄存器的值
|
||||
}while((ctl & SysTick_CTRL_ENABLE_Msk)&&!(ctl & SysTick_CTRL_COUNTFLAG_Msk));
|
||||
//循环退出,禁用 SysTick 定时器
|
||||
SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;
|
||||
//将 SysTick 计数器的当前值清零,以便下次使用
|
||||
SysTick->VAL = 0x0000U;
|
||||
}
|
||||
|
||||
/**
|
||||
* ************************************************************************
|
||||
* @brief delay_ms 毫秒延时函数
|
||||
*
|
||||
* @param[in] count 毫秒值
|
||||
*
|
||||
* ************************************************************************
|
||||
*/
|
||||
void delay_ms(uint32_t count)
|
||||
{
|
||||
uint32_t ctl;
|
||||
|
||||
//设置 SysTick 计数器的装载值
|
||||
SysTick->LOAD = (uint32_t)(count * count_1ms);
|
||||
//清零 SysTick 计数器,以确保计数器从零开始计数
|
||||
SysTick->VAL = 0x0000U;
|
||||
//使能 SysTick 定时器,开始进行计数
|
||||
SysTick->CTRL = SysTick_CTRL_ENABLE_Msk;
|
||||
//等待 SysTick 计数器的计数值达到装载值时退出
|
||||
do
|
||||
{
|
||||
ctl = SysTick->CTRL; //读取 CTRL 寄存器的值
|
||||
}while((ctl&SysTick_CTRL_ENABLE_Msk)&&!(ctl & SysTick_CTRL_COUNTFLAG_Msk));
|
||||
//循环退出,禁用 SysTick 定时器
|
||||
SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;
|
||||
//将 SysTick 计数器的当前值清零,以便下次使用
|
||||
SysTick->VAL = 0x0000U;
|
||||
}
|
46
src/usart.c
Normal file
46
src/usart.c
Normal file
@@ -0,0 +1,46 @@
|
||||
//
|
||||
// Created by yelv1 on 24-12-30.
|
||||
//
|
||||
|
||||
#include "usart.h"
|
||||
|
||||
/**
|
||||
* @brief configure the USART
|
||||
* @param none
|
||||
* @retval none
|
||||
*/
|
||||
void usart_config(void)
|
||||
{
|
||||
rcu_periph_clock_enable(USART_GPIO_RCU);
|
||||
rcu_periph_clock_enable(USART_RCU);
|
||||
|
||||
gpio_af_set(USART_GPIO_PORT, USART_GPIO_AF, USART_RX_PIN);
|
||||
gpio_af_set(USART_GPIO_PORT, USART_GPIO_AF, USART_TX_PIN);
|
||||
|
||||
gpio_mode_set(USART_GPIO_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, USART_RX_PIN);
|
||||
gpio_output_options_set(USART_GPIO_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_10MHZ, USART_RX_PIN);
|
||||
gpio_mode_set(USART_GPIO_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, USART_TX_PIN);
|
||||
gpio_output_options_set(USART_GPIO_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_10MHZ, USART_TX_PIN);
|
||||
|
||||
usart_deinit(USART_PHY);
|
||||
usart_baudrate_set(USART_PHY, USART_PHY_BAUDRATE);
|
||||
usart_receive_config(USART_PHY, USART_RECEIVE_ENABLE);
|
||||
usart_transmit_config(USART_PHY, USART_TRANSMIT_ENABLE);
|
||||
|
||||
usart_enable(USART_PHY);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief configure the RS485(MAX13487) driver
|
||||
* @param none
|
||||
* @retval none
|
||||
*/
|
||||
void rs485_config(void)
|
||||
{
|
||||
usart_config();
|
||||
|
||||
gpio_mode_set(RS485_EN_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, RS485_EN_PIN);
|
||||
gpio_output_options_set(RS485_EN_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, RS485_EN_PIN);
|
||||
|
||||
gpio_bit_write(RS485_EN_PORT, RS485_EN_PIN, SET); //auto dircetion control
|
||||
}
|
Reference in New Issue
Block a user