AVR Read/Write to another AVR's EEPROM via ICSP [Solved]

First off I'm relatively new to coding so please bare with me.

I cobbled together some code to read the internal AVR EEPROM to Serial. Nothing fancy. It can read the value at an address, write a value to an address, or list the address/values.

/* Program based off work from the below source
     
    Arduino EEPROM Read/Write using Serial Monitor
    https://circuits.io/circuits/1366613-arduino-eeprom-read-write-using-serial-monitor
    Author: Eric W. Johnson  
    Date 13th December 2015

*/


#include <EEPROM.h>

// ********************************
// Declare and initialize variables
String strCommand = "";           // string variable to hold the command
char chrInput[128];               // character variable for reading bytes
boolean bDisplayMessage = true;   // boolean variable to determine whether or not to display message.
int iLocRead = 0;                 // integer variable for location of 'read'
int iLocWrite = 0;                // integer variable for location of 'write'
int iLocList = 0;                 // integer variable for location of 'list'
int iLocSpace = 0;                // integer variable for location of space
int iAddress = 0;                 // integer variable for EEPROM address
byte bytValue = 0;                // byte variable for value stored at EEPROM address
String strTmp = "";               // temporary string variable

// ********************************
// SETUP serial monitor
void setup() {
  Serial.begin(9600);           // Set baud rate for serial monitor
  
}

// ********************************
void loop() {
  // Display informational message if it's not already displayed
  if (bDisplayMessage) {
    Serial.println("\nPlease enter a command. Read <address>, Write <address> <value> Or List");
    bDisplayMessage = false;  // suppress message, for now.
  }

  // Get command and store in a string
  if (Serial.available()) {
    //Wait a bit, then read the serial buffer
    delay(100);

    if (false) {
      Serial.readBytes(chrInput, 128);
      strCommand = String(chrInput);
    }
    else {
      strCommand = Serial.readString();
      strCommand.toUpperCase();          // change to upper case to allow mixed case commands
    }

    // Determine if it's a read or a write command
    iLocRead = strCommand.indexOf("READ");      // location of 'read'
    iLocWrite = strCommand.indexOf("WRITE");    // location of 'write'
    iLocList = strCommand.indexOf("LIST");    // location of 'list'

    // Display error message if command not found.
    if (iLocRead < 0 && iLocWrite < 0 && iLocList < 0) {
      Serial.println("\nNo read or write command found, please try again.");
    }
    else {

      if (iLocRead >= 0) {    // Process read command
        strTmp = strCommand.substring(iLocRead + 5);
        iAddress = strTmp.toInt();
        bytValue = EEPROM.read(iAddress);
        Serial.println("The contents of EEPROM address " + String(iAddress) + " is " + String(bytValue));
      }
      else if (iLocList >= 0) {  // List locations and values for a set number
        Serial.println("List EEPROM");
        Serial.println();
        Serial.print("Loc");
        Serial.print("\t");
        Serial.print("Value");
        Serial.println();
        iAddress = 0;
        while (iAddress < 45) {
          bytValue = EEPROM.read(iAddress);
          Serial.print(iAddress);
          Serial.print("\t");
          Serial.print(bytValue, DEC);
          Serial.println();
          iAddress++;
        }
      }
      else {                  // Process write command
        strTmp = strCommand.substring(iLocWrite + 6);
        iAddress = strTmp.toInt();
        iLocSpace = strTmp.indexOf(" ");        // location of space
        strTmp = strTmp.substring(iLocSpace + 1);
        bytValue = strTmp.toInt();
        EEPROM.write(iAddress, bytValue);
        Serial.println("The value of " + String(bytValue) + " has been saved to EEPROM address " + String(iAddress));
      }

    }   // END else{ Process Command

    bDisplayMessage = true;       // Get next command

  }   // END if (Serial.available())

}   // END void loop()

This works well but it can only access the internal EEPROM. I'd like to have a version that can read/write from the "Master" AVR to the "Target" AVR's EEPROM via ISP. Very similar to Nick Gammon's excellent Atmega_Board_Programmer. I had hoped to simply add the ability to this Programmer sketch but so far have been unsuccessful. There is a lot going on in his program and my skills just are lacking.

(continued from post above as I was over 9000 characters)

So I'd like to put together a simplified version based on the sketch above.

