嵌入式系统与单片机|技术阅读
登录|注册

您现在的位置是:嵌入式系统与单片机 > 技术阅读 > 超级精简系列之四:超级精简的IO模拟IIC的C实现:EEPROM编辑工具应用

超级精简系列之四:超级精简的IO模拟IIC的C实现:EEPROM编辑工具应用

接上文

四.应用

以上实现了IO模拟IIC接口,整个过程很自然,参考时序图操作IO即可。但是是骡子是马拉出来遛遛。那么我们就基于此来进行EEPROM的读写测试吧,以24LC02为例。

4.1 24LC02驱动

我们这里以24LC02的驱动为例。手册参考《https://ww1.microchip.com/downloads/aemDocuments/documents/MPD/ProductDocuments/DataSheets/24AA02-24LC02B-24FC02-2K-I2C-Serial-EEPROM-20001709N.pdf

同样的我还是先设计接口。

很自然的IIC行为抽象如下

typedef void (*eeprom_iic_start_pf)(void); /**< IIC启动接口 */
typedef void (*eeprom_iic_stop_pf)(void); /**< IIC停止接口 */
typedef int (*eeprom_iic_read_pf)(uint8_t* val, uint8_t ack); /**< IIC读接口 */
typedef int (*eeprom_iic_write_pf)(uint8_t val); /**< IIC写接口 */
typedef void (*eeprom_iic_init_pf)(void); /**< 初始化接口 */
typedef void (*eeprom_iic_deinit_pf)(void); /**< 解除初始化接口 */

那么加上属性,设备地址addr,对象如下

/**
* \struct eeprom_dev_st
* 接口结构体
*/
typedef struct
{
eeprom_iic_start_pf start; /**< IIC启动接口 */
eeprom_iic_stop_pf stop; /**< IIC停止接口 */
eeprom_iic_read_pf read; /**< IIC读接口 */
eeprom_iic_write_pf write; /**< IIC写接口 */
eeprom_iic_init_pf init; /**< 初始化接口 */
eeprom_iic_deinit_pf deinit; /**< 解除初始化接口 */
uint8_t addr; /**< 设备地址 */
} eeprom_dev_st;

以上是对下的依赖,我们根据手册,自然的想到要实现以下对外接口

/**
* \fn eeprom_random_read
* 随机读
* \param[in] dev \ref eeprom_dev_st
* \param[in] addr 地址
* \param[in] val 存读出的值
* \retval 0 成功
* \retval <0 失败
*/
int eeprom_random_read(eeprom_dev_st* dev, uint32_t addr, uint8_t* buffer, uint32_t len);
/**
* \fn eeprom_byte_write
* 字节写
* \param[in] dev \ref eeprom_dev_st
* \param[in] addr 地址
* \param[in] val 待写入的值
* \retval 0 成功
* \retval <0 失败
*/
int eeprom_page_write(eeprom_dev_st* dev, uint32_t addr, uint8_t* buffer, uint32_t len);
/**
* \fn eeprom_init
* 初始化
* \param[in] dev \ref eeprom_dev_st
*/
void eeprom_init(eeprom_dev_st* dev);
/**
* \fn eeprom_deinit
* 解除初始化
* \param[in] dev \ref eeprom_dev_st
*/
void eeprom_deinit(eeprom_dev_st* dev);

随机读和PAGE写,另外手册里还有CURRENT ADDRESS READByte Write实际应用基本不会使用,随机读和PAGE写即可包含。

 

 

实现起来也就很简单了,初始化和解除初始化即调用底层对应接口,自己无需特殊处理。

 

随机读实现,直接按照时序图,分解到IIC的具体操作即可

其中#define CTRL_BYTE 0xA0

 

写也是类似

 

4.2 读写EEPROM测试

以上实现了EEPROM的驱动,实际我们实现了不同层级的构建。

现在我们将这些构件拼接起来,就可以实现具体的应用了。

我们这里实现一个基于命令行的eeprom编写工具。

命令行实现参考《https://mp.weixin.qq.com/s/XLmbJn0SKoDT1aLdxHDrbg

shell_func.c中申明读写实现函数

static void printeepromfunc(uint8_t* param);
static void writeeepromfunc(uint8_t* param);

添加命令信息到对应的表格g_shell_cmd_list_ast

{ (uint8_t*)"printeeprom", printeepromfunc, (uint8_t*)"printeeprom addr len"},
{ (uint8_t*)"writeeeprom", writeeepromfunc, (uint8_t*)"writeeeprom addr hexstr"},

IO模拟IIC的依赖实现

static void io_iic_port_init(void){


}
static void io_iic_port_deinit(void){


}
static void io_iic_port_scl_write(uint8_t val){



}
static void io_iic_port_sda_write(uint8_t val){


}
static void io_iic_port_sda_2read(void){


}
static uint8_t io_iic_port_sda_read(void){


}
static void io_iic_port_delay(uint32_t delay){


}
static io_iic_dev_st io_iic_dev=
{
.scl_write = io_iic_port_scl_write,
.sda_2read = io_iic_port_sda_2read,
.sda_read = io_iic_port_sda_read,
.sda_write = io_iic_port_sda_write,
.delayus = 10,
.delay_pf = io_iic_port_delay,
.init = io_iic_port_init,
.deinit = io_iic_port_deinit,
};

基于IO模拟的IIC实现EEPROM读写

