# Question
Title: How to make an Arduino act reliably as an SPI slave?
I want two Arduino Nanos to communicate with each other using SPI, ideally at around 2MHz or faster.

I have two standard Nanos running at 16MHz on 5V.

* The master uses `SPI.transfer()` to send an array across the wire.¹ For ease of troubleshooting, the array alternately contains a bunch of zeroes *or* a bunch of 255s; but never both.
* The slave simply returns decimal 66 for every byte. This was chosen because it's easy to spot on a logic trace.
* The master checks the responses, and if there are any values that aren't 66, it prints the array to the UART.

Even at 125Kbit, which is the slowest available speed, I'm regularly getting corrupted bytes. Interestingly, most of the time (but not always!) the corrupted byte is either 0 or 255 - in other words, exactly the same as the byte sent from the master! This strikes me as a very unlikely coincidence.

I have inspected the traffic with a logic analyser, and it seems that the slave just occasionally decides not to operate as instructed; and instead it just sends the input straight out again. As in, the byte going out on MISO is exactly the same as the byte coming in on MOSI. But only *sometimes.*

What is happening here? Why doesn't it work? And what can I do about it?

---

Master sketch:

```
#define MOSI    12
#define SCK     13

#include <SPI.h>
#include "pins_arduino.h"
#include <avr/wdt.h>

void setup(void) {
    Serial.begin(9600);

    digitalWrite(SS, HIGH);
    pinMode(SS, OUTPUT);
    digitalWrite(SCK, HIGH);
    pinMode(SCK, OUTPUT);
    pinMode(MOSI, OUTPUT);

    SPI.setClockDivider(SPI_CLOCK_DIV128);      // 125KHz
    SPI.begin();

    Serial.println("\n\nSTARTING...\n");
}

void do_transfer(byte attempt, byte payload) {

    // packet size of 200
    byte buffer[200];

    // initialise packet
    for (byte count = 0; count < sizeof(buffer); count++)
        buffer[count] = payload;

    // perform transfer
    digitalWrite(SS, LOW);
    SPI.transfer(buffer, sizeof(buffer));
    digitalWrite(SS, HIGH);    // SS is pin 10

    // tally results
    byte successes = 0, failures = 0;
    for (byte index = 0; index < sizeof(buffer); index++)
        if (buffer[index] == 66) successes++; else failures++;

    // print results
    Serial.print("Attempt ");
    Serial.print(attempt);
    Serial.print(" with payload ");
    Serial.print(payload);
    Serial.print(": ");
    if (failures == 0)
        Serial.print("SUCCESS");
    else {
        Serial.print(successes);
        Serial.print(" correct bytes, ");
        Serial.print(failures);
        Serial.print(" incorrect bytes");
        for (byte index = 0; index < sizeof(buffer); index++) {
            if (index % 10 == 0)
                Serial.print("\n\t");
            if (buffer[index] == 66)
                Serial.print("-");
            else
                Serial.print(buffer[index]);
            if (index < sizeof(buffer) - 1)
                Serial.print("\t");
        }
    }
    Serial.println();
    Serial.println();
}

void loop(void) {
    delay(800);                                                         // give the slave time to be ready

    for (byte attempt = 1; attempt <= 10; attempt+=2) {
        do_transfer(attempt, 0x00);
        do_transfer(attempt+1, 0xFF);
        wdt_reset();
    }
    while(true);                                                        // end of program
}

```

Slave sketch:

```
#include "pins_arduino.h"

void setup(void) {
    pinMode(MISO, OUTPUT);          // MISO needs to be an output
    SPCR |= _BV(SPE);               // enable SPI in slave mode
    SPCR |= _BV(SPIE);              // enable interrupts
    SPDR = 66;
}

ISR (SPI_STC_vect) { SPDR = 66; }   // just send 66 until the cows come home

void loop (void) { }

```

Connections: The following pins on both Arduinos are connected together:

* SS (pin 10)
* MISO (pin 11)
* MOSI (pin 12)
* SCK (pin 13)
* GND

