[开发板与模块]

【ESK32-30519 + ESK32-21001测评】03.I2C+EEPROM & SPI+SPI FLASH

[复制链接]
263|4
手机看帖
扫描二维码
随时随地手机跟帖
xld0932|  楼主 | 2022-10-10 17:26 | 显示全部楼层 |阅读模式
本帖最后由 xld0932 于 2022-10-10 17:30 编辑

HT32F54253 MCU带有3个硬件I2C接口和2个硬件SPI接口,具体的特性如下所示:

内部集成电路——I2C
支持高达 1 MHz 频率的主从模式
提供仲裁功能和时钟同步功能
支持 7-bit 10-bit 寻址模式和广播呼叫寻址
可屏蔽地址功能支持多种从机寻址模式
I2C 模块是一个允许与外部 I2C 接口通信的内部电路,此外部 I2C 接口是一个符合工业标准的用于连接外部硬件的两线串行接口。这两条串行线被称为串行数据线 SDA 和串行时钟线 SCLI2C
模块提供三种数据传输速率:即标准模式下的 100 kHz、快速模式下的 400 kHz 和高速模式下的1 MHzSCL 周期产生寄存器用于设置不同的占空比得到不同的 SCL 脉冲。
SDA 线是一条双向数据线,它连接整个 I2C 总线,在主机和从机之间用于数据的发送和接收。 I2C模块还具有仲裁检测功能和时钟同步,可防止多个主机试图同时传送数据到 I2C 总线的情况。

串行外设接口——SPI
支持主机和从机模式
主机模式频率高达 (fPCLK/2) MHz,从机模式频率高达 (fPCLK/3) MHz
▆ FIFO 深度: 8
多个主机和多个从机工作模式
串行外设接口
SPI 使用 SPI 协议可在主机和从机模式下进行数据发送和接收。 SPI 接口使用 4 个引脚,其中有串行数据输入和输出线, MISO MOSI,时钟线 SCK 和从机选择线 SELSPI 作为主机使用,用 SEL SCK 信号控制数据流来说明数据通信启动和数据采样率。要接收数据字节,数据流在特定的时钟边沿时被锁存且存储在数据寄存器或 RX FIFO。数据发送也是通过类似的方式,但以相反的顺序。模式故障检测功能使其适用于多主机应用。


原理图
  • ESK32-30519
5.png
  • ESK32-21001
6.png


实现功能
通过硬件I2C读写扩展板板载的EEPROM芯片,写入随机数据后再进行回读,比较写入数据和读出数据是否相一致;通过硬件SPI操作扩展板板载的SPI FLASH芯片,移植SFUD软件包组件实现对SPI FLASH的读、写、擦除等操作。


实现代码
  • EEPROM
/* Define to prevent recursive inclusion -------------------------------------*/
#define __EEPROM_C__


/* Includes ------------------------------------------------------------------*/
#include "EEPROM.h"


/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/


/* Exported variables --------------------------------------------------------*/
/* Exported function prototypes ----------------------------------------------*/


/*******************************************************************************
* [url=home.php?mod=space&uid=247401]@brief[/url]      
* @param      
* @retval      
* [url=home.php?mod=space&uid=93590]@Attention[/url]   
*******************************************************************************/
void _I2C_EEPROM_AckPolling(void)
{
    uint32_t reg;

    /* wait if bus busy */
    while(I2C_GetFlagStatus(HT_I2C1, I2C_FLAG_BUSBUSY));

    while(1)
    {
        /* send slave address */
        I2C_TargetAddressConfig(HT_I2C1, I2C_EEPROM_DEV_ADDR, I2C_MASTER_WRITE);

        /* check status */
        while(1)
        {
            reg = HT_I2C1->SR;

            if(reg & I2C_FLAG_ADRS)
            {
                return;
            }

            if(reg & I2C_FLAG_RXNACK)
            {
                I2C_ClearFlag(HT_I2C1, I2C_FLAG_RXNACK);
                break;
            }
        }
    }
}


