Distinguishing one Arduboy from another in software?

I was noting that there are a number of points where it is useful to distinguish multiple Arduboys, one from another, in software.

The whole concept of multi-device options, no matter how the communication happens, can be enhanced if devices can consistently and repeatedly be identified as “yes, that one”. In other places, a unique value can be a key inclusion in generating pseudo-random numbers with a guarantee of device-by-device uniqueness.

This concept is not unheard of - every device with an Ethernet port has a unique MAC address. Sure, it can be overridden, but down at the hardware level, it is always there.

Is there anything in the Arduboy - any component, not just the ATmega32u4 - that can provide a unique value to on-board software?

Now that I think about, this could also be a benefit in production and fulfillment tracking, essentially serving as an Arduboy serial number so that you have some way of saying “we sent you devices x, y, z; did you get devices x, y, z?”

1 Like

If you are talking about a PC communicating with multiple Arduboys, Serial provides the ability to give a variable name to each serial connection.

So if serial 1 sends some data. It will be received as data from serial 1 and stored that way. and you can send data to specific serial ports.

Sorry if I’ve got the wrong end of the stick here, but I think that is what you meant.

Not quite. (Or, I don’t think so.)

If you had four Arduboys connected over USB/serial with one PC, and one Arduboy goes away, you lose one connection. Then, a connection with some Arduboy comes back up. Is there anything that Arduboy can send - based on it’s own intrinsic capabilities - to indicate to the host that it is the same Arduboy that was there before? And - that value would be the same if the Arduboy communicated with a different host?

Communication is only one scenario. If you are generating pseudo-random values (perhaps with a hash function) having a locally unique value that no other Arduboy should have that you can include in the inputs will avoid problems like two Arduboys generating the same values (which sometimes happens if you load the same software and run at exactly the same time).

The hardware-based MAC address really is the closest to what I am thinking of, although a processor based serial number would be similarly useful.

Hmmm. I see what you mean now. As far as I know there is no unique value to every Atmega processor. However, apparently all USB chips have a unique ID. I’m not sure how you can retrieve this value though.

So was just having a look into some values given to Windows for each device through the device manager GUI. I was using the same USB port and cable and switching after looking at each value, but all the values were the same for both of my Arduboy’s. I only had a couple minutes so weren’t able to try anything in code :frowning:

There is a vendor ID and device ID for USB. I’m not aware of any unique ID (related to USB) that changes per device. For “networking” purposes I think you’d want each player to set their name, save it in EEPROM, then use that name to distinguish devices when playing a group game, etc. I’ve always felt core lib should reserve 16 bytes for itself in EEPROM. I’ve only found uses for a few bytes so far. There’s definitely room for a 8 character name or so to identify a device (or even store a default name for games that ask). Gamebuino does this I think.

This isn’t strictly necessary though just to network - it’s more for identification. To network each device could send out a random # in an init packet and then the host program could send back a temporary unique ID for that host to be used for the duration of the networking session. That works as long as you have some type of master device setup. If you were hacking Arduboys to have like a serial bus cable network that chained a bunch of Arduboys together then something else would need to be invented for that use case.

I think the right way to do a “serial number” if @bateske was interested is work with a company that can alter the bootloader as it flashes it to each chip. Then they would encode an incrementing serial # into the bootloader HEX, burn it, and we’d provide a userland function to access the serial #. The few people who plan to flash their own bootloader would have to understand they are potentially erasing their serial #.