To get it to work I know I need to add code to;

  • Communicate via ISP and put the Target board into program mode. (Master Pin 10 -> Target Reset)
  • Send command to read/write EEPROM value to Target address
  • Take the Target board out of program mode.

Page 233 of the Atmega8 data sheet details the communication needed to do this. The Atmega328 and Atmega8 with be the Target boards most commonly used in my application. From what I have read the Atmega8 can't be polled like the Atmega328.

Looking at the ArduinoISP code it seems it has the code to put the target board into/out of programming mode as well as some of the EEPROM read/write code.

I've added what I think are the pertinent parts to the original sketch. I know I will need to remove the internal EEPROM parts.

/* Program based off work from the below sources 
     
    Arduino EEPROM Read/Write using Serial Monitor
    https://circuits.io/circuits/1366613-arduino-eeprom-read-write-using-serial-monitor
    Author: Eric W. Johnson  
    Date 13th December 2015

    ArduinoISP version 04m3
    https://www.arduino.cc/en/Tutorial/ArduinoISP
    Copyright (c) 2008-2011 Randall Bohn

    Atmega Board Detector
    https://github.com/nickgammon/arduino_sketches/tree/master/Atmega_Board_Detector
    Author: Nick Gammon
    Date: 22nd May 2012
    Version: 1.19

*/


#include <EEPROM.h>
#include <SPI.h>

// ********************************
// Declare and initialize variables
String strCommand = "";           // string variable to hold the command
char chrInput[128];               // character variable for reading bytes
boolean bDisplayMessage = true;   // boolean variable to determine whether or not to display message.
int iLocRead = 0;                 // integer variable for location of 'read'
int iLocWrite = 0;                // integer variable for location of 'write'
int iLocList = 0;                 // integer variable for location of 'list'
int iLocSpace = 0;                // integer variable for location of space
int iAddress = 0;                 // integer variable for EEPROM address
byte bytValue = 0;                // byte variable for value stored at EEPROM address
String strTmp = "";               // temporary string variable
int pmode=0;
#define RESET     10

// ********************************
// SETUP serial monitor
void setup() {
  Serial.begin(9600);           // Set baud rate for serial monitor
  
}

// ********************************
void loop() {
  // Display informational message if it's not already displayed
  if (bDisplayMessage) {
    Serial.println("\nPlease enter a command. Read <address>, Write <address> <value> Or List");
    bDisplayMessage = false;  // suppress message, for now.
  }

  // Get command and store in a string
  if (Serial.available()) {
    //Wait a bit, then read the serial buffer
    delay(100);

    if (false) {
      Serial.readBytes(chrInput, 128);
      strCommand = String(chrInput);
    }
    else {
      strCommand = Serial.readString();
      strCommand.toUpperCase();          // change to upper case to allow mixed case commands
    }

    // Determine if it's a read or a write command
    iLocRead = strCommand.indexOf("READ");      // location of 'read'
    iLocWrite = strCommand.indexOf("WRITE");    // location of 'write'
    iLocList = strCommand.indexOf("LIST");    // location of 'list'

    // Display error message if command not found.
    if (iLocRead < 0 && iLocWrite < 0 && iLocList < 0) {
      Serial.println("\nNo read, write or list command found, please try again.");
    }
    else {

      if (iLocRead >= 0) {    // Process read command
        strTmp = strCommand.substring(iLocRead + 5);
        iAddress = strTmp.toInt();
        bytValue = EEPROM.read(iAddress);
        Serial.println("The contents of EEPROM address " + String(iAddress) + " is " + String(bytValue));
      }
      else if (iLocList >= 0) { // List locations and values for a set number
        Serial.println("List EEPROM");
        Serial.println();
        Serial.print("Loc");
        Serial.print("\t");
        Serial.print("Value");
        Serial.println();
        iAddress = 0;
        while (iAddress < 45) {
          bytValue = EEPROM.read(iAddress);
          Serial.print(iAddress);
          Serial.print("\t");
          Serial.print(bytValue, DEC);
          Serial.println();
          iAddress++;
        }
      }
      else {                  // Process write command
        strTmp = strCommand.substring(iLocWrite + 6);
        iAddress = strTmp.toInt();
        iLocSpace = strTmp.indexOf(" ");        // location of space
        strTmp = strTmp.substring(iLocSpace + 1);
        bytValue = strTmp.toInt();
        EEPROM.write(iAddress, bytValue);
        Serial.println("The value of " + String(bytValue) + " has been saved to EEPROM address " + String(iAddress));
      }

    }   // END else{ Process Command

    bDisplayMessage = true;       // Get next command

  }   // END if (Serial.available())

}   // END void loop()

