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