diff --git a/CMakeLists.txt b/CMakeLists.txt index 11519a3..841fac0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,6 +20,9 @@ set(TARGET_C_SRC ${CMAKE_SOURCE_DIR}/src/systick.c ${CMAKE_SOURCE_DIR}/src/led.c ${CMAKE_SOURCE_DIR}/src/usart.c + ${CMAKE_SOURCE_DIR}/src/soft_i2c.c + ${CMAKE_SOURCE_DIR}/src/i2c.c + ${CMAKE_SOURCE_DIR}/src/fwdgt.c ) add_executable(gd32e23x_template ${TARGET_C_SRC}) diff --git a/inc/board_config.h b/inc/board_config.h index de0b880..d853b8e 100644 --- a/inc/board_config.h +++ b/inc/board_config.h @@ -5,14 +5,15 @@ #ifndef BOARD_CONFIG_H #define BOARD_CONFIG_H -#define SOFTWARE_IIC +// #define SOFTWARE_IIC // #define DEBUG_VERBOES /******************************************************************************/ -#define RCU_GPIO_I2C RCU_GPIOF -#define RCU_I2C RCU_I2C0 +#define I2C_GPIO_RCU RCU_GPIOF +#define I2C_RCU RCU_I2C0 +#define I2C_PHY I2C0 #define I2C_SCL_PORT GPIOF #define I2C_SCL_PIN GPIO_PIN_1 #define I2C_SDA_PORT GPIOF @@ -21,8 +22,8 @@ /******************************************************************************/ -#define USART_RCU RCU_USART0 #define USART_GPIO_RCU RCU_GPIOA +#define USART_RCU RCU_USART0 #define USART_GPIO_PORT GPIOA #define USART_GPIO_AF GPIO_AF_1 #define USART_TX_PIN GPIO_PIN_2 diff --git a/inc/fwdgt.h b/inc/fwdgt.h new file mode 100644 index 0000000..035ca24 --- /dev/null +++ b/inc/fwdgt.h @@ -0,0 +1,17 @@ +// +// 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); + +void watchdog_reload(void); + +#endif //FWDGT_H diff --git a/inc/i2c.h b/inc/i2c.h new file mode 100644 index 0000000..ea09aa7 --- /dev/null +++ b/inc/i2c.h @@ -0,0 +1,53 @@ +// +// 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 +#include +#include +#include +#include + +#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/main.h b/inc/main.h index b2da3dd..22cd3d4 100644 --- a/inc/main.h +++ b/inc/main.h @@ -41,6 +41,13 @@ OF SUCH DAMAGE. #include "gd32e23x_libopt.h" #include "led.h" #include "usart.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/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/src/fwdgt.c b/src/fwdgt.c new file mode 100644 index 0000000..4beebce --- /dev/null +++ b/src/fwdgt.c @@ -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(); +} \ No newline at end of file diff --git a/src/i2c.c b/src/i2c.c new file mode 100644 index 0000000..300f784 --- /dev/null +++ b/src/i2c.c @@ -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; +} diff --git a/src/main.c b/src/main.c index 3402a38..ebdcccc 100644 --- a/src/main.c +++ b/src/main.c @@ -20,13 +20,16 @@ int main(void) rs485_config(); /* configure LED */ led_blink_config(); + /* configure FWDGT */ + watchdog_init(); - delay_ms(5000); printf("system start!\r\n"); while(1){ - printf("hello world!\r\n"); - delay_ms(5000); + printf("hello world!\r\n"); + delay_ms(500); + watchdog_reload(); + } } diff --git a/src/soft_i2c.c b/src/soft_i2c.c new file mode 100644 index 0000000..843cfd0 --- /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(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; +} \ No newline at end of file