void startProgramming() {
  spi_init();
  pinMode(RESET, OUTPUT);
  digitalWrite(RESET, HIGH);
  pinMode(SCK, OUTPUT);
  digitalWrite(SCK, LOW);
  delay(50);
  digitalWrite(RESET, LOW);
  delay(50);
  pinMode(MISO, INPUT);
  pinMode(MOSI, OUTPUT);
  spi_transaction(0xAC, 0x53, 0x00, 0x00);
  pmode = 1;
}

void stopProgramming() {
  digitalWrite (RESET, LOW);
  digitalWrite (SCK,   LOW);
  digitalWrite (MOSI,  LOW);
  digitalWrite (MISO,  LOW);
  pinMode (RESET, INPUT);
  pinMode(MISO, INPUT);
  pinMode(MOSI, INPUT);
  pinMode(SCK, INPUT);
  pmode = 0;
}

void spi_init() {
  uint8_t x;
  SPCR = 0x53;
  x=SPSR;
  x=SPDR;
}

void spi_wait() {
  do {
  } 
  while (!(SPSR & (1 << SPIF)));
}

uint8_t spi_send(uint8_t b) {
  uint8_t reply;
  SPDR=b;
  spi_wait();
  reply = SPDR;
  return reply;
}

uint8_t spi_transaction(uint8_t a, uint8_t b, uint8_t c, uint8_t d) {
  uint8_t n;
  spi_send(a); 
  n=spi_send(b);
  //if (n != a) error = -1;
  n=spi_send(c);
  return spi_send(d);
 
}

//Below are the EEPROM transaction codes 0xC0 for write and 0xA0 for read

//// write (length) bytes, (start) is a byte address
//uint8_t write_eeprom_chunk(int start, int length) {
//  // this writes byte-by-byte,
//  // page writing may be faster (4 bytes at a time)
//  fill(length);
//  prog_lamp(LOW);
//  for (int x = 0; x < length; x++) {
//    int addr = start+x;
//    spi_transaction(0xC0, (addr>>8) & 0xFF, addr & 0xFF, buff[x]);
//    delay(45);
//  }
//  prog_lamp(HIGH); 
//  return STK_OK;
//}

//char eeprom_read_page(int length) {
//  // here again we have a word address
//  int start = here * 2;
//  for (int x = 0; x < length; x++) {
//    int addr = start + x;
//    uint8_t ee = spi_transaction(0xA0, (addr >> 8) & 0xFF, addr & 0xFF, 0xFF);
//    Serial.print((char) ee);
//  }
//  return STK_OK;
//}

//http://www.atmel.com/Images/Atmel-2486-8-bit-AVR-microcontroller-ATmega8_L_datasheet.pdf
//Page 233 Serial Programming Set

Okay, now I've tried to explain what I'm trying to do, is there anyone that has dealt with this before and could give me some direction to get this to work? Any help is greatly appreciated!

Okay, it's not pretty but I finally figured out how to get the Master AVR to read the Target's EEPROM. (Happy dance!) Lots of scouring the web and the Adruino Reference page for info.

Next I need to figure out writing to the the Target's EEPROM. I also need to add a check to report when a Target isn't connected as it still returns a 255 value when the Target is absent.

Attached is the code.

/* Program based off work from the below sources 
     
    Arduino EEPROM Read/Write using Serial Monitor
    https://circuits.io/circuits/1366613-arduino-eeprom-read-write-using-serial-monitor
    Author: Eric W. Johnson  
    Date 13th December 2015

    ArduinoISP version 04m3
    https://www.arduino.cc/en/Tutorial/ArduinoISP
    Copyright (c) 2008-2011 Randall Bohn

    Atmega Board Detector
    https://github.com/nickgammon/arduino_sketches/tree/master/Atmega_Board_Detector
    Author: Nick Gammon
    Date: 22nd May 2012
    Version: 1.19

    AVR-standalone-ISP
    https://github.com/DeqingSun/AVR-standalone-ISP
    Author: DeqingSun
    Date: Mar 15, 2015

    http://www.atmel.com/Images/Atmel-2486-8-bit-AVR-microcontroller-ATmega8_L_datasheet.pdf
    Page 233 Serial Programming Set
    
*/


