|
本帖最后由 soloforce 于 2013-11-18 21:17 编辑
发个i2c访问at24c256 eeprom(
at24c256.pdf
(362.27 KB, 下载次数: 18)
)的DIY,按例先上图。
用了四个at24c256, 并联在Cubieboard的TWI-1接口上,设备文件是/dev/i2c-1。下面我画的示意图有点小错,把WP脚接VCC了,会导致写保护(无法写入),必须悬空掉。
为了更清楚地了解at24c,给个设备编址说明,网上下载的,不过有错误,我已经修正了。
研究了一下午i2c on linux,终于写出了代码:
- /*
- * at24c256_i2c.c
- *
- * This script is a demo for AT24C256 EEPROM access via I2C on Cubieboard
- *
- * Author: soloforce, forum.cubietech.com
- * Date: 2013.11.18
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include <sys/ioctl.h>
- #include <linux/i2c-dev.h>
- // Cubieboard IO port PB18 & PB19 are configured to TWI1-SCK & TWI1-SDA (I2C-1)
- #define DEFAULT_AT24C256_DEV "/dev/i2c-1"
- // ATmega AT24C series EEPROM slave devices are addressed from 0x50~0x57
- // As for AT24C256, should be 0x50~0x53
- #define DEFAULT_AT24C256_ADDRESS 0x50
- // AT24C256 has 512 pages, 64 bytes each
- #define PAGE_BYTES 64
- typedef unsigned char uint8;
- typedef unsigned short uint16;
- /*
- * Open the i2c bus device
- */
- int init_at24c256_i2c(const char* device)
- {
- int fd=open(device, O_RDWR);
- if(fd<0){
- perror("Failed to open I2C device!");
- return -1;
- }
- ioctl(fd, I2C_TIMEOUT, 3); // i2c timeout, 1 for 10ms ; if too small, i2c may lose response
- ioctl(fd, I2C_RETRIES, 3); // i2c retry limit
-
- return fd;
- }
- /*
- * Page write (or partially page write), data_len should less than PAGE_BYTES
- *
- */
- int at24c256_write(int fd, int device_addr, uint16 offset, const char* data, int data_len)
- {
- struct i2c_rdwr_ioctl_data at24c256; // structure pass to i2c driver
- struct i2c_msg i2cmsg;
- if(data_len>PAGE_BYTES){
- printf("*** Warning: Page write mode should not exceed %d bytes, otherwise the current page will be rolled over!\n",PAGE_BYTES);
- }
- at24c256.nmsgs = 1; // message count in the structure
- at24c256.msgs = &i2cmsg;
- at24c256.msgs[0].len = 2 + data_len; // the offset address word is 2 bytes long, plus the buf_len
- at24c256.msgs[0].addr = device_addr; // i2c slave device address
- at24c256.msgs[0].flags = 0; // 0 for write; 1 for read
- at24c256.msgs[0].buf = (uint8 *)malloc( at24c256.msgs[0].len );
- if(!at24c256.msgs[0].buf){
- printf("at24c256_write(): Failed to allocate memory for i2c message buffer!\n");
- return -1;
- }
-
- at24c256.msgs[0].buf[0] = (uint8)(offset >> 8); // MSB first
- at24c256.msgs[0].buf[1] = (uint8)(offset); // LSB
- strncpy( at24c256.msgs[0].buf+2, data, data_len); // copy user's data to the structure buffer
- if(ioctl(fd, I2C_RDWR, (unsigned long)&at24c256)<0 ){ // write ioctl data to the i2c bus
- printf("at24c256_write(): Failed to write data to i2c device!\n");
- free(at24c256.msgs[0].buf);
- return -1;
- }
-
- free(at24c256.msgs[0].buf);
- return 0;
- }
- /*
- * Sequential read from AT24C256, data_len should less than PAGE_BYTES
- */
- int at24c256_read(int fd, int device_addr, uint16 offset, char* data, int data_len)
- {
- struct i2c_rdwr_ioctl_data at24c256; // structure pass to i2c driver
- struct i2c_msg i2cmsg[2]; // message count in the structure
- char dummy_write_buf[2];
-
- if(data_len>PAGE_BYTES){
- printf("*** Warning: Sequential read should not exceed %d bytes, otherwise the read data will be rolled over!\n",PAGE_BYTES);
- }
- // A dummy write operation should be done according to the AT24C256 i2c protocol
- at24c256.nmsgs = 2; // message count in the structure
- at24c256.msgs = i2cmsg;
- at24c256.msgs[0].len = 2; // the offset address word is 2 bytes long
- at24c256.msgs[0].addr = device_addr;
- at24c256.msgs[0].flags = 0; // 0 for write;
- at24c256.msgs[0].buf = dummy_write_buf;
- at24c256.msgs[0].buf[0] = (unsigned char)(offset >> 8); // write address
- at24c256.msgs[0].buf[1] = (unsigned char)(offset); // write address
- // read operation
- at24c256.msgs[1].len = data_len;
- at24c256.msgs[1].addr = device_addr;
- at24c256.msgs[1].flags = 1; // 1 for read; 0 for write
- at24c256.msgs[1].buf = data;
- if (ioctl(fd, I2C_RDWR, (unsigned long)&at24c256) < 0) {
- printf("at24c256_read(): Failed to read data from EEPROM via i2c!\n");
- return -1;
- }
- return 0;
- }
- /*
- * Show help message
- */
- void show_usage(char* argv[])
- {
- printf("%s <-d device> <-a address> [-o offset] [-r length] [-w data] [-h]\n",argv[0]);
- printf("\t-d device: i2c device file, like /dev/i2c-1 by default\n");
- printf("\t-a address: i2c slave device base address, like 0x50 by default\n");
- printf("\t-o offset: offset from base address, like 0x00, 0x10 ...\n");
- printf("\t-r length: read length bytes from at24c256 eeprom\n");
- printf("\t-w data: write to at24c256 eeprom\n");
- printf("\t-h: show help message\n\n");
- }
- int main(int argc, char* argv[])
- {
- char* device=DEFAULT_AT24C256_DEV;
- int slave_address=DEFAULT_AT24C256_ADDRESS;
- int offset=0x00; // default offset is 0
- int length=32; // read 32 bytes by default
- char* data=NULL;
- int rw_mode=1; // 0 for write, 1 for read;
- if(argc==1){
- show_usage(argv);
- return 0;
- }
- int i;
- while ((i = getopt(argc, argv, "d:a:o:r:w:n:h")) >= 0){
- switch(i){
- case 'd':
- device=optarg;
- break;
- case 'a':
- if (sscanf(optarg, "0x%x", &slave_address) != 1) {
- fprintf(stderr, "Cannot parse '%s' as i2c slave device address, example: '0x50'\n", optarg);
- return -1;
- }
- break;
- case 'o':
- if (sscanf(optarg, "%d", &offset) != 1) {
- fprintf(stderr, "Cannot parse '%s' as address offset, example: '32'\n", optarg);
- return -1;
- }
- break;
- case 'r':
- rw_mode=1;
- if (sscanf(optarg, "%d", &length) != 1) {
- fprintf(stderr, "Cannot parse '%s' as length, example: '17'\n", optarg);
- return -1;
- }
- break;
- case 'w':
- rw_mode=0;
- data=optarg;
- length=strlen(data);
- break;
- case 'h':
- show_usage(argv);
- return 0;
- break;
- }
- }
-
- int fd=init_at24c256_i2c(device);
- if(fd<0) return -1;
- printf("i2c device file:%s\nslave_address:0x%X\nR/W offset:0x%X\n",device, slave_address, offset);
- if(rw_mode==0){
- // test at24c256 write
- at24c256_write(fd, slave_address, offset, data, length);
- printf("try to write: %s (%d bytes)!\n",data,length);
- usleep(10000); // some delay is necessary for the write operation done
- }else if(rw_mode==1){
- // test at24c256 read
- char *buf=(char*)malloc(length+1);
- memset(buf,0,length+1);
- at24c256_read(fd, slave_address, offset, buf, length);
- usleep(10000); // necessary for the read operation done
-
- printf("read from at24c256 eeprom: %s (%d bytes)\n", buf, strlen(buf));
- free(buf);
- }
-
- close(fd);
- }
复制代码 |
|