最近拿到一块DS2431芯片,需要进行控制操作。虽然最后把芯片玩坏了(被锁死了),但还是成功实现了功能,这里简单记录一下。
1. DS2431芯片
1.1 芯片概述
DS2431 是一款 1024 位 1-Wire® EEPROM芯片,由四个存储器页组成,每页 256 位。数据先被写入一个8 字节暂存器中,经校验无误后复制到EEPROM存储器。其特点在于,四个存储器页相互独立,可以单独设置写保护或EPROM仿真模式,在EPROM仿真模式下,所有位的状态只能从 1 变成 0。 DS2431 通过一根1-Wire总线进行通信。通信采用Dallas Semiconductor标准的 1-Wire协议。每个器件都有唯一 的、不能更改的 64 位ROM地址码,该地址码由工厂光刻写入芯片。在一个多点的 1-Wire网络环境中,该地址码用于对器件进行寻址。
1.2 芯片存储器结构
DS2431总共有144个byte,其中地址0000 ~ 007FH包含了4页,总共128个byte的内存可供读写;0081H~0084H分别用于控制前四页的写保护,一旦设置了写保护,对应页讲无法进行写操作。
1.3 几个重要的指令及操作方式
0xCCH:单一从机总线系统中,主机使用此命令访问存储器命令;
0x0FH:写缓存器数据命令
0xAAH:读缓存器数据命令
0x55H:拷贝缓存器数据到内存命令
2. DS2431读写操作
2.1 DS2431数据转换流程
要成功实现将数据写入DS2431的00~7FH地址去,首先要将数据写到缓存器中去,然后通过缓存器的校验无误,再通过数据拷贝命令,将缓存器数据复制到内存中去。
2.2 DS2431读写一个字节
1、初始化DS2431的GPIO输入输出引脚
这里需要注意,当配置GPIO为输入模式时,一定要配置为上拉模式,不然可能读取不到数据,全为0XFF。这里我用的是STM32F767单片机,IO用的是PH2。
#define DQ_MODE_IN() {GPIOH->MODER&=~(3<<(2*2));GPIOH->MODER|=0<<2*2;GPIOH->PUPDR&=~(3<<(2*2));GPIOH->PUPDR|=1<<2*2;}
#define DQ_MODE_OUT() {GPIOH->MODER&=~(3<<(2*2));GPIOH->MODER|=1<<2*2;GPIOH->OSPEEDR&=~(3<<(2*2));}
#define DQ_OUT(x) ((x)?HAL_GPIO_WritePin(GPIOH, GPIO_PIN_2, GPIO_PIN_SET):HAL_GPIO_WritePin(GPIOH, GPIO_PIN_2, GPIO_PIN_RESET))
#define DQ_READ HAL_GPIO_ReadPin(GPIOH,GPIO_PIN_2)
2、DS2431向总线发送一个字节数据
void bus_sendbyte(uint8_t dat)
{
uint8_t count;
DQ_MODE_OUT();
DQ_OUT(1);
for(count=0;count<8;count++)
{
if((dat&(0x01<<count))==0)
{
DQ_OUT(0);
delay_us(55);
DQ_OUT(1);
delay_us(5);
}
else
{
DQ_OUT(0);
delay_us(5);
DQ_OUT(1);
delay_us(55);
}
}
DQ_OUT(1);
DQ_MODE_IN();
delay_us(100);
}
3、DS2431向总线接收一个字节数据
uint8_t bus_getbyte(void)
{
uint8_t dat=0;
uint8_t count;
for(count=0;count<8;count++)
{
DQ_MODE_OUT() ;
DQ_OUT(0);
delay_us(5);
DQ_OUT(1);
DQ_MODE_IN();
delay_us(10);
if(DQ_READ==GPIO_PIN_SET)
{
dat|=(0x01<<count);
}
delay_us(40);
}
delay_us(100);
return dat;
}
2.3 DS2431复位操作
每次对DS2431进行命令操作前,都需要进行复位,保证芯片的正常应答,在此之后,再进行相应的操作。
uint8_t bus_reset(void)
{
DQ_MODE_OUT() ;
DQ_OUT(1);
delay_ms(1);
DQ_OUT(0);
delay_us(500);
DQ_OUT(1);
DQ_MODE_IN();
delay_us(100);
if(DQ_READ==GPIO_PIN_RESET)
{
delay_us(150);
return OK;
}
else
{
delay_us(150);
return NG;
}
}
2.4 DS2431写缓存器及查看操作
1、写缓存器
前面我们提到,要想将数据写入DS2431的内存,首先要将数据写缓存器,以下就是写数据到缓存器的操作。
uint8_t Write_To_Sp(uint8_t addr,uint8_t *data)
{
uint8_t i = 0,crc[2]={0};
uint8_t crc_dat[11]={0};
uint16_t crc_result = 0;
if((data==NULL)||(addr>0x8F))
return 1;
if(bus_reset()==NG)
{
printf("bus_reset err!!!\r\n");
return 1;
}
else
{
bus_sendbyte(0xcc);
bus_sendbyte(0x0f);
bus_sendbyte(addr);
bus_sendbyte(0x00);
crc_dat[0]=0x0f;
crc_dat[1]=addr;
crc_dat[2]=0x00;
for(i=0;i<8;i++)
{
bus_sendbyte(data[i]);
crc_dat[i+3]=data[i];
}
crc_result = CRC16(crc_dat,11);
crc[0] = bus_getbyte();
crc[1] = bus_getbyte();
if(((crc[0]<<8)+crc[1])!=((uint16_t)~crc_result))
{
printf("Write_To_Sp err\r\n");
return 1;
}
//printf("read crc :%x ,cal crc:%x\r\n",(crc[0]<<8)+crc[1],~crc_result);
return 0;
}
}
当向缓存器正常写入数据后,缓存器会返回一个crc16的校验,通过这个校验值,我们可以判断写入数据的正确性。关于DS2431的校验,它使用的是CRC-16/MAXIM的校验方式,这个需要注意。
2、读缓存器
通过读缓存器中的内容,我们可以更加直观判断写入的数据的正确性。
void Read_Cur_Sp(uint8_t *data)
{
uint8_t i = 0,ta_es[3]={0},crc[2]={0};
if(bus_reset()==NG)
{
printf("bus_reset err!!!\r\n");
}
else
{
bus_sendbyte(0xcc);
bus_sendbyte(0xaa);
ta_es[0]=bus_getbyte();
ta_es[1]=bus_getbyte();
ta_es[2]=bus_getbyte();
printf("TA1:%x TA2:%x E/S:%x\r\n",ta_es[0],ta_es[1],ta_es[2]);
for(i=0;i<8;i++)
{
data[i] = bus_getbyte();
printf("Read_Sp data[%d]:%x\r\n",i,data[i]);
}
crc[0] = bus_getbyte();
crc[1] = bus_getbyte();
printf("crc:%x %x\r\n",crc[0],crc[1]);
}
}
2.5 DS2431复制缓存器操作
在确定校验值正常的情况下,我们就可以使用复制命令,将缓存器中的值复制到存储器当中去了。其中,addr表示复制到存储器的地址。
uint8_t Copy_Spdata_To_Mem(uint8_t addr)
{
uint8_t i = 0,crc[2]={0},ret=0;
if(bus_reset()==NG)//???
{
printf("bus_reset err!!!\r\n");
return 1;
}
else
{
bus_sendbyte(0xcc);
bus_sendbyte(0x55);
bus_sendbyte(addr);
bus_sendbyte(0x00);
bus_sendbyte(0x07);
delay_us(1000);
ret = bus_getbyte();
if(ret!=0xaa)
{
printf("Copy_Spdata_To_Mem err!!!\r\n");
return 1;
}
else
{
//printf("Copy_Spdata_To_Mem Success!!!\r\n");
return 0;
}
}
}
2.6 DS2431复制缓存器操作
最后,我们可以通过读存储器内容,看看我们写入的数据是否正确。
uint8_t Read_Mem_Data(uint8_t addr,uint8_t *read_buf,uint8_t len)
{
uint8_t i = 0,crc[2]={0},ret=0,data[144];
if((read_buf==NULL)||(len>128)||(addr>0x8F))
{
return 1;
}
if(bus_reset()==NG)
{
printf("bus_reset err!!!\r\n");
}
else
{
bus_sendbyte(0xcc);
bus_sendbyte(0xf0);
bus_sendbyte(addr);
bus_sendbyte(0x00);
for(i=0;i<len;i++)
{
read_buf[i] = bus_getbyte();
}
}
}
3 结果
通过以上步骤,我们就可以完成一片DS2431芯片的读写操作,最后看看结果。
可以看到,数据是写进去了,也读出来了,但是就像我开头说的那样,我为了验证DS2431的写保护功能,把页写来保护起了,并且,把写保护寄存器也保护起来了,导致最后无法解除写保护(我试了多次,都不行),芯片就GG了。如果大家有解除保护的办法,希望能指教一下,谢谢。