#include <EEPROM.h>
#include <SPI.h>

// ********************************
// Declare and initialize variables
String strCommand = "";           // string variable to hold the command
char chrInput[128];               // character variable for reading bytes
boolean bDisplayMessage = true;   // boolean variable to determine whether or not to display message.
int iLocRead = 0;                 // integer variable for location of 'read'
int iLocWrite = 0;                // integer variable for location of 'write'
int iLocList = 0;                 // integer variable for location of 'list'
int iLocSpace = 0;                // integer variable for location of space
int iAddress = 0;                 // integer variable for EEPROM address
byte bytValue = 0;                // byte variable for value stored at EEPROM address
String strTmp = "";               // temporary string variable
int pmode=0;

#define RESET 10 // Connect Target RESET to D10 of Master

// ********************************
// SETUP serial monitor
void setup() {
  Serial.begin(9600);           // Set baud rate for serial monitor

}

// ********************************
void loop() {
  // Display informational message if it's not already displayed
  if (bDisplayMessage) {
    Serial.println("\nPlease enter a command. Read <address>, Write <address> <value> Or List");
    bDisplayMessage = false;  // suppress message, for now.
  }

  // Get command and store in a string
  if (Serial.available()) {
    //Wait a bit, then read the serial buffer
    delay(100);

    if (false) {
      Serial.readBytes(chrInput, 128);
      strCommand = String(chrInput);
    }
    else {
      strCommand = Serial.readString();
      strCommand.toUpperCase();          // Change to upper case to allow mixed case commands
    }

    // Determine if it's a read or a write command
    iLocRead = strCommand.indexOf("READ");      // location of 'read'
    iLocWrite = strCommand.indexOf("WRITE");    // location of 'write'
    iLocList = strCommand.indexOf("LIST");    // location of 'list'

    // Display error message if command not found.
    if (iLocRead < 0 && iLocWrite < 0 && iLocList < 0) {
      Serial.println("\nNo read, write or list command found, please try again.");
    }
    else {

      if (iLocRead >= 0) {    // Process read command
        strTmp = strCommand.substring(iLocRead + 5);
        iAddress = strTmp.toInt(); 
        startProgramming();
        bytValue = spi_transaction(0xA0, (iAddress >> 8) & 0x1F, iAddress & 0xFF, 0x00) & 0xFF;
        stopProgramming(); 
        Serial.println("The contents of Target EEPROM address " + String(iAddress) + " is " + String(bytValue));
      }
      else if (iLocList >= 0) { // List locations and values for a set number
        Serial.println("List EEPROM");
        Serial.println();
        Serial.print("Address");
        Serial.print("\t");
        Serial.print("Value");
        Serial.println();
        iAddress = 0;
        while (iAddress < 45) {
          bytValue = EEPROM.read(iAddress);
          Serial.print(iAddress);
          Serial.print("\t");
          Serial.print(bytValue, DEC);
          Serial.println();
          iAddress++;
        }
      }
      else {                  // Process write command
        strTmp = strCommand.substring(iLocWrite + 6);
        iAddress = strTmp.toInt();
        iLocSpace = strTmp.indexOf(" ");        // location of space
        strTmp = strTmp.substring(iLocSpace + 1);
        bytValue = strTmp.toInt();
        EEPROM.write(iAddress, bytValue);
        Serial.println("The value of " + String(bytValue) + " has been saved to EEPROM address " + String(iAddress));
      }

    }   // END else{ Process Command

    bDisplayMessage = true;       // Get next command

  }   // END if (Serial.available())

}   // END void loop()

unsigned char readByteEEPROM(unsigned int addr) {
  unsigned char value = spi_transaction(0xA0, (addr >> 8) & 0x1F, addr & 0xFF, 0x00) & 0xFF;
  return value;
}

void startProgramming() {
  digitalWrite(PROG_LED, HIGH);
  spi_init();
  pinMode(RESET, OUTPUT);
  digitalWrite(RESET, HIGH);
  pinMode(SCK, OUTPUT);
  digitalWrite(SCK, LOW);
  delay(50);
  digitalWrite(RESET, LOW);
  delay(50);
  pinMode(MISO, INPUT);
  pinMode(MOSI, OUTPUT);
  spi_transaction(0xAC, 0x53, 0x00, 0x00);
  pmode = 1;
}

