Specific question about STK500 protocol

Hi all!
I was very interested in checking out what exactly happens during a sketch upload. I hooked up a logic analyzer to my board to check out what exactly occurs when the Arduino IDE uploads a sketch and I used the STK500 protocol docs (ver. 1) to decode the messages. Most of them are straightforward, but there was one set I could not find much information on: what are Universal Commands (command value 0x56) exactly? I've read the brief description and I've tried to decode the ones I see in my capture but I just don't get them :smiley:

Specifically, after avrdude reads the device signature, it proceeds to execute the following Universal commands:
0x56 0x50 0x00 0x00 0x00 0x20 (3 times in a row)
0x56 0x58 0x08 0x00 0x00 0x20 (3 times in a row)
0x56 0x50 0x08 0x00 0x00 0x20 (3 times in a row)
It sends the same 9 commands after all memory pages have been updated too (for whatever reason).

So I dug around and tried to find something that could help decode the values 0x50, 0x58, 0x08. A couple posts online just say "Oh, those are just commands, the bootloader ignores them anyway", which... is fine, but completely useless. Skimming through the AVR datasheet and instruction set amounted to nothing (although I admit that I can easily overlook things).
I understand that the 4 bytes in every universal command are some sort of separate command, but... what, exactly :laughing: ? What protocol does it belong to? What other command types exist? And, most importantly, what do they decode to? Are they important to the upload process? It has something to do with settings fuse and lock bits, but if someone could just break these commands into pieces and explain what they denote, I'll be really grateful!

See the Serial Programming Instruction Set in the datasheet.

$50 $00 Read Fuse bits
$58 $08 Read Fuse High Bits
$50 $08 Read Extended Fuse Bits

Hi John! I must be really careless lately, because I honestly cannot find the source you're referring to :laughing: . Once I'd posted my original question, I did notice the pseudocode in the STK500 comms protocol v1 doc appendix, where we can see the values 0x50 0x00 and 0x58 0x08 being used to read the low and high fuse bytes. But I can't find any place where these instructions are described in detail. Could you kindly provide a link to this instruction set you mention?

Additionally, I have 2 more questions:

  • why would avrdude read each fuse byte 3 times (seems a bit redundant)?
  • why would it do so before AND after uploading a sketch?

ATmega48A/PA/88A/PA/168A/PA/328/P Data Sheet
DS number 40002061
Download from: Dynamic Product Page | Microchip Technology

Section 28.8.3: Serial Programming Instruction set
Table 28-19 on page 305 and Figure 28-8 on page 306 describes the Instruction set

1 Like

I think you will have to look at the edit history of avrdude to find out details like that. Perhaps some device didn't work right if you didn't check three times before and after.

1 Like

Found it! Thanks a lot for the clarification!
So the multiple serial read instructions are probably historic at this point. Just for the fun of it, I will follow the trail you suggest and try to find out why they still exist in avrdude :smiley:. Thanks again!

First, if you turn on additional debugging for avrdude (add "-vvvv" to the command line - each v increases the amount of debugging info), it will tell you what it's doing:

avrdude: safemode read 1, lfuse value: 0
avrdude: Send: V [56] P [50] . [00] . [00] . [00]   [20] 
avrdude: Recv: . [14] 
avrdude: Recv: . [00] 
avrdude: Recv: . [10] 
avrdude: safemode read 2, lfuse value: 0
avrdude: Send: V [56] P [50] . [00] . [00] . [00]   [20] 
avrdude: Recv: . [14] 
avrdude: Recv: . [00] 
avrdude: Recv: . [10] 
avrdude: safemode read 3, lfuse value: 0
avrdude: safemode: lfuse reads as 0
avrdude: Send: V [56] X [58] . [08] . [00] . [00]   [20] 
avrdude: Recv: . [14] 
avrdude: Recv: . [00] 
avrdude: Recv: . [10] 
avrdude: safemode read 1, hfuse value: 0
avrdude: Send: V [56] X [58] . [08] . [00] . [00]   [20] 
avrdude: Recv: . [14] 
avrdude: Recv: . [00] 
avrdude: Recv: . [10] 
avrdude: safemode read 2, hfuse value: 0
avrdude: Send: V [56] X [58] . [08] . [00] . [00]   [20] 
avrdude: Recv: . [14] 
avrdude: Recv: . [00] 
avrdude: Recv: . [10] 
avrdude: safemode read 3, hfuse value: 0
avrdude: safemode: hfuse reads as 0
avrdude: Send: V [56] P [50] . [08] . [00] . [00]   [20] 
avrdude: Recv: . [14] 
avrdude: Recv: . [00] 
avrdude: Recv: . [10] 
avrdude: safemode read 1, efuse value: 0
avrdude: Send: V [56] P [50] . [08] . [00] . [00]   [20] 
avrdude: Recv: . [14] 
avrdude: Recv: . [00] 
avrdude: Recv: . [10] 
avrdude: safemode read 2, efuse value: 0
avrdude: Send: V [56] P [50] . [08] . [00] . [00]   [20] 
avrdude: Recv: . [14] 
avrdude: Recv: . [00] 
avrdude: Recv: . [10] 
avrdude: safemode read 3, efuse value: 0
avrdude: safemode: efuse reads as 0

Then, armed with the info that this has something to do with "safemode", you can find avrdude documentation:

Ie - it's reading the fuses three times each to make sure that it's getting the same value each time. (I'm not aware of the history that apparently created the need for this. Seems weird.)

Amusingly (?) the bootloader doesn't actually "support" the commands to read the fuses (or any of the other "Universal" commands); it just eats the arguments and returns 0...

    else if(ch == STK_UNIVERSAL) {
      // UNIVERSAL command is ignored
      getNch(4);
      putch(0x00);
    }
1 Like

Interesting trivia indeed, thanks @westfw! If it were possible to mark 2 posts as solutions, I'd mark this one as well since it answers another one of my several questions. Maybe this particular bootloader is programmed to ignore these commands just to make the bootloader code smaller (i.e. more space for application code)?

Yes, exactly.