LED fader...in Assembly

I'm back with more assembly.  This time it's a LED fader using PWM.  To do this I vary the duty cycle of the PWM signal by incrementing the length until it reaches 255 and then decrementing until it reaches 0.  This happens in an interrupt which is generated when the counter reaches TOP or 255 in the case of my settings.  So I'm kinda getting 2 in 1 with this timer,  PWM and an interrupt every cycle.  There is one side effect of updating the PWM cycle this way and that is that the fade starts off slow and then goes fast instead of remaining the consistent.  That could be solved by using another timer which is set to interrupt at the corresponding fade rate that you want.
Any way here is the code.

/*Andrew Olson
  2011
  ATtiny2313
*/
#include <avr/io.h>

#define IO_DDRB _SFR_IO_ADDR(DDRB)
#define IO_TCCR0A _SFR_IO_ADDR(TCCR0A)
#define IO_TCCR0B _SFR_IO_ADDR(TCCR0B)
#define IO_TIMSK _SFR_IO_ADDR(TIMSK)
#define IO_OCR0A _SFR_IO_ADDR(OCR0A)
 
.global TIMER0_OVF_vect
TIMER0_OVF_vect:
    sbrs r1,0                 ; skip if bit 0 set
    rjmp 2f
    dec r16                   ; decrement
    brne 3f                   ; branch if not zero
    dec r1                    ; we reached 0, so dec r1
    rjmp 3f
2:
    inc r16                   ; increment
    brvc 3f                   ; branch if overflow clear
    inc r1                    ; we reached 255, so inc r1
3:
    out IO_OCR0A, r16         ; update cycle
    reti
    
.global main
main:
    rcall init
1:
    rjmp 1b

init:
    ldi r16, (1<<COM0A1)|(1<<WGM01)|(1<<WGM00)        ; non inverting fast PWM mode
    out IO_TCCR0A, r16
    ldi r16, (1<<CS01)|(1<<CS00)                    ; /64
    out IO_TCCR0B, r16
    ldi r16, (1<<TOIE0)                                ; enable timer overflow
    out IO_TIMSK, r16
    ldi r16,0x04                                    ; OC0A(PB2) as output
    out IO_DDRB, r16
    ldi r16, 0x00
    out IO_OCR0A, r16
    clr r1
    
    sei
    ret
I had a little trouble getting to work since I forgot to set up the data direction register and I had a small bug in the fading routine.  Sorry, no video this time.  But I can tell you that it's pretty cool.  The fading of the light is like someone breathing when they are sleeping, slow and rhythmic.  Pretty relaxing to watch.

Assembly FTW!!

A while back I ordered some ATtiny 2313 microcontrollers so I could make some small projects and whatnot.  The 2313 is pretty popular with the folks over at the Evil Mad Scientist and other places.  Plus it has a bunch of nice features that will be cool to implement into my projects. 

Any way I needed a way to program the chips so I got myself a USBtinyISP from Adafruit industries.  It comes as a kit with instructions on Adafruit's website.  The build was super straight forward and was great opportunity to work on my soldering skills. When I was finished soldering it, I downloaded the drivers and plugged it into my computer and installed them with no hassle.

I never ended up using it since I got caught up with school and was playing around with my Arduino and LaunchPad instead.

I've been refreshing myself on assembly over the past week or so to help with my SNES controller to Gamecube/Wii adapter project.  I took alittle break from school work and writing that code to write a small little assembly program that I could load onto the 2313 to test out the USBtiny and if the way I am writing my assembly code is correct.  The program consisted of flashing an LED.  However I didn't write a delay that was long enough, so the LED was flashing at ~1kHz.  Codez. Sorry for the lack of comments.
#include <avr/io.h>

#define IO_PORTB _SFR_IO_ADDR(PORTB)

.global main

main:
    ldi r16,0x01
    out DDRB,r16
1:
    sbi IO_PORTB,0
    ldi r16,0xff
2:
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    dec r16
    brne 2b
    cbi IO_PORTB,0
    ldi r16,0xff
3:
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    dec r16
    brne 3b
    rjmp 1b
I used the sample Makefile that comes with WinAVR.  In order to use that Makefile you have to change some expressions so that they agree with the chip and the programmer you're using, the name of your file(s), etc.  I complied my program with avr-gcc and then loaded it onto the chip.  The LED lit up when I connected it so I'm going to hedge a guess that it worked!

I think I'll write a couple more small programs while I finished the SNES project.  For some reason I just enjoy coding in assembly.  I think its because its challenging and makes you think in a different way.

Recent Posts