打印
[产品应用]

【CW32L031CxTx StartKit评估板测评】02-软件模拟I2C读写板载EEPROM

[复制链接]
933|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 怀揣少年梦 于 2023-11-10 11:44 编辑

一、开发板上硬件设计
CW32L031CxTx StartKit评估板上板载一颗型号为CW24C02AD的EEPROM,EEPROM适用于保存数据量比较小的场景,并且可靠性比较高。
先看一下CW24C02AD的数据手册,可以看到该EEPROM只有2Kbit,也就是256字节(这是EEPROM中容量最小的芯片),每页8个字节,一共32页。工作电压1.7-5.5V;允许页面局部写入;I2C 时钟频率为 1MHz (5V,3V),400 KHz (1.7V);擦写寿命:100 万次;数据保持时间: 20年;

从评估板的原理图来看,EEPROM的A2\A1\A0三个引脚接地,说明读写EEPROM的地址为A0;

二、软件设计
使用GPIO口模拟I2C读写EEPROM。
具体代码如下:

1).c代码
#include "eeprom.h"

#define I2C_DIR_TRANSMIT                 0x00
#define I2C_DIR_RECEIVE                  0x01

#define I2C_ACK_TIMEOUT                  64

#define I2C_SCL_HIGH()                   GPIO_WritePin(I2Cx_SCL_GPIO_PORT, I2Cx_SCL_PIN, GPIO_Pin_SET)
#define I2C_SCL_LOW()                    GPIO_WritePin(I2Cx_SCL_GPIO_PORT, I2Cx_SCL_PIN, GPIO_Pin_RESET)

#define I2C_SDA_HIGH()                   GPIO_WritePin(I2Cx_SDA_GPIO_PORT, I2Cx_SDA_PIN, GPIO_Pin_SET)
#define I2C_SDA_LOW()                    GPIO_WritePin(I2Cx_SDA_GPIO_PORT, I2Cx_SDA_PIN, GPIO_Pin_RESET)

#define I2C_SDA_READ                     GPIO_ReadPin(I2Cx_SDA_GPIO_PORT, I2Cx_SDA_PIN)
#define I2C_DALEY_US         5

/**
  * [url=home.php?mod=space&uid=247401]@brief[/url] i2c address direction
  */

void i2c_config(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  
  /* i2c gpio clock enable */
        __RCC_GPIOB_CLK_ENABLE();
  
  /* gpio configuration */  
        GPIO_InitStruct.IT = GPIO_IT_NONE;
        GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;

  /* configure i2c pins: scl */   
  GPIO_InitStruct.Pins = I2Cx_SCL_PIN;
  GPIO_Init(I2Cx_SCL_GPIO_PORT, &GPIO_InitStruct);

  /* configure i2c pins: sda */     
  GPIO_InitStruct.Pins = I2Cx_SDA_PIN;
  GPIO_Init(I2Cx_SDA_GPIO_PORT, &GPIO_InitStruct);

  I2C_SDA_HIGH();
  I2C_SCL_HIGH();
}

/**
  * @brief  used to set the i2c clock frequency.
  * @param  none.
  * @retval none.
  */
void i2c_delay(void)
{
        uint8_t i = 0;
        uint8_t j = 48;
        for (i = 0; i< I2C_DALEY_US; i++) {
                while(j--);
        }
}


/**
* @brief 循环延时
*
* @param nCount
*/
void Delay(__IO uint16_t nCount)
{
    /* Decrement nCount value */
    while (nCount != 0)
    {
        nCount--;
    }
}

/**
  * @brief  used to generate start conditions.
  * @param  none.
  * @retval none.
  */
void i2c_start(void)
{
  i2c_delay();
  
  I2C_SDA_HIGH();
  I2C_SCL_HIGH();
  i2c_delay();
  
  I2C_SDA_LOW();
  i2c_delay();
  
  I2C_SCL_LOW();
  i2c_delay();
}

/**
  * @brief  used to generate stop conditions.
  * @param  none.
  * @retval none.
  */
void i2c_stop(void)
{
  I2C_SCL_LOW();
  I2C_SDA_LOW();  
  i2c_delay();
  
  I2C_SCL_HIGH();
  i2c_delay();
  
  I2C_SDA_HIGH();
  i2c_delay();
}

