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,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();
|
||||
}
|
||||
Reference in New Issue
Block a user