/*******************************************************************************
* [url=home.php?mod=space&uid=247401]@brief[/url]      
* @param      
* @retval      
* [url=home.php?mod=space&uid=93590]@Attention[/url]   
*******************************************************************************/
void I2C_EEPROM_BufferRead(uint8_t* pBuffer, uint8_t ReadAddr, uint16_t NumByteToRead)
{
    /* check parameters */
    Assert_Param(NumByteToRead > 0);

    /* acknowledge polling */
    _I2C_EEPROM_AckPolling();

    /* set EEPROM address */
    while (!I2C_CheckStatus(HT_I2C1, I2C_MASTER_TX_EMPTY));
    I2C_SendData(HT_I2C1, ReadAddr);

    /* send read command */
    I2C_TargetAddressConfig(HT_I2C1, I2C_EEPROM_DEV_ADDR, I2C_MASTER_READ);
    while(!I2C_CheckStatus( HT_I2C1, I2C_MASTER_SEND_START));
    while(!I2C_CheckStatus( HT_I2C1, I2C_MASTER_RECEIVER_MODE));

    /* enable master receiver ACK */
    if(NumByteToRead > 1)
    {
        I2C_AckCmd(HT_I2C1, ENABLE);
    }

    /* sequential read */
    while(NumByteToRead)
    {
        while(!I2C_CheckStatus(HT_I2C1, I2C_MASTER_RX_NOT_EMPTY));

        *pBuffer++ = I2C_ReceiveData(HT_I2C1);

        if(--NumByteToRead == 1)
        {
            I2C_AckCmd(HT_I2C1, DISABLE);
        }
    }

    /* end of read */
    I2C_GenerateSTOP(HT_I2C1);
}


/*******************************************************************************
* @brief      
* @param      
* @retval      
* @attention   
*******************************************************************************/
void I2C_EEPROM_PageWrite(uint8_t* pBuffer, uint8_t WriteAddr, uint16_t NumByteToWrite)
{
    /* check parameters */
    Assert_Param((NumByteToWrite > 0) &&
                ((NumByteToWrite <= (I2C_EEPROM_PAGE_SIZE - (WriteAddr & I2C_EEPROM_PAGE_MASK)))));

    /* acknowledge polling */
    _I2C_EEPROM_AckPolling();

    /* set EEPROM address */
    while(!I2C_CheckStatus(HT_I2C1, I2C_MASTER_TX_EMPTY));
    I2C_SendData(HT_I2C1, WriteAddr);

    /* page write */
    while(NumByteToWrite--)
    {
        while(!I2C_CheckStatus(HT_I2C1, I2C_MASTER_TX_EMPTY));
        I2C_SendData(HT_I2C1, *pBuffer++);
    }

    /* end of write */
    while(!I2C_CheckStatus(HT_I2C1, I2C_MASTER_TX_EMPTY));
    I2C_GenerateSTOP(HT_I2C1);
}


/*******************************************************************************
* @brief      
* @param      
* @retval      
* @attention   
*******************************************************************************/
void I2C_EEPROM_BufferWrite(uint8_t* pBuffer, uint8_t WriteAddr, uint16_t NumByteToWrite)
{
    uint16_t Byte2Wr, AvailableByte;

    /* check parameters */
    Assert_Param(NumByteToWrite <= I2C_EEPROM_CAPACITY);

    /* sequential write */
    while (NumByteToWrite)
    {
        AvailableByte = I2C_EEPROM_PAGE_SIZE - (WriteAddr & I2C_EEPROM_PAGE_MASK);
        Byte2Wr       = (NumByteToWrite > AvailableByte)?(AvailableByte):(NumByteToWrite);

        I2C_EEPROM_PageWrite(pBuffer, WriteAddr, Byte2Wr);

        pBuffer        += Byte2Wr;
        WriteAddr       = (WriteAddr + Byte2Wr) & I2C_EEPROM_ADDR_MASK;
        NumByteToWrite -= Byte2Wr;
    }
}


/*******************************************************************************
* @brief      
* @param      
* @retval      
* @attention   
*******************************************************************************/
void EEPROM_Init(void)
{
    I2C_InitTypeDef I2C_InitStructure;

    CKCU_PeripClockConfig_TypeDef CKCUClock = {{0}};
    CKCUClock.Bit.PB   = 1;
    CKCUClock.Bit.PC   = 1;
    CKCUClock.Bit.I2C1 = 1;
    CKCUClock.Bit.AFIO = 1;
    CKCU_PeripClockConfig(CKCUClock, ENABLE);

    AFIO_GPxConfig(GPIO_PB, AFIO_PIN_15, AFIO_FUN_I2C);
    AFIO_GPxConfig(GPIO_PC, AFIO_PIN_0,  AFIO_FUN_I2C);

    I2C_InitStructure.I2C_GeneralCall    = I2C_GENERALCALL_DISABLE;
    I2C_InitStructure.I2C_AddressingMode = I2C_ADDRESSING_7BIT;
    I2C_InitStructure.I2C_Acknowledge    = I2C_ACK_DISABLE;
    I2C_InitStructure.I2C_OwnAddress     = 0x00;
    I2C_InitStructure.I2C_Speed          = 400000;  //---400k
    I2C_InitStructure.I2C_SpeedOffset    = 0;
    I2C_Init(HT_I2C1, &I2C_InitStructure);

    I2C_Cmd(HT_I2C1, ENABLE);
}