/**
  * @brief  used to generate ack conditions.
  * @param  none.
  * @retval none.
  */
void i2c_ack(void)
{
  I2C_SCL_LOW();
  I2C_SDA_LOW();
  i2c_delay();
  
  I2C_SCL_HIGH();
  i2c_delay();
  
  I2C_SCL_LOW();
  i2c_delay();
}

/**
  * @brief  used to generate nack conditions.
  * @param  none.
  * @retval none.
  */
void i2c_no_ack(void)
{
  I2C_SCL_LOW();
  I2C_SDA_HIGH();
  i2c_delay();
  
  I2C_SCL_HIGH();
  i2c_delay();
  
  I2C_SCL_LOW();
  i2c_delay();
}

/**
  * @brief  used to wait ack conditions.
  * @param  none.
  * @retval ack receive status.
  *         - 1: no ack received.
  *         - 0: ack received.
  */
uint8_t i2c_wait_ack(uint8_t timeout)
{
  I2C_SCL_LOW();
  I2C_SDA_HIGH();  
  
  i2c_delay();
  
  while(timeout)
  {
    if (I2C_SDA_READ == 0)
    {
      I2C_SCL_HIGH();
      
      i2c_delay();
      
      I2C_SCL_LOW();
      
      return 0;
    }
   
    i2c_delay();
   
    timeout--;
  }  
  
  return 1;
}

/**
  * @brief  send a byte.
  * @param  data: byte to be transmitted.
  * @retval none.
  */
void i2c_send_byte(uint8_t data)
{
  uint8_t i = 8;
       
  I2C_SCL_LOW(); //
  while (i--)
  {
    if (data & 0x80)
    {
      I2C_SDA_HIGH();   
    }
    else
    {
      I2C_SDA_LOW();   
    }   
   
    i2c_delay();
   
    I2C_SCL_HIGH();
    i2c_delay();
                I2C_SCL_LOW();
    i2c_delay();
       
        data <<= 1;
  }   
}

/**
  * @brief  receive a byte.
  * @param  data: byte to be received.
  * @retval none.
  */
uint8_t i2c_receive_byte(void)
{
  uint8_t i = 8;
  uint8_t byte = 0;

  I2C_SDA_HIGH();
  I2C_SCL_LOW();
       
  while (i--)
  {
    byte <<= 1;
    I2C_SCL_HIGH();
    i2c_delay();
  
    byte |= I2C_SDA_READ;
          I2C_SCL_LOW();
    i2c_delay();

  }

  return byte;
}

uint8_t i2c_WriteByte(uint8_t I2C_Addr,uint8_t addr,uint8_t data)
{
        i2c_start();
        i2c_send_byte(I2C_Addr | I2C_DIR_TRANSMIT);; //
        if (i2c_wait_ack(I2C_ACK_TIMEOUT) == 1)
        {
      i2c_stop();
               
          return 1;
        }
        i2c_send_byte(addr); //
        if (i2c_wait_ack(I2C_ACK_TIMEOUT) == 1)
        {
      i2c_stop();
      printf("EEPROM %x \r\n",addr);       
          return 1;
        }          
        i2c_send_byte(data);
        if (i2c_wait_ack(I2C_ACK_TIMEOUT) == 1)
        {
      i2c_stop();
      printf("EEPROM %x \r\n",data);               
          return 1;
        }
       
        i2c_stop(); //

        Delay(0xffff);
        Delay(0xffff);
        Delay(0xffff);
        printf("write ok\r\n");
        return 0;
}


uint8_t i2c_ReadCurrentAddrByte(uint8_t I2C_Addr)
{
        uint8_t data;
        i2c_start();
        i2c_send_byte(I2C_Addr | I2C_DIR_RECEIVE);; //锟斤拷锟酵从伙拷锟斤拷址
        if (i2c_wait_ack(I2C_ACK_TIMEOUT) == 1)
        {
      i2c_stop();
               
          return 1;
        }
        data = i2c_receive_byte();
        i2c_no_ack();
        i2c_stop(); //
        printf("receive1 ok\r\n");
        return data;
}