void stopProgramming() {
  digitalWrite (RESET, LOW);
  digitalWrite (SCK,   LOW);
  digitalWrite (MOSI,  LOW);
  digitalWrite (MISO,  LOW);
  pinMode (RESET, INPUT);
  pinMode(MISO, INPUT);
  pinMode(MOSI, INPUT);
  pinMode(SCK, INPUT);
  digitalWrite(PROG_LED, LOW);
  pmode = 0;
}

void spi_init() {
  uint8_t x;
  SPCR = 0x53;
  x=SPSR;
  x=SPDR;
}

void spi_wait() {
  do {
  } 
  while (!(SPSR & (1 << SPIF)));
}

uint8_t spi_send(uint8_t b) {
  uint8_t reply;
  SPDR=b;
  spi_wait();
  reply = SPDR;
  return reply;
}

uint8_t spi_transaction(uint8_t a, uint8_t b, uint8_t c, uint8_t d) {
  uint8_t n;
  spi_send(a); 
  n=spi_send(b);
  //if (n != a) error = -1;
  n=spi_send(c);
  return spi_send(d); 
}

Please feel free to critique or point out any programming faux pas as I'm still very new to this.

Well I finally got the Read/Write/List functionality working. I've attached the code so hopefully it will help someone looking to do something similar. Didn't get much response here. ¯_(ツ)_/¯

/* 
  Arduino EEPROM Read/Write via ICSP
  Author: Jon Raymond
  Date: March 19th 2017
  Version: 0.33

  The point of this program is to enable read/write/list of EEPROM values of a target 
  AVR without interfacing with the code running on it. Handy if you need to modify 
  parameters of chips running legacy code that you don't have source to.
  
  ------------------------------------------------------------
  "THE BEERWARE LICENSE":
  Jon Raymond pieced together this abomination of code. As long as you retain this 
  notice, you can do whatever you want with this stuff. If we
  meet someday, and anything here helped you, you can
  buy me a beer in return. Cheers
  ------------------------------------------------------------  
   Program based off work from the below sources 
     
    Arduino EEPROM Read/Write using Serial Monitor
    https://circuits.io/circuits/1366613-arduino-eeprom-read-write-using-serial-monitor
    Author: Eric W. Johnson  
    Date 13th December 2015

    ArduinoISP version 04m3
    https://www.arduino.cc/en/Tutorial/ArduinoISP
    Copyright (c) 2008-2011 Randall Bohn

    Atmega Board Detector
    https://github.com/nickgammon/arduino_sketches/tree/master/Atmega_Board_Detector
    Author: Nick Gammon
    Date: 22nd May 2012
    Version: 1.19

    AVR-standalone-ISP
    https://github.com/DeqingSun/AVR-standalone-ISP
    Author: DeqingSun
    Date: Mar 15, 2015

    http://www.atmel.com/Images/Atmel-2486-8-bit-AVR-microcontroller-ATmega8_L_datasheet.pdf
    Page 233 Serial Programming Set
    
*/

#include <SPI.h>

// ********************************
// Declare and initialize variables
String strCommand = "";           // string variable to hold the command
char chrInput[128];               // character variable for reading bytes
boolean bDisplayMessage = true;   // boolean variable to determine whether or not to display message.
int iLocRead = 0;                 // integer variable for location of 'read'
int iLocWrite = 0;                // integer variable for location of 'write'
int iLocList = 0;                 // integer variable for location of 'list'
int iLocSpace = 0;                // integer variable for location of space
int iAddress = 0;                 // integer variable for EEPROM address
byte bytValue = 0;                // byte variable for value stored at EEPROM address
String strTmp = "";               // temporary string variable
//int pmode=0;

#define RESET 10  // Important - Reset of Target need to be connected to D10 of Master

// ********************************
// SETUP serial monitor
void setup() {
  Serial.begin(9600);           // Set baud rate for serial monitor
  //Serial.begin(115200); 
}

