Close

Raspberry Pi Hat ID EEPROM Details

A project log for Not Quite Useless Raspberry Pi Replacement

Make a Raspberry Pi replacement using a Cypress Semiconductor Programmable System on a Chip (PSOC 5)

land-boardscomland-boards.com 10/17/2019 at 12:240 Comments

The creation of Raspberry Pi Hat EEPROMs is described in the Foundation's documents.

The HAT EEPROM allows the hat to describe the function of the GPIO pins. Most of our cards are not for a specific purpose but are I/O breakouts with power distribution. Many of the cards perform 3.3V to 5V translation. As such, there's no dedicated purpose for a given GPIO pin so there's no way to fully pre-determine the contents of the hat EEPROM. In fact, it might even be an input pin or an output pin.  But we still provide the EEPROM on these cards for users who want to fill in the contents based on their specific applications. This is complicated enough to do that most casual users never bother with doing it.

The hats typically do connect to all pins. But in the case where the hat is designed to fit on either the 40-pin connector or the older 26-pin connector, there's no pins on the additional 14 connector pins.

Details of the EEPROM Contents

Details of the EEPROM data format can be found in the EEPROM format specification

Host Side Software Tools to Create EEPROM Images

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. Conveniently the tools are written in C and that's compatible (at least at the language level) with PSOC Creator.

EEPROM Flashing Tool

The tool to program and read the EEPROM on the card (eepmake32) obviously don't run on the PSoC so it needs to be re-created.

The EEPROM image will be loaded into the PSoC Flash Memory when the PSOC is programmed and needs to be made into a C Array from the perspective of the PSoC Creator. We've used one of the srecord utilities called srec_cat to convert binary images into C Arrays before so this would probably be a good tool for this instance. The specific tool can actually be run on the Pi itself to make the binary file:

eepmake: Parses EEPROM text file and creates binary .eep file

We've already done this for the hats we currently make and probably will continue to use the Pi for this function. Alternately, the code could be run on a PC or Linux machine.

EEPROM Physical Interface from the PSoC

The ID EEPROM is at I2C address 0x50 on ID_SD and ID_SC pins. That is the I2C slave address and is a function of the EEPROM part itself.

The I2C lines are connected to a dedicated I2C interface in the PSoC.

The pins are pre-determined for this I2C interface as above. Dropping the I2C Master symbol onto the PSOC Creator schematic page causes API code to be generated for the I2C master function but the API functions need to be called by the program that needs to use the I2C master.

EEPROM

We use the recommended On Semiconductor CAT24C32 32Kbit EEPROM for our hats.
A recommended part that satisfies the above constraints is OnSemi CAT24C32 
which is a 32kbit (4kbyte) device. 

The CAT24C32 has the key feature that it has "Hardware Write Protection for Entire Memory".

We could use either byte write mode or page write mode. The eepflash.sh program uses the linux dd command to copy data from the file to the Flash and there's no easy visibility to which mode it uses.

The spec for the contents of the flash is here.

Since the data is only written and read as a block, I'm going to use the Page Write mode. This only comes at the cost of speed and the part is so small that speed isn't particularly critical. Write cycles are 10 mSec. If we were to write to all of the 4KB of the EEPROM that would be 40 seconds. But looking at the file for the RPP-UIO-16 shows that it's only 109 bytes long so this will take a little over a second to flash the portion of the EEPROM we want to flash. That should be fine.

Let's use a 256-byte block size. Since the EEPROM has 32-byte blocks we will need to break this up into 8 separate block transfers.

We will use a software delay timer of 10 mS between each write to ensure that the part has completed the previous transfer.

There is a handy application note by Cypress on connecting an external EEPROM to the PSoC. Here is a link to the source code. In the example, the code does the following to write a block to the EEPROM:

        //Following API writes the data from PSoC3 RAM buffer to EEPROM
        //SLAVE_ADDR is the slave address in this API
        //cMessage is the pointer to array which contains the data to be written to EEPROM.
        //cLength is the number of bytes which have to be written to EEPROM
        //I2C_MODE_COMPLETE_XFER, is to send data completly before sending stop command.
        
        I2C_MasterWriteBuf(SLAVE_ADDR, cMessage, cLength, I2C_MODE_COMPLETE_XFER);
        
        //wait until Transfer is complete
        while((I2C_MasterStatus() & I2C_MSTAT_WR_CMPLT )==0); 
        
        // delay to complete the write operation(twr)
        CyDelay(10);

Reads are similar except there's a "dummy write" to get the address set for read.

        //write a dummy byte to initialize the address word counter of 
        //eeprom to start address for read back operation. First location 
        //of cMessage array has word address.
        
        I2C_MasterWriteBuf(SLAVE_ADDR, cMessage, 1, I2C_MODE_COMPLETE_XFER);
        
        //wait until Transfer is complete
        while((I2C_MasterStatus() & I2C_MSTAT_WR_CMPLT )==0);
        
        //Delay for setting address in EEPROM
        CyDelayUs(1);
        
        //Read the 16 bytes from slave, staring from word address specified by iMessage
        //SLAVE_ADDR is the slave address in this API
        //cRx_Buffer is the pointer to array where data has to be stored after reading from EEPROM.
        //cLength-1 is the number of bytes which have to be read from EEPROM
        //I2C_MODE_COMPLETE_XFER, is to read data completly before sending stop command.
        
        I2C_MasterReadBuf(SLAVE_ADDR, cRx_Buffer,cLength-1, I2C_MODE_COMPLETE_XFER );
                
        //wait until Transfer is complete
        while((I2C_MasterStatus() & I2C_MSTAT_RD_CMPLT )==0); 
        

This is similar to the Arduino code to write/read EEPROMs on our ODAS cards.

Before working on this code, I think I need to have a way of displaying the EEPROM contents. For that I will create some Test Menu code.

Discussions