Of course it’s also possible to fuse the hardware to prevent the bootloader from EVER being modified (preserving the serial # in posterity) but I’m not sure that we’d want to do this for this type of project.

There are other ways around this problem. No locking the bootloader!!!

A serial number in the bootloader would mean some rather special customization in the bootloader, which I’m thinking is a no-no. Not because it wouldn’t work, but because it strikes me as stretching the job of the bootloader into a different realm. Possible - yes. Wise - maybe not so much.

The other alternative is that any software that needs this can call a library function to build a “pseudo unique id” (PUI). Give the library call a space in EEPROM, and it will check if it meets specific criteria, such as a CRC check. If it does, then the PUI has been built. If not, it builds it, with a valiant attempt at a psuedo randomness – and the software can use it as a big clue that the EEPROM has not been initialised for this piece of software. This is potentially then a building block for another item that I think @bateske mentioned - freshly loaded software having to watch out for the previous software’s EEPROM storage.

I’m guessing that something in the standard launch code starts at least one of the on-chip timers. That timer’s current value, along with a checksum or CRC over that and the loaded software, perhaps preceded by an “enter your name” option (which adds both random data and random passage of time) should be enough to build a PUI.

The professional solution (sorry - the profe$$ional solution!) is something like the DS2401, a 64 bit silicon serial number SPI device, expressly designed to put unique serial numbers on devices. I don’t think we need this that much!

I wasn’t suggesting locking it, just mentioning it was possible. We already have to compile our own bootloader (just to change the USB IDs), adding a unique production count to isn’t really any type of sophisticated customization - IF it’s something the builder readily supports. They could already have one of these DS2401 machines. And most users likely aren’t going to reflash their boot loaders, making this a pretty secure location for such an ID to hide.

freshly loaded software having to watch out for the previous software’s EEPROM storage.

I of course think all apps should share the space nicely… but if some aren’t going to do that it would be nice to have an agreed upon system so an app could check if it needed to “format” the space prior to use or if it had been run before. Could be as simple as throwing a string label somewhere in high EEPROM.

Mixing your name into it is an interesting idea. There is already a random seed function in the core library that uses timer, temperature, and voltage level to seed the random # generator. Actually your own name plus a PUI is a pretty solid bet. You have to realize that the random number generator is seeded with only 16 bits though. So unless you add further entropy with some type of loop to jump random values that any routine that just seeds the generator then asks for say a random string is only going to ever generate 65,536 unique strings.

Hmmm.

Is there a standard way to share EEPROM? At only 1K, you need to be super efficient. But - there is complex efficient and then there is simple efficient…

Ok, this is still on topic, so…

I could see that there might be value in some items, like a Pseudo Unique Identifier, or your name. But I can also see that you could divide up EEPROM so that value like these are preserved in an available space, but can be set by an Arduboy Utility. You load the Arduboy Utility, and it can set some of these special values, and then gets out of the way when the next app overwrites it.

The simplest model I could imagine for EEPROM management is a Len-Tag model.

  • LEN - byte - number of 4 byte blocks in this block (including this label)
  • TAG - byte*3 - alphanumeric tag identifying block purpose/owner
  • blk*LEN - 4 byte blocks repeated LEN times

Sample Contents of EEPROM

\x05ABY" - 4 blocks (16 bytes) Arduboy data
"Chris…" - 8 bytes of user identifier
"\x11\x22\x33\x44\x55\x66\x77\x88" - 8 bytes of random unique ID
\x02"ALA" - 1 block (4 bytes) Alien Attack highscore
\x00\x00\x03\xE8 - score of 1000
\x02"TKB" - 1 block (4 bytes) Tank Battle highscore
\x00\x00\x00\x23 - score of 35
\xF7"—" - reserved tag, empty space of 246 blocks after this

A three character (Upper/Lower/Numeric) tag gives you nearly a quarter million possible tags. Simple API functions that walk the blocks allow for the reading and filling of blocks. If this is standardized, then that external program associated with loading and overwriting apps can manage the EEPROM space as well. In fact, the external EEPROM manager could easily fill in Name and PUI and you would never have to load a special app for that.

This gets you the special Arduboy features (like a name or unique id) with only a minimal cost to all the other apps. Along the way, it provides a way to hand each app it’s preferred size of EEPROM space, allowing - with some management, granted - persistent storage of things like high scores.

It hints at a couple of other things. A loadable Arduboy app would need the program image, a memory ownership tag value (3 characters), and the size of EEPROM blocks needed, and perhaps default EEPROM contents. This is also a good place to add an official name and an icon, so that that specialized loader app can show a screen full of nice game options for loading.

I’ll stop rambling now, but I close by noting that this memory management seems to fit with the overall Arduboy philosophy – simple, compact solutions, not wide ranging complexity.

1 Like

Please add this over in the EEPROM management thread.

1 Like

The core library already assumes that the first 16 bytes are reserved for system use. We could decide to store name there (if it was deemed THAT important). I think if an app is going to use the core lib they need to accept that those 16 bytes are off limits (unless they want to really start hacking)… so any type of EEPROM management that sets on top of that would be managing the rest of the space. If these management functions end up being built into the core library itself I think the full 16 bytes (or so) of “reserved” space could be used however necessary - it wouldn’t need to have the same tags or storage overhead as the rest of “shared” EEPROM.

Perhaps this is of some interest:
AVR922: Add a Serial Number to your USB Device

Ah.

Yes. (!!!)

The oddest part is that unless you actually know what you have found (as opposed to what you were looking for), you would not know that this solves the problem.

Even distinct searches like “ATmega32u4 serial number” give you the implication that this is for USB. It’s not. It’s a generic serial number for just about any use - including, but not limited to, USB.

As far as I can tell, even the data sheet does not mention this.

Eighty bits of added entropy, guaranteed device-by-device unique, is huge.

I did note that the ATmega32u4 also has a “DES primitive” instruction (!!!). Since we’re more interested in “pseudo random” and not so much “FIPS compliance”, that may be an incredibly useful shortcut to making a compact and fast pseudo random generator.

I actually came across it as a fluke, when trying to find out if Atmel made USB Product IDs available to customers while allowing the use of their Vendor ID (if they have one). (I think the answer I was searching for is: no.)

Darn. Have to read the fine print. Only XMEGA cores get the DES instruction.

From the linked PDF:

This request is managed by the usb_standard_request.c file. Please note that the serial number generation can be enabled or disabled in your firmware.
To enable or disable the serial number generation, you have to set the correct configuration in the conf_usb.h header file, see below:

I’m not sure this is the magic unicorn you are looking for. This is all done in software. They are talking about a unique serial # that you add to your firmware (the software compiled onto the chip) that then the USB host can request. This is exactly what I was suggesting with modifying the bootloader for every chip to place a unique identifier there then exposing it to user land. Evidently some small # of chips have an “internal serial number”, which might be different, but I don’t see anything yet to think the AtMega32U4 is such a chip. Furthermore, this PDF is talking about the host computer retrieving the serial # over the USB channel… all USB communication on the AtMega32U4 is managed vs software. If there is a 5 bytes serial # hiding somewhere it would have to be one of the places that normal software has access to (even if read only)… that would leave RAM, IO ports, EEPROM, Flash, fuses, boot fuses, etc.

I’m not aware of a hidden 5 bytes somewhere. If so I assume they would be mapped into the memory addressing scheme, and I just don’t see any mention of that in the AtMega32U4 docs… The only two pieces that might be promising were “External memory (not present)” and “Ext I/O Registers”. Again, 98% sure here they are talking about simply flashing your own serial #s… no magic voodoo here.

Re: Entropy. You could use entropy from multiple points in time to build the serial #… at first boot it could tell someone to hit the button slowly 10 times and then the timing of those presses plus micro variants in voltage, temp, etc. could be used to build a unique serial. Though again you have to remember the final # you feed to randomSeed is still only 16 bits… so having a 40 bit serial # doesn’t really necessarily translate into a bunch of additional entropy for random number generation.

To be clear if we’re building the serial # in user space then it’s going to have to be store in EEPROM. Believe it or not user space DOES have the ability to overwrite the bootloader, but I’m not sure we’d want to risk doing that just to store the serial # in flash.

Well, it’s definitely not voodoo. But after chasing through documentation, header files, and the sources for the bootloader, it appears to come down to this. Cutting to the chase…

    b0 <- LPM(14)
    b1 <- LPM(15)
    b2 <- LPM(16)
    b3 <- LPM(17)
    b4 <- LPM(18)
    b5 <- LPM(19)
    b6 <- LPM(20)
    b7 <- LPM(21)
    b8 <- LPM(22)
    b9 <- LPM(23)

Now, that is in no way legitimate code, either asm or C, but I think you get the point. (Load Program Memory is the flash read instruction. It normally has to be supported by scaffolding code to get the right results.)

Buried as a function in the bootloader is the ability to “read hardware signature bytes”. All it appears to do is read from the lowest values in the flash memory. Best clue is to look for entry point flash_read_sig in flash_drv.s to see what is going on. For the “serial number”, this is called via this define:

   Flash_read_sn(pos)  ( flash_read_sig((0x07*2)+pos))

which is what gives me the 14 through 23 location values for the “number”.

The implication strikes me as quite clear - if you have the factory bootloader, then this “hardware id” is likely unique and there. Now it might be “an id for the hardware”, but it certainly is not “an id in the hardware”. It really is just a value in flash. If the ATmega32u4 in the Arduboy came from the factory with a bootloader (and why wouldn’t it) then I get the strong impression - which I annoyingly cannot back up with data - that this unique value will be there.

You noted that there is reserved space at the start of flash memory. I tried getting that documented, but could not find anything definitive. Upon reflection, though, it doesn’t need to be definitive - if you use the bootloader, it can ensure that whatever code is loaded does not stomp on the reserve area. If you change the bootloader, all bets are off. I would also note that with a flash page size of 128 bytes, it makes sense to reserve that area in its entirety. If you only reserve part of it, the bootloader gets the fancy job of reading and merging a partial page before writing the whole thing back. Not too complex, but holding 128 leaves space for options. And - it’s only 0.4% of the flash memory.

I think this boils down to the bootloader; if it is strongly compatible or original, then those reserved values would be preserved, and should be present up and down the line. For most id purposes, that’s more than enough.

((EDITTED much later to add: read the whole thread; this LPM address space is not quite the same as the normal EEPROM))

I have no idea about these offsets in low flash memory. That makes no sense to me - since we’d be refreshing them all the time. For a product like Arduboy where the bootloader is going to be 99% static for most users you’d want to put a unique serial of any sort in the bootloader area - so only 1% of users would ever overwrite it. I’m not aware of an easy way with the default Arduino software to rope off another “reserved” portion of flash.

Obviously if we were building a firmware to be written once we could stick a S/N anywhere in flash we wanted.

You noted that there is reserved space at the start of flash memory.

Not sure what you’re referring to here.

if you use the bootloader, it can ensure that whatever code is loaded does not stomp on the reserve area.

True… if you’re ONLY reflashing with the boot-loader we could make a funky decision like to allow MAX_SIZE-128 and then you could “remap” the Arduino IDE rewrites to RAM + 128… of course that is a problem for the vector table - I’m not sure it can be at any random address. But one could imagine the boot-loader lying about things and reserving memory… but I can’t see the advantage of doing that vs just reserving x bytes at a fixed location inside the bootloader and storing the serial # there. And let the lower flash just be read and written normally without any magic.

I don’t know what source you’re looking at. I couldn’t find any of that in the Catarina or LUFA source.