#!/usr/bin/perl # # readI2cEeprom.pl # Version 1.01 # 04 March 2015 # # A script to read from the AT24C32 eeprom (4K bytes) # attached to the Raspberry Pi's i2c bus #1 at address 0x57 # The AT24C32 uses 12 address bits - with max address 0xFFF # The datasheet states that when used at 3.3 volts, # the i2c bus maximum speed is 100kHz # # Two parameters must be passed to this script: # -a the start address for the read (decimal or hex in the format 0xFFF) # -l the number of bytes to read # -o the output filename can be omitted. If present and contains a valid path # with a filename, the output will go to the named file, creating it # if necessary. # If -o is not present or is empty, the output is displayed on screen # with address information. # A fourth parameter '-h' is optional # If included, -h causes the screen output to display as # hex characters instead of 'ascii' characters # # The script must be called as root, but lowers permissions once # the i2c object has been created # use Getopt::Std; use HiPi::Utils; use File::Basename; use HiPi::BCM2835::I2C qw( :all ); # use strict; # # get the parameters (-a, -l, -o) getopt('alo:'); # our ( $opt_a, $opt_l, $opt_o, $opt_h, $opt_v ); # # setup regular user & group id's for lowering permissions my $user = ''; my $group = ''; # #setup bus number, eeprom address on i2c bus and max eeprom address my $i2cBus = BB_I2C_PERI_1; my $i2cAddr = 0x57; my $eeMax = 0xFFF; # # character to print on screen in place of codes <32 decimal my $repl = "~"; # # Test & handle parameters if ( $opt_a > $eeMax ) { # address exceeds last eeprom address so exit exit 1; } elsif ( $opt_a eq "" ) { # no address information - defaults to 0 $opt_a = 0; } # if ( $opt_l eq "" ) { # no length information - defaults to 32 (1 page) $opt_l = 32; } # # create i2c device object my $objI2c = HiPi::BCM2835::I2C->new( peripheral => $i2cBus, address => $i2cAddr ); # HiPi::Utils::drop_permissions_name( $user, $group ); # $objI2c->set_baudrate( $i2cBus, BB_I2C_CLOCK_100_KHZ ); # # test -o parameter # first set flag for printing formatted output with hex addresses my $outFlag = 1; if ( !$opt_o == undef ) { # -o is present # set flag to stop address formatted output $outFlag = 0; # get path and filename my $path = dirname $opt_o; my $file = basename $opt_o; # test for existence of path if ( -d $path ) { # path exists - so test for output file if ( !-f $file ) { # file does not exist, so create it open( OFILE, ">", $opt_o ) || die "Could not open file $file"; } else { # file does exist, so open it and append data open( OFILE, ">>", $opt_o ) || die "Could not open file $file"; } } else { # path does not exist - exit with error 2 exit 2; } } # # convert start address if hex value used if ( substr( $opt_a, 0, 2 ) == "0x" ) { $opt_a = hex($opt_a); } # # address manipulations - opt_a contains requested start address my $addrPB = ( $opt_a & 0b0000111111100000 ); # 32 byte page boundary my $addrMSB = ( $addrPB & 0b0000111100000000 ) >> 8; # MSB (upper nibble always zero) my $addrLSB = ( $addrPB & 0b0000000011111111 ); # LSB (at page boundary) my $addrRA = ( $opt_a & 0b0000111111100000 ) >> 4; # row address for output table # # calculate offset from start of first page boundary to start address requested my $offst = $opt_a - $addrPB; # # calculate number of bytes to read # length requested + offset from page boundary to first byte requested my $numbBytes = $opt_l + $offst; # # crop number of bytes to read if read exceeds max eeprom address if ( $opt_a + $opt_l > $eeMax ) { $numbBytes = $numbBytes - ( $opt_a + $opt_l - $eeMax -1 ); } # # write base address for read (at page boundary) $objI2c->bus_write( $addrMSB, $addrLSB ); # # read number of bytes into array my @RdData = $objI2c->i2c_read($numbBytes); # if ($outFlag) { # print formatted output with hex addresses if ( !$opt_h ) { # display data as characters - 32 bytes per row print "\n 32 bytes of data per row\n"; print " 0--------------f0--------------f\n"; for ( my $i = 0 ; $i < $numbBytes ; $i++ ) { if ( $i % 32 == 0 ) { # print row start address and increment it printf( "%02x ", $addrRA ); $addrRA = $addrRA + 2; } if ( $i >= $offst ) { # print data if at or after start address (uses offset value) # characters <32 replaced by a printable character if ( $RdData[ $i ] < 32 ) { print $repl; } else { printf "%s", chr( $RdData[ $i ] ); } } else { # haven't reached start address - so print blanks print " "; } if ( ( $i + 1 ) % 32 == 0 ) { # every 32 bytes start new row print "\n"; } } print "\n\n"; } else { # display data as hex pairs, 16 bytes per line # print hex column headers print "\n 0 1 2 3 4 5 6 7 8 9 a b c d e f\n"; for (my $i = 0 ; $i < $numbBytes ; $i++ ) { if ( $i % 16 == 0 ) { # print row start address and increment it printf( "%02x ", $addrRA ); $addrRA = $addrRA + 1; } if ( $i >= $offst ) { # print data if at or after start address (uses offset) printf "%02x ", $RdData[ $i ]; } else { # haven't reached start address - so print position marks print ".. "; } if ( ( $i + 1 ) % 16 == 0 ) { # every 16 bytes start new row print "\n"; } } print "\n\n"; } } else { # print to file for ( my $i = 0 ; $i < $numbBytes ; $i++ ) { if ( $i >= $offst ) { # print data if at or after start address (uses offset) print OFILE chr( $RdData[ $i ] ); } } } # exit 0;