Generating load time serial number for PCB application - c

I am trying to generate an incrementing value at load time to be used to "serialize" a PCB with a unique code value. Not an expert in ld or preprocessor commands, so looking for some help.
The value will be used in a unique ID for each board that the code is loaded on and will also be used as a counter for boards in the field.
I have no preconceived idea of how I might accomplish this, so any workable answer to get me started, including a pre-preprocessor macro is fine. In my olden days, I recollect adding a couple lines to the linker file that would accomplish this, but I have been unable to resurrect that information anywhere (including my brain's memory cells).
The simpler the answer, the better.

My solution to the problem was remarkably simple.
The binary contained
const char *serial = "XY-00000";
I then wrote a short program that boiled down to:
char uniqueserial [8];
/* Generate serial - this was an SQL call to the manufacturing DB */
char *array;
/* Read binary into array */
memcpy(memmem(array, "XY-00000",8), uniqueserial,8);
/* Write array to temp bin file for flashing */
Depends on the serial template string being unique in the binary. Use strings command to check. I disable crc protected object files due to taste. I like my embedded binaries being exact memory dumps.

The linker is not the right place for two reasons:
the executable can be loaded with the same id in several devices, making your approach void.
You should have to link the executable for each device you are programming, which poses an spent of cpu resources.
The best place is to patch the executable at loading time with the serial number.
Select a data patern as token to initialize your variable with the device id (a pattern difficult to happen elsewhere in your program binary) and initialize your serial number variable to that data pattern (better if you do it statically initializing an array variable or something similar)
Make a program to be executed on each download to device that search for the pattern in the executable file, before loading the binary program into the device and writes the correct value to be programmed into the device (beware that you are patching a binary, so you cannot think on variable lenght strings or the like, that can trash all the work made by the linker)
Once patched the binary executable, you can download it to the device.
Another solution is to reserve a fixed area in your linker script for all this kind of information. Then, put all your device information variables there. Then get the exact positions in rom for the individual variables and include the proper data in the loaded image. In this case, the linker is your friend, reserving some fixed segment in your device's rom allocated for storing the device's individual data (you can put there mac addresses, serial numbers, default configuration, etc.)

Related

Creating different versions of .bin file in stm32cubeide

Context
I'm currently working on a firmware for a STM32F411CEU6, using STM32CubeIDE, I'm going to be programming several UC's, everyone of them is going to have an ID (a 32 bit unsigned number), this number is static and it will never be change in his lifespan, we are a small team but maybe we will have to program a few hundred of these devices, so changing the value associated whit that ID in the code manually will be kinda exhausting, and time consuming, so, my question is:
¿Is there a way to compile different versions of firmware so it generate several .bin files, each one whit the only difference that this single constant change?
¿Is there a way to automate this process?
What have I thought
I have thought on defining this constant (and other constants if I have to) on a header file, then use something like Python to make different versions of the code, but then I would have to open every project or workspace and still have to compile and produce every .binfile manually, ¿Is there a way to produce the .bin file from python (using the STM32CubeIDE), or something like that?
Additional information
Working on a STM32F411CEU6
Using STM32CubeIDE
I have basic knowledge in python C++
Medium-advance knowledge in C
Thanks in advance!
Any help would be very much appreciated
Here are a few ideas.
The STM32F411 chip is pre-programmed (by STMicro at the factory) with a 96-bit unique device ID. Perhaps you can use the device's unique ID for your purposes rather than creating and assigning your own ID value. See Section 24.1 of the reference manual. This seems much safer than trying to create and manage a different bin file for each ID value.
If you really want your own custom ID value, then program the ID value separately from the firmware bin file so that you don't need to create/manage different bin files for each unit. Write the program so that the ID value is at a known fixed address in ROM. Use the linker scatter file to reserve that address for the ID value. Program the ROM of each unit in two steps, the bin file and the ID value.
If you really want to incorporate the ID value into the bin file then you can use a tool such as srec_cat.exe to concatenate bin (also hex or srec) files. It's very versatile and you should study the man page. One example of how you could use this tool is this: In the source code for your program, declare your unique ID value a constant pointer to a constant value located at a fixed address in ROM beyond the end of the ROM consumed by the bin file. Build the bin file like normal. Then run srec_cat.exe to concatenate the unique ID value to the bin file with the appropriate offset. You could write a script to do this repeatedly for each unique ID value. Perhaps this script runs as a post-build action from the IDE. This solution could work but it seems like a maintenance nightmare to ensure the right bin file gets programmed onto the right device.
If using a hex file is an option, you could avoiding the need for re-compilation like so:
Reserve some flash space outside of your program (optionally configure the linker script to make sure no data is placed in that section).
Use a python script to generate intel hex data with the required ID placed in the reserved location.
Simply concatenate the two hex files and program as usual. I tested this with STM32 ST-LINK Utility / STM32CubeProgrammer.
To generate the hex data, you can use the intelhex package. For example:
import struct
from intelhex import IntelHex
from io import StringIO
ID_FLASH_ADDRESS = 0x8020000
hex_data = StringIO()
ih = IntelHex()
ih.puts(ID_FLASH_ADDRESS, struct.pack('<I', chip_id))
# Output data to variable
ih.write_hex_file(hex_data)
# Get the data
hex_data.getvalue().encode('utf-8')
Notes:
See the struct documentation for the meaning of '<I'.
I output the data to a variable, but you could also write directly to a file. See intelhex documentation.

Create a fixed size section with gcc and place values in it

I need to embed a binary file within an executable generated with gcc on Linux, to be executed in the host (not in a separated device).
In addition, I want to be able to change that binary content externally by using obcjcopy --update-section.
I could do that with __attribute__(("section")), but the problem is that the mentioned binary file might have different sizes at different moments, so I want to allocate a section of a fixed maximum size. Thus, I can update slightly bigger/smaller binaries in the future.
Apart from the above, I would like to give a default value to that particular section at build time (a predefined binary file that is available at build time).
This can be done with a linker script. However, as far as I understand, I would need to modify the OS default linker script, what I want to avoid.
The only thing that comes to my mind is to create an array on that section with a fixed size, using the first bytes for allocating the default binary file and padding the rest with 0xFF's for instance.
Is there a better way to do this?
As ikegami has mentioned, it's enough to specify the maximum size of the array and then initialise the values you need.

Read STM32L4 flash memory through JTAG in C

I am trying to read the MCU_ID (device electronic signature) from STM32L476 chip using a JTAG ST-Link/V2 on Windows 7. No code has to be uploaded inside the chip, the program shall just be launched on my cumputer and read this information from the flash memory.
I have managed to find and extract the following screenshot from the Reference Manuel given on ST website :
So I have to read the value stored in the flash memory at the adess 0x1FFF7590 by using a C program. I am using the Atollic TrueStudio IDE which is recommended by ST itself, but it seems to me that it includes the "stm32l476xx.h"library which does not even contain any function which could help me.
What I have done so far
After spending days and days looking for some functions or examples to do something as simple as read flash memory, I have asked on this very site How to interact with a STM32 chip memory, which helped me understand a couple of things about what I had to do; nevertheless, I haven't been able to find what I was looking for even after days reading all the links and docs advised in the comments.
I have asked a couple of professionals who told me that I should search for a JTAG driver to interact with the flash memory, but it seems a bit complicated and I haven't been able to found any.
Someone on this site told me that simply using pointer should be enough; the lack of C example and internet tutorials couldn't help me figure out how to do so.
Finally, I started recently digging around STM32Cube and HAL, even since I wanted to avoid using those because I thought that a simple read could be done without having to include those layers. Asking this question is my final hope before trying to use them.
In Conclusion :
I can't show any code since the only thing I have so far is a #include "stm32l476xx.h"and an empty main.
A hint or solution on How to read a STM32L476's flash memory in C would be just perfect. Every example of C (or any programming language which would be as low or higher level) program or instructions interacting with a STM32 chip's memory could help me a lot since it is very hard to find on internet.
Reading MCU ID using ST-Link (graphical interface)
You can use ST-Link Utility (can be downloaded from ST.com here: http://www.st.com/en/embedded-software/stsw-link004.html). After you do Target->Connect you can specify the address and number of bytes you want to read on top of the Window. This also works for the memory area where MCU ID is defined.
For STM32L476 MCU that you use it's going to be memory address 0x1FFF7590, size 0xC (96 bits). Pressing enter should allow you to see the unique ID read from the MCU you're connected to, in form of 3x32 bit values.
Reading MCU ID using ST-Link (command line interface)
ST-Link Utility provides CLI (command line interface) to do the most common operations. This is done using ST-LINK_CLI.exe located in your ST-Link Utility installation directory.
Reading Unique ID as 32-bit values (STM32L476 MCU from the example):
ST-LINK_CLI.exe -r32 0x1FFF7590 0xC
Reading as 8-bit values:
ST-LINK_CLI.exe -r8 0x1FFF7590 0xC
You can also read it to file using -Dump parameter:
ST-LINK_CLI.exe -Dump 0x1FFF7590 0xC D:\temp\out.bin
Keep in mind that you must have the priviledges to write to the destination directory. If you don't run the command prompt with administrative priviledges, in most common cases this means that you won't be able to create the file in locations such as root drive directory (C:\out.bin) or inside "Program Files", where most likely your program is installed (for example by specifying a relative path, such as giving an output file name only out.bin). The program sadly doesn't inform about failed attempts to write the file, however it does say when it succeeds to create the file. The program execution should end with a green line saying Dumping memory to D:\temp\out.bin succeded. In addition, keep in mind that only the following file extensions are supported: *.bin *.hex *.srec *.s19. It cannot be anything because the extension determines the format in which the data will be written to the file.
You can find more information about CLI parameters in User Manual UM0892.
Reading MCU ID using C code
The same can be done using a program loaded into the MCU. You read it by simply accessing the memory directly. Sample code:
#define STM32_UNIQUEID_ADDR 0x1FFF7590
uint32_t id[3];
id[0] = *(STM32_UNIQUEID_ADDR + 0);
id[1] = *(STM32_UNIQUEID_ADDR + 1);
id[2] = *(STM32_UNIQUEID_ADDR + 2);
After this operation id array should contain the same 3x32bit values you've previously read using ST-Link Utility. You may of course choose to read it as uint8_t byte array of size 12, you may even choose to read it into a struct, in case you're interested in the details (lot number, wafer number etc.). This example should however give you a general idea of how to access this value.
There is Texane stlink, that does what you want. It's written in C, interacts with STM32 chips through an ST-Link adapter, and it can read from chip memory.
What you are looking for is not a feature of ST but a feature of ARM.
Remember, ST simply uses an ARM core. I know most programmers load some code in RAM and use that to access flash. You can find these simple programs in the install directory or Keil for example.
I think this is the manual you will need. But I don't know if there is more information behind the login-wall.

Intel hex format and position independent code using gcc

I'm not sure if this is specific to the processor I'm using, so for what it's worth I'm using a Cortex M0+. I was wondering: if I generate a hex file through gcc using -fPIC, I produce...Position Independent Code. However, the intel hex file format that I get out of objcopy always has address information on each line's header. If I'm trying to write a bootloader, do I just ignore that information, skip the bytes relating to it, and load the actual code into memory wherever I want, or do I have to keep track of it somehow?
The intel-HEX format was specially designed to programm PROMs, EPROMS or processors with an internal EPROM and is normally used with programmers for theses devices. The addresses at the beginning of the records have not much to do with the program code directly. They indicate at which address of the PROM the data will be written. Remember also that the PROM can be mapped anywhere into the address space of the processor, thus the final address can change anyway.
As long as you don't want to program a PROM you must remove anything except the data from the records. (Don't forget the checksum at the end ;-)
As I understand the intel-HEX format the records must not be contiguous, there may be holes in between.
Some remarks:
The -f PIC parameter is not responsible for the intel-HEX format. I think that somewhere in your command lines you'll find -O ihex. If you want to have a file that could be executed, objcopy provides better suited output formats.
As long as you don't write earlier stages of the boot process by yourself, you don't load your bootloader - it will be loaded for you. The address at which this will happen is normally fixed and not changeable. So there is no need for position independent code, but it doesn't hurt either.

Why does inserting characters into an executable binary file cause it to "break"?

Why does inserting characters into an executable binary file cause it to "break" ?
And, is there any way to add characters without breaking the compiled program?
Background
I've known for a long time that it is possible to use a hex editor to change code in a compiled executable file and still have it run as normal...
Example
As an example in the application below, Facebook could be changed to Lacebook, and the program will still execute just fine:
But it Breaks with new Characters
I'm also aware that if new characters are added, it will break the program and it won't run, or it will crash immediately. For example, adding My in front of Facebook would achieve this:
What I know
I've done some work with C and understand that code is written in human readable, compiled, and linked into an executable file.
I've done introductory studies of assembly language and understand the concepts about data, commands, and pointers being moved around
I've written small programs for Windows, Mac and Linux
What I don't know
I don't quite understand the relationship between the operating system and the executable file. I'd guess that when you type in the name of the program and press return you are basically instructing the operating system to "execute" that file, which basically means loading the file into memory, setting the processor's pointer to it, and telling it 'Go!'
I understand why having extra characters in a text string of the binary file would cause problems
What I'd like to know
Why do the extra characters cause the program to break?
What thing determines that the program is broken? The OS? Does the OS also keep this program sandboxed so that it doesn't crash the whole system nowadays?
Is there any way to add in extra characters to a text string of a compiled program via a hex editor and not have the application break?
I don't quite understand the relationship between the operating system and the executable file. I'd guess that when you type in the name of the program and press return you are basically instructing the operating system to "execute" that file, which basically means loading the file into memory, setting the processor's pointer to it, and telling it 'Go!'
Modern operating systems just map the file into memory. They don't bother loading pages of it until it's needed.
Why do the extra characters cause the program to break?
Because they put all the other information in the file in the wrong place, so the loader winds up loading the wrong things. Also, jumps in the code wind up being to the wrong place, perhaps in the middle of an instruction.
What thing determines that the program is broken? The OS? Does the OS also keep this program sandboxed so that it doesn't crash the whole system nowadays?
It depends on exactly what gets screwed up. It may be that you move a header and the loader notices that some parameters in the header have invalid data.
Is there any way to add in extra characters to a text string of a compiled program via a hex editor and not have the application break?
Probably not reliably. At a minimum, you'd need to reliably identify sections of code that need to be adjusted. That can be surprisingly difficult, particularly if someone has attempted to make it so deliberately.
When a program is compiled into machine code, it includes many references to the addresses of instructions and data in the program memory. The compiler determines the layout of all the memory of the program, and puts these addresses into the program. The executable file is also organized into sections, and there's a table of contents at the beginning that contains the number of bytes in each section.
If you insert something into the program, the address of everything after that is shifted up. But the parts of the program that contain references to the program and data locations are not updated, they continue to point to the original addresses. Also, the table that contains the sizes of all the sections is no longer correct, because you increased the size of whatever section you modified.
The format of a machine-language executable file is based on hard offsets, rather than on parsing a byte stream (like textual program source code). When you insert a byte somewhere, the file format continues to reference information which follows the insertion point at the original offsets.
Offsets may occur in the file format itself, such as the header which tells the loader where things are located in the file and how big they are.
Hard offsets also occur in machine language itself, such in instructions which refer to the program's data or in branch instructions.
Suppose an instruction says "branch 200 bytes down from where we are now", and you insert a byte into those 200 bytes (because a character string happens to be there that you want to alter). Oops; the branch still covers 200 bytes.
On some machines, the branch couldn't even be 201 bytes even if you fixed it up because it would be misaligned and cause a CPU exception; you would have to add, say, four bytes to patch it to 204 (along with a myriad other things needed to make the file sane).

Resources