---

¹ The problem also happens if I send one byte at a time using `SPI.transfer()`, unless (maybe) if I insert a 1ms delay between each byte. Which of course is ridiculous.

# Answer
Your problem here is timing. I tried your setup, and found that I did indeed get occasional errors at 125 kHz. Disabling Timer 0 (as suggested by Chrisl) fixed that:

```
  power_timer0_disable();

```

> But while it now works up to 250KHz, I get many many errors at 500KHz.

OK, the time between clock pulses is now 2 µs, however as I document here the time taken to execute an ISR like SPI\_STC\_vect is 2.625 µs, therefore it can't keep up with having to put the data there every 2 s.

You actually have slightly more time than 2 µs because the critical time is the time between the end of the first byte (which is when the ISR is called) and the time before the start of the second byte, which is when the master will start sampling your response.

See screenshot below with the critical time boxed in yellow.

That time is 2.45 µs and the ISR takes 2.625 µs. Now some of that is the ISR epilogue which won't really matter that much, but you can see that things are tight. It's hard to know exactly at what point the processor starts calling the ISR after the last bit arrives, and the length of the instruction it is currently executing could be an influencing factor.

I got your sketches to work running at 250 kHz with these amendments to the slave:

```
#include "pins_arduino.h"
#include <avr/power.h>
#include <avr/sleep.h>

void setup(void) {
  pinMode(MISO, OUTPUT);          // MISO needs to be an output
  SPCR |= _BV(SPE);               // enable SPI in slave mode
  SPCR |= _BV(SPIE);              // enable interrupts
  SPDR = 66;
  power_timer0_disable();
  set_sleep_mode (SLEEP_MODE_IDLE);
}

ISR (SPI_STC_vect) { SPDR = 66; }   // just send 66 until the cows come home

void loop (void)
 {
 sleep_mode ();
 }

```

The sleeping in idle mode makes sure that the processor is not half-way through an instruction when the interrupt is raised.

As expected (for the reasons above) it did not work at 500 kHz.

If you want to transfer data reliably you need to allow, in the master, for the time it takes the slave to do stuff. Every line of code in the slave means that the master has to wait for that to be executed.

I mention that in my page about SPI where I build in a delay in the master, if I want the slave to do calculations or something.

---

> But the datasheet says that speeds of Fosc/4 are possible in slave mode, which would be 4MHz in this case. Would that be achievable if I removed the ISR and just used a busy loop?

Well, yes the datasheet has an example of doing a busy loop:

```
char SPI_SlaveReceive(void)
{
/* Wait for reception complete */
while(!(SPSR & (1<<SPIF)))
;
/* Return Data Register */
return SPDR;
}

```

Regardless of what they claim, what you intend has to be physically possible. So with Fosc/4, assuming a 16 MHz clock, you have 2 µs for a byte to arrive (250 ns * 8). So the hardware may well be able to receive one byte in that time, and you may just have enough clock cycles to notice it arriving and plonk it into memory somewhere (although things could be tight) but you *won't* have time to send a different response after each incoming byte, because you only have around 250 ns to do it in, and the loop that detects the interrupt will probably use up most or all of that.

After a bit of mucking around, I got it to work at 250 kHz where the objective was just for the slave to return some data (after all, I presume that is what the slave is supposed to do).

## Master

