Looking through the psoc4 implementation in openocd I noticed a function called psoc4_get_family(). In this function, reads some data from the ROMTABLE, deriving a family and designer from the data available there. Now, this ROMTABLE is documented in the various register TRMs, and it is a part of the CoreSight specifications. This is the information the debugger, connected over the JTAG or SWD interface, uses to identify the part.
Now, can I access this information from my code, rather then over the debugger? I’ve been looking at this in the past, and back then, I assumed I could not. But it turned out to be possible. At least, when the debugger is attached. I still have to verify it works when not debugging.
Information in this ROM table is stored in a kinda odd way. Data is stored at 32-bit offsets, but at each offset there is only 8 bits of data. Let’s have a look. Running the following code gives the expected values in family and designer.
uint32_t * pid = (int*)(0xF0000FE0); uint32_t family = pid[0] | ((pid[1] & 0xf) << 8); uint32_t designer = ((pid[1] & 0xf0) >> 4) | ((pid[2] & 0xf) << 4);
Now, I am curious, as the ROMTABLE is part of the CoreSight specifications, will this run on other Cortex-M microcontrollers as well? So, I ran the code on an nRF52832, and surely, the designer variable gives 0xc4. When we look at the JEP106 specifications, we see Nordic listed on page 3 entry 68. This is a match, but, we haven't looked at the page yet. Some changes to the code, to, first, identify if it even uses JEP106 identification, and if to, retrieve the identify code (without the used bit) and the continuation_code (This is bank-1, as the banks start at 1 in the specs)
uint32_t * pid = (int*)(0xF0000FE0); bool used = pid[2] & 8; uint8_t identity_code = ((pid[1] & 0xf0) >> 4) | ((pid[2] & 0x7) << 4); uint8_t continuation_code = (*(int*)(0xF0000FD0));
And we get an identity_code of 68 (10) and a continuation_code of 2. This matches the expected values! Nice! Now, let's try another. Running the code on an STM32F103, and guess what? HARDFAULT!!!! Bummer! But heading over to the reference manual, paragraph 31.6.4 "Cortex®-M3 JEDEC-106 ID code", we see we're looking at the wrong address. Adjusting the code accordingly gives
int * pid = (int*)(0xE00FFFE0); bool used = pid[2] & 8; uint8_t identity_code = ((pid[1] & 0xf0) >> 4) | ((pid[2] & 0x7) << 4); uint8_t continuation_code = (*(int*)(0xE00FFFD0));
Running this code on an STM32F103 gives an identity code of 32 and a continuation code of 0. This is the identification code for "STMicroelectronics", this looks correct. Now, let's run the same code on a GD32F103 part. Identity code 81, continuation code 7, so looking at the spect, bank 8, entry 81, it says "GigaDevice Semiconductor (Beijing) Inc.". Perfect!
One thing to do, as mentioned before, can I also read this when the debugger is not attached? The reason for this, is related to this STM32F103 and the almost-drop-in-replacement GD32F103. In many cases, code designed for one will run on the other, unmodified, but there are some corner cases. Basically, if there is way to identify the part I'm running on, I can take these differences into account.
In the past, I've looked at the DBGMCU_IDCODE register. Basically, by looking at the revision (REV_ID). The value used by GigaDevice does not overlap the values used by ST, so we know what part we're running on.
There is an erreta on the STM32F1 which results that this register can only be read when the debugger is attached. STM32F1xxx errata (See paragraph 2.3) Other STM32 series don't suffer from this problem. Furthermore, this problem does not exist on the GD32F103 either. So, if the value is non-zero, either a debugger is attached or it's a GigaDevice part. However, this errata might get fixed in a future revision of the STM32F103. So, I'd still have to look at the value, and with a new revision comes a new value. But I know the expected value for a GigaDevice part. So, this wouldn't be a problem after all.
Some other thoughts regarding this. Recently I've been looking at lcsc, where I discovered they're selling some more STM32F103 clones or drop-in-replacements. The BLM32F103C8T6 by Shnzhen Betterlife Electronic Science and Technology and the MM32F103CBT6 by MindMotion Microelectronics. I haven't been able to find either of those companies in the JEP106 list. So, I'm curious, how do these microcontrollers identify themselves? One way to find out, order some! I'll do so soon, first I need to get some new PCBs to solder them on. But that is, yet another project.
EDIT 2020-02-09: Upon reading some ARM Technical Reference Manuals, for both ARMv6m and ARMv7m, the ROMTABLE should be located at 0xE00FF000-0xE00FFFFF ( ID051917 page 282 , ID120114 page 741 ) So I'm not sure what was happening with the 0xF in stead of 0xE addresses here. This will need some future investigation