2022-10-07 11:14 AM
Hi
I am working on a drivers for the various peripherals on the STM32. Let me take the GPIO as an example. GPIO BSRR is a write only register that I want to read and I need to read back always 0x00000000. Why?
I made a bit-field struct on the whole GPIO block. That struct is accessed based on Register name and specific bit field.
The processor can not operate on individual bits so the compiler translates the Bit field instruction in to a register read followed by mask and shift operations ending with a Register write. It's the compiler that manipulates individual bits in a register in this way.
So the value of the write only register like a BSRR when it is read is important and needs to be 0x00000000 for a bit set operation.
Here is my question, is the read back of a write only register like the BSRR well-defined in the design of the STM32 chip or is that value undefined.
Question:
Can someone tell me if the read back of Write only registers is well-defined as 0x0000000 for the STM32 family of processors.
typedef struct {
struct {
uint32_t ch00 :4;
uint32_t ch01 :4;
uint32_t ch02 :4;
uint32_t ch03 :4;
uint32_t ch04 :4;
uint32_t ch05 :4;
uint32_t ch06 :4;
uint32_t ch07 :4;
} CRL; // 0x44444444, RW
struct {
uint32_t ch08 :4;
uint32_t ch09 :4;
uint32_t ch10 :4;
uint32_t ch11 :4;
uint32_t ch12 :4;
uint32_t ch13 :4;
uint32_t ch14 :4;
uint32_t ch15 :4;
} CRH; // 0x44444444, RW
struct {
uint32_t idr00 :1;
uint32_t idr01 :1;
uint32_t idr02 :1;
uint32_t idr03 :1;
uint32_t idr04 :1;
uint32_t idr05 :1;
uint32_t idr06 :1;
uint32_t idr07 :1;
uint32_t idr08 :1;
uint32_t idr09 :1;
uint32_t idr10 :1;
uint32_t idr11 :1;
uint32_t idr12 :1;
uint32_t idr13 :1;
uint32_t idr14 :1;
uint32_t idr15 :1;
uint32_t res :16;
} IDR; // 0x00000000, R
struct {
uint32_t odr00 :1;
uint32_t odr01 :1;
uint32_t odr02 :1;
uint32_t odr03 :1;
uint32_t odr04 :1;
uint32_t odr05 :1;
uint32_t odr06 :1;
uint32_t odr07 :1;
uint32_t odr08 :1;
uint32_t odr09 :1;
uint32_t odr10 :1;
uint32_t odr11 :1;
uint32_t odr12 :1;
uint32_t odr13 :1;
uint32_t odr14 :1;
uint32_t odr15 :1;
uint32_t res :16;
} ODR; // 0x00000000, RW
struct {
uint32_t bs00 :1;
uint32_t bs01 :1;
uint32_t bs02 :1;
uint32_t bs03 :1;
uint32_t bs04 :1;
uint32_t bs05 :1;
uint32_t bs06 :1;
uint32_t bs07 :1;
uint32_t bs08 :1;
uint32_t bs09 :1;
uint32_t bs10 :1;
uint32_t bs11 :1;
uint32_t bs12 :1;
uint32_t bs13 :1;
uint32_t bs14 :1;
uint32_t bs15 :1;
uint32_t br00 :1;
uint32_t br01 :1;
uint32_t br02 :1;
uint32_t br03 :1;
uint32_t br04 :1;
uint32_t br05 :1;
uint32_t br06 :1;
uint32_t br07 :1;
uint32_t br08 :1;
uint32_t br09 :1;
uint32_t br10 :1;
uint32_t br11 :1;
uint32_t br12 :1;
uint32_t br13 :1;
uint32_t br14 :1;
uint32_t br15 :1;
} BSRR; // 0x00000000, W
struct {
uint32_t br00 :1;
uint32_t br01 :1;
uint32_t br02 :1;
uint32_t br03 :1;
uint32_t br04 :1;
uint32_t br05 :1;
uint32_t br06 :1;
uint32_t br07 :1;
uint32_t br08 :1;
uint32_t br09 :1;
uint32_t br10 :1;
uint32_t br11 :1;
uint32_t br12 :1;
uint32_t br13 :1;
uint32_t br14 :1;
uint32_t br15 :1;
uint32_t res :16;
} BRR; // 0x00000000, W
struct {
uint32_t lck00 :1;
uint32_t lck01 :1;
uint32_t lck02 :1;
uint32_t lck03 :1;
uint32_t lck04 :1;
uint32_t lck05 :1;
uint32_t lck06 :1;
uint32_t lck07 :1;
uint32_t lck08 :1;
uint32_t lck09 :1;
uint32_t lck10 :1;
uint32_t lck11 :1;
uint32_t lck12 :1;
uint32_t lck13 :1;
uint32_t lck14 :1;
uint32_t lck15 :1;
uint32_t lck16 :1;
uint32_t res :15;
} LCKR; // 0x00000000, RW
} GPIO_RBLK;
GPIO_RBLK RegisterBlock;
GPIO_RBLK *GPIO=&RegisterBlock;
#define Reg32(R) (*(uint32_t*)&R)
#define Reg16(R) (*(uint16_t*)&R)
int main() {
printf("size:%u\n",sizeof(GPIO_RBLK));
GPIO->CRL.ch00=0x0u;
GPIO->CRL.ch01=0x1u;
GPIO->CRL.ch02=0x2u;
GPIO->CRL.ch03=0x3u;
Reg32(GPIO->CRL)=0xAABBCCDD;
printf("CRL:%08X\n",Reg32(GPIO->CRL));
HEX_MEM((uint8_t*)GPIO);
}
2022-10-10 10:06 AM
> page 46 of Chapter2 of the RM0008 manual it states
> write-only (w) Software can only write to this bit. Reading the bit returns the reset value. That value is 0x00000000
I've missed that information, too. It then indicates, that all write-only registers should reliably read 0, if that's given as their reset value.
@PatrickF , can you please comment on this?
JW
2022-10-10 11:01 AM
For being this deep into the weeds knowing some machine code and assembler, and machine operation, would seem to be a prerequisite.
The bit-banding mode creates a faux bit level model, but at it's heart is a RMW action that the MCU, and surrounding logic, implement. There are *known* hazards with this, and it's use with the TIM->SR, among others.
2022-10-11 12:15 AM
Hi,
I guess what is written in RefMan introduction is true but slightly overoptimistic, but for most registers, it will be true. There is certainly very few exceptions.
Anyway, as process for writing low level drivers involve some validation checks, this will certainly catch any specific behavior.
There is no 'random' or 'floating' read data (high-z buses inside a chip was present in 20th century designs), by default the logic will drive 0 on unused bits (including write only) unless noted in the spec or if there is something hidden in the spec (i.e. test bits not described).
Regards.
2022-10-11 12:22 AM
I confirm that bit-banding was not really handy (and the hidden RMW is quite hard to understand) and by then not really used except by fans/gurus .
As far as I know, bit banding was only present in few Cortex-M cores (M3 and M4 I guess).
Set/Reset registers are a more robust, efficient and easy to understand way of working.
Regards.
2022-10-12 06:17 AM
Hi Patrick,
Thanks for the explanation.
JW
@PatrickF