/*******************************************************************************
* @brief      
* @param      
* @retval      
* @attention   
*******************************************************************************/
void EEPROM_Demo(void)
{
    uint8_t wBuffer[I2C_EEPROM_PAGE_SIZE];
    uint8_t rBuffer[I2C_EEPROM_PAGE_SIZE];

    for(uint32_t j = 0; j < (I2C_EEPROM_CAPACITY / I2C_EEPROM_PAGE_SIZE); j++)
    {
        memset(rBuffer, 0, sizeof(rBuffer));
        memset(wBuffer, 0, sizeof(wBuffer));

        for(uint32_t i = 0; i < I2C_EEPROM_PAGE_SIZE; i++)
        {
            wBuffer[i] = rand();
        }

        I2C_EEPROM_BufferWrite((uint8_t *)wBuffer, I2C_EEPROM_PAGE_SIZE * j, I2C_EEPROM_PAGE_SIZE);

        printf("\r\nEEPROM Write...[Page%d]", j+1);

        for(uint32_t i = 0; i < I2C_EEPROM_PAGE_SIZE; i++)
        {
            if((i % 10) == 0) printf("\r\n");
            printf("0x%02x ", wBuffer[i]);
        }

        I2C_EEPROM_BufferRead((uint8_t  *)rBuffer, I2C_EEPROM_PAGE_SIZE * j, I2C_EEPROM_PAGE_SIZE);

        printf("\r\nEEPROM Read....[Page%d]", j+1);

        for(uint32_t i = 0; i < I2C_EEPROM_PAGE_SIZE; i++)
        {
            if((i % 10) == 0) printf("\r\n");
            printf("0x%02x ", rBuffer[i]);
        }

        for(uint32_t i = 0; i < I2C_EEPROM_PAGE_SIZE; i++)
        {
            if(rBuffer[i] != wBuffer[i])
            {
                printf("\r\n\r\nEEPROM Read & Write Test Failed!!!"); while(1);
            }
        }

        printf("\t\tCompare Success : %d%%\r\n", (int)((j + 1) * 100) / (I2C_EEPROM_CAPACITY / I2C_EEPROM_PAGE_SIZE));
    }

    printf("\r\n\r\nEEPROM Read & Write Test Pass!!!");
}
  • SPI FLASH
/* Define to prevent recursive inclusion -------------------------------------*/
#define __SPI_FLASH_C__


/* Includes ------------------------------------------------------------------*/
#include "SPI_FLASH.h"
#include <sfud.h>


/* Private typedef -----------------------------------------------------------*/


/* Private define ------------------------------------------------------------*/
#define SFUD_DEMO_BUFFER_SIZE      (512)


/* Private macro -------------------------------------------------------------*/


/* Private variables ---------------------------------------------------------*/
uint8_t sfud_demo_buf[SFUD_DEMO_BUFFER_SIZE];


/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/


/* Exported variables --------------------------------------------------------*/
/* Exported function prototypes ----------------------------------------------*/


/*******************************************************************************
* @brief       SFUD demo for the first flash device test
* @param       addr flash start address
* @param       size test flash size
* @param       size test flash data buffer
* @retval      
* @attention   
*******************************************************************************/
void sfud_demo(uint32_t addr, size_t size, uint8_t *data)
{
    sfud_err result = SFUD_SUCCESS;

    const sfud_flash *flash = sfud_get_device_table() + 0;

    size_t i;

    /* prepare write data */
    for(i = 0; i < size; i++)
    {
        data[i] = i;
    }

    /* erase test */
    result = sfud_erase(flash, addr, size);

    if(result == SFUD_SUCCESS)
    {
        printf("\r\nErase the %s flash data finish. Start from 0x%08X, size is %d.\r\n", flash->name, addr, size);
    }
    else
    {
        printf("\r\nErase the %s flash data failed.\r\n", flash->name);
        return;
    }

    /* write test */
    result = sfud_write(flash, addr, size, data);

    if(result == SFUD_SUCCESS)
    {
        printf("\r\nWrite the %s flash data finish. Start from 0x%08X, size is %d.\r\n", flash->name, addr, size);
    }
    else
    {
        printf("\r\nWrite the %s flash data failed.\r\n", flash->name);
        return;
    }

    /* read test */
    result = sfud_read(flash, addr, size, data);

    if(result == SFUD_SUCCESS)
    {
        printf("\r\nRead the %s flash data success. Start from 0x%08X, size is %d. The data is:\r\n", flash->name, addr, size);

        printf("Offset (h) 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\r\n");

        for(i = 0; i < size; i++)
        {
            if((i % 16) == 0)
            {
                printf("[%08X] ", addr + i);
            }

            printf("%02X ", data[i]);

            if(((i + 1) % 16 == 0) || (i == size - 1))
            {
                printf("\r\n");
            }
        }

        printf("\r\n");
    }
    else
    {
        printf("\r\nRead the %s flash data failed.\r\n", flash->name);
    }

    /* data check */
    for(i = 0; i < size; i++)
    {
        if(data[i] != i % 256)
        {
            printf("\r\nRead and check write data has an error. Write the %s flash data failed.\r\n", flash->name);
            break;
        }
    }

    if(i == size)
    {
        printf("\r\nThe %s flash test is success.\r\n", flash->name);
    }
}


