RaspberrPi project source code
guowenxue
2024-03-14 d973d6f8e12b16c3cdd84e63e19b61187424f4ce
Add AT24C EEPROM code

Signed-off-by: guowenxue <guowenxue@gmail.com>
1 files added
3 files modified
1001 ■■■■ changed files
modules/at24c.c 641 ●●●●● patch | view | raw | blame | history
modules/sht20.c 300 ●●●●● patch | view | raw | blame | history
modules/w25qflash.c 33 ●●●●● patch | view | raw | blame | history
modules/w25qflash.h 27 ●●●●● patch | view | raw | blame | history
modules/at24c.c
New file
@@ -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);
    }
}
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);
    }
}
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)
{
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
 *
 ********************************************************************************/