// ********************************
void loop() {
  // Display informational message if it's not already displayed
  if (bDisplayMessage) {
    Serial.println(F("\nPlease enter a command. Read <address>, Write <address> <value> Or List"));
    bDisplayMessage = false;  // suppress message, for now.
  }

  // Get command and store in a string
  if (Serial.available()) {
    //Wait a bit, then read the serial buffer
    delay(100);

    if (false) {
      Serial.readBytes(chrInput, 128);
      strCommand = String(chrInput);
    }
    else {
      strCommand = Serial.readString();
      strCommand.toUpperCase();          // change to upper case to allow mixed case commands
    }

    // Determine if it's a read, write or list command
    iLocRead = strCommand.indexOf("READ");      // location of 'read'
    iLocWrite = strCommand.indexOf("WRITE");    // location of 'write'
    iLocList = strCommand.indexOf("LIST");    // location of 'list'

    // Display error message if command not found.
    if (iLocRead < 0 && iLocWrite < 0 && iLocList < 0) {
      Serial.println(F("\nNo read, write or list command found, please try again."));
    }
    else {

      if (iLocRead >= 0) {    // Process read command
        strTmp = strCommand.substring(iLocRead + 5);
        iAddress = strTmp.toInt();
        startProgramming();
// ** Need to add check if startProgramming was successfull as Read returns 255 if not connected
          bytValue = spi_transaction(0xA0, (iAddress >> 8) & 0x1F, iAddress & 0xFF, 0x00) & 0xFF;
        stopProgramming(); 
        Serial.println("The contents of Target EEPROM address " + String(iAddress) + " is " + String(bytValue));
      }
      else if (iLocList >= 0) { // List locations and values for a set number
        Serial.println(F("\nList Target EEPROM"));
        Serial.print(F("Address"));
        Serial.print("\t");
        Serial.print(F("Value"));
        Serial.println();
        iAddress = 0;
        startProgramming();
          while (iAddress < 41) {
            bytValue = spi_transaction(0xA0, (iAddress >> 8) & 0x1F, iAddress & 0xFF, 0x00) & 0xFF;
            Serial.print(iAddress);
            Serial.print("\t");
            Serial.print(bytValue, DEC);
            Serial.println();
            iAddress++;
        }
        stopProgramming();
      }
      else {                  // Process write command
        strTmp = strCommand.substring(iLocWrite + 6);
        iAddress = strTmp.toInt();
        iLocSpace = strTmp.indexOf(" ");        // location of space
        strTmp = strTmp.substring(iLocSpace + 1);
        bytValue = strTmp.toInt();
        startProgramming();
         spi_transaction(0xC0, (iAddress >> 8) & 0xFF, iAddress & 0xFF, bytValue); // Write value to address
// ** Need to add check if value was written to address
        stopProgramming(); 
        Serial.println("The value of " + String(bytValue) + " has been saved to Targets EEPROM address " + String(iAddress));
      }

    }   // END else{ Process Command

    bDisplayMessage = true;       // Get next command

  }   // END if (Serial.available())

}   // END void loop()

void startProgramming() {
  spi_init();
  pinMode(RESET, OUTPUT);
  digitalWrite(RESET, HIGH);
  pinMode(SCK, OUTPUT);
  digitalWrite(SCK, LOW);
  delay(50);
  digitalWrite(RESET, LOW);
  delay(50);
  pinMode(MISO, INPUT);
  pinMode(MOSI, OUTPUT);
  spi_transaction(0xAC, 0x53, 0x00, 0x00);
//  pmode = 1;
}

void stopProgramming() {
  digitalWrite (RESET, LOW);
  digitalWrite (SCK,   LOW);
  digitalWrite (MOSI,  LOW);
  digitalWrite (MISO,  LOW);
  pinMode (RESET, INPUT);
  pinMode(MISO, INPUT);
  pinMode(MOSI, INPUT);
  pinMode(SCK, INPUT);
//  pmode = 0;
}

void spi_init() {
  uint8_t x;
  SPCR = 0x53;
  x=SPSR;
  x=SPDR;
}

void spi_wait() {
  do {
  } 
  while (!(SPSR & (1 << SPIF)));
}

uint8_t spi_send(uint8_t b) {
  uint8_t reply;
  SPDR=b;
  spi_wait();
  reply = SPDR;
  return reply;
}

uint8_t spi_transaction(uint8_t a, uint8_t b, uint8_t c, uint8_t d) {
  uint8_t n;
  spi_send(a); 
  n=spi_send(b);
  //if (n != a) error = -1;
  n=spi_send(c);
  return spi_send(d); 
}
1 Like