Why set a status and control register this way ?? - Page 1
Forum section: electronics / general

author: MathWizard
author_rank: Super Contributor
timestamp: September 14, 2024, 04:55:48 am
content: 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 forMSB b7=1 for external clockb6=1 for Vcc/3 biasb5:4=10 for 1/3 duty cycleb3=0 reservedb2: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 241QuoteJust from the " (1<<LCDCS) | (1<<LCDMUX1)| (1<<LCDPM2) " section, that they want to load into r16The 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 = 1And 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 expression1<<LCDCS, would they really mean 10000000<<0, since the LCDCS is the 8th bit ? Then I can see the OR getting somewhere.

author: brucehoult
author_rank: Super Contributor
timestamp: September 14, 2024, 05:46:04 am
content: Quote from: MathWizard on September 14, 2024, 04:55:48 amThere is presumably some#includeof 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 is0b10000000 | 0b1000000 | 0b100000 | 0b111which is0b11100111The compiler or assembler does this calculation at compile time, so it's exactly the same as if you'd written0b11100111yourself, or0xE7, or 231.Note:0bxxxsyntax might or might not be accepted by your compiler or assembler.

author: pcprogrammer
author_rank: Super Contributor
timestamp: September 14, 2024, 07:01:46 am
content: 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)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

author: eutectique
author_rank: Frequent Contributor
timestamp: September 14, 2024, 12:45:27 pm
content: Quote from: MathWizard on September 14, 2024, 04:55:48 amYou 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/#msg5638431The bottom line is: a good program is written for a person, and then for a compiler.

author: jpanhalt
author_rank: Super Contributor
timestamp: September 14, 2024, 01:48:31 pm
content: 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 Assemblymovlwb'abcdefgh';a = something;b = something else;c ="";d-h =""movwf OPTIONThat was done for readability on reviewing the code.

author: Andy Chee
author_rank: Super Contributor
timestamp: September 14, 2024, 02:30:44 pm
content: That's how I coded PIC assembly:Code:OPTIONSETUPequB'01011110';the default option setup for this program; | | |||; | | +++----WDT prescaler 1:64 (<PS2:PS0> = 110) 18ms*64 = 1.152s; | +---------TMR0 increments on internal clock (T0CS lo); +-----------GPIO pullups on (GPPU lo)clrfTMR0;clear TMR0, and THEN WDT to ensure no accidental watchdog resetclrwdtmovlwOPTIONSETUP;setup option register for TMR0 interupt sourcebsfSTATUS,RP0movwfOPTION_REGbcfSTATUS,RP0

author: MathWizard
author_rank: Super Contributor
timestamp: September 14, 2024, 07:15:07 pm
content: Thanks, so forQuotewrite your desired value on the left, then left shift it, to the starting/LSB bit position of the variable in question.Yeah so for say LCDPM2,LC2PM1, LCDPM0, at bit position at 2,1,0 of the 8-bit LCDCRB register, that's equiv to LCDPM2:0 , so those would set to b000001111<<LCDPM2 would be 1<<2 goes to b000001001<<LCDPM1 " 1<<1 " b000000101<<LCDPM0 " 1<<0 " b00000001and then bitwise OR themor justb111<<0 equates to b111The way I tried it would only work, if all the initial values were 0, so that won't really work.

author: Andy Chee
author_rank: Super Contributor
timestamp: September 15, 2024, 03:22:44 am
content: Quote from: MathWizard on September 14, 2024, 07:15:07 pmNormally the hardware reset will set the registers to a known condition, so it should work provided you reset it.

author: pcprogrammer
author_rank: Super Contributor
timestamp: September 15, 2024, 05:44:58 am
content: If it is necessary to change the bits to a new setting during runtime one can use bitwise AND with the negated bits.In C:Code:char a = 0;//Initial configurationa = (1 << 5) | (1 << 3);//Need to change the configurationa &= ~(1 << 5);a |= (1 << 6);

