Saturday, March 28, 2020

0000 0000 0010 1000

A dabble in AVR Assembly (II)

In an earlier blog I looked at putting a very tired (128kHz) Attiny13a to sleep using some assembler code. But when it's awake, maybe we want to make it act like a candle and flicker. "First learn stand, then learn fly" Mr Miyagi said, so instead of a deep dive I will see if I can get one PWM channel on the μC to ramp up and down, then maybe I can get the two of them to move randomly-ish?

First we choose a pin to output to:


PWM pins are pin5 and pin 6 from this diagram. If OC0A is on PB0 (pin5), and OC0B in on PB1 (pin6) then looking at the datasheet it seems that the TCCR0A register controls the PWM behaviour of these channels (copy 2 [binary 10] into COM0A0 and 2 [binary 10] into COM0B0).


We also want to use Fast PWM mode so in assembler (copy 3 [binary 11] into WGM00); these instructions look like this:

ldi r16, 0b10100011    ; load immediate binary 10100011 to r16 register
out TCCR0A, r16        ; move out the byte from r16 to TCCR0A

The full code is a little too boring for one blog - but you can find it linked here at github, and I go over it a little in the video linked below.

Now to randomise the PWM ramping up and down (flickering), the code will need some way of generating a "random" number. The simplest way is to use a basic linear feedback shift register (LFSR) algorithm as described on page 71-ish of my Attiny13A Assembler by Example booklet. 

For an 8-bit shift, I start at 0x29 (Decimal 41) and do the LSL operation (documented in this link). There is a branch then depending on the carry bit, and an XOR operation may also be performed (in this case with 0x8B). If all goes well, the algorithm produces numbers shown in green in the right hand column.

Of course - it is only "pseudo" random as the constant starting point and XOR number ensures a set pattern each time - but it'll do for our candley-goodness. You can set it to be more random by sampling a pin and using that as a starting point.

Op
Bit 7
Bit 6
Bit 5
Bit 4
Bit 3
Bit 2
Bit 1
Bit 0
Hex
Dec
start
0
0
1
0
1
0
0
1
29
41
lsl
0
1
0
1
0
0
1
0
52
82
8B
1
0
0
0
1
0
1
1
8B
139
eor
1
1
0
1
1
0
0
1
D9
217
lsl
1
0
1
1
0
0
1
0
B2
178
lsl
0
1
1
0
0
1
0
0
64
100
lsl
1
1
0
0
1
0
0
0
C8
200
8B
1
0
0
0
1
0
1
1
8B
139
eor
0
1
0
0
0
0
1
1
43
67
lsl
1
0
0
0
0
1
1
0
86
134
8B
1
0
0
0
1
0
1
1
8B
139
eor
0
0
0
0
1
1
0
1
0D
13
lsl
0
0
0
1
1
0
1
0
1A
26
8B
1
0
0
0
1
0
1
1
8B
139
eor
1
0
0
1
0
0
0
1
91
145


Then having achieved "randomness" we will have to keep track of a few numbers in order to vary the ramping.


Slow Ramping (two LEDs)
Slow Low Low - the smallest low value for the slow LED (SLL = 15)
Slow Low High - the largest low value for the slow LED (SLH = 40)
Slow High Low - the smallest high value for the slow LED (SHL = 150)
Slow High High - the largest high value for the slow LED (SHH = 220)

Fast Ramping (one LED)
Fast Low Low - the smallest low value for the fast LED (FLL = 100)
Fast Low High - the largest low value for the fast LED (FLH = 140)
Fast High Low - the smallest high value for the fast LED (FHL = 180)
Fast High High - the largest high value for the fast LED (FHH = 220)


The plan is to generate a "random number" between 0 and 255 using our LFSR, and then when it falls between the SLL and SLH we nab it for the starting slow ramp low value. Likewise for the slow ramp high value, the fast ramp low value and the fast ramp high value. 

The loop just checks where each ramp is, and when it reaches one of the limits, generates a new limit and bounces towards that number. A little delay (a time worth varying using this site) means we can see the LEDs ramp up and down with the naked eye and we have a "candle"!


Postscript: I found that with quite a few starting conditions the flicker was a little too predictable so I have altered the code to "throw a spanner" into the random generator. Basically there is now a counter (which you can set) for keeping track of how many random numbers have been generated. When the counter is exceeded, the spanner is thrown by subtracting a number (also set) from the random number before proceeding. Preliminary results are encouraging! The new code has been uploaded to github - look for the keyword "spanner".


No comments:

Post a Comment