#avr Logs

Sep 12 2021

#avr Calendar

03:20 AM Aighearach is now known as _Aighearach
03:28 AM _Aighearach is now known as Aighearach
08:12 AM joakimk: I've got a timer running at a steady rate of 1/256 sec, and I want to toggle some LEDs at a variable rate. The tempo is then controlled by counting number of such "ticks" (1/256), and toggling 3 LEDs like this: `if (ticks++ > tempo) PORTB = ~(program[step++]);`
08:13 AM joakimk: here, `program` is an array of unsigned ints, like `[0b00000111, 0b00000000]`. I make sure to "reset" `step` back to 0 when it becomes 2 etc
08:15 AM joakimk: this works; I can change the tempo and the LEDs blink at variable rates. Nice and steady. I now want to use the remaining 7 LEDs to output some status info on the system, like "isConnected" (to wifi), and "isRunning" (i.e. the main while(1) loop) etc
08:16 AM joakimk: Initially, I did this: `PORTB = (~(program[step++] | (isConnected<< 7) | (isRunning<< 6)));` which also works fine
08:17 AM joakimk: But then I want to extend on this, by introducing a blinking state also on the status/indicator LEDs. They, however, should blink at a *steady* rate -- independent of the program-tempo
08:20 AM joakimk: Within the ISR (this is all in the `ISR (TIMER1_COMPA_vect)` ) I expected to be able to do something like this: https://controlc.com/c8ae1892
08:22 AM joakimk: but if I "OR" in the different bits on/to PORTB (like in the paste) then I get nothing on the 8 LEDs: all off. I assume this is because there is no "initial state" of PORTB to OR onto
08:23 AM twnqx: well
08:23 AM twnqx: if you always "or" you will never get a zero again, so after setting the state will be fixed, indeed
08:23 AM joakimk: right
08:23 AM twnqx: the recommendation would be xor instead
08:23 AM twnqx: xor with a 0 bit to not change, xor with a 1 bit to toggle
08:24 AM joakimk: but then I get wild output across the 8 LEDs. I guess I'm losing track, especially since I also have to revert the output (pin 1 means LED off)
08:24 AM twnqx: well, wild blinking at least indicates that something happens :P
08:24 AM joakimk: yes!
08:25 AM joakimk: very true
08:26 AM joakimk: So, I can get it (almost) working if I always set the entire byte in both cases, like `PORTB = (~(program[step] | (Running_Status << 5) | (masterState << 4)));`
08:26 AM joakimk: but then I sometimes will set the "program byte" twice, and the smoothness is lost
08:27 AM qu1j0t3: yes, that's basically the sane way to do it.
08:29 AM joakimk: set all every time?
08:30 AM joakimk: but apparently this is not a good way of achieving steady blinking of different bits, at different rates...
08:30 AM qu1j0t3: it can do that.
08:30 AM joakimk: they do blink at different rates, but everything "jitters"
08:31 AM qu1j0t3: yes.
08:31 AM qu1j0t3: that's math.
08:31 AM joakimk: the lights are flickering at a barely noticable rate... not good
08:31 AM joakimk: yes I see
08:31 AM qu1j0t3: ok, so if you want to set them independently, you can do that with bitwise operations.
08:31 AM joakimk: it's because the two if-s are sometimes occuring both, right?
08:32 AM qu1j0t3: i mean "sane way" assuming if your update rate was high enough to sufficiently reduce the jitter
08:32 AM joakimk: but how can I write to PORTB without affecting what's on there already?
08:32 AM qu1j0t3: several ways
08:32 AM joakimk: the update rate goes all the way down to 1Hz
08:32 AM qu1j0t3: but one way is to take what's there, change one bit, and store
08:32 AM joakimk: (approx)
08:32 AM qu1j0t3: C gives you the operators to do that
08:32 AM joakimk: yeah.. ok. I should start both ifs (cases) by reading off what's on PORTB
08:33 AM joakimk: like `uint8_t mem = (~PORTB);`
08:33 AM qu1j0t3: you could read PORTB once, before doing any of your logic, yeah
08:33 AM qu1j0t3: when i say 'update rate', though, i don't mean for an individual led
08:34 AM qu1j0t3: i mean the rate you run all this and update PORTB.
08:34 AM joakimk: 1/256?
08:34 AM joakimk: or wait... I think I misunderstood
08:34 AM joakimk: the ISR fires off every 1/256
08:34 AM joakimk: but the program LEDs are blinked every X such "ticks"
08:34 AM qu1j0t3: yes
08:35 AM qu1j0t3: in that situation, you don't gain anything by updating single bits
08:35 AM qu1j0t3: i think your code logic is flawed
08:35 AM joakimk: surely
08:35 AM qu1j0t3: my first suggestion is:
08:35 AM qu1j0t3: update all of PORTB every tick
08:35 AM joakimk: hm
08:35 AM joakimk: ok
08:36 AM joakimk: but only advance program[step] every "tick" times?
08:36 AM qu1j0t3: yes
08:36 AM qu1j0t3: you are basically doing that as a separate step
08:36 AM LeoNerd: If you have two notionally-independent flashing LEDs, I'd keep two indepenent counters for them
08:36 AM qu1j0t3: ^
08:36 AM LeoNerd: Run the update logic on each in the ISR
08:37 AM joakimk: I do have two counters... You mean two timers?
08:37 AM qu1j0t3: no
08:37 AM joakimk: I have `ticks` and `ticks2` :P
08:37 AM qu1j0t3: LeoNerd means you keep a counter per LED, which makes the rates independent
08:38 AM joakimk: one counter for 3 program LEDs (they all blink same rate!), and the other for the status LEDs (same -- common tempo)
08:38 AM LeoNerd: ISR { { static int ticks = 0; ticks++; if(ticks > RATE_A) { do the A stuff; ticks = 0 } } { static int ticks = 0; ... same again but with B } }
08:38 AM joakimk: and then write to PORTB at the end of the ISR?
08:38 AM qu1j0t3: where 'do the A stuff' and 'do the B stuff' is to update the output bits
08:38 AM qu1j0t3: joakimk: Yes.
08:38 AM LeoNerd: yeah that could be nice
08:38 AM qu1j0t3: joakimk: update every tick.
08:38 AM qu1j0t3: and that solves your problem
08:38 AM LeoNerd: uint8_t new_portb = PORTB.OUT; ... logic here; PORTB.OUT = new_portb;
08:39 AM joakimk: starting with reading off what's on PORTB, right?
08:39 AM joakimk: then XOR-ing on bits
08:39 AM qu1j0t3: > update the output bits // sorry, i don't mean directly. i mean update the values that you will write to PORTB
08:39 AM joakimk: and then writing at the end
08:39 AM qu1j0t3: joakimk: yes
08:39 AM qu1j0t3: joakimk: Well, no -- you don't even need to read PORTB unless there is unrelated state.
08:40 AM joakimk: so...
08:40 AM qu1j0t3: joakimk: if there's no state to preserve, just start with 0, because your two counters fully determine LED state
08:40 AM joakimk: ah
08:40 AM qu1j0t3: well
08:40 AM qu1j0t3: actually i'm wrong in a way
08:40 AM qu1j0t3: you want to 'toggle on reset'
08:40 AM qu1j0t3: which is ok too
08:41 AM joakimk: reset ticks and ticks2 yes
08:41 AM joakimk: ^ reset on ticks
08:41 AM qu1j0t3: your way is probably better: read PORTB, and toggle when each counter reaches X
08:41 AM twnqx: but only if the LED is supposed to blink and not be fixed on/off :P
08:41 AM joakimk: but read and write PORTB every time
08:41 AM qu1j0t3: joakimk: Yes.
08:41 AM joakimk: well -- isRunning etc should be fixed on though
08:41 AM qu1j0t3: that's easy
08:41 AM joakimk: (until status changes)
08:43 AM qu1j0t3: joakimk: the safe way to manage that may be to copy its state from a global, every tick. that way other non-isr code can safely change its state.
08:43 AM joakimk: yes
08:43 AM joakimk: I have volatile ints to hold the various status/states
08:43 AM qu1j0t3: but it just becomes part of your general "compute new PORTB"
08:43 AM joakimk: but check this:
08:44 AM joakimk: `ISR { uint8_t newState = (~PORTB); if (ticks++ >= tempo) newState ^= (~(program[step++])); PORTB = newState; } `
08:44 AM joakimk: is this essentially what we're talking about?
08:45 AM joakimk: do I XOR onto newState or what? This bit-twiddling is messing with my mind...
08:45 AM joakimk: the extended/status version would then be:
08:45 AM qu1j0t3: joakimk: remember that these are bitwise operations
08:46 AM joakimk: `ISR { uint8_t newState = (~PORTB); if (ticks++ >= tempo) newState ^= (~(program[step++])); if (ticks2++ >= 50) newState ^= (~(isConnected << 7)); PORTB = newState; } `
08:46 AM joakimk: (I skipped the actual reset of ticks and ticks2 back to 0 above)
08:46 AM qu1j0t3: actually i think your jitter "bug" is something else
08:46 AM joakimk: jitter bug
08:46 AM joakimk: :D
08:47 AM qu1j0t3: i think you're possibly not computing the "mod X" correctly, looking at this
08:47 AM qu1j0t3: program is an array of counters?
08:47 AM joakimk: now I understand that Wham! song much better
08:47 AM qu1j0t3: what is step doing?
08:47 AM joakimk: step is the position in the "byte array" containing the "program" (bit pattern to put on the 3 LEDs)
08:48 AM qu1j0t3: ohhhh sorry,ok
08:48 AM joakimk: can be like, 001 010 100 010
08:48 AM qu1j0t3: unrelated to ticks
08:48 AM joakimk: yeah
08:48 AM qu1j0t3: gotcha, never mind.
08:48 AM joakimk: another program will be just 000 111
08:48 AM joakimk: :)
08:48 AM qu1j0t3: well, okay, so:
08:48 AM qu1j0t3: i still think you have a bug. When ticks >= tempo, you need to reset ticks to zero. are you doing that
08:48 AM joakimk: yes
08:48 AM qu1j0t3: ok
08:48 AM joakimk: like in the paste
08:48 AM qu1j0t3: no bug there then :)
08:49 AM joakimk: https://controlc.com/c8ae1892
08:49 AM joakimk: yep :)
08:49 AM qu1j0t3: ok, so make sure you do that inside the conditional
08:49 AM joakimk: yes
08:49 AM qu1j0t3: but not like your line paste
08:49 AM qu1j0t3: that's incorrect
08:50 AM qu1j0t3: the reset to zero has to be inside each >= conditional
08:50 AM qu1j0t3: they're independent
08:50 AM qu1j0t3: if that was wrong before, then you would not get correct timing
08:50 AM joakimk: yeah... I was just trying to keep that short
08:50 AM joakimk: sorry
08:50 AM qu1j0t3: ok
08:53 AM joakimk: but if I start by reading off PORTB like this, `uint8_t newState = (~PORTB);`
08:53 AM joakimk: how do I then set, say, bit 8 to the bit contained in `Running_Status`?
08:54 AM qu1j0t3: you can mask it to 0 with & then | or ^ it in
08:54 AM joakimk: do I do, `newState |= (Running_Status << 7);` ?
08:54 AM joakimk: where Running_Status is uint8_t = 0 or 1
08:54 AM qu1j0t3: newState = (newState & ~ (Running_Status << 7)) | (Running_Status << 7)
08:54 AM joakimk: but why am I inverting it now?
08:55 AM qu1j0t3: no need
08:55 AM qu1j0t3: it doesn't toggle like the others
08:55 AM joakimk: but your ~
08:55 AM qu1j0t3: that's the bit mask for AND (&)
08:55 AM joakimk: &~ ?
08:55 AM qu1j0t3: & ~x
08:55 AM qu1j0t3: ~ is unary
08:55 AM qu1j0t3: NOT
08:55 AM joakimk: ~ is invert, isn't it?
08:55 AM qu1j0t3: yes.
08:55 AM joakimk: yeah not
08:55 AM qu1j0t3: you invert a bit to get a bit mask for AND
08:55 AM joakimk: why are you inverting/not-ing
08:55 AM joakimk: ah
08:55 AM qu1j0t3: applying that mask zeroes the bit.
08:56 AM qu1j0t3: clearly you can't zero it with | or ^
08:56 AM qu1j0t3: (unless ^ and knowing with certainty it was set)
08:56 AM qu1j0t3: (but let's not assume that)
08:56 AM qu1j0t3: sorry
08:57 AM qu1j0t3: my code is incorrect, the first reference to Running_Status should be 1
08:57 AM qu1j0t3: apologies
08:57 AM qu1j0t3: newState = (newState & ~ (1 << 7)) | (Running_Status << 7)
08:57 AM qu1j0t3: haven't had coffee yet
08:57 AM joakimk: hehe
08:57 AM qu1j0t3: and i'm used to seeing symbolic names for bits
08:57 AM qu1j0t3: so you're taking the positional mask for the bit, inverting it, and'ing it to zero it, then or'ing in the actual state
08:58 AM joakimk: I can't get anything to work.. It's either all 8 LEDs on, all off, or dancing madness :(
08:58 AM qu1j0t3: ok paste what you have
08:58 AM joakimk: unless I set all 8 bits directly onto PORTB, every time
08:58 AM joakimk: ok
08:58 AM qu1j0t3: but that's what we _are_ doing now.
08:58 AM qu1j0t3: that's the right thing to do on every tick.
08:58 AM joakimk: but not separately, within each if
08:59 AM joakimk: just write to PORTB once
08:59 AM joakimk: that I can't get working
08:59 AM qu1j0t3: you read PORTB once (or not at all, if you compute all state), and write it once.
08:59 AM qu1j0t3: okay show your paste
09:00 AM joakimk: https://controlc.com/adf800fa
09:01 AM joakimk: see how I'm reading off PORTB, and writing it -- once! -- at the end
09:01 AM qu1j0t3: reading
09:01 AM joakimk: :)
09:02 AM qu1j0t3: ok the expressions are wrong, i think
09:02 AM qu1j0t3: looks like this line:
09:02 AM qu1j0t3: newState = (newState & ~((Running_Status << 5) | (masterState << 4)));
09:02 AM qu1j0t3: should be more like:
09:02 AM qu1j0t3: newState = (newState & ~((Running_Status << 5) | (masterState << 4)));
09:02 AM qu1j0t3: oops
09:04 AM qu1j0t3: newState = (newState & ~(1 << 5) & ~(1 << 4)) | (Running_Status << 5) | (masterState << 4);
09:04 AM qu1j0t3: but
09:04 AM qu1j0t3: the program update seems also to need changing
09:04 AM qu1j0t3: and
09:04 AM qu1j0t3: i would rearrange this whole thing
09:05 AM qu1j0t3: let me do a separate paste
09:05 AM joakimk: :+1:
09:05 AM joakimk: thanks a lot
09:05 AM qu1j0t3: which are the bits in program[step] that you update?
09:05 AM joakimk: but you're making sure there's a 1 in positions (bits) 4 and 5
09:05 AM joakimk: program = 0b00000100 etc
09:05 AM joakimk: so "last three"
09:05 AM joakimk: (or first three?)
09:06 AM qu1j0t3: we can say 'least significant 3'
09:06 AM joakimk: top
09:06 AM qu1j0t3: or with usual numbering, bits 0,1,2
09:06 AM joakimk: :)
09:09 AM qu1j0t3: actually i don't think i need a new paste. try changing the 2nd update to: newState = (newState & ~7) | program[step++];
09:09 AM qu1j0t3: that does the same trick, use the mask to zero the bits, then OR them back in
09:09 AM qu1j0t3: as well as the similar change above
09:09 AM joakimk: so 7, as in 0b00000111 ?
09:09 AM qu1j0t3: yes
09:10 AM joakimk: OK- I now have:
09:10 AM qu1j0t3: obviously you can express this any way you want.. in real code you might have a #define for the mask
09:10 AM joakimk: `uint8_t newState = PORTB;`
09:10 AM joakimk: should I invert the bits?
09:10 AM joakimk: before starting?
09:10 AM joakimk: guess so...
09:10 AM qu1j0t3: actually i meant to ask about that
09:10 AM qu1j0t3: no you wouldn't
09:10 AM joakimk: ok -- then I start with that
09:10 AM joakimk: then
09:11 AM joakimk: `newState = (newState & ~(1 << 5) & ~(1 << 4)) | (Running_Status << 5) | (masterState << 4);`
09:11 AM joakimk: (if first conditional)
09:11 AM joakimk: and
09:11 AM joakimk: `newState = (newState & ~7) | program[step++];`
09:11 AM joakimk: (if 2nd conditional)
09:11 AM joakimk: and finally,
09:11 AM joakimk: `PORTB = (~(newState));`
09:11 AM qu1j0t3: ok
09:11 AM qu1j0t3: so that one
09:11 AM qu1j0t3: you don't invert either
09:11 AM joakimk: no?
09:11 AM joakimk: just `PORTB = newState;`
09:12 AM joakimk: ?
09:12 AM qu1j0t3: yes
09:12 AM joakimk: but if I want to turn on all 3 leds, I have to output PORTB = 0b11111000
09:12 AM qu1j0t3: ok so that's a bit of a different question
09:12 AM joakimk: yeah... I kind of tried to include it initally
09:12 AM joakimk: blows my mind
09:12 AM joakimk: "also, everything is inverted too"
09:12 AM joakimk: fun!
09:13 AM qu1j0t3: it's better to not do those inversions when rading and writing portb
09:13 AM joakimk: ok...
09:13 AM qu1j0t3: just do your state computations in the inverted way, so flip your blinkstate values
09:13 AM qu1j0t3: and, the 2nd update changes to:
09:13 AM qu1j0t3: newState = (newState & ~7) | (program[step++] ^ 7)
09:13 AM qu1j0t3: is one way to do it
09:14 AM joakimk: can I do `newState = (newState & ~(1 << 5) & ~(1 << 4)) | ~(Running_Status << 5) | ~(masterState << 4);`
09:14 AM qu1j0t3: no
09:14 AM joakimk: invert RunningStatus and masterState
09:14 AM joakimk: ok
09:14 AM qu1j0t3: but you don't need to
09:14 AM qu1j0t3: just compute blinkState the other way round, and comment // this is the inverted value that goes on the pin
09:14 AM qu1j0t3: or something
09:15 AM qu1j0t3: or 0 = ON, 1 = OFF, or whatever you like :)
09:15 AM joakimk: yeah!
09:15 AM joakimk: now we're talking!
09:15 AM qu1j0t3: i think it will mess with your head less if you don't work with the inverted portb, in short
09:15 AM joakimk: blinking (scrolling LEDs) while also steadily blinking bit 4
09:15 AM joakimk: the "master state" indicator
09:16 AM joakimk: Running_Status is off now, but I can change that as you say
09:16 AM joakimk: I will now have dinner (hehe) and then look over this and consider why this bit-twiddling has to be like this :)
09:17 AM qu1j0t3: sure. bon appetit
09:17 AM joakimk: so much easier to understand something that works, rather than figure out why something is failing the way it fails
09:17 AM joakimk: but wow -- you taking the time for this...
09:17 AM qu1j0t3: np
09:17 AM joakimk: thanks a lot!
09:17 AM qu1j0t3: don't forget to add comments
09:17 AM qu1j0t3: :)
09:17 AM qu1j0t3: yw
09:18 AM joakimk: yes!
09:18 AM joakimk: I have a small description of the project here: https://github.com/joakimgk/trafikklys
09:19 AM joakimk: maybe I've shown you before :P
09:28 AM joakimk: btw, `newState & ~(1 << 5) & ~(1 << 4)` that's not "putting a 1 in bits 4 and 5", right`?
09:28 AM qu1j0t3: right, it's not
09:28 AM joakimk: it's "extracting" out (reading or masking or whatever) what's there, in those bits, currently
09:28 AM qu1j0t3: yes
09:28 AM joakimk: :+1:
09:29 AM qu1j0t3: you can force those bits anywhere you like
09:29 AM qu1j0t3: the final write to PORTB would be one good place
09:29 AM qu1j0t3: oh sorry
09:29 AM joakimk: yes :) So it's the same as you're doing with `newState & ~ 7`
09:29 AM qu1j0t3: ignore that last bit.
09:29 AM joakimk: very nice :)
09:29 AM qu1j0t3: yeah, mask to zero, then OR
09:30 AM qu1j0t3: my brain clearly isn't fully working this morning
09:31 AM qu1j0t3: how did you make the pcb?
09:40 AM joakimk: I had access, once, to the lab at the U
09:40 AM joakimk: ;)
09:41 AM joakimk: print on foil, and expose onto photo pcb, then develop board and finally etch in acid
09:41 AM joakimk: used photo-sensitive pcb, if that's what it's called
09:43 AM qu1j0t3: nice.
09:43 AM joakimk: yeah :)
09:44 AM joakimk: OK, got to go. Thanks again for the help!
09:44 AM qu1j0t3: cheers. o/
09:44 AM joakimk: :)
02:31 PM specing_ is now known as specing
05:55 PM Smashcat: Can anyone see what's wrong with this code? Trying to enter sleep mode on an ATMega328pb, and wake on pin change on PORTD 2 - it's sleeping, but pin change is not working: https://pastebin.com/qu4CvPBF
06:23 PM nero: hello, previously, i did my avr stuff with avr-gcc and makefiles
06:23 PM nero: i'd like to program directly in assembly
06:24 PM Phantom: that is generally a stupid idea
06:24 PM nero: its an attiny45 driving ws2812b leds
06:25 PM Phantom: so?
06:25 PM nero: so both timing and ram are critical
06:25 PM nero: im asking for the "how"
06:25 PM Smashcat: nero: You can write in asm using microchip studio
06:26 PM Smashcat: nero: If you look at some timing critical projects like bit-banged UARTS they are usually in ASM, so you can see how the projects are set up
06:28 PM nero: is there some thing for avr what NASM is to x86 ?
06:28 PM Smashcat: nero: As said, Microchip Studio
06:33 PM nohit: there are many assemblers for avr iirc
06:33 PM nohit: and you can also use gcc
06:34 PM Smashcat: Am I visible in this channel?
06:34 PM nero: Smashcat: yes
06:34 PM nohit: or the gnu as
06:34 PM nero: sorry i didnt honour your reply, i was researching into the studio
06:34 PM Smashcat: Oh ok.
06:35 PM Smashcat: It used to be called AVR Studio - it's the same thing.
06:36 PM nohit: if you want minimal changes to your previous setup you can use avr-as
06:37 PM nohit: and makefiles
06:37 PM nero: ah im an idiot
06:37 PM nero: yeah binutils have an assembler for each arch
06:37 PM nohit: but yeah, atmel studio is great, but its not for everyone
06:38 PM nero: and due to avr-gcc, i also have the avr binutils already installed
06:38 PM nero: yeha im hesitant to use the studio, im a terminal monkey
06:40 PM nero: avr-objdump is also able to disassemble the binaries so i can verify the results
06:48 PM Smashcat: Hmm, I think I'm missing something here - seems like the ATMega328pb doesn't handle interrupts the same as the ATMega328P
06:56 PM nohit: this is also an option https://sourceforge.net/projects/avra/
06:57 PM nohit: avrasm2 is atmel's own assembler but sadly it seems to be windows only