From d973d6f8e12b16c3cdd84e63e19b61187424f4ce Mon Sep 17 00:00:00 2001 From: guowenxue <guowenxue@gmail.com> Date: Thu, 14 Mar 2024 10:06:12 +0800 Subject: [PATCH] Add AT24C EEPROM code --- modules/w25qflash.c | 33 + modules/at24c.c | 641 +++++++++++++++++++++++++++++++++++++ modules/sht20.c | 300 +++++++++++----- modules/w25qflash.h | 27 + 4 files changed, 880 insertions(+), 121 deletions(-) diff --git a/modules/at24c.c b/modules/at24c.c new file mode 100644 index 0000000..2c12f88 --- /dev/null +++ b/modules/at24c.c @@ -0,0 +1,641 @@ +/********************************************************************************* + * Copyright: (C) 2023 LingYun IoT System Studio + * All rights reserved. + * + * Filename: at24c.c + * Description: This file is AT24Cxx EEPROM code + * + * Version: 1.0.0(10/08/23) + * Author: Guo Wenxue <guowenxue@gmail.com> + * ChangeLog: 1, Release initial version on "10/08/23 17:52:00" + * + * Pin connection: + * AT24Cxx Raspberry Pi 40Pin + * VCC <-----> #Pin1(3.3V) + * SDA <-----> #Pin3(SDA, BCM GPIO2) + * SCL <-----> #Pin5(SCL, BCM GPIO3) + * GND <-----> GND + * + * /boot/config.txt: + * dtoverlay=i2c1,pins_2_3 + * + ********************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> +#include <string.h> +#include <unistd.h> +#include <libgen.h> +#include <getopt.h> +#include <time.h> +#include <errno.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <linux/types.h> +#include <linux/i2c.h> +#include <linux/i2c-dev.h> + +/*+----------------------+ + *| EEPROM Information | + *+----------------------+*/ + +/* AT24Cxx 7-bit I2C slave address */ +#define AT24C_CHIPADDR 0x50 + +enum +{ + AT24C01 = 1, + AT24C02 = 2, + AT24C04 = 4, + AT24C08 = 8, + AT24C16 = 16, + AT24C32 = 32, + AT24C64 = 64, + AT24C128 = 128, + AT24C256 = 256, + AT24C512 = 512, +} chipid_t; + +typedef struct i2c_s +{ + char *dev; /* I2C master device, /dev/i2c-N */ + int addr; /* 7-bits slave address */ + int fd; /* File description */ +} i2c_t; + +typedef struct eeprom_s +{ + int chip; /* Chip ID */ + uint32_t capacity; /* Chip size in bytes */ + int pagesize; /* Page size in bytes */ +} eeprom_t; + +#define EEP_INFO(_chip, _capacity, _pagesize) \ + .chip = _chip, \ + .capacity = _capacity, \ + .pagesize = _pagesize, \ + +static eeprom_t at24c_ids[] = { + { EEP_INFO(AT24C01, 128, 8) }, + { EEP_INFO(AT24C02, 256, 8) }, + { EEP_INFO(AT24C04, 512, 16) }, + { EEP_INFO(AT24C08, 1024, 16) }, + { EEP_INFO(AT24C16, 2048, 16) }, + { EEP_INFO(AT24C32, 4096, 32) }, + { EEP_INFO(AT24C64, 8192, 32) }, + { EEP_INFO(AT24C128, 16384, 64) }, + { EEP_INFO(AT24C256, 32768, 64) }, + { EEP_INFO(AT24C512, 65536, 128) }, +}; + +typedef struct at24c_s +{ + i2c_t i2c; + eeprom_t *eeprom; +} at24c_t; + +int at24c_init(at24c_t *at24c, int chip); +int at24c_read(at24c_t *at24c, int offset, uint8_t *buf, int size); +int at24c_write(at24c_t *at24c, int offset, uint8_t *data, int len); +int at24c_test(at24c_t *at24c); + +int i2c_init(i2c_t *i2c, char *i2cdev, int addr); +int i2c_write(i2c_t *i2c, uint8_t *data, int len); +int i2c_read(i2c_t *i2c, uint8_t *buf, int size); +void i2c_term(i2c_t *i2c); + +static inline void msleep(unsigned long ms); +void dump_buf(const char *prompt, char *buf, size_t len); + +static inline void banner(const char *progname) +{ + printf("%s program Version v1.0.0\n", progname); + printf("Copyright (C) 2023 LingYun IoT System Studio.\n"); +} + +static void program_usage(const char *progname) +{ + printf("Usage: %s [OPTION]...\n", progname); + printf(" %s is AT24Cxx EEPROM test program. \n", progname); + + printf(" -c[chipid ] Specify EEPROM chipID: 1,2,4,8...512 \n"); + printf(" -d[device ] Specify I2C device, such as /dev/i2c-1\n"); + printf(" -h[help ] Display this help information\n"); + printf(" -v[version ] Display the program version\n"); + + printf("\n"); + banner(progname); + return; +} + +int main(int argc, char **argv) +{ + char *progname=NULL; + char *dev="/dev/i2c-1"; + int chipid = AT24C256; /* default */ + at24c_t at24c; + int rv; + + struct option long_options[] = { + {"chip", required_argument, NULL, 'c'}, + {"device", required_argument, NULL, 'd'}, + {"version", no_argument, NULL, 'v'}, + {"help", no_argument, NULL, 'h'}, + {NULL, 0, NULL, 0} + }; + + progname = basename(argv[0]); + + /* Parser the command line parameters */ + while ((rv = getopt_long(argc, argv, "c:d:vh", long_options, NULL)) != -1) + { + switch (rv) + { + case 'c': /* Set chip ID: 1,2,4,8...512 */ + chipid = atoi(optarg); + break; + + case 'd': /* Set I2C device path: /dev/i2c-1 */ + dev = optarg; + break; + + case 'v': /* Get software version */ + banner(progname); + return EXIT_SUCCESS; + + case 'h': /* Get help information */ + program_usage(progname); + return 0; + + default: + break; + } + } + + if( at24c_init(&at24c, chipid) < 0 ) + { + printf("at24c initial failed!\n"); + return 1; + } + + if( i2c_init(&at24c.i2c, dev, AT24C_CHIPADDR) < 0 ) + { + printf("i2c initial failed!\n"); + return 2; + } + + if( at24c_test(&at24c) < 0 ) + { + return 3; + } + + i2c_term(&at24c.i2c); + return 0; +} + +/*+----------------------+ + *| EEPROM API functions | + *+----------------------+*/ + +int at24c_init(at24c_t *at24c, int chip) +{ + int i; + + if( !at24c ) + return -1; + + for(i=0; i<sizeof(at24c_ids)/sizeof(at24c_ids[0]); i++) + { + if( at24c_ids[i].chip == chip ) + { + at24c->eeprom = &at24c_ids[i]; + printf("Detect EEPROM AT24C%02d capacity %d bytes, pagesize %d bytes.\r\n", + chip, at24c->eeprom->capacity, at24c->eeprom->pagesize); + return 0; + } + } + + printf("EEPROM: Can not found EEPROM by chip ID[%d]\r\n", chip); + return -2; +} + +int at24c_test(at24c_t *at24c) +{ + eeprom_t *eeprom; + uint8_t buf[128]; + int i; + int addr = 0; + + if( !at24c ) + return -1; + + eeprom = at24c->eeprom; + + /* Read data before write */ + memset(buf, 0, sizeof(buf)); + if( at24c_read(at24c, addr, buf, sizeof(buf)) < 0 ) + { + return -2; + } + dump_buf("<<<EEPROM read data:\n", (char *)buf, sizeof(buf)); + + /* fill a page data */ + for(i=0; i<eeprom->pagesize; i++) + { + buf[i] = i; + } + + /* write a page data from the address not page alignment */ + if( at24c_write(at24c, addr+8, buf, eeprom->pagesize) < 0 ) + { + return -3; + } + + /* Read data after write */ + memset(buf, 0, sizeof(buf)); + if( at24c_read(at24c, addr, buf, sizeof(buf)) < 0 ) + { + return -2; + } + dump_buf("<<<EEPROM read data:\n", (char *)buf, sizeof(buf)); + + return 0; +} + +/* Figure 9. Page Write */ +int at24c_write_page(at24c_t *at24c, int offset, uint8_t *data, int len) +{ + uint8_t buf[256]; + int bytes, rv; + int addrlen; + eeprom_t *eeprom; + + if(!at24c || offset<0 || !data || !len) + return -1; + + eeprom = at24c->eeprom; + + /* exceeding EEPROM size */ + if( offset+len > eeprom->capacity ) + return -1; + + if( len > eeprom->pagesize ) + len = eeprom->pagesize; + + /* + * A temporary write buffer must be used which contains both the address + * and the data to be written, put the address in first based upon the + * size of the address for the EEPROM. + */ + if( eeprom->chip >= AT24C16) + { + buf[0]=(uint8_t)(offset>>8); + buf[1]=(uint8_t)(offset); + addrlen = 2; + } + else + { + buf[0]=(uint8_t)(offset); + addrlen = 1; + } + + /* Put the data in the write buffer following the address */ + memcpy(&buf[addrlen], data, len); + + /* Write a page of data at the specified address to the EEPROM. */ + rv = i2c_write(&at24c->i2c, buf, len+addrlen); + if( rv < 0 ) + printf("%s() write data failed\n", __func__); + + /* Must give a delay here to wait page write finish */ + msleep(5); + + return rv; +} + +int at24c_write(at24c_t *at24c, int offset, uint8_t *data, int len) +{ + int bytes; + eeprom_t *eeprom; + + if(!at24c || offset<0 || !data || len<0) + return -1; + + eeprom = at24c->eeprom; + + /* exceeding EEPROM size */ + if( offset+len > eeprom->capacity ) + return -1; + + /* The offset + write bytes shouldn't overflow that page, + * or it will over write the start bytes of this page */ + if( offset%eeprom->pagesize ) + bytes = eeprom->pagesize - offset%eeprom->pagesize; + + /* Write max one page at a time */ + while(len > 0) + { + if( at24c_write_page(at24c, offset, data, bytes) ) + { + return -2; + } + + len -= bytes; + data += bytes; + offset += bytes; + + bytes = len>eeprom->pagesize? eeprom->pagesize : len; + } + + return 0; +} + +/* Figure 12. Sequential Read */ +int at24c_read(at24c_t *at24c, int offset, uint8_t *buf, int size) +{ + struct i2c_rdwr_ioctl_data tr; + eeprom_t *eeprom; + uint8_t addr[2]; + int addrlen; + int bytes; + int rv = 0; + + if(!at24c || offset<0 || !buf || size<=0) + return -1; + + eeprom = at24c->eeprom; + + /* exceeding EEPROM size */ + if( offset+size > eeprom->capacity ) + return -1; + + memset(buf, 0, size); + + if( eeprom->chip >= AT24C16) + { + addr[0]=(uint8_t)(offset>>8); + addr[1]=(uint8_t)(offset); + addrlen = 2; + } + else + { + addr[0]=(uint8_t)(offset); + addrlen = 1; + } + + /* We can't call i2c_write() and i2c_read() because it will generate a + * stop condition after send the offset address, it doesn't compatible + * with EEPROM sequential read sequence; + */ + + + /* use I2C userspace API to send two message without stop condition */ + + tr.nmsgs = 2; + tr.msgs = malloc( sizeof(struct i2c_msg)*tr.nmsgs ); + if ( !tr.msgs ) + { + printf("%s() msgs malloc failed!\n", __func__); + return -2; + } + + /* Create the I2C message for writing the EEPROM offset address */ + tr.msgs[0].addr = at24c->i2c.addr; + tr.msgs[0].flags = 0; //write + tr.msgs[0].len = addrlen; + tr.msgs[0].buf = addr; + + /* Create the I2C message for reading data from EEPROM */ + memset(buf, 0, size); + tr.msgs[1].addr = at24c->i2c.addr; + tr.msgs[1].flags = I2C_M_RD; //read + tr.msgs[1].len = size; + tr.msgs[1].buf = buf; + + if( ioctl(at24c->i2c.fd, I2C_RDWR, &tr)<0 ) + { + printf("%s() ioctl failure: %s\n", __func__, strerror(errno)); + rv = -4; + } + + free( tr.msgs ); + return rv; +} + + +/*+----------------------+ + *| I2C API functions | + *+----------------------+*/ + +int i2c_init(i2c_t *i2c, char *i2cdev, int addr) +{ + if( !i2c || !i2cdev || !addr ) + return -1; + + memset(i2c, 0, sizeof(*i2c)); + i2c->addr = addr; + i2c->dev = i2cdev; + + if( (i2c->fd=open(i2cdev, O_RDWR)) < 0) + { + printf("open i2c device %s failed: %s\n", i2cdev, strerror(errno)); + return -1; + } + + return 0; +} + +void i2c_term(i2c_t *i2c) +{ + if( !i2c ) + return; + + if( i2c->fd > 0) + close(i2c->fd); + + return ; +} + +int i2c_write(i2c_t *i2c, uint8_t *data, int len) +{ + struct i2c_rdwr_ioctl_data tr; + int rv = 0; + + if( !data || len<= 0) + { + printf("%s() invalid input arguments!\n", __func__); + return -1; + } + + /* I2C device program API: ioctl() */ + tr.nmsgs = 1; + tr.msgs = malloc( sizeof(struct i2c_msg)*tr.nmsgs ); + if ( !tr.msgs ) + { + printf("%s() msgs malloc failed!\n", __func__); + return -2; + } + + tr.msgs[0].addr = i2c->addr; + tr.msgs[0].flags = 0; //write + tr.msgs[0].len = len; + tr.msgs[0].buf = malloc(len); + if( !tr.msgs[0].buf ) + { + printf("%s() msgs malloc failed!\n", __func__); + rv = -3; + goto cleanup; + } + memcpy(tr.msgs[0].buf, data, len); + + + if( ioctl(i2c->fd, I2C_RDWR, &tr)<0 ) + { + printf("%s() ioctl failure: %s\n", __func__, strerror(errno)); + rv = -4; + goto cleanup; + } + +cleanup: + if( tr.msgs[0].buf ) + free(tr.msgs[0].buf); + + if( tr.msgs ) + free(tr.msgs); + + return rv; +} + +int i2c_read(i2c_t *i2c, uint8_t *buf, int size) +{ + struct i2c_rdwr_ioctl_data tr; + int rv = 0; + + if( !buf || size<= 0) + { + printf("%s() invalid input arguments!\n", __func__); + return -1; + } + + tr.nmsgs = 1; + tr.msgs = malloc( sizeof(struct i2c_msg)*tr.nmsgs ); + if ( !tr.msgs ) + { + printf("%s() msgs malloc failed!\n", __func__); + return -2; + } + + tr.msgs[0].addr = i2c->addr; + tr.msgs[0].flags = I2C_M_RD; //read + tr.msgs[0].len = size; + tr.msgs[0].buf = buf; + memset(buf, 0, size); + + if( ioctl(i2c->fd, I2C_RDWR, &tr)<0 ) + { + printf("%s() ioctl failure: %s\n", __func__, strerror(errno)); + rv = -4; + } + + free( tr.msgs ); + return rv; +} + +/*+----------------------+ + *| Misc functions | + *+----------------------+*/ + +static inline void msleep(unsigned long ms) +{ + struct timespec cSleep; + unsigned long ulTmp; + + cSleep.tv_sec = ms / 1000; + if (cSleep.tv_sec == 0) + { + ulTmp = ms * 10000; + cSleep.tv_nsec = ulTmp * 100; + } + else + { + cSleep.tv_nsec = 0; + } + + nanosleep(&cSleep, 0); +} + +#define LINELEN 81 +#define CHARS_PER_LINE 16 +static char *print_char = +" " +" " +" !\"#$%&'()*+,-./" +"0123456789:;<=>?" +"@ABCDEFGHIJKLMNO" +"PQRSTUVWXYZ[\\]^_" +"`abcdefghijklmno" +"pqrstuvwxyz{|}~ " +" " +" " +" ???????????????" +"????????????????" +"????????????????" +"????????????????" +"????????????????" +"????????????????"; + +void dump_buf(const char *prompt, char *buf, size_t len) +{ + int rc; + int idx; + char prn[LINELEN]; + char lit[CHARS_PER_LINE + 2]; + char hc[4]; + short line_done = 1; + + if( prompt ) + printf("%s", prompt); + + rc = len; + idx = 0; + lit[CHARS_PER_LINE] = '\0'; + + while (rc > 0) + { + if (line_done) + snprintf(prn, LINELEN, "%08X: ", idx); + + do + { + unsigned char c = buf[idx]; + snprintf(hc, 4, "%02X ", c); + strncat(prn, hc, LINELEN); + + lit[idx % CHARS_PER_LINE] = print_char[c]; + } + while (--rc > 0 && (++idx % CHARS_PER_LINE != 0)); + + line_done = (idx % CHARS_PER_LINE) == 0; + if (line_done) + { + printf("%s %s\r\n", prn, lit); + } + } + + if (!line_done) + { + int ldx = idx % CHARS_PER_LINE; + lit[ldx++] = print_char[(int)buf[idx]]; + lit[ldx] = '\0'; + + while ((++idx % CHARS_PER_LINE) != 0) + strncat(prn, " ", sizeof(prn)-strlen(prn)); + + printf("%s %s\r\n", prn, lit); + + } +} diff --git a/modules/sht20.c b/modules/sht20.c index c3aa745..477adc6 100644 --- a/modules/sht20.c +++ b/modules/sht20.c @@ -10,7 +10,7 @@ * ChangeLog: 1, Release initial version on "10/08/23 17:52:00" * * Pin connection: - * STH20 Module Raspberry Pi Board + * SHT20 Raspberry Pi 40Pin * VCC <-----> #Pin1(3.3V) * SDA <-----> #Pin3(SDA, BCM GPIO2) * SCL <-----> #Pin5(SCL, BCM GPIO3) @@ -20,6 +20,7 @@ * dtoverlay=i2c1,pins_2_3 * ********************************************************************************/ + #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -53,22 +54,26 @@ MODE_RDWR, /* I2C device API use read()/write() */ }; -typedef struct sht2x_s +typedef struct i2c_s { - char *dev; /* SHT20 connect I2C device, /dev/i2c-N */ - int addr; /* SHT20 7-bits slave address */ + char *dev; /* I2C master device, /dev/i2c-N */ + int addr; /* 7-bits slave address */ int fd; /* File description */ int mode; /* I2C device API use read/write or ioctl mode */ -} sht2x_t; +} i2c_t; -int sht2x_init(sht2x_t *sht2x); -int sht2x_get_serialnumber(sht2x_t *sht2x, uint8_t *serialnumber, int size); -int sht2x_get_temp_humidity(sht2x_t *sht2x, float *temp, float *rh); +int sht2x_softreset(i2c_t *i2c); +int sht2x_get_serialnumber(i2c_t *i2c, uint8_t *serialnumber, int size); +int sht2x_get_temp_humidity(i2c_t *i2c, float *temp, float *rh); + +int i2c_init(i2c_t *i2c, int mode, char *i2cdev, int addr); +int i2c_write(i2c_t *i2c, uint8_t *data, int len); +int i2c_read(i2c_t *i2c, uint8_t *buf, int size); +void i2c_term(i2c_t *i2c); static inline void msleep(unsigned long ms); -static inline void dump_buf(const char *prompt, uint8_t *buf, int size); -static int i2c_write(sht2x_t *sht2x, uint8_t *data, int len); -static int i2c_read(sht2x_t *sht2x, uint8_t *buf, int size); +void print_buf(const char *prompt, uint8_t *buf, int size); +void dump_buf(const char *prompt, char *buf, size_t len); static inline void banner(const char *progname) { @@ -94,11 +99,13 @@ int main(int argc, char **argv) { + char *dev="/dev/i2c-1"; + char *progname=NULL; + int mode = MODE_IOCTL; int rv; float temp, rh; uint8_t serialnumber[8]; - char *progname=NULL; - sht2x_t sht2x; + i2c_t i2c; struct option long_options[] = { {"device", required_argument, NULL, 'd'}, @@ -110,21 +117,17 @@ progname = basename(argv[0]); - memset(&sht2x, 0, sizeof(sht2x)); - sht2x.addr = SHT2X_CHIPADDR; - sht2x.dev = "/dev/i2c-1"; - /* Parser the command line parameters */ while ((rv = getopt_long(argc, argv, "d:m:vh", long_options, NULL)) != -1) { switch (rv) { case 'd': /* Set I2C device path: /dev/i2c-1 */ - sht2x.dev = optarg; + dev = optarg; break; case 'm': /* Set I2C API mode: 0,1 */ - sht2x.mode = atoi(optarg) ? MODE_RDWR : MODE_IOCTL; + mode = atoi(optarg) ? MODE_RDWR : MODE_IOCTL; break; case 'v': /* Get software version */ @@ -140,19 +143,25 @@ } } - if( sht2x_init(&sht2x) < 0 ) + if( i2c_init(&i2c, mode, dev, SHT2X_CHIPADDR) < 0 ) + { + printf("I2C master device initial failed.\n"); + return 1; + } + + if( sht2x_softreset(&i2c) < 0 ) { printf("SHT2x initialize failure, maybe device not present!\n"); return 1; } - if( sht2x_get_serialnumber(&sht2x, serialnumber, 8) < 0) + if( sht2x_get_serialnumber(&i2c, serialnumber, 8) < 0) { printf("SHT2x get serial number failure\n"); return 3; } - if( sht2x_get_temp_humidity(&sht2x, &temp, &rh) < 0 ) + if( sht2x_get_temp_humidity(&i2c, &temp, &rh) < 0 ) { printf("SHT2x get get temperature and relative humidity failure\n"); return 3; @@ -160,14 +169,16 @@ printf("Temperature=%lf ℃ relative humidity=%lf.\n", temp, rh); - close(sht2x.fd); + i2c_term(&i2c); + + return 0; } -int sht2x_softreset(sht2x_t *sht2x) +int sht2x_softreset(i2c_t *i2c) { uint8_t buf[1]; - if( !sht2x || sht2x->fd<0 ) + if( !i2c || i2c->fd<0 ) { printf("%s line [%d] %s() get invalid input arguments\n", __FILE__, __LINE__, __func__ ); return -1; @@ -175,7 +186,7 @@ /* software reset SHT2x */ buf[0] = SOFTRESET; - if( i2c_write(sht2x, buf, 1) < 0 ) + if( i2c_write(i2c, buf, 1) < 0 ) { return -2; } @@ -185,35 +196,11 @@ return 0; } -int sht2x_init(sht2x_t *sht2x) -{ - if( (sht2x->fd=open(sht2x->dev, O_RDWR)) < 0) - { - printf("i2c device open failed: %s\n", strerror(errno)); - return -1; - } - - if( MODE_RDWR == sht2x->mode ) - { - /* set I2C mode and SHT2x slave address */ - ioctl(sht2x->fd, I2C_TENBIT, 0); /* Not 10-bit but 7-bit mode */ - ioctl(sht2x->fd, I2C_SLAVE, SHT2X_CHIPADDR); /* set SHT2x slave address 0x40*/ - } - - if( sht2x_softreset(sht2x) < 0 ) - { - printf("SHT2x softreset failure\n"); - return -2; - } - - return 0; -} - -int sht2x_get_temp_humidity(sht2x_t *sht2x, float *temp, float *rh) +int sht2x_get_temp_humidity(i2c_t *i2c, float *temp, float *rh) { uint8_t buf[4]; - if( !sht2x || !temp || !rh || sht2x->fd<0 ) + if( !i2c || !temp || !rh || i2c->fd<0 ) { printf("%s line [%d] %s() get invalid input arguments\n", __FILE__, __LINE__, __func__ ); return -1; @@ -222,35 +209,35 @@ /* send trigger temperature measure command and read the data */ memset(buf, 0, sizeof(buf)); buf[0]=TRIGGER_TEMPERATURE_NO_HOLD; - i2c_write(sht2x, buf, 1); + i2c_write(i2c, buf, 1); msleep(85); /* datasheet: typ=66, max=85 */ memset(buf, 0, sizeof(buf)); - i2c_read(sht2x, buf, 3); - dump_buf("Temperature sample data: ", buf, 3); + i2c_read(i2c, buf, 3); + print_buf("Temperature sample data: ", buf, 3); *temp = 175.72 * (((((int) buf[0]) << 8) + buf[1]) / 65536.0) - 46.85; /* send trigger humidity measure command and read the data */ memset(buf, 0, sizeof(buf)); buf[0] = TRIGGER_HUMIDITY_NO_HOLD; - i2c_write(sht2x, buf, 1); + i2c_write(i2c, buf, 1); msleep(29); /* datasheet: typ=22, max=29 */ memset(buf, 0, sizeof(buf)); - i2c_read(sht2x, buf, 3); - dump_buf("Relative humidity sample data: ", buf, 3); + i2c_read(i2c, buf, 3); + print_buf("Relative humidity sample data: ", buf, 3); *rh = 125 * (((((int) buf[0]) << 8) + buf[1]) / 65536.0) - 6; return 0; } -int sht2x_get_serialnumber(sht2x_t *sht2x, uint8_t *serialnumber, int size) +int sht2x_get_serialnumber(i2c_t *i2c, uint8_t *serialnumber, int size) { uint8_t buf[4]={0x0}; - if( !sht2x || sht2x->fd<0 || !serialnumber || size!=8 ) + if( !i2c || i2c->fd<0 || !serialnumber || size!=8 ) { printf("%s line [%d] %s() get invalid input arguments\n", __FILE__, __LINE__, __func__ ); return -1; @@ -260,10 +247,10 @@ memset(buf, 0, sizeof(buf)); buf[0] = 0xfa; /* command for readout on-chip memory */ buf[1] = 0x0f; /* on-chip memory address */ - i2c_write(sht2x, buf, 2); + i2c_write(i2c, buf, 2); memset(buf, 0, sizeof(buf)); - i2c_read(sht2x, buf, 4); + i2c_read(i2c, buf, 4); if( !buf[0] && !buf[1] && !buf[2] && !buf[3] ) { @@ -280,24 +267,65 @@ memset(buf, 0, sizeof(buf) ); buf[0]=0xfc; /* command for readout on-chip memory */ buf[1]=0xc9; /* on-chip memory address */ - i2c_write(sht2x, buf, 2); + i2c_write(i2c, buf, 2); memset(buf, 0, sizeof(buf) ); - i2c_read(sht2x, buf, 4); + i2c_read(i2c, buf, 4); serialnumber[1]=buf[0]; /* Read SNC_1 */ serialnumber[0]=buf[1]; /* Read SNC_0 */ serialnumber[7]=buf[2]; /* Read SNA_1 */ serialnumber[6]=buf[3]; /* Read SNA_0 */ - dump_buf("SHT2x Serial number: ", serialnumber, 8); + print_buf("SHT2x Serial number: ", serialnumber, 8); return 0; } -static int i2c_write(sht2x_t *sht2x, uint8_t *data, int len) +/*+----------------------+ + *| I2C API functions | + *+----------------------+*/ + +int i2c_init(i2c_t *i2c, int mode, char *i2cdev, int addr) { - struct i2c_rdwr_ioctl_data i2cdata; + if( !i2c || !i2cdev || !addr ) + return -1; + + memset(i2c, 0, sizeof(*i2c)); + i2c->addr = addr; + i2c->dev = i2cdev; + i2c->mode = mode; + + if( (i2c->fd=open(i2cdev, O_RDWR)) < 0) + { + printf("open i2c device %s failed: %s\n", i2cdev, strerror(errno)); + return -1; + } + + if( MODE_RDWR == i2c->mode ) + { + /* set I2C mode and SHT2x slave address */ + ioctl(i2c->fd, I2C_TENBIT, 0); /* Not 10-bit but 7-bit mode */ + ioctl(i2c->fd, I2C_SLAVE, i2c->addr); /* set SHT2x slave address */ + } + + return 0; +} + +void i2c_term(i2c_t *i2c) +{ + if( !i2c ) + return; + + if( i2c->fd > 0) + close(i2c->fd); + + return ; +} + +int i2c_write(i2c_t *i2c, uint8_t *data, int len) +{ + struct i2c_rdwr_ioctl_data tr; int rv = 0; if( !data || len<= 0) @@ -307,35 +335,35 @@ } /* I2C device program API: read()/write() */ - if( MODE_RDWR == sht2x->mode ) + if( MODE_RDWR == i2c->mode ) { - write(sht2x->fd, data, len); + write(i2c->fd, data, len); return 0; } /* I2C device program API: ioctl() */ - i2cdata.nmsgs = 1; - i2cdata.msgs = malloc( sizeof(struct i2c_msg)*i2cdata.nmsgs ); - if ( !i2cdata.msgs ) + tr.nmsgs = 1; + tr.msgs = malloc( sizeof(struct i2c_msg)*tr.nmsgs ); + if ( !tr.msgs ) { printf("%s() msgs malloc failed!\n", __func__); return -2; } - i2cdata.msgs[0].addr = sht2x->addr; - i2cdata.msgs[0].flags = 0; //write - i2cdata.msgs[0].len = len; - i2cdata.msgs[0].buf = malloc(len); - if( !i2cdata.msgs[0].buf ) + tr.msgs[0].addr = i2c->addr; + tr.msgs[0].flags = 0; //write + tr.msgs[0].len = len; + tr.msgs[0].buf = malloc(len); + if( !tr.msgs[0].buf ) { printf("%s() msgs malloc failed!\n", __func__); rv = -3; goto cleanup; } - memcpy(i2cdata.msgs[0].buf, data, len); + memcpy(tr.msgs[0].buf, data, len); - if( ioctl(sht2x->fd, I2C_RDWR, &i2cdata)<0 ) + if( ioctl(i2c->fd, I2C_RDWR, &tr)<0 ) { printf("%s() ioctl failure: %s\n", __func__, strerror(errno)); rv = -4; @@ -343,18 +371,18 @@ } cleanup: - if( i2cdata.msgs[0].buf ) - free(i2cdata.msgs[0].buf); + if( tr.msgs[0].buf ) + free(tr.msgs[0].buf); - if( i2cdata.msgs ) - free(i2cdata.msgs); + if( tr.msgs ) + free(tr.msgs); return rv; } -static int i2c_read(sht2x_t *sht2x, uint8_t *buf, int size) +int i2c_read(i2c_t *i2c, uint8_t *buf, int size) { - struct i2c_rdwr_ioctl_data i2cdata; + struct i2c_rdwr_ioctl_data tr; int rv = 0; if( !buf || size<= 0) @@ -364,40 +392,40 @@ } /* I2C device program API: read()/write() */ - if( MODE_RDWR == sht2x->mode ) + if( MODE_RDWR == i2c->mode ) { - read(sht2x->fd, buf, size); + read(i2c->fd, buf, size); return 0; } /* I2C device program API: ioctl() */ - i2cdata.nmsgs = 1; - i2cdata.msgs = malloc( sizeof(struct i2c_msg)*i2cdata.nmsgs ); - if ( !i2cdata.msgs ) + tr.nmsgs = 1; + tr.msgs = malloc( sizeof(struct i2c_msg)*tr.nmsgs ); + if ( !tr.msgs ) { printf("%s() msgs malloc failed!\n", __func__); return -2; } - i2cdata.msgs[0].addr = sht2x->addr; - i2cdata.msgs[0].flags = I2C_M_RD; //read - i2cdata.msgs[0].len = size; - i2cdata.msgs[0].buf = buf; + tr.msgs[0].addr = i2c->addr; + tr.msgs[0].flags = I2C_M_RD; //read + tr.msgs[0].len = size; + tr.msgs[0].buf = buf; memset(buf, 0, size); - if( ioctl(sht2x->fd, I2C_RDWR, &i2cdata)<0 ) + if( ioctl(i2c->fd, I2C_RDWR, &tr)<0 ) { printf("%s() ioctl failure: %s\n", __func__, strerror(errno)); rv = -4; } - free( i2cdata.msgs ); + free( tr.msgs ); return rv; } -/*+----------------+ - *| Misc functions | - *+----------------+*/ +/*+----------------------+ + *| Misc functions | + *+----------------------+*/ static inline void msleep(unsigned long ms) { @@ -418,7 +446,7 @@ nanosleep(&cSleep, 0); } -static inline void dump_buf(const char *prompt, uint8_t *buf, int size) +void print_buf(const char *prompt, uint8_t *buf, int size) { int i; @@ -440,3 +468,75 @@ return ; } + +#define LINELEN 81 +#define CHARS_PER_LINE 16 +static char *print_char = +" " +" " +" !\"#$%&'()*+,-./" +"0123456789:;<=>?" +"@ABCDEFGHIJKLMNO" +"PQRSTUVWXYZ[\\]^_" +"`abcdefghijklmno" +"pqrstuvwxyz{|}~ " +" " +" " +" ???????????????" +"????????????????" +"????????????????" +"????????????????" +"????????????????" +"????????????????"; + +void dump_buf(const char *prompt, char *buf, size_t len) +{ + int rc; + int idx; + char prn[LINELEN]; + char lit[CHARS_PER_LINE + 2]; + char hc[4]; + short line_done = 1; + + if( prompt ) + printf("%s", prompt); + + rc = len; + idx = 0; + lit[CHARS_PER_LINE] = '\0'; + + while (rc > 0) + { + if (line_done) + snprintf(prn, LINELEN, "%08X: ", idx); + + do + { + unsigned char c = buf[idx]; + snprintf(hc, 4, "%02X ", c); + strncat(prn, hc, LINELEN); + + lit[idx % CHARS_PER_LINE] = print_char[c]; + } + while (--rc > 0 && (++idx % CHARS_PER_LINE != 0)); + + line_done = (idx % CHARS_PER_LINE) == 0; + if (line_done) + { + printf("%s %s\r\n", prn, lit); + } + } + + if (!line_done) + { + int ldx = idx % CHARS_PER_LINE; + lit[ldx++] = print_char[(int)buf[idx]]; + lit[ldx] = '\0'; + + while ((++idx % CHARS_PER_LINE) != 0) + strncat(prn, " ", sizeof(prn)-strlen(prn)); + + printf("%s %s\r\n", prn, lit); + + } +} diff --git a/modules/w25qflash.c b/modules/w25qflash.c index 345f0b6..449a9c7 100644 --- a/modules/w25qflash.c +++ b/modules/w25qflash.c @@ -1,16 +1,25 @@ /********************************************************************************* - * Copyright: (C) 2023 LingYun IoT System Studio. All Rights Reserved. + * Copyright: (C) 2023 LingYun IoT System Studio + * All rights reserved. + * + * Filename: at24c.c + * Description: This file is AT24Cxx EEPROM code + * + * Version: 1.0.0(10/08/23) * Author: Guo Wenxue <guowenxue@gmail.com> + * ChangeLog: 1, Release initial version on "10/08/23 17:52:00" * - * Description: This file is W25Qxx SPI Norflash driver on RaspberryPi 40Pin. + * Pin connection: + * W25QXX Raspberry Pi 40Pin + * VCC <---> Pin#1 (3.3V) + * CS <---> Pin#24(CS) + * DO <---> Pin#21(MISO) + * GND <---> Pin#9 (GND) + * CLK <---> Pin#23(SCLK) + * DI <---> Pin#19(MOSI) * - * W25QXX RaspberryPi 40Pin - * VCC <---> 3.3V(Pin#1) - * CS <---> CS(Pin#24) - * DO <---> MISO(Pin#21) - * GND <---> GND(Pin#9) - * CLK <---> SCLK(Pin#23) - * DI <---> MOSI(Pin#19) + * /boot/config.txt: + * dtparam=spi=on * ********************************************************************************/ @@ -745,9 +754,9 @@ } while ((buf[1] & 0x01) == 0x01); } -/*+----------------+ - *| dump_buf | - *+----------------+*/ +/*+----------------------+ + *| Misc functions | + *+----------------------+*/ void print_buf(const char *prompt, uint8_t *buf, int size) { diff --git a/modules/w25qflash.h b/modules/w25qflash.h index 4c9edac..8b0ca05 100644 --- a/modules/w25qflash.h +++ b/modules/w25qflash.h @@ -1,16 +1,25 @@ /********************************************************************************* - * Copyright: (C) 2023 LingYun IoT System Studio. All Rights Reserved. + * Copyright: (C) 2023 LingYun IoT System Studio + * All rights reserved. + * + * Filename: at24c.c + * Description: This file is AT24Cxx EEPROM code + * + * Version: 1.0.0(10/08/23) * Author: Guo Wenxue <guowenxue@gmail.com> + * ChangeLog: 1, Release initial version on "10/08/23 17:52:00" * - * Description: This file is W25Qxx SPI Norflash driver on RaspberryPi 40Pin. + * Pin connection: + * W25QXX Raspberry Pi 40Pin + * VCC <---> Pin#1 (3.3V) + * CS <---> Pin#24(CS) + * DO <---> Pin#21(MISO) + * GND <---> Pin#9 (GND) + * CLK <---> Pin#23(SCLK) + * DI <---> Pin#19(MOSI) * - * W25QXX RaspberryPi 40Pin - * VCC <---> 3.3V(Pin#1) - * CS <---> CS(Pin#24) - * DO <---> MISO(Pin#21) - * GND <---> GND(Pin#9) - * CLK <---> SCLK(Pin#23) - * DI <---> MOSI(Pin#19) + * /boot/config.txt: + * dtparam=spi=on * ********************************************************************************/ -- Gitblit v1.9.1