From 80686e6bc4cb17e9d856647084725203fa63ebe6 Mon Sep 17 00:00:00 2001
From: guowenxue <guowenxue@gmail.com>
Date: Mon, 19 Aug 2024 16:47:42 +0800
Subject: [PATCH] Add LCD API examples

---
 hal/modules/at24c.c |  616 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 616 insertions(+), 0 deletions(-)

diff --git a/hal/modules/at24c.c b/hal/modules/at24c.c
new file mode 100644
index 0000000..575bf55
--- /dev/null
+++ b/hal/modules/at24c.c
@@ -0,0 +1,616 @@
+/*********************************************************************************
+ *      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 Avnet.\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;
+    else
+        bytes = len>eeprom->pagesize? eeprom->pagesize : len;
+
+    /* 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);
+}
+
+void dump_buf(const char *prompt, char *buf, size_t len)
+{
+    char        line[256];
+    size_t      i, j;
+    int         offset;
+
+    if( prompt )
+    {
+        printf("%s", prompt);
+    }
+
+    for(i = 0; i < len; i += 16)
+    {
+        offset = snprintf(line, sizeof(line), "%08zx: ", i);
+
+        /* Print hex representation */
+        for (j = 0; j < 16; j++)
+        {
+            if (i + j < len)
+                offset += snprintf(line + offset, sizeof(line) - offset, "%02x ", buf[i + j]);
+            else
+                offset += snprintf(line + offset, sizeof(line) - offset, "   ");
+        }
+
+        offset += snprintf(line + offset, sizeof(line) - offset, " ");
+
+        /* Print ASCII representation */
+        for (j = 0; j < 16; j++)
+        {
+            if (i + j < len)
+            {
+                unsigned char c = buf[i + j];
+                offset += snprintf(line + offset, sizeof(line) - offset, "%c", (c >= 32 && c <= 126) ? c : '.');
+            }
+            else
+            {
+                offset += snprintf(line + offset, sizeof(line) - offset, " ");
+            }
+        }
+
+        /* Print the line */
+        printf("%s\n", line);
+    }
+}

--
Gitblit v1.9.1