【TINY4412】LINUX移植笔记:(24)设备树EEPROM驱动
2018-01-16 08:46
555 查看
【TINY4412】LINUX移植笔记:(24)设备树 EEPROM驱动
宿主机 : 虚拟机 Ubuntu 16.04 LTS / X64目标板[底板]: Tiny4412SDK - 1506
目标板[核心板]: Tiny4412 - 1412
LINUX内核: 4.12.0
交叉编译器: arm-none-linux-gnueabi-gcc(gcc version 4.8.3 20140320)
日期: 2017-9-7 19:12:14
作者: SY
简介
EEPROM的型号为:
24AA025E48查看数据手册:
容量:
2Kbit
总线:
I2C
页大小:
16-Byte
备注地址:
1010000也就是
0x50,
A2 = 0
A1 = 0
A0 = 0查看手册:
从上图看一看出最后一位为
R/W位,在读写数据时用到,先不用管这个位,高
4位定死为
10,那么决定
I2C地址的只剩下
A2 A1 A0。
综上所述:地址为
1010000和原理图上的地址相符。
移植
知道上述的条件,已经可以移植了。I2C既然称为总线,那么基本上不用你来写相关的总线驱动,
Linux内核肯定已经写好
I2C框架,框架必然是一个与不依赖任何底层实现的东西,只定义接口,实现由各个具体的平台来实现。找到
drivers\i2c\busses\i2c-s3c2410.c,这是三星的
I2C底层实现。
在框架的基础上支持多个具体的
I2C设备,找到
drivers\misc\eeprom\at24.c,这个驱动支持
AT24C02、
AT24C64等
EEPROM,其中
AT24C16和
24AA025E48类似,都是
16Bytes页大小。
设备树
写自己的dts
&i2c_0 { samsung,i2c-sda-delay = <100>; samsung,i2c-max-bus-freq = <400000>; status = "okay"; eeprom: eeprom@50 { compatible = "atmel,24c16", "microchip, 24aa025e48"; reg = <0x50>; pagesize = <16>; }; };
reg填写
I2C地址。
menuconfig
Device Drivers ---> Misc devices ---> EEPROM support ---> <*> I2C EEPROMs / RAMs / ROMs from most vendors I2C support ---> I2C Hardware Bus support ---> <*> S3C2410 I2C Driver
烧录
[ 0.398542] s3c-i2c 13860000.i2c: slave address 0x00 [ 0.398552] s3c-i2c 13860000.i2c: bus frequency set to 390 KHz [ 0.398802] s3c-i2c 13860000.i2c: i2c-0: S3C I2C adapter [ 2.849104] at24 0-0050: 2048 byte 24c16 EEPROM, writable, 16 bytes/write
查看设备节点
[root@TINY4412:~]# ls /dev/i2c-0 /dev/i2c-0
APP
/* * eeprom driver for tiny4412 * * Copyright (c) 2017 * Author: SY <1530454315@qq.com> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include <signal.h> #include <stdbool.h> #include <pthread.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/epoll.h> #include <sys/ioctl.h> #include <sys/mman.h> #include <linux/i2c-dev.h> #include <linux/i2c.h> #if 1 static void help(void) { printf("Usage:\n"); printf(" read: ./eeprom r [i2c_addr] [dev_addr] [lenth]\n"); printf(" write: ./eeprom w [i2c_addr] [dev_addr] [lenth] ...\n"); } #endif #pragma pack(1) struct i2c_data { uint8_t addr; uint8_t data[0]; }; #pragma pack() bool i2c_write(int fd, uint8_t i2c_addr, uint16_t dev_addr, uint8_t *buf, uint16_t len) { bool ret = true; int i; struct i2c_rdwr_ioctl_data i2c; i2c.nmsgs = 1; i2c.msgs = (struct i2c_msg *)calloc(i2c.nmsgs, sizeof(struct i2c_msg)); struct i2c_msg *p = &i2c.msgs[0]; p->addr = i2c_addr; p->flags = 0; p->len = sizeof(struct i2c_data) + len; p->buf = calloc(1, p->len); struct i2c_data *data = (struct i2c_data *)p->buf; data->addr = dev_addr; memcpy(data->data, buf, len); int res = ioctl(fd, I2C_RDWR, &i2c); if (res & 4000 lt; 0) { perror("Write ioctl error"); ret = false; goto error; } printf("WRITE\n"); for (i=0; i<len; ++i) { printf("%x ", buf[i]); } printf("\n"); error: free(p->buf); free(i2c.msgs); return ret; } bool i2c_read(int fd, uint8_t i2c_addr, uint16_t dev_addr, uint8_t *buf, uint16_t len) { bool ret = true; struct i2c_rdwr_ioctl_data i2c; i2c.nmsgs = 2; i2c.msgs = (struct i2c_msg *)calloc(i2c.nmsgs, sizeof(struct i2c_msg)); /* First Write addr */ struct i2c_msg *p1 = &i2c.msgs[0]; p1->addr = i2c_addr; p1->flags = 0; p1->len = sizeof(struct i2c_data); p1->buf = calloc(1, p1->len); ((struct i2c_data *)p1->buf)->addr = dev_addr; /* Read */ struct i2c_msg *p2 = &i2c.msgs[1]; p2->addr = i2c_addr; p2->flags = I2C_M_RD; p2->len = len; p2->buf = buf; int res = ioctl(fd, I2C_RDWR, &i2c); if (res < 0) { perror("Read ioctl error"); ret = false; goto error; } error: free(p1->buf); free(i2c.msgs); return ret; } int main(int argc, char **argv) { if (argc < 2) { help(); exit(0); } char rw = *argv[1]; if (rw == 'r') { if (argc != 5) { help(); exit(0); } } else if (rw == 'w') { if (argc != 6) { help(); exit(0); } } else { help(); exit(0); } int i2c_addr; sscanf(argv[2], "%x", &i2c_addr); int dev_addr; sscanf(argv[3], "%x", &dev_addr); uint16_t len = atoi(argv[4]); printf("> i2c_addr = %x, dev_addr = %x, lenth = %d\n", i2c_addr, dev_addr, len); int fd = open("/dev/i2c-0", O_RDWR); if(!fd) { printf("open /dev/i2c-0 return error\n"); exit(0); } int i; switch (rw) { case 'r': { uint8_t *buff = calloc(1, len); if (buff == NULL) { printf("calloc error!\n"); goto error1; } if (i2c_read(fd, i2c_addr, dev_addr, buff, len) == false) { free(buff); goto error1; } printf("READ:\n"); for (i=0; i<len; ++i) { printf("%x ", buff[i]); } printf("\n"); free(buff); break; } case 'w': { uint8_t *buff = calloc(1, len); if (buff == NULL) { printf("calloc error!\n"); goto error1; } memcpy(buff, argv[5], len); if (i2c_write(fd, i2c_addr, dev_addr, buff, len) == false) { free(buff); goto error1; } free(buff); break; } default: help(); break; } error1: close(fd); return 0; }
测试
[root@TINY4412:~]# ./tmp/eeprom Usage: read: ./eeprom r [i2c_addr] [dev_addr] [lenth] write: ./eeprom w [i2c_addr] [dev_addr] [lenth] ... [root@TINY4412:~]# ./tmp/eeprom w 50 0 10 0000000000 > i2c_addr = 50, dev_addr = 0, lenth = 10 WRITE 30 30 30 30 30 30 30 30 30 30 [root@TINY4412:~]# [root@TINY4412:~]# [root@TINY4412:~]# ./tmp/eeprom r 50 0 10 > i2c_addr = 50, dev_addr = 0, lenth = 10 READ: 30 30 30 30 30 30 30 30 30 30 [root@TINY4412:~]# [root@TINY4412:~]# [root@TINY4412:~]# [root@TINY4412:~]# ./tmp/eeprom w 50 0 5 12345 > i2c_addr = 50, dev_addr = 0, lenth = 5 WRITE 31 32 33 34 35 [root@TINY4412:~]# ./tmp/eeprom r 50 0 10 > i2c_addr = 50, dev_addr = 0, lenth = 10 READ: 31 32 33 34 35 30 30 30 30 30
如果数据写入到
EEPROM成功的话,断电重启后应该可以读取到之前写入的数据。重新上电…
[root@TINY4412:~]# ./tmp/eeprom r 50 0 10 > i2c_addr = 50, dev_addr = 0, lenth = 10 READ: 31 32 33 34 35 30 30 30 30 30
仍然和之前读取的结果一致!
参考
详解Linux-I2C驱动相关文章推荐
- 【TINY4412】LINUX移植笔记:(26)设备树ADC驱动
- 【TINY4412】LINUX移植笔记:(22)设备树LCD按键驱动
- 【TINY4412】LINUX移植笔记:(25)设备树RTC驱动
- 【TINY4412】LINUX移植笔记:(9)USB驱动
- 【TINY4412】LINUX移植笔记:(17)设备树HELLO WORLD驱动
- 【TINY4412】LINUX移植笔记:(18)设备树BEEP驱动
- 【TINY4412】LINUX移植笔记:(27)设备树LCD驱动
- 【TINY4412】LINUX移植笔记:(19)设备树KEY驱动
- 【TINY4412】LINUX移植笔记:(20)设备树LCD背光驱动
- 【TINY4412】LINUX移植笔记:(23)设备树LCD触摸屏驱动
- 【TINY4412】LINUX移植笔记:(6)eMMC驱动
- 【TINY4412】LINUX移植笔记:(13)SD卡驱动
- [linux驱动]linux块设备学习笔记(四)——请求处理
- linux4.10.8 内核移植(四)---字符设备驱动_led驱动程序
- 基于tiny4412的Linux内核移植 -- SD卡驱动移植(五)
- 【TINY4412】LINUX移植笔记:(8)PWM蜂鸣器
- linux-2.6.32在mini2440开发板上移植(14)之移植I2C-EEPROM 驱动
- 【TINY4412】LINUX移植笔记:(16)eMMC启动Linux内核
- [Linux驱动]字符设备驱动学习笔记(三)———高级
- 精通linux设备驱动开发 笔记