uint8_t i2c_ReadByte(uint8_t I2C_Addr,uint8_t addr)
{
        uint8_t data;
        i2c_start();
        i2c_send_byte(I2C_Addr | I2C_DIR_TRANSMIT);; //
        if (i2c_wait_ack(I2C_ACK_TIMEOUT) == 1)
        {
      i2c_stop();
               
          return 1;
        }
        i2c_send_byte((uint8_t)addr); //
        if (i2c_wait_ack(I2C_ACK_TIMEOUT) == 1)
        {
      i2c_stop();
      printf("EEPROM %x \r\n",addr);       
          return 1;
        }          
       
        i2c_start();
        i2c_send_byte(I2C_Addr | I2C_DIR_RECEIVE);; //
        if (i2c_wait_ack(I2C_ACK_TIMEOUT) == 1)
        {
      i2c_stop();
      printf("EEPROM %x \r\n",I2C_Addr);               
          return 1;
        }
        data = i2c_receive_byte();
        i2c_no_ack();
        i2c_stop(); //
        printf("receive ok\r\n");
        return data;
}


uint8_t i2c_ReadMultByte(uint8_t I2C_Addr,uint16_t addr,uint8_t length, uint8_t *pdata)
{
        uint8_t i = 0;
       
        i2c_start();
        i2c_send_byte(I2C_Addr | I2C_DIR_TRANSMIT);; //
        if (i2c_wait_ack(I2C_ACK_TIMEOUT) == 1)
        {
      i2c_stop();
               
          return 1;
        }

        i2c_send_byte((uint8_t)addr); //
        if (i2c_wait_ack(I2C_ACK_TIMEOUT) == 1)
        {
      i2c_stop();
      printf("EEPROM %x \r\n",addr);       
          return 1;
        }          
       
        i2c_start();
        i2c_send_byte(I2C_Addr | I2C_DIR_RECEIVE);; //
        if (i2c_wait_ack(I2C_ACK_TIMEOUT) == 1)
        {
      i2c_stop();
      printf("EEPROM %x \r\n",I2C_Addr);               
          return 1;
        }
       
        for(i = 0; i< length; i++) {
       
      pdata[i] = i2c_receive_byte();
   
      if (i < (length - 1))
      {
        i2c_ack();
      }
      else
      {
        i2c_no_ack();
      }
        }

        i2c_stop(); //
        printf("mul receive ok\r\n");
        return 0;
}

uint8_t i2c_WriteMultByte(uint8_t I2C_Addr,uint16_t addr,uint8_t length, uint8_t *pdata)
{
        uint8_t i = 0;
       
        i2c_start();
        i2c_send_byte(I2C_Addr | I2C_DIR_TRANSMIT);; //
        if (i2c_wait_ack(I2C_ACK_TIMEOUT) == 1)
        {
      i2c_stop();
               
          return 1;
        }
       
        i2c_send_byte((uint8_t)addr); //
  printf("addr high %x",(uint8_t)(addr));
        if (i2c_wait_ack(I2C_ACK_TIMEOUT) == 1)
        {
      i2c_stop();
      printf("EEPROM %x\r\n",addr);       
          return 1;
        }          
       
        for(i = 0; i< length; i++) {
      i2c_send_byte(pdata[i]);
      if (i2c_wait_ack(I2C_ACK_TIMEOUT) == 1)
      {
        i2c_stop();
        printf("EEPROM %d %x \r\n",i,addr);       
        return 1;
      }
        }

        i2c_stop(); //
  printf("write ok\r\n");
        Delay(0xffff);

        return 0;
}


2)、.h代码
#ifndef __EEPROM_H__
#define __EEPROM_H__

#include "..\inc\main.h"

#define I2Cx_SCL_PIN                     GPIO_PIN_6
#define I2Cx_SCL_GPIO_PORT               CW_GPIOB

#define I2Cx_SDA_PIN                     GPIO_PIN_7
#define I2Cx_SDA_GPIO_PORT               CW_GPIOB



/** @defgroup I2C_library_exported_functions
  * @{
  */

