|
| 1 | +// |
| 2 | +// Simple program to display the info of the attached RPI HAT |
| 3 | +// This info is stored in an I2C EEPROM attached to pins 27 & 28 |
| 4 | +// of the 40 pin RPI GPIO header. |
| 5 | +// |
| 6 | +// Info about the physical, electrical and software specifications |
| 7 | +// of the RPI HAT standard are defined here: |
| 8 | +// https://github.com/raspberrypi/hats/blob/master/eeprom-format.md |
| 9 | +// |
| 10 | +// Copyright (c) 2021 BitBank Software, Inc. |
| 11 | +// Written by Larry Bank |
| 12 | + |
| 13 | +// Project started 11/07/2021 |
| 14 | +// |
| 15 | +// This program is free software: you can redistribute it and/or modify |
| 16 | +// it under the terms of the GNU General Public License as published by |
| 17 | +// the Free Software Foundation, either version 3 of the License, or |
| 18 | +// (at your option) any later version. |
| 19 | +// |
| 20 | +// This program is distributed in the hope that it will be useful, |
| 21 | +// but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 22 | +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 23 | +// GNU General Public License for more details. |
| 24 | +// |
| 25 | +// You should have received a copy of the GNU General Public License |
| 26 | +// along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 27 | +// |
| 28 | +// Uses my Bit Bang I2C library. You can find it here: |
| 29 | +// https://github.com/bitbank2/BitBang_I2C |
| 30 | +#include <stdlib.h> |
| 31 | +#include <string.h> |
| 32 | +#include <stdio.h> |
| 33 | +#include <stdint.h> |
| 34 | +#include <inttypes.h> |
| 35 | +#include <BitBang_I2C.h> |
| 36 | +#include <pigpio.h> |
| 37 | + |
| 38 | +BBI2C bbi2c; |
| 39 | +#define SDA_ID 27 |
| 40 | +#define SCL_ID 28 |
| 41 | +// Fixed address of all HAT EEPROM chips |
| 42 | +#define EEPROM_ADDR 0x50 |
| 43 | +// |
| 44 | +// Read a block of 32 bytes at the given address |
| 45 | +// or from the last read address if iAddr == -1 |
| 46 | +// |
| 47 | +int eeReadBlock(int iAddr, unsigned char *pData) |
| 48 | +{ |
| 49 | +unsigned char ucTemp[4]; |
| 50 | +int rc; |
| 51 | + |
| 52 | + if (iAddr != -1) // send the address |
| 53 | + { |
| 54 | + ucTemp[0] = (unsigned char)(iAddr >> 8); |
| 55 | + ucTemp[1] = (unsigned char)iAddr; |
| 56 | + rc = I2CWrite(&bbi2c, EEPROM_ADDR, ucTemp, 2); |
| 57 | + } // otherwise read from the last address and increment |
| 58 | + rc = I2CRead(&bbi2c, EEPROM_ADDR, pData, 32); |
| 59 | + return (rc == 32); |
| 60 | +} /* eeReadBlock() */ |
| 61 | + |
| 62 | +const char *szTypes[] = {"invalid", "vendor info", "GPIO map", "Linux device tree blob", "manufacturer custom data", "reserved", "invalid"}; |
| 63 | + |
| 64 | +int main(int argc, char **argv) |
| 65 | +{ |
| 66 | +int i, iAtoms, iLen, iOff; |
| 67 | +uint8_t ucHAT[256], ucTemp[256]; // read some of the HAT info here |
| 68 | + |
| 69 | + memset(&bbi2c, 0, sizeof(bbi2c)); |
| 70 | + bbi2c.bWire = 0; // use bit bang, not wire library |
| 71 | + bbi2c.iSDA = SDA_ID; |
| 72 | + bbi2c.iSCL = SCL_ID; |
| 73 | + I2CInit(&bbi2c, 100000L); |
| 74 | + // Read 256 bytes of the HAT data starting at offset 0 |
| 75 | + for (i=0; i<256; i+=32) { |
| 76 | + eeReadBlock(i, &ucHAT[i]); |
| 77 | + } |
| 78 | + // Print signature |
| 79 | + memcpy(ucTemp, ucHAT, 4); |
| 80 | + ucTemp[4] = 0; |
| 81 | + printf("EEPROM Header Info:\n"); |
| 82 | + printf("signature: %s\n", ucHAT); |
| 83 | + printf("version: 0x%02x\n", ucHAT[4]); |
| 84 | + iAtoms = ucHAT[6]; |
| 85 | + printf("total atoms: %d\n", iAtoms); |
| 86 | + iLen = *(uint32_t *)&ucHAT[8]; |
| 87 | + printf("total length: %d bytes\n", iLen); |
| 88 | + // Display info for each Atom |
| 89 | + iOff = 12; // starting offset of first Atom |
| 90 | + for (i=0; i<iAtoms; i++) { |
| 91 | + uint32_t iType, iSize; |
| 92 | + int j, iPins, vslen, pslen; |
| 93 | + iType = *(uint16_t *)&ucHAT[iOff]; |
| 94 | + if (iType > 5 && iType < 0xffff) iType = 5; // reserved |
| 95 | + if (iType == 0xffff) iType = 0; // invalid |
| 96 | + iSize = *(uint32_t *)&ucHAT[iOff+4]; |
| 97 | + printf("Atom Type: 0x%04x (%s)\n",iType, szTypes[iType]); |
| 98 | + printf("Atom Size: %d bytes\n",iSize); |
| 99 | + if (iType == 0x0001) { // vendor info |
| 100 | + printf("** Vendor Info **\n"); |
| 101 | + 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]); |
| 102 | + printf(" Product ID: %d\n", *(uint16_t *)&ucHAT[iOff+24]); |
| 103 | + printf(" Product Ver: %d\n", *(uint16_t *)&ucHAT[iOff+26]); |
| 104 | + vslen = ucHAT[iOff+28]; // vendor name string length |
| 105 | + pslen = ucHAT[iOff+29]; // vendor product string length |
| 106 | + memcpy(ucTemp, &ucHAT[iOff+30], vslen); |
| 107 | + ucTemp[vslen] = 0; |
| 108 | + printf(" Vendor: %s\n", ucTemp); |
| 109 | + memcpy(ucTemp, &ucHAT[iOff+30+vslen], pslen); |
| 110 | + ucTemp[pslen] = 0; |
| 111 | + printf(" Product: %s\n", ucTemp); |
| 112 | + } else if (iType == 0x0002) { // GPIO map |
| 113 | + printf("** GPIO Map **\n"); |
| 114 | + printf(" GPIO (BCM #) pins used:\n"); |
| 115 | + iPins = 0; |
| 116 | + for (j=0; j<28; j++) { |
| 117 | + if (ucHAT[iOff+10+j] & 0x80) { // bit 7 indicates pin is used |
| 118 | + printf("%02d,",ucHAT[iOff+10+j]); |
| 119 | + iPins++; |
| 120 | + } |
| 121 | + } |
| 122 | + printf("\n %d pins defined\n", iPins); |
| 123 | + } |
| 124 | + iOff += iSize + 8; |
| 125 | + } |
| 126 | + printf("** End of Atom list **\n"); |
| 127 | + return 0; |
| 128 | +} |
0 commit comments