微波EDA网,见证研发工程师的成长!
首页 > 研发问答 > 嵌入式设计讨论 > FPGA,CPLD和ASIC > 4.测试Ricoboard开发板上的eeprom功能-1

4.测试Ricoboard开发板上的eeprom功能-1

时间:10-02 整理:3721RD 点击:
EEPROM是Electrically Erasable Programmable Read-Only Memory的简写,可以翻译为电可擦可编程只读存储器,是一种掉电后数据不丢失的存储芯片。专门用于需要断电保存数据的情况下。据说有的eeprom设备可以在断电的情况下保存数据100年左右。EEPROM可以在电脑上或专用设备上擦除已有信息,重新编程。很遗憾我们的开发板直接将写保护拉高,导致我们无法写,只能读。
CAT24C256w是我们开发板上使用的eeprom芯片,是安森美半导体((ON Semiconductor)的产品,具有以下特点:256kbit串行电可擦的可编程只读存储器,8引脚双排直插式封装,具有结构紧凑、存储容量大等特点,可以在2线总线上并接4片该IC,特别适用于具有高容量数据储存要求的数据采集系统。AT24C256采用SOP-8封装。i2c编程接口,每页64字节,共512页,256kb的存储空间。
关于读写的i2c时序暂时不说,等后面可以测试完写操作后在一起总结。
下面首先来看看测试情况。
第一种情况,在uboot中的测试。
board/ti/am43xx文件夹下board.c中的get_header函数为我们提供了可以读写cat24c256器件的例程,代码逻辑非常简洁,看看函数名字估计就可以猜到功能就不一一介绍,主要代码如下:

  1. int get_header(myir_header_t *header)
  2. {
  3.         u32 i2c_bus_old = i2c_get_bus_num();
  4.         printf("get_header i2c_bus_old=0x%x\n", i2c_bus_old);

  5.         if (!header)
  6.                 return -1;

  7.         /* Set current i2c bus, the eeprom was mounted to i2c1 */
  8.         if (i2c_set_bus_num(0)) {
  9.                 printf("Can not set the current i2c bus to 1\n");
  10.                 goto err;
  11.         }
  12.         printf("get_header i2c_probe CONFIG_SYS_I2C_SLAVE=0x%x LCD_HEADER_I2C_ADDR=0x%x\n", CONFIG_SYS_I2C_SLAVE, LCD_HEADER_I2C_ADDR);

  13.         if (i2c_probe(LCD_HEADER_I2C_ADDR)) {
  14.                 printf("Not found the LCD header IC\n");
  15.                 goto err;
  16.         }
  17.         printf("get_header i2c_read LCD_HEADER_I2C_ADDR=0x%x 0,2 header sizeof(header)\n", LCD_HEADER_I2C_ADDR);

  18.         if (i2c_read(LCD_HEADER_I2C_ADDR,
  19.                                  0,
  20.                                  2,
  21.                                  (unsigned char *)header,
  22.                                  sizeof(myir_header_t))) {
  23.                 printf("Failed to read lcd header\n");
  24.                 goto err;
  25.         }
  26.         printf("header->page1=%s, header->page2=%s\n", header->page1, header->page2);
  27.         printf("header->header=0x%x header->type=%s, header->subtype=%s, header->revision=%s, header->rchksum=0x%x\n", header->header, header->type, header->subtype, header->revision, header->rchksum);

  28.         if (check_header(header))
  29.                 goto err;
  30.        
  31.         i2c_set_bus_num(i2c_bus_old);
  32.         return 0;
  33.        
  34. err:
  35.         /* Restore current i2c bus to default */
  36.         i2c_set_bus_num(i2c_bus_old);
  37.         return -1;
  38. }

复制代码

注意:1.cat24c256器件在i2c总线0上,而不是原来代码中的1上;
          2.cat24c256器件i2c地址为0x50,而不是原来的0x51;
          3.为了方便我直接在header结构体中添加了两个64字节的字符数组。
下面是一些运行的log信息

  1. U-Boot 2013.10 (Nov 04 2016 - 09:10:36)

  2. I2C:   ready
  3. DRAM:  512 MiB
  4. lcd_bl_init
  5. MMC:   OMAP SD/MMC: 0, OMAP SD/MMC: 1
  6. SF: Detected S25FL128S_64K with page size 256 Bytes, erase size 64 KiB, total 16 MiB, mapped at 30000000
  7. Init vbus0: 500mA@5V, OFF
  8. Init vbus1: 500mA@5V, ON
  9. get_header i2c_bus_old=0x1
  10. get_header i2c_probe CONFIG_SYS_I2C_SLAVE=0x1 LCD_HEADER_I2C_ADDR=0x50
  11. get_header i2c_read LCD_HEADER_I2C_ADDR=0x50 0,2 header sizeof(header)
  12. header->page1=MYiR EEPROM SECOND TEST STR?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????, header->page2=????????????????????????????????????????????????????????????????????????????????????????????????
  13. header->header=0xffff header->type=??????????????????????????????, header->subtype=??????????????????????, header->revision=????????, header->rchksum=0xff
  14. MYIR_HEADER: Invalid header: 0x9FF8C173
  15. Net:   cpsw
  16. Hit any key to stop autoboot:  0
  17. U-Boot#

复制代码

还有一中情况,可以使用uboot中cmd命令读eeprom。测试命令和运行结果如下:

  1. U-Boot# eeprom read 50 0 0 32

  2. EEPROM @0x50 read: addr 00000000  off 0000  count 50 ... do_eeprom pheader->page1=MYiR EEPROM SECOND TEST STR??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????, pheader->page2=?????????????????????????????????????????????????????????????????????????????????????????????????
  3. 0x4d0x590x690x520x200x450x450x500x520x4f0x4d0x200x530x450x430x4f0x4e0x440x200x540x450x530x540x200x530x540x520xff0xff0xff0xff0xff0xff0xff0xff0xff0xff0xff0xff0xff0xff0xff0xff0xff0xff0xff0xff0xff0xff0xff0xff0xff0xff0xff0xff0xff0xff0xff0xff0xff0xff0xff0xff0xff
  4. done

复制代码

不过原来的代码有点问题,稍微修改一下即可。开始我对“?”字符很不理解,现在就把它理解为0xff即可。

  1. int do_eeprom ( cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
  2. {
  3.         myir_header_t mheader;
  4.         myir_header_t *pheader;
  5.         pheader = &mheader;
  6.         int i = 0;
  7.         memset(&mheader, '\0', sizeof(myir_header_t));
  8.         //省略1
  9. #if 1
  10.                         rcode = eeprom_read (dev_addr, off, (unsigned char *)pheader, sizeof(myir_header_t));
  11. #else
  12.                         rcode = eeprom_read (dev_addr, off, (uchar *) addr, cnt);

  13. #endif               
  14.         printf("do_eeprom pheader->page1=%s, pheader->page2=%s\n", pheader->page1, pheader->page2);
  15.         for(i = 0; i page1) +i));
  16.         }                        puts ("\n");
  17.         //省略2
  18. }

