cancel
Showing results for 
Search instead for 
Did you mean: 

That is the readback value of a write only register.

WOGoos
Associate II

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);
}

14 REPLIES 14

> 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

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.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

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.

In order to give better visibility on the answered topics, please click on 'Accept as Solution' on the reply which solved your issue or answered your question.

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.

In order to give better visibility on the answered topics, please click on 'Accept as Solution' on the reply which solved your issue or answered your question.

Hi Patrick,

Thanks for the explanation.

JW

@PatrickF​