From ed1c6857c750294747f3705d1d9e37c89658bd5b Mon Sep 17 00:00:00 2001 From: Kevin Rosenberg Date: Tue, 8 Apr 2008 21:14:07 -0600 Subject: [PATCH] initial version of assembly port of serial_lcd. Not yet tested --- gcc_asm/Makefile | 74 +++++ serial_lcd.S | 713 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 787 insertions(+) create mode 100644 gcc_asm/Makefile create mode 100644 serial_lcd.S diff --git a/gcc_asm/Makefile b/gcc_asm/Makefile new file mode 100644 index 0000000..68a8d88 --- /dev/null +++ b/gcc_asm/Makefile @@ -0,0 +1,74 @@ +############################################################################### +# Makefile for the serial_lcd C version for GCC + +## General Flags +PROJECT = serial_lcd +MCU = attiny2313 +TARGET = $(PROJECT).elf +CC = avr-gcc + +## Options common to compile, link and assembly rules +COMMON = -mmcu=$(MCU) + +## Compile options common for all C compilation units. +CFLAGS = $(COMMON) +CFLAGS += -DF_CPU=14745600UL -Os + +## Assembly specific flags +ASMFLAGS = $(COMMON) -D__ASSEMBLER__ +ASMFLAGS += -DF_CPU=14745600UL -Os +ASMFLAGS += -Wa,-gstabs + +## Linker flags +LDFLAGS = $(COMMON) +LDFLAGS += -Wl,-Map=$(PROJECT).map,--cref + + +## Intel Hex file production flags +HEX_FLASH_FLAGS = -R .eeprom +HEX_EEPROM_FLAGS = -j .eeprom +HEX_EEPROM_FLAGS += --set-section-flags=.eeprom="alloc,load" +HEX_EEPROM_FLAGS += --change-section-lma .eeprom=0 --no-change-warnings + + +## Objects that must be built in order to link +OBJECTS = $(PROJECT).o + +## Objects explicitly added by the user +LINKONLYOBJECTS = + +## Build +all: $(PROJECT).hex $(PROJECT).eep $(PROJECT).lss size + +## Compile +$(PROJECT).o: ../$(PROJECT).S + $(CC) $(ASMFLAGS) -c $< -o $(PROJECT).o + +##Link +$(TARGET): $(OBJECTS) + $(CC) $(LDFLAGS) $(OBJECTS) $(LINKONLYOBJECTS) $(LIBDIRS) $(LIBS) -o $(TARGET) + +$(PROJECT).hex: $(TARGET) + avr-objcopy -O ihex $(HEX_FLASH_FLAGS) $< $@ + +$(PROJECT).eep: $(TARGET) + -avr-objcopy $(HEX_EEPROM_FLAGS) -O ihex $< $@ || exit 0 + +$(PROJECT).lss: $(TARGET) + avr-objdump -h -S $< > $@ + +.PHONY: size +size: ${TARGET} + @echo $(TARGET) size + @avr-size -C --mcu=${MCU} ${TARGET} + +## Clean target +.PHONY: distclean +distclean: clean + @rm -rf $(PROJECT).hex $(PROJECT).lss $(PROJECT).map $(PROJECT).lst + +.PHONY: clean +clean: + @rm -rf $(OBJECTS) $(TARGET) $(PROJECT).eep + + 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<