```
#define MOSI    12
#define SCK     13

#include <SPI.h>
#include "pins_arduino.h"
#include <avr/wdt.h>

void setup(void) {
    Serial.begin(9600);

    digitalWrite(SS, HIGH);
    pinMode(SS, OUTPUT);
    digitalWrite(SS, HIGH);

    digitalWrite(SCK, HIGH);
    pinMode(SCK, OUTPUT);
    pinMode(MOSI, OUTPUT);

    SPI.begin();
    SPI.setClockDivider(SPI_CLOCK_DIV64);

    Serial.println("\n\nSTARTING...\n");

}

void do_transfer(byte attempt, byte payload) {

    // packet size of 200
    byte buffer[200];

    // perform transfer
    digitalWrite(SS, LOW);
    delay (1);    // give slave time to react
    SPI.transfer(buffer, sizeof(buffer));
    digitalWrite(SS, HIGH);    // SS is pin 10

    // tally results
    byte successes = 0, failures = 0;
    for (byte index = 0; index < sizeof(buffer); index++)
        if (buffer[index] == index) successes++; else failures++;

    // print results
    Serial.print("Attempt ");
    Serial.print(attempt);
    Serial.print(" with payload ");
    Serial.print(payload);
    Serial.print(": ");
    if (failures == 0)
        Serial.print("SUCCESS");
    else {
        Serial.print(successes);
        Serial.print(" correct bytes, ");
        Serial.print(failures);
        Serial.print(" incorrect bytes");
        for (byte index = 0; index < sizeof(buffer); index++) {
            if (index % 10 == 0)
                Serial.print("\n\t");
            if (buffer[index] == index)
                Serial.print("-");
            else
                Serial.print(buffer[index]);
            if (index < sizeof(buffer) - 1)
                Serial.print("\t");
        }
    }
    Serial.println();
    Serial.println();
}

void loop(void) {
    delay(800);                                                         // give the slave time to be ready

    for (byte attempt = 1; attempt <= 10; attempt+=2) {
        do_transfer(attempt, 0x00);
        do_transfer(attempt+1, 0xFF);
        wdt_reset();
    }
    while(true);                                                        // end of program
}

```

## Slave

```
#include "pins_arduino.h"
#include <avr/power.h>
#include <avr/sleep.h>

const int TEST_SIZE = 200;

volatile byte my_data [TEST_SIZE];

volatile byte dummy;

ISR (PCINT0_vect)
 {
 // handle pin change interrupt for D8 to D13 here

  // ignore transition to HIGH
  if (digitalRead (SS) == HIGH)
    return;

  SPDR = 0;

  for (byte i = 0; i < TEST_SIZE; i++)
    {
    SPDR = my_data [i];
    while(!(SPSR & (1<<SPIF)))
      {
      // if SS went high, give up
      if (PINB & (1 << 2))
        return;
      }
    } // end of for loop

 }  // end of PCINT0_vect

void setup(void) {
  pinMode(MISO, OUTPUT);          // MISO needs to be an output
  SPCR |= _BV(SPE);               // enable SPI in slave mode
  power_timer0_disable();
  for (int i = 0; i < TEST_SIZE; i++)
    my_data [i] = i;

  // pin change interrupt for D10
  PCMSK0 |= bit (PCINT2);  // want pin 10
  PCIFR  |= bit (PCIF0);   // clear any outstanding interrupts
  PCICR  |= bit (PCIE0);   // enable pin change interrupts for D8 to D13

  SPDR = 0;

  set_sleep_mode (SLEEP_MODE_IDLE);

}

void loop (void)
  {
  sleep_mode ();
  }

```

At the next clock divisor (SPI\_CLOCK\_DIV32) I started getting occasional errors. After all, Fclk/32 is only 2 µs per clock pulse and 16 µs per byte, and the necessary stuff in the inner loop must be taking that long — I didn't calculate the individual instruction times, you are welcome to do that. :)

I was hoping to get better performance than that, but then I realised that even with a tight sending loop in the slave, you can't afford to send before the master has acknowledged the previous byte (ie. that it has read it) so you still have the tight interval between the end of one byte and the start of the next, which is the time in which you have to prepare the next byte for sending.

It's not as bad if you are the master, because *you* control when the byte starts, so you can take as long as you want between bytes.
> 3 votes

# Answer
My conclusion from Nick's excellent explanations, reading the specifications and based on my own experience (a two-slave system is running without problems since more than a year):

The hardware of an Arduino can reliably send and receive a single byte at 4MHz SPI clock, because dedicated hardware is used.

