CC2538 zigbee I2C示例代码读写AT24C02D eeprom

AT24C02D
  • AT24C02D由于不是标准的I2C总线,所以没有完全使用I2C的8字节地址总线,而是兼容I2c,估计是为了逃避NXP的专利费,使用了5+3外部引脚设置(A2,A1,A0)来决定和哪路器件通讯的,一个i2c总线上最多能挂载8个AT24C02D,刚好是2的三次方。

  • 不明白为什么AT24C02D把i2c里面的sub address叫做Word Address,很是奇怪,我这里表述都按照sub address来表述,下同。

  • AT24C02D 作为CC2538外挂的eeprom,通过i2c总线和CC2538通讯,实现读写,花了很长时间一直搞不定,网上找的十有八九都是什么GPIO模拟i2c,我的CC2538本身就有i2c接口,还模拟什么模拟。

  • 开始没搞懂读写AT24C02D eeprom,以为和普通的i2c器件一样,写的话,发送slave address+ sub address+data,就可以写了,读的话,发送slave address+sub address,就可以读出指定地址的数据了,其实是错的


  • 我们都知道,i2c有起始位,也就是Start,有停止位,也就是Stop。写的话,按照eeprom芯片手册给的时序图,就是Start以后,发送从机地址slave address,发送完从机地址,是不能有Stop的,必须接着发送sub address,然后也不能有Stop,接着发送data,就是需要写入的数据,最后再发送Stop,才算是完成了一次写操作,真麻烦。

  • 读的话,芯片手册里面提到的有三种读的方式,分别为Current Address ReadRandom Address ReadSequential Read

  • 在真正写入数据的时候,eeprom需要有一个时间等待写入完成,叫做self-write time,简称Twr,数据手册里面提到最长是5ms,很多人就会写个循环让等5ms,而且还为了能达到5ms循环反复做测试,这样其实非常愚蠢,合适的做法数据手册里面已经给出了,就是5.3 Acknowledge Polling提到的,原理就是在写入指令发送完成以后,继续发送写入,如果此时eeprom正在self-write,那么肯定就不会有ACK应答,这样一直轮询,直到self-write完成之后才会有ACK应答,这样就可以不需要固定的延时5ms了。


CC2538 I2C功能
  • 找遍互联网,也找不到CC2538 I2C相关的示例代码,除了一个master_slave_loopback.c示例回环读写i2c之外,别的要么是什么gpio模拟i2c,要么是什么firmware foundation提供的示例代码,竟没有一个是真正能成功使用过的。看来使用CC2538的人少的很,多数人都用CC2530带十几个二十个节点满足home应用就完事了。
头文件
/*
  Atmel AT24C02 EEPROM read and write
*/

#ifndef HAL_EEPROM_H
#define HAL_EEPROM_H

#include <stdint.h>

#ifdef __cplusplus
extern "C"
{
#endif

/*
* PC.6->I2C_SCL
* PC.7->I2C_SDA
*/
#define I2C_SCL             GPIO_PIN_6
#define I2C_SDA             GPIO_PIN_7
#define GPIO_I2C_BASE       GPIO_C_BASE
  
void HalEepromWriteByte(uint8 slaveAddr,uint32_t subAddr,uint32_t data);
uint32_t HalEepromReadByte(uint8 slaveAddr,uint32_t subAddr);

void HalEepromWriteWord(uint8 slaveAddr,uint32_t subAddr,uint32_t data);
uint32_t HalEepromReadWord(uint8 slaveAddr,uint32_t subAddr);

void HalEepromWriteDword(uint8 slaveAddr,uint32_t subAddr,uint32_t data);
uint32_t HalEepromReadDword(uint8 slaveAddr,uint32_t subAddr);

#ifdef __cplusplus
}
#endif

#endif
源文件
/**************************************************************************************************
 *                                           INCLUDES
*
* Description: Atmel Inc  AT24C02D eeprom chip write and read. For CC2538 cortex-M3 core
*
*
 **************************************************************************************************/

#include <string.h>
#include "hw_i2cm.h"
#include "hal_types.h"
#include "hal_eeprom.h"
#include "hw_ioc.h"
#include "hal_mcu.h"

/* ref. AT24C02 DATASHEET 5.3 Acknowledge Polling*/
static void waitSlaveACK(uint8 slaveAddr)
{
  /*used volatile prevent compiler optimize*/
  volatile bool busy=true;
  while(busy == true){
    I2CMasterSlaveAddrSet(slaveAddr,false);       //false:write
    I2CMasterControl(I2C_MASTER_CMD_SINGLE_SEND); //star+run+stop
    busy=I2CMasterBusy();
  }
}