void i2c_config(void);
void delay_us(uint32_t us);
void Delay(__IO uint16_t nCount);
uint8_t i2c_WriteByte(uint8_t I2C_Addr,uint8_t addr,uint8_t data);
uint8_t i2c_ReadCurrentAddrByte(uint8_t I2C_Addr);
uint8_t i2c_ReadByte(uint8_t I2C_Addr,uint8_t addr);
uint8_t i2c_ReadMultByte(uint8_t I2C_Addr,uint16_t addr,uint8_t length, uint8_t *pdata);
uint8_t i2c_WriteMultByte(uint8_t I2C_Addr,uint16_t addr,uint8_t length, uint8_t *pdata);
#endif


3)、测试主程序
#include "..\inc\main.h"
/******************************************************************************
* Local pre-processor symbols/macros ('#define')
******************************************************************************/
//UARTx
#define  DEBUG_USARTx                   CW_UART1   
#define  DEBUG_USART_CLK                RCC_APB2_PERIPH_UART1
#define  DEBUG_USART_APBClkENx          RCC_APBPeriphClk_Enable2
#define  DEBUG_USART_BaudRate           9600
#define  DEBUG_USART_UclkFreq           8000000
#define  LED_GPIO_PORT CW_GPIOB
#define  LED_GPIO_PINS GPIO_PIN_8 | GPIO_PIN_9
//UARTx GPIO
#define  DEBUG_USART_GPIO_CLK           RCC_AHB_PERIPH_GPIOA
#define  DEBUG_USART_TX_GPIO_PORT       CW_GPIOA
#define  DEBUG_USART_TX_GPIO_PIN        GPIO_PIN_8
#define  DEBUG_USART_RX_GPIO_PORT       CW_GPIOA
#define  DEBUG_USART_RX_GPIO_PIN        GPIO_PIN_9

//GPIO AF
#define  DEBUG_USART_AFTX               PA08_AFx_UART1TXD()
#define  DEBUG_USART_AFRX               PA09_AFx_UART1RXD()
/******************************************************************************
* Global variable definitions (declared in header file with 'extern')
******************************************************************************/
uint8_t test_data[] = {0x01,0x02,0x03};
uint8_t test_readdata[3] = {0x00};
/******************************************************************************
* Local type definitions ('typedef')
******************************************************************************/

/******************************************************************************
* Local function prototypes ('static')
******************************************************************************/
void RCC_Configuration(void);
void GPIO_Configuration(void);
void UART_Configuration(void);

#ifdef __GNUC__
    /* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
    set to 'Yes') calls __io_putchar() */
    #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
    #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */

/******************************************************************************
* Local variable definitions ('static')                                      *
******************************************************************************/

/******************************************************************************
* Local pre-processor symbols/macros ('#define')
******************************************************************************/

/*****************************************************************************
* Function implementation - global ('extern') and local ('static')
******************************************************************************/

/**
******************************************************************************
** \brief  Main function of project
**
** \return uint32_t return value, if needed
**
******************************************************************************/
int32_t main(void)
{
    //配置RCC
    RCC_Configuration();

    //配置GPIO
    GPIO_Configuration();
                //i2c_config();
    //配置UART
    UART_Configuration();
               
    printf("\r\n use CW32L031 simulate I2C READ EEPROM Example\r\n");
               
    while(1)
    {
                        if (GPIO_ReadPin(CW_GPIOA, GPIO_PIN_1) == 0) {
                                i2c_WriteByte(0xA0,0x01,0x5A);
                                i2c_WriteMultByte(0xA0,0x05,3,test_data);
                        }
                       
                        if (GPIO_ReadPin(CW_GPIOA, GPIO_PIN_2) == 0) {
                                printf("data:%x \r\n",i2c_ReadByte(0xA0,0x01));
                                i2c_ReadMultByte(0xA0,0x05,3,test_readdata);
                                for(int i = 0;i < 3; i++) {
                                        printf("test_readdata[%d] = %x \r\n",i,test_readdata[i]);
                                }
                               
                        }
                       
                        GPIO_TogglePin(LED_GPIO_PORT, LED_GPIO_PINS);
      Delay(0xFFFF);
    }
}


/**
* @brief 配置RCC
*
*/
void RCC_Configuration(void)
{
    //SYSCLK = HSI = 8MHz = HCLK = PCLK
    RCC_HSI_Enable(RCC_HSIOSC_DIV6);

    //外设时钟使能
    RCC_AHBPeriphClk_Enable(DEBUG_USART_GPIO_CLK, ENABLE);
    DEBUG_USART_APBClkENx(DEBUG_USART_CLK, ENABLE);
                RCC_AHBPeriphClk_Enable(RCC_AHB_PERIPH_GPIOB,ENABLE);
                __RCC_GPIOA_CLK_ENABLE();
}

