樹莓派 HATs ︰ I2C 拾遺《二》

學習者切莫怕閱讀!有時直須對照文字,程式設計構想自然顯現也☆

SMBus Protocol Summary
======================
The following is a summary of the SMBus protocol. It applies to all revisions of the protocol (1.0, 1.1, and 2.0).
Certain protocol features which are not supported by this package are briefly described at the end of this document.

Some adapters understand only the SMBus (System Management Bus) protocol, which is a subset from the I2C protocol. Fortunately, many devices use only the same subset, which makes it possible to put them on an SMBus.

If you write a driver for some I2C device, please try to use the SMBus commands if at all possible (if the device uses only that subset of the I2C protocol). This makes it possible to use the device driver on both SMBus adapters and I2C adapters (the SMBus command set is automatically translated to I2C on I2C adapters, but plain I2C commands can not be handled at all on most pure SMBus adapters).

Below is a list of SMBus protocol operations, and the functions executing them. Note that the names used in the SMBus protocol specifications usually don’t match these function names. For some of the operations which pass a single data byte, the functions using SMBus protocol operation names execute a different protocol operation entirely.

Each transaction type corresponds to a functionality flag. Before calling a transaction function, a device driver should always check (just once) for the corresponding functionality flag to ensure that the underlying I2C adapter supports the transaction in question. See <file:Documentation/i2c/functionality> for the details.

Key to symbols
==============

S (1 bit) : Start bit
P (1 bit) : Stop bit
Rd/Wr (1 bit) : Read/Write bit. Rd equals 1, Wr equals 0.
A, NA (1 bit) : Accept and reverse accept bit.
Addr (7 bits): I2C 7 bit address. Note that this can be expanded as usual to get a 10 bit I2C address.
Comm (8 bits): Command byte, a data byte which often selects a register on the device.
Data (8 bits): A plain data byte. Sometimes, I write DataLow, DataHigh for 16 bit data.
Count (8 bits): A data byte containing the length of a block operation.

[..]: Data sent by I2C device, as opposed to data sent by the host adapter.

SMBus Quick Command
===================

This sends a single bit to the device, at the place of the Rd/Wr bit.

A Addr Rd/Wr [A] P

Functionality flag: I2C_FUNC_SMBUS_QUICK

 

SMBus Receive Byte: i2c_smbus_read_byte()
==========================================

This reads a single byte from a device, without specifying a device register. Some devices are so simple that this interface is enough; for others, it is a shorthand if you want to read the same register as in the previous SMBus command.

S Addr Rd [A] [Data] NA P

Functionality flag: I2C_FUNC_SMBUS_READ_BYTE

 

SMBus Send Byte: i2c_smbus_write_byte()
========================================

This operation is the reverse of Receive Byte: it sends a single byte to a device. See Receive Byte for more information.

S Addr Wr [A] Data [A] P

Functionality flag: I2C_FUNC_SMBUS_WRITE_BYTE

 

SMBus Read Byte: i2c_smbus_read_byte_data()
============================================

This reads a single byte from a device, from a designated register.
The register is specified through the Comm byte.

S Addr Wr [A] Comm [A] S Addr Rd [A] [Data] NA P

Functionality flag: I2C_FUNC_SMBUS_READ_BYTE_DATA

 

SMBus Read Word: i2c_smbus_read_word_data()
============================================

This operation is very like Read Byte; again, data is read from a device, from a designated register that is specified through the Comm byte. But this time, the data is a complete word (16 bits).

S Addr Wr [A] Comm [A] S Addr Rd [A] [DataLow] A [DataHigh] NA P

Functionality flag: I2C_FUNC_SMBUS_READ_WORD_DATA

Note the convenience function i2c_smbus_read_word_swapped is available for reads where the two data bytes are the other way around (not SMBus compliant, but very popular.)

 

SMBus Write Byte: i2c_smbus_write_byte_data()
==============================================

This writes a single byte to a device, to a designated register. The register is specified through the Comm byte. This is the opposite of the Read Byte operation.

S Addr Wr [A] Comm [A] Data [A] P

Functionality flag: I2C_FUNC_SMBUS_WRITE_BYTE_DATA

 

SMBus Write Word: i2c_smbus_write_word_data()
==============================================

This is the opposite of the Read Word operation. 16 bits of data is written to a device, to the designated register that is specified through the Comm byte.

S Addr Wr [A] Comm [A] DataLow [A] DataHigh [A] P

Functionality flag: I2C_FUNC_SMBUS_WRITE_WORD_DATA

Note the convenience function i2c_smbus_write_word_swapped is available for writes where the two data bytes are the other way around (not SMBus compliant, but very popular.)

……

 

CAT24C32 Data Sheet

cat24c32-w1

 

cat24c32-w2

 

cat24c32-r1

 

cat24c32-2

 

 

eeprog-0.7.6-tear12.tar.gz

/***************************************************************************
copyright : (C) by 2003-2004 Stefano Barbato
email : stefano@codesink.org

Copyright (C) 2011 by Kris Rusocki <kszysiu@gmail.com>
– support for user-defined write cycle time

Id: 24cXX.c,v 1.5 2004/02/29 11:05:28 tat Exp
***************************************************************************/

/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <linux/fs.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <assert.h>
#include <string.h>
#include “24cXX.h”

static int i2c_write_1b(struct eeprom *e, __u8 buf)
{
int r;
// we must simulate a plain I2C byte write with SMBus functions
r = i2c_smbus_write_byte(e->fd, buf);
if(r < 0)
fprintf(stderr, “Error i2c_write_1b: %s\n”, strerror(errno));
usleep(10);
return r;
}

 

static int i2c_write_2b(struct eeprom *e, __u8 buf[2])
{
int r;
// we must simulate a plain I2C byte write with SMBus functions
r = i2c_smbus_write_byte_data(e->fd, buf[0], buf[1]);
if(r < 0)
fprintf(stderr, “Error i2c_write_2b: %s\n”, strerror(errno));
usleep(10);
return r;
}

 

