;***************************************************************************************** ;** ;** EASi Line Assembly Technology Expo 2006 Readerboard Give-away Assembly Source Code ;** Written by David Beecher & Keith Nelson ;** Copyright 2006 CPU Ready Consulting Inc. ;** ;** For schematics, instructions and full source, visit: ;** http://www.cpureadyconsulting.com/ ;** ;** Written for the Atmel ATTiny2313 ;** ;** License Agreement ;** You are free to copy and use our source code in your non-commercial project as long as ;** you include this comment block at the top of any source file which contains our code. ;** Commercial use is prohibited without prior authorization from CPU Ready Consulting Inc. ;** ;****************************************************************************************** ;****************************************************************************** ;* * ;* (Beecher's AVR Template version 1.2) * ;* * ;****************************************************************************** .include "tn2313def.inc" .include "easiline.inc" ;****************************************************************************** ;* ;* Reset and Interrupt Vectors ;* ;****************************************************************************** .cseg .org $0000 ;Reset handler rjmp reset .org INT0addr ;External Interrupt0 rjmp reset .org INT1addr ;External Interrupt1 rjmp reset .org ICP1addr ;Input capture interrupt 1 rjmp reset .org OC1Aaddr ;Timer/Counter1 Compare Match A rjmp reset .org OVF1addr ;Overflow1 Interrupt rjmp reset .org OVF0addr ;Overflow0 Interrupt rjmp reset .org URXC0addr ;USART0 RX Complete Interrupt rjmp reset .org UDRE0addr ;USART0 Data Register Empty Interrupt rjmp reset .org UTXC0addr ;USART0 TX Complete Interrupt rjmp reset .org ACIaddr ;Analog Comparator Interrupt rjmp reset .org PCIaddr ;Pin Change Interrupt rjmp reset .org OC1Baddr ;Timer/Counter1 Compare Match B rjmp reset .org OC0Aaddr ;Timer/Counter0 Compare Match A rjmp reset .org OC0Baddr ;Timer/Counter0 Compare Match B rjmp reset .org USI_STARTaddr ;USI start interrupt rjmp reset .org USI_OVFaddr ;USI overflow interrupt rjmp reset .org ERDYaddr ;EEPROM write complete rjmp reset .org WDTaddr ;Watchdog Timer Interrupt rjmp reset ;****************************************************************************** ; Routine: main ; Purpose: ; Inputs: ; Outputs: ; Exit: ; Notes: ; History: ; Algorithm: ;****************************************************************************** main: rcall ClearDispRam ldi TimerHigh, HIGH(DELAY_SHIFT) ;counter for rotating all data to the left ldi TimerLow, LOW(DELAY_SHIFT) clr CurrentChar ;point to fist char of message ldi Temp, MSG_PWR_OFF ;set number of times to repeat messgae mov MsgCounter, Temp ldi Temp, DIGIT_COUNT ;counter for when to insert new digit mov DigitCount, Temp ;load message into EEPROM if no data (0xff) at first location of EEPROM clr EEAddr rcall read_eeprom_array mov Temp, r0 cpi Temp, 0xff brne main1 ;jump if first EE loc != 0xff ldi ZH,HIGH(ATexpo_msg * 2) ;load message to EEPROM ldi ZL,LOW(ATexpo_msg * 2) ;copy string till end main0: lpm rcall write_eeprom_array tst r0 breq main1 subi ZL, LOW(-1) ;string pntr++ sbci ZH, HIGH(-1) inc EEAddr ;EE storage++ rjmp main0 ;display message forever or until max on timeout occurs what ever comes first main1: rcall multiplex_display subi TimerLow, LOW(1) ;sub 1 from 16bit counter sbci TimerHigh, HIGH(1) brcc main1 ldi TimerHigh, HIGH(DELAY_SHIFT) ldi TimerLow, LOW(DELAY_SHIFT) rcall ShiftDispRam dec DigitCount brne main1 ldi Temp, DIGIT_COUNT mov DigitCount, Temp rcall send_str tst MsgCounter ;check if message counter = 0 brne main1 ;no keep showing messgae main2: sbi PWR_ENA_O, PWR_ENA_B ;turn power off, amd loop till CPU cbi COL_RST_O, COL_RST_B cbi COL_LOAD_O, COL_LOAD_B sbi COL_LOAD_O, COL_LOAD_B sbi COL_RST_O, COL_RST_B rjmp main2 ;****************************************************************************** ; Routine: read_eeprom_array ; Purpose: read data from the internal processor EEprom ; Inputs: EEAddr = address of EEprom data to read ; Outputs: r0 = data read from EEprom ; Exit: ; Notes: ; History: 25-Oct-01 Initial Version. David Beecher ; Algorithm: ;****************************************************************************** read_eeprom_array: in Temp, SREG ;store SREG value cli ;disable interrupts during timed sequence read_eeprom_array_1: sbic EECR,EEWE ;if EEWE not clear rjmp read_eeprom_array_1 ;wait more out EEAR, EEAddr ;output address low sbi EECR, EERE ;set EEPROM Read strobe ;This instruction takes 4 clock cycles since ;it halts the CPU for two clock cycles in r0, EEDR ;get data out SREG, Temp ;restore SREG value (I-bit) ret ;****************************************************************************** ; Routine: write_eeprom_array ; Purpose: write data to the internal processor EEprom ; Inputs: EEAddr = address of EEprom data to read ; r0 = data to write to EEprom ; Outputs: ; Exit: ; Notes: ; History: 25-Oct-01 Initial Version. David Beecher ; Algorithm: ;****************************************************************************** write_eeprom_array: in Temp, SREG ;store SREG value cli ;disable interrupts during timed sequence write_eeprom_array_1: sbic EECR, EEPE ;if EEWE not clear rjmp write_eeprom_array_1 ; wait more out EEAR, EEAddr ;output address low out EEDR, r0 sbi EECR, EEMPE ;set master write enable sbi EECR, EEPE ;set EEPROM Write strobe ;This instruction takes 4 clock cycles since ;it halts the CPU for two clock cycles out SREG, Temp ;restore SREG value (I-bit) ret ;****************************************************************************** ; Routine: send_str ; Purpose: send null terminated string to serial port ; Inputs: z = string to send ; Outputs: ; Exit: ; Notes: ; History: ; Algorithm: ;****************************************************************************** send_str: ; ldi ZH,HIGH(ATexpo_msg * 2) ; ldi ZL,LOW(ATexpo_msg * 2) ; add ZL,CurrentChar ; brcc send_str_1 ; inc ZH send_str_1: ; lpm ;put char to send in r0 mov EEAddr, CurrentChar rcall read_eeprom_array inc CurrentChar ;point to next char tst r0 ;is char = 0 ? brne send_str_2 ; exit if null not reached clr CurrentChar ;null reached, reset message ldi Temp,' ' mov r0, Temp dec MsgCounter ;Message counter -1 send_str_2: rcall Char2DispRam ret ;****************************************************************************** ; Routine: ShiftDispRam ; Purpose: shift display ram so new data comes to view, and oldest data ; goes away ; Inputs: None ; Outputs: None ; Exit: ; Notes: ; History: ; Algorithm: ;****************************************************************************** ShiftDispRam: ldi Temp, 8 mov Loop1, Temp ldi ZH,HIGH(DISPLAY_RAM) ldi ZL,LOW(DISPLAY_RAM) ShiftDispRam_1: ldd Temp, Z+2 lsr Temp std Z+2, Temp ldd Temp, Z+1 ror Temp std Z+1, Temp ldd Temp, Z+0 ror Temp std Z+0, Temp subi ZL, LOW(-4) ;add 4 to ram pointer sbci ZH, HIGH(-4) dec Loop1 brne ShiftDispRam_1 ret ;****************************************************************************** ; Routine: Char2DispRam ; Purpose: Copy new character to display memory ; Inputs: ; Outputs: ; Exit: ; Notes: ; History: ; Algorithm: ;****************************************************************************** Char2DispRam: ;set Z pointer to character ldi Temp, ' ' ;first character in font table starts at sub r0, Temp ; ASCII char ' ', offset passed in parameter ; by ASCII ' ' clr ZH ;Char to write x 5 (size per each entry) mov ZL, r0 mov Temp, ZL ;and save mov Temp2, ZH lsl ZL ;x 2 rol ZH lsl ZL ;x 4 rol ZH add ZL, Temp ;add x 1 result for x 5 total adc ZH, Temp2 ldi Temp, LOW(CharSet * 2) ;Temp = pointer to character font table ldi Temp2, HIGH(CharSet * 2) add ZL, Temp ;Z = pointer to character data adc ZH, Temp2 subi ZL, LOW(-4) ;point to display ram + row select sbci ZH, HIGH(-4) //set up outer loop (font width) ldi Temp, CHR_FONT_WIDTH ;outer loop = character width mov Loop1, Temp //set up inner loop (font length) Char2DispRam_1: ldi Temp, CHR_FONT_LENGTH ;inner loop = character length mov Loop2, Temp lpm Temp2, Z ;Temp2 = column of font data ldi YH,HIGH(DISPLAY_RAM) ;Point to beginning of display ram ldi YL,LOW(DISPLAY_RAM) //store Font data in Display ram Char2DispRam_2: lsl Temp2 ;Carry = bit of font data ldd Temp, Y + NEW_CHR_OFFSET ;Load byte of display ram rol Temp ;shift in new font data std Y + NEW_CHR_OFFSET, Temp ;Store modified byte of display ram inc YL ;adjust pointer to where next bit inc YL ; of font data goes inc YL inc YL dec Loop2 ;dec inner loop brne Char2DispRam_2 ;branch till inner loop = 0 subi ZL, LOW(1) ;point to display ram + row select sbci ZH, HIGH(1) Char2DispRam_3: dec Loop1 ;dec outer loop brne Char2DispRam_1 ;branch till outer loop = 0 ret ;****************************************************************************** ; Routine: reset routines ; Purpose: ; Inputs: ; Outputs: ; Exit: ; Notes: ; History: ; Algorithm: ;****************************************************************************** reset: ;reset stack pointer ldi Temp,low(RAMEND) out SPL,Temp ;set up I/O port direction ldi Temp, DDRB_INIT out DDRB, Temp ;set up port B direction ldi Temp, DDRD_INIT out DDRD, Temp ;set up port D direction ;set up initial state for I/O ports ldi Temp, PORTB_INIT out PORTB, Temp ;set up port B data ldi Temp, PORTD_INIT out PORTD, Temp ;set up port D data ;set up initial hardware registers ldi Temp, GIMSK_DATA out GIMSK, Temp ldi Temp, TIMSK_DATA out TIMSK, Temp ldi Temp, MCUCR_DATA out MCUCR, Temp ldi Temp, TCCR0_DATA out TCCR0, Temp ldi Temp, TCCR1A_DATA out TCCR1A, Temp ldi Temp, TCCR1B_DATA out TCCR1B, Temp ldi Temp, WDTCR_DATA out WDTCR, Temp ldi Temp, UCSRB_DATA out UCSRB, Temp ldi Temp, UCSRC_DATA out UCSRC, Temp ldi Temp, UBRRL_DATA out UBRRL, Temp ldi Temp, UBRRH_DATA out UBRRH, Temp ldi Temp, ACSR_DATA out ACSR, Temp ;enable Interrupts, and set up port directions sei ;enable power cbi PWR_ENA_O, PWR_ENA_B ;clear 595 shift register cbi COL_CLK_O, COL_CLK_B cbi COL_RST_O, COL_RST_B cbi COL_LOAD_O, COL_LOAD_B sbi COL_LOAD_O, COL_LOAD_B sbi COL_RST_O, COL_RST_B cbi COL_LOAD_O, COL_LOAD_B rjmp main ;****************************************************************************** ; Routine: multiplex_display ; Purpose: write out data for all columns, and enable selected row ; Inputs: ; Outputs: ; Exit: ; Notes: ; History: ; Algorithm: ;****************************************************************************** multiplex_display: ;point to ram where the data is for this row mov ZL, CurRow andi ZL, 0b00000111 ;mask valid rows lsl ZL ;CurRow x 4 (2 instructions per row) lsl ZL clr ZH subi ZL, LOW(-DISPLAY_RAM) ;point to display ram + row select sbci ZH, HIGH(-DISPLAY_RAM) ;set up loop ldi Temp, 16 ;number of bits to send for selected row mov loop1, Temp ldd Temp, Z + 0 ;Temp(1) = 16 bits of display memory ldd Temp2, Z + 1 ;load shift registers with new column data multiplex_display_1: rol Temp ;bit to send is in Carry rol Temp2 cbi COL_DAT_O, COL_DAT_B ;clear or set data pin based on carry brcc multiplex_display_2 sbi COL_DAT_O, COL_DAT_B multiplex_display_2: sbi COL_CLK_O, COL_CLK_B ;clock bit into shift registers cbi COL_CLK_O, COL_CLK_B dec loop1 ;loop till all bits shifted brne multiplex_display_1 ;enable new row ldi Temp, 0x00 out LED_ROW, Temp ;turn off previous row cbi COL_LOAD_O, COL_LOAD_B ;load new column data sbi COL_LOAD_O, COL_LOAD_B rcall select_row ;enable selected row inc CurRow ;advance row for next pass ret ;****************************************************************************** ; Routine: select_row ; Purpose: enable for drive based od register CurRow ; Inputs: CurRow ; Outputs: ; Exit: ; Notes: ; History: ; Algorithm: ;****************************************************************************** select_row: push ZL push ZH push Temp mov ZL, CurRow andi ZL, 0b00000111 ;mask valid rows lsl ZL ;CurRow x 2 (2 instructions per row) clr ZH ;add offset of pkt_jump_table to Z register and jump to selected state subi ZL, LOW(-row_select_table) sbci ZH, HIGH(-row_select_table) ijmp ;jump to selected state row_select_table: ldi Temp, 0b00000001 ;value for row selection rjmp select_row_exit ldi Temp, 0b00000010 ;value for row selection rjmp select_row_exit ldi Temp, 0b00000100 ;value for row selection rjmp select_row_exit ldi Temp, 0b00001000 ;value for row selection rjmp select_row_exit ldi Temp, 0b00010000 ;value for row selection rjmp select_row_exit ldi Temp, 0b00100000 ;value for row selection rjmp select_row_exit ldi Temp, 0b01000000 ;value for row selection rjmp select_row_exit ldi Temp, 0b10000000 ;value for row selection rjmp select_row_exit select_row_exit: out LED_ROW, Temp pop Temp pop ZH pop ZL ; ret ;****************************************************************************** ; Routine: ClearDispRam ; Purpose: Copy new character to display memory ; Inputs: ; Outputs: ; Exit: ; Notes: ; History: ; Algorithm: ;****************************************************************************** ClearDispRam: ldi Temp, SIZE_DISPLAY_RAM mov loop1, Temp ldi ZH,HIGH(DISPLAY_RAM) ldi ZL,LOW(DISPLAY_RAM) clr Temp ClearDispRam_1: st Z+, Temp dec loop1 brne ClearDispRam_1 ret ATexpo_msg: .db 'W','e','l','c','o','m','e',' ','t','o',' ','E' .db 'A','S','i',' ','L','i','n','e',' ','A','T','E' .db 'x','p','o',' ','2','0','0','6', 0x00, 0x00 CharSet: .db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfa,0x00,0x00 ; sp ! .db 0x00,0xe0,0x00,0xe0,0x00,0x28,0xfe,0x28,0xfe,0x28 ; " # .db 0x24,0x54,0xfe,0x54,0x48,0xc4,0xc8,0x10,0x26,0x46 ; $ % .db 0x6c,0x92,0xaa,0x44,0x0a,0x00,0xa0,0xc0,0x00,0x00 ; & ' .db 0x00,0x38,0x44,0x82,0x00,0x00,0x82,0x44,0x38,0x00 ; ( ) .db 0x28,0x10,0x7c,0x10,0x28,0x10,0x10,0x7c,0x10,0x10 ; * + .db 0x00,0x0a,0x0c,0x00,0x00,0x10,0x10,0x10,0x10,0x10 ; , - .db 0x00,0x06,0x06,0x00,0x00,0x04,0x08,0x10,0x20,0x40 ; . / .db 0x7c,0x8a,0x92,0xa2,0x7c,0x00,0x42,0xfe,0x02,0x00 ; 0 1 .db 0x42,0x86,0x8a,0x92,0x62,0x84,0x82,0xa2,0xd2,0x8c ; 2 3 .db 0x18,0x28,0x48,0xfe,0x08,0xe5,0xa2,0xa2,0xa2,0x9c ; 4 5 .db 0x3c,0x52,0x92,0x92,0x0c,0x80,0x8e,0x90,0xa0,0xc0 ; 6 7 .db 0x6c,0x92,0x92,0x92,0x6c,0x60,0x92,0x92,0x94,0x78 ; 8 9 .db 0x00,0x6c,0x6c,0x00,0x00,0x00,0x6a,0x6c,0x00,0x00 ; : ; .db 0x10,0x28,0x44,0x82,0x00,0x28,0x28,0x28,0x28,0x28 ; < = .db 0x00,0x82,0x44,0x28,0x10,0x40,0x80,0x8a,0x90,0x60 ; > ? .db 0x4c,0x92,0x9e,0x82,0x7c,0x7e,0x88,0x88,0x88,0x7e ; @ A .db 0xfe,0x92,0x92,0x92,0x6c,0x7c,0x82,0x82,0x82,0x44 ; B C .db 0xfe,0x82,0x82,0x44,0x38,0xfe,0x92,0x92,0x92,0x82 ; D E .db 0xfe,0x90,0x90,0x90,0x80,0x7c,0x82,0x92,0x92,0x5e ; F G .db 0xfe,0x10,0x10,0x10,0xfe,0x00,0x82,0xfe,0x82,0x00 ; H I .db 0x04,0x02,0x82,0xfc,0x80,0xfe,0x10,0x28,0x44,0x82 ; J K .db 0xfe,0x02,0x02,0x02,0x02,0xfe,0x40,0x30,0x40,0xfe ; L M .db 0xfe,0x20,0x10,0x08,0xfe,0x7c,0x82,0x82,0x82,0x7c ; N O .db 0xfe,0x90,0x90,0x90,0x60,0x7c,0x82,0x8a,0x84,0x7a ; P Q .db 0xfe,0x90,0x98,0x94,0x62,0x62,0x92,0x92,0x92,0x8c ; R S .db 0x80,0x80,0xfe,0x80,0x80,0xfc,0x02,0x02,0x02,0xfc ; T U .db 0xf8,0x04,0x02,0x04,0xf8,0xfc,0x02,0x1c,0x02,0xfc ; V W .db 0xc6,0x28,0x10,0x28,0xc6,0xe0,0x10,0x0e,0x10,0xe0 ; X Y .db 0x86,0x8b,0x92,0xa2,0xc2,0x00,0xfe,0x82,0x82,0x00 ; Z [ .db 0x40,0x20,0x10,0x08,0x04,0x00,0x82,0x82,0xfe,0x00 ; \ ] .db 0x20,0x40,0x80,0x40,0x20,0x02,0x02,0x02,0x02,0x02 ; ^ _ .db 0x00,0x80,0x40,0x20,0x00,0x04,0x2a,0x2a,0x2a,0x1e ; ` a .db 0xfe,0x12,0x22,0x22,0x1c,0x1c,0x22,0x22,0x22,0x04 ; b c .db 0x1c,0x22,0x22,0x12,0xfe,0x1c,0x2a,0x2a,0x2a,0x18 ; d e .db 0x10,0x7e,0x90,0x80,0x40,0x30,0x4a,0x4a,0x4a,0x7c ; f g .db 0xfe,0x10,0x20,0x20,0x1e,0x00,0x22,0xbe,0x02,0x00 ; h i .db 0x04,0x02,0x22,0xbc,0x00,0xfe,0x08,0x14,0x22,0x00 ; j k .db 0x00,0x82,0xfe,0x02,0x00,0x3e,0x20,0x18,0x20,0x1e ; l m .db 0x3e,0x10,0x20,0x20,0x1e,0x1c,0x22,0x22,0x22,0x1c ; n o .db 0x3e,0x28,0x28,0x28,0x10,0x10,0x28,0x28,0x18,0x3e ; p q .db 0x3e,0x10,0x20,0x20,0x10,0x12,0x2a,0x2a,0x2a,0x04 ; r s .db 0x20,0xfc,0x22,0x02,0x04,0x3c,0x02,0x02,0x04,0x3e ; t u .db 0x38,0x04,0x02,0x04,0x38,0x3c,0x02,0x0c,0x02,0x3c ; v w .db 0x22,0x14,0x08,0x14,0x22,0x30,0x0a,0x0a,0x0a,0x3c ; x y .db 0x22,0x26,0x2a,0x32,0x22,0x00,0x10,0x6c,0x82,0x00 ; z { .db 0x00,0x00,0xfe,0x00,0x00,0x00,0x82,0x6c,0x10,0x00 ; | }