/**
* @brief 配置GPIO
*
*/
void GPIO_Configuration(void)
{
    GPIO_InitTypeDef GPIO_InitStructure = {0};

               
    //UART TX RX 复用
    DEBUG_USART_AFTX;
    DEBUG_USART_AFRX;

    GPIO_InitStructure.Pins = DEBUG_USART_TX_GPIO_PIN;
    GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_Init(DEBUG_USART_TX_GPIO_PORT, &GPIO_InitStructure);

                GPIO_InitStructure.Pins = GPIO_PIN_1 | GPIO_PIN_2;
    GPIO_InitStructure.Mode = GPIO_MODE_INPUT_PULLUP;
    GPIO_Init(CW_GPIOA, &GPIO_InitStructure);
               
    GPIO_InitStructure.Pins = DEBUG_USART_RX_GPIO_PIN;
    GPIO_InitStructure.Mode = GPIO_MODE_INPUT_PULLUP;
    GPIO_Init(DEBUG_USART_RX_GPIO_PORT, &GPIO_InitStructure);  

    GPIO_InitStructure.IT = GPIO_IT_NONE;
    GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStructure.Pins = LED_GPIO_PINS;               
               
                GPIO_Init(LED_GPIO_PORT, &GPIO_InitStructure);
               
               
                  /* gpio configuration */  
                GPIO_InitStructure.IT = GPIO_IT_NONE;
                GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_OD;

                /* configure i2c pins: scl */   
                GPIO_InitStructure.Pins = I2Cx_SCL_PIN;
                GPIO_Init(I2Cx_SCL_GPIO_PORT, &GPIO_InitStructure);

                /* configure i2c pins: sda */     
                GPIO_InitStructure.Pins = I2Cx_SDA_PIN;
                GPIO_Init(I2Cx_SDA_GPIO_PORT, &GPIO_InitStructure);

                GPIO_WritePin(I2Cx_SCL_GPIO_PORT, I2Cx_SCL_PIN, GPIO_Pin_SET);
                GPIO_WritePin(I2Cx_SDA_GPIO_PORT, I2Cx_SDA_PIN, GPIO_Pin_SET);
}

/**
* @brief 配置UART
*
*/
void UART_Configuration(void)
{
    USART_InitTypeDef USART_InitStructure = {0};

    USART_InitStructure.USART_BaudRate = DEBUG_USART_BaudRate;
    USART_InitStructure.USART_Over = USART_Over_16;
    USART_InitStructure.USART_Source = USART_Source_PCLK;
    USART_InitStructure.USART_UclkFreq = DEBUG_USART_UclkFreq;
    USART_InitStructure.USART_StartBit = USART_StartBit_FE;
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    USART_InitStructure.USART_Parity = USART_Parity_No ;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
    USART_Init(DEBUG_USARTx, &USART_InitStructure);
}

// KEIL
/**
* @brief Retargets the C library printf function to the USART.
*
*/
PUTCHAR_PROTOTYPE
{
    USART_SendData_8bit(DEBUG_USARTx, (uint8_t)ch);

    while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_TXE) == RESET);

    return ch;
}


// IAR
size_t __write(int handle, const unsigned char * buffer, size_t size)
{
    size_t nChars = 0;

    if (buffer == 0)
    {
        /*
         * This means that we should flush internal buffers.  Since we
         * don't we just return.  (Remember, "handle" == -1 means that all
         * handles should be flushed.)
         */
        return 0;
    }


    for (/* Empty */; size != 0; --size)
    {
        USART_SendData_8bit(DEBUG_USARTx, *buffer++);
        while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_TXE) == RESET);
        ++nChars;
    }

    return nChars;
}
三、实际测试串口输出

单字节写入5a,单字节读出来也是5a;
多字节写入01 02 03;多字节读出来也是01 02 03



使用特权

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

本版积分规则

个人签名:一切皆有可能

30

主题

400

帖子

2

粉丝