static int i2c_write_3b(struct eeprom *e, __u8 buf[3])
{
int r;
// we must simulate a plain I2C byte write with SMBus functions
// the __u16 data field will be byte swapped by the SMBus protocol
r = i2c_smbus_write_word_data(e->fd, buf[0], buf[2] << 8 | buf[1]);
if(r < 0)
fprintf(stderr, “Error i2c_write_3b: %s\n”, strerror(errno));
usleep(10);
return r;
}

#define CHECK_I2C_FUNC( var, label ) \
do { if(0 == (var & label)) { \
fprintf(stderr, “\nError: ” \
#label ” function is required. Program halted.\n\n”); \
exit(1); } \
} while(0);

 

int eeprom_open(char *dev_fqn, int addr, int type, int write_cycle_time, struct eeprom* e)
{
int funcs, fd, r;
e->fd = e->addr = 0;
e->dev = 0;

fd = open(dev_fqn, O_RDWR);
if(fd <= 0)
{
fprintf(stderr, “Error eeprom_open: %s\n”, strerror(errno));
return -1;
}

// get funcs list
if((r = ioctl(fd, I2C_FUNCS, &funcs) < 0))
{
fprintf(stderr, “Error eeprom_open: %s\n”, strerror(errno));
return -1;
}
// check for req funcs
CHECK_I2C_FUNC( funcs, I2C_FUNC_SMBUS_READ_BYTE );
CHECK_I2C_FUNC( funcs, I2C_FUNC_SMBUS_WRITE_BYTE );
CHECK_I2C_FUNC( funcs, I2C_FUNC_SMBUS_READ_BYTE_DATA );
CHECK_I2C_FUNC( funcs, I2C_FUNC_SMBUS_WRITE_BYTE_DATA );
CHECK_I2C_FUNC( funcs, I2C_FUNC_SMBUS_READ_WORD_DATA );
CHECK_I2C_FUNC( funcs, I2C_FUNC_SMBUS_WRITE_WORD_DATA );

// set working device
if( ( r = ioctl(fd, I2C_SLAVE, addr)) < 0)
{
fprintf(stderr, “Error eeprom_open: %s\n”, strerror(errno));
return -1;
}
e->fd = fd;
e->addr = addr;
e->dev = dev_fqn;
e->type = type;
e->write_cycle_time = write_cycle_time;
return 0;
}

 

int eeprom_close(struct eeprom *e)
{
close(e->fd);
e->fd = -1;
e->dev = 0;
e->type = EEPROM_TYPE_UNKNOWN;
return 0;
}

 

#if 0
int eeprom_24c32_write_byte(struct eeprom *e, __u16 mem_addr, __u8 data)
{
__u8 buf[3] = { (mem_addr >> 8) & 0x00ff, mem_addr & 0x00ff, data };
return i2c_write_3b(e, buf);
}

 

int eeprom_24c32_read_current_byte(struct eeprom* e)
{
ioctl(e->fd, BLKFLSBUF); // clear kernel read buffer
return i2c_smbus_read_byte(e->fd);
}

 

int eeprom_24c32_read_byte(struct eeprom* e, __u16 mem_addr)
{
int r;
ioctl(e->fd, BLKFLSBUF); // clear kernel read buffer
__u8 buf[2] = { (mem_addr >> 8) & 0x0ff, mem_addr & 0x0ff };
r = i2c_write_2b(e, buf);
if (r < 0)
return r;
r = i2c_smbus_read_byte(e->fd);
return r;
}
#endif

 

int eeprom_read_current_byte(struct eeprom* e)
{
ioctl(e->fd, BLKFLSBUF); // clear kernel read buffer
return i2c_smbus_read_byte(e->fd);
}

 

int eeprom_read_byte(struct eeprom* e, __u16 mem_addr)
{
int r;
ioctl(e->fd, BLKFLSBUF); // clear kernel read buffer
if(e->type == EEPROM_TYPE_8BIT_ADDR)
{
__u8 buf = mem_addr & 0x0ff;
r = i2c_write_1b(e, buf);
} else if(e->type == EEPROM_TYPE_16BIT_ADDR) {
__u8 buf[2] = { (mem_addr >> 8) & 0x0ff, mem_addr & 0x0ff };
r = i2c_write_2b(e, buf);
} else {
fprintf(stderr, “ERR: unknown eeprom type\n”);
return -1;
}
if (r < 0)
return r;
r = i2c_smbus_read_byte(e->fd);
return r;
}

 

int eeprom_write_byte(struct eeprom *e, __u16 mem_addr, __u8 data)
{
int ret;

if(e->type == EEPROM_TYPE_8BIT_ADDR) {
__u8 buf[2] = { mem_addr & 0x00ff, data };
ret = i2c_write_2b(e, buf);
if (ret == 0 && e->write_cycle_time != 0) {
usleep(1000 * e->write_cycle_time);
}
return ret;
} else if(e->type == EEPROM_TYPE_16BIT_ADDR) {
__u8 buf[3] =
{ (mem_addr >> 8) & 0x00ff, mem_addr & 0x00ff, data };
ret = i2c_write_3b(e, buf);
if (ret == 0 && e->write_cycle_time != 0) {
usleep(1000 * e->write_cycle_time);
}
return ret;
}
fprintf(stderr, “ERR: unknown eeprom type\n”);
return -1;
}

 

 

 

 

 

 

 

 

 

 

樹莓派 HATs ︰ I2C 拾遺《一》

若以 HATs add-on board 之目的而言,前面文本以及軟體工具已經具足。假使應用上需要直接讀寫 I2C ID EEPROM ,那麼務須先了解設計指南裡有關 ID EEPROM 選擇考慮的一段文字︰

ID EEPROM

Within the set of pins available on the J8 GPIO header, ID_SC and ID_SD (GPIO0/SCL and GPIO1/SDA) are reserved for board detection / identification. The only allowed connections to the ID_ pins are an ID EEPROM plus 3.9K pull up resistors. Do not connect anything else to these pins!

The ID EEPROM is interrogated at boot time and provides the Pi with the vendor information, the required GPIO setup (pin settings and functions) for the board as well as a binary Linux device tree fragment which also specifies which hardware is used and therefore which drivers need loading. EEPROM information is also available to userland Linux software for identifying attached boards (probably via a sysfs interface but this is TBD).

Pull-ups must be provided on the top board for ID_SC and ID_SD (SCL and SDA respectively) to 3V3 if using an EEPROM. The required pull-up value is 3.9K.

EEPROM Device Specification

  • 24Cxx type 3.3V I2C EEPROM must be used (some types are 5V only, do not use these).
  • The EEPROM must be of the 16-bit addressable type (do not use ones with 8-bit addressing)
  • Do not use ‘paged’ type EEPROMs where the I2C lower address bit(s) select the EEPROM page.
  • Only required to support 100kHz I2C mode.
  • Devices that perform I2C clock stretching are not supported.
  • Write protect pin must be supported and protect the entire device memory.

Note that due to the restrictions above (only using non-paged 16-bit addressable devices is allowed), many of the smaller I2C EEPROMs are ruled out – please check datasheets carefully when choosing a suitable EEPROM for your HAT.

A recommended part that satisfies the above constraints is OnSemi CAT24C32 which is a 32kbit (4kbyte) device. The minimum EEPROM size required is variable and depends on the size of the vendor data strings in the EEPROM and whether a device tree data blob is included (and its size) and whether any other vendor specific data is included.

It is recommended that EEPROM WP (write protect) pin be connected to a test point on the board and pulled up to 3V3 with a 1K resistor. The idea is that at board test/probe the EEPROM can be written (WP pin can be driven LOW), but there is no danger of a user accidentally changing the device contents once the board leaves the factory. Note that the recommended device has an internal pull down hence the stiff (1K) pull up is required. Note that on some devices WP does not write protect the entire array (e.g. some Microchip variants) – avoid using these.

It may be desirable for a board to have the ability for its EEPROM to be reflashed by an end user, in this case it is recommended to also include a user settable jumper to short WP to GND and make the EEPROM writable once more. At least this way a user has to perform a specific action to make the EEPROM writeable again before being able to re-flash it and a suitable warning process can be put in place to make sure the correct image is used.

Address pins where present on a device should be set to make sure the EEPROM I2C address is 0x50. This usually means tying them all to zero. (NB reduced pin count variants of the recommended device – e.g. SOT23-5 package – usually have A[2:0] set to 0 anyway).

Details of the EEPROM data format can be found in the EEPROM format specification. Software tools are available for creation of valid EEPROM images, to flash an image or read and dump and image to/from an attached ID EEPROM.

The following schematic fragment is an example of connecting an EEPROM including a jumper and probe point to disable write protect.

eeprom-circuit

 

由於 CAT24CXX 這種 EEPROM 之 I2C 運作模式,

【參考圖示】

cat24c32-1

 

cat24c32-2

 

cat24c32-3

 

與 SMBus 想法的差異,過去在 x86 PC 上,就有此類讀寫相容之『軟體工具』設計︰

eeprog is a Linux C program that allows you to read and write to 24Cxx EEPROM.

24Cxx EEPROM use the I2C protocol but most common controllers found in most PC hardware only support SMBus (a superset of I2C).

What eeprog does is using SMBus commands to read/write to I2C EEPROM so almost every controller could be used.

To use it you have to connect someway a 24Cxx EEPROM to the SMBus bus of your PC.

I connected a 24C32(32kbit EEPROM) to the I2C connector of my Via Epia board but you could use one of those parallel-to-I2C devices (I’ve never seen/used one of those).

 

後來有人將之癹 POST 到樹莓派來︰

Rasberry Pi I2C EEPROM Program

eeprog

eeprog-0.7.6-tear5.tar.gz NOT the original eeprog as it wont program (anything I’ve tried) on a Pi, you will get this without a write cycle time delay

  Writing stdin starting at address 0x0
..Error i2c_write_3b: Input/output error
Error at line 150: write error

write

root@raspberrypi:/tmp/eeprog-0.7.6-tear12# date | ./eeprog -f -16 -w 0 -t 5 /dev/i2c-0 0x53
eeprog 0.7.6-tear12, a 24Cxx EEPROM reader/writer
Copyright (c) 2003-2004 by Stefano Barbato - All rights reserved.
Copyright (c) 2011 by Kris Rusocki - All rights reserved.
  Bus: /dev/i2c-0, Address: 0x53, Mode: 16bit
  Operation: write at offset 0, Input file: <stdin>
  Write cycle time: 5 milliseconds
  Writing <stdin> starting at address 0x0
.............................

read

root@raspberrypi:/tmp/eeprog-0.7.6-tear12# ./eeprog -xf /dev/i2c-0 0x53 -16 -r 0x00:0x100
eeprog 0.7.6-tear12, a 24Cxx EEPROM reader/writer
Copyright (c) 2003-2004 by Stefano Barbato - All rights reserved.
Copyright (c) 2011 by Kris Rusocki - All rights reserved.
  Bus: /dev/i2c-0, Address: 0x53, Mode: 16bit
  Operation: read 256 bytes from offset 0, Output file: <stdout>
  Reading 256 bytes from 0x0
 
 0000|  46 72 69 20 41 75 67 20   31 35 20 32 32 3a 32 36 
 0010|  3a 33 35 20 55 54 43 20   32 30 31 34 0a 00 00 00 
 0020|  00 00 00 00 00 00 00 00   00 00 00 00 00 00 00 00 
 0030|  00 00 00 00 00 00 00 00   00 00 00 00 00 00 00 00 
 0040|  00 00 00 00 00 00 00 00   00 00 00 00 00 00 00 00 
<SNIP>

 

還請讀者先行閱讀相關資料,來趟 24C32 I2C EEPROM 讀寫之旅。

 

 

 

 

 

 

 

 

 

樹莓派 HATs ︰ eepmake 之《補充》

原本並不打算說此『立意未明』之選項︰

pi@raspberrypi:~/hats/eepromutils $ ./eepmake -h
Wrong input format.
Try ‘eepmake input_file output_file [dt_file] [-c custom_file_1 … custom_file_n]

 

但思即使『揣測錯誤』,或許亦能嘉惠讀者??故而姑妄言之,也請讀者姑妄聽之!!

若是考之以原始碼︰

# line 521
int read_custom(char* in) {
        FILE * fp;
        unsigned long size = 0;

        printf("Opening custom data file %s for read\n", in);

        fp = fopen(in, "r");
        if (fp == NULL) {
                printf("Error opening input file\n");
                return -1;
        }
        
        fseek(fp, 0L, SEEK_END);
        size = ftell(fp);
        fseek(fp, 0L, SEEK_SET);
        
        printf("Adding %lu bytes of custom data\n", size);

        total_size+=ATOM_SIZE+size;
        
        custom_atom[custom_ct].type = ATOM_CUSTOM_TYPE;
        custom_atom[custom_ct].count = 3+custom_ct;
        custom_atom[custom_ct].dlen = size+CRC_SIZE;

        custom_atom[custom_ct].data = (char *) malloc(size);
        if (!fread(custom_atom[custom_ct].data, size, 1, fp)) goto err;

        custom_ct++;

        fp = fopen(in, "r");
        if (fp == NULL) {
                printf("Error opening input file\n");
                return -1;
        }
        
        fseek(fp, 0L, SEEK_END);
        size = ftell(fp);
        fseek(fp, 0L, SEEK_SET);
        
        printf("Adding %lu bytes of custom data\n", size);

        total_size+=ATOM_SIZE+size;
        
        custom_atom[custom_ct].type = ATOM_CUSTOM_TYPE;
        custom_atom[custom_ct].count = 3+custom_ct;
        custom_atom[custom_ct].dlen = size+CRC_SIZE;

        custom_atom[custom_ct].data = (char *) malloc(size);
        if (!fread(custom_atom[custom_ct].data, size, 1, fp)) goto err;

        custom_ct++;

        fclose(fp);
        return 0;

err:
        printf("Unexpected EOF or error occurred\n");
        fclose(fp);
        return 0;

}

 

eepmake 只是將『客制檔』 custom_file_n 抄錄至 ID EEPROM 而已 。因此作者認為可以用於一般應用系統/軟體之特定『組構檔』或是『預設檔』。簡單例釋如下︰

pi@raspberrypi:~/hats/eepromutils $ cat custom_file.cfg

/* This is a test of custom file. */

user_name=freesandal
user_passwd=freesandal

default=0

 

pi@raspberrypi:~/hats/eepromutils $ ./eepmake eeprom_settings.txt allo-piano-dac-pcm512x-audio-overlay-ct.eep allo-piano-dac-pcm512x-audio-overlay.dtbo -c custom_file.cfg

Opening file eeprom_settings.txt for read
UUID=585288a1-8c0f-4f7e-b43c-498e590639a7
Done reading
Opening DT file allo-piano-dac-pcm512x-audio-overlay.dtbo for read
Adding 1033 bytes of DT data
Opening custom data file custom_file.cfg for read
Adding 93 bytes of custom data
Writing out…
Writing out DT…
Done.

 

pi@raspberrypi:~/hats/eepromutils $ ./eepdump allo-piano-dac-pcm512x-audio-overlay-ct.eep allo-piano-dac-pcm512x-audio-overlay-ct.txt
Reading atom 0…
CRC OK
Reading atom 1…
CRC OK
Reading atom 2…
CRC OK
Reading atom 3…
CRC OK
Done.

 

pi@raspberrypi:~/hats/eepromutils $ cat allo-piano-dac-pcm512x-audio-overlay-ct.txt

# ———- Dump generated by eepdump handling format version 0x01 ———-
#
# –Header–
# signature=0x69502d52
# version=0x01
# reserved=0
# numatoms=4
# eeplen=1262
# ———-
# Start of atom #0 of type 0x0001 and length 56
# Vendor info
product_uuid 585288a1-8c0f-4f7e-b43c-498e590639a7
product_id 0x0001
product_ver 0x0001
vendor “www.freesandal.org” # length=18
product “ID EEPROM test” # length=14
# End of atom. CRC16=0x9ee5

……

# Start of atom #3 of type 0x0004 and length 95
custom_data
2F 2A 20 54 68 69 73 20 69 73 20 61 20 74 65 73
74 20 6F 66 20 63 75 73 74 6F 6D 20 66 69 6C 65
2E 20 2A 2F 0A 0A 75 73 65 72 5F 6E 61 6D 65 3D
66 72 65 65 73 61 6E 64 61 6C 0A 75 73 65 72 5F
70 61 73 73 77 64 3D 66 72 65 65 73 61 6E 64 61
6C 0A 0A 64 65 66 61 75 6C 74 3D 30 0A
# End of atom. CRC16=0x6095

 

pi@raspberrypi:~/hats/eepromutils $ hexedit allo-piano-dac-pcm512x-audio-overlay-ct.eep

eepmake-ct

 

若問可能之用途,端賴想像的乎☆

 

 

 

 

 

 

 

 

 

樹莓派 HATs ︰ eepmake 《下》

友人問︰理論、實務與應用能否使一氣貫通呢?故而特以實用為例 ,說此『自動組構』 automatic configuration 之事。且權充呼應 o4l 友人《音樂派初登場》之文矣。

peano-2-1

 

PEANO 2.1 的 dts ︰

pi@raspberrypi:~/hats/example $ more allo-piano-dac-pcm512x-audio-overlay.dts

/*
* Definitions for Allo Piano DAC (2.0/2.1) boards
*
* NB. The Piano DAC 2.1 board contains 2x TI PCM5142 DAC’s. One DAC is stereo
* (left/right) and the other provides a subwoofer output, using DSP on the
* chip for digital high/low pass crossover.
* The initial support for this hardware, that doesn’t require any codec driver
* modifications, uses only one DAC chip for stereo (left/right) output, the
* chip with 0x4c slave address. The other chip at 0x4d is currently ignored!
*/

/dts-v1/;
/plugin/;

/ {
compatible = “brcm,bcm2708”;

fragment@0 {
target = <&i2s>;
__overlay__ {
status = “okay”;
};
};

fragment@1 {
target = <&i2c1>;
__overlay__ {
#address-cells = <1>;
#size-cells = <0>;
status = “okay”;

pcm5142@4c {
#sound-dai-cells = <0>;
compatible = “ti,pcm5142”;
reg = <0x4c>;
status = “okay”;
};
};
};

fragment@2 {
target = <&sound>;
piano_dac: __overlay__ {
compatible = “allo,piano-dac”;
i2s-controller = <&i2s>;
status = “okay”;
};
};

__overrides__ {
24db_digital_gain =
<&piano_dac>,”allo,24db_digital_gain?”;
};
};

 

編譯︰

dtc -@ -I dts -O dtb -o allo-piano-dac-pcm512x-audio-overlay.dtbo allo-piano-dac-pcm512x-audio-overlay.dts

 

撰寫 40W GPIOs 之用途︰

pi@raspberrypi:~/hats/eepromutils $ cat eeprom_settings.txt

########################################################################
# EEPROM settings text file
#
# Edit this file for your particular board and run through eepmake tool,
# then use eepflash tool to write to attached HAT ID EEPROM
#
# Tools available:
# eepmake Parses EEPROM text file and creates binary .eep file
# eepdump Dumps a binary .eep file as human readable text (for debug)
# eepflash Write or read .eep binary image to/from HAT EEPROM
#
########################################################################

########################################################################
# Vendor info

# 128 bit UUID. If left at zero eepmake tool will auto-generate
# RFC 4122 compliant UUID
product_uuid 00000000-0000-0000-0000-000000000000

# 16 bit product id
product_id 0x0001

# 16 bit product version
product_ver 0x0001

# ASCII vendor string (max 255 characters)
vendor “www.freesandal.org”

# ASCII product string (max 255 characters)
product “ID EEPROM test”
########################################################################
# GPIO bank settings, set to nonzero to change from the default.
# NOTE these setting can only be set per BANK, uncommenting any of
# these will force the bank to use the custom setting.

# drive strength, 0=default, 1-8=2,4,6,8,10,12,14,16mA, 9-15=reserved
gpio_drive 0

# 0=default, 1=slew rate limiting, 2=no slew limiting, 3=reserved
gpio_slew 0

# 0=default, 1=hysteresis disabled, 2=hysteresis enabled, 3=reserved
gpio_hysteresis 0

# If board back-powers Pi via 5V GPIO header pins:
# 0 = board does not back-power
# 1 = board back-powers and can supply the Pi with a minimum of 1.3A
# 2 = board back-powers and can supply the Pi with a minimum of 2A
# 3 = reserved
# If back_power=2 then USB high current mode will be automatically
# enabled on the Pi
back_power 0

########################################################################
# GPIO pins, uncomment for GPIOs used on board
# Options for FUNCTION: INPUT, OUTPUT, ALT0-ALT5
# Options for PULL: DEFAULT, UP, DOWN, NONE
# NB GPIO0 and GPIO1 are reserved for ID EEPROM so cannot be set

# GPIO FUNCTION PULL
# —- ——– —-
setgpio 2 ALT0 UP
setgpio 3 ALT0 UP
#setgpio 4 INPUT DEFAULT
setgpio 5 INPUT DEFAULT
setgpio 6 INPUT DEFAULT
#setgpio 7 INPUT DEFAULT
#setgpio 8 INPUT DEFAULT
#setgpio 9 INPUT DEFAULT
#setgpio 10 INPUT DEFAULT
#setgpio 11 INPUT DEFAULT
#setgpio 12 INPUT DEFAULT
#setgpio 13 INPUT DEFAULT
#setgpio 14 INPUT DEFAULT
#setgpio 15 INPUT DEFAULT
#setgpio 16 INPUT DEFAULT
#setgpio 17 INPUT DEFAULT
setgpio 18 ALT0 DEFAULT
setgpio 19 ALT0 DEFAULT
setgpio 20 ALT0 DEFAULT
setgpio 21 ALT0 DEFAULT
#setgpio 22 INPUT DEFAULT
#setgpio 23 INPUT DEFAULT
#setgpio 24 INPUT DEFAULT
setgpio 25 INPUT DEFAULT
#setgpio 26 INPUT DEFAULT
#setgpio 27 INPUT DEFAULT

 

創建 .eep 檔案︰

pi@raspberrypi:~/hats/eepromutils ./eepmake eeprom_settings.txt allo-piano-dac-pcm512x-audio-overlay.eep allo-piano-dac-pcm512x-audio-overlay.dtbo  Opening file eeprom_settings.txt for read UUID=c32cb482-ef8e-4d44-85d4-29f4f346b03b Done reading Opening DT file allo-piano-dac-pcm512x-audio-overlay.dtbo for read Adding 1033 bytes of DT data Writing out... Writing out DT... Done. pi@raspberrypi:~/hats/eepromutils

 

燒錄︰

pi@raspberrypi:~/hats/eepromutils sudo ./eepflash.sh -w -f=allo-piano-dac-pcm512x-audio-overlay.eep -t=24c32 This will attempt to talk to an eeprom at i2c address 0x50. Make sure there is an eeprom at this address. This script comes with ABSOLUTELY no warranty. Continue only if you know what you are doing. Do you wish to continue? (yes/no): yes Writing... 2+1 records in 2+1 records out 1159 bytes (1.2 kB) copied, 23.1602 s, 0.1 kB/s Done.</pre>    <span style="color: #003300;">打開 /boot/config.txt 的</span>  <span style="color: #ff9900;">dtparam=i2c_vc=on</span>  <span style="color: #003300;">,重啟體驗 ID EEPROM 之目的也!!?? </span> <pre class="lang:default decode:true">pi@raspberrypi:~ cd /proc/device-tree
pi@raspberrypi:/proc/device-tree ls #address-cells  clocks      interrupt-parent  name           soc aliases         compatible  memory            __overrides__  __symbols__ axi             cpus        memreserve        serial-number  system chosen          hat         model             #size-cells pi@raspberrypi:/proc/device-tree cd hat
pi@raspberrypi:/proc/device-tree/hat ls name  product  product_id  product_ver  uuid  vendor  pi@raspberrypi:/proc/device-tree/hat cat name
hat

pi@raspberrypi:/proc/device-tree/hat cat product ID EEPROM test  pi@raspberrypi:/proc/device-tree/hat cat product_id 
0x0001

pi@raspberrypi:/proc/device-tree/hat cat product_ver  0x0001  pi@raspberrypi:/proc/device-tree/hat cat uuid
c32cb482-ef8e-4d44-85d4-29f4f346b03b

pi@raspberrypi:/proc/device-tree/hat cat vendor www.freesandal.org pi@raspberrypi:/proc/device-tree/hat

 

 

 

 

 

 

 

 

 

 

樹莓派 HATs ︰ eepmake 《中》

如果聽聞

RPI does not boot if HAT EEPROM is corrupted #33

I’ve seen a problem with a board where the EEPROM content wasn’t written correctly. With older 3.x kernels the board boots, but not with the latest kernel/firmware. Is there any kernel parameter to ignore the ID PROM contents? This needs to be only temporary to write the correct EEPROM contents.

……

 

,恐怕不敢嘗試了!假使知道

You can disable the EEPROM reading using the config.txt setting force_eeprom_read=0. I’ll take a look at the reading code to see why it doesn’t boot. If you can read the EEPROM contents and upload it somewhere (or email it to me) I can use it as a test case.

 

,玩玩又有何妨耶?

且讓我們仔細看看 eepflash.sh 怎麼讀寫 ID EEPROM 的呢?

# eepflash.sh line 90

modprobe i2c_dev
dtoverlay i2c-gpio i2c_gpio_sda=0 i2c_gpio_scl=1
rc=? if [rc != 0 ]; then
        echo "Loading of i2c-gpio dtoverlay failed. Do an rpi-update (and maybe apexitrc
fi
modprobe at24
rc=? if [rc != 0 ]; then
        echo "Modprobe of at24 failed. Do an rpi-update."
        exit rc fi  if [ ! -d "/sys/class/i2c-adapter/i2c-3/3-0050" ]; then         echo "TYPE 0x50" > /sys/class/i2c-adapter/i2c-3/new_device
fi

if [ "MODE" = "write" ]  then         echo "Writing..."         dd if=FILE of=/sys/class/i2c-adapter/i2c-3/3-0050/eeprom
        rc=? elif [ "MODE" = "read" ]
 then
        echo "Reading..."
        dd if=/sys/class/i2c-adapter/i2c-3/3-0050/eeprom of=FILE         rc=?
fi

 

,原來是用 dd !如是可以假設是以 kernel at24 驅動程式來作的了 !!??由於 HiFiBerry DAC+ 的『寫入』 WR 太過麻煩,

Flash your DAC+ for automatic configuration

Do you need to flash your card?
No. If you have your system configured already, you can just keep it as it is.

What do you need to do to flash your HiFiBerry DAC+?

  1. Download the flash image from here and extract the ZIP file.
  2. Write the file flash-dacplus.img to an empty SD card
  3. Connect a display to your Raspberry Pi and boot from SD card you just wrote to
  4. When the flasher says “Press WRITE button”, press the white button (named “WR”) on your HiFiBerry DAC+. You need to press the button for about 40-60 seconds.
  5. When the data is written to the EEPROM the Raspberry Pi will reboot and play a (loud) test tone.

Is this only available for the DAC+?
We want to test this first with one card. At this time, only the DAC+ Standard and DAC+ Pro are supported.  If everything works fine, we will provide a flash tool for the Digi+ in the near future.

───

 

所以作者選擇

Adafruit Perma-Proto HAT for Pi Mini Kit – With EEPROM

作測試也。相信讀者自可解讀測試結果的吧??!!

pi@raspberrypi:~ cat /proc/version  Linux version 4.4.26-v7+ (dc4@dc4-XPS13-9333) (gcc version 4.9.3 (crosstool-NG crosstool-ng-1.22.0-88-g8460611) ) #915 SMP Thu Oct 20 17:08:44 BST 2016 pi@raspberrypi:~

 

pi@raspberrypi:~ sudo modprobe i2c_dev pi@raspberrypi:~ sudo dtoverlay i2c-gpio i2c_gpio_sda=0 i2c_gpio_scl=1
pi@raspberrypi:~ sudo modprobe at24  pi@raspberrypi:~ dmesg | tail
[   11.362701] Bluetooth: BNEP filters: protocol multicast
[   11.362718] Bluetooth: BNEP socket layer initialized
[   26.324406] pcm512x 1-004c: No SCLK, using BCLK: -2
[   26.328952] pcm512x 1-004c: No SCLK, using BCLK: -2
[   26.330990] pcm512x 1-004c: No SCLK, using BCLK: -2
[   26.335874] pcm512x 1-004c: No SCLK, using BCLK: -2
[   26.340147] pcm512x 1-004c: No SCLK, using BCLK: -2
[   26.753253] pcm512x 1-004c: No SCLK, using BCLK: -2
[   28.322041] EXT4-fs (sda1): mounted filesystem with ordered data mode. Opts: (null)
[ 5362.460586] i2c-gpio i2c@0: using pins 0 (SDA) and 1 (SCL)
pi@raspberrypi:~ </pre>   <pre class="lang:default decode:true">pi@raspberrypi:~ cd hats/eepromutils/
pi@raspberrypi:~/hats/eepromutils dd if=/dev/zero ibs=1k count=4 of=zero.eep 4+0 records in 8+0 records out 4096 bytes (4.1 kB) copied, 0.000937858 s, 4.4 MB/s  pi@raspberrypi:~/hats/eepromutils sudo ./eepflash.sh -w -f=zero.eep -t=24c32
This will attempt to talk to an eeprom at i2c address 0x50. Make sure there is an eeprom at this address.
This script comes with ABSOLUTELY no warranty. Continue only if you know what you are doing.
Do you wish to continue? (yes/no): yes
Writing...
8+0 records in
8+0 records out
4096 bytes (4.1 kB) copied, 81.909 s, 0.1 kB/s
Done.
pi@raspberrypi:~/hats/eepromutils </pre>   <pre class="lang:default decode:true"># dmesg [ 5572.324220] device-tree: Duplicate name in base, renamed to "i2c@0#1" [ 5572.324381] ------------[ cut here ]------------ [ 5572.324396] WARNING: CPU: 3 PID: 1264 at fs/sysfs/dir.c:31 sysfs_warn_dup+0x78/0x88() [ 5572.324401] sysfs: cannot create duplicate filename '/devices/platform/i2c@0' [ 5572.324406] Modules linked in: at24 i2c_gpio i2c_algo_bit bnep hci_uart btbcm bluetooth sg hid_multitouch brcmfmac brcmutil snd_soc_pcm512x_i2c snd_soc_pcm512x joydev cfg80211 evdev regmap_i2c rfkill snd_soc_bcm2835_i2s snd_soc_allo_piano_dac snd_soc_core snd_pcm_dmaengine i2c_bcm2708 bcm2835_wdt snd_pcm snd_timer snd bcm2835_gpiomem uio_pdrv_genirq uio i2c_dev fuse ipv6 [ 5572.324481] CPU: 3 PID: 1264 Comm: dtoverlay Not tainted 4.4.26-v7+ #915 [ 5572.324486] Hardware name: BCM2709 [ 5572.324505] [<80018784>] (unwind_backtrace) from [<80014058>] (show_stack+0x20/0x24) [ 5572.324518] [<80014058>] (show_stack) from [<80321364>] (dump_stack+0xd4/0x118) [ 5572.324531] [<80321364>] (dump_stack) from [<800253c4>] (warn_slowpath_common+0x98/0xc8) [ 5572.324542] [<800253c4>] (warn_slowpath_common) from [<80025434>] (warn_slowpath_fmt+0x40/0x48) [ 5572.324552] [<80025434>] (warn_slowpath_fmt) from [<801cd2a8>] (sysfs_warn_dup+0x78/0x88) [ 5572.324562] [<801cd2a8>] (sysfs_warn_dup) from [<801cd3a4>] (sysfs_create_dir_ns+0x94/0xa4) [ 5572.324573] [<801cd3a4>] (sysfs_create_dir_ns) from [<80323e10>] (kobject_add_internal+0xb4/0x30c) [ 5572.324585] [<80323e10>] (kobject_add_internal) from [<80324240>] (kobject_add+0x50/0x94) [ 5572.324596] [<80324240>] (kobject_add) from [<803a6880>] (device_add+0xe8/0x574) [ 5572.324609] [<803a6880>] (device_add) from [<804a454c>] (of_device_add+0x44/0x4c) [ 5572.324622] [<804a454c>] (of_device_add) from [<804a4de8>] (of_platform_device_create_pdata+0x94/0xc8) [ 5572.324633] [<804a4de8>] (of_platform_device_create_pdata) from [<804a4f04>] (of_platform_notify+0xc4/0xfc) [ 5572.324645] [<804a4f04>] (of_platform_notify) from [<800438b4>] (notifier_call_chain+0x54/0x94) [ 5572.324656] [<800438b4>] (notifier_call_chain) from [<80043cec>] (__blocking_notifier_call_chain+0x58/0x70) [ 5572.324667] [<80043cec>] (__blocking_notifier_call_chain) from [<80043d2c>] (blocking_notifier_call_chain+0x28/0x30) [ 5572.324679] [<80043d2c>] (blocking_notifier_call_chain) from [<804a5dd8>] (__of_changeset_entry_notify+0x94/0xf0) [ 5572.324690] [<804a5dd8>] (__of_changeset_entry_notify) from [<804a6728>] (of_changeset_apply+0x68/0xd8) [ 5572.324700] [<804a6728>] (of_changeset_apply) from [<804aa320>] (of_overlay_create+0x264/0x37c) [ 5572.324711] [<804aa320>] (of_overlay_create) from [<804a569c>] (create_overlay+0x58/0xbc) [ 5572.324723] [<804a569c>] (create_overlay) from [<804a5768>] (cfs_overlay_item_dtbo_write+0x68/0xa8) [ 5572.324734] [<804a5768>] (cfs_overlay_item_dtbo_write) from [<801cec64>] (configfs_release_bin_file+0x6c/0xa0) [ 5572.324745] [<801cec64>] (configfs_release_bin_file) from [<8015934c>] (__fput+0x94/0x1e4) [ 5572.324754] [<8015934c>] (__fput) from [<8015950c>] (____fput+0x18/0x1c) [ 5572.324766] [<8015950c>] (____fput) from [<80040b64>] (task_work_run+0xa0/0xd4) [ 5572.324777] [<80040b64>] (task_work_run) from [<80013914>] (do_work_pending+0xcc/0xd0) [ 5572.324789] [<80013914>] (do_work_pending) from [<8000fb68>] (slow_work_pending+0xc/0x20) [ 5572.324795] ---[ end trace b35122a91729970c ]--- [ 5572.324800] ------------[ cut here ]------------ [ 5572.324809] WARNING: CPU: 3 PID: 1264 at lib/kobject.c:240 kobject_add_internal+0x294/0x30c() [ 5572.324814] kobject_add_internal failed for i2c@0 with -EEXIST, don't try to register things with the same name in the same directory. [ 5572.324818] Modules linked in: at24 i2c_gpio i2c_algo_bit bnep hci_uart btbcm bluetooth sg hid_multitouch brcmfmac brcmutil snd_soc_pcm512x_i2c snd_soc_pcm512x joydev cfg80211 evdev regmap_i2c rfkill snd_soc_bcm2835_i2s snd_soc_allo_piano_dac snd_soc_core snd_pcm_dmaengine i2c_bcm2708 bcm2835_wdt snd_pcm snd_timer snd bcm2835_gpiomem uio_pdrv_genirq uio i2c_dev fuse ipv6 [ 5572.324879] CPU: 3 PID: 1264 Comm: dtoverlay Tainted: G        W       4.4.26-v7+ #915 [ 5572.324883] Hardware name: BCM2709 [ 5572.324895] [<80018784>] (unwind_backtrace) from [<80014058>] (show_stack+0x20/0x24) [ 5572.324905] [<80014058>] (show_stack) from [<80321364>] (dump_stack+0xd4/0x118) [ 5572.324915] [<80321364>] (dump_stack) from [<800253c4>] (warn_slowpath_common+0x98/0xc8) [ 5572.324926] [<800253c4>] (warn_slowpath_common) from [<80025434>] (warn_slowpath_fmt+0x40/0x48) [ 5572.324937] [<80025434>] (warn_slowpath_fmt) from [<80323ff0>] (kobject_add_internal+0x294/0x30c) [ 5572.324947] [<80323ff0>] (kobject_add_internal) from [<80324240>] (kobject_add+0x50/0x94) [ 5572.324958] [<80324240>] (kobject_add) from [<803a6880>] (device_add+0xe8/0x574) [ 5572.324968] [<803a6880>] (device_add) from [<804a454c>] (of_device_add+0x44/0x4c) [ 5572.324979] [<804a454c>] (of_device_add) from [<804a4de8>] (of_platform_device_create_pdata+0x94/0xc8) [ 5572.324990] [<804a4de8>] (of_platform_device_create_pdata) from [<804a4f04>] (of_platform_notify+0xc4/0xfc) [ 5572.325001] [<804a4f04>] (of_platform_notify) from [<800438b4>] (notifier_call_chain+0x54/0x94) [ 5572.325011] [<800438b4>] (notifier_call_chain) from [<80043cec>] (__blocking_notifier_call_chain+0x58/0x70) [ 5572.325022] [<80043cec>] (__blocking_notifier_call_chain) from [<80043d2c>] (blocking_notifier_call_chain+0x28/0x30) [ 5572.325033] [<80043d2c>] (blocking_notifier_call_chain) from [<804a5dd8>] (__of_changeset_entry_notify+0x94/0xf0) [ 5572.325043] [<804a5dd8>] (__of_changeset_entry_notify) from [<804a6728>] (of_changeset_apply+0x68/0xd8) [ 5572.325052] [<804a6728>] (of_changeset_apply) from [<804aa320>] (of_overlay_create+0x264/0x37c) [ 5572.325062] [<804aa320>] (of_overlay_create) from [<804a569c>] (create_overlay+0x58/0xbc) [ 5572.325073] [<804a569c>] (create_overlay) from [<804a5768>] (cfs_overlay_item_dtbo_write+0x68/0xa8) [ 5572.325083] [<804a5768>] (cfs_overlay_item_dtbo_write) from [<801cec64>] (configfs_release_bin_file+0x6c/0xa0) [ 5572.325092] [<801cec64>] (configfs_release_bin_file) from [<8015934c>] (__fput+0x94/0x1e4) [ 5572.325100] [<8015934c>] (__fput) from [<8015950c>] (____fput+0x18/0x1c) [ 5572.325110] [<8015950c>] (____fput) from [<80040b64>] (task_work_run+0xa0/0xd4) [ 5572.325120] [<80040b64>] (task_work_run) from [<80013914>] (do_work_pending+0xcc/0xd0) [ 5572.325131] [<80013914>] (do_work_pending) from [<8000fb68>] (slow_work_pending+0xc/0x20) [ 5572.325136] ---[ end trace b35122a91729970d ]--- [ 5572.325144] of_platform_notify: failed to create for '//i2c@0' [ 5572.325149] __of_changeset_entry_notify: notifier error @//i2c@0 [ 5572.391499] at24 3-0050: 4096 byte 24c32 EEPROM, writable, 1 bytes/write [ 5572.391549] i2c i2c-3: new_device: Instantiated device 24c32 at 0x50 pi@raspberrypi:~/hats/eepromutils

 

pi@raspberrypi:~/hats/eepromutils sudo ./eepflash.sh -r -f=invalid.eep -t=24c32 This will attempt to talk to an eeprom at i2c address 0x50. Make sure there is an eeprom at this address. This script comes with ABSOLUTELY no warranty. Continue only if you know what you are doing. Do you wish to continue? (yes/no): yes Reading... 8+0 records in 8+0 records out 4096 bytes (4.1 kB) copied, 0.243574 s, 16.8 kB/s Done.  pi@raspberrypi:~/hats/eepromutils hexdump invalid.eep 
0000000 0000 0000 0000 0000 0000 0000 0000 0000
*
0001000
pi@raspberrypi:~/hats/eepromutils $