/*******************************************************************************
* @brief      
* @param      
* @retval      
* @attention   
*******************************************************************************/
void SPI_FLASH_Init(void)
{
    printf("\r\n");

    if(sfud_init() == SFUD_SUCCESS)
    {
        sfud_demo(0, sizeof(sfud_demo_buf), sfud_demo_buf);
    }
}
  • SFUD移植接口
#include <sfud.h>
#include <stdarg.h>
#include "config.h"

static char log_buf[256];

void sfud_log_debug(const char *file, const long line, const char *format, ...);

/**
* SPI write data then read data
*/
static sfud_err spi_write_read(const sfud_spi *spi, const uint8_t *write_buf, size_t write_size, uint8_t *read_buf,
        size_t read_size) {
    sfud_err result = SFUD_SUCCESS;
    uint8_t send_data, read_data;

    if (write_size) {
        SFUD_ASSERT(write_buf);
    }

    if (read_size) {
        SFUD_ASSERT(read_buf);
    }

    /**
     * add your spi write and read code
     */
    GPIO_ClearOutBits(HT_GPIOA, GPIO_PIN_8);

    for (size_t i = 0; i < (write_size + read_size); i++) {
        if (i < write_size) {
            send_data = *write_buf++;
        } else {
            send_data = SFUD_DUMMY_DATA;
        }

        while(!SPI_GetFlagStatus(HT_SPI1, SPI_FLAG_TXBE));
        SPI_SendData(HT_SPI1, send_data);

        while(!SPI_GetFlagStatus(HT_SPI1, SPI_FLAG_RXBNE));
        read_data = SPI_ReceiveData(HT_SPI1);

        if (i >= write_size) {
            *read_buf++ = read_data;
        }
    }

    GPIO_SetOutBits(HT_GPIOA, GPIO_PIN_8);

    return result;
}

#ifdef SFUD_USING_QSPI
/**
* read flash data by QSPI
*/
static sfud_err qspi_read(const struct __sfud_spi *spi, uint32_t addr, sfud_qspi_read_cmd_format *qspi_read_cmd_format,
        uint8_t *read_buf, size_t read_size) {
    sfud_err result = SFUD_SUCCESS;

    /**
     * add your qspi read flash data code
     */

    return result;
}
#endif /* SFUD_USING_QSPI */

static void rcc_initialize(void) {
    CKCU_PeripClockConfig_TypeDef CKCUClock = {{0}};
    CKCUClock.Bit.PA   = 1;
    CKCUClock.Bit.PB   = 1;
    CKCUClock.Bit.PC   = 1;
    CKCUClock.Bit.SPI1 = 1;
    CKCUClock.Bit.AFIO = 1;
    CKCU_PeripClockConfig(CKCUClock, ENABLE);
}

static void gpio_initialize(void) {
    AFIO_GPxConfig(GPIO_PA, GPIO_PIN_8,  AFIO_FUN_GPIO);
    AFIO_GPxConfig(GPIO_PA, GPIO_PIN_15, AFIO_FUN_SPI);
    AFIO_GPxConfig(GPIO_PB, GPIO_PIN_6,  AFIO_FUN_SPI);
    AFIO_GPxConfig(GPIO_PC, GPIO_PIN_3,  AFIO_FUN_SPI);

    GPIO_SetOutBits(HT_GPIOA, GPIO_PIN_8);
    GPIO_DirectionConfig(HT_GPIOA, GPIO_PIN_8, GPIO_DIR_OUT);
}

