X-Git-Url: http://git.kpe.io/?p=avr_serial_lcd.git;a=blobdiff_plain;f=serial_lcd.S;fp=serial_lcd.S;h=1de94537d46e5884bc2bd6537a003f7a47e28763;hp=0000000000000000000000000000000000000000;hb=ed1c6857c750294747f3705d1d9e37c89658bd5b;hpb=32f563c436c2f9ae80b083280b54aa24af7f5398 diff --git a/serial_lcd.S b/serial_lcd.S new file mode 100644 index 0000000..1de9453 --- /dev/null +++ b/serial_lcd.S @@ -0,0 +1,713 @@ +/***************************************************************************** +* FILE IDENTIFICATION +* +** Name: serial_lcd.S +** Purpose: Serial LCD Backpack code for GCC Assembler +** Programmer: Kevin Rosenberg (AVR Freaks member kmr) +** Date Started: April 2008 +** +** Copyright (c) 2008 by Kevin Rosenberg +*******************************************************************************/ + + #include +#ifndef F_CPU +#define F_CPU 14745600UL +#endif + +#define CONSERVATIVE_ENABLE_DURATION 0 +#define USE_CTS 0 + +/*************************************************************/ +/*************************************************************/ + +/* //// From the LCD perspective \\\\ + RxD --> PORTD:0 + LED <-- PORTD:1 // High = ON, Low = OFF + J_1 --> PORTD:2 // BAUD rate select + J_2 --> PORTD:3 // BAUD rate select + LCD:R/W <-- PORTD:4 + LCD:RS <-- PORTD:5 + LCD:E <-- PORTD:6 + N/A <-> PORTD:7 + + LCD:R/W <-- PORTD:4 + LCD:RS <-- PORTD:5 + LCD:E <-- PORTD:6 + LCD:Vee <-- CONTRAST + LCD:DB0 <-- PORTB:0 + LCD:DB1 <-- PORTB:1 + LCD:DB2 <-- PORTB:2 + LCD:DB3 <-- PORTB:3 + LCD:DB4 <-- 4.7K Ohm <-- PORTx:4 + LCD:DB5 <-- 4.7K Ohm <-- PORTx:5 + LCD:DB6 <-- 4.7K Ohm <-- PORTx:6 + LCD:DB7 <-- 4.7K Ohm <-- PORTx:7 + + //// From the I/O PORTx perspective \\\\ + PORTD:0 <--RxD + PORTD:1 --> LED // High = ON, Low = OFF + PORTD:2 <-- J_1 // BAUD rate select + PORTD:3 <-- J_2 // BAUD rate select + PORTD:4 --> LCD:R/W + PORTD:5 --> LCD:RS + PORTD:6 --> LCD:E + PORTD:7 <-> N/A + + PORTB:0 --> LCD:DB0 + PORTB:1 --> LCD:DB1 + PORTB:2 --> LCD:DB2 + PORTB:3 --> LCD:DB3 + PORTB:4 --> 4.7K Ohm --> LCD:DB4 + PORTB:5 --> 4.7K Ohm --> LCD:DB5 + PORTB:6 --> 4.7K Ohm --> LCD:DB6 + PORTB:7 --> 4.7K Ohm --> LCD:DB7 +*/ + +/*************************************************************/ +/*************************************************************/ +// If you want to use a different I/O port for LCD control & data, +// do it here!!! +#define LCD_DATA_PORT PORTB +#define LCD_DATA_PIN_REG PINB +#define LCD_DATA_DIR DDRB + +#define LCD_CONTROL_PORT PORTD +#define LCD_CONTROL_PIN_REG PIND +#define LCD_CONTROL_DIR DDRD + +// LED backlight control pin +#define LED_DIR DDRD +#define LED_PORT PORTD +#define LED_PIN PD1 + +// LCD Read/Write Pin +#define LCD_RW PD4 +// LCD Register Select Pin +#define LCD_RS PD5 +// LCD Enable Pin +#define LCD_E PD6 +/*************************************************************/ +/*************************************************************/ + +// LCD busy status pin +#define LCD_BUSY PB7 + +// BAID rate setting pins +#define BAUD_PORT PORTD +#define BAUD_DIR DDRB +#define BAUD_PIN_REG PIND +#define BAUD_J1 PD2 +#define BAUD_J2 PD3 + +#if USE_CTS +// Direction register for clear to send signal +#define CTS_DIR DDRA +// Output port for clear to send signal +#define CTS_PORT PORTA +// Pin for clear to send signal (RESET pin on Tiny2313) +// Ensure fuse is set to disable RESET function on RESET pin +#define CTS_PIN PA2 +#endif + +// Number of PWM brightness levels supported +#define LED_BRIGHTNESS_LEVELS 8 + +////// LCD Commands /////// +// Turn on power to the display, no cursor +#define LCD_ON 0x0C +// Clear display command +#define LCD_CLR 0x01 +// Set 4 data bits +#define LCD_4_Bit 0x20 +// Set 8 data bits +#define LCD_8_Bit 0x30 +// Set number of lines +#define LCD_4_Line 0x08 +// Set 8 data bits +#define DATA_8 0x30 +// Set character font +#define LCD_Font 0x04 +// Turn the cursor on +#define LCD_CURSOR_ON 0x02 +// Turn on cursor blink +#define LCD_CURSOR_BLINK 0x01 + +////// Serial command codes /////// +// ASCII control code to set brightness level +// Next byte is brightness ranging from 0 (no backlight) to 255 (max backlight) +#define LED_SET_BRIGHTNESS 0xFB +// ASCII control code turns on LED +#define LED_SW_ON 0xFC +// ASCII control code turns off LED +#define LED_SW_OFF 0xFD +// Character generator RAM command +#define REG_MODE 0xFE + +// Circular buffer for UART RX +#define UART_RX_BUFFER_SIZE 48 +.section .data +sUartRxBuf: + .org 0 +sUartTxBufEnd: + .org sUartRxBuf + UART_RX_BUFFER_SIZE + +.section .text + +// Actual baud rate = 9600 BAUD, (0.0% error) @ 14.7456MHz +// Actual baud rate = 19.2K BAUD, (0.0% error) @ 14.7456MHz +// Actual baud rate = 38.4K BAUD, (0.0% error) @ 14.7456MHz +// Actual baud rate = 115.2K BAUD, (0.0% error) @ 14.7456MHz +#define BAUD_4800 191 +#define BAUD_9600 95 +#define BAUD_14400 63 +#define BAUD_19200 47 +#define BAUD_28800 31 +#define BAUD_38400 23 +#define BAUD_57600 15 +#define BAUD_76800 11 +#define BAUD_115200 7 + +BaudLookupTable: + .byte BAUD_115200 + .byte BAUD_38400 + .byte BAUD_19200 + .byte BAUD_9600 + +// PWM Patterns (8-brightness levels) +ledPwmPatterns: + .byte 0x10 // 0b00010000 0 + .byte 0x11 // 0b00010001 1 + .byte 0x4A // 0b01001010 2 + .byte 0x55 // 0b01010101 3 + .byte 0x5D // 0b01011101 4 + .byte 0xEE // 0b11101110 5 + .byte 0x7F // 0b11110111 6 + .byte 0xFF // 0b11111111 7 + + +// PWeh must be 230nS minimum, nop = 67nS @ 14.7456MHz +// At 4 cycles, E = 271nS +// Some slow systems require 450ns, or 7 cycles at 14.7456MHz +#if CONSERVATIVE_ENABLE_DURATION +.macro ENABLE_WAIT + rjmp 1f +1: rjmp 2f +2: rjmp 3f +3: nop +.endm +#else +.macro ENABLE_WAIT + rjmp 1f +1: rjmp 2f +2: +.endm +#endif + +// register variables +#define zeroReg r1 +#define saveSregReg r2 +#define ledPwmCycling r3 +#define isrTemp1 r16 +#define isrTemp2 r17 +#define isrTemp3 r18 +#define ledPwmCount r19 +#define ledStatus r20 +#define sUartRxHead r21 +#define sUartRxTail r22 +#define returnReg1 r23 +#define loadReg r24 +#define ledPwmPattern r25 +#define tmpReg1 r26 +#define tmpReg2 r27 +#define tmpReg3 r28 +#define tmpReg4 r29 + +.macro LedTimerStop + out _SFR_IO_ADDR(TCCR0B), zeroReg +.endm +.macro LedTimerStart +// Start with 256 prescaler + ldi loadReg, (1<> 8; + mov tmpReg1, returnReg1 + mov tmpReg2, zeroReg + mov tmpReg3, (LED_BRIGHTNESS_LEVELS-2) +brightMultLoop: + add tmpReg1, returnReg1 + adc tmpReg2, zeroReg + dec tmpReg3 + brne brightMultLoop + ldi loadReg, 127 + add tmpReg1, loadReg + adc tmpReg2, zeroReg + // ledPwmPos now in tmpReg2 + + // Below is probably not required, but ensures we don't exceed array + // if (ledPwmPos > LED_BRIGHTNESS_LEVELS - 1) + // ledPwmPos = LED_BRIGHTNESS_LEVELS - 1; + cpi tmpReg2, LED_BRIGHTNESS_LEVELS - 1 + brlo brightMax + ldi tmpReg2, LED_BRIGHTNESS_LEVELS - 1 +brightMax: + // ledPwmPattern = PGM_READ_BYTE (&ledPwmPatterns[ledPwmPos]); + ldi ZL,lo8(ledPwmPatterns) + ldi ZH,hi8(ledPwmPatterns) + add ZL, tmpReg3 + adc ZH, zeroReg + lpm r0,Z // ledPwmPos is in r0 + mov tmpReg2, r0 + mov ledPwmCount, zeroReg + mov ledPwmCycling, ledPwmPattern + + cpi tmpReg2, (LED_BRIGHTNESS_LEVELS-1) // compare to maxmimum brightness + brsh brightSetMax + // if (IS_BACKLIGHT_ON()) LedTimerStart(); + ret +brightSetMax: + sbrc ledStatus, 0 + // don't need PWM for continuously on + ret + LedTimerStop + sbi _SFR_IO_ADDR(LED_PORT), LED_PIN + ret + +.global main +main: + clr zeroReg + wdr + + ldi loadReg, (1<= LED_BRIGHTNESS_LEVELS-1) { +// ledPwmCount = 0; +// ledPwmCycling = ledPwmPattern; +// } else { +// ledPwmCount++; +// ledPwmCycling >>= 1; +// } +//} + cpi ledPwmCount, (LED_BRIGHTNESS_LEVELS - 1) + brsh tcIsrResetCount + inc ledPwmCount + asr ledPwmCycling + rjmp tcIsrDone +tcIsrResetCount: + clr ledPwmCount + mov ledPwmCycling, ledPwmPattern + +tcIsrDone: + RestoreSREG + reti + + + .global USART_RX_vect +USART_RX_vect: + StoreSREG + // check for frame error + sbic _SFR_IO_ADDR(UCSRA), FE + // framing error. Currrently, this is silently ignored + // real applications may wish to output information to LCD to indicate + // erroroneous byte received + rjmp urxIsrDone + + in isrTemp1, _SFR_IO_ADDR(UDR) + // Calculate next buffer position. + // tmphead = sUartRxHead; + // if (tmphead == UART_RX_BUFFER_SIZE-1) + // tmphead = 0; + // else + // tmphead++; + clr isrTemp2 + cpi sUartRxHead, (UART_RX_BUFFER_SIZE-1) + breq urxIsrAtEnd + mov isrTemp2, sUartRxHead + inc isrTemp2 +urxIsrAtEnd: + // store in buffer if there is room + // if (tmphead != sUartRxTail) { + // sUartRxHead = tmphead; // Store new index. + // sUartRxBuf[tmphead] = rx; + // } + cp isrTemp2, sUartRxTail + breq urxIsrNoRoom + mov sUartRxHead, isrTemp2 + push ZL + push ZH + ldi ZL, lo8(sUartRxBuf) + ldi ZH, hi8(sUartRxBuf) + add ZL, isrTemp2 + adc ZH, 0 + st Z, isrTemp1 + pop ZH + pop ZL +urxIsrNoRoom: + +#if USE_CTS + // check if buffer is now full, if so switch CTS to inactive + if (tmphead == UART_RX_BUFFER_SIZE-1) + tmphead = 0; + else + tmphead++; + // CTS active if still room in buffer + if (tmphead != sUartRxTail) { + CTS_PORT |= (1<