// // Simple program to display the info of the attached RPI HAT // This info is stored in an I2C EEPROM attached to pins 27 & 28 // of the 40 pin RPI GPIO header. // // Info about the physical, electrical and software specifications // of the RPI HAT standard are defined here: // https://github.com/raspberrypi/hats/blob/master/eeprom-format.md // // Copyright (c) 2021 BitBank Software, Inc. // Written by Larry Bank // email: bitbank@pobox.com // Project started 11/07/2021 // // 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 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . // // Uses my Bit Bang I2C library. You can find it here: // https://github.com/bitbank2/BitBang_I2C #include #include #include #include #include #include #include BBI2C bbi2c; #define SDA_ID 27 #define SCL_ID 28 // Fixed address of all HAT EEPROM chips #define EEPROM_ADDR 0x50 // // Read a block of 32 bytes at the given address // or from the last read address if iAddr == -1 // int eeReadBlock(int iAddr, unsigned char *pData) { unsigned char ucTemp[4]; int rc; if (iAddr != -1) // send the address { ucTemp[0] = (unsigned char)(iAddr >> 8); ucTemp[1] = (unsigned char)iAddr; rc = I2CWrite(&bbi2c, EEPROM_ADDR, ucTemp, 2); } // otherwise read from the last address and increment rc = I2CRead(&bbi2c, EEPROM_ADDR, pData, 32); return (rc == 32); } /* eeReadBlock() */ const char *szTypes[] = {"invalid", "vendor info", "GPIO map", "Linux device tree blob", "manufacturer custom data", "reserved", "invalid"}; int main(int argc, char **argv) { int i, iAtoms, iLen, iOff; uint8_t ucHAT[256], ucTemp[256]; // read some of the HAT info here memset(&bbi2c, 0, sizeof(bbi2c)); bbi2c.bWire = 0; // use bit bang, not wire library bbi2c.iSDA = SDA_ID; bbi2c.iSCL = SCL_ID; I2CInit(&bbi2c, 100000L); // Read 256 bytes of the HAT data starting at offset 0 for (i=0; i<256; i+=32) { eeReadBlock(i, &ucHAT[i]); } // Print signature memcpy(ucTemp, ucHAT, 4); ucTemp[4] = 0; printf("EEPROM Header Info:\n"); printf("signature: %s\n", ucHAT); printf("version: 0x%02x\n", ucHAT[4]); iAtoms = ucHAT[6]; printf("total atoms: %d\n", iAtoms); iLen = *(uint32_t *)&ucHAT[8]; printf("total length: %d bytes\n", iLen); // Display info for each Atom iOff = 12; // starting offset of first Atom for (i=0; i 5 && iType < 0xffff) iType = 5; // reserved if (iType == 0xffff) iType = 0; // invalid iSize = *(uint32_t *)&ucHAT[iOff+4]; printf("Atom Type: 0x%04x (%s)\n",iType, szTypes[iType]); printf("Atom Size: %d bytes\n",iSize); if (iType == 0x0001) { // vendor info printf("** Vendor Info **\n"); printf(" UUID: %08x%08x%08x%08x\n", *(uint32_t *)&ucHAT[iOff+8], *(uint32_t *)&ucHAT[iOff+12], *(uint32_t *)&ucHAT[iOff+16], *(uint32_t *)&ucHAT[iOff+20]); printf(" Product ID: %d\n", *(uint16_t *)&ucHAT[iOff+24]); printf(" Product Ver: %d\n", *(uint16_t *)&ucHAT[iOff+26]); vslen = ucHAT[iOff+28]; // vendor name string length pslen = ucHAT[iOff+29]; // vendor product string length memcpy(ucTemp, &ucHAT[iOff+30], vslen); ucTemp[vslen] = 0; printf(" Vendor: %s\n", ucTemp); memcpy(ucTemp, &ucHAT[iOff+30+vslen], pslen); ucTemp[pslen] = 0; printf(" Product: %s\n", ucTemp); } else if (iType == 0x0002) { // GPIO map printf("** GPIO Map **\n"); printf(" GPIO (BCM #) pins used:\n"); iPins = 0; for (j=0; j<28; j++) { if (ucHAT[iOff+10+j] & 0x80) { // bit 7 indicates pin is used printf("%02d,",ucHAT[iOff+10+j]); iPins++; } } printf("\n %d pins defined\n", iPins); } iOff += iSize + 8; } printf("** End of Atom list **\n"); return 0; }