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