static void spi_device_initialize(void) {
    SPI_InitTypeDef  SPI_InitStructure;

    SPI_InitStructure.SPI_Mode        = SPI_MASTER;
    SPI_InitStructure.SPI_FIFO        = SPI_FIFO_DISABLE;
    SPI_InitStructure.SPI_DataLength  = SPI_DATALENGTH_8;
    SPI_InitStructure.SPI_SELMode     = SPI_SEL_SOFTWARE;
    SPI_InitStructure.SPI_SELPolarity = SPI_SELPOLARITY_LOW;
    SPI_InitStructure.SPI_FirstBit    = SPI_FIRSTBIT_MSB;
    SPI_InitStructure.SPI_CPOL        = SPI_CPOL_HIGH;
    SPI_InitStructure.SPI_CPHA        = SPI_CPHA_SECOND;
    SPI_InitStructure.SPI_RxFIFOTriggerLevel = 0;
    SPI_InitStructure.SPI_TxFIFOTriggerLevel = 0;
#if (LIBCFG_MAX_SPEED > 48000000)
    SPI_InitStructure.SPI_ClockPrescaler = 4;
#else
    SPI_InitStructure.SPI_ClockPrescaler = 2;
#endif
    SPI_Init(HT_SPI1, &SPI_InitStructure);

    SPI_SELOutputCmd(HT_SPI1, ENABLE);

    SPI_Cmd(HT_SPI1, ENABLE);
}

static void spi_lock(const sfud_spi *spi) {
    __disable_irq();
}

static void spi_unlock(const sfud_spi *spi) {
    __enable_irq();
}

static void retry_delay_100us(void) {
    uint32_t delay = 120;
    while (delay--);
}

sfud_err sfud_spi_port_init(sfud_flash *flash) {
    sfud_err result = SFUD_SUCCESS;

    /**
     * add your port spi bus and device object initialize code like this:
     * 1. rcc initialize
     * 2. gpio initialize
     * 3. spi device initialize
     * 4. flash->spi and flash->retry item initialize
     *    flash->spi.wr = spi_write_read; //Required
     *    flash->spi.qspi_read = qspi_read; //Required when QSPI mode enable
     *    flash->spi.lock = spi_lock;
     *    flash->spi.unlock = spi_unlock;
     *    flash->spi.user_data = &spix;
     *    flash->retry.delay = null;
     *    flash->retry.times = 10000; //Required
     */
    switch (flash->index) {
        case SFUD_FLASH_DEVICE_INDEX:
            rcc_initialize();

            gpio_initialize();

            spi_device_initialize();

            flash->spi.wr        = spi_write_read;
            flash->spi.qspi_read = qspi_read;
            flash->spi.lock      = spi_lock;
            flash->spi.unlock    = spi_unlock;
            flash->spi.user_data = NULL;
            flash->retry.delay   = retry_delay_100us;
            flash->retry.times   = 60 * 10000;
            break;

        default: break;
    }

    return result;
}

/**
* This function is print debug info.
*
* @param file the file which has call this function
* @param line the line number which has call this function
* @param format output format
* @param ... args
*/
void sfud_log_debug(const char *file, const long line, const char *format, ...) {
    va_list args;

    /* args point to the first variable parameter */
    va_start(args, format);
    printf("[SFUD](%s:%ld) ", file, line);
    /* must use vprintf to print */
    vsnprintf(log_buf, sizeof(log_buf), format, args);
    printf("%s\r\n", log_buf);
    va_end(args);
}

/**
* This function is print routine info.
*
* @param format output format
* @param ... args
*/
void sfud_log_info(const char *format, ...) {
    va_list args;

    /* args point to the first variable parameter */
    va_start(args, format);
    printf("[SFUD]");
    /* must use vprintf to print */
    vsnprintf(log_buf, sizeof(log_buf), format, args);
    printf("%s\r\n", log_buf);
    va_end(args);
}


运行结果
  • EEPROM
1.png 2.png 3.png
  • SPI FLASH
4.png


软件工程源代码
Project.zip (896.97 KB)

使用特权

评论回复
51xlf| | 2022-11-1 14:29 | 显示全部楼层
SPI FLASH 主要用于哪些产品呢?

使用特权

评论回复
houjiakai| | 2022-11-1 15:24 | 显示全部楼层
是硬件spi驱动的吗?              

使用特权

评论回复
fengm| | 2022-11-1 15:45 | 显示全部楼层
eeprom可以实现文件的存储吗

使用特权

评论回复
olivem55arlowe| | 2022-11-1 17:12 | 显示全部楼层
移植了fatfs文件操作系统了吗

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则