From fecaa256ca875a88d75a33249926d835c4ddafe0 Mon Sep 17 00:00:00 2001 From: yelvlab Date: Mon, 30 Dec 2024 22:22:48 +0800 Subject: [PATCH] test --- CMakeLists.txt | 6 +- README.md | 1 - inc/board_config.h | 44 +++ inc/fwdgt.h | 15 + inc/i2c.h | 48 ++++ inc/led.h | 13 + inc/main.h | 16 ++ inc/peripheral.h | 11 - inc/rs485.h | 22 ++ inc/soft_i2c.h | 53 ++++ sdk/CMSIS/src/system_gd32e23x.c | 2 +- src/fwdgt.c | 28 ++ src/gd32e23x_it.c | 54 ++-- src/i2c.c | 491 ++++++++++++++++++++++++++++++++ src/led.c | 38 +++ src/main.c | 25 +- src/peripheral.c | 63 ---- src/rs485.c | 49 ++++ src/soft_i2c.c | 217 ++++++++++++++ 19 files changed, 1079 insertions(+), 117 deletions(-) create mode 100644 inc/board_config.h create mode 100644 inc/fwdgt.h create mode 100644 inc/i2c.h create mode 100644 inc/led.h delete mode 100644 inc/peripheral.h create mode 100644 inc/rs485.h create mode 100644 inc/soft_i2c.h create mode 100644 src/fwdgt.c create mode 100644 src/i2c.c create mode 100644 src/led.c delete mode 100644 src/peripheral.c create mode 100644 src/rs485.c create mode 100644 src/soft_i2c.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 30de3dc..9135aef 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,7 +18,11 @@ set(TARGET_C_SRC ${CMAKE_SOURCE_DIR}/src/main.c ${CMAKE_SOURCE_DIR}/src/gd32e23x_it.c ${CMAKE_SOURCE_DIR}/src/systick.c - ${CMAKE_SOURCE_DIR}/src/peripheral.c + ${CMAKE_SOURCE_DIR}/src/rs485.c + ${CMAKE_SOURCE_DIR}/src/led.c + ${CMAKE_SOURCE_DIR}/src/i2c.c + ${CMAKE_SOURCE_DIR}/src/soft_i2c.c + ${CMAKE_SOURCE_DIR}/src/fwdgt.c ) add_executable(gd32e23x_template ${TARGET_C_SRC}) diff --git a/README.md b/README.md index 40b9a59..f53230e 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,6 @@ set(TARGET_C_SRC ${CMAKE_SOURCE_DIR}/src/main.c ${CMAKE_SOURCE_DIR}/src/gd32e23x_it.c ${CMAKE_SOURCE_DIR}/src/systick.c - ${CMAKE_SOURCE_DIR}/src/peripheral.c ) ``` ## 关于链接脚本 diff --git a/inc/board_config.h b/inc/board_config.h new file mode 100644 index 0000000..c8a2284 --- /dev/null +++ b/inc/board_config.h @@ -0,0 +1,44 @@ +// +// Created by dell on 24-12-28. +// + +#ifndef BOARD_CONFIG_H +#define BOARD_CONFIG_H + +#define SOFTWARE_IIC + +// #define DEBUG_VERBOES + +/******************************************************************************/ + +#define RCU_GPIO_I2C RCU_GPIOF +#define RCU_I2C RCU_I2C0 +#define I2C_SCL_PORT GPIOF +#define I2C_SCL_PIN GPIO_PIN_1 +#define I2C_SDA_PORT GPIOF +#define I2C_SDA_PIN GPIO_PIN_0 +#define I2C_GPIO_AF GPIO_AF_1 + +/******************************************************************************/ + +#define RS485_RCU RCU_USART0 +#define RS485_GPIO_RCU RCU_GPIOA +#define RS485_GPIO_PORT GPIOA +#define RS485_TX_PIN GPIO_PIN_2 +#define RS485_RX_PIN GPIO_PIN_3 +#define RS485_PHY USART0 +#define RS485_BAUDRATE 115200U +#define RS485_EN_PIN GPIO_PIN_1 + +/******************************************************************************/ + +#define LED_PORT GPIOA +#define LED_PIN GPIO_PIN_7 +#define LED_RCU RCU_GPIOA +#define LED_BLINK_TIMER_RCU RCU_TIMER16 +#define LED_BLINK_TIMER TIMER16 +#define LED_BLINK_IRQ TIMER16_IRQn + +/******************************************************************************/ + +#endif //BOARD_CONFIG_H diff --git a/inc/fwdgt.h b/inc/fwdgt.h new file mode 100644 index 0000000..28da74c --- /dev/null +++ b/inc/fwdgt.h @@ -0,0 +1,15 @@ +// +// Created by yelv1 on 24-12-29. +// + +#ifndef FWDGT_H +#define FWDGT_H + +#include "gd32e23x.h" +#include "board_config.h" + +void watchdog_init(void); + +void fwdgt_reset_mcu(void); + +#endif //FWDGT_H diff --git a/inc/i2c.h b/inc/i2c.h new file mode 100644 index 0000000..927e28d --- /dev/null +++ b/inc/i2c.h @@ -0,0 +1,48 @@ +// +// Created by dell on 24-12-20. +// + +#ifndef I2C_H +#define I2C_H + +#include "gd32e23x_it.h" +#include "gd32e23x.h" +#include "systick.h" +#include "main.h" + +#include "board_config.h" + +/******************************************************************************/ + +#define I2C_SPEED 20000 + +#define I2C_TIME_OUT (uint16_t)(5000) +#define I2C_OK 1 +#define I2C_FAIL 0 +#define I2C_END 1 + +/******************************************************************************/ + +typedef enum { + I2C_START = 0, + I2C_SEND_ADDRESS, + I2C_CLEAR_ADDRESS_FLAG, + I2C_TRANSMIT_DATA, + I2C_STOP +} i2c_process_enum; + +/******************************************************************************/ + +void i2c_gpio_config(void); + +void i2c_config(void); + +void i2c_bus_reset(void); + +void i2c_scan(void); + +uint8_t i2c_write_16bits(uint8_t slave_addr, uint8_t reg_addr, uint8_t data[2]); + +uint8_t i2c_read_16bits(uint8_t slave_addr, uint8_t reg_addr, uint8_t *data); + +#endif //I2C_H diff --git a/inc/led.h b/inc/led.h new file mode 100644 index 0000000..b02d4ee --- /dev/null +++ b/inc/led.h @@ -0,0 +1,13 @@ +// +// Created by dell on 24-12-20. +// + +#ifndef LED_H +#define LED_H + +#include "gd32e23x_it.h" +#include "board_config.h" + +void led_config(void); + +#endif //LED_H diff --git a/inc/main.h b/inc/main.h index dd037de..15fde7c 100644 --- a/inc/main.h +++ b/inc/main.h @@ -35,4 +35,20 @@ OF SUCH DAMAGE. #ifndef MAIN_H #define MAIN_H +#include +#include "gd32e23x.h" +#include "systick.h" +#include "gd32e23x_libopt.h" +#include "rs485.h" +#include "led.h" +#include "fwdgt.h" +#include "board_config.h" + +#ifdef SOFTWARE_IIC +#include "soft_i2c.h" +#else +#include "i2c.h" +#endif + + #endif /* MAIN_H */ diff --git a/inc/peripheral.h b/inc/peripheral.h deleted file mode 100644 index 31004a4..0000000 --- a/inc/peripheral.h +++ /dev/null @@ -1,11 +0,0 @@ -// -// Created by yelv1 on 24-9-22. -// - -#ifndef PERIPHERAL_H -#define PERIPHERAL_H - -void usart_config(void); -void led_blink_config(void); - -#endif //PERIPHERAL_H diff --git a/inc/rs485.h b/inc/rs485.h new file mode 100644 index 0000000..c63cfd1 --- /dev/null +++ b/inc/rs485.h @@ -0,0 +1,22 @@ +// +// Created by dell on 24-12-3. +// + +#ifndef RS485_H +#define RS485_H + +#include "gd32e23x_it.h" +#include "gd32e23x.h" +#include "board_config.h" + +/******************************************************************************/ + +#define RX_BUFFER_SIZE 32 + +/******************************************************************************/ + +void usart_config(void); + +void rs485_config(void); + +#endif //RS485_H diff --git a/inc/soft_i2c.h b/inc/soft_i2c.h new file mode 100644 index 0000000..5b4d23e --- /dev/null +++ b/inc/soft_i2c.h @@ -0,0 +1,53 @@ +// +// Created by dell on 24-12-28. +// + +#ifndef SOFT_I2C_H +#define SOFT_I2C_H + +#include "gd32e23x_it.h" +#include "gd32e23x.h" +#include "systick.h" +#include "main.h" + +#include "board_config.h" + +/******************************************************************************/ + +#define I2C_SCL_HIGH() gpio_bit_set(I2C_SCL_PORT, I2C_SCL_PIN) +#define I2C_SCL_LOW() gpio_bit_reset(I2C_SCL_PORT, I2C_SCL_PIN) +#define I2C_SDA_HIGH() gpio_bit_set(I2C_SDA_PORT, I2C_SDA_PIN) +#define I2C_SDA_LOW() gpio_bit_reset(I2C_SDA_PORT, I2C_SDA_PIN) +#define I2C_SDA_READ() gpio_input_bit_get(I2C_SDA_PORT, I2C_SDA_PIN) + +/******************************************************************************/ + +#define SOFT_I2C_OK 1 +#define SOFT_I2C_FAIL 0 +#define SOFT_I2C_END 1 + +/******************************************************************************/ + +void soft_i2c_delay(void); + +void soft_i2c_config(void); + +void soft_i2c_start(void); + +void soft_i2c_stop(void); + +void soft_i2c_send_ack(void); + +void soft_i2c_send_nack(void); + +uint8_t soft_i2c_wait_ack(void); + +void soft_i2c_send_byte(uint8_t data); + +uint8_t soft_i2c_receive_byte(uint8_t ack); + +uint8_t soft_i2c_write_16bits(uint8_t slave_addr, uint8_t reg_addr, uint8_t data[2]); + +uint8_t soft_i2c_read_16bits(uint8_t slave_addr, uint8_t reg_addr, uint8_t *data); + +#endif //SOFT_I2C_H diff --git a/sdk/CMSIS/src/system_gd32e23x.c b/sdk/CMSIS/src/system_gd32e23x.c index 84e5032..d8ab26e 100644 --- a/sdk/CMSIS/src/system_gd32e23x.c +++ b/sdk/CMSIS/src/system_gd32e23x.c @@ -45,7 +45,7 @@ /* select a system clock by uncommenting the following line */ //#define __SYSTEM_CLOCK_8M_HXTAL (__HXTAL) -//#define __SYSTEM_CLOCK_8M_IRC8M (__IRC8M) +// #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) diff --git a/src/fwdgt.c b/src/fwdgt.c new file mode 100644 index 0000000..b933237 --- /dev/null +++ b/src/fwdgt.c @@ -0,0 +1,28 @@ +// +// Created by yelv1 on 24-12-29. +// + +#include "fwdgt.h" + +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(); +} + +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(); +} \ No newline at end of file diff --git a/src/gd32e23x_it.c b/src/gd32e23x_it.c index 0c77955..520ce72 100644 --- a/src/gd32e23x_it.c +++ b/src/gd32e23x_it.c @@ -35,6 +35,8 @@ OF SUCH DAMAGE. #include "gd32e23x_it.h" #include "main.h" #include "systick.h" +#include "rs485.h" +#include "led.h" /*! \brief this function handles NMI exception @@ -42,10 +44,9 @@ OF SUCH DAMAGE. \param[out] none \retval none */ -void NMI_Handler(void) -{ +void NMI_Handler(void) { /* if NMI exception occurs, go to infinite loop */ - while(1) { + while (1) { } } @@ -55,10 +56,9 @@ void NMI_Handler(void) \param[out] none \retval none */ -void HardFault_Handler(void) -{ +void HardFault_Handler(void) { /* if Hard Fault exception occurs, go to infinite loop */ - while(1) { + while (1) { } } @@ -68,10 +68,9 @@ void HardFault_Handler(void) \param[out] none \retval none */ -void SVC_Handler(void) -{ +void SVC_Handler(void) { /* if SVC exception occurs, go to infinite loop */ - while(1) { + while (1) { } } @@ -81,10 +80,9 @@ void SVC_Handler(void) \param[out] none \retval none */ -void PendSV_Handler(void) -{ +void PendSV_Handler(void) { /* if PendSV exception occurs, go to infinite loop */ - while(1) { + while (1) { } } @@ -94,26 +92,26 @@ void PendSV_Handler(void) \param[out] none \retval none */ -void SysTick_Handler(void) -{ +void SysTick_Handler(void) { } -void TIMER13_IRQHandler(void) -{ - if (timer_interrupt_flag_get(TIMER13, TIMER_INT_FLAG_UP) == SET) - { - timer_interrupt_flag_clear(TIMER13, TIMER_INT_FLAG_UP); +/** + * @brief This function handles TIMER5 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(GPIOB, GPIO_PIN_1, RESET); - timer_autoreload_value_config(TIMER13, 19200); + if (led_status) { + 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(GPIOB, GPIO_PIN_1, SET); - timer_autoreload_value_config(TIMER13, 800); + gpio_bit_write(LED_PORT, LED_PIN, SET); + timer_autoreload_value_config(LED_BLINK_TIMER, 800); } led_status = !led_status; } -} \ No newline at end of file +} diff --git a/src/i2c.c b/src/i2c.c new file mode 100644 index 0000000..76381c7 --- /dev/null +++ b/src/i2c.c @@ -0,0 +1,491 @@ +// +// 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(RCU_GPIO_I2C); + + /* 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(RCU_I2C); + /* configure I2C clock */ + i2c_clock_config(I2C0, I2C_SPEED, I2C_DTCY_2); + /* configure I2C address */ + i2c_mode_addr_config(I2C0, I2C_I2CMODE_ENABLE, I2C_ADDFORMAT_7BITS, 0xA0); + /* enable I2CX */ + i2c_enable(I2C0); + /* enable acknowledge */ + i2c_ack_config(I2C0, I2C_ACK_ENABLE); +} + +/*! + \brief reset I2C bus + \param[in] none + \param[out] none + \retval none +*/ +void i2c_bus_reset(void) { + i2c_deinit(I2C0); + /* 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(I2C0, I2C_FLAG_I2CBSY) && (timeout < I2C_TIME_OUT)) + timeout++; + if (timeout >= I2C_TIME_OUT) { + continue; // 超时,跳过该地址 + } + i2c_start_on_bus(I2C0); + timeout = 0; + + // 等待起始条件发送完成 + while (!i2c_flag_get(I2C0, I2C_FLAG_SBSEND) && (timeout < I2C_TIME_OUT)) + timeout++; + if (timeout >= I2C_TIME_OUT) { + continue; // 超时,跳过该地址 + } + i2c_master_addressing(I2C0, (address << 1), I2C_TRANSMITTER); + timeout = 0; + + // 等待地址发送完成 + while (!i2c_flag_get(I2C0, I2C_FLAG_ADDSEND) && (timeout < I2C_TIME_OUT)) + timeout++; + if (timeout < I2C_TIME_OUT) { + i2c_flag_clear(I2C0, I2C_FLAG_ADDSEND); + printf("Found device at 0x%02X\r\n", address); + found_devices++; + } + + // 生成停止条件 + i2c_stop_on_bus(I2C0); + + timeout = 0; + + while (i2c_flag_get(I2C0, 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); + } +} + +/*! + \brief write 16 bits data to the specified register of the slave device + \param[in] slave_addr: slave device address + \param[in] reg_addr: register address + \param[in] data: data to be written + \param[out] none + \retval 0: failed, 1: success +*/ +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(I2C0, 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(I2C0, I2C_FLAG_I2CBSY) && (timeout < I2C_TIME_OUT)) { + timeout++; + } + if (timeout < I2C_TIME_OUT) { + i2c_start_on_bus(I2C0); + 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(I2C0, I2C_FLAG_SBSEND)) && (timeout < I2C_TIME_OUT)) { + timeout++; + } + if (timeout < I2C_TIME_OUT) { + i2c_master_addressing(I2C0, 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(I2C0, I2C_FLAG_ADDSEND)) && (timeout < I2C_TIME_OUT)) { + timeout++; + } + if (timeout < I2C_TIME_OUT) { + i2c_flag_clear(I2C0, 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(I2C0, I2C_FLAG_TBE)) && (timeout < I2C_TIME_OUT)) { + timeout++; + } + if (timeout < I2C_TIME_OUT) { + /* send IIC register address */ + i2c_data_transmit(I2C0, 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(I2C0, I2C_FLAG_BTC)) && (timeout < I2C_TIME_OUT)) { + timeout++; + } + if (timeout < I2C_TIME_OUT) { + /* send register MSB value */ + i2c_data_transmit(I2C0, 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(I2C0, I2C_FLAG_BTC)) && (timeout < I2C_TIME_OUT)) { + timeout++; + } + if (timeout < I2C_TIME_OUT) { + /* send register LSB value */ + i2c_data_transmit(I2C0, 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(I2C0, 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(I2C0); + /* i2c master sends STOP signal successfully */ + while ((I2C_CTL0(I2C0) & 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; +} + +/*! + \brief read 16 bits data from the specified register of the slave device + \param[in] slave_addr: slave device address + \param[in] reg_addr: register address + \param[out] data: data to be read + \retval 0: failed, 1: success +*/ +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(I2C0, 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(I2C0, 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(I2C0, 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(I2C0); + timeout = 0; + state = I2C_SEND_ADDRESS; + break; + case I2C_SEND_ADDRESS: + /* i2c master sends START signal successfully */ + while ((!i2c_flag_get(I2C0, I2C_FLAG_SBSEND)) && (timeout < I2C_TIME_OUT)) { + timeout++; + } + if (timeout < I2C_TIME_OUT) { + if (RESET == read_cycle) { + i2c_master_addressing(I2C0, slave_addr, I2C_TRANSMITTER); + state = I2C_CLEAR_ADDRESS_FLAG; + } else { + i2c_master_addressing(I2C0, slave_addr, I2C_RECEIVER); + i2c_ack_config(I2C0, 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(I2C0, I2C_FLAG_ADDSEND)) && (timeout < I2C_TIME_OUT)) { + timeout++; + } + if (timeout < I2C_TIME_OUT) { + i2c_flag_clear(I2C0, I2C_FLAG_ADDSEND); + if ((SET == read_cycle) && (1 == number_of_byte)) { + /* send a stop condition to I2C bus */ + i2c_stop_on_bus(I2C0); + } + 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(I2C0, 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(I2C0, 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(I2C0, 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(I2C0, I2C_FLAG_BTC)); + /* send a stop condition to I2C bus */ + i2c_stop_on_bus(I2C0); + } + /* wait until RBNE bit is set */ + if (i2c_flag_get(I2C0, I2C_FLAG_RBNE)) { + /* read a byte from the EEPROM */ + *data = i2c_data_receive(I2C0); + /* 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(I2C0) & 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; +} diff --git a/src/led.c b/src/led.c new file mode 100644 index 0000000..556e2ef --- /dev/null +++ b/src/led.c @@ -0,0 +1,38 @@ +// +// Created by dell on 24-12-20. +// + +#include "led.h" + +/*! + \brief configure LED + \param[in] none + \param[out] none + \retval none +*/ +void led_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_PP, 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); +} diff --git a/src/main.c b/src/main.c index ec1f78d..6dacc00 100644 --- a/src/main.c +++ b/src/main.c @@ -5,12 +5,6 @@ \version 2024-02-22, V2.1.0, firmware for GD32E23x */ #include "main.h" -#include -#include "gd32e23x.h" -#include "systick.h" -#include "gd32e23x_libopt.h" - -#include "peripheral.h" /*! \brief main function @@ -18,19 +12,26 @@ \param[out] none \retval none */ -int main(void) -{ +int main(void) { + // setbuf(stdout, NULL); /* configure systick */ systick_config(); - usart_config(); - led_blink_config(); + /* configure USART */ + // rs485_config(); + /* configure LED */ + // led_config(); - delay_ms(5000); printf("system start!\r\n"); + rcu_periph_clock_enable(RCU_GPIOA); + + gpio_mode_set(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_7); + gpio_output_options_set(GPIOA, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, GPIO_PIN_7); + gpio_bit_write(GPIOA, GPIO_PIN_7, SET); + while(1){ printf("hello world!\r\n"); - delay_ms(5000); + delay_ms(1000); } } diff --git a/src/peripheral.c b/src/peripheral.c deleted file mode 100644 index 9e8d282..0000000 --- a/src/peripheral.c +++ /dev/null @@ -1,63 +0,0 @@ -// -// Created by yelv1 on 24-9-22. -// -#include "peripheral.h" -#include "gd32e23x.h" - -void usart_config(void) -{ - rcu_periph_clock_enable(RCU_GPIOA); - rcu_periph_clock_enable(RCU_USART0); - - gpio_af_set(GPIOA, GPIO_AF_1, GPIO_PIN_3); - gpio_af_set(GPIOA, GPIO_AF_1, GPIO_PIN_2); - - gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_3); - gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_10MHZ, GPIO_PIN_3); - gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_2); - gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_10MHZ, GPIO_PIN_2); - - usart_deinit(USART0); - usart_baudrate_set(USART0, 115200U); - usart_receive_config(USART0, USART_RECEIVE_ENABLE); - usart_transmit_config(USART0, USART_TRANSMIT_ENABLE); - - usart_enable(USART0); - - gpio_mode_set(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_4); - gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_4); - - gpio_bit_write(GPIOA, GPIO_PIN_4, SET); -} - -/*! - \brief led blink configuration - \param[in] none - \param[out] none - \retval none -*/ -void led_blink_config(void) -{ - rcu_periph_clock_enable(RCU_GPIOB); - - gpio_mode_set(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_1); - gpio_output_options_set(GPIOB, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, GPIO_PIN_1); - gpio_bit_write(GPIOB, GPIO_PIN_1, SET); - - rcu_periph_clock_enable(RCU_TIMER13); - timer_deinit(RCU_TIMER13); - - 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 =999; - timer_initpara.clockdivision =TIMER_CKDIV_DIV1; - timer_init(TIMER13, &timer_initpara); - - timer_auto_reload_shadow_enable(TIMER13); - timer_interrupt_enable(TIMER13, TIMER_INT_UP); - nvic_irq_enable(TIMER13_IRQn, 0); - timer_enable(TIMER13); -} diff --git a/src/rs485.c b/src/rs485.c new file mode 100644 index 0000000..7d1f418 --- /dev/null +++ b/src/rs485.c @@ -0,0 +1,49 @@ +// +// Created by dell on 24-12-3. +// + +#include "rs485.h" + +/** + * @brief configure the USART0 + * @param none + * @retval none + */ +void usart_config(void) { + 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); + + /* 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); +} + +/** + * @brief configure the RS485(MAX13487EESA) + * @param none + * @retval none + */ +void rs485_config(void) { + usart_config(); + + rcu_periph_clock_enable(RS485_GPIO_RCU); + + /* 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); // auto direction control +} diff --git a/src/soft_i2c.c b/src/soft_i2c.c new file mode 100644 index 0000000..69e0240 --- /dev/null +++ b/src/soft_i2c.c @@ -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(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) { + // 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; +} \ No newline at end of file