CMSIS 5.1 defines macros/functions for LDREX/STREX functionality. The macros/functions have variants for 'B'yte, 'H'alfword and 'W'ord. Ie, LDREXH, STREXB. It does not use the functionality to implement atomic/lock-free primitives, but you can use them to implement your own.
| Instruction | CMSIS function |
| ------------ | ----------------------------------- |
| LDREX | uint32_t __LDREXW (uint32_t \*addr) |
| LDREXH | uint16_t __LDREXH (uint16_t \*addr) |
| LDREXB | uint8_t __LDREXB (uint8_t \*addr) |
| STREX | uint32_t __STREXW (uint32_t value, uint32_t \*addr) |
| STREXH | uint32_t __STREXH (uint16_t value, uint16_t \*addr) |
| STREXB | uint32_t __STREXB (uint8_t value, uint8_t \*addr) |
| CLREX | void __CLREX (void) |
For single core CPUs and a bare metal single thread, there is no reason for an atomic increment (most drivers won't want an atomic increment). For bit fields shared with interrupts, it can be important to atomically RMW (read-modify-write) atomically. If you have an RTOS with scheduling, the scheduler MUST perform a CRLEX() on a context switch. You can also use 'single reader/single writer' structures such as a ring buffer/fifo without resorting to atomics. However, I assume you have the knowledge and need to have these primitives.
I would use either C++ or the generated code to confirm a 'C' equivalent.
See: godbolt to process this SO example for some assembler,
create_id():
ldr r3, =ID
dmb ish
.L2:
ldrex r0, [r3]
adds r2, r0, #1
strex r1, r2, [r3]
cmp r1, #0
bne .L2
dmb ish
bx lr
This gives,
void atomic_inc(uint32_t *val)
{
DMB();
do {
uint32_t tmp = LDREX(val);
tmp++;
} while(STREX(tmp,val));
DMB();
}
For a CMSIS 'C' implementation. I would just use the C++ atomics and expose them as extern "C". There would be no overhead for object files that are just using the atomic C++ primitive and I would trust (and verify) the compiler. Lots of smart people have worked on making it correct.
You probably don't need the DMB() for non-SMP systems, but it is not that harmful unless performance is a must. As you can see, the loop could lock for eternity. You may wish to insert a retry counter depending on your application space and design criteria.