接上文
以上实现了IO模拟IIC接口,整个过程很自然,参考时序图操作IO即可。但是是骡子是马拉出来遛遛。那么我们就基于此来进行EEPROM的读写测试吧,以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 READ和Byte Write实际应用基本不会使用,随机读和PAGE写即可包含。
实现起来也就很简单了,初始化和解除初始化即调用底层对应接口,自己无需特殊处理。
随机读实现,直接按照时序图,分解到IIC的具体操作即可
其中#define CTRL_BYTE 0xA0
写也是类似
以上实现了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
{
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);
}
输入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字节
writeeeprom 16 2826160a48443d45
继续修改8字节
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里的,有了这个工具我们就可以进行自由的改写,甚至hark,clone某些设备了,这也可以作为我们今后”瑞士军刀调试工具”的一个功能。我们延续一贯的精简线路,设计积累自已的轮子,用时才能”真香”。