复制代码

uboot可以理解为一个小号的linux kernel,还可以做很多事情,只是这样需要反复拷贝编译文件到tf卡,我们还是专心使用tftp和nfs学习kernel的相关知识吧。
kernel对i2c的支持非常到位,关于i2c子系统的框架就不在介绍,首先看看i2c-0的设备情况,如下图:


查看0-0050设备节点的name,如下:
root@m437x-evm:/sys/class/i2c-dev/i2c-0/device/0-0050# cat name
24c256
与dts文件myir_ricoboard.dts里面的内容对应起来。
&i2c0 {
                status = "okay";
              pinctrl-names = "default";
        pinctrl-0 = ;
        ov2659@30 {
                compatible = "ti,ov2659";
                reg = ;
                port {
                        ov2659_1: endpoint {
                                remote-endpoint = ;
                                mclk-frequency = ;
                        };
                };
        };
        cat24c256@50 {
                compatible = "24c256";
                reg = ;
                pagesize = ;
        };
};
我们可以访问/dev/i2c-0这个设备节点,使用ioctl方式读取eeprom里面的内容,应用程序代码如下。

  1. #include
  2. #include
  3. #include
  4. #include
  5. #include
  6. #include
  7. #define CHIP_ADDR 0x50   //24CXX
  8. #define PAGE_SIZE 64 //根据自己的数据手册
  9. #define I2C_DEV "/dev/i2c-0"
  10. static int read_eeprom(int fd,char buff[],int addr,int count)
  11. {
  12.      int res;
  13.      lseek(fd, 64, SEEK_SET);
  14.      if (write(fd,&addr,1)!=1)
  15.      {
  16.     printf("Can't write %s's addr %d\n",I2C_DEV,addr);
  17.     return -1;
  18.      }
  19.      res = read(fd,buff,count);
  20.      printf("read %d bytes at 0x%02x\n\r",res,addr);
  21.      return res;
  22. }
  23. static int write_eeprom(int fd,char buff[],int addr,int count)
  24. {
  25.    int res;
  26.    int i;
  27.    static char sendbuffer[PAGE_SIZE+1];
  28.   
  29.    memcpy(sendbuffer+1,buff,count);
  30.    sendbuffer[0]=addr;
  31.    
  32.    res = write(fd,&sendbuffer,count+1);
  33.    printf("write %d bytes at 0x%02x buff[0]=%c\n",res,sendbuffer[0], buff[0]);
  34.    return res;
  35. }
  36. int main(void)
  37. {
  38. int fd,i,res;
  39. unsigned char str1[PAGE_SIZE] = "aaaaaaaaaaaaaaaaaaaaaaaaa";
  40. unsigned char s2[PAGE_SIZE] = "11111111111111111111111111111111";
  41. unsigned char buf[PAGE_SIZE] = {0};

  42. fd=open(I2C_DEV,O_RDWR);
  43. if(fd 0x4d= \n", 0x4d, 0x4d);
  44.         read_eeprom (fd,buf, 0, 32);
  45.     printf("=2=buf = %s\n 0x4d= \r", buf, 0x4d);
  46.     close(fd);
  47.     return 0;
  48. }

复制代码

编译后运行结果如下:

  1. root@m437x-evm:/opt# ./eeprom_test
  2. 0x4d= 0x4d=
  3. read 32 bytes at 0x00
  4. =2=buf = MYiR EEPROM SECOND TEST STR?????

复制代码

读出的内容跟uboot中的一样。这个程序使用了cat24c256设备的Immediate Address Read方式和Sequential Read方式。
在应用程序还可以使用另外一种方式来读取eeprom,因为代码比较多,我就只贴关键代码,其他代码见附件。

  1. int
  2. i2c_read_data(u16 addr, u8 offset, u8 *val)
  3. {
  4.         int i,ret = 0;

  5.         struct i2c_rdwr_ioctl_data *data;

  6.         if ((data = (struct i2c_rdwr_ioctl_data *)malloc(sizeof(struct i2c_rdwr_ioctl_data))) == NULL)
  7.         return -1;

  8.         data->nmsgs = 2;
  9.         if ((data->msgs = (struct i2c_msg *)malloc(data->nmsgs * sizeof(struct i2c_msg))) == NULL) {
  10.                 ret = -1;
  11.                 goto errexit3;
  12.         }
  13.         if ((data->msgs[0].buf = (unsigned char *)malloc(sizeof(unsigned char) * 64)) == NULL) {
  14.                 ret = -1;
  15.                 goto errexit2;
  16.         }
  17.         if ((data->msgs[1].buf = (unsigned char *)malloc(sizeof(unsigned char) * 64)) == NULL) {
  18.                 ret = -1;
  19.                 goto errexit1;
  20.         }

  21.         data->msgs[0].addr = addr;
  22.         data->msgs[0].flags = 0;
  23.         data->msgs[0].len = 1;
  24.         data->msgs[0].buf[0] = offset;

  25.         data->msgs[1].addr = addr;
  26.         data->msgs[1].flags = I2C_M_RD;
  27.         data->msgs[1].len = 64;                        //original data is 1
  28.         data->msgs[1].buf[0] = 0;

  29.         if ((ret = __i2c_send(fd, data)) msgs[1].len=%d\n", data->msgs[1].len);
  30.         for(i = 0 ;i msgs[1].len; i++)
  31.                 val[i] = data->msgs[1].buf[i];

  32. errexit0:
  33.         free(data->msgs[1].buf);
  34. errexit1:
  35.         free(data->msgs[0].buf);
  36. errexit2:
  37.         free(data->msgs);
  38. errexit3:
  39.         free(data);

  40.         return ret;
  41. }

复制代码

这个程序使用了cat24c256设备的Selective Read方式。
第三个应用程序也可以读取eeprom的数据,只是需要kernel支持。
make ARCH=arm CROSS_COMPILE=${RICO_CROSSTOOL} menuconfig
Device Drivers  ---> Misc devices  ---> EEPROM support  --->   I2C EEPROMs / RAMs / ROMs from most vendors

编译kernel,加载这个kernel。我们可以在发现如下信息,跟前面的相比多一个设备节点,直接cat这个设备节点就可以读到eeprom的全部内容。
root@m437x-evm:/sys/class/i2c-dev/i2c-0/device/0-0050# ls -l
lrwxrwxrwx    1 root     root             0 Jun  9 22:40 driver -> ../../../../../bus/i2c/drivers/at24
-rw-------    1 root     root         32768 Jun  9 22:40 eeprom
-r--r--r--    1 root     root          4096 Jun  9 22:40 modalias
-r--r--r--    1 root     root          4096 Jun  9 22:40 name
drwxr-xr-x    2 root     root             0 Jun  9 22:40 power
lrwxrwxrwx    1 root     root             0 Jun  9 22:39 subsystem -> ../../../../../bus/i2c
-rw-r--r--    1 root     root          4096 Jun  9 22:39 uevent
应用程序读取源代码如下:

  1. #include
  2. #include
  3. #include

  4. #define EEPROM_DEVICE "/sys/devices/44000000.ocp/44e0b000.i2c/i2c-0/0-0050/eeprom"
  5. #define TEST_STR "eeprom write/read test!"

  6. int main(void)
  7. {
  8.         int fd;
  9.         struct stat eeprom_stat;
  10.         char read_buf[64] = { '\0' };

  11.         fd = open(EEPROM_DEVICE, O_RDWR);
  12.         if (fd < 0) {
  13.                 printf("open eeprom unsuccess\n");
  14.                 return;
  15.         }

  16.         if (stat(EEPROM_DEVICE, &eeprom_stat) < 0) {
  17.                 perror("failed to get eeprom status");
  18.         } else {
  19.                 printf("\neeprom size: %d KB\n\n", eeprom_stat.st_size/1024);
  20.         }
  21. /*        lseek(fd, 64, SEEK_SET);

  22.         printf("write \'%s\' to eeprom\n", TEST_STR);
  23.         if (write(fd, TEST_STR, strlen(TEST_STR)) < 0) {
  24.                 perror("write to eeprom failed\n");
  25.                 return;
  26.         }
  27. */        lseek(fd, 0, SEEK_SET);

  28.         if (read(fd, read_buf, sizeof(read_buf)) < 0) {
  29.                 printf("read back failed\n");
  30.                 return;
  31.         }

  32.         printf("\nget the following string from eeprom:\n%s\n\n", read_buf);
  33.        
  34.         return 0;
  35. }

复制代码

应用程序运行结果如下:


  1. root@m437x-evm:/opt# ./at24_eeprom_test

  2. eeprom size: 32 KB


  3. get the following string from eeprom:
  4. MYiR EEPROM SECOND TEST STR?????????????????????????????????????

复制代码



以上三个应用程序都是我参考他人的成果,特此向哪些好心人们表示感谢。
后面可以在eeprom上进行写操作在继续eeprom的学习。


2.63 KB, 下载次数: 4

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top