How to find the device id of a STM32F103RET

bislinux picture bislinux · Mar 29, 2015 · Viewed 13.9k times · Source

I have been told that each STM32F103RET devices carry a unique device id.If so what is the procedure to retrieve the ID?I am running a system wherein I communicate with more than one STM borads. To differentiate each STM board I can use this unique Id. thanks

Answer

Sam Protsenko picture Sam Protsenko · Mar 29, 2015

You can find this information in STM32F103 Reference Manual. More specifically, you want to read chapter 30.2 Unique device ID register (96 bits).

So your device ID contained in read-only register, called U_ID. This register address is 0x1ffff7e8. It's 96 bits long, so it can be read (for example) using 3 read operations, each 32-bit long. Of course you can't hold it in one variable. So you should come up with some way of storing it in memory. It can be array, or structure, etc.

I would probably use structure for this purpose, using offsets described in Reference Manual:

#include <stdint.h>

struct u_id {
    uint16_t off0;
    uint16_t off2;
    uint32_t off4;
    uint32_t off8;
};

How to read it is up to you (depends on which framework you are using, e.g. in libopencm3 you have MMIO32 macro for this). In general case I would do something like that:

#define MMIO16(addr)  (*(volatile uint16_t *)(addr))
#define MMIO32(addr)  (*(volatile uint32_t *)(addr))
#define U_ID          0x1ffff7e8

/* Read U_ID register */
void uid_read(struct u_id *id)
{
    id->off0 = MMIO16(U_ID + 0x0);
    id->off2 = MMIO16(U_ID + 0x2);
    id->off4 = MMIO32(U_ID + 0x4);
    id->off8 = MMIO32(U_ID + 0x8);
}

You will also need a function to compare two IDs. You can either use memcmp() or some custom function for that matter. I'd prefer a custom one in this case:

#include <stdbool.h>

/* Returns true if IDs are the same */
bool uid_cmp(struct u_id *id1, struct u_id *id2)
{
    return id1->off0 == id2->off0 &&
           id1->off2 == id2->off2 &&
           id1->off4 == id2->off4 &&
           id1->off8 == id2->off8;
}

You can use it like that:

int main(void)
{
    struct u_id id1 = { 0x0, 0x1, 0x2, 0x3 };
    struct u_id id2;
    bool same_id;

    uid_read(&id2);
    same_id = uid_cmp(&id1, &id2);

    printf("%s\n", same_id ? "equal" : "not equal");
    return 0;
}

UPDATE

As I understand your situation:

  1. Each of your boards should send some interrupt to your master board (more specifically, to GPIO pin on master board).
  2. Once master board received interrupt, it initiates transfer (request) to board where interrupt came from (probably using I2C, SPI, UART or something like that to communicate between boards).
  3. Then client board responds with it's device ID.
  4. Interrupts are handled sequentially, so device IDs will be obtained one by one.

Picture below illustrates case with I2C bus used for ID transmission.

Fig. 1 - Boards connections

For board 1 you will have GPIO1 interrupt handler executed, for board 2 -- GPIO 2 interrupt handler. Hence you know which one to ask for device ID. So device ID will be obtained one at a time. From here you can figure out how to store those IDs. I propose to use regular array:

struct u_id device_ids[2];

Here is pseudo-code showing how to populate this array:

void gpio1_isr(void)
{
    uint8_t i2c_buf[12];

    i2c_get(i2c_buf);
    memcpy(&device_ids[0], i2c_buf, 12);
}

void gpio2_isr(void)
{
    uint8_t i2c_buf[12];

    i2c_get(i2c_buf);
    memcpy(&device_ids[1], i2c_buf, 12);
}

(isr stands for Interrupt Service Routine, which is the same as interrupt handler).

In case you are sure that your two client boards are ready for I2C transfer in a time when master board is gonna ask them for IDs, you can get rid of 2 GPIO lines and just use I2C transactions from master board to clients whenever you want.