static void eeprom_iic_port_init(void){
io_iic_init(&io_iic_dev);
}
static void eeprom_iic_port_deinit(void){
io_iic_deinit(&io_iic_dev);
}
static void eeprom_iic_port_start(void){
io_iic_start(&io_iic_dev);
}
static void eeprom_iic_port_stop(void){
io_iic_stop(&io_iic_dev);
}
static int eeprom_iic_port_read(uint8_t* val ,uint8_t ack){
return io_iic_read(&io_iic_dev, val ,ack);
}
static int eeprom_iic_port_write(uint8_t val){
return io_iic_write(&io_iic_dev, val);
}
eeprom_dev_st eepromdev=
{
.addr = 0,
.read = eeprom_iic_port_read,
.start = eeprom_iic_port_start,
.stop = eeprom_iic_port_stop,
.write = eeprom_iic_port_write,
.init = eeprom_iic_port_init,
.deinit = eeprom_iic_port_deinit,
};

读命令实现

void printeepromfunc(uint8_t* param){
uint8_t buffer[16];
uint32_t addr;
uint32_t len;
uint8_t* p = param;
int res;
//if(3 == sscanf((const char*)param, "%*s %s %d %d", type, &addr, &len))
while(1)
{
if((*p > 'z') || (*p < 'a'))
{
break;
}
else
{
p++;
}
}
while(1)
{
if(*p != ' ')
{
break;
}
else
{
p++;
}
}
addr = atoi((const char*)p);
while(1)
{
if((*p > '9') || (*p < '0'))
{
break;
}
else
{
p++;
}
}
while(1)
{
if(*p != ' ')
{
break;
}
else
{
p++;
}
}
len = atoi((const char*)p);
uint32_t toread;
uint32_t read = 0;
eeprom_init(&eepromdev);
while(read < len)
{
toread = ((len-read) > sizeof(buffer)) ? sizeof(buffer) : (len-read);
if(0 != (res = eeprom_random_read(&eepromdev, addr+read, buffer, toread)))
{
printf("read err %d\r\n",res);
eeprom_deinit(&eepromdev);
return;
}
read += toread;
for(uint32_t i=0; i<toread ;i++)
{
printf("%02x ",buffer[i]);
}
printf("\r\n");
}
eeprom_deinit(&eepromdev);
}

写命令实现

static uint8_t char2hex(uint8_t ch){
if((ch<='9') && (ch>='0'))
{
return ch-'0';
}
else if((ch<='f') && (ch>='a'))
{
return ch-'a' + 10;
}
else if((ch<='F') && (ch>='A'))
{
return ch-'A' + 10;
}
return 0;
}
void writeeepromfunc(uint8_t* param){
uint8_t buffer[16];
uint32_t addr;
uint32_t len=0;
uint8_t* p = param;
uint8_t flag;
uint8_t tmp;
int res;
//if(3 == sscanf((const char*)param, "%*s %s %d %d", type, &addr, &len))
while(1)
{
if((*p > 'z') || (*p < 'a'))
{
break;
}
else
{
p++;
}
}
while(1)
{
if(*p != ' ')
{
break;
}
else
{
p++;
}
}
addr = atoi((const char*)p);
while(1)
{
if((*p > '9') || (*p < '0'))
{
break;
}
else
{
p++;
}
}
while(1)
{
if(*p != ' ')
{
break;
}
else
{
p++;
}
}
flag = 0;
while(*p)
{
if(flag == 0)
{
tmp = char2hex(*p) << 4;
flag = 1;
}
else if(flag == 1)
{
tmp |= char2hex(*p);
flag = 0;
buffer[len++] = tmp;
if(len>=16)
{
break;
}
}
p++;
}
eeprom_init(&eepromdev);
if(0 != (res = eeprom_page_write(&eepromdev, addr, buffer, len)))
{
printf("write err %d\r\n",res);
eeprom_deinit(&eepromdev);
return;
}
printf("\r\n");
eeprom_deinit(&eepromdev);
}

4.3 测试

输入printeeprom 0 256回车打印如下

printeeprom 0 256
c0 a9 21 01 10 00 00 00 46 88 1f aa 2f fd b2 e9
28 26 16 0a 48 44 3d 45 4b 47 68 5e 29 78 1f 5c
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff

逻辑分析仪抓取波形

 

写入测试输入

writeeeprom 32 11223344回车

抓取波形

 

连续写

先看原来的值

printeeprom 0 256
c0 a9 21 01 10 00 00 00 1b 89 ab eb b7 fd 47 e4
e1 c5 ed eb e4 1f f3 96 2d d3 2b 55 de e6 cb aa
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff

修改8字节

writeeeprom 8 46881faa2ffdb2e9

查看修改后值

sh>
printeeprom 0 256
c0 a9 21 01 10 00 00 00 46 88 1f aa 2f fd b2 e9
e1 c5 ed eb e4 1f f3 96 2d d3 2b 55 de e6 cb aa
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff

继续修改8字节

sh>
writeeeprom 16 2826160a48443d45

继续修改8字节

sh>
writeeeprom 24 4b47685e29781f5c

查看最终修改后结果

sh>
printeeprom 0 256
c0 a9 21 01 10 00 00 00 46 88 1f aa 2f fd b2 e9
28 26 16 0a 48 44 3d 45 4b 47 68 5e 29 78 1f 5c
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff

.总结

以上实现了自由修改EEPROM的工具。可以看出以上IO模拟IIC的代码非常简单容易移植,非常好用。包括eeprom的读写实现也可以作为库代码使用,也是按照开头的思想实现的。

很多设备的参数都是存储在EEPROM里的,有了这个工具我们就可以进行自由的改写,甚至harkclone某些设备了,这也可以作为我们今后瑞士军刀调试工具的一个功能。我们延续一贯的精简线路,设计积累自已的轮子,用时才能真香