Electronics > Microcontrollers

Why set a status and control register this way ??

(1/3) > >>

MathWizard:
I'm learning about the LCD display drive in an ATmega169pa (and AVR, C and assembly). I've seen how it works IRL on a scope, and I know what most of the basic settings would be.

In this example from the datasheet below, they want to set the "LCDCRB – LCD Control and Status Register B" to the desired b11100111, which would be for

MSB b7=1 for external clock
b6=1 for  Vcc/3 bias
b5:4=10 for 1/3 duty cycle
b3=0 reserved
b2:0=111 if up to segment 24, is to be used (ignoring they only want SEG21 to SEG24 for now)

So if someone wanted to load this into the chip, wouldn't they just store this one 8-bit number in the memory, and then load it up into the LCDCRB register when the MCU starts running ? Maybe just to not use that 1 byte, it would add up for all the other stuff that needs setting ? But the program code takes space too so ??


Instead they do it with bitwise leftshift, and bitwise OR. I'm probably missing something, otherwise, I don't get why they do all this.

from page 241

--- Quote ---Assembly Code Example(1)
LCD_Init:
; Use 32 kHz crystal oscillator
; 1/3 Bias and 1/3 duty, SEG21:SEG24 is used as port pins
ldi r16, (1<<LCDCS) | (1<<LCDMUX1)| (1<<LCDPM2)
sts LCDCRB, r16
; Using 16 as prescaler selection and 7 as LCD Clock Divide
; gives a frame rate of 49 Hz
ldi r16, (1<<LCDCD2) | (1<<LCDCD1)
sts LCDFRR, r16
; Set segment drive time to 125 µs and output voltage to 3.3 V
ldi r16, (1<<LCDDC1) | (1<<LCDCC3) | (1<<LCDCC2) | (1<<LCDCC1)
sts LCDCCR, r16
; Enable LCD, default waveform and no interrupt enabled
ldi r16, (1<<LCDEN)
sts LCDCRA, r16
ret
C Code Example(1)
Void LCD_Init(void);
{
/* Use 32 kHz crystal oscillator */
/* 1/3 Bias and 1/3 duty, SEG21:SEG24 is used as port pins */
LCDCRB = (1<<LCDCS) | (1<<LCDMUX1)| (1<<LCDPM2);
/* Using 16 as prescaler selection and 7 as LCD Clock Divide */
/* gives a frame rate of 49 Hz */
LCDFRR = (1<<LCDCD2) | (1<<LCDCD1);
/* Set segment drive time to 125 µs and output voltage to 3.3 V*/
LCDCCR = (1<<LCDDC1) | (1<<LCDCC3) | (1<<LCDCC2) | (1<<LCDCC1);
/* Enable LCD, default waveform and no interrupt enabled */
LCDCRA = (1<<LCDEN);
--- End quote ---


Just from the " (1<<LCDCS) | (1<<LCDMUX1)| (1<<LCDPM2) " section, that they want to load into r16

The initial value of the LCDCS, Clock select bit b7 is 0. And so are all the other initial values. So for 1<<LCDCS, isn't that just 1<<0 = 1

And then the same for the other 2, and then bitwise OR  would be (1|1|1)=1 ?? , so at best b0000001, and not b11100111 ??


What am I missing here ?


Ok they don;t even use LCD2B is the 1st section, so yeah it would never work.

But for the expression
1<<LCDCS, would they really mean 10000000<<0, since the LCDCS is the 8th bit ? Then I can see the OR getting somewhere.

brucehoult:

--- Quote from: MathWizard on September 14, 2024, 04:55:48 am ---In this example from the datasheet below, they want to set the "LCDCRB – LCD Control and Status Register B" to the desired b11100111, which would be for

MSB b7=1 for external clock
b6=1 for  Vcc/3 bias
b5:4=10 for 1/3 duty cycle
b3=0 reserved
b2:0=111 if up to segment 24, is to be used (ignoring they only want SEG21 to SEG24 for now)

:

; Use 32 kHz crystal oscillator
; 1/3 Bias and 1/3 duty, SEG21:SEG24 is used as port pins
ldi r16, (1<<LCDCS) | (1<<LCDMUX1)| (1<<LCDPM2)
sts LCDCRB, r16

Just from the " (1<<LCDCS) | (1<<LCDMUX1)| (1<<LCDPM2) " section, that they want to load into r16

The initial value of the LCDCS, Clock select bit b7 is 0. And so are all the other initial values. So for 1<<LCDCS, isn't that just 1<<0 = 1

And then the same for the other 2, and then bitwise OR  would be (1|1|1)=1 ?? , so at best b0000001, and not b11100111 ??

--- End quote ---

There is presumably some #include of a file that defines LCDCS, LCDMUX1, LCDPM2.

It's not clear to me how those names map to the fields you describe, except LCDCS presumably Clock Select, and therefore will equal 7.

I'd expect names such as LCDBIAS=6, LCDDUTY=4. I don't understand the encoding of bits 2:0 well enough to name that but let's say LCDSEG=0.

So to code CS=1, bias=1, duty=10, segment select=111 you'd write:

(1<<LCDCS) | (1<<LCDBIAS) | (2<<LCDDUTY) | (7<<LCDSEG)

which is

(0b1<<7) | (0b1<<6) | (0b10<<4) | (0b111<<0)

which is

0b10000000 | 0b1000000 | 0b100000 | 0b111

which is

0b11100111

The compiler or assembler does this calculation at compile time, so it's exactly the same as if you'd written 0b11100111 yourself, or 0xE7, or 231.

Note: 0bxxx syntax might or might not be accepted by your compiler or assembler.

pcprogrammer:
Like brucehoult wrote, it boils down to the same in the final machine code.

It just makes it somewhat easier to read in a way that you know what the configuration is. A single hex or binary number says nothing until you translate the bits back to the actual configuration. Using the defined names can be more informative.

The construct with the shifting of the setting bit makes it a bit less readable. I myself like to use defines that contain that shifting in it. Like in C:


--- Code: ---#define LCDCS_TOSC1    (1<<LCDCS)
#define LCDCS_CLKIO    (0<<LCDCS)

--- End code ---

Sure shifting a 0 does nothing, but using the LCDCS_ names in the code can be more meaningful.

Edit: modified the names in the C defines to match the datasheet

eutectique:

--- Quote from: MathWizard on September 14, 2024, 04:55:48 am ---Instead they do it with bitwise leftshift, and bitwise OR. I'm probably missing something, otherwise, I don't get why they do all this.

--- End quote ---

You might want to read the following discussion in the neighbouring thread: https://www.eevblog.com/forum/microcontrollers/is-st-cube-ide-a-piece-of-buggy-crap/msg5638431/#msg5638431

The bottom line is: a good program is written for a person, and then for a compiler.

jpanhalt:
I agree with the others who suggest it is for readability.  Many years ago, it was not uncommon to see something like this in PIC Assembly:

--- Code: ---PIC Assembly

movlw b'abcdefgh'      ;a = something
;b = something else
;c =  ""
;d-h = ""
        movwf      OPTION

--- End code ---

That was done for readability on reviewing the code.

Navigation

[0] Message Index

[#] Next page

There was an error while thanking
Thanking...
Go to full version
Powered by SMFPacks Advanced Attachments Uploader Mod