From 90c5c097702cec99a4e16e2f390325469bb7bf0a Mon Sep 17 00:00:00 2001 From: Kevin Rosenberg Date: Sun, 16 Mar 2008 09:14:10 -0600 Subject: [PATCH] Initial import --- .gitignore | 2 + ChangeLog | 179 ++++++++++++ LICENSE | 25 ++ Makefile | 60 ++++ README | 54 ++++ cv_c/serlcd_cv.prj | 223 +++++++++++++++ gcc_c/Makefile | 80 ++++++ gcc_cpp/Makefile | 81 ++++++ gcc_cpp_obj/Makefile | 80 ++++++ iar_c/Makefile | 42 +++ iar_cpp/Makefile | 42 +++ iar_cpp_obj/Makefile | 42 +++ icc_c/Makefile | 45 +++ serial_lcd.c | 478 +++++++++++++++++++++++++++++++ serial_lcd.h | 308 ++++++++++++++++++++ serial_lcd_cpp.cpp | 524 ++++++++++++++++++++++++++++++++++ serial_lcd_obj.cpp | 561 +++++++++++++++++++++++++++++++++++++ tester/Makefile | 13 + tester/serial_lcd_tester.c | 487 ++++++++++++++++++++++++++++++++ 19 files changed, 3326 insertions(+) create mode 100644 .gitignore create mode 100644 ChangeLog create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 README create mode 100644 cv_c/serlcd_cv.prj create mode 100644 gcc_c/Makefile create mode 100644 gcc_cpp/Makefile create mode 100644 gcc_cpp_obj/Makefile create mode 100644 iar_c/Makefile create mode 100644 iar_cpp/Makefile create mode 100644 iar_cpp_obj/Makefile create mode 100644 icc_c/Makefile create mode 100644 serial_lcd.c create mode 100644 serial_lcd.h create mode 100644 serial_lcd_cpp.cpp create mode 100644 serial_lcd_obj.cpp create mode 100644 tester/Makefile create mode 100644 tester/serial_lcd_tester.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b2273ca --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +tester-build +*.~[0-9]~ diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..8c13117 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,179 @@ +2008-03-15 Kevin Rosenberg + * serial_lcd.c: Add 4-bit interface mode + * serial_lcd.h: Move LCD control codes here with renaming. Use + new device-independant iccioavr.h file for ImageCraft + (requires ICC V7.16+). Use __flash keyword for + Imagecraft (requires ICC V7.15+) + * Use custom Makefiles for all IAR, GCC, and ICC compilations + +2008-02-24 Kevin Rosenberg + * Enscapulate MAIN_FUNC() and MAIN_FUNC_LAST to avoid compile + warnings on all platforms + +2008-01-04 Kevin Rosenberg + * README: Update sizes for 20080104 release + +2008-01-03 Kevin Rosenberg + + * README: Update with information about the two C++ variants. + + * serial_lcd.h: Rename LCD_DATA_OUT to LCD_DATA_PORT. Create IO + definitions for baud rate jumpers to segment their access in + serial_lcd_obj.cpp. Add MAIN_FUNC() macro for new GCC OS_main + attribute. + + * serial_lcd.c: GetUsartBaud() move variable declaration to + assignment. Rename LCD_DATA_OUT to LCD_DATA_PORT. Use MAIN_FUNC(). + + * serial_lcd.cpp: Rename some member variables by prepending "m_". + Modify UART_UBRR() to round to nearest integer. Rename + LCD_DATA_OUT to LCD_DATA_PORT. Remove intermediate Baud Divisors + since C++ can employ preprocessor macro in array + initialization. Use MAIN_FUNC(). + + * serial_lcd_obj.cpp: Rename some member variables by prepending + "m_". Move GetBaud from Uart class to standalone function + GetBaudDivisor(). Use that divisor as for Uart::setBaudDivisor() + method. Modify UART_UBRR() to round to nearest integer. Rename + LCD_DATA_OUT to LCD_DATA_PORT. Remove intermediate Baud Divisors + since C++ can employ preprocessor macro in array + initialization. Use MAIN_FUNC(). Modify Lcd::init() to accept + parameters to define io definitions. Separate and add methods for + setting Uart baud divisor, parity, rx/tx enable and interrupt + enable configurations. + +2008-01-01 Kevin Rosenberg + + * ChangeLog: Renamed from CHANGES + + * serial_lcd.h: Move LED_BRIGHTNESS_LEVELS to .c and .cpp + functions so value can be encapsulated in .cpp LedPwm class. Move + LCD command codes to .c and .cpp files so that they can be + encapsulated by C++ classes. + + * serial_lcd.c: Make init functions inline to correspond to C++ versions. + Change GetUsartBaud to inline since it is only called once in a program. + Move LED PWM brightness computation to inline function. Make LED switch + on and off code into inline functions. Move CTS initialization to UsartInit. + + * serial_lcd.cpp: Change GetUsartBaud to inline since it is only called + once in a program. Move RX buffer into member variable of object (saves + 2 bytes in GCC and no change in IAR size). Change UART_RX_BUFFER_SIZE + from preprocessor definition to static const in class (no change in + code size). Move pwmPattern array to static variable in LedPwm class + and make pwmPattern an inline method (no change in code size). Make + setting LedPwmBrightness a class method. Move LED switch on and off code + to class methods. Move baud rate constants into Uart class. Change + UBRR from numeric constants to values computed from F_CPU. Move CTS init + to Uart::init(). Convert Watchdog and SleepMode to fully static classes. + Add Delay class. + + * serial_lcd_obj.cpp: New source file to test the implementation + and impact of using independed C++ classes which can potentially + be used as part of a standalone C++ AVR library. + +2007-12-31 Kevin Rosenberg + + * LICENSE: Include appropriate copyright statements + (Thanks to AVRFreaks member cpluscon) + + * serial_lcd.c: Fix Livingston's name Thanks to AVRFreaks member + cpluscon) + + * serial_lcd.cpp: Remove all object constructors to reduce code + size by eliminating constructors. Fix Livinston's name (Thanks to + AVRFreaks member cpluscon) + + * gcc_c_cpp/Makefile: Use proper map file for C++ code (Thanks to + AVRFreaks member cpluscon) + + * gcc_c_cpp: Directory renamed from gcc_c_cpp_comparison + + * iar_c_cpp: new directory + + * icc_c: new directory + + * Add assembly listings, map files, and hex files for all compiled + output + + * serial_lcd_tester.c: Serial_Lcd tester (tested on Cygwin, should + work on Linux) + + * serial_lcd_tester.exe: Compiled version of serial_lcd_tester.c + for Windows (requires Cygwin DLL file) + + +2007-12-30 Kevin Rosenberg + + * Initial source code + + * Change UART RX from polling to interrupt-driven circular buffer + + * LED backlight PWM brightness setting (8-levels) using Timer0 + COMPA interrupt. Store PWM patterns in flash ram. + + * Port code to IAR and GCC using kavr_compat.h compatibility + defintions and macros + + * NO_RETURN_FUNC macro on main to remove unnecessary + prologue/epilogue code + + * Move BaudLookupTable array from heap to flash ram. Requires 4 + more bytes of program code, but frees 4 bytes of SRAM. + + * Use _delay_ms functions for GCC and _delay_cycles for IAR + + * Add idle sleep mode setup and enter sleep when no input is + waiting + + * Add watchdog timer setups and resets + + * Bind key variables to registers + + * Change from IO Pin numbers to Pin names + + * Instead of NULL definition, use 0 to be explicit + + * If F_CPU (frequency of CPU) is not specified, default to value + for standard serial_backpack hardware + + * Define CPU type (__AVR_ATTiny2313__) for kavr_compat.h if not + already defined + + * Rename preprocessor definition LED to LED_PIN + + * Move USART_DATA from heap allocated to stack allocated, renamed + rx_byte + + * Remove auto-initialized variable so that auto-initialize code is + not included in binary (for compilers that support this + optimization) + + * New BIT variable for led_on status (stored in GPIO register) + + * Added CTS (clear to send) signal on PA2 pin since RESET pin + isn't used by original hardware design + + * Add conditional compilation of SLEEP_MODE, WATCHDOG, CTS + features + + * Add LED_PORT and LED_DIR definitions (in care LED not on same + PORT as LCD control) + + * Rename LCD_CONTROL_OUT to LCD_CONTROL_PORT, LCD_CONTROL_IN to + LCD_CONTROL_PIN_REG, LCD_CONTROL_DDR to LCD_CONTROL_DIR, + LCD_DATA_DDR to LCD_DATA_DIR, LCD_DATA_IN to LCD_DATA_PIN_REG + + * Use "= 0xFF" rather than "|= 0xFF" and simplify compare in + LcdBusyWait + + * Create ENABLE_WAIT() to reuse in 3 functions + + * Separate common declarations for .c and .cpp versions into .h + file + + * Rename a number of functions for common naming format + +Copyright (c) 2007-2008 by Kevin Rosenberg. All rights reserved. +Copying and distribution of this file, with or without modification, are +permitted provided the copyright notice and this notice are preserved. diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..6373c96 --- /dev/null +++ b/LICENSE @@ -0,0 +1,25 @@ +Copyright (c) 2007-2008 by Kevin Rosenberg. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the author nor the names of the contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..7dd0c84 --- /dev/null +++ b/Makefile @@ -0,0 +1,60 @@ +date := $(shell date +"%Y%m%d") + +.PHONY: all +all: build + +tester := tester/serial_lcd_tester + +tester-build: $(tester).exe + touch tester-build + +$(tester).exe: + (cd tester && make) + +.PHONY: build +build: tester-build + (cd gcc_c; make; make clean) + (cd gcc_cpp; make; make clean) + (cd gcc_cpp_obj; make; make clean) + (cd iar_c; make; make clean) + (cd iar_cpp; make; make clean) + (cd iar_cpp_obj; make; make clean) + (cd icc_c; make; make clean) + +dist: tester-build build + @chmod -x *.c *.h *.cpp README ChangeLog LICENSE + @find $(GCCDIR) -type f -exec chmod -x {} \; + @find $(IARDIR) -type f -exec chmod -x {} \; + @find $(ICCDIR) -type f -exec chmod -x {} \; + @zip serial_lcd-$(date).zip README serial_lcd.c serial_lcd.cpp serial_lcd_obj.cpp serial_lcd.h LICENSE ChangeLog \ + $(GCCDIR)/Makefile $(GCCDIR)/serial_lcd.map $(GCCDIR)/serial_lcd_cpp.map $(GCCDIR)/serial_lcd.lss \ + $(GCCDIR)/serial_lcd_cpp.lss $(GCCDIR)/serial_lcd.hex $(GCCDIR)/serial_lcd_cpp.hex \ + $(GCCDIR)/serial_lcd_obj.lss $(GCCDIR)/serial_lcd_obj.map $(GCCDIR)/serial_lcd_obj.map \ + $(IARDIR)/*.lst $(IARDIR)/*.map $(IARDIR)/*.hex $(ICCDIR)/*.mp $(ICCDIR)/*.lst $(ICCDIR)/*.hex \ + $(tester).c $(tester).exe + +.PHONY: clean +clean: + @rm -rf tester-build + $(MAKE) -C tester clean + $(MAKE) -C gcc_c clean + $(MAKE) -C gcc_cpp clean + $(MAKE) -C gcc_cpp_obj clean + $(MAKE) -C iar_c clean + $(MAKE) -C iar_cpp clean + $(MAKE) -C iar_cpp_obj clean + $(MAKE) -C iar_cpp_obj clean + $(MAKE) -C icc_c clean + +.PHONY: distclean +distclean: + @rm -rf tester-build + $(MAKE) -C tester distclean + $(MAKE) -C gcc_c distclean + $(MAKE) -C gcc_cpp distclean + $(MAKE) -C gcc_cpp_obj distclean + $(MAKE) -C iar_c distclean + $(MAKE) -C iar_cpp distclean + $(MAKE) -C iar_cpp_obj distclean + $(MAKE) -C iar_cpp_obj distclean + $(MAKE) -C icc_c distclean diff --git a/README b/README new file mode 100644 index 0000000..87d1346 --- /dev/null +++ b/README @@ -0,0 +1,54 @@ +AVR SERIAL_LCD C/C++ PROJECT +Kevin M. Rosenberg +===================================================================== + +The home for this project is http://www.avrcode/serial_lcd/ + +This is my version of AVR code to drive the Serial Backpack +Project created by Carl W. Livingston. I've rewritten the original +firmware to add a number of features, add compatibility for IAR and +GCC, and well as create two different C++ version. + +Tthis project is also used to demonstrate how C code can be turned +into C++ classes and to view the resulting differences in assembly +output. + +There are two versions of the C++ code: serial_lcd.cpp (which +generates output files with the prefix serial_lcd_cpp) and +serial_lcd_obj.cpp (generates output files with the prefix +serial_lcd_obj). + +The first C++ variant is designed to be "equivalent" to the C code in +that the same inlining of functions were used. Also, the C++ classes +were only to segment functions. No C++ class object contents member +variables. The global variables in the C code remain global in the C++ +code. Primarily, because these variables are stored in CPU and IO +registers for greater efficiency. Other variables, like the UART +circular buffer, remain in global memory space so its address is known +at compile time and spare the address computation required if the +variable was a member of a C++ object. + +The second C++ variant uses classes that contain member variables and +to which initialization parameters are sent. In this way, multiple +objects of that class can be created. As an example, for connecting 2 +LCD panels or multiple LED PWM outputs. + +The code can be modified and redistributed as governed by the terms of +the accompaning LICENSE file. + + +Code/Data Sizes (for 20080316 release) +====================================== + +Compiler Code Data Notes +--------- ---- ---- ----- +AVR-GCC C 720 48 -Os +AVR-GCC C++ 806 50 -Os +AVR-GCC Obj 1574 72 -Os +IAR C 648 48 Size optimization high (+ 64 bytes stack) +IAR C++ 746 49 Size optimization high (+ 64 bytes stack) +IAR Obj 1130 65 Size optimization high (+ 63 bytes stack) +ICC7 C 834 48 Full optimizations + +Please consider forwarding suggestions, improvements, or bug fixes to +me. diff --git a/cv_c/serlcd_cv.prj b/cv_c/serlcd_cv.prj new file mode 100644 index 0000000..2a35dbe --- /dev/null +++ b/cv_c/serlcd_cv.prj @@ -0,0 +1,223 @@ +[Project] +Toolset=AVR +FormatVersion=2 +Files=1 +OpenedFiles=3 +Top0=430 +Left0=711 +Height0=339 +Width0=497 +Active0=0 +State0=0 +OF1=c:\home\kevin\src\avr\serial_lcd\serial_lcd.c +Top1=151 +Left1=84 +Height1=509 +Width1=614 +Row1=135 +Collumn1=0 +Active1=0 +State1=0 +OF2=C:\home\kevin\src\avr\serial_lcd\serial_lcd.h +Top2=257 +Left2=268 +Height2=339 +Width2=497 +Row2=0 +Collumn2=0 +Active2=0 +State2=0 +F1=C:\home\kevin\src\avr\serial_lcd\serial_lcd.c +OF3=c:\cvavreval\inc\tiny2313.h +Top3=197 +Left3=133 +Height3=339 +Width3=497 +Row3=84 +Collumn3=3 +Active3=1 +State3=0 +[Compiler] +Chip=ATtiny2313 +CPUClock=14745600 +MemoryModel=0 +OptimizeSize=1 +OptimizationLevel=2 +PrintfFeatures=1 +ScanfFeatures=0 +DataStackSize=64 +PgmMemSize=2048 +RAMStart=96 +RAMEnd=223 +XRAMSize=0 +XRAMWaitState=0 +HeapSize=0 +ExternalInterruptVectors=0 +InterruptVectorsNumber=19 +InterruptVectorJump=0 +ResetVector=0 +PromoteCharToInt=0 +CharIsUnsigned=1 +8BitEnums=1 +EnhancedCoreInstructions=1 +AutomaticRegisterAllocation=1 +SmartRegisterAllocation=1 +WordAlignFLASHStructMembers=0 +PreprocessorOutput=1 +ExternalStartupFile=0 +ExternalStartupFileWarning=0 +BitVariablesSize=8 +UseHiGPIORbit=0 +StackEndMarkers=0 +Warnings=1 +WarningConstantRange=0 +WarningPossibleLossOfPrecision=0 +WarningArrayIndex=1 +WarningGlobalVariableAddress=1 +WarningInterruptVector=1 +WarningUninitializedFLASH=1 +WarningUninitializedEEPROM=1 +WarningSuspiciousPointerConversion=1 +WarningRegisterAllocated=1 +WarningMacroRedefined=1 +WarningFunctionReturn=1 +WarningUnreferencedFunction=1 +WarningUnreferencedFunctionParameter=1 +WarningUnreferencedLocalVariable=1 +WarningUnreferencedGlobalVariable=1 +WarningUnreferencedLabel=1 +WarningEmptyLine=1 +WarningExpressionHasNoEffect=1 +WarningUnknownEscapeSequence=1 +WarningShiftResult0=1 +Warning8BitAdditionOverflow=1 +Warning8BitMultiplicationOverflow=1 +Warning16BitAdditionOverflow=1 +Warning16BitMultiplicationOverflow=1 +WarningPossiblyIncorrectAssignment=1 +WarningPointlessComparison=1 +WarningConstCtrlExpr=1 +WarningUndefinedSymbol=1 +WarningCantAllocVarToReg=1 +WarningDataStackUsage=1 +WarningDataStackRecursion=1 +WarningHardwareStackLow=1 +DebugBootLoader=0 +Build=5 +UseEEPROMLocation0=1 +IncludePath0= +IncludePath1= +IncludePath2= +IncludePath3= +IncludePath4= +IncludePath5= +IncludePath6= +IncludePath7= +IncludePath8= +IncludePath9= +IncludePath10= +IncludePath11= +IncludePath12= +IncludePath13= +IncludePath14= +IncludePath15= +IncludePath16= +IncludePath17= +IncludePath18= +IncludePath19= +IncludePath20= +IncludePath21= +IncludePath22= +IncludePath23= +IncludePath24= +IncludePath25= +IncludePath26= +IncludePath27= +IncludePath28= +IncludePath29= +IncludePath30= +IncludePath31= +LibraryPath0= +LibraryPath1= +LibraryPath2= +LibraryPath3= +LibraryPath4= +LibraryPath5= +LibraryPath6= +LibraryPath7= +LibraryPath8= +LibraryPath9= +LibraryPath10= +LibraryPath11= +LibraryPath12= +LibraryPath13= +LibraryPath14= +LibraryPath15= +LibraryPath16= +LibraryPath17= +LibraryPath18= +LibraryPath19= +LibraryPath20= +LibraryPath21= +LibraryPath22= +LibraryPath23= +LibraryPath24= +LibraryPath25= +LibraryPath26= +LibraryPath27= +LibraryPath28= +LibraryPath29= +LibraryPath30= +LibraryPath31= +[DefinedSymbols] +Count=0 +[Assembler] +OutputFormat=1 +TerminalIO=0 +[AfterMake] +ProgrammChip=0 +MergeROMFile=0 +ROMFilePath= +SCKFrequency=230400 +LockBits=0 +BootLockBits0=0 +BootLockBits1=0 +ProgramFuseBits=1 +Fuse1=0 +Fuse2=0 +Fuse3=0 +Fuse4=0 +Fuse5=0 +Fuse6=0 +Fuse7=0 +Fuse8=0 +Fuse9=0 +Fuse10=0 +Fuse11=0 +Fuse12=0 +Fuse13=0 +Fuse14=0 +Fuse15=0 +Fuse16=0 +Fuse17=0 +Fuse18=0 +Fuse19=0 +Fuse20=0 +Fuse21=0 +Fuse22=0 +Fuse23=0 +Fuse24=0 +CheckSignature=1 +CheckErasure=1 +PreserveEEPROM=0 +VerifyProgramming=1 +ProgrammingCounter=0 +RunUserProg=0 +UserProgPath= +UserProgCmdLine= +UserProgWorkDir= +[BeforeMake] +RunUserProg=0 +UserProgPath= +UserProgCmdLine= +UserProgWorkDir= diff --git a/gcc_c/Makefile b/gcc_c/Makefile new file mode 100644 index 0000000..47eb208 --- /dev/null +++ b/gcc_c/Makefile @@ -0,0 +1,80 @@ +############################################################################### +# Makefile for the serial_lcd C & CPP versions + +## 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 += -Wall -gdwarf-2 -DF_CPU=14745600UL -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums +CFLAGS += -MD -MP -MT $(*F).o -MF dep/$(@F).d + +## Assembly specific flags +ASMFLAGS = $(COMMON) +ASMFLAGS += $(CFLAGS) +ASMFLAGS += -x assembler-with-cpp -Wa,-gdwarf2 + +## Linker flags +LDFLAGS = $(COMMON) +LDFLAGS += -Wl,-Map=$(PROJECT).map + + +## 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 + + +## Include Directories +INCLUDES = -I. + +## 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: ../serial_lcd.c + $(CC) $(INCLUDES) $(CFLAGS) -std=gnu99 -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 + +.PHONY: clean +clean: + @rm -rf $(OBJECTS) $(TARGET) dep $(PROJECT).eep + +## Other dependencies +-include $(shell mkdir dep 2>/dev/null) $(wildcard dep/*) + diff --git a/gcc_cpp/Makefile b/gcc_cpp/Makefile new file mode 100644 index 0000000..1e142cf --- /dev/null +++ b/gcc_cpp/Makefile @@ -0,0 +1,81 @@ +############################################################################### +# Makefile for the serial_lcd C & CPP versions + +## General Flags +PROJECT = serial_lcd_cpp +MCU = attiny2313 +TARGET = $(PROJECT).elf +CC = avr-g++ + +## Options common to compile, link and assembly rules +COMMON = -mmcu=$(MCU) + +## Compile options common for all C compilation units. +CFLAGS = $(COMMON) +CFLAGS += -Wall -gdwarf-2 -DF_CPU=14745600UL -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums +CFLAGS += -MD -MP -MT $(*F).o -MF dep/$(@F).d + +## Assembly specific flags +ASMFLAGS = $(COMMON) +ASMFLAGS += $(CFLAGS) +ASMFLAGS += -x assembler-with-cpp -Wa,-gdwarf2 + +## Linker flags +LDFLAGS = $(COMMON) +LDFLAGS += -Wl,-Map=$(PROJECT).map + + +## 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 + + +## Include Directories +INCLUDES = -I. + +## 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).cpp + $(CC) $(INCLUDES) $(CFLAGS) -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 + +.PHONY: clean +clean: + @rm -rf $(OBJECTS) $(TARGET) dep $(PROJECT).eep + +## Other dependencies +-include $(shell mkdir dep 2>/dev/null) $(wildcard dep/*) + diff --git a/gcc_cpp_obj/Makefile b/gcc_cpp_obj/Makefile new file mode 100644 index 0000000..9f5811c --- /dev/null +++ b/gcc_cpp_obj/Makefile @@ -0,0 +1,80 @@ +############################################################################### +# Makefile for the serial_lcd C & CPP versions + +## General Flags +PROJECT = serial_lcd_obj +MCU = attiny2313 +TARGET = $(PROJECT).elf +CC = avr-g++ + +## Options common to compile, link and assembly rules +COMMON = -mmcu=$(MCU) + +## Compile options common for all C compilation units. +CFLAGS = $(COMMON) +CFLAGS += -Wall -gdwarf-2 -DF_CPU=14745600UL -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums +CFLAGS += -MD -MP -MT $(*F).o -MF dep/$(@F).d + +## Assembly specific flags +ASMFLAGS = $(COMMON) +ASMFLAGS += $(CFLAGS) +ASMFLAGS += -x assembler-with-cpp -Wa,-gdwarf2 + +## Linker flags +LDFLAGS = $(COMMON) +LDFLAGS += -Wl,-Map=$(PROJECT).map + + +## 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 + + +## Include Directories +INCLUDES = -I. + +## 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).cpp + $(CC) $(INCLUDES) $(CFLAGS) -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 + +.PHONY: clean +clean: + @rm -rf $(OBJECTS) $(TARGET) $(PROJECT).eep dep + +## Other dependencies +-include $(shell mkdir dep 2>/dev/null) $(wildcard dep/*) diff --git a/iar_c/Makefile b/iar_c/Makefile new file mode 100644 index 0000000..c0dfcb5 --- /dev/null +++ b/iar_c/Makefile @@ -0,0 +1,42 @@ +############################################################################### +# Makefile for the serial_lcd C & CPP versions + +## General Flags +PROJECT = serial_lcd +MCU = tiny2313 +TARGET = $(PROJECT).hex +CC = /Program Files/IAR Systems/Embedded Workbench 5.0/avr/bin/iccavr.exe +LD = /Program Files/IAR Systems/Embedded Workbench 5.0/avr/bin/xlink.exe + +## Compile options common for all C compilation units. +CFLAGS = --cpu $(MCU) -lA $(PROJECT).lst -z9 -e --lock_regs 4 -D ENABLE_BIT_DEFINITIONS + +## Linker flags +LDFLAGS = -Fubrof9 -xm -xs -f '/Program Files/IAR Systems/Embedded Workbench 5.0/avr/config/lnktiny2313t.xcl' -l $(PROJECT).map -s main +LIBS = '/Program Files/IAR Systems/Embedded Workbench 5.0/avr/lib/clib/cl0t.r90' + +## Include Directories +INCLUDES = -I .. -I . -I '/Program Files/IAR Systems/Embedded Workbench 5.0/avr/inc' + +## Objects that must be built in order to link +OBJECTS = $(PROJECT).r90 + +## Build +all: $(TARGET) + +## Compile +$(PROJECT).r90: ../$(PROJECT).c + $(CC) $(INCLUDES) $(CFLAGS) $< + +##Link +$(TARGET): $(OBJECTS) + $(LD) $(LDFLAGS) $(OBJECTS) $(LIBDIRS) $(LIBS) -o $(TARGET) + +## Clean target +.PHONY: distclean +distclean: clean + @rm -f $(TARGET) $(PROJECT).lst $(PROJECT).map + +.PHONY: clean +clean: + @rm -f $(OBJECTS) diff --git a/iar_cpp/Makefile b/iar_cpp/Makefile new file mode 100644 index 0000000..5c63854 --- /dev/null +++ b/iar_cpp/Makefile @@ -0,0 +1,42 @@ +############################################################################### +# Makefile for the serial_lcd C & CPP versions + +## General Flags +PROJECT = serial_lcd_cpp +MCU = tiny2313 +TARGET = $(PROJECT).hex +CC = /Program Files/IAR Systems/Embedded Workbench 5.0/avr/bin/iccavr.exe +LD = /Program Files/IAR Systems/Embedded Workbench 5.0/avr/bin/xlink.exe + +## Compile options common for all C compilation units. +CFLAGS = --cpu $(MCU) -lA $(PROJECT).lst -z9 -e --ec++ --lock_regs 4 -D ENABLE_BIT_DEFINITIONS + +## Linker flags +LDFLAGS = -Fubrof9 -xm -xs -f '/Program Files/IAR Systems/Embedded Workbench 5.0/avr/config/lnktiny2313t.xcl' -l $(PROJECT).map -s main +LIBS = '/Program Files/IAR Systems/Embedded Workbench 5.0/avr/lib/clib/cl0t.r90' + +## Include Directories +INCLUDES = -I .. -I . -I '/Program Files/IAR Systems/Embedded Workbench 5.0/avr/inc' + +## Objects that must be built in order to link +OBJECTS = $(PROJECT).r90 + +## Build +all: $(TARGET) + +## Compile +$(PROJECT).r90: ../$(PROJECT).cpp + $(CC) $(INCLUDES) $(CFLAGS) $< + +##Link +$(TARGET): $(OBJECTS) + $(LD) $(LDFLAGS) $(OBJECTS) $(LIBDIRS) $(LIBS) -o $(TARGET) + +## Clean target +.PHONY: distclean +distclean: clean + @rm -f $(TARGET) $(PROJECT).lst $(PROJECT).map + +.PHONY: clean +clean: + @rm -f $(OBJECTS) diff --git a/iar_cpp_obj/Makefile b/iar_cpp_obj/Makefile new file mode 100644 index 0000000..c9ddf60 --- /dev/null +++ b/iar_cpp_obj/Makefile @@ -0,0 +1,42 @@ +############################################################################### +# Makefile for the serial_lcd C & CPP versions + +## General Flags +PROJECT = serial_lcd_obj +MCU = tiny2313 +TARGET = $(PROJECT).hex +CC = /Program Files/IAR Systems/Embedded Workbench 5.0/avr/bin/iccavr.exe +LD = /Program Files/IAR Systems/Embedded Workbench 5.0/avr/bin/xlink.exe + +## Compile options common for all C compilation units. +CFLAGS = --cpu $(MCU) -lA $(PROJECT).lst -z9 -e --ec++ --lock_regs 4 -D ENABLE_BIT_DEFINITIONS + +## Linker flags +LDFLAGS = -Fubrof9 -xm -xs -f '/Program Files/IAR Systems/Embedded Workbench 5.0/avr/config/lnktiny2313t.xcl' -l $(PROJECT).map -s main +LIBS = '/Program Files/IAR Systems/Embedded Workbench 5.0/avr/lib/clib/cl0t.r90' + +## Include Directories +INCLUDES = -I .. -I . -I '/Program Files/IAR Systems/Embedded Workbench 5.0/avr/inc' + +## Objects that must be built in order to link +OBJECTS = $(PROJECT).r90 + +## Build +all: $(TARGET) + +## Compile +$(PROJECT).r90: ../$(PROJECT).cpp + $(CC) $(INCLUDES) $(CFLAGS) $< + +##Link +$(TARGET): $(OBJECTS) + $(LD) $(LDFLAGS) $(OBJECTS) $(LIBDIRS) $(LIBS) -o $(TARGET) + +## Clean target +.PHONY: distclean +distclean: clean + @rm -f $(TARGET) $(PROJECT).lst $(PROJECT).map + +.PHONY: clean +clean: + @rm -f $(OBJECTS) diff --git a/icc_c/Makefile b/icc_c/Makefile new file mode 100644 index 0000000..dd575ab --- /dev/null +++ b/icc_c/Makefile @@ -0,0 +1,45 @@ +############################################################################### +# Makefile for the serial_lcd C & CPP versions + +## General Flags +PROJECT = serial_lcd +MCU = attiny2313 +TARGET = $(PROJECT).hex +CC = iccavr +OBJECTS = $(PROJECT).o + +## Compile options common for all C compilation units. +CFLAGS = -e -D__ICC_VERSION="7.16A" -DATtiny2313 -l -A -A -g -Wf-r20_23 + +## Linker flags +LDFLAGS = -g -e:0x0800 -bfunc_lit:0x26.0x800 -dram_end:0xdf -bdata:0x60.0xdf -dhwstk_size:30 -beeprom:0.128 -fihx_coff -S2 + +## Assembler flags +ASMFLAGS = $(CFLAGS) -Wa-g + +## Include Directories +INCLUDES = -I. + +## Objects explicitly added by the user +LINKONLYOBJECTS = + +## Build +all: $(TARGET) + +## Compile +$(PROJECT).o: ../serial_lcd.c + $(CC) -c $(CFLAGS) $(INCLUDES) $< + +$(TARGET): $(OBJECTS) + $(CC) -o SERIAL_LCD $(LDFLAGS) $(OBJECTS) -lcavrgr + +## Clean target +.PHONY: distclean +distclean: clean + @rm -f $(OBJECTS) $(TARGET) $(PROJECT).lst $(PROJECT).mp $(PROJECT).hex + +.PHONY: clean +clean: + @rm -f $(OBJECTS) $(PROJECT).dbg $(PROJECT).cof $(PROJECT).s \ + $(PROJECT).cof $(PROJECT).lis + diff --git a/serial_lcd.c b/serial_lcd.c new file mode 100644 index 0000000..0c8bb10 --- /dev/null +++ b/serial_lcd.c @@ -0,0 +1,478 @@ +/***************************************************************************** +** FILE IDENTIFICATION +** +** Name: serial_lcd.cpp +** Purpose: USART driven HD44780 LCD Driver +** Programmer: Kevin Rosenberg +** (AVR Freaks member kmr) +** Date Started: Dec 2007 +** +** Copyright (c) 2007-2008 by Kevin Rosenberg. All rights reserved. +** +** Compilers supported: +** - WinAVR-20071221 (includes avr-libc 1.6 required for proper _delay_us) +** - IAR AVR 4.30 +** - Imagecraft AVR 7 +** +** LICENSE +** See accompaning LICENSE file +** +** CHANGES +** See accompaning CHANGES file for modifications log from original +******************************************************************************/ + +#include "serial_lcd.h" + +#if defined(__GNUC__) +FUSES = { + .low = SUT1, + .high = (unsigned char) (DWEN & WDTON & RSTDISBL & BODLEVEL1 & BODLEVEL2), + .extended = EFUSE_DEFAULT, +}; +#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 +#if defined(__IMAGECRAFT__) +#pragma data:noinit +volatile unsigned char sUartRxBuf[UART_RX_BUFFER_SIZE]; +#pragma data:data +#else +NO_INIT_DECLARE(volatile unsigned char sUartRxBuf[UART_RX_BUFFER_SIZE]); +#endif + +// PWM Patterns (8-brightness levels) +static FLASH_DECLARE(const unsigned char ledPwmPatterns[]) = +{ + 0x10, // 0b00010000 0 + 0x11, // 0b00010001 1 + 0x4A, // 0b01001010 2 + 0x55, // 0b01010101 3 + 0x5D, // 0b01011101 4 + 0xEE, // 0b11101110 5 + 0x7F, // 0b11110111 6 + 0xFF, // 0b11111111 7 +}; + +// register variables +#if defined(__IMAGECRAFT__) +#pragma global_register ledPwmCount:20 sUartRxHead:21 sUartRxTail:22 ledPwmCycling:23 +unsigned char ledPwmCount, sUartRxHead, sUartRxTail, ledPwmCycling; + +#else +REGISTER_VAR(unsigned char ledPwmCount, "r4", 15); +REGISTER_VAR(unsigned char sUartRxHead, "r5", 14); +REGISTER_VAR(unsigned char sUartRxTail, "r6", 13); +REGISTER_VAR(unsigned char ledPwmCycling, "r7", 12); +#endif + +#define ledPwmPattern GPIOR0 +#define ledStatus GPIOR1 +#define BIT_led_on REGISTER_BIT(GPIOR1,0) + +// Function declarations +void LcdWriteCmd (unsigned char); +void LcdWriteData (unsigned char); +unsigned char LcdBusyWait (void); +static unsigned char WaitRxChar (void); + +// ImageCraft doesn't support inline functions, so use preprocessor +#if defined(__IMAGECRAFT__) +#define LedTimerStop() TCCR0B = 0 +// Start with 256 prescaler +#define LedTimerStart() TCCR0B = (1<> 8; + // Below is probably not required, but ensures we don't exceed array + if (ledPwmPos > LED_BRIGHTNESS_LEVELS - 1) + ledPwmPos = LED_BRIGHTNESS_LEVELS - 1; + + ledPwmPattern = PGM_READ_BYTE (&ledPwmPatterns[ledPwmPos]); + ledPwmCount = 0; + ledPwmCycling = ledPwmPattern; + if (ledPwmPos >= LED_BRIGHTNESS_LEVELS-1) { // maximum brightness + // don't need PWM for continuously on + if (BIT_led_on) { + LedTimerStop(); + LED_PORT |= (1<> BAUD_J1); + + return PGM_READ_BYTE (&BaudLookupTable[BaudSelectJumpersValue]); +} + + +INLINE_FUNC_DECLARE(static void UsartInit (void)); +static inline void UsartInit(void) { + // Initialize USART + UCSRB = 0; // Disable while setting baud rate + UCSRA = 0; + UCSRC = (1<= LED_BRIGHTNESS_LEVELS-1) { + ledPwmCount = 0; + ledPwmCycling = ledPwmPattern; + } else { + ledPwmCount++; + ledPwmCycling >>= 1; + } +} diff --git a/serial_lcd.h b/serial_lcd.h new file mode 100644 index 0000000..d02e589 --- /dev/null +++ b/serial_lcd.h @@ -0,0 +1,308 @@ +/***************************************************************************** +** FILE IDENTIFICATION +** +** Name: serial_lcd.h +** Purpose: Common header file for serial_lcd.c and serial_lcd.cpp +** Programmer: Kevin Rosenberg (AVR Freaks member kmr) +** Date Started: Dec 2007 +** +** Copyright (c) 2007-2008 by Kevin Rosenberg +*******************************************************************************/ + +#ifndef __SERIAL_LCD_H__ +#define __SERIAL_LCD_H__ 1 + +#ifndef F_CPU +#define F_CPU 14745600UL +#endif + +#define CONSERVATIVE_ENABLE_DURATION 0 +#define USE_CTS 0 + +// Set STANDALONE_SOURCE as 1 to compile without KMR's standard header files, using +// the below excerpts from these files +#define STANDALONE_SOURCE 1 +#if STANDALONE_SOURCE + +#if defined(__GNUC__) +#include +#include +#include +#include +#include +#include + +typedef struct +{ + unsigned bit0:1; + unsigned bit1:1; + unsigned bit2:1; + unsigned bit3:1; + unsigned bit4:1; + unsigned bit5:1; + unsigned bit6:1; + unsigned bit7:1; +} _io_reg; + +#define FLASH_DECLARE(x) const x __attribute__((progmem)) +#define NO_INIT_DECLARE(x) x __attribute__((section (".noinit"))) +#define INLINE_FUNC_DECLARE(x) inline x __attribute__((always_inline)) +#define PGM_READ_BYTE(x) pgm_read_byte(x) +#define NOP() asm volatile("nop"); +#define REGISTER_BIT(rg,bt) ((volatile _io_reg*)_SFR_MEM_ADDR(rg))->bit##bt +#define REGISTER_VAR(V,GNU,IAR) register volatile V asm(GNU) +#define NO_RETURN_FUNC(fn) fn __attribute__((noreturn)); \ +fn +#define MAIN_FUNC() int main(void) __attribute__((OS_main)); \ +int main(void) +#define MAIN_FUNC_LAST() return 0 + +#elif defined(__ICCAVR__) +#include +#include + +// Ensure that register/vector definitions match datasheet/GCC +#if defined(__ATtiny2313__) + #if !defined(WDTCSR) + #define WDTCSR WDTCR + #endif + #if defined(USART0_RX_vect) && !defined(USART_RX_vect) + #define USART_RX_vect USART0_RX_vect + #endif +#endif + +#define FLASH_DECLARE(x) __flash x +#define PRAGMA(x) _Pragma(#x) +#define NO_INIT_DECLARE(x) __no_init x +#define INLINE_FUNC_DECLARE(x) PRAGMA(inline=forced) \ +inline x +#define PGM_READ_BYTE(x) (*(x)) +#define NOP() __no_operation(); +#define REGISTER_BIT(rg,bt) rg##_Bit##bt +#define REGISTER_VAR(V,GNU,IAR) __regvar __no_init V @ ## IAR +#define ISR(x) PRAGMA(vector=x) \ +__interrupt void x##_handler(void); \ +__interrupt void x##_handler(void) +#define NO_RETURN_FUNC(fn) __C_task fn +#define MAIN_FUNC() __task void main(void) +#define MAIN_FUNC_LAST() +#define cli() __disable_interrupt() +#define sei() __enable_interrupt() +#define wdt_reset() __watchdog_reset() +#define _delay_us(us) __delay_cycles((unsigned long)(((us * F_CPU)/1e6) + 0.5)) +#define _delay_ms(ms) __delay_cycles((unsigned long)(((ms * F_CPU)/1e3) + 0.5)) +#define sleep_cpu() __sleep() +#if defined(__ATtiny2313__) +#define sleep_enable() MCUCR |= (1< +typedef struct { + unsigned bit0:1; + unsigned bit1:1; + unsigned bit2:1; + unsigned bit3:1; + unsigned bit4:1; + unsigned bit5:1; + unsigned bit6:1; + unsigned bit7:1; +} _io_reg; + +#define NOP() asm("nop"); +// ImageCraft does not support inline functions +#define inline +#define INLINE_FUNC_DECLARE(x) x +#define REGISTER_BIT(rg,bt) ((volatile _io_reg*)&rg)->bit##bt +#define NO_RETURN_FUNC(fn) fn +#define MAIN_FUNC() void main(void) +#define MAIN_FUNC_LAST() +// __flash keyword was introduced in Imagecraft v7.15 +#define FLASH_DECLARE(x) __flash x +#define PGM_READ_BYTE(x) (*(x)) +#define cli() asm("cli") +#define sei() asm("sei") +#define wdt_reset() asm("wdr") +#define sleep_cpu() asm("sleep") +// Below two definition specific for ATTiny2313 compatible sleep enable +#define sleep_enable() MCUCR |= (1< + +typedef struct { + unsigned bit0:1; + unsigned bit1:1; + unsigned bit2:1; + unsigned bit3:1; + unsigned bit4:1; + unsigned bit5:1; + unsigned bit6:1; + unsigned bit7:1; +} _io_reg; + +#define FLASH_DECLARE(x) flash x +#define ASM(a) asm(a) +#define NOP() asm("nop"); +#define inline +#define INLINE_FUNC_DECLARE(x) x +#define REGISTER_BIT(rg,bt) ((volatile _io_reg*)&rg)->bit##bt +#define NEAR_VAR(x) x +#define NO_RETURN_FUNC(fn) fn +#define MAIN_FUNC(fn) fn +#define MAIN_FUNC() void main(void) +#define MAIN_FUNC_LAST() + +// 2007/11/29 - ImageCraft states they will support _Pragma() like IAR +// in a "few months". At that point, REGISTER_VAR and NO_INIT_DECLARE can +// be supported. REGISTER_VAR will need to be expanded with 4th variable to +// hold register number for ImageCraft. +// noinit for ImageCraft requires #pragma data:noinit +//#define NO_INIT_DECLARE(x) _Pragma(data:noinit); x; _Pragma(data:data); +#define NO_INIT_DECLARE(x) x +//#define REGISTER_VAR(V,GNUR,IAR,ICC) _Pragma(global_register V ## : ## ICC) +#define REGISTER_VAR(V,GNUR,IAR) V + +#define cli() asm("cli") +#define sei() asm("sei") +#define wdt_reset() asm("wdr") + +#else +#error Unsupported compiler +#endif + +#else +// Use local cross-compiler compability files +#include "kavr_compat.h" +#include "ksleep.h" +#include "kdelay.h" +#endif + + +/*************************************************************/ +/*************************************************************/ + +/* //// 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 + + +// 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 defined(__ICCAVR__) + #if CONSERVATIVE_ENABLE_DURATION + #define ENABLE_WAIT() __delay_cycles(7); + #else + #define ENABLE_WAIT() __delay_cycles(4); + #endif +#elif defined(__GNUC__) + static __inline__ void _NOP1 (void) { __asm__ volatile ( "nop " "\n\t" ); } + static __inline__ void _NOP2 (void) { __asm__ volatile ( "rjmp 1f" "\n\t" "1:" "\n\t" ); } + #if CONSERVATIVE_ENABLE_DURATION + #define ENABLE_WAIT() _NOP2(); _NOP2(); _NOP2(); _NOP1(); + #else + #define ENABLE_WAIT() _NOP2(); _NOP2(); + #endif +#else + #if CONSERVATIVE_ENABLE_DURATION + #define ENABLE_WAIT() NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); + #else + #define ENABLE_WAIT() NOP(); NOP(); NOP(); NOP(); + #endif +#endif + +#endif diff --git a/serial_lcd_cpp.cpp b/serial_lcd_cpp.cpp new file mode 100644 index 0000000..b4f0171 --- /dev/null +++ b/serial_lcd_cpp.cpp @@ -0,0 +1,524 @@ +/***************************************************************************** +** FILE IDENTIFICATION +** +** Name: serial_lcd.cpp +** Purpose: Serial Backpack firmware with C++ methods (no member variables) +** Programmer: Kevin Rosenberg (AVR Freaks member kmr) +** Date Started: Dec 2007 (based on Jan 2, 2007 release by C.W. Livinston) +** +** Copyright (c) 2007-2008 by Kevin Rosenberg. All rights reserved. +** +** Compilers supported: +** - WinAVR-20071221 +** - IAR AVR 4.30 +** +** LICENSE +** See accompaning LICENSE file +** +** CHANGES +** See accompaning CHANGES file for modifications log from original +******************************************************************************/ + + +#include "serial_lcd.h" + +// register variables +REGISTER_VAR(unsigned char ledPwmCount, "r4", 15); +REGISTER_VAR(unsigned char sUartRxHead, "r5", 14); +REGISTER_VAR(unsigned char sUartRxTail, "r6", 13); +REGISTER_VAR(unsigned char ledPwmCycling, "r7", 12); + +#define ledPwmPattern GPIOR0 +#define ledStatus GPIOR1 +#define BIT_led_on REGISTER_BIT(GPIOR1,0) + +//// Classes with only static methods + +class Watchdog { +public: + INLINE_FUNC_DECLARE(static void init(void)) { + reset(); + WDTCSR |= (1<> 8; + // Below is probably not required, but ensures we don't exceed array + if (ledPwmPos > LED_BRIGHTNESS_LEVELS - 1) + ledPwmPos = LED_BRIGHTNESS_LEVELS - 1; + ledPwmPattern = pwmPattern(ledPwmPos); + ledPwmCount = 0; + ledPwmCycling = ledPwmPattern; + if (ledPwmPos >= LED_BRIGHTNESS_LEVELS-1) { // maximum brightness + // don't need PWM to continuously on + if (BIT_led_on) { + stop(); + lampOn(); + } + } else { + if (BIT_led_on) { + start(); + } + } + } + + INLINE_FUNC_DECLARE(void cyclePwm(void)) { + if (ledPwmCycling & 0x01) { // Set current LED state based on cycling variable + lampOn(); + } else { + lampOff(); + } + + // Update cycling variable for next interrupt + if (ledPwmCount >= LED_BRIGHTNESS_LEVELS-1) { + ledPwmCount = 0; + ledPwmCycling = ledPwmPattern; + } else { + ledPwmCount++; + ledPwmCycling >>= 1; + } + } + + INLINE_FUNC_DECLARE(void lampOn(void)) { +#if USE_LED_PWM_IO_MEMBERS + *m_LedPortPtr |= (1<> BAUD_J1); + + return PGM_READ_BYTE (&BaudLookupTable[BaudSelectJumpersValue]); + } + +public: + INLINE_FUNC_DECLARE(void init(void)) { + // Initialize UART0 + UCSRB = 0; // Disable while setting baud rate + UCSRA = 0; + UCSRC = (1< (AVR Freaks member kmr) +** Date Started: Dec 2007 +** +** Copyright (c) 2007-2008 by Kevin Rosenberg. All rights reserved. +** +** Compilers supported: +** - WinAVR-20071221 +** - IAR AVR 4.30 +** +** LICENSE +** See accompaning LICENSE file +** +** CHANGES +** See accompaning CHANGES file for modifications log from original +******************************************************************************/ + + +#include "serial_lcd.h" + +//// Classes with only static methods + +class Watchdog { +public: + INLINE_FUNC_DECLARE(static void init(void)) { + reset(); + WDTCSR |= (1<> 8; + // Below is probably not required, but ensures we don't exceed array + if (ledPwmPos > m_LED_BRIGHTNESS_LEVELS - 1) + ledPwmPos = m_LED_BRIGHTNESS_LEVELS - 1; + m_ledPwmPattern = pwmPattern(ledPwmPos); + m_ledPwmCount = 0; + m_ledPwmCycling = m_ledPwmPattern; + if (ledPwmPos >= m_LED_BRIGHTNESS_LEVELS-1) { // maximum brightness + // don't need PWM to continuously on + if (m_BIT_led_on) { + stop(); + lampOn(); + } + } else { + if (m_BIT_led_on) { + start(); + } + } + } + + INLINE_FUNC_DECLARE(void cyclePwm(void)) { + if (m_ledPwmCycling & 0x01) { // Set current LED state based on cycling variable + lampOn(); + } else { + lampOff(); + } + + // Update cycling variable for next interrupt + if (m_ledPwmCount >= m_LED_BRIGHTNESS_LEVELS-1) { + m_ledPwmCount = 0; + m_ledPwmCycling = m_ledPwmPattern; + } else { + m_ledPwmCount++; + m_ledPwmCycling >>= 1; + } + } + + INLINE_FUNC_DECLARE(void lampOn(void)) { + *m_LedPort |= (1<> 8; + } + + INLINE_FUNC_DECLARE(void rxEnable(void)) { + UCSRB |= (1<> BAUD_J1); + + return PGM_READ_BYTE (&BaudLookupTable[BaudSelectJumpersValue]); +} + + +Lcd gLcd; +LedPwm gLed; +Uart gUart; + +// This class has only static methods +class SerialCommandProcessor { +private: + // ASCII control code to set brightness level + // Next byte is brightness ranging from 0 (no backlight) to 255 (maximum) + static const unsigned char m_LED_SET_BRIGHTNESS = 0xFB; + // ASCII control code turns on LED + static const unsigned char m_LED_SW_ON = 0xFC; + // ASCII control code turns off LED + static const unsigned char m_LED_SW_OFF = 0xFD; + // Character generator RAM command + static const unsigned char m_REG_MODE = 0xFE; + +public: + INLINE_FUNC_DECLARE(static void processChar(unsigned char ch)) { + // avoid use of switch statement as ImageCraft and GCC produce signifcantly + // more code for a switch statement than a sequence of if/else if + if (ch == m_LED_SW_OFF) { + gLed.switchOff(); + } else if (ch == m_LED_SW_ON) { + gLed.switchOn(); + } else if (ch == m_LED_SET_BRIGHTNESS) { + // read next byte which will be brightness + gLed.setBrightness(gUart.waitRxChar()); + } else if (ch == m_REG_MODE) { + gLcd.putCmd (gUart.waitRxChar()); // Send LCD command character + } else { + gLcd.putChar (ch); // Send LCD data character + } + } +}; + + +MAIN_FUNC() { + MCUSR = 0; // clear all reset flags + Watchdog::init(); + + SleepMode::initIdleMode(); + + gUart.init(); // Initialize the AVR USART + gUart.setBaudDivisor(GetBaudDivisor()); + gUart.rxEnable(); + gUart.rxInterruptEnable(); + gLed.init(&LED_PORT, &LED_DIR, LED_PIN); + gLcd.init(&LCD_CONTROL_PORT, &LCD_CONTROL_DIR, &LCD_DATA_PORT, + &LCD_DATA_DIR, &LCD_DATA_PIN_REG, LCD_RS, LCD_RW, LCD_E); + + sei(); + while (1) { + if (gUart.charAvail()) { + SerialCommandProcessor::processChar (gUart.waitRxChar()); + } else { // No characters waiting in RX buffer + Watchdog::off(); + SleepMode::enterSleep(); + Watchdog::on(); + } + } + MAIN_FUNC_LAST(); +} + + +ISR(USART_RX_vect) { + gUart.storeChar(UDR); +} + +ISR(TIMER0_COMPA_vect) { + sei(); // Okay to allow USART interrupts while controlling LED PWM + gLed.cyclePwm(); +} diff --git a/tester/Makefile b/tester/Makefile new file mode 100644 index 0000000..d47ec19 --- /dev/null +++ b/tester/Makefile @@ -0,0 +1,13 @@ +tester := serial_lcd_tester +CC := gcc + +all: $(tester).exe + +$(tester).exe: $(tester).c + PATH=$(PATH}:/c/cygwin/bin $(CC) -O2 $(tester).c -o $(tester).exe + +clean: + @rm -f $(tester).exe $(tester).o *~ + +distclean: clean + diff --git a/tester/serial_lcd_tester.c b/tester/serial_lcd_tester.c new file mode 100644 index 0000000..3af60b4 --- /dev/null +++ b/tester/serial_lcd_tester.c @@ -0,0 +1,487 @@ +/****************************************************************************** + ** FILE IDENTIFICATION + ** Name: serial_lcd_tester.c + ** Purpose: Tests Serial_Lcd + ** Author: Kevin M. Rosenberg + ** Last Modification: March 2007 + ** + ** PLATFORM + ** Linux and Windows/Cygwin + ** + ** Custom character bitmaps by Carl W. Livingston + ******************************************************************************/ + +// Will likely need to change for your system and LCD display + +#define DEFAULT_PORT "/dev/com7" +static unsigned char lcdCols = 20; +static unsigned char lcdRows = 4; + +#include /* Standard input/output definitions */ +#include /* String function definitions */ +#include /* UNIX standard function definitions */ +#include /* File control definitions */ +#include /* Error number definitions */ +#include /* POSIX terminal control definitions */ +#include +#include +#include +#include + +void MakeCustomChar (const char *Symbol, char Address); +void delay_ms(unsigned int t); +void clear_display(void); +void display_banner(void); + +int open_serial_port (char const* const); +void close_serial_port (void); +void serial_puts (const char* str); +void serial_putc (const unsigned char c); +void run_test(void); + +static inline double get_time(void) { + struct timeval tv; + gettimeofday (&tv, NULL); + return tv.tv_sec + tv.tv_usec/1e6; +} + +// Integer delay_ms routine +// 65.535 seconds maximum +void delay_ms(unsigned int t) +{ + double start = get_time(); + double end = start + t/1000; + while (get_time() < end) {} +} + + +void usage(char const* const prog) { + fprintf(stderr, "usage: %s \n", basename(prog)); + fprintf(stderr, "Port name is in Cygwin format.\n"); + fprintf(stderr, "Example: COM1 would be /dev/com1\n"); +} + + +int main(int argc, char ** argv) { + char portName[30]; + portName[sizeof(portName)] = 0; // ensure string is zero-terminated by below strncpy + if (argc == 1) { + strncpy (portName, DEFAULT_PORT, sizeof(portName)-1); + fprintf (stderr, "Using default serial port of %s\n", portName); + } else if (argc == 2) { + strncpy (portName, argv[1], sizeof(portName)); + } else { + usage(argv[0]); + exit(1); + } + if (! open_serial_port (portName)) { + fprintf(stderr, "Unable to open serial port %s\n", portName); + return 1; + } + run_test(); + close_serial_port(); + return 0; +} + +// Serial_Lcd command delimiter +#define SERIAL_LCD_CMD_MODE 0xFE + +// Display clear text command +#define LCD_CLR_CMD 0x01 +// Display home cursor command +#define LCD_HOME_CMD 0x02 + +// Display entry mode command & parameters +#define LCD_ENTRY_CMD 0x04 +#define CURSOR_DIR 0x02 +#define CURSOR_MOVE 0x01 + +// Display control mode & parameters +#define LCD_CONTROL_CMD 0x08 +#define LCD_ON 0x04 +#define CURSOR_ON 0x02 +#define CURSOR_BLINK 0x01 + +// Display cursor control & parameters +#define LCD_CURSOR_CMD 0x10 +#define LCD_SHIFT 0x08 +#define DISPLAY_L_R 0x04 + +// Display line position addressing +#define LINE1_ADDR 0x80 +#define LINE2_ADDR 0xC0 +#define LINE3_ADDR 0x94 +#define LINE4_ADDR 0xD4 + +// Display data & character generator selection bits +#define DD_RAM 0x80 +#define CG_RAM 0x40 + +// Custom Character DDRAM location addressing +#define DDRAM_START_ADD_0 0x00 +#define DDRAM_START_ADD_1 0x01 +#define DDRAM_START_ADD_2 0x02 +#define DDRAM_START_ADD_3 0x03 +#define DDRAM_START_ADD_4 0x04 +#define DDRAM_START_ADD_5 0x05 +#define DDRAM_START_ADD_6 0x06 +#define DDRAM_START_ADD_7 0x07 + +// Custom Character CGRAM Starting addresses +#define CGRAM_START_ADD_0 0x40 +#define CGRAM_START_ADD_1 0x48 +#define CGRAM_START_ADD_2 0x50 +#define CGRAM_START_ADD_3 0x58 +#define CGRAM_START_ADD_4 0x60 +#define CGRAM_START_ADD_5 0x68 +#define CGRAM_START_ADD_6 0x70 +#define CGRAM_START_ADD_7 0x78 + +// ASCII control code (0xFB) to set LED brightness. +// Next byte sets brightness (from 0 to 255) +#define CMD_SET_BRIGHTNESS 0xFB +#define NUM_BRIGHTNESS_LEVELS 8 +#define BRIGHTNESS_SCALE(b) ((unsigned char) ((b * 254.) / (double) (NUM_BRIGHTNESS_LEVELS-1)) + 1) + +// ASCII control code (0xFC) turns on LED +#define LED_ON 0xFC +// ASCII control code (0xFD) turns on LED +#define LED_OFF 0xFD + +// Smiley face +const char Smiley_face[] = {// Smiley face + 0x0E, // 0b00001110, + 0x1F, // 0b00011111, + 0x00, // 0b00000000, + 0x0A, // 0b00001010, + 0x04, // 0b00000100, + 0x11, // 0b00010001, + 0x0E, // 0b00001110, + 0x00, // 0b00000000 +}; +const char Thin_cross[] = {// Thin cross + 0x11, // 0b00010001, + 0x00, // 0b00000000, + 0x1F, // 0b00011111, + 0x15, // 0b00010101, + 0x1B, // 0b00011011, + 0x0E, // 0b00001110, + 0x11, // 0b00010001, + 0x00, // 0b00000000 +}; +const char Thick_cross[] = {// Thick cross + 0x00, // 0b00000000, + 0x0E, // 0b00001110, + 0x1B, // 0b00011011, + 0x11, // 0b00010001, + 0x1B, // 0b00011011, + 0x0E, // 0b00001110, + 0x00, // 0b00000000, + 0x00, // 0b00000000 +}; +const char Music_note[] = {// Music note + 0x03, // 0b00000011, + 0x02, // 0b00000010, + 0x07, // 0b00000111, + 0x02, // 0b00000010, + 0x1E, // 0b00011110, + 0x12, // 0b00010010, + 0x1E, // 0b00011110, + 0x00, // 0b00000000 +}; +const char Loop_Antenna[] = {// Loop Antenna + 0x11, // 0b00010001, + 0x11, // 0b00010001, + 0x1F, // 0b00011111, + 0x15, // 0b00010101, + 0x15, // 0b00010101, + 0x04, // 0b00000100, + 0x0E, // 0b00001110, + 0x00, // 0b00000000 +}; +const char Lh_Yagi_Antenna[] = {// Lh Yagi Antenna + 0x10, // 0b00010000, + 0x14, // 0b00010100, + 0x15, // 0b00010101, + 0x1F, // 0b00011111, + 0x15, // 0b00010101, + 0x14, // 0b00010100, + 0x10, // 0b00010000, + 0x00, // 0b00000000 +}; +const char Diamond[] = {// Diamond + 0x00, // 0b00000000, + 0x1F, // 0b00011111, + 0x11, // 0b00010001, + 0x15, // 0b00010101, + 0x11, // 0b00010001, + 0x1F, // 0b00011111, + 0x00, // 0b00000000, + 0x00, // 0b00000000 +}; +const char Rh_Yagi_Antenna[] = {// Rh Yagi Antenna + 0x01, // 0b00000001, + 0x05, // 0b00000101, + 0x15, // 0b00010101, + 0x1F, // 0b00011111, + 0x15, // 0b00010101, + 0x05, // 0b00000101, + 0x01, // 0b00000001, + 0x00, // 0b00000000 +}; + +const char BannerMessage1[] = "Serial Lcd"; +const char BannerMessage2[] = "Tester By"; +const char BannerMessage3[] = "Kevin M. Rosenberg"; +const char BannerMessage4[] = "www.avrcode.com"; + +char led_on; +unsigned char brightness = NUM_BRIGHTNESS_LEVELS - 1; + +void run_test (void) { + double start_time = get_time(); + + delay_ms(40); // Ensure time for LCD to be ready + led_on = 0; + serial_putc (LED_OFF); // turn off the LED + + MakeCustomChar (Smiley_face, CGRAM_START_ADD_0); + MakeCustomChar (Lh_Yagi_Antenna, CGRAM_START_ADD_1); + MakeCustomChar (Diamond, CGRAM_START_ADD_2); + MakeCustomChar (Rh_Yagi_Antenna, CGRAM_START_ADD_3); + MakeCustomChar (Thin_cross, CGRAM_START_ADD_4); + MakeCustomChar (Thick_cross, CGRAM_START_ADD_5); + MakeCustomChar (Music_note, CGRAM_START_ADD_6); + MakeCustomChar (Loop_Antenna, CGRAM_START_ADD_7); + + // Put the banner message on the display + clear_display(); // Clear the display for the banner message + display_banner(); // Display the banner message + delay_ms(1000); // Display banner message for 1 seconds + + struct termios inopt; + funlockfile(stdin); +#ifdef __CYGWIN__ + tcgetattr(stdin->_file, &inopt); +#else + tcgetattr(stdin->_fileno, &inopt); +#endif + inopt.c_lflag &= ~ICANON; // non-canonical mode: no waiting on read + inopt.c_cc[VMIN] = 0; // minimum read characters + inopt.c_cc[VTIME] = 0; // timeout in deciseconds +#ifdef __CYGWIN__ + if (tcsetattr (stdin->_file, TCSANOW, &inopt) < 0) { +#else + if (tcsetattr (stdin->_fileno, TCSANOW, &inopt) < 0) { +#endif + fprintf(stderr, "Error setting stdin parameters (%d: %s)\n", + errno, strerror(errno)); + exit(1); + } + + clear_display(); // Clear the display for updating data + + while(1) { + char cntStr[20]; + serial_putc (SERIAL_LCD_CMD_MODE); // Put the LCD in command mode + serial_putc (LINE2_ADDR); // Set the LCD cursor position + double elapsed = get_time() - start_time; + snprintf(cntStr, sizeof(cntStr), "%.3lf", elapsed); + serial_puts (cntStr); + + // Write the custom characters to the display + serial_putc (SERIAL_LCD_CMD_MODE); // Put the LCD in command mode + serial_putc (LINE1_ADDR); // Set the LCD cursor position + serial_putc (DDRAM_START_ADD_0); // Display custom character 0 + serial_putc (DDRAM_START_ADD_1); // Display custom character 1 + serial_putc (DDRAM_START_ADD_2); // Display custom character 2 + serial_putc (DDRAM_START_ADD_3); // Display custom character 3 + serial_putc (DDRAM_START_ADD_4); // Display custom character 4 + serial_putc (DDRAM_START_ADD_5); // Display custom character 5 + serial_putc (DDRAM_START_ADD_6); // Display custom character 6 + serial_putc (DDRAM_START_ADD_7); // Display custom character 7 + + + char ch = getc_unlocked(stdin); + if (ch == 'l') { + if (led_on) { + serial_putc (LED_OFF); // Else, turn off the LED + led_on = 0; + } else { + serial_putc (LED_ON); // Turn on the LED + led_on = 1; + } + } else if (ch == 'b') { + if (brightness >= NUM_BRIGHTNESS_LEVELS - 1) + brightness = 0; + else + brightness++; + serial_putc (CMD_SET_BRIGHTNESS); + printf("%u(%u)", brightness, (unsigned int) BRIGHTNESS_SCALE(brightness)); + serial_putc (BRIGHTNESS_SCALE(brightness)); + } + } +} + +void MakeCustomChar (const char *Symbol, char Address) { + // Set up the custom characters + serial_putc (SERIAL_LCD_CMD_MODE); // Put the LCD in command mode + serial_putc (Address); // Set the display to CGRAM mode, address 0 + // Output the 8 bytes of the custom character + for (unsigned char i = 0; i < 8; i++) { + serial_putc (Symbol[n]); + } +} + +// Clear the display +void clear_display(void) +{ + serial_putc (SERIAL_LCD_CMD_MODE); // Put the LCD in command mode + serial_putc (LCD_CLR_CMD); // Send the clear the LCD display + delay_ms (30); // Wait for LCD controller to startup +} + +void tx_string_center (const char* str, unsigned char line_num) { + unsigned char pos; + switch (line_num) { + case 3: + pos = LINE4_ADDR; + break; + case 2: + pos = LINE3_ADDR; + break; + case 1: + pos = LINE2_ADDR; + break; + case 0: + default: + pos = LINE1_ADDR; + break; + } + + serial_putc (SERIAL_LCD_CMD_MODE); // Put the LCD in command mode + char offset = (lcdCols - strlen(str)) / 2; // offset to center line + if (offset < 0) + offset = 0; + serial_putc (pos + offset); // Set LCD cursor position + serial_puts (str); // Display string +} + +// Print the banner message +void display_banner(void) { + tx_string_center (BannerMessage1, 0); + tx_string_center (BannerMessage2, 1); + tx_string_center (BannerMessage3, 2); + tx_string_center (BannerMessage4, 3); +} + + +// Serial port section + +static int serialFd = -1; // serial port file descriptor + +int open_serial_port(char const* const port ) { + struct termios options; + int count,ret; + + serialFd = open (port, O_RDWR | O_NOCTTY | O_NONBLOCK); + if (serialFd == -1) + return 0; + + fcntl(serialFd, F_SETFL, 0); + + if (tcgetattr(serialFd, &options) < 0) { + fprintf(stderr, "Error reading serial port parameters (%d: %s)\n", + errno, strerror(errno)); + exit(1); + } + + cfsetispeed (&options, B115200); // 115200 baud + cfsetospeed (&options, B115200); // 115200 baud + + options.c_cflag |= (CLOCAL | CREAD); /* enable */ + options.c_cflag &= ~PARENB; // turn off parity + options.c_cflag &= ~CSTOPB; // one stop bit + options.c_cflag &= ~CSIZE; + options.c_cflag |= CS8; // 8-bit input + options.c_cflag &= ~CRTSCTS; // no flow control + + options.c_lflag &= ~ICANON; // non-canonical mode: no waiting on read + options.c_lflag &= ~ECHO; // Do not echo bytes written + options.c_lflag &= ~ECHOE; + options.c_lflag &= ~ECHONL; // Do not echo newline + options.c_lflag &= ~IEXTEN; // Disable implementation input processing + options.c_lflag &= ~ISIG; // Disable signal processing + + options.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INPCK | IXOFF + | INLCR | IGNCR | ICRNL | IXON | IXANY); + + options.c_oflag &= ~OPOST; // Disable implementation output processing + + options.c_cc[VMIN] = 0; // minimum read characters + options.c_cc[VTIME] = 0; // timeout in deciseconds + + /* set all of the options */ + tcflush(serialFd, TCIFLUSH); + if (tcsetattr (serialFd, TCSANOW, &options) < 0) { + fprintf(stderr, "Error setting serial port parameters (%d: %s)\n", + errno, strerror(errno)); + exit(1); + } + + // Verify settings + if (tcgetattr(serialFd, &options) < 0) { + fprintf(stderr, "Error to re-read serial port parameters (%d: %s)\n", + errno, strerror(errno)); + exit(1); + } + if (options.c_lflag & ICANON) { + fprintf(stderr, "Error: still in canonical serial mode\n"); + exit(1); + } + if (options.c_cc[VTIME] != 0) { + fprintf(stderr, "Error: VTIME does not equal 0, but is %d\n", options.c_cc[VTIME]); + exit(1); + } + if (options.c_cc[VMIN] != 0) { + fprintf(stderr, "Error: VMIN does not equal 0, but is %d\n", options.c_cc[VMIN]); + exit(1); + } + + + return 1; +} + +void close_serial_port(void) { + if (serialFd >= 0) { + close(serialFd); + serialFd = -1; + } +} + +void serial_puts (const char* str) { + int len = strlen(str); + int written = write (serialFd, str, len); + if (written < 0) { + fprintf (stderr, "Unable to write '%s' to fd %d, errno = %d (%s)\n", + str, serialFd, errno, strerror(errno)); + close (serialFd); + exit (1); + } else if (written != len) { + fprintf (stderr, "Unable to fully write '%s', %d bytes written\n", + str, written); + close (serialFd); + exit(1); + } +} + + +void serial_putc (const unsigned char c) { + int written = write (serialFd, &c, 1); + if (written < 0) { + fprintf (stderr, "Unable to write '%c' to fd %d, errno = %d (%s)\n", + c, serialFd, errno, strerror(errno)); + close (serialFd); + exit (1); + } +} -- 2.34.1