[SOLVED] Accessing the device serial number through avrISP versus through boot_signature_byte_get

Go To Last Post
3 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

 

I am having a problem determining the correct unique serial number on an ATmega328PB when using avrISP, and I was hoping for a little insight into what I'm doing wrong.

 

 

If I run an app on the ATmega328PB to retrieve the serial number using boot_signature_byte_get() function from `avr/boot.h`, I get a different sequence of signature bytes than I do if I try to retrieve the bytes using a secondary microcontroller that uses avrISP to retrieve the signature bytes from the ATmega328PB.

 

ATmega328PB code:
 

for(uint8_t sig_addr = UUID_SIGROW_OFFSET_START; sig_addr < (UUID_SIGROW_OFFSET_START + UUID_NUM_BYTES); sig_addr++){
   //Send out a byte on UART as binary data
   Serial.println(boot_signature_byte_get(sig_addr), HEX);
}

 

output: 

 

50
51
53
46
42
37
69
C
2D
1A

 

 

 

Secondary microcontroller code:

 

 

   uint8_t serial_number[10] = {0};
   uint8_t addr = 0;
   for(byte count = 0; count < 10; count++){
      addr = (0x0E) + count;
      serial_number[count] = spi_transaction(0x30, 0x00, addr, 0x00);
      Serial.println(serial_number[count], HEX);
   }

....where:

unsigned long spi_transaction (uint8_t a, uint8_t b, uint8_t c, uint8_t d)
{
   uint8_t n, m;
   spi_send(a);
   n = spi_send(b);
   //if (n != a) error = -1;
   m = spi_send(c);
   return 0xFFFFFF & ((((uint32_t)n) << 16) + (m << 8) + spi_send(d));
}

 

 

 

 

output:

 

13
FF
86
86
86
86
FF
FF
0
0

 

 

So, clearly there is something different happening between the boot.h implementation and my spi implementation via avrISP protocol.

 

 

avrISP protocol - serial number retrieval

 

According to the ATmega328PB datasheet:

 

 

 

 

and:

 

 

 

 

 

 

 

Playing around  (trying to make it work)

 

If I modify the code running on the secondary microcontroller to print out as many bytes from signature as possible, here is what I get:

 

 

code:

   Serial.println("All signature bytes are:");
   uint32_t transaction_result = 0;
   for(byte count = 0; count < 0XFF; count++){
      addr = count;
      Serial.print("addr ");
      Serial.print(count, HEX);
      Serial.print(" --> ");
      transaction_result = spi_transaction(0x30, 0x00, addr, 0x00);
      Serial.println(transaction_result, HEX);
   }

output:

All signature bytes are:
addr 0 --> 30001E
addr 1 --> 300095
addr 2 --> 300016
addr 3 --> 3000A5
addr 4 --> 3000FF
addr 5 --> 3000FF
addr 6 --> 3000FF
addr 7 --> 300050	*same as boot_signature_get_byte(0x0E)
addr 8 --> 300053	*same as boot_signature_get_byte(0x10)
addr 9 --> 300042	*same as boot_signature_get_byte(0x12)
addr A --> 300069	*same as boot_signature_get_byte(0x14)
addr B --> 30002D	*same as boot_signature_get_byte(0x16)
addr C --> 300017
addr D --> 300012
addr E --> 300013
addr F --> 3000FF
addr 10 --> 300086
addr 11 --> 300086
addr 12 --> 300086
addr 13 --> 300086
addr 14 --> 3000FF
addr 15 --> 3000FF
addr 16 --> 300000
addr 17 --> 300000
addr 18 --> 3000FF
addr 19 --> 3000FF
addr 1A --> 300000
addr 1B --> 300000
addr 1C --> 3000FF
addr 1D --> 3000FF
addr 1E --> 3000FF
addr 1F --> 3000FF

 

 

So, it looks like:

 

boot_signature_get_byte( X )  == spi_transaction(0x30, 0x00, X/2, 0X00)

 

If that is the case, how can I retrieve the serial number bytes stored at odd-numbered offsets (i.e. when X = 2 or 3, X/2 =1)?

 

 

I love the smell of burning silicon in the morning

Last Edited: Tue. May 21, 2019 - 06:29 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1


FIGURED IT OUT

 

It turns out there is secretly two commands for reading from signature address space, despite what the datasheet may lead you to believe.

 

The "aha!" moment came after staring at the serial programming instruction set for a while:

 

 

Just as there are two separate commands for reading program memory (high byte and low byte) that differ by an 0X08, there are two separate commands for reading from signature row address space that differ by 0x08.

 

I realized this after looking at the signature bytes table:

 

 

Notice that the oscillator calibration register (at an odd-numbered offset of 1) is read using the 0x38 command (which is 0x08 more than the 0x30 signature byte read command).  This must therefore mean that the serial programming instruction set table should read:

 

 

 

Here is a function that I wrote that correctly returns the expected signature byte given the offset as per the table provided in the datasheet:

 

uint8_t get_sig_byte(uint8_t offset){

   uint16_t word_address = offset / 2;

   if(offset % 2 == 0){
      return spi_transaction(0x30, 0x00, word_address, 0x00);
   }
   else{
      return spi_transaction(0x38, 0x00, word_address, 0x00);
   }
}

 

 

 

I love the smell of burning silicon in the morning

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Nice find!