author: m k
author_rank: Super Contributor
timestamp: September 15, 2024, 02:28:36 pm
content: With shifting bits they can define bits directly by their locations.It's also how datasheets are written.Writing a code is a bit more difficult first, but completely mechanical after that.Just some copy/paste and actual order is also irrelevant.Resetting a bit is a bit more complex, but just a bit.

author: MathWizard
author_rank: Super Contributor
timestamp: September 18, 2024, 12:09:52 am
content: I'm decoding the Intel Hex, into opcodes, of an ATtiny13A with a blink program on there, so far I'm up to WORD 45 in the program flash. And so far it's gone ok, since I found 1 of the only AVR OPCODE tables in existence it seems.https://fruttenboel.nl/AVR/opcodes.htmlIt's only a few linesLine 2:20002000B0E001C01D92A436B207E1F727D03EC0E7CF1F920F920FB60F9211248F939F9369program data should beB0E001C01D92A436B207E1F727D03EC0E7CF1F920F920FB60F9211248F939F93which in Assembly should beLDI R11,0RJMP 1SR X+,R1CPI R25,97CPC R27,R17BRNE 124RCALL 39RJMP 62RJMP 3877PUSH R1PUSH R0IN R0,63PUSH R0CLR R17PUSH R24PUSH R25I need to see how that matches up with the very short blink code written in C by ArduinoIDE

author: westfw
author_rank: Super Contributor
timestamp: September 19, 2024, 06:47:53 am
content: QuoteSee also:https://drive.google.com/file/d/0B6dMB5dovDUZQ1pPMWtfMkJSU1k/view?usp=sharing&resourcekey=0-mB8Ye-PIxvODzztiWa9xzgQuoteWhy? avr-objdump will do that for you...Code:> avr-objdump -D -mavr Arduino1.8.13Build/Blink.ino.hexArduino1.8.13Build/Blink.ino.hex: file format ihexDisassembly of section .sec1:00000000 <.sec1>:0: 09 c0 rjmp .+18 ; 0x142: 28 c0 rjmp .+80 ; 0x544: 27 c0 rjmp .+78 ; 0x546: 26 c0 rjmp .+76 ; 0x548: 25 c0 rjmp .+74 ; 0x54a: 24 c0 rjmp .+72 ; 0x54c: 23 c0 rjmp .+70 ; 0x54e: 22 c0 rjmp .+68 ; 0x5410: 21 c0 rjmp .+66 ; 0x5412: 20 c0 rjmp .+64 ; 0x5414: 11 24 eor r1, r116: 1f be out 0x3f, r1 ; 6318: cf e9 ldi r28, 0x9F ; 1591a: cd bf out 0x3d, r28 ; 611c: 01 d0 rcall .+2 ; 0x201e: 1b c0 rjmp .+54 ; 0x5620: 78 94 sei22: b9 9a sbi 0x17, 1 ; 2324: c1 9a sbi 0x18, 1 ; 2426: 89 ee ldi r24, 0xE9 ; 23328: 93 e0 ldi r25, 0x03 ; 32a: 01 97 sbiw r24, 0x01 ; 12c: 61 f4 brne .+24 ; 0x462e: c1 98 cbi 0x18, 1 ; 2430: 89 ee ldi r24, 0xE9 ; 233

author: MathWizard
author_rank: Super Contributor
timestamp: September 20, 2024, 06:41:10 am
content: Ok I'll use something like that down the road. I had a few errors so far.But I'm doing it all in a spreadsheet, and putting notes everywhere. So far I think I get it, I'm up to a Branch if NOT Equal at instruction 21.In the ArduinoIDE, I think that's related to the "while :" function, that they use as they bitshift through one of the LED port register to turn it, or set direction. And it delays 500 or 1000ms depending on where it is in that bitshift of the port register. But yeah I'm not that familiar with C or programming either.