Initial commit: CCU621_M firmware project with BLE debug link support.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* @file eeprom_map.h
|
||||
* @brief Compatibility shim for legacy includes.
|
||||
*
|
||||
* EEPROM/FRAM capacity and logical partition macros are now defined in
|
||||
* `fm24cl16.h`. Keep this header to avoid breaking old include paths.
|
||||
*/
|
||||
#ifndef EEPROM_MAP_H
|
||||
#define EEPROM_MAP_H
|
||||
|
||||
#include "fm24cl16.h"
|
||||
|
||||
#endif /* EEPROM_MAP_H */
|
||||
@@ -0,0 +1,102 @@
|
||||
# eeprom 模块说明(i2c1 / fm24cl16)
|
||||
|
||||
> 本文档描述 `CCU621_M` 工程中 `BSP/eeprom` 的职责、接口、初始化方式与测试方法。
|
||||
|
||||
[返回主说明](./../../README.md)
|
||||
|
||||
## 快速跳转
|
||||
|
||||
- [1. 模块职责](#1-模块职责)
|
||||
- [2. 涉及文件](#2-涉及文件)
|
||||
- [3. 初始化流程](#3-初始化流程)
|
||||
- [4. 对外接口](#4-对外接口)
|
||||
- [5. 已接入测试](#5-已接入测试)
|
||||
- [6. 维护注意事项](#6-维护注意事项)
|
||||
- [返回主说明 README](./../../README.md)
|
||||
|
||||
---
|
||||
|
||||
## 1. 模块职责
|
||||
|
||||
`BSP/eeprom` 负责 FM24CL16(I2C FRAM)基础驱动能力,当前职责为:
|
||||
|
||||
- I2C1 引脚与时序配置;
|
||||
- FRAM 地址初始化;
|
||||
- FRAM 指定地址写入与读出;
|
||||
- 提供上层测试调用接口(由 `app_test` 验证读写一致性)。
|
||||
|
||||
---
|
||||
|
||||
## 2. 涉及文件
|
||||
|
||||
| 文件 | 说明 |
|
||||
|---|---|
|
||||
| `BSP/eeprom/i2c1.h` | I2C1 宏配置与函数声明 |
|
||||
| `BSP/eeprom/i2c1.c` | I2C1 GPIO/I2C 初始化与总线复位 |
|
||||
| `BSP/eeprom/fm24cl16.h` | FM24CL16 对外接口声明 + 容量/地址分区宏 |
|
||||
| `BSP/eeprom/fm24cl16.c` | FM24CL16 读写实现(`eeprom_buffer_write/read` 等) |
|
||||
| `BSP/eeprom/eeprom_map.h` | 兼容头(转发到 `fm24cl16.h`) |
|
||||
|
||||
> 说明:历史冗余文件 `eeprom_I2C_fm24cl16.c/.h` 已移除,避免双实现并存导致维护混乱。
|
||||
|
||||
---
|
||||
|
||||
## 3. 初始化流程
|
||||
|
||||
当前已在 `BSP/sys_drv_init.c` 的 `v_sys_hardware_init()` 中接入:
|
||||
|
||||
1. `gpio_config()`:配置 I2C1 对应 GPIO;
|
||||
2. `i2c_config()`:配置 I2C1 时序并使能;
|
||||
3. `i2c_eeprom_init()`:初始化 FM24CL16 设备地址等参数。
|
||||
|
||||
调用位置:系统硬件初始化阶段(通信外设初始化流程中)。
|
||||
|
||||
---
|
||||
|
||||
## 4. 对外接口
|
||||
|
||||
### 4.1 I2C 基础接口(`i2c1.c`)
|
||||
|
||||
- `void gpio_config(void);`
|
||||
- `void i2c_config(void);`
|
||||
- `void i2c_bus_reset(void);`
|
||||
|
||||
### 4.2 EEPROM 接口与地址分区(`fm24cl16.h` + `fm24cl16.c`)
|
||||
|
||||
- `void i2c_eeprom_init(void);`
|
||||
- `void eeprom_buffer_write(uint8_t *p_buffer, uint16_t write_address, uint16_t number_of_byte);`
|
||||
- `void eeprom_buffer_read(uint8_t *p_buffer, uint16_t read_address, uint16_t number_of_byte);`
|
||||
- `void eeprom_driver_init(void);`
|
||||
- 容量/范围宏:`FRAM_SIZE_BYTES`、`FRAM_START_ADDR`、`FRAM_END_ADDR` 等;
|
||||
- 分区宏:`EEPROM_ADDR_CHGRCD_MNG`、`EEPROM_ADDR_HISALARM_MNG`、`EEPROM_ADDR_UNSETTLED_MNG`、`EEPROM_ADDR_CARD_MNG`、`EEPROM_ADDR_A_LOG_DATA`、`EEPROM_ADDR_B_LOG_DATA`。
|
||||
|
||||
> 说明:`eeprom_page_write()` 为驱动内部函数,已收敛为 `fm24cl16.c` 内部 `static`,不再对外暴露。
|
||||
|
||||
---
|
||||
|
||||
## 5. 已接入测试
|
||||
|
||||
在 `app/app_init/app_test.c` 中,测试流程已统一由 `v_app_test_periodic()` 调度,并受总开关控制:
|
||||
|
||||
- `APP_TEST_ENABLE`:0 时不编译测试实现,仅保留空函数桩;
|
||||
- EEPROM 基础读写:固定地址 32B;
|
||||
- EEPROM 多地址测试:覆盖分区起点与测试窗口地址,执行备份-写读校验-恢复;
|
||||
- EEPROM 速度测试:在测试窗口执行循环读写并统计吞吐;
|
||||
- Flash 测试:固定地址测速 + 1MB 步长 32MB 全空间校验。
|
||||
|
||||
---
|
||||
|
||||
## 6. 维护注意事项
|
||||
|
||||
1. 保持 EEPROM 仅一套实现,避免同名接口重复定义;
|
||||
2. 修改 I2C 引脚/时序时,同步更新 `i2c1.h` 与硬件原理图;
|
||||
3. 增加上层功能前,先通过 `u8_app_test_eeprom_rw_once()` 回归;
|
||||
4. EEPROM 驱动已引入互斥访问,新增调用方需避免在中断上下文直接调用阻塞式接口;
|
||||
5. 建议业务数据区与测试区分离(例如测试使用 `0x0600` 起始窗口),避免互相覆盖。
|
||||
|
||||
---
|
||||
|
||||
## 关联文档
|
||||
|
||||
- 主索引:[`CCU621_M/README.md`](./../../README.md)
|
||||
- 本文位置:`BSP/eeprom/eeprom模块说明.md`
|
||||
@@ -0,0 +1,631 @@
|
||||
/*!
|
||||
\file fm24cl16.c
|
||||
\brief the read and write function file
|
||||
|
||||
\version 2025-01-24, V1.4.0, firmware for GD32H7xx
|
||||
*/
|
||||
|
||||
/*
|
||||
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 "fm24cl16.h"
|
||||
#include "i2c1.h"
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "semphr.h"
|
||||
|
||||
#define EEPROM_BLOCK0_ADDRESS 0xA0
|
||||
#define MAX_RELOAD_SIZE 255
|
||||
#define EEPROM_WRITE_DELAY_MS 5U
|
||||
#define EEPROM_STATE_LOOP_MAX 64U
|
||||
/* Stable mode on this board: fixed slave address + 16-bit internal address */
|
||||
#define EEPROM_MEM_ADDR_16BIT 1U
|
||||
#define EEPROM_DEVADDR_FIXED 1U
|
||||
|
||||
static uint8_t eeprom_address;
|
||||
static volatile uint32_t g_eeprom_last_error = 0U;
|
||||
static SemaphoreHandle_t g_eeprom_mutex = NULL;
|
||||
|
||||
/* forward declarations for internal helpers */
|
||||
static void eeprom_i2c_clear_error_flags(void);
|
||||
uint8_t eeprom_probe(uint16_t mem_address);
|
||||
|
||||
static void eeprom_lock(void)
|
||||
{
|
||||
if (g_eeprom_mutex != NULL) {
|
||||
(void)xSemaphoreTake(g_eeprom_mutex, portMAX_DELAY);
|
||||
}
|
||||
}
|
||||
|
||||
static void eeprom_unlock(void)
|
||||
{
|
||||
if (g_eeprom_mutex != NULL) {
|
||||
(void)xSemaphoreGive(g_eeprom_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
enum {
|
||||
EEPROM_ERR_NONE = 0U,
|
||||
EEPROM_ERR_WR_BUSY_TIMEOUT = 1U,
|
||||
EEPROM_ERR_WR_ADDR_TBE_TIMEOUT = 2U,
|
||||
EEPROM_ERR_WR_DATA_TBE_TIMEOUT = 3U,
|
||||
EEPROM_ERR_WR_STOP_TIMEOUT = 4U,
|
||||
EEPROM_ERR_RD_BUSY_TIMEOUT = 5U,
|
||||
EEPROM_ERR_RD_ADDR_TBE_TIMEOUT = 6U,
|
||||
EEPROM_ERR_RD_RESTART_TC_TIMEOUT = 7U,
|
||||
EEPROM_ERR_RD_RELOAD_TCR_TIMEOUT = 8U,
|
||||
EEPROM_ERR_RD_DATA_RBNE_TIMEOUT = 9U,
|
||||
EEPROM_ERR_RD_STOP_TIMEOUT = 10U,
|
||||
EEPROM_ERR_LOOP_GUARD = 11U,
|
||||
EEPROM_ERR_I2C_NACK = 12U,
|
||||
EEPROM_ERR_I2C_BUS = 13U
|
||||
};
|
||||
|
||||
static uint8_t eeprom_i2c_error_pending(void)
|
||||
{
|
||||
if(i2c_flag_get(I2CX, I2C_FLAG_NACK)) {
|
||||
g_eeprom_last_error = EEPROM_ERR_I2C_NACK;
|
||||
i2c_flag_clear(I2CX, I2C_FLAG_NACK);
|
||||
return 1U;
|
||||
}
|
||||
if(i2c_flag_get(I2CX, I2C_FLAG_BERR) || i2c_flag_get(I2CX, I2C_FLAG_LOSTARB) ||
|
||||
i2c_flag_get(I2CX, I2C_FLAG_OUERR)) {
|
||||
g_eeprom_last_error = EEPROM_ERR_I2C_BUS;
|
||||
i2c_flag_clear(I2CX, I2C_FLAG_BERR);
|
||||
i2c_flag_clear(I2CX, I2C_FLAG_LOSTARB);
|
||||
i2c_flag_clear(I2CX, I2C_FLAG_OUERR);
|
||||
return 1U;
|
||||
}
|
||||
return 0U;
|
||||
}
|
||||
|
||||
static void eeprom_i2c_clear_error_flags(void)
|
||||
{
|
||||
i2c_flag_clear(I2CX, I2C_FLAG_NACK);
|
||||
i2c_flag_clear(I2CX, I2C_FLAG_BERR);
|
||||
i2c_flag_clear(I2CX, I2C_FLAG_LOSTARB);
|
||||
i2c_flag_clear(I2CX, I2C_FLAG_OUERR);
|
||||
i2c_flag_clear(I2CX, I2C_FLAG_TIMEOUT);
|
||||
}
|
||||
|
||||
static uint8_t eeprom_make_dev_addr(uint16_t mem_addr)
|
||||
{
|
||||
#if (EEPROM_DEVADDR_FIXED == 1U)
|
||||
(void)mem_addr;
|
||||
return (uint8_t)EEPROM_BLOCK0_ADDRESS;
|
||||
#else
|
||||
return (uint8_t)(EEPROM_BLOCK0_ADDRESS | ((mem_addr >> 7U) & 0x0EU));
|
||||
#endif
|
||||
}
|
||||
|
||||
static void eeprom_page_write(uint8_t *p_buffer, uint16_t write_address, uint8_t number_of_byte);
|
||||
static uint8_t eeprom_read_chunk(uint8_t *p_buffer, uint16_t read_address, uint8_t number_of_byte);
|
||||
|
||||
uint32_t eeprom_get_last_error(void)
|
||||
{
|
||||
return g_eeprom_last_error;
|
||||
}
|
||||
|
||||
uint8_t eeprom_probe(uint16_t mem_address)
|
||||
{
|
||||
uint32_t timeout = 0U;
|
||||
uint8_t dev_addr = eeprom_make_dev_addr(mem_address);
|
||||
|
||||
eeprom_lock();
|
||||
eeprom_i2c_clear_error_flags();
|
||||
if(eeprom_i2c_error_pending()) {
|
||||
i2c_bus_reset();
|
||||
eeprom_unlock();
|
||||
return I2C_FAIL;
|
||||
}
|
||||
i2c_master_addressing(I2CX, dev_addr, I2C_MASTER_TRANSMIT);
|
||||
i2c_transfer_byte_number_config(I2CX,
|
||||
#if (EEPROM_MEM_ADDR_16BIT == 1U)
|
||||
2U
|
||||
#else
|
||||
1U
|
||||
#endif
|
||||
);
|
||||
i2c_automatic_end_disable(I2CX);
|
||||
|
||||
while(i2c_flag_get(I2CX, I2C_FLAG_I2CBSY) && (timeout < I2C_TIME_OUT)) {
|
||||
timeout++;
|
||||
}
|
||||
if(timeout >= I2C_TIME_OUT) {
|
||||
g_eeprom_last_error = EEPROM_ERR_WR_BUSY_TIMEOUT;
|
||||
i2c_bus_reset();
|
||||
eeprom_unlock();
|
||||
return I2C_FAIL;
|
||||
}
|
||||
|
||||
i2c_start_on_bus(I2CX);
|
||||
timeout = 0U;
|
||||
while((!i2c_flag_get(I2CX, I2C_FLAG_TBE)) && (timeout < I2C_TIME_OUT)) {
|
||||
if(eeprom_i2c_error_pending()) {
|
||||
i2c_stop_on_bus(I2CX);
|
||||
i2c_bus_reset();
|
||||
eeprom_unlock();
|
||||
return I2C_FAIL;
|
||||
}
|
||||
timeout++;
|
||||
}
|
||||
if(timeout >= I2C_TIME_OUT) {
|
||||
g_eeprom_last_error = EEPROM_ERR_WR_ADDR_TBE_TIMEOUT;
|
||||
i2c_bus_reset();
|
||||
eeprom_unlock();
|
||||
return I2C_FAIL;
|
||||
}
|
||||
|
||||
/* send memory address bytes to validate addressing scheme */
|
||||
#if (EEPROM_MEM_ADDR_16BIT == 1U)
|
||||
i2c_data_transmit(I2CX, (uint8_t)((mem_address >> 8U) & 0xFFU));
|
||||
timeout = 0U;
|
||||
while((!i2c_flag_get(I2CX, I2C_FLAG_TBE)) && (timeout < I2C_TIME_OUT)) {
|
||||
if(eeprom_i2c_error_pending()) {
|
||||
i2c_stop_on_bus(I2CX);
|
||||
i2c_bus_reset();
|
||||
eeprom_unlock();
|
||||
return I2C_FAIL;
|
||||
}
|
||||
timeout++;
|
||||
}
|
||||
if(timeout >= I2C_TIME_OUT) {
|
||||
g_eeprom_last_error = EEPROM_ERR_WR_ADDR_TBE_TIMEOUT;
|
||||
i2c_bus_reset();
|
||||
eeprom_unlock();
|
||||
return I2C_FAIL;
|
||||
}
|
||||
#endif
|
||||
i2c_data_transmit(I2CX, (uint8_t)(mem_address & 0xFFU));
|
||||
timeout = 0U;
|
||||
while((!i2c_flag_get(I2CX, I2C_FLAG_TC)) && (timeout < I2C_TIME_OUT)) {
|
||||
if(eeprom_i2c_error_pending()) {
|
||||
i2c_stop_on_bus(I2CX);
|
||||
i2c_bus_reset();
|
||||
eeprom_unlock();
|
||||
return I2C_FAIL;
|
||||
}
|
||||
timeout++;
|
||||
}
|
||||
if(timeout >= I2C_TIME_OUT) {
|
||||
g_eeprom_last_error = EEPROM_ERR_WR_DATA_TBE_TIMEOUT;
|
||||
i2c_bus_reset();
|
||||
eeprom_unlock();
|
||||
return I2C_FAIL;
|
||||
}
|
||||
|
||||
i2c_stop_on_bus(I2CX);
|
||||
timeout = 0U;
|
||||
while((!i2c_flag_get(I2CX, I2C_FLAG_STPDET)) && (timeout < I2C_TIME_OUT)) {
|
||||
timeout++;
|
||||
}
|
||||
if(timeout >= I2C_TIME_OUT) {
|
||||
g_eeprom_last_error = EEPROM_ERR_WR_STOP_TIMEOUT;
|
||||
i2c_bus_reset();
|
||||
eeprom_unlock();
|
||||
return I2C_FAIL;
|
||||
}
|
||||
i2c_flag_clear(I2CX, I2C_FLAG_STPDET);
|
||||
g_eeprom_last_error = EEPROM_ERR_NONE;
|
||||
eeprom_unlock();
|
||||
return I2C_OK;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief unified init entry for EEPROM driver
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void eeprom_driver_init(void)
|
||||
{
|
||||
gpio_config();
|
||||
i2c_config();
|
||||
i2c_eeprom_init();
|
||||
if (g_eeprom_mutex == NULL) {
|
||||
g_eeprom_mutex = xSemaphoreCreateMutex();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief initialize peripherals used by the I2C EEPROM driver
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void i2c_eeprom_init(void)
|
||||
{
|
||||
eeprom_address = EEPROM_BLOCK0_ADDRESS;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief write buffer of data to the I2C EEPROM
|
||||
\param[in] p_buffer: pointer to the buffer containing the data to be written to the EEPROM
|
||||
\param[in] write_address: EEPROM's internal address to write to
|
||||
\param[in] number_of_byte: number of bytes to write to the EEPROM
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void eeprom_buffer_write(uint8_t *p_buffer, uint16_t write_address, uint16_t number_of_byte)
|
||||
{
|
||||
uint16_t remain;
|
||||
uint16_t off;
|
||||
uint8_t chunk;
|
||||
uint8_t page_left;
|
||||
uint8_t retry;
|
||||
if ((p_buffer == NULL) || (number_of_byte == 0U)) {
|
||||
g_eeprom_last_error = EEPROM_ERR_NONE;
|
||||
return;
|
||||
}
|
||||
eeprom_lock();
|
||||
g_eeprom_last_error = EEPROM_ERR_NONE;
|
||||
|
||||
remain = number_of_byte;
|
||||
off = 0U;
|
||||
while (remain > 0U) {
|
||||
/* Do not cross page boundary (AT24/FRAM compatible safe strategy). */
|
||||
page_left = (uint8_t)(I2C_PAGE_SIZE - (((uint16_t)(write_address + off)) % I2C_PAGE_SIZE));
|
||||
if (page_left == 0U) {
|
||||
page_left = I2C_PAGE_SIZE;
|
||||
}
|
||||
chunk = (remain > (uint16_t)page_left) ? page_left : (uint8_t)remain;
|
||||
if (chunk > I2C_PAGE_SIZE) {
|
||||
chunk = I2C_PAGE_SIZE;
|
||||
}
|
||||
|
||||
retry = 0U;
|
||||
while (retry < 3U) {
|
||||
eeprom_page_write(&p_buffer[off], (uint16_t)(write_address + off), chunk);
|
||||
if (g_eeprom_last_error == EEPROM_ERR_NONE) {
|
||||
break;
|
||||
}
|
||||
/* retry after simple bus recovery */
|
||||
i2c_bus_reset();
|
||||
vTaskDelay(pdMS_TO_TICKS(1U));
|
||||
retry++;
|
||||
}
|
||||
if (g_eeprom_last_error != EEPROM_ERR_NONE) {
|
||||
eeprom_unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
off = (uint16_t)(off + (uint16_t)chunk);
|
||||
remain = (uint16_t)(remain - (uint16_t)chunk);
|
||||
vTaskDelay(pdMS_TO_TICKS(EEPROM_WRITE_DELAY_MS));
|
||||
}
|
||||
eeprom_unlock();
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief write more than one byte to the EEPROM with a single write cycle
|
||||
\param[in] p_buffer: pointer to the buffer containing the data to be written to the EEPROM
|
||||
\param[in] write_address: EEPROM's internal address to write to
|
||||
\param[in] number_of_byte: number of bytes to write to the EEPROM
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
static void eeprom_page_write(uint8_t *p_buffer, uint16_t write_address, uint8_t number_of_byte)
|
||||
{
|
||||
uint32_t timeout = 0U;
|
||||
uint8_t bytes_sent = 0;
|
||||
uint8_t mem_high_addr = (uint8_t)((write_address >> 8U) & 0xFFU);
|
||||
uint8_t mem_low_addr = (uint8_t)(write_address & 0xFFU);
|
||||
|
||||
if ((p_buffer == NULL) || (number_of_byte == 0U)) {
|
||||
return;
|
||||
}
|
||||
|
||||
eeprom_address = eeprom_make_dev_addr(write_address);
|
||||
eeprom_i2c_clear_error_flags();
|
||||
i2c_flag_clear(I2CX, I2C_FLAG_STPDET);
|
||||
while(i2c_flag_get(I2CX, I2C_FLAG_I2CBSY) && (timeout < I2C_TIME_OUT)) {
|
||||
timeout++;
|
||||
}
|
||||
if(timeout >= I2C_TIME_OUT) {
|
||||
g_eeprom_last_error = EEPROM_ERR_WR_BUSY_TIMEOUT;
|
||||
i2c_bus_reset();
|
||||
return;
|
||||
}
|
||||
|
||||
i2c_master_addressing(I2CX, eeprom_address, I2C_MASTER_TRANSMIT);
|
||||
i2c_transfer_byte_number_config(I2CX,
|
||||
#if (EEPROM_MEM_ADDR_16BIT == 1U)
|
||||
(uint32_t)number_of_byte + 2U
|
||||
#else
|
||||
(uint32_t)number_of_byte + 1U
|
||||
#endif
|
||||
);
|
||||
/* Use explicit TC->STOP sequence to avoid partial writes */
|
||||
i2c_automatic_end_disable(I2CX);
|
||||
i2c_reload_disable(I2CX);
|
||||
i2c_start_on_bus(I2CX);
|
||||
|
||||
timeout = 0U;
|
||||
while((!i2c_flag_get(I2CX, I2C_FLAG_TBE)) && (timeout < I2C_TIME_OUT)) {
|
||||
if(eeprom_i2c_error_pending()) {
|
||||
i2c_bus_reset();
|
||||
return;
|
||||
}
|
||||
timeout++;
|
||||
}
|
||||
if(timeout >= I2C_TIME_OUT) {
|
||||
g_eeprom_last_error = EEPROM_ERR_WR_ADDR_TBE_TIMEOUT;
|
||||
i2c_bus_reset();
|
||||
return;
|
||||
}
|
||||
#if (EEPROM_MEM_ADDR_16BIT == 1U)
|
||||
i2c_data_transmit(I2CX, mem_high_addr);
|
||||
timeout = 0U;
|
||||
while((!i2c_flag_get(I2CX, I2C_FLAG_TBE)) && (timeout < I2C_TIME_OUT)) {
|
||||
if(eeprom_i2c_error_pending()) {
|
||||
i2c_bus_reset();
|
||||
return;
|
||||
}
|
||||
timeout++;
|
||||
}
|
||||
if(timeout >= I2C_TIME_OUT) {
|
||||
g_eeprom_last_error = EEPROM_ERR_WR_ADDR_TBE_TIMEOUT;
|
||||
i2c_bus_reset();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
i2c_data_transmit(I2CX, mem_low_addr);
|
||||
|
||||
/* wait address byte(s) accepted before data */
|
||||
timeout = 0U;
|
||||
while((!i2c_flag_get(I2CX, I2C_FLAG_TBE)) && (timeout < I2C_TIME_OUT)) {
|
||||
if(eeprom_i2c_error_pending()) {
|
||||
i2c_bus_reset();
|
||||
return;
|
||||
}
|
||||
timeout++;
|
||||
}
|
||||
if(timeout >= I2C_TIME_OUT) {
|
||||
g_eeprom_last_error = EEPROM_ERR_WR_ADDR_TBE_TIMEOUT;
|
||||
i2c_bus_reset();
|
||||
return;
|
||||
}
|
||||
|
||||
while(bytes_sent < number_of_byte) {
|
||||
timeout = 0U;
|
||||
while((!i2c_flag_get(I2CX, I2C_FLAG_TBE)) && (timeout < I2C_TIME_OUT)) {
|
||||
if(eeprom_i2c_error_pending()) {
|
||||
i2c_bus_reset();
|
||||
return;
|
||||
}
|
||||
timeout++;
|
||||
}
|
||||
if(timeout >= I2C_TIME_OUT) {
|
||||
g_eeprom_last_error = EEPROM_ERR_WR_DATA_TBE_TIMEOUT;
|
||||
i2c_bus_reset();
|
||||
return;
|
||||
}
|
||||
i2c_data_transmit(I2CX, *p_buffer);
|
||||
p_buffer++;
|
||||
bytes_sent++;
|
||||
}
|
||||
|
||||
/* wait transfer complete then send stop */
|
||||
timeout = 0U;
|
||||
while((!i2c_flag_get(I2CX, I2C_FLAG_TC)) && (timeout < I2C_TIME_OUT)) {
|
||||
if(eeprom_i2c_error_pending()) {
|
||||
i2c_bus_reset();
|
||||
return;
|
||||
}
|
||||
timeout++;
|
||||
}
|
||||
if(timeout >= I2C_TIME_OUT) {
|
||||
g_eeprom_last_error = EEPROM_ERR_WR_DATA_TBE_TIMEOUT;
|
||||
i2c_bus_reset();
|
||||
return;
|
||||
}
|
||||
i2c_stop_on_bus(I2CX);
|
||||
|
||||
timeout = 0U;
|
||||
while((!i2c_flag_get(I2CX, I2C_FLAG_STPDET)) && (timeout < I2C_TIME_OUT)) {
|
||||
if(eeprom_i2c_error_pending()) {
|
||||
i2c_bus_reset();
|
||||
return;
|
||||
}
|
||||
timeout++;
|
||||
}
|
||||
if(timeout >= I2C_TIME_OUT) {
|
||||
g_eeprom_last_error = EEPROM_ERR_WR_STOP_TIMEOUT;
|
||||
i2c_bus_reset();
|
||||
return;
|
||||
}
|
||||
i2c_flag_clear(I2CX, I2C_FLAG_STPDET);
|
||||
}
|
||||
|
||||
static uint8_t eeprom_read_chunk(uint8_t *p_buffer, uint16_t read_address, uint8_t number_of_byte)
|
||||
{
|
||||
uint32_t timeout = 0U;
|
||||
uint8_t mem_high_addr = (uint8_t)((read_address >> 8U) & 0xFFU);
|
||||
uint8_t mem_low_addr = (uint8_t)(read_address & 0xFFU);
|
||||
uint8_t dev_addr = eeprom_make_dev_addr(read_address);
|
||||
uint8_t i = 0U;
|
||||
|
||||
if ((p_buffer == NULL) || (number_of_byte == 0U)) {
|
||||
return I2C_FAIL;
|
||||
}
|
||||
|
||||
eeprom_i2c_clear_error_flags();
|
||||
|
||||
while(i2c_flag_get(I2CX, I2C_FLAG_I2CBSY) && (timeout < I2C_TIME_OUT)) {
|
||||
timeout++;
|
||||
}
|
||||
if(timeout >= I2C_TIME_OUT) {
|
||||
g_eeprom_last_error = EEPROM_ERR_RD_BUSY_TIMEOUT;
|
||||
i2c_bus_reset();
|
||||
return I2C_FAIL;
|
||||
}
|
||||
|
||||
/* phase 1: set memory low address */
|
||||
i2c_master_addressing(I2CX, dev_addr, I2C_MASTER_TRANSMIT);
|
||||
i2c_transfer_byte_number_config(I2CX,
|
||||
#if (EEPROM_MEM_ADDR_16BIT == 1U)
|
||||
2U
|
||||
#else
|
||||
1U
|
||||
#endif
|
||||
);
|
||||
i2c_automatic_end_disable(I2CX);
|
||||
i2c_start_on_bus(I2CX);
|
||||
|
||||
timeout = 0U;
|
||||
while((!i2c_flag_get(I2CX, I2C_FLAG_TBE)) && (timeout < I2C_TIME_OUT)) {
|
||||
if(eeprom_i2c_error_pending()) {
|
||||
i2c_bus_reset();
|
||||
return I2C_FAIL;
|
||||
}
|
||||
timeout++;
|
||||
}
|
||||
if(timeout >= I2C_TIME_OUT) {
|
||||
g_eeprom_last_error = EEPROM_ERR_RD_ADDR_TBE_TIMEOUT;
|
||||
i2c_bus_reset();
|
||||
return I2C_FAIL;
|
||||
}
|
||||
#if (EEPROM_MEM_ADDR_16BIT == 1U)
|
||||
i2c_data_transmit(I2CX, mem_high_addr);
|
||||
timeout = 0U;
|
||||
while((!i2c_flag_get(I2CX, I2C_FLAG_TBE)) && (timeout < I2C_TIME_OUT)) {
|
||||
if(eeprom_i2c_error_pending()) {
|
||||
i2c_bus_reset();
|
||||
return I2C_FAIL;
|
||||
}
|
||||
timeout++;
|
||||
}
|
||||
if(timeout >= I2C_TIME_OUT) {
|
||||
g_eeprom_last_error = EEPROM_ERR_RD_ADDR_TBE_TIMEOUT;
|
||||
i2c_bus_reset();
|
||||
return I2C_FAIL;
|
||||
}
|
||||
#endif
|
||||
i2c_data_transmit(I2CX, mem_low_addr);
|
||||
|
||||
timeout = 0U;
|
||||
while((!i2c_flag_get(I2CX, I2C_FLAG_TC)) && (timeout < I2C_TIME_OUT)) {
|
||||
if(eeprom_i2c_error_pending()) {
|
||||
i2c_bus_reset();
|
||||
return I2C_FAIL;
|
||||
}
|
||||
timeout++;
|
||||
}
|
||||
if(timeout >= I2C_TIME_OUT) {
|
||||
g_eeprom_last_error = EEPROM_ERR_RD_RESTART_TC_TIMEOUT;
|
||||
i2c_bus_reset();
|
||||
return I2C_FAIL;
|
||||
}
|
||||
|
||||
/* phase 2: repeated start + read bytes */
|
||||
i2c_master_addressing(I2CX, dev_addr, I2C_MASTER_RECEIVE);
|
||||
i2c_transfer_byte_number_config(I2CX, number_of_byte);
|
||||
i2c_automatic_end_enable(I2CX);
|
||||
i2c_start_on_bus(I2CX);
|
||||
|
||||
for(i = 0U; i < number_of_byte; i++) {
|
||||
timeout = 0U;
|
||||
while((!i2c_flag_get(I2CX, I2C_FLAG_RBNE)) && (timeout < I2C_TIME_OUT)) {
|
||||
if(eeprom_i2c_error_pending()) {
|
||||
i2c_bus_reset();
|
||||
return I2C_FAIL;
|
||||
}
|
||||
timeout++;
|
||||
}
|
||||
if(timeout >= I2C_TIME_OUT) {
|
||||
g_eeprom_last_error = EEPROM_ERR_RD_DATA_RBNE_TIMEOUT;
|
||||
i2c_bus_reset();
|
||||
return I2C_FAIL;
|
||||
}
|
||||
p_buffer[i] = (uint8_t)i2c_data_receive(I2CX);
|
||||
}
|
||||
|
||||
timeout = 0U;
|
||||
while((!i2c_flag_get(I2CX, I2C_FLAG_STPDET)) && (timeout < I2C_TIME_OUT)) {
|
||||
if(eeprom_i2c_error_pending()) {
|
||||
i2c_bus_reset();
|
||||
return I2C_FAIL;
|
||||
}
|
||||
timeout++;
|
||||
}
|
||||
if(timeout >= I2C_TIME_OUT) {
|
||||
g_eeprom_last_error = EEPROM_ERR_RD_STOP_TIMEOUT;
|
||||
i2c_bus_reset();
|
||||
return I2C_FAIL;
|
||||
}
|
||||
i2c_flag_clear(I2CX, I2C_FLAG_STPDET);
|
||||
return I2C_OK;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief read data from the EEPROM
|
||||
\param[in] p_buffer: pointer to the buffer that receives the data read from the EEPROM
|
||||
\param[in] read_address: EEPROM's internal address to start reading from
|
||||
\param[in] number_of_byte: number of bytes to reads from the EEPROM
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void eeprom_buffer_read(uint8_t *p_buffer, uint16_t read_address, uint16_t number_of_byte)
|
||||
{
|
||||
uint16_t remain;
|
||||
uint16_t off;
|
||||
uint8_t chunk;
|
||||
uint8_t retry;
|
||||
|
||||
if ((p_buffer == NULL) || (number_of_byte == 0U)) {
|
||||
g_eeprom_last_error = EEPROM_ERR_NONE;
|
||||
return;
|
||||
}
|
||||
eeprom_lock();
|
||||
g_eeprom_last_error = EEPROM_ERR_NONE;
|
||||
|
||||
remain = number_of_byte;
|
||||
off = 0U;
|
||||
while (remain > 0U) {
|
||||
/* For read, allow larger chunk but keep it reasonable */
|
||||
chunk = (remain > 128U) ? 128U : (uint8_t)remain;
|
||||
|
||||
retry = 0U;
|
||||
while (retry < 3U) {
|
||||
if (eeprom_read_chunk(&p_buffer[off], (uint16_t)(read_address + off), chunk) == I2C_OK) {
|
||||
break;
|
||||
}
|
||||
i2c_bus_reset();
|
||||
vTaskDelay(pdMS_TO_TICKS(1U));
|
||||
retry++;
|
||||
}
|
||||
if (g_eeprom_last_error != EEPROM_ERR_NONE) {
|
||||
eeprom_unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
off = (uint16_t)(off + (uint16_t)chunk);
|
||||
remain = (uint16_t)(remain - (uint16_t)chunk);
|
||||
vTaskDelay(pdMS_TO_TICKS(1U));
|
||||
}
|
||||
eeprom_unlock();
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
/*!
|
||||
\file fm24cl16.h
|
||||
\brief the header file of AT24Cxx
|
||||
|
||||
\version 2025-01-24, V1.4.0, firmware for GD32H7xx
|
||||
*/
|
||||
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef FM24CL16_H
|
||||
#define FM24CL16_H
|
||||
|
||||
#include "gd32h7xx_it.h"
|
||||
|
||||
typedef enum {
|
||||
I2C_START = 0,
|
||||
I2C_SEND_ADDRESS,
|
||||
I2C_RESTART,
|
||||
I2C_TRANSMIT_DATA,
|
||||
I2C_RELOAD,
|
||||
I2C_STOP,
|
||||
I2C_END
|
||||
} i2c_process_enum;
|
||||
|
||||
#define I2C_TIME_OUT (uint32_t)(20000)
|
||||
#define EEP_FIRST_PAGE 0x00
|
||||
#define I2C_OK 0
|
||||
#define I2C_FAIL 1
|
||||
|
||||
/* FM24xx logical capacity/address map */
|
||||
#define FRAM_SIZE_KBIT (16U)
|
||||
#define FRAM_SIZE_BYTES (2048U)
|
||||
#define FRAM_ADDR_BITS (11U)
|
||||
|
||||
#define FRAM_START_ADDR (0x0000U)
|
||||
#define FRAM_END_ADDR (0x07FFU)
|
||||
#define FRAM_TOTAL_ADDR (0x0800U)
|
||||
|
||||
#define FRAM_PAGE_SIZE (256U)
|
||||
#define FRAM_PAGES_COUNT (8U)
|
||||
|
||||
/* Logical partitions (ported from CCU601E_D) */
|
||||
#define EEPROM_ADDR_CHGRCD_MNG (0x0000U) /* charge record manager */
|
||||
#define EEPROM_ADDR_HISALARM_MNG (0x0020U) /* history alarm manager */
|
||||
#define EEPROM_ADDR_UNSETTLED_MNG (0x0040U) /* unsettled order manager */
|
||||
#define EEPROM_ADDR_CARD_MNG (0x00A0U) /* card whitelist manager */
|
||||
#define EEPROM_ADDR_A_LOG_DATA (0x0100U) /* gun A temporary order data */
|
||||
#define EEPROM_ADDR_B_LOG_DATA (0x0400U) /* gun B temporary order data */
|
||||
#define EEPROM_ADDR_OCPP_MV_OFFLINE_CTRL 0x0700U
|
||||
#define EEPROM_OCPP_MV_OFFLINE_CTRL_SIZE 128u
|
||||
#define EEPROM_ADDR_OCPP_FW_INSTALLED_PENDING 0x0780U
|
||||
#define EEPROM_OCPP_FW_INSTALLED_PENDING_VAL 0x55U
|
||||
#define EEPROM_OCPP_FW_INSTALLED_PENDING_CLEAR 0x00U
|
||||
|
||||
#define EEPROM_ADDR_IN_RANGE(addr) ((uint16_t)(addr) <= (uint16_t)FRAM_END_ADDR)
|
||||
|
||||
/* function declarations */
|
||||
/* unified EEPROM init: GPIO + I2C + device address */
|
||||
void eeprom_driver_init(void);
|
||||
/* initialize peripherals used by the I2C EEPROM driver */
|
||||
void i2c_eeprom_init(void);
|
||||
/* write buffer of data to the I2C EEPROM */
|
||||
void eeprom_buffer_write(uint8_t *p_buffer, uint16_t write_address, uint16_t number_of_byte);
|
||||
/* read data from the EEPROM */
|
||||
void eeprom_buffer_read(uint8_t *p_buffer, uint16_t read_address, uint16_t number_of_byte);
|
||||
/* read latest driver error code (0 means no error) */
|
||||
uint32_t eeprom_get_last_error(void);
|
||||
/* probe one EEPROM block address and return I2C_OK/I2C_FAIL */
|
||||
uint8_t eeprom_probe(uint16_t mem_address);
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* Compatibility layer for migrated modules from CCU601E_D
|
||||
* - old API: eeprom_write/eeprom_read(...) returns HAL_OK on success
|
||||
* - local API: eeprom_buffer_write/eeprom_buffer_read(...) with error queried
|
||||
* -------------------------------------------------------------------------- */
|
||||
#ifndef HAL_OK
|
||||
#define HAL_OK (0)
|
||||
#endif
|
||||
#ifndef HAL_ERROR
|
||||
#define HAL_ERROR (1)
|
||||
#endif
|
||||
|
||||
static inline int eeprom_write(uint16_t addr, uint8_t *buf, uint16_t len)
|
||||
{
|
||||
eeprom_buffer_write(buf, addr, len);
|
||||
return (eeprom_get_last_error() == 0U) ? HAL_OK : HAL_ERROR;
|
||||
}
|
||||
|
||||
static inline int eeprom_read(uint16_t addr, uint8_t *buf, uint16_t len)
|
||||
{
|
||||
eeprom_buffer_read(buf, addr, len);
|
||||
return (eeprom_get_last_error() == 0U) ? HAL_OK : HAL_ERROR;
|
||||
}
|
||||
|
||||
#endif /* AT24CXX_H */
|
||||
@@ -0,0 +1,128 @@
|
||||
/*!
|
||||
\file i2c.c
|
||||
\brief I2C configuration file
|
||||
|
||||
\version 2025-01-24, V1.4.0, firmware for GD32H7xx
|
||||
*/
|
||||
|
||||
/*
|
||||
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 "i2c1.h"
|
||||
#include <stdio.h>
|
||||
#include "gd32h7xx.h"
|
||||
/*!
|
||||
\brief configure the GPIO ports
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void gpio_config(void)
|
||||
{
|
||||
/* enable GPIO clock */
|
||||
rcu_periph_clock_enable(RCU_GPIO_I2C);
|
||||
|
||||
/* enable I2C clock */
|
||||
rcu_periph_clock_enable(RCU_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_60MHZ, 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_60MHZ, I2C_SDA_PIN);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief configure the I2C interface
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void i2c_config(void)
|
||||
{
|
||||
/* configure I2C timing */
|
||||
i2c_timing_config(I2CX, 0x3, 0x7, 0);
|
||||
i2c_master_clock_config(I2CX, 0x32, 0x32);
|
||||
/* enable analog filter and disable digital filter for bus robustness */
|
||||
i2c_analog_noise_filter_enable(I2CX);
|
||||
i2c_digital_noise_filter_config(I2CX, FILTER_DISABLE);
|
||||
/* enable I2C */
|
||||
i2c_enable(I2CX);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief reset I2C gpio configure
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void i2c_gpio_reset(void)
|
||||
{
|
||||
/* reset I2C_SCL_PIN and I2C_SDA_PIN */
|
||||
gpio_mode_set(I2C_SCL_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, I2C_SCL_PIN);
|
||||
gpio_output_options_set(I2C_SCL_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, I2C_SCL_PIN);
|
||||
gpio_mode_set(I2C_SDA_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, I2C_SDA_PIN);
|
||||
gpio_output_options_set(I2C_SDA_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, I2C_SDA_PIN);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief reset i2c bus
|
||||
\param[in] none
|
||||
\param[out] none
|
||||
\retval none
|
||||
*/
|
||||
void i2c_bus_reset()
|
||||
{
|
||||
/* configure SDA/SCL for GPIO */
|
||||
GPIO_BC(I2C_SCL_PORT) |= I2C_SCL_PIN;
|
||||
GPIO_BC(I2C_SDA_PORT) |= I2C_SDA_PIN;
|
||||
/* reset I2C_SCL_PIN and I2C_SDA_PIN */
|
||||
i2c_gpio_reset();
|
||||
__NOP();
|
||||
__NOP();
|
||||
__NOP();
|
||||
__NOP();
|
||||
__NOP();
|
||||
/* stop signal */
|
||||
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_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_60MHZ, 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_60MHZ, I2C_SDA_PIN);
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*!
|
||||
\file i2c.h
|
||||
\brief the header file of I2C
|
||||
|
||||
\version 2025-01-24, V1.4.0, firmware for GD32H7xx
|
||||
*/
|
||||
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef I2C_H
|
||||
#define I2C_H
|
||||
|
||||
|
||||
#define I2C_SPEED 400000
|
||||
#define I2C_PAGE_SIZE 8
|
||||
#define I2CX I2C1
|
||||
#define RCU_GPIO_I2C RCU_GPIOF
|
||||
#define RCU_I2C RCU_I2C1
|
||||
#define I2C_SCL_PORT GPIOF
|
||||
#define I2C_SDA_PORT GPIOF
|
||||
#define I2C_SCL_PIN GPIO_PIN_1
|
||||
#define I2C_SDA_PIN GPIO_PIN_0
|
||||
#define I2C_GPIO_AF GPIO_AF_4
|
||||
|
||||
/* function declarations */
|
||||
/* configure the GPIO ports */
|
||||
void gpio_config(void);
|
||||
/* configure the I2C interface */
|
||||
void i2c_config(void);
|
||||
/* reset I2C gpio configure */
|
||||
void i2c_gpio_reset(void);
|
||||
/* reset i2c bus */
|
||||
void i2c_bus_reset(void);
|
||||
|
||||
#endif /* I2C_H */
|
||||
Reference in New Issue
Block a user