One can expect that SPI.transfer(bytes, size) can reliably send the bytes at full hardware speed, and even receive reliably the same amout of bytes. It is not specified what the maximum speed is in this case, what the maximum size is, and whether other interrupts are disabled. The library may even disable all and use polling to check for the end of a transfer. So a very long transfer may disturb your system upto failure.

Receiving a block of bytes requires that the slave can process the data at SPI byte speed. If hardware shift registers are used (e.g. in an SD card), you may send many bytes reliably at full speed.

But your Arduino slave has a hardware buffer of 8 Bits only, and the time when the interrupt routine is run is NOT when the last bit of a byte has been sent, but some time later. To predict this time reliably is not trivial. Determining it by experiment is not reliable per se.

Thus, when you want to use SPI block transfers, you need to slow down the SPI speed drastically to give the receiver time to process the data during the time of 8 bits.

You may still use full SPI speed, if you send single bytes (without returning SS) and wait the time required by the slave including any interrupt handling delays.

Or you restrict yourself to single byte transfers at full speed, and use a handshake protocol. This may be quicker than the simple block transfer on the sender's side. Unless you can put operation code and data into 8 bits, you have to maintain state information on both sides.

Conclusion: You may receive single bytes at full SPI speed. The function SPI.transfer(block, bytes) sends more than byte, but does not imply that any SPI slave can collect them. In particular, this function is not appropriate for sending data to an Arduino slave.
> 0 votes

---
Tags: spi, communication
---


# Question
Title: Programming ATtiny1616 error: A programmer is required to upload
I have this ATtiny1616 breakout board and I'm attempting to upload an Arduino sketch to it following this documentation, but I'm getting the error "A programmer is required to upload" upon uploading a simple blink sketch. I have the following parameters set in the IDE:

Board: ATtiny

Chip: Attiny1616

Programmer: Serial UPDI: Slow 57600 baud

I am using this USB-Serial adapter and it is connected to the ATtiny like so:

USB Vcc -\> Vin

USB GND -\> GND

USB RX -\> 1k OHM

USB TX -\> 1k OHM

1k OHM -\> UPDI

And I have an LED connected to pin 5 of the ATtiny:

PIN 5 -\> LED -\> 220 OHM -\> GND

Any help would be greatly appreciated. Thank you.

Edit: Below is the circuit. I also thought that maybe I had RX and TX mixed up, so I tried switching those connections but that didn't work either.

Edit 2: Using Arduino IDE 1.8.19 I get this error:

pymcuprog.pymcuprog\_errors.PymcuprogError: UPDI initialisation failed

# Answer
Please make sure that your USB to serial adapter is working well. If the adapter itself is faulty, it can create problems. Also, check if you have all the necessary drivers installed.

Here is another tutorial regarding how to program the ATTiny1616 Breakout board using the MegaTinycore library. You can find it here :
https://www.pcbway.com/project/shareproject/ATTiny1616\_Minimal\_Breakout\_board\_QFN\_bad990fc.html
> 1 votes

# Answer
In order to use a USB-Serial adapter as a SerialUPDI programmer, it needs to wire it as the diagram shown below

```
                        Vcc                     Vcc
                        +-+                     +-+
                         |                       |
 +---------------------+ |                       | +--------------------+
 |                     +-+                       +-+                    |
 |                     |      +----------+         |                    |
 |                  TX +------+   1k     +---------+ UPDI               |
 |                     |      +----------+    |    |                    |
 | USB-Serial Adaptor  |                      |    |  Target AVR Board  |
 |                     |                      |    |                    |
 |                  RX +----------------------+    |                    |
 |                     |                           |                    |
 |                     +--+                     +--+                    |
 +---------------------+  |                     |  +--------------------+
                         +-+                   +-+
                         GND                   GND

```
> 0 votes

---
Tags: attiny
---


title: GPS Module not catching signal

text:
# Question
Title: GPS Module not catching signal
I am making a gps tracker with neo6m gps module and esp32 dev board.

I checked wiring and coding but still my module isn't catching a signal

I am already on roof of my house in case it require clear sky to connect