static void dummyWrite(uint8 slaveAddr,uint32_t subAddr)
{
#if (HAL_EEPROM == TRUE)
  if(subAddr < 0xFF)
  {
    HalEepromInit();  //we have to reinitialization i2c module every read/write cycle
    //1. dummy write
    //set slave address(Device Address)
    I2CMasterSlaveAddrSet(slaveAddr,false);       //false:write
    //set sub address(Word Address)
    I2CMasterDataPut(subAddr);
    I2CMasterControl(I2C_MASTER_CMD_BURST_SEND_START);
    while(I2CMasterBusy()){}
  }
#endif
}

static void HalEepromInit(void)
{
#if (HAL_EEPROM == TRUE) 
    //
    //  The I2C peripheral must be enabled before use.
    //
    SysCtrlPeripheralEnable(SYS_CTRL_PERIPH_I2C);
    
    //
    // Do reset of I2C module
    //
    SysCtrlPeripheralReset(SYS_CTRL_PERIPH_I2C);

    //
    // Configure I2C physical pins
    //
    GPIOPinTypeI2C(GPIO_I2C_BASE, I2C_SCL);
    GPIOPinTypeI2C(GPIO_I2C_BASE, I2C_SDA);

    // Configure pins as peripheral input and output
    IOCPinConfigPeriphInput(GPIO_I2C_BASE, I2C_SCL,IOC_I2CMSSCL);             //this may be caused "while(I2CMasterBusy()){}" infinite loop,so we have to comment it
    IOCPinConfigPeriphInput(GPIO_I2C_BASE, I2C_SDA,IOC_I2CMSSDA);    
    IOCPinConfigPeriphOutput(GPIO_I2C_BASE, I2C_SCL,IOC_MUX_OUT_SEL_I2C_CMSSCL);
    IOCPinConfigPeriphOutput(GPIO_I2C_BASE, I2C_SDA,IOC_MUX_OUT_SEL_I2C_CMSSDA);

    // data rate setting
    // fase:100kbps
    // true:400kbps
    I2CMasterInitExpClk(SysCtrlClockGet(), false);
#endif
}

/*
*Write data to external eeprom(AT24C02D)
*
@param 7-bit of slave address
@param 8-bit of sub-address
@param byte to be write
*/
void HalEepromWriteByte(uint8 slaveAddr,uint32_t subAddr,uint32_t data)
{
#if (HAL_EEPROM == TRUE)  
  if(subAddr < 0xFF)
  {
    HalEepromInit();  //we have to reinitialization i2c module every read/write cycle
    //set slave address(Device Address)
    I2CMasterSlaveAddrSet(slaveAddr,false);       //false:write

    //set sub address(Word Address)
    I2CMasterDataPut(subAddr);
    I2CMasterControl(I2C_MASTER_CMD_BURST_SEND_START);     //star+run
    // Wait until master module is done transferring.
    while(I2CMasterBusy()){}

    // Place the data to be sent in the data register
    I2CMasterDataPut(data);
    I2CMasterControl(I2C_MASTER_CMD_BURST_SEND_FINISH);    //run+stop
    // Wait until master module is done transferring.
    while(I2CMasterBusy()){}
    
    waitSlaveACK(slaveAddr);
  }
#endif
}

/*
* read one byte
@param index of total eeprom(0~255)
*/
uint32_t HalEepromReadByte(uint8 slaveAddr,uint32_t subAddr)
{
#if (HAL_EEPROM == TRUE)
  uint32_t uRead=0;
  if(subAddr < 0xFF)
  {
    HalEepromInit();  //we have to reinitialization i2c module every read/write cycle

    dummyWrite(slaveAddr,subAddr);
    
    //2. actual read
    I2CMasterSlaveAddrSet(slaveAddr,true);
    I2CMasterControl(I2C_MASTER_CMD_SINGLE_RECEIVE);    

    while(I2CMasterBusy()){}
  
    uRead = I2CMasterDataGet();
  }
  return uRead;
#endif
}

void HalEepromWriteWord(uint8 slaveAddr,uint32_t subAddr,uint32_t data)
{
#if (HAL_EEPROM == TRUE)
  if(subAddr < 0xFF)
  {
    uint8 i=0;
    HalEepromInit();  //we have to reinitialization i2c module every read/write cycle

    //set slave address(Device Address)
    I2CMasterSlaveAddrSet(slaveAddr,false);       //false:write

    //set sub address(Word Address)
    I2CMasterDataPut(subAddr);
    I2CMasterControl(I2C_MASTER_CMD_BURST_SEND_START);     //star+run
    while(I2CMasterBusy()){}

    // Place the data to be sent in the data register
    for(i=sizeof(uint16_t);i>0;i--)
    {
      I2CMasterDataPut(data>>(8*(i-1))&0xFF);
      if(i != 1)
      {
        I2CMasterControl(I2C_MASTER_CMD_BURST_SEND_CONT);       //run
      }else
      {
        I2CMasterControl(I2C_MASTER_CMD_BURST_SEND_FINISH);    //run+stop
      }
      while(I2CMasterBusy()){}
    }
   
    waitSlaveACK(slaveAddr);
  }
#endif
}

/*
* dummy write for read purpose
@param index of total eeprom(0~255)
*/
uint32_t HalEepromReadWord(uint8 slaveAddr,uint32_t subAddr)
{
#if (HAL_EEPROM == TRUE)
  uint32_t uRead=0;
  if(subAddr < 0xFF)
  {
    uint8 i=0;
    HalEepromInit();  //we have to reinitialization i2c module every read/write cycle
    
    dummyWrite(slaveAddr,subAddr);

    //read
    I2CMasterSlaveAddrSet(slaveAddr,true);
    I2CMasterControl(I2C_MASTER_CMD_BURST_RECEIVE_START);
    while(I2CMasterBusy()){}

    for(i=0;i<sizeof(uint16_t);i++)
    {
      // Read the data from the master.
      uRead |=I2CMasterDataGet()&0xFF;
      if(i != 1)
      {
        uRead<<=8;
        I2CMasterControl(I2C_MASTER_CMD_BURST_RECEIVE_CONT);    //run+ack
      }else
      {
        I2CMasterControl(I2C_MASTER_CMD_BURST_RECEIVE_FINISH);  //run+stop (nack)
      }
      while(I2CMasterBusy()){}
    }
  }
  return uRead;
#endif
}

/*
*Write data to external eeprom(AT24C02D)
*
@param 7-bit of slave address
@param 8-bit of sub-address
@param DWORD to be write
*/
void HalEepromWriteDword(uint8 slaveAddr,uint32_t subAddr,uint32_t data)
{
#if (HAL_EEPROM == TRUE)  
  if(subAddr < 0xFF)
  {
    uint8 i=0;
    HalEepromInit();  //we have to reinitialization i2c module every read/write cycle
    //set slave address(Device Address)
    I2CMasterSlaveAddrSet(slaveAddr,false);       //false:write

    //set sub address(Word Address)
    I2CMasterDataPut(subAddr);
    I2CMasterControl(I2C_MASTER_CMD_BURST_SEND_START);     //star+run
    while(I2CMasterBusy()){}

    // Place the data to be sent in the data register
    for(i=sizeof(uint32_t);i>0;i--)
    {
      I2CMasterDataPut(data>>(8*(i-1))&0xFF);
      if(i != 1)
      {
        I2CMasterControl(I2C_MASTER_CMD_BURST_SEND_CONT);       //run
      }else
      {
        I2CMasterControl(I2C_MASTER_CMD_BURST_SEND_FINISH);    //run+stop
      }
      while(I2CMasterBusy()){}
    }

    waitSlaveACK(slaveAddr);
  }
#endif
}

/*
* dummy write for read purpose
@param index of total eeprom(0~255)
*/
uint32_t HalEepromReadDword(uint8 slaveAddr,uint32_t subAddr)
{
#if (HAL_EEPROM == TRUE)
  uint32_t uRead=0;

  if(subAddr < 0xFF)
  {
    uint8 i=0;
    HalEepromInit();  //we have to reinitialization i2c module every read/write cycle
    
    dummyWrite(slaveAddr,subAddr);
    
    //actual read
    I2CMasterSlaveAddrSet(slaveAddr,true);    
    I2CMasterControl(I2C_MASTER_CMD_BURST_RECEIVE_START);
    while(I2CMasterBusy()){}

    for(i=0;i<sizeof(uint32_t);i++)
    {
      // Read the data from the slave
      uRead |=I2CMasterDataGet()&0xFF;
      if(i != 3)
      {
        uRead<<=8;
        I2CMasterControl(I2C_MASTER_CMD_BURST_RECEIVE_CONT);    //run+ack
      }else
      {
        I2CMasterControl(I2C_MASTER_CMD_BURST_RECEIVE_FINISH);  //run+stop (nack)
      }
      while(I2CMasterBusy()){}
    }
  }
  return uRead;
#endif
}
示例代码
#define EERPOM_ADDRESS 0x50

// 8-bit word address (total 256 pages)
#define EEPROM_PAGE_0                           (0<<3)        // eeprom page 0(0~7 byte)
#define EEPROM_PAGE_1                           (1<<3)        // eeprom page 1(8~15 byte)
#define EEPROM_PAGE_2                           (2<<3)
#define EEPROM_PAGE_3                           (3<<3)
#define EEPROM_PAGE_4                           (4<<3)
#define EEPROM_PAGE_5                           (5<<3)
  
//Word Address MACRO
#define ADDR_VALUE1                  ((EEPROM_PAGE_0)+0x01)            //index of page
#define ADDR_VALUE2                  ((EEPROM_PAGE_0)+0x02)            //index of page

/* write one byte */
uint8_t writeByte=0x88;
HalEepromWriteByte(EERPOM_ADDRESS,ADDR_VALUE1,writeByte);

/* read one byte */
uint8_t readByte= HalEepromReadByte(EERPOM_ADDRESS,ADDR_VALUE1);
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值