# HG changeset patch # User Tero Marttila # Date 1402135533 -10800 # Node ID 1b3cea759eff4c200369534783e5bfbdcee3c2a0 # Parent c923295ee520432c38caa77ea36ac831cdc2b432 clean out non-dmx related arudino stuff diff -r c923295ee520 -r 1b3cea759eff Makefile --- a/Makefile Mon Jun 02 18:27:08 2014 +0300 +++ b/Makefile Sat Jun 07 13:05:33 2014 +0300 @@ -40,21 +40,10 @@ AS = avra ASFLAGS = -matrix.hex: spi.inc matrix.inc timer.inc delay.inc macros.inc font.inc font.def -led7seg.hex: spi.inc led7seg.inc adc.inc timer.inc delay.inc macros.inc -timer.hex: timer.inc macros.inc - %.hex: %.s $(AS) $(ASFLAGS) $< mv $<.hex $@ -# fonts -font.inc: font.def - -font.def: font.txt font-compile.py - python font-compile.py $< $@ > /dev/null - - ## Flashing # Arduino Duemilanove AD_PART = m328p diff -r c923295ee520 -r 1b3cea759eff adc.inc --- a/adc.inc Mon Jun 02 18:27:08 2014 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,68 +0,0 @@ -;; -;; Basic ADC operation -;; - -; Reference select -.set ADC_REF = 0b01 ; AVcc - -; Bit adjustment -.set ADC_LAR = 1 ; Left-adjust - -; Input select -.set ADC_MUX = 0b000 ; ADC0 - -; Auto-trigger source -.set ADC_ATS = 0b011 ; TC0 OCA - -; Auto-trigger enable -.set ADC_ATE = 1 - -; Prescaler -.set ADC_PS = 0b111 ; 1/128 - -; I/O pins -.equ ADC_DDR = DDRC -.equ ADC_PORT = PORTC -.equ ADC_PIN = PORTC0 - -;; Initialize the ADC for starting conversions -ADC_Init: - ; ADMUX - ldi r16, (ADC_REF << REFS0) | (ADC_LAR << ADLAR) | (ADC_MUX << MUX0) - sts ADMUX, r16 - - ; ADCSRB - ldi r16, (ADC_ATS << ADTS0) - sts ADCSRB, r16 - - ; ADCSRA - ; ADSC: No need if using external auto-trigger ??? - ; Enable interrupt - ldi r16, (1 << ADEN) | (1 << ADSC) | (ADC_ATE << ADATE) | (1 << ADIE) | (ADC_PS << ADPS0) - sts ADCSRA, r16 - - ; Disable digital circuit for pin - ldi r16, (1 << ADC_PIN) - sts DIDR0, r16 - - ; Done - ret - -;; Interrupt handler stub for ADC_HANDLER -ADC_Interrupt: - in r0, SREG - - rcall ADC_HANDLER - - out SREG, r0 - reti - -;; Read the current 8-bit ADC sample -; Returns value in r16 -ADC_Read8: - ; Copy - lds r16, ADCH - - ; Done - ret - diff -r c923295ee520 -r 1b3cea759eff console.s --- a/console.s Mon Jun 02 18:27:08 2014 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,270 +0,0 @@ -.nolist -.include "m168def.inc" ; Same family as 328P -.list - -.include "macros.inc" - -;; Load a 16-bit *word* address into the given register a a byte address -.macro loadp_16_i - ldi @0, high(2 * @2) - ldi @1, low(2 * @2) -.endm - -.macro load_16_i - ldi @0, high(@2) - ldi @1, low(@2) -.endm - -;; Data -.dseg -buffer: .byte 0 - -;; Interrupt Vector -.cseg -.org 0x0000 - rjmp Main - -;; Libraries -.include "div.inc" ; Division routines - -;; Serial -.set SERIAL_BAUD = 103 ; 9.6k @ 16Mhz - -;; Initialize the UART for -Serial_Init: - ; Set up control registers - ; Single-speed - poke [UCSR0A, r16, (0 << U2X0)] - - ; Async - ; n parity - ; 1 stop - ; 8 bits - poke [UCSR0C, r16, (0b00 << UMSEL00) | (0b00 << UPM00) | (0 << USBS0) | (0b11 << UCSZ00)] - - ; Baud rate - poke [UBRR0L, r16:r17, SERIAL_BAUD] - - ; Enable RX - ; Enable TX - ; 8 bits - poke [UCSR0B, r16, (1 << RXEN0) | (1 << TXEN0) | (0 << UCSZ02)] - - ; Done - ret - -;; Send a single byte on serial port -; Input byte in r16 -Serial_Send: - ; Wait for idle - lds r0, UCSR0A - sbrs r0, UDRE0 - rjmp Serial_Send - - ; Copy byte to buffer - sts UDR0, r16 - - ; Done - ret - -;; Read a single byte from serial port -; Output byte in r16 -Serial_Recv: - ; Wait for recv - lds r0, UCSR0A - sbrs r0, RXC0 - rjmp Serial_Recv - - ; Copy byte from buffer - lds r16, UDR0 - - ; Done - ret - -;; Write nul-terminated string from program mem to serial port -; Input string in Z -Serial_pprint: - ; Load byte to r16 - lpm r16, Z+ - - ; Quit if nul - tst r16 - breq _serial_pprint_end - - ; Write it - rcall Serial_Send - - ; Continue - rjmp Serial_pprint - -_serial_pprint_end: - ret - -;; Write nul-terminated string from sram and \r\n to serial port -; Input string in Z -Serial_sprintln: - ; Load byte to r16 - ld r16, Z+ - - ; Quit if nul - tst r16 - breq _serial_sprintln_end - - ; Write it - rcall Serial_Send - - ; Continue - rjmp Serial_sprintln - -_serial_sprintln_end: - ; \r\n - ldi r16, 13 - rcall Serial_Send - ldi r16, 10 - rcall Serial_Send - - ; Done - ret - -;; Write char to serial port -; Input byte in r16 -Serial_bprint: - ; ASCII offset for '0' - ldi r17, 48 - mov r4, r17 - - ; Convert - ldi r17, 100 - call div8u - add r16, r4 - rcall Serial_Send - mov r16, r15 - - ldi r17, 10 - call div8u - add r16, r4 - rcall Serial_Send - mov r16, r15 - - add r16, r4 - rcall Serial_Send - - ret - -;; Program -message: .db "Hello World", 13, 10, 0 - -Main: -; Initialization - ; Stack - poke [SPL, r16:r17, RAMEND] - - ; Enable interrupts - sei - - ; Init - rcall Serial_Init - -; Main program - ldi ZH, high(message * 2) - ldi ZL, low(message * 2) - - rcall Serial_pprint - -; Echo out - sbi DDRB, PORTB5 - ldi r20, 0 - ldi r21, 0 - ldi r22, 0 - - ; pointer to memory buffer - ldi XH, high(buffer) - ldi XL, low(buffer) - - st X, r22 ; '\0' - -Main_Echo: - ; blink LED - out PORTB, r20 - - ; read - rcall Serial_Recv - push r16 - - ; display - rcall Serial_bprint - ldi r16, 32 - rcall Serial_Send - - pop r16 - - ; test for control chars - cpi r16, 127 ; DEL - breq backspace - - cpi r16, 13 ; '\r' - breq cr - - cpi r16, 10 ; '\n' - breq Main_Echo ; ignore - - rjmp char ; buffer char - -; Erase last char -backspace: - ; ignore if already at zero - cpi XL, low(buffer) - ldi r23, high(buffer) - cpc XH, r23 - breq echo - - ; use pre-decrement to store nul - st -X, r22 ; '\0' - - rjmp echo - -; Erase line -cr: - ; seek to start - ldi XH, high(buffer) - ldi XL, low(buffer) - - ; store nul - st X, r22 ; '\0' - - rjmp echo - -char: - ; buffer char - st X+, r16 - st X, r22 ; '\0' - -echo: - ; running counter - inc r21 - mov r16, r21 - rcall Serial_bprint - - ; ' ' - ldi r16, 32 - rcall Serial_Send - - ; length - mov r16, XL - rcall Serial_bprint - - ; ' ' - ldi r16, 32 - rcall Serial_Send - - ; output buffer - ldi ZH, high(buffer) - ldi ZL, low(buffer) - rcall Serial_sprintln - - ; toggle - com r20 - - ; continue - rjmp Main_Echo - diff -r c923295ee520 -r 1b3cea759eff delay.inc --- a/delay.inc Mon Jun 02 18:27:08 2014 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,37 +0,0 @@ -;; vim: set ft=avr: -;; -;; Busy-loop delays -;; - -;; Delay for approx. one second -Delay_1s: - ; ~16M cycles - ldi r20, 82 - rjmp delay_init - -;; Delay for a variable amount of time, adjusted by r20 -; Input: r20 controls number of delay loops -VarDelay: - tst r20 - breq delay_out - -delay_init: - ldi r21, 255 - -delay_loop: - ; 254 * (1 + 2) + 1 * (1 + 1) = 764 cycles / loop - dec r22 - brne delay_loop - - ; 254 * 764 + 764 = 194820 cycles / loop - dec r21 ; 1 * r20 * r21 - brne delay_loop ; 2 * r20 * r21 - - ; r20 * 194820 + r20 * 3 = 194823 cycles / loop (r20) - dec r20 ; 1 * r20 - brne delay_loop ; 2 * r20 - -delay_out: - ret - - diff -r c923295ee520 -r 1b3cea759eff dip.inc --- a/dip.inc Mon Jun 02 18:27:08 2014 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,17 +0,0 @@ -;; -;; Reading DIP switches from SPI -;; - -.set DIP_BUFFER = spi_inbuf + 1 - -;; Read state of dip switches -;; Output: r16 -DIP_Read8: - ; update -; rcall SPI_SendRecv - - ; get bits - lds r16, DIP_BUFFER - - ret - diff -r c923295ee520 -r 1b3cea759eff div.inc --- a/div.inc Mon Jun 02 18:27:08 2014 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,41 +0,0 @@ -;*************************************************************************** -;* -;* "div8u" - 8/8 Bit Unsigned Division -;* -;* This subroutine divides the two register variables "dd8u" (dividend) and -;* "dv8u" (divisor). The result is placed in "dres8u" and the remainder in -;* "drem8u". -;* -;* Number of words :14 -;* Number of cycles :97 -;* Low registers used :1 (drem8u) -;* High registers used :3 (dres8u/dd8u,dv8u,dcnt8u) -;* -;*************************************************************************** - -;***** Subroutine Register Variables - -.def drem8u =r15 ;remainder -.def dres8u =r16 ;result -.def dd8u =r16 ;dividend -.def dv8u =r17 ;divisor -.def dcnt8u =r18 ;loop counter - -;***** Code - -div8u: sub drem8u,drem8u ;clear remainder and carry - ldi dcnt8u,9 ;init loop counter -d8u_1: rol dd8u ;shift left dividend - dec dcnt8u ;decrement counter - brne d8u_2 ;if done - ret ; return -d8u_2: rol drem8u ;shift dividend into remainder - sub drem8u,dv8u ;remainder = remainder - divisor - brcc d8u_3 ;if result negative - add drem8u,dv8u ; restore remainder - clc ; clear carry to be shifted into result - rjmp d8u_1 ;else -d8u_3: sec ; set carry to be shifted into result - rjmp d8u_1 - - diff -r c923295ee520 -r 1b3cea759eff dmx.s --- a/dmx.s Mon Jun 02 18:27:08 2014 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,264 +0,0 @@ -;;; vim: set ft=avr: - -.nolist -.include "m168def.inc" ; Same family as 328P -.list - -.include "macros.inc" - -;; Interrupt Vector -.cseg -.org 0x0000 - rjmp Main - - -;; CPU cycles / second: 16 Mhz -.set CPU_CYCLES = 16 * 1000 * 1000 - -;; Delays -.include "delay.inc" - -;; DMX baud raite: 250k -.set DMX_BAUD = 250 * 1000 - -;; CPU cycles / bit: 64 -.set DMX_CYCLES = CPU_CYCLES / DMX_BAUD - -;; DMX output I/O -.set DMX_DDR = DDRB -.set DMX_PORT = PORTB -.equ DMX_DATA = PORTB3 - -;; DMX protocol timer -; Registers -.set DMX_TIMER_CRA = TCCR2A -.set DMX_TIMER_CRB = TCCR2B -.set DMX_TIMER_CNT = TCNT2 -.set DMX_TIMER_OCRA = OCR2A -.set DMX_TIMER_OCRB = OCR2B -.set DMX_TIMER_IMSK = TIMSK2 -.set DMX_TIMER_IFR = TIFR2 - -; Compare output match isn't used -.set DMX_TIMER_COMA = 0b00 -.set DMX_TIMER_COMB = 0b00 - -; Control register, generation mode value -.set DMX_TIMER_WGM_10 = 0b10 ; CTC -.set DMX_TIMER_WGM_2 = 0b0 - -; Clock select -.set DMX_TIMER_CS_STOP = 0b000 -.set DMX_TIMER_CS = 0b001 ; 1/1 -;.set DMX_TIMER_CS = 0b111 ; 1/1024 - -; Counted value -.set DMX_TIMER_TOP = DMX_CYCLES ; number of cycles for baud - -;; Debug LED -.set LED_DDR = DDRB -.set LED_PORT = PORTB -.set LED_PIN = PINB -.set LED_BIT = PORTB0 - -;; Set up DMX output -DMX_Init: - ; Setup output port - ; out - sbi DMX_DDR, DMX_DATA - - ; drive high - sbi DMX_PORT, DMX_DATA - - ; Setup timer - ; setup CTC mode with no output pins - poke [DMX_TIMER_CRA, r16, (DMX_TIMER_COMA << COM2A0) | (DMX_TIMER_COMB << COM2B0) | (DMX_TIMER_WGM_10 << WGM20)] - poke [DMX_TIMER_CRB, r16, (DMX_TIMER_WGM_2 << WGM22) | (DMX_TIMER_CS_STOP << CS20)] - - ; trigger threshold for CTC - poke [DMX_TIMER_OCRA, r16, (DMX_TIMER_TOP)] - - ; OK - ret - -;; Start Break signal -;; -;; 22 bits - 1s long; then DMX_Break_Mark -;; -DMX_Break_Start: - ; Low - cbi DMX_PORT, DMX_DATA - - ret - -;; Start Mark-after-break signal -;; -;; 2 bits - 1s long; then DMX_Break_End -;; -DMX_Break_Mark: - ; High - sbi DMX_PORT, DMX_DATA - - ret - -;; End break; prepare for DMX_Frame -DMX_Frame_Start: - ; Start timer - poke [DMX_TIMER_CRB, r20, (DMX_TIMER_WGM_2 << WGM22) | (DMX_TIMER_CS << CS20)] - - ret - -;; Do a full DMX break, using some random length -;; -DMX_Break: - ; Break - ; start - rcall DMX_Break_Start - - ; wait; about 100ms? - ldi r20, 82 / 10 - rcall VarDelay - - ; MAB - ; mark - rcall DMX_Break_Mark - - ; short wait - ldi r20, 1 - rcall VarDelay - - ; Timed frames - ; start frame - rcall DMX_Frame_Start - - ; ok - ret - -;; Bitbang one DMX bit out -;; uses SREG/C to send -; -; Uses Timer2 as a bit sync clock, sending out the next bit once we've hit 64 cycles on the timer -DMX_Bit: - ; Wait for bit sync clock -_dmx_bit_wait: - ; test OCA hit - sbic TIFR2, OCF2A - rjmp _dmx_bit_wait - -;sbi LED_PORT, LED_BIT - - ; Output bit - ; XXX: ugly bit-testing, can't we do this using something more nifty? - brcs _dmx_bit_1 - - ; bit 0 - cbi DMX_PORT, DMX_DATA - rjmp _dmx_bit_done - -_dmx_bit_1: - ; bit 1 - sbi DMX_PORT, DMX_DATA - nop - - ; Bit sent -_dmx_bit_done: - ; reset OCA hit for next bit - cbi TIFR2, OCF2A - - ; OK, bit sync clock keeps running for next bit - ret - -;; Bitbang one DMX byte out, using DMX_Bit -;; r16: byte value -; -; Uses Timer2 as a bit sync clock; must call DMX_Frame_Start before first DMX_Frame -DMX_Frame: - ; Start bit - clc - rcall DMX_Bit - - ; Data bits: 8 - ldi r21, 8 - -_dmx_frame_loop: - ; shift + send bit - lsl r16 - rcall DMX_Bit - - ; loop - dec r21 - brne _dmx_frame_loop - - ; Stop bits - sec - rcall DMX_Bit - rcall DMX_Bit - - ; OK - ret - -;; End of DMX frames -DMX_Frame_End: - ; Keep mark from end of last frame; DMX_Break_Start starts the break - ; Stop the timer - poke [DMX_TIMER_CRB, r20, (DMX_TIMER_WGM_2 << WGM22) | (DMX_TIMER_CS_STOP << CS20)] - - ; OK - ret - -;; Send one value on all frames -;; r17: byte value -DMX_Flood: - ; Break - rcall DMX_Break - - ; Start code - ldi r16, 0 - rcall DMX_Frame - - ; Channels - ; number of channels to send - ldi r22, 100 - -_dmx_flood_channels: - ; restore channel value - mov r16, r17 - - ; send channel value - rcall DMX_Frame - - ; loop - dec r22 - brne _dmx_flood_channels - - ; End packet - rcall DMX_Frame_End - - - ret - -;; Program main -Main: -; Initialization - ; Debug - sbi LED_DDR, LED_BIT -sbi LED_PORT, LED_BIT - - ; Stack - poke [SPL, r16:r17, RAMEND] - - ; Init - rcall DMX_Init - -cbi LED_PORT, LED_BIT - - ; Send; value -_main_loop: - ldi r17, 255 - rcall DMX_Flood - -cbi LED_PORT, LED_BIT - - ; never returns.. - rjmp _main_loop - diff -r c923295ee520 -r 1b3cea759eff font-compile.py --- a/font-compile.py Mon Jun 02 18:27:08 2014 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,193 +0,0 @@ -def read_block (fh) : - """ - Yield a series of non-empty lines from the given file, ignoring any leading empty lines, and stopping after the first empty line - """ - - leading = True - - for line in fh : - if line.strip() : - leading = False - - # yield non-empty - yield line - - elif leading : - # skip leading empty - continue - - else : - # stop on empty - return - - else : - # EOF - return - -def read_charblock (lines) : - """ - Read in a char from the given lines, returning an - (ascii, rows) - - tuple, or None, if there weren't any more blocks - """ - - # the ascii code as a char - ascii = '' - - # row data as ints - rows = [] - - for line in lines : - line = line.strip() - - if line.startswith(';') : - # set ascii code - ascii = line.replace(';', '').strip() - - if not ascii : - print 'read_charblock', 'empty' - - # skip - return None - - elif len(ascii) == 1 : - print 'read_charblock', 'simplechar', ascii - - else : - ascii = ascii.decode('string_escape') - - print 'read_charblock', 'decodechar', ascii - - assert len(ascii) == 1 - - else : - # convert - row = line.replace('#', '1').replace('-', '0') - - print 'read_charblock', 'row', row - - # 6 columns - assert len(row) == 6 - - # from binary - row = int(row, 2) - - rows.append(row) - - # got data? - if ascii and rows : - # 8 rows - assert len(rows) == 8 - - return ascii, rows - - else : - # nope, empty block, EOF - return None - -def read_charblocks (fh) : - """ - Read in all char blocks as (ascii, rows) tuples from given file - """ - - while True : - out = read_charblock(read_block(fh)) - - if out : - yield out - - else : - break - -def decode_rows (inrows) : - """ - Decode char def data from its 6x8 row format into the format we need (6x8 col format) - """ - - outcols = [0x00] * 6 - - for rowidx, row in enumerate(inrows) : - - for colidx, col in enumerate(outcols) : - # get bit from row - bit = (row >> (5 - colidx)) & 1 - - # set bit into column - outcols[colidx] |= (bit << rowidx) - - # ok... - return outcols - -def write_chardef (fh, ascii, cols) : - """ - Write out character definition block to given .def file, using given char code and column data - """ - - fh.write( - ("; %r\n" % ascii) - + (".db %s\n" % (', '.join(bin(col) for col in cols))) - + ("\n") - ) - -def compile_fonts (infh, outf) : - """ - Compile char blocks from infh, writing out definitions to outf - """ - - charmap = dict() - - # decode in - for charblock in read_charblocks(infh) : - # unpack - ascii, rows = charblock - - # convert - cols = decode_rows(rows) - - # map - charmap[ascii] = cols - - print 'compile_fonts', 'read', ascii - - # detect min/max syms - syms = charmap.keys() - font_start = min(syms) - font_end = max(syms) - - assert(ord(font_start) < ord(font_end)) - - # write out - outf.write( - ";; AUTOMATICALLY GENERATED - Do not edit!\n" - ";; 8x6 font, '0' - '1', rows-by-col format\n" - + (".equ FONT_8x6_START = %d ; %r\n" % (ord(font_start), font_start)) - + (".equ FONT_8x6_END = %d ; %r\n" % (ord(font_end), font_end)) - + (".equ FONT_8x6_COLS = %d\n" % (6, )) - + (".equ FONT_8x6_ROWS = %d\n" % (8, )) - + "FONT_8x6:\n" - "\n" - ) - - # default symbol for unknown chars - defsym = charmap['\0'] - - for char in xrange(ord(font_start), ord(font_end) + 1) : - ascii = chr(char) - cols = charmap.get(ascii, defsym) - - write_chardef(outf, ascii, cols) - -def main () : - import sys, getopt - - opts, args = getopt.getopt(sys.argv[1:], '') - - inpath, outpath = args - - # run - compile_fonts(open(inpath, 'r'), open(outpath, 'w')) - -if __name__ == '__main__' : - main() - diff -r c923295ee520 -r 1b3cea759eff font.inc --- a/font.inc Mon Jun 02 18:27:08 2014 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,73 +0,0 @@ -;; Basic LED matrix fonts -;; vim: set ft=avr: - -.cseg - -;; Font definition -; Defines FONT_8x6 symbol -.include "font.def" - -; Font to use -.set FONT_TABLE = FONT_8x6 -.set FONT_START = FONT_8x6_START -.set FONT_END = FONT_8x6_END -.set FONT_COLS = FONT_8x6_COLS -.set FONT_ROWS = FONT_8x6_ROWS ; XXX: fixed to 8 - -;; Render the given ASCII char into the given buffer -; Input: r16 - ASCII char code -; Y - dest buf (Wx8 column data) -Font_Render: - ; Test char index - - ; test under-range - ldi r17, FONT_START - cp r16, r17 - brlt font_r_invalid - - ; test over-range - ldi r17, FONT_END - cp r17, r16 - brlt font_r_invalid - - ; compute offset in chars (r16) - subi r16, FONT_START - - ; ok - rjmp font_r_render - -font_r_invalid: - ; use first sym - ldi r16, 0 - - cbi PORTD, PIND7 - -font_r_render: - ; compute offset in bytes (r1:r0) - ldi r17, FONT_COLS - mul r16, r17 - - ; font table start offset from words - ldi ZL, low(FONT_TABLE * 2) - ldi ZH, high(FONT_TABLE * 2) - - ; apply offset - add ZL, r0 - adc ZH, r1 - - ; Copy column pixel data - ; count columns - ldi r16, FONT_COLS -font_r_cpy: - - ; copy via r17 - lpm r17, Z+ - st Y+, r17 - - dec r16 - brne font_r_cpy - - - ; Done - ret - diff -r c923295ee520 -r 1b3cea759eff font.txt --- a/font.txt Mon Jun 02 18:27:08 2014 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,210 +0,0 @@ -; \x00 ------- --####- --#--#- --#--#- --#--#- --#--#- --####- ------- - -; \x20 ------- ------- ------- ------- ------- ------- ------- ------- - -; ! ---##-- ---##-- ---##-- ---##-- ---##-- ------- ---##-- ---##-- - -; 0 --####- -#----# -#----# -#----# -#----# -#----# -#----# --####- - -; 1 ----#-- ---##-- --#-#-- -#--#-- ----#-- ----#-- ----#-- --##### - -; 2 ---###- --#---# --#---# -----#- ----#-- ---#--- --#---- -###### - -; 3 --###-- -#---#- ------# -----#- ----##- ------# -#---#- --###-- - -; 4 -----#- --#--#- -##--#- -#---#- -###### -----#- -----#- -----#- - -; 5 -###### -#----- -#----- -#####- ------# ------# -#----# --####- - -; 6 ------- --####- -##---# -#----- -#####- -#----# -#----# --####- - -; 7 --##### -#----# -----#- ----#-- ---#--- --#---- -#----- ------- - -; 8 ------- --####- -#----# -#----# --####- -#----# -#----# --####- - -; 9 --####- -#----# -#----# -#----# --##### ------# ------# -----#- - -; h -#----- -#----- -#----- -#----- -#-###- -##---# -#----# -#----# - -; e ---##-- --#--#- -#----# -###### -#----- -#---#- --###-- ------- - -; l ---##-- ----#-- ----#-- ----#-- ----#-- ----#-- ----#-- ---###- - -; o ------- ------- ------- --####- -#----# -#----# -#----# --####- - -; w ------- ------- ------- -#---#- -#---#- -#---#- -#-#-#- --#-#-- - -; r ------- ------- -#----- -#-##-- -##---- -#----- -#----- -#----- - -; d -----#- -----#- -----#- --####- -#---#- -#---#- -#---#- --###-- - -; ------- ------- ------- ------- ------- ------- ------- ------- - diff -r c923295ee520 -r 1b3cea759eff hw.S --- a/hw.S Mon Jun 02 18:27:08 2014 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,72 +0,0 @@ -.nolist -.include "m168def.inc" ; Same family as 328P -.list - -; Interrupt vector -.org 0x00 - rjmp main ; Reset - -.org OC1Aaddr - rjmp timer ; Timer 1 Compare A - -; Program code -main: - ; Setup pins for output - sbi DDRB, PORTB4 ; Out - sbi DDRB, PORTB5 ; Out - - ; Flags for output - ldi r16, (1 << PORTB4) - - ; Setup Timer 0 - ; Count to 64k - ldi r18, HIGH(0xffff/2) - ldi r19, LOW(0xffff/2) - sts OCR1AH, r18 - sts OCR1AL, r19 - - ; Normal port operation for both comperators - ; Bits WGM10:1 zero - ldi r18, 0x00 - sts TCCR1A, r18 - - ; CTC mode, 1/64 prescaled - ; the timer will start counting from now, but that shouldn't matter.. - ldi r18, (1 << WGM12) | (0b011 << CS10) - sts TCCR1B, r18 - - ; Enable timer interrupt - ldi r18, (1 << OCIE1A) - sts TIMSK1, r18 - - ; Setup sleep for Idle mode - ldi r18, (0b000 << SM0) | (1 << SE) - sts SMCR, r18 - - ; ...and enable interrupts - sei - -loop: - ; Flip - com r16 - - ; Output - out PORTB, r16 - - ; Wait -wait: sleep - cpi r20, 1 - brne wait - ldi r20, 0 - - ; continue - rjmp loop - -; Counter overflow handler -timer: - ; Set flag - ldi r20, 1 - - ; Re-enable interrupts - reti - diff -r c923295ee520 -r 1b3cea759eff led7seg.inc --- a/led7seg.inc Mon Jun 02 18:27:08 2014 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,152 +0,0 @@ -;; -;; Driving 7-segment LED displays over SPI -;; - -; Output Enable control -.equ LED7_DDR = DDRB -.equ LED7_PORT = PORTB -.equ LED7_OE = PORTB1 ; Output Enable (Low) - -; Font for 7-segment display -; Includes decimal digits 0-9, hexadecimal digits A-F, and some special chars -LED7_Font: -.db 0b00111111, 0b00000110 ; 0, 1 -.db 0b01011011, 0b01001111 ; 2, 3 -.db 0b01100110, 0b01101101 ; 4, 5 -.db 0b01111101, 0b00000111 ; 6, 7 -.db 0b01111111, 0b01100111 ; 8, 9 -.db 0b01110111, 0b01111100 ; A, b -.db 0b00111001, 0b01011110 ; C, d -.db 0b01111001, 0b01110001 ; E, f -.db 0b10000000, 0b00000000 ; ., - -.equ LED7_0 = 0 -.equ LED7_1 = 1 -.equ LED7_2 = 2 -.equ LED7_3 = 3 -.equ LED7_4 = 4 -.equ LED7_5 = 5 -.equ LED7_6 = 6 -.equ LED7_7 = 7 -.equ LED7_8 = 8 -.equ LED7_9 = 9 -.equ LED7_A = 10 -.equ LED7_B = 11 -.equ LED7_C = 12 -.equ LED7_D = 13 -.equ LED7_E = 14 -.equ LED7_F = 15 -.equ LED7_DOT = 16 -.equ LED7_EMPTY = 17 - -; LEDs are on beginning of SPI universe -.set led7_buffer = spi_outbuf + 0 - -;; Initialize LCD to empty, and enable -LED7_Init: - ; Setup ENable port - sbi LED7_PORT, LED7_OE ; Disabled (Low) - sbi LED7_DDR, LED7_OE ; Out - - ; Initialize buffer - ldi r16, 0b01000000 - sts led7_buffer + 0, r16 - sts led7_buffer + 1, r16 - - ; Update display - rcall SPI_SendRecv - - ; Enable output once the initial display has been shifted out - cbi LED7_PORT, LED7_OE - - ; Done - ret - -LED7_LoadChar: - clr r0, 0 - - ; Prep address - ; base addr for font table - ldi ZH, high(2 * LED7_Font) - ldi ZL, low(2 * LED7_Font) - - ; offset - add ZL, r8 - adc ZH, r0 - - ; Load char - lpm r8, Z - - ; Done - ret - -;; Display an 8-bit hexadecimal value on the display -;; Input: r16 -LED7_ShowHex: - ; base16 - ldi r17, 16 - - ; 1's - call div8u - - ; r16 = result, r15 = remainder - mov r17, r15 - - ; Continue - rjmp LED7_Show - -;; Display an 8-bit decimal value on the display -;; Input: r16 -LED7_ShowDec: - ; base10 - ldi r17, 10 - - ; 1's - call div8u - mov r8, r15 - - ; 10's - call div8u - mov r9, r16 ; 100's - - ; 1's from r8 - rcall LED7_LoadChar - mov r17, r8 - - ; 10's from r15 - mov r8, r15 - rcall LED7_LoadChar - mov r16, r8 - - ; Set dots for 100's - sbrc r9, 0 - ori r17, 0b10000000 ; +100 - sbrc r9, 1 - ori r16, 0b10000000 ; +200 - - ; Continue - rjmp LED7_ShowRaw - -;; Display a single digit on the display -;; Input: r16, r17 -LED7_Show: - mov r8, r16 - rcall LED7_LoadChar - mov r16, r8 - - mov r8, r17 - rcall LED7_LoadChar - mov r17, r8 - - ;; Continue - -;; Display a raw segment mask -;; Input: r16, r17 -LED7_ShowRaw: - ; Store buffer - sts led7_buffer + 0, r16 - sts led7_buffer + 1, r17 - - ; Update display - rjmp SPI_Update - diff -r c923295ee520 -r 1b3cea759eff led7seg.s --- a/led7seg.s Mon Jun 02 18:27:08 2014 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,246 +0,0 @@ -.nolist -.include "m168def.inc" ; Same family as 328P -.list - - -;; Interrupt Vector -.org 0x00 - rjmp init - -.org OC1Aaddr - ; Timer/Counter1 Compare Output A - rjmp Timer_OC1A - -.org OC0Aaddr - ; Timer/Counter0 Compare Output A - rjmp Timer_OC0A - -.org SPIaddr - rjmp SPI_Interrupt - -.org ADCCaddr - rjmp ADC_Interrupt - -.org 0x40 - -;; Syntax -.include "macros.inc" - -;; SPI -.include "spi.inc" - -;; LCD -.include "led7seg.inc" - -;; DIPs -.include "dip.inc" - -;; ADC - -; ADC Interrupt handler -On_ADC: - ; DEBUG - sbi PIND, PORTD7 - - ; Check timer, from r16 - rcall ADC_Read8 - - ldi r17, 64 - mul r16, r17 - mov XL, r0 - mov XH, r1 - - rjmp Timer_Update - -.set ADC_Handler = On_ADC - -.include "adc.inc" - -;; Timer -.set TIMER0_CB_A = SPI_Update - -.include "timer.inc" - -;; Utils -.include "delay.inc" -.include "div.inc" - -Sleep_ADC: - ; delay - rcall ADC_Read8 - ; rcall DIP_Read8 - - ; Sleep for 64 * var timer cycles - ldi r17, 64 - mul r16, r17 - mov XL, r0 - mov XH, r1 - - rjmp Timer_Sleep - -;; Show value -Main_ShowValue: - ; load value to r16 - ; rcall DIP_Read8 - rcall ADC_Read8 - ; rcall Timer0_Read8 - - ; display from r16 - rcall LED7_ShowHex - - ; wait - rcall Sleep_ADC - - ; ldi XL, 0 - ; ldi XH, 16 - ; rcall Timer_Sleep - - ; rcall ADC_Read8 - ; mov r20, r16 - ; rcall VarDelay - - ; continue - rjmp Main_ShowValue - -;; Count down from F -; Returns once we've hit zero -Main_Countdown: - ; init from F - ldi r24, LED7_F - -_count_loop: - ; display - mov r16, r24 - mov r16, r24 - rcall LED7_Show - - ; exit if zero - tst r24 - breq _count_end - - ; count down - dec r24 - - ; wait... - rcall Sleep_ADC - - ; next - rjmp _count_loop - -_count_end: - ; done - ret - -;; Count up from 00 -> 255 -; Returns once done -Main_CountUp: - ; init from 0 - ldi r24, 0 - -_countup_loop: - ; display - mov r16, r24 - rcall LED7_ShowDec - - ; wait... - rcall Sleep_ADC - - ; exit if zero - cpi r24, 255 - breq _countup_end - - ; count up - inc r24 - - ; continue - rjmp _countup_loop - -_countup_end: - ; done - ret - -;; Blink between dot and empty -Main_Blink: -_blink_loop: - ; dot - ldi r16, LED7_DOT - ldi r17, LED7_EMPTY - rcall LED7_Show - - ; wait... - rcall Sleep_ADC - - ; empty - ldi r16, LED7_EMPTY - ldi r17, LED7_DOT - rcall LED7_Show - - ; wait... - rcall Sleep_ADC - - ; loop - rjmp _blink_loop - -;; Chase segments -Main_Spin: -_spin_init: - ; init from top - ldi r24, 0b00000001 - -_spin_next: - ; display - mov r16, r24 - mov r17, r24 - com r17 - andi r17, 0b00111111 - rcall LED7_ShowRaw - - ; delay - rcall Sleep_ADC - - ; next segment - lsl r24 - - ; go back to A if we hit G - sbrc r24, 6 - rjmp _spin_init - - rjmp _spin_next - -Main: -init: - ; Stack - ldi r16, high(RAMEND) - ldi r17, low(RAMEND) - out SPH, r16 - out SPL, r17 - - ; Enable interrupts - sei - - ; ADC (slowest to start up) - rcall ADC_Init - - ; Timer - rcall Timer_Init - - ; SPI - rcall SPI_Init - - ; LCD (requires interrupts, blocks) - rcall LED7_Init - - ; DEBUG - sbi DDRD, PORTD7 - cbi PORTD, PORTD7 - - ; Run - rcall Main_Countup - ; rcall Main_Countdown - ; rcall Main_ShowValue - ; rcall Main_Spin - rcall Main_Blink - -end: - rjmp end - diff -r c923295ee520 -r 1b3cea759eff m168def.inc --- a/m168def.inc Mon Jun 02 18:27:08 2014 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,958 +0,0 @@ -;***** THIS IS A MACHINE GENERATED FILE - DO NOT EDIT ******************** -;***** Created: 2005-01-11 10:30 ******* Source: ATmega168.xml *********** -;************************************************************************* -;* A P P L I C A T I O N N O T E F O R T H E A V R F A M I L Y -;* -;* Number : AVR000 -;* File Name : "m168def.inc" -;* Title : Register/Bit Definitions for the ATmega168 -;* Date : 2005-01-11 -;* Version : 2.14 -;* Support E-mail : avr@atmel.com -;* Target MCU : ATmega168 -;* -;* DESCRIPTION -;* When including this file in the assembly program file, all I/O register -;* names and I/O register bit names appearing in the data book can be used. -;* In addition, the six registers forming the three data pointers X, Y and -;* Z have been assigned names XL - ZH. Highest RAM address for Internal -;* SRAM is also defined -;* -;* The Register names are represented by their hexadecimal address. -;* -;* The Register Bit names are represented by their bit number (0-7). -;* -;* Please observe the difference in using the bit names with instructions -;* such as "sbr"/"cbr" (set/clear bit in register) and "sbrs"/"sbrc" -;* (skip if bit in register set/cleared). The following example illustrates -;* this: -;* -;* in r16,PORTB ;read PORTB latch -;* sbr r16,(1< 8 rows) -matrix_colbuf: .byte MATRIX_BUF_COLS ; framebuffer (row data by column) - -; Column scan bit -; in the matrix refresh loop, we push out each column's row data in turn -; this bit tracks the currently refreshing column -matrix_colbit: .byte 1 ; column scan bit - -; Matrix viewport offset -; the visible matrix data is taken directly from the framebuffer, but it can be taken at an arbitrary offset -; this determines the starting offset for the visible viewport's left edge from the start of the framebuffer in columns -matrix_colshift: .byte 1 ; viewport left column offset - -;; Text -; Maximum length of message -.set TEXT_MAXLENGTH = 64 - -; Scrolling speed (kiloticks per frame) -.set TEXT_SPEED = 1 - -text_buffer: .byte TEXT_MAXLENGTH ; display message buffer -text_offset: .byte 1 ; current offset in text - -.cseg - -;; Normalize the outputs, enable the matrix, and set up buffers -Matrix_Init: - ; Setup ENable port - sbi MATRIX_PORT, MATRIX_OE ; high -> disabled - sbi MATRIX_DDR, MATRIX_OE ; out - - ; blank hardware - ldi r16, 0 - - sts spi_outbuf + 0, r16 ; column sinks - sts spi_outbuf + 1, r16 ; row drivers - - ; write out - rcall SPI_SendRecv - - ; enable - cbi MATRIX_PORT, MATRIX_OE ; low -> enabled - - ; init buffers - ldi r16, 0b1 - sts matrix_colbit, r16 - - ldi r16, 0 - sts matrix_colshift, r16 - - ldi r16, 0 - ldi r17, MATRIX_BUF_COLS - ldi YL, low(matrix_colbuf) - ldi YH, high(matrix_colbuf) - -m_init_mzero: - st Y+, r16 - - ; loop until zero - dec r17 - brne m_init_mzero - - ; Use Timer0, 32k cycles -> 500Hz scan rate - ldi r16, 32 - rcall Timer0_Start - - ; done - ret - -;; Scan the matrix's next column from the viewport -;; Interrupt-driven -Matrix_ScanCol: - ; Save registers - push r16 - push r17 - - ; Column bit - ; load - lds r16, matrix_colbit - - ; start packet - cbi SPI_PORT, SPI_SS - - ; output single column-enable bit - out SPDR, r16 - - ; Compute col index - ldi r17, 0 - -m_sc_colidx: - ; shift - lsr r16 - - ; done if we shifted the bit out - brcs m_sc_row - - ; count shifts - inc r17 - rjmp m_sc_colidx - -m_sc_row: - ; Column shift - ; load - lds r16, matrix_colshift - - ; add to col index - add r17, r16 - - ; Row mask - ; base - ldi XL, low(matrix_colbuf) - ldi XH, high(matrix_colbuf) - - ; offset - ldi r16, 0 - - add XL, r17 - adc XH, r16 - - ; load - ld r16, X - - ; output full row-enable bitmask - rcall SPI_Wait - out SPDR, r16 - - ; Update col bit - lds r16, matrix_colbit - - ; shift left - lsl r16 - brcc m_sc_colout - - ; overflow, take bit from C - rol r16 - -m_sc_colout: - ; store - sts matrix_colbit, r16 - - ; End of packet - rcall SPI_Wait - sbi SPI_PORT, SPI_SS - - ; Done - pop r17 - pop r16 - - ret - -;; Scan the matrix once in one go -;; XXX: doesn't support colshift -Matrix_ScanFull: - ; Row index - ldi ZL, low(matrix_colbuf) - ldi ZH, high(matrix_colbuf) - - ; Column bit - ldi r25, 0 - sec ; set C - -m_pulse_col: - ; rotate bit left from C - rol r25 - - ; overflow - brcs m_pulse_end - - ; store in output buffer - sts spi_outbuf + 1, r25 - - ; Row mask - ld r16, Z+ - - sts spi_outbuf + 0, r16 - - ; Display - rcall SPI_SendRecv - - ; Next column - rjmp m_pulse_col - -m_pulse_end: - ; Done - ret - -;; Reset the viewport to the start (left edge) of the framebuffer -Matrix_ShiftZero: - ; Constant offset - ldi r16, 0 - - ; Set - rjmp Matrix_ShiftSet - -;; Shift the viewport one column to the left in the framebuffer, looping around to the end of the framebuffer -; This moves the visible output one column to the right -Matrix_ShiftLeft: - ; Decrement-loop current value - ; current value - lds r16, matrix_colshift - - ; shift window left - dec r16 - - ; test for underflow (MSB/N set) -> don't skip reset - brpl Matrix_ShiftSet - - ; reset window to right edge - ldi r16, MATRIX_BUF_COLS - MATRIX_COLS - - ; Set - rjmp Matrix_ShiftSet - -;; Shift the viewport one column to the right in the framebuffer, looping around to the start of the FB -; This moves the visible output one column to the left -Matrix_ShiftRight: - ; Increment-loop current value - ; current value - lds r16, matrix_colshift - - ; shift window right - inc r16 - - ; test for overflow -> don't skip reset - cpi r16, MATRIX_BUF_COLS - MATRIX_COLS - brlt Matrix_ShiftSet - - ; reset window to left edge - ldi r16, 0 - - ; Set - rjmp Matrix_ShiftSet - -;; Set the matrix viewport offset -;; Input: r16 -Matrix_ShiftSet: - ; store new value - sts matrix_colshift, r16 - - ; done - ret - -;; Rewinds the currently visible viewport to the beginning of the framebuffer -; This copies the currently visible viewport data to the beginning of the framebuffer and resets the offset -Matrix_ShiftRewind: - ; current view offset - ldi XL, low(matrix_colbuf) - ldi XH, high(matrix_colbuf) - - ; offset - lds r16, matrix_colshift - - ; add - ldi r17, 0 - add XL, r16 - adc XH, r17 - - ; start of framebuffer - ldi YL, low(matrix_colbuf + 0) - ldi YH, high(matrix_colbuf + 0) - - ; viewport width - ldi r17, MATRIX_COLS - -matrix_shiftrew_loop: - ; copy - ld r16, X+ - st Y+, r16 - - ; count - dec r17 - brne matrix_shiftrew_loop - - ; done, reset offset - rjmp MAtrix_ShiftZero - - -;; Load a NUL-terminated ASCII string from PGM into the text buffer -; Input: Z - Address of NUL-terminated ASCII string in PGM -Text_LoadString: - ; Setup - ; storage buffer - ldi YL, low(text_buffer) - ldi YH, high(text_buffer) - - ; max. length - ldi r18, TEXT_MAXLENGTH - -text_loads_loop: - ; Test max length - ; count and check for overflow - dec r18 - brne text_loads_char - - ; Load char - ; force NUL - ldi r16, 0x00 - -text_loads_char: - ; load next char - lpm r16, Z+ - -text_loads_store: - ; Store and test NUL - ; store it - st Y+, r16 - - ; test for NUL - tst r16 - brne text_loads_loop - - ; Update scroll offset - ; reset offset - ldi r17, 0 - sts text_offset, r17 - - ; done - ret - -;; Shows the loaded string of ASCII text on the display, scrolling it horizontally -; Uses font.inc for rendering -; XXX: uses blocking timer sleeps and doesn't return until done -Text_ShowString: - ; Load initial char - ldi XL, low(text_buffer + 0) - ldi XH, high(text_buffer + 0) - - ; load char - ld r16, X+ - push XL - push XH - - ; one column spacing - ldi YL, low(matrix_colbuf + 1) - ldi YH, high(matrix_colbuf + 1) - - ; render to framebuffer - rcall Font_Render - - ; reset viewport - rcall Matrix_ShiftZero - - ; Load next char -text_shows_next: - ; next char - pop XH - pop XL - ld r16, X+ - push XL - push XH - - ; test NUL - tst r16 - breq text_shows_end - - ; offscreen - ldi YL, low(matrix_colbuf + 1 + 6 + 1) - ldi YH, high(matrix_colbuf + 1 + 6 + 1) - - ; render - rcall Font_Render - - ; Animate to next char - ldi r20, 7 - -text_shows_animloop: - ; sleep - ldi XH, high(TEXT_SPEED * 1024) - ldi XL, low(TEXT_SPEED * 1024) - - rcall Timer_Sleep - - ; shift - rcall Matrix_ShiftRight - - ; count - dec r20 - brne text_shows_animloop - - ; Rewind to next char - rcall Matrix_ShiftRewind - - sbi PIND, PIND7 - - ; load next char and animate it in - rjmp text_shows_next - -text_shows_end: - ; Done - pop XH - pop XL - - - ; Clear second frame - ldi YL, low(matrix_colbuf + 16) - ldi YH, high(matrix_colbuf + 16) - ldi r16, MATRIX_COLS - ldi r17, 0 - -text_shows_end2: - st -Y, r17 - - dec r16 - brne text_shows_end2 - - ; Blink -text_shows_end3: - ; on - ldi r16, 0 - rcall Matrix_ShiftSet - - ; sleep - ldi XH, high(TEXT_SPEED * 6 * 1024) - ldi XL, low(TEXT_SPEED * 6 * 1024) - - rcall Timer_Sleep - - ; off - ldi r16, 8 - rcall Matrix_ShiftSet - - ; sleep - ldi XH, high(TEXT_SPEED * 6 * 1024) - ldi XL, low(TEXT_SPEED * 6 * 1024) - - rcall Timer_Sleep - - ; loop - rjmp text_shows_end3 - - ; XXX: end - ret - diff -r c923295ee520 -r 1b3cea759eff matrix.s --- a/matrix.s Mon Jun 02 18:27:08 2014 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,255 +0,0 @@ -;; vim: set ft=avr: - -.nolist -.include "m168def.inc" ; Same family as 328P -.list - - -;; Interrupt Vector -.org 0x00 - rjmp init - -.org OC1Aaddr - ; Timer/Counter1 Compare Output A - rjmp Timer_OC1A - -.org OC0Aaddr - ; Timer/Counter0 Compare Output A - rjmp Timer_OC0A - -.org SPIaddr - rjmp SPI_Interrupt - - -cseg0: .org 0x40 - -;; Syntax -.include "macros.inc" - -;; SPI -.include "spi.inc" - -;; Matrix -.include "matrix.inc" - -;; Timer -.set TIMER0_CB_A = Matrix_ScanCol - -.include "timer.inc" - -;; Utils -.include "delay.inc" - -;; Font rendering -.include "font.inc" - -;; Scan through each pixel -Main_ScanRaw: - ; init - ldi r18, 1 - ldi r19, 1 - -scan_loop: - ; write out to SPI - sts spi_outbuf + 0, r18 ; rows - sts spi_outbuf + 1, r19 ; columns - - rcall SPI_SendRecv - - ; delay - ldi r20, 5 ; ~4M cycles - rcall VarDelay - - ; cols - lsl r19 ; next col - brcc scan_loop ; refresh if we didn't overflow - - rol r19 ; shift back from C into r21.0 - - ; rows - lsl r18 ; next row - brcc scan_loop ; refresh if we didn't overflow - - rol r18 ; shift back from C into r20.0 - - ; one scan completed - ret - -;; Scan with test pattern -Main_ScanTest: - ; Generate pattern - ; end of buffer - ldi r17, MATRIX_BUF_COLS - ldi XL, low(matrix_colbuf + MATRIX_BUF_COLS) - ldi XH, high(matrix_colbuf + MATRIX_BUF_COLS) - - ; bit pattern - ldi r16, 0b11 - -st_loop: - ; put, pre-decrement - st -X, r16 - - ; flip - rol r16 - - ; loop until zero - dec r17 - brne st_loop - -st_animate: - ; Animate - ; shift right - rcall Matrix_ShiftLeft - - ; wait for X/16th of a second - ldi XH, high(8 * 1024) - ldi XL, low(8 * 1024) - - rcall Timer_Sleep - - ; loop - rjmp st_animate - - -;; Display device code memory -Main_ScanCode: - ; Code start - ldi ZL, low(cseg0 * 2) ; word addr - ldi ZH, high(cseg0 * 2) ; word addr - - ; Pause refresh - cli - - ; Load initial frame - ; to first frame, starting from right edge - ldi r17, 8 - ldi XL, low(matrix_colbuf + 16) - ldi XH, high(matrix_colbuf + 16) - -sc_load_initial: - ; one byte - lpm r16, Z+ - st -X, r16 - - ; loop until zero - dec r17 - brne sc_load_initial - - ; the first ShiftLeft below will jump to the end of the framebuffer - -sc_next: - ; Show this frame - rcall Matrix_ShiftLeft - - ; Load next frame - ldi r17, 8 - ldi XL, low(matrix_colbuf + 8) - ldi XH, high(matrix_colbuf + 8) - -sc_load_next: - ; one byte - lpm r16, Z+ - st -X, r16 - - ; loop until zero - dec r17 - brne sc_load_next - - ; Enable refresh - sei - - ; Animate from this -> next frame - ldi r17, 8 ; 8 columns - -sc_anim: - ; wait for X/16th of a second - ldi XH, high(2 * 1024) - ldi XL, low(2 * 1024) - - rcall Timer_Sleep - - ; shift - rcall Matrix_ShiftLeft - - ; loop until zero - dec r17 - brne sc_anim - - ; Pause refresh - cli - - ; Move next -> this - ldi r17, 8 - ldi XL, low(matrix_colbuf + 16) - ldi XH, high(matrix_colbuf + 16) - ldi YL, low(matrix_colbuf + 8) - ldi YH, high(matrix_colbuf + 8) - -sc_move_this: - ; one byte - ld r16, -Y - st -X, r16 - - ; loop until zero - dec r17 - brne sc_move_this - -sbi PIND, PIND7 - - ; Load next frame, and animate - rjmp sc_next - -Main_ScanText: - - ; Constants -stxt_message: ; text to render - .db 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x21, 0x0 ; 'hello world!' - - ; Load into buffer - ldi ZL, low(stxt_message * 2) - ldi ZH, high(stxt_message * 2) - - rcall Text_LoadString - -sbi PORTD, PIND7 - - ; Display - rcall Text_ShowString - - ; Done - ret - -Main: -init: - ; Stack - ldi r16, high(RAMEND) - ldi r17, low(RAMEND) - out SPH, r16 - out SPL, r17 - - ; Enable interrupts - sei - -; DEBUG -sbi DDRD, PORTD7 -cbi PORTD, PORTD7 - - ; Timer - rcall Timer_Init - - ; SPI - rcall SPI_Init - - ; Matrix - rcall Matrix_Init - - ; Run - ; rcall Main_ScanRaw - ; rcall Main_ScanTest - ; rcall Main_ScanCode - rcall Main_ScanText - -end: - rjmp end - diff -r c923295ee520 -r 1b3cea759eff spi.inc --- a/spi.inc Mon Jun 02 18:27:08 2014 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,144 +0,0 @@ -;; vim: filetype=avr -;; -;; SPI interface control and use -;; - -;; I/O Port -.equ SPI_DDR = DDRB -.equ SPI_PORT = PORTB -.equ SPI_SCK = PORTB5 -.equ SPI_MISO = PORTB4 -.equ SPI_MOSI = PORTB3 -.equ SPI_SS = PORTB2 - -;; Internal status flags -.equ SPI_FLAGS = GPIOR0 -.equ SPI_BUSY = 0 - -;; Settings -.set SPI_DORD = 0 ; word order -.set SPI_CPOL = 0 ; clock polarity -.set SPI_CPHA = 0 ; clock phase -.set SPI_CLOCK = 0b01 ; clock speed - -;; Internal state -; Number of in/out bytes -.set SPI_BUFLEN = 2 - -.dseg -; Buffer for incoming frames -spi_inbuf: .byte SPI_BUFLEN - -; Buffer for outgoing frames -spi_outbuf: .byte SPI_BUFLEN - -.cseg - -;; Initialize SPI subsystem for master operation -SPI_Init: - ; Set modes - sbi SPI_DDR, SPI_SCK ; Out - sbi SPI_DDR, SPI_MOSI ; Out - sbi SPI_DDR, SPI_SS ; Out - - ; Drive SS high (off) - sbi SPI_PORT, SPI_SS - - ; Set control mode - ; XXX: Enable interrupt - ; Enable SPI - ; MSB first - ; Master mode - ; Polarity/phase: Mode 0 (sample on rising edge) - ; Clock rate 1/16 - ldi r16, (0 << SPIE) | (1 << SPE) | (SPI_DORD << DORD) | (1 << MSTR) | (SPI_CPOL << CPOL) | (SPI_CPHA << CPHA) | (SPI_CLOCK << SPR0) - out SPCR, r16 - - ; Flags - clr r0 - out SPI_FLAGS, r0 - - ; Start update timer - ; XXX: also used for ADC -; ldi r16, 64 ; every 64k cycles -; rcall Timer0_Start - - ; Done - ret - -;; Triggered by Timer0, updates the spi_bufs -;; Run from timer interrupt context -SPI_Update: - ; skip if updating - sbic SPI_FLAGS, SPI_BUSY - ret - - ;; Continue - ; XXX: blocks too much? - -;; Send/Recv from/to SPI buffers -SPI_SendRecv: - ; Flag - sbi SPI_FLAGS, SPI_BUSY - - ; Start of packet - cbi SPI_PORT, SPI_SS - - ; Init buffers - ldi r16, SPI_BUFLEN - - ; send/recv in reverse order - ldi XL, low(spi_inbuf + SPI_BUFLEN) - ldi XH, high(spi_inbuf + SPI_BUFLEN) - ldi YL, low(spi_outbuf + SPI_BUFLEN) - ldi YH, high(spi_outbuf + SPI_BUFLEN) - - ; Write -spi_sr_next: - ; load+send tail byte - ld r1, -Y - out SPDR, r1 - - ; Wait -spi_sr_wait: - in r1, SPSR - sbrs r1, SPIF - rjmp spi_sr_wait - - ; Read - ; XXX: wrong, should be head byte? - ; read+store tail byte - in r1, SPDR - st -X, r1 - - ; Done? - dec r16 - brne spi_sr_next ; if nonzero - - ; End of packet - sbi SPI_PORT, SPI_SS - - cbi SPI_FLAGS, SPI_BUSY - - ; Done - ret - -;; Wait for SPI to be ready for send -SPI_Wait: - ; Test - in r1, SPSR - sbrs r1, SPIF - rjmp SPI_Wait - - ; Read SPDR to clear SPIF - in r10, SPDR - - ; Done - ret - -;; Service SPI interrupt -SPI_Interrupt: - ; XXX: disabled - reti - - diff -r c923295ee520 -r 1b3cea759eff src/hello-lkm.c --- a/src/hello-lkm.c Mon Jun 02 18:27:08 2014 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,484 +0,0 @@ -/* - * Control the JY-LKM1638 LED display module. - */ - -#include -#include - -#include "stdlib.h" - -// XXX -#include "timer.c" - -#define LKM_DDR DDRC -#define LKM_PORT PORTC -#define LKM_PIN PINC -#define LKM_CLK 0 -#define LKM_DIO 1 -#define LKM_STB 2 - -enum lkm_cmd { - LKM_CMD_DATA = 0b01000000, - LKM_CMD_CONTROL = 0b10000000, - LKM_CMD_ADDRESS = 0b11000000, - - LKM_DATA_WRITE = 0b00000000, - LKM_DATA_READ = 0b00000010, - - LKM_DATA_ADDR_AUTO = 0b00000000, - LKM_DATA_ADDR_FIXED = 0b00000100, - - LKM_DATA_TEST_NORMAL = 0b00000000, - LKM_DATA_TEST_TEST = 0b00001000, - - LKM_ADDRESS = 0b00001111, - - LKM_CONTROL_INTENSITY = 0b00000111, - LKM_CONTROL_INTENSITY_MIN = 0b00000000, - LKM_CONTROL_INTENSITY_MAX = 0b00000111, - - LKM_CONTROL_DISPLAY_OFF = 0b00000000, - LKM_CONTROL_DISPLAY_ON = 0b00001000, -}; - -static const uint8_t LKM_DISPLAY_FONT[] = { - 0b00111111, // 0 - 0b00000110, // 1 - 0b01011011, // 2 - 0b01001111, // 3 - 0b01100110, // 4 - 0b01101101, // 5 - 0b01111101, // 6 - 0b00000111, // 7 - 0b01111111, // 8 - 0b01100111, // 9 - 0b01110111, // A - 0b01111100, // B - 0b00111001, // C - 0b01011110, // D - 0b01111001, // E - 0b01110001, // F -}; - -enum { - LKM_DISPLAY_DECIMAL = 0b10000000, -}; - -/* - * XXX: RED/GREEN somehow swapped vs reference; bug in our write code? - */ -enum { - LKM_LED_OFF = 0b00, - LKM_LED_GREEN = 0b01, - LKM_LED_RED = 0b10, - LKM_LED_ORANGE = 0b11, -}; - -/* - * Button bitfields. - * - * The JY-LKM1638 uses K3 - */ -enum { - LKM_BUTTON_K1L = 0b00000100, - LKM_BUTTON_K2L = 0b00000010, - LKM_BUTTON_K3L = 0b00000001, - - LKM_BUTTON_K1H = 0b01000000, - LKM_BUTTON_K2H = 0b00100000, - LKM_BUTTON_K3H = 0b00010000, -}; - -void lkm_init () -{ - // strobe off: high output - // XXX: should use an external pull-up resistor? - sbi(&LKM_PORT, LKM_STB); - sbi(&LKM_DDR, LKM_STB); - - // clock low - sbi(&LKM_DDR, LKM_CLK); - cbi(&LKM_PORT, LKM_CLK); - - // data tri-state - cbi(&LKM_DDR, LKM_DIO); - cbi(&LKM_DDR, LKM_DIO); -} - -/* - * Select the LKM for write. - */ -void lkm_out () -{ - // clock low - cbi(&LKM_PORT, LKM_CLK); - - // data out - sbi(&LKM_DDR, LKM_DIO); - - // select on: low - cbi(&LKM_PORT, LKM_STB); -} - -/* - * Select the LKM for read. - */ -void lkm_in () -{ - // data in - cbi(&LKM_DDR, LKM_DIO); - cbi(&LKM_PORT, LKM_DIO); - - // select on: low - cbi(&LKM_PORT, LKM_STB); - - // clock high - sbi(&LKM_PORT, LKM_CLK); - - // pause - _delay_us(1); -} - -/* - * Write out one byte - */ -void lkm_write (byte b) -{ - char i; - - for (i = 0; i < 8; i++) { - // clock read: low - cbi(&LKM_PORT, LKM_CLK); - - // set output - if (b & 1) - sbi(&LKM_PORT, LKM_DIO); - else - cbi(&LKM_PORT, LKM_DIO); - - // clock write: high - sbi(&LKM_PORT, LKM_CLK); - - // next bit - b >>= 1; - } -} - -/* - * Read in one byte. - */ -byte lkm_read () -{ - byte b = 0; - char i; - - // XXX: this loop is timing-critical; we must allow the signal to settle betwen clocks - for (i = 0; i < 8; i++) { - // next bit - b >>= 1; - - // clock read: low - cbi(&LKM_PORT, LKM_CLK); - - // pause - _delay_us(1); - - // read input - if (tbi(&LKM_PIN, LKM_DIO)) - b |= 0x80; - - // pause - _delay_us(1); - - // clock write: high - sbi(&LKM_PORT, LKM_CLK); - - // pause - _delay_us(1); - } - - return b; -} - -/* - * End command. - */ -void lkm_end () -{ - // select off: high - sbi(&LKM_PORT, LKM_STB); - - // tristate data - cbi(&LKM_DDR, LKM_DIO); -} - -void lkm_cmd (byte cmd) -{ - lkm_out(); - lkm_write(cmd); - lkm_end(); -} - -void lkm_cmd1 (byte cmd, byte arg) -{ - lkm_out(); - lkm_write(cmd); - lkm_write(arg); - lkm_end(); -} - -static inline void lkm_control (byte display, byte intensity) -{ - lkm_cmd(LKM_CMD_CONTROL - | (display ? LKM_CONTROL_DISPLAY_ON : LKM_CONTROL_DISPLAY_OFF) - | (intensity & LKM_CONTROL_INTENSITY) - ); -} - -/* - * Blank display/LEDs - */ -static void lkm_clear () -{ - char i; - - lkm_cmd(LKM_CMD_DATA - | LKM_DATA_TEST_NORMAL - | LKM_DATA_ADDR_AUTO - | LKM_DATA_WRITE - ); - - // write out all 16 bytes of 0x00 - lkm_out(); - lkm_write(LKM_CMD_ADDRESS | (0x0) & LKM_ADDRESS); - for (i = 0; i < 16; i++) { - lkm_write(0x00); - } - lkm_end(); - -} - -/* - * Set raw output mask for given display 0..7 - */ -static inline void lkm_display (byte display, byte value) -{ - lkm_cmd(LKM_CMD_DATA - | LKM_DATA_TEST_NORMAL - | LKM_DATA_ADDR_AUTO - | LKM_DATA_WRITE - ); - lkm_cmd1(LKM_CMD_ADDRESS | ((display * 2 + 0) & LKM_ADDRESS), - value - ); -} - -/* - * Set raw output mask for given led 0..7 - */ -static inline void lkm_led (byte led, byte value) -{ - lkm_cmd(LKM_CMD_DATA - | LKM_DATA_TEST_NORMAL - | LKM_DATA_ADDR_AUTO - | LKM_DATA_WRITE - ); - lkm_cmd1(LKM_CMD_ADDRESS | ((led * 2 + 1) & LKM_ADDRESS), - value - ); -} - -/* - * Set 4-bit hexadecimal output for given display 0..7 - */ -static inline void lkm_display_hex (byte display, byte hex) -{ - lkm_display(display, LKM_DISPLAY_FONT[hex]); -} - -static inline void lkm_display_dec (byte display, byte dec, byte decimal) -{ - byte raw; - - if (dec < 10) - raw = LKM_DISPLAY_FONT[dec]; - else - raw = 0x00; - - if (decimal) - raw |= LKM_DISPLAY_DECIMAL; - - lkm_display(display, raw); -} - -/* - * Read the 8-bit key states - */ -byte lkm_buttons () -{ - byte k3 = 0; - char i; - - lkm_out(); - lkm_write(LKM_CMD_DATA - | LKM_DATA_TEST_NORMAL - | LKM_DATA_ADDR_AUTO - | LKM_DATA_READ - ); - lkm_in(); - for (i = 0; i < 4; i++) { - /* - * The ordering of keys used is weird; it seems to go 04 15 26 37 - */ - k3 |= lkm_read() << i; - - /* - k3 >>= 1; - - byte b = lkm_read(); - - if (b & LKM_BUTTON_K3L) - k3 |= 0b00001000; - - if (b & LKM_BUTTON_K3H) - k3 |= 0b10000000; - */ - } - lkm_end(); - - return k3; -} - -/* - * Set 8-bit hexadecimal output on displays n..n+1 - */ -void lkm_display_hh (byte display, byte hex) -{ - lkm_display_hex(display + 0, ((hex >> 4) & 0xF)); - lkm_display_hex(display + 1, ((hex >> 0) & 0xF)); -} - -/* - * Set 16-bit hexadecimal output on displays 4..7 - */ -void lkm_display_hhhh (short hex) -{ - lkm_display_hex(7, ((hex >> 0) & 0xF)); - lkm_display_hex(6, ((hex >> 4) & 0xF)); - lkm_display_hex(5, ((hex >> 8) & 0xF)); - lkm_display_hex(4, ((hex >> 12) & 0xF)); -} - -/* - * Set 2-digit decimal output on displays n..n+1 - */ -void lkm_display_dd (byte display, byte dec) -{ - byte d = dec / 10; - byte u = dec % 10; - - byte c = d / 10; - d = d % 10; - - lkm_display_dec(display + 0, d, c > 1); - lkm_display_dec(display + 1, u, c > 0); -} - -// debug -#define DEBUG_DDR DDRB -#define DEBUG_PORT PORTB -#define DEBUG_LED 0 - -int main (void) -{ - // led_init(); - sbi(&DEBUG_DDR, DEBUG_LED); - - timer_init(); - lkm_init(); - - sei(); - - // setup display - lkm_clear(); - lkm_control(LKM_CONTROL_DISPLAY_ON, LKM_CONTROL_INTENSITY_MAX); - -/* - // test - lkm_led(0, LKM_LED_OFF); - lkm_led(1, LKM_LED_RED); - lkm_led(2, LKM_LED_GREEN); - lkm_led(3, LKM_LED_ORANGE); - - return 0; -*/ - - // start - byte channels[4] = { }; - enum channel_state { - CHANNEL_IDLE = 0, - CHANNEL_INC, - CHANNEL_DEC, - } channel_state[4] = { }; - byte channel_count[4] = { }; - char c; - - while (true) { - // scan input - byte buttons = lkm_buttons(); - - for (c = 0; c < 4; c++) { - enum channel_state state = channel_state[c], next; - byte count = channel_count[c]; - - // decode buttons -> state - if (buttons & 0b1) { - next = CHANNEL_INC; - } else if (buttons & 0b10) { - next = CHANNEL_DEC; - } else { - next = CHANNEL_IDLE; - } - - buttons >>= 2; - - // feedback - if (state == CHANNEL_INC || next == CHANNEL_INC) - lkm_led(c * 2 + 0, LKM_LED_GREEN); - else if (state == CHANNEL_DEC && next == CHANNEL_DEC) - lkm_led(c * 2 + 0, LKM_LED_RED); - else - lkm_led(c * 2 + 0, LKM_LED_OFF); - - if (state == CHANNEL_DEC || next == CHANNEL_DEC) - lkm_led(c * 2 + 1, LKM_LED_RED); - else if (state == CHANNEL_INC && next == CHANNEL_INC) - lkm_led(c * 2 + 1, LKM_LED_GREEN); - else - lkm_led(c * 2 + 1, LKM_LED_OFF); - - // counts - if ((channel_state[c] = next) != state) - channel_count[c] = 0; - else - count = ++channel_count[c]; - - // state transitions - if (next == CHANNEL_INC && count > 0) { - channels[c] += count; - } else if (next == CHANNEL_DEC && count > 0) { - channels[c] -= count; - } else if (state == CHANNEL_INC && !count) { - channels[c] = 0xff; - } else if (state == CHANNEL_DEC && !count) { - channels[c] = 0x00; - } - - lkm_display_hh(c * 2, channels[c]); - - xbi(&DEBUG_PORT, DEBUG_LED); - } - - timer_sleep(8000); - } -} diff -r c923295ee520 -r 1b3cea759eff src/hello.c --- a/src/hello.c Mon Jun 02 18:27:08 2014 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,213 +0,0 @@ -#include - -#include "stdlib.h" - -// XXX -#include "timer.c" -#include "serial.c" -#include "spi.c" -#include "led7.c" - -static enum state { - START = '\n', - CMD_SET = 's', - CMD_INC = '+', - CMD_DEC = '-', - CMD_READ = 'r', - ARG_CHAR = '0', - ERROR = '!', -} state = START, cmd = 0; - -static enum { - CMD_LED_1 = 0, -} cmd_led = 0; - -static char arg_char; - -static unsigned char led_state = 0; - -int command (enum state cmd) -{ - switch (cmd) { - case CMD_SET: - led_state = arg_char; - - return 0; - - case CMD_INC: - if (led_state == 0xff) - return 1; - - led_state++; - return 0; - - case CMD_DEC: - if (!led_state) - return 1; - - led_state--; - return 0; - - case CMD_READ: - led_state = spi_rx[1]; // XXX - return 0; - - default: - return 1; - } -} - -char input (char c) -{ - if (c == '\r') { - char ret = '?'; - - // command state - switch (state) { - case START: - cmd = 0; - break; - - case CMD_SET: - case CMD_INC: - case CMD_DEC: - break; - - case ARG_CHAR: - break; - - case ERROR: - cmd = 0; - break; - } - - // command - if (!cmd) { - ret = ' '; - } else if (command(cmd)) { - ret = '!'; - } else { - ret = '\n'; - } - - // return to START with response - state = START; - return ret; - - } else if (31 < c && c < 128) { - // process input char - switch (state) { - case START: - if (c == 's') { - cmd = CMD_SET; - state = ARG_CHAR; - arg_char = 0; - } else if (c == 'S') { - cmd = state = CMD_SET; - arg_char = 255; - } else if (c == '+') { - cmd = state = CMD_INC; - } else if (c == '-') { - cmd = state = CMD_DEC; - } else if (c == 'r') { - cmd = state = CMD_READ; - } else { - break; - } - - return state; - break; - - /* - case CMD_SET: - if (c == '1') { - cmd_led = CMD_LED_1; - state = ARG_CHAR; - arg_char = 0; - } else { - state = ERROR; - } - - break; - */ - case ARG_CHAR: - if (c >= '0' && c <= '9') { - arg_char *= 10; - arg_char += (c - '0'); - } else { - break; - } - - return c; - break; - } - - // reject - state = ERROR; - return ERROR; - - } else { - // ignore - return ' '; - } -} - - -#define DEBUG_DDR DDRB -#define DEBUG_PORT PORTB -#define DEBUG_LED 0 - -int main (void) -{ - led7_init(); - timer_init(); - serial_init(); - spi_init(); - - // led_init(); - sbi(&DEBUG_DDR, DEBUG_LED); - - sei(); - - // start - char c; - unsigned short timeout = 0; - - serial_write(state); - - while (true) { - // TODO: SPI timer - led7_update(led_state); - spi_update(); - - // toggle - if (led_state == 0) { - timeout = 0; - cbi(&DEBUG_PORT, DEBUG_LED); - - } else if (led_state == 255) { - timeout = 0; - sbi(&DEBUG_PORT, DEBUG_LED); - - } else { - // as Hz - timeout = (16000 / led_state); - xbi(&DEBUG_PORT, DEBUG_LED); - } - - // sleep - if (timer_sleep(timeout)) { - c = '.'; - - } else if ((c = serial_read())) { - // got serial data - c = input(c); - - } else { - c = '?'; - } - - // output... - serial_write(c); - } -} diff -r c923295ee520 -r 1b3cea759eff timer.inc --- a/timer.inc Mon Jun 02 18:27:08 2014 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,196 +0,0 @@ -;; vim: filetype=avr -;; -;; Timer unit control and use -;; - -.equ TIMER_FLAGS = GPIOR0 - -;; Timer0 -; Compare output mode -.set TIMER0_COMA = 0b00 ; null -.set TIMER0_COMB = 0b00 ; null - -; Waveform Generation Mode (triplet low/high) -.set TIMER0_WGML = 0b10 ; CTC -.set TIMER0_WGMH = 0b0 ; CTC - -; Clock Source -.set TIMER0_CS = 0b101 ; 1/1024 - -;; Timer1 -; Waveform Generation Mode (nibble low/high) -.set TIMER1_WGML = 0b00 ; CTC -.set TIMER1_WGMH = 0b01 ; CTC - -; Clock Source -.set TIMER1_CS = 0b101 ; 1/1024 - -; Flags -.equ TIMER1_BUSY = 1 - -.set SLEEP_MODE = 0b000 ; Idle - -Timer_Init: -Timer0_Init: - ; OC0A/B disconnected from output - ; No PWM mode - ldi r16, (TIMER0_COMA << COM0A0) | (TIMER0_COMB << COM0B0) | (TIMER0_WGML << WGM00) - out TCCR0A, r16 - - ; Clear - ldi r16, 0 - out OCR0A, r16 - out OCR0B, r16 - out TCCR0B, r16 - - ; Enable compare interrupt - ldi r16, (1 << OCIE0A) - sts TIMSK0, r16 - -Timer1_Init: - ; OC1A/B disconnected from output - ; No PWM mode - poke [TCCR1A, r16, (0b00 << COM1A0) | (0b00 << COM1B0) | (TIMER1_WGML << WGM10)] - - ; Clear - poke [TCCR1B, r16, 0] - poke [TCCR1C, r16, 0] - - ; Enable compare interrupt - poke [TIMSK1, r16, (1 << OCIE1A)] - -Sleep_init: - ; Select sleep mode - ; Enable `sleep` - poke [SMCR, r16, (SLEEP_MODE << SM0) | (1 << SE)] - - ; Disable ADC - poke [SMCR, r16, (1 << PRTWI) | (1 << PRUSART0) | (1 << PRADC)] - - ret - -;; Timer0 is recurring; this starts it running, and it keeps hitting OC0A periodically -;; Input: r16 (period, in 1k-cycles) -Timer0_Start: - ; Initialize timer - ; set CTC trigger from r16 - out OCR0A, r16 - - ; clear counter - ldi r16, 0 - out TCNT0, r16 - - ; Start - ; WGM - ; Clock Source - ldi r16, (TIMER0_WGMH << WGM02) | (TIMER0_CS << CS00) - out TCCR0B, r16 - - ret - -Timer0_Read8: - in r16, TCNT0 - - ret - -;; Timer0 Compare A interrupt handler -Timer_OC0A: - in r0, SREG - - ; Run callback - rcall TIMER0_CB_A - - out SREG, r0 - reti - -;; Timer1 is one-shot; this starts it running, and it is then stopped once it hits OC1A -Timer1_Start: - ; Initialize timer - poke [TCNT1H, r16, high(0)] - poke [TCNT1L, r16, low(0)] - - ; Set flag - sbi TIMER_FLAGS, TIMER1_BUSY - - ; Start - ; WGM - ; Clock Source - poke [TCCR1B, r16, (TIMER1_WGMH << WGM12) | (TIMER1_CS << CS10)] - - ret - -Timer1_Stop: - ; WGM - ; Clock off - poke [TCCR1B, r16, (TIMER1_WGMH << WGM12) | (0b00 << CS10)] - - ; Clear flag - cbi TIMER_FLAGS, TIMER1_BUSY - - ret - -;; Timer1 Compare A interrupt handler -Timer_OC1A: - in r0, SREG - - ; Stop timer - rcall Timer1_Stop - - out SREG, r0 - reti - -;; Prime the timer and sleep for 1s -Timer_Sleep_1s: - ; Initialize counter to 16k cycles - ldi XH, high(16 * 1024) - ldi XL, low(16 * 1024) - - ;; Continue - -;; Count to X -Timer_Sleep: - ; Set TOP - sts OCR1AH, XH - sts OCR1AL, XL - - ; Start timer - rcall Timer1_Start - - ; Wait for timer to complete -_timer1_sleep: - sleep - - sbic TIMER_FLAGS, TIMER1_BUSY - rjmp _timer1_sleep - - ; Done - ret - -;; Update timer for given timeout -Timer_Update: - ; Set TOP - sts OCR1AH, XH - sts OCR1AL, XL - - ; Check timer - lds YL, TCNT1L - lds YH, TCNT1H - - cp YL, XL - cpc YH, XH - - brlo timer_up_out - - ; Update - ; XXX: figure out a better way to do this... - ldi r16, 0 - subi XL, 2 - sbc XH, r16 - - sts TCNT1L, XL - sts TCNT1H, XH - -timer_up_out: - ; Done - ret - diff -r c923295ee520 -r 1b3cea759eff timer.s --- a/timer.s Mon Jun 02 18:27:08 2014 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,68 +0,0 @@ -.nolist -.include "m168def.inc" ; Same family as 328P -.list - -;; Interrupt Vector -.org 0x00 - rjmp init - -.org OC1Aaddr - ; Timer/Counter1 Compare Output A - rjmp Timer_OC1A - -.org OC0Aaddr - ; Timer/Counter0 Compare Output A - rjmp Timer_OC0A - -.org 0x40 - -;; Syntax -.include "macros.inc" - -;; Timer0 Compare A handler -Tick: - ; Toggle - sbi PIND, PORTD7 - - ret - -;; Timer -.set TIMER0_CB_A = Tick -.include "timer.inc" - -Main: -init: - ; Stack - ldi r16, high(RAMEND) - ldi r17, low(RAMEND) - out SPH, r16 - out SPL, r17 - - ; Enable interrupts - sei - - ; Turn off LED7 - sbi DDRB, PORTB1 - sbi PORTB, PORTB1 - - - ; DEBUG - sbi DDRD, PORTD7 - cbi PORTD, PORTD7 - - sbi DDRD, PORTD6 - sbi DDRD, PORTD5 - - - ; Timer - ; setup - rcall Timer0_Init - - ; run with 255k cycles - ldi r16, 255 - rcall Timer0_Start - -loop: - ; Run timer - rjmp loop -