This is my code

```
#include <WiFi.h>//for connecting esp32 to a wifi

#include <TinyGPS++.h>//to obtain gps data from neo-6m gps module

#define WIFI_SSID "Airtel_pawa_4182"//wifi name in simple words
#define WIFI_PWD "Ahuja6230"//wifi password

TinyGPSPlus GPS;//creating a gps object from tinygps++ library

void setup() {
 Serial.begin(9600);
  //wifi setup{
  WiFi.begin(WIFI_SSID, WIFI_PWD);
  Serial.println("connecting to wifi");
  while(WiFi.status() != WL_CONNECTED){
   Serial.println(".");
   delay(100);
  }
  Serial.print("Successfully connected to ");
  Serial.println(WIFI_SSID);
  //}

  //gps setup{
  Serial2.begin(9600);
  delay(1000);
  Serial.println(".");
  Serial.println("ESP32-GPS Tracker");
  Serial.println("Initializing...");
  //}
}

void loop() {
  if(Serial2.available() > 0) {
    if(GPS.encode(Serial2.read())) {
      if(GPS.location.isValid()) {
        double latitude = GPS.location.lat();
        double longitude = GPS.location.lng();

        Serial.print(F("- latitude: "));
        Serial.println(latitude);

        Serial.print(F("- longitude: "));
        Serial.println(longitude);
      }
      else{
        Serial.println(F("- location: INVALID"));
      }
      Serial.println();
    }
  }
  if (millis() > 5000 && GPS.charsProcessed() < 10) {
    Serial.println(F("No GPS data received: check wiring"));
  }
}

```

The connection is simple

```
VCC(gps)--->3V3(esp32)

Gnd--->Gnd

Rx---->GPIO17(Tx)

Tx---->GPIO16(Rx)

```

This is what serial monitor reads:

```
connecting to wifi
.
.
.
.
.
Successfully connected to Airtel_pawa_4182
.
ESP32-GPS Tracker
Initializing...
No GPS data received: check wiring
No GPS data received: check wiring
No GPS data received: check wiring
No GPS data received: check wiring

```

How to resolve this issue?

Edit: the breadboard was initially wired wrong but later this was fixed.thanks to Starcat for correcting mistake But still the gps module is taking very much time to catch signal. When it starts, it first print that no gps data recived for some time then it says location is invalid. Only then it prints the lat. and long.Also, the lat and long are not being updated on serial moniter on time. The delay is just one second but it is taking much more time... If anybody has a solution then pls answer..

# Answer
The "No GPS detected" message means that 5 seconds have passed and less than 10 valid characters have arrived at the GPS serial port. Could be a baud rate mismatch.
> 1 votes

# Answer
The breadboard is wired wrong. The parts on either side of the center bar of of the breadboard are not connected to each other (see here), so the white and orange wires and the black yellow and wires are not making a connection.

Solution: Put the wires on the same side of the breadboard and you have a higher change of a working GPS.

You should now at least receive output from the GPS, even if it is just reporting the fact that it has not yet received a valid position. It may take some time (especially when using it for the first time) to get a fix. I would give it at least 30 minutes for the first fix.
> 1 votes

---
Tags: esp32, gps, signal-processing, tinygps
---


# Question
Title: Smoke coming out of Arduino Uno R4 Minima
My Arduino Uno R4 Minima started smoking after connecting to a computer. I disconnected it and visually checked it and I saw this bubble as shown on this photo.

Can I recover my Uno from this to still use it or do I have to throw it away?

# Answer
> 2 votes
The marked IC is burnt. You should complain to the seller and claim warranty. if it is still within the warranty period. If you are very skilled at soldering. You can try to replace the IC.

# Answer
> 6 votes
That's the buck-converter that connects to the external power supply.

The board should still work when powered by the USB cable.

Remove R11 to isolate the blown circuit if you like.

https://docs.arduino.cc/resources/schematics/ABX00080-schematics.pdf

---
Tags: arduino-uno-r4-wifi
---