From a5518ce072f359ba3a41497c7a6504de3fb93c0f Mon Sep 17 00:00:00 2001 From: Giorgio Momigliano <gmomigliano@protonmail.com> Date: Thu, 21 May 2020 04:19:05 +0200 Subject: [PATCH] Game --- Makefile | 129 ++++++++++++++++++++ buttons.c | 59 +++++++++ buttons.h | 13 ++ lafortuna.sh | 43 +++++++ lib/README.md | 5 + lib/lcd/font.h | 104 ++++++++++++++++ lib/lcd/ili934x.h | 103 ++++++++++++++++ lib/lcd/lcd.c | 262 ++++++++++++++++++++++++++++++++++++++++ lib/lcd/lcd.h | 49 ++++++++ lib/led/led.c | 36 ++++++ lib/led/led.h | 14 +++ lib/rotary/rotary.c | 48 ++++++++ lib/rotary/rotary.h | 21 ++++ main.c | 287 ++++++++++++++++++++++++++++++++++++++++++++ main.h | 9 ++ 15 files changed, 1182 insertions(+) create mode 100644 Makefile create mode 100644 buttons.c create mode 100644 buttons.h create mode 100644 lafortuna.sh create mode 100644 lib/README.md create mode 100644 lib/lcd/font.h create mode 100644 lib/lcd/ili934x.h create mode 100644 lib/lcd/lcd.c create mode 100644 lib/lcd/lcd.h create mode 100644 lib/led/led.c create mode 100644 lib/led/led.h create mode 100644 lib/rotary/rotary.c create mode 100644 lib/rotary/rotary.h create mode 100644 main.c create mode 100644 main.h diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..ec3c0f4 --- /dev/null +++ b/Makefile @@ -0,0 +1,129 @@ +# Universal Makefile Version: 23.02.2016 +# +# Appears to work under Linux, OSX, and Cygwin/Windows. +# Under OSX it should be named "Makefile". +# +# Requires GNU 'make' and 'find'. + +# Target Architecture +BOARD := LaFortuna +MCU := at90usb1286 +F_CPU := 8000000UL + +# Tool Options +CFLAGS := -Os -mmcu=$(MCU) -DF_CPU=$(F_CPU) +# CFLAGS += -Wl,-u,vfprintf -lprintf_flt -lm # floating point support +CFLAGS += -fno-strict-aliasing # FATfs does not adhere to strict aliasing +CFLAGS += -Wno-main # main() will never return +CFLAGS += -Wall -Wextra -pedantic +CFLAGS += -Wstrict-overflow=5 -fstrict-overflow -Winline +CHKFLAGS := +# CHKFLAGS += -fsyntax-only +BUILD_DIR := _build + +# Ignoring hidden directories; sorting to drop duplicates: +CFILES := $(shell find . ! -path "*/\.*" -type f -name "*.c") +CPPFILES := $(shell find . ! -path "*/\.*" -type f -name "*.cpp") +CPATHS := $(sort $(dir $(CFILES))) +CPPATHS += $(sort $(dir $(CPPFILES))) +vpath %.c $(CPATHS) +vpath %.cpp $(CPPATHS) +HFILES := $(shell find . ! -path "*/\.*" -type f -name "*.h") +HPATHS := $(sort $(dir $(HFILES))) +vpath %.h $(HPATHS) +CFLAGS += $(addprefix -I ,$(HPATHS)) +DEPENDENCIES := $(patsubst %.c,$(BUILD_DIR)/%.d,$(notdir $(CFILES))) +DEPENDENCIES += $(patsubst %.cpp,$(BUILD_DIR)/%.d,$(notdir $(CPPILES))) +OBJFILES := $(patsubst %.c,$(BUILD_DIR)/%.o,$(notdir $(CFILES))) +OBJFILES += $(patsubst %.cpp,$(BUILD_DIR)/%.o,$(notdir $(CPPFILES))) + +.PHONY: upld prom clean check-syntax ? + +upld: $(BUILD_DIR)/main.hex + $(info ) + $(info =========== ${BOARD} =============) + dfu-programmer $(MCU) erase + dfu-programmer $(MCU) flash $(BUILD_DIR)/main.hex + dfu-programmer $(MCU) launch --no-reset # requires dfu-programmer >= v0.7.0 + +prom: $(BUILD_DIR)/main.eep upld + $(info ======== EEPROM: ${BOARD} ========) + dfu-programmer $(MCU) flash-eeprom $(BUILD_DIR)/main.eep + +$(BUILD_DIR)/%.o: %.c Makefile | $(BUILD_DIR) + @avr-gcc $(CFLAGS) -MMD -MP -c $< -o $@ + +$(BUILD_DIR)/%.o: %.cpp Makefile | $(BUILD_DIR) + @avr-g++ $(CFLAGS) -MMD -MP -c $< -o $@ + +$(BUILD_DIR)/%.elf %.elf: $(OBJFILES) + @avr-gcc -mmcu=$(MCU) -o $@ $^ + +$(BUILD_DIR)/%.hex %.hex: $(BUILD_DIR)/%.elf + @avr-objcopy -R .eeprom -R .fuse -R .lock -R .signature -O ihex $< "$@" + +$(BUILD_DIR)/%.eep %.eep: $(BUILD_DIR)/%.elf + @avr-objcopy -j .eeprom --change-section-lma .eeprom=0 -O ihex $< "$@" + + +-include $(sort $(DEPENDENCIES)) + +$(BUILD_DIR): + @mkdir -p $(BUILD_DIR) + +# Emacs flymake support +check-syntax: + @avr-gcc $(CFLAGS) $(CHKFLAGS) -o /dev/null -S $(CHK_SOURCES) + +clean: + @$(RM) -rf $(BUILD_DIR) + +?%: + @echo '$*=$($*)' + +?: + $(info -------------------------------------------------) + $(info Usage:) + $(info Source files can be grouped into subdirectories.) + $(info To build an executable and attempt to upload it,) + $(info use just "make". If the executable requires EEPROM) + $(info initialization, use "make prom".) + $(info ) + $(info make mymain.hex --> to build a hex-file for mymain.c) + $(info make mymain.eep --> for an EEPROM file for mymain.c) + $(info make mymain.elf --> for an elf-file for mymain.c) + $(info make ?CFILES --> show C source files to be used) + $(info make ?CPPFILES --> show C++ source files to be used) + $(info make ?HFILES --> show header files found) + $(info make ?HPATHS --> show header locations) + $(info make ?CFLAGS --> show compiler options) + $(info ) + $(info See the Makefile for more variables that can be) + $(info displayed as above.) + $(info -------------------------------------------------) + @: + + +# The MIT License (MIT) +# +# Copyright (c) 2014-2015 Klaus-Peter Zauner +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# +#=================================================================== diff --git a/buttons.c b/buttons.c new file mode 100644 index 0000000..309f7aa --- /dev/null +++ b/buttons.c @@ -0,0 +1,59 @@ +// +// Created by platelminto on 2/11/20. +// Is one of the buttons pressed (only triggers once per press) + +#include <avr/io.h> +#include "lib/rotary/rotary.h" + +int up_pressed = 0; +int right_pressed = 0; +int down_pressed = 0; +int left_pressed = 0; + +int is_up_pressed() { + if (!up_pressed && !((PINC >> SWN) & 1)) { + up_pressed = 1; + return 1; + } else if (!((PINC >> SWN) & 1)) { + return 0; + } else { + up_pressed = 0; + return 0; + } +} + +int is_right_pressed() { + if (!right_pressed && !((PINC >> SWE) & 1)) { + right_pressed = 1; + return 1; + } else if (!((PINC >> SWE) & 1)) { + return 0; + } else { + right_pressed = 0; + return 0; + } +} + +int is_down_pressed() { + if (!down_pressed && !((PINC >> SWS) & 1)) { + down_pressed = 1; + return 1; + } else if (!((PINC >> SWS) & 1)) { + return 0; + } else { + down_pressed = 0; + return 0; + } +} + +int is_left_pressed() { + if (!left_pressed && !((PINC >> SWW) & 1)) { + left_pressed = 1; + return 1; + } else if (!((PINC >> SWW) & 1)) { + return 0; + } else { + left_pressed = 0; + return 0; + } +} \ No newline at end of file diff --git a/buttons.h b/buttons.h new file mode 100644 index 0000000..a52bc4c --- /dev/null +++ b/buttons.h @@ -0,0 +1,13 @@ +// +// Created by platelminto on 2/11/20. +// + +#ifndef TESTING_BUTTONS_H +#define TESTING_BUTTONS_H + +#endif //TESTING_BUTTONS_H + +int is_up_pressed(void); +int is_right_pressed(void); +int is_down_pressed(void); +int is_left_pressed(void); diff --git a/lafortuna.sh b/lafortuna.sh new file mode 100644 index 0000000..71647e0 --- /dev/null +++ b/lafortuna.sh @@ -0,0 +1,43 @@ +#!/bin/bash + +#Arguments: flag and file +FLAG=$1 +FILE=$2 +FILE_HEAD=$(echo $FILE | cut -f1 -d".") + +case $FLAG in + -hex) + echo "Compiling file '$FILE' and creating hex object:" + avr-gcc -mmcu=at90usb1286 -DF_CPU=8000000 -Wall -Os $FILE -o $FILE_HEAD.elf + avr-objcopy -O ihex $FILE_HEAD.elf $FILE_HEAD.hex + + echo "DONE. Flash using flag -load" + ;; + -load) + echo "Flashing hex program '$FILE' to board:" + dfu-programmer at90usb1286 erase + dfu-programmer at90usb1286 flash $FILE_HEAD.hex + dfu-programmer at90usb1286 reset + + echo "DONE. Restart your LaFortuna board." + ;; + -all) + echo "Compiling file '$FILE' and creating hex object:" + avr-gcc -mmcu=at90usb1286 -DF_CPU=8000000 -Wall -Os $FILE -o $FILE_HEAD.elf + avr-objcopy -O ihex $FILE_HEAD.elf $FILE_HEAD.hex + + echo "Flashing hex program '$FILE_HEAD' to board:" + dfu-programmer at90usb1286 erase + dfu-programmer at90usb1286 flash $FILE_HEAD.hex + dfu-programmer at90usb1286 reset + + echo "Delete temporary files" + rm $FILE_HEAD.elf + rm $FILE_HEAD.hex + + echo "DONE. Power cycle your LaFortuna board." + ;; + -info) + echo "------Compile & Flash script for LaFortuna------" + echo "--Adapted from ak6g12's script by ec6g13 2015--" +esac diff --git a/lib/README.md b/lib/README.md new file mode 100644 index 0000000..3459092 --- /dev/null +++ b/lib/README.md @@ -0,0 +1,5 @@ +# Libraries for the La Fortuna # + +* `lcd`: LCD display library - Steve Gunn +* `led`: LED utility library - Steve Gunn +* `rotary`: Rotary encoder utility library - Steve Gunn diff --git a/lib/lcd/font.h b/lib/lcd/font.h new file mode 100644 index 0000000..3f0a7c8 --- /dev/null +++ b/lib/lcd/font.h @@ -0,0 +1,104 @@ +/* Author: Steve Gunn + * Licence: This work is licensed under the Creative Commons Attribution License. + * View this license at http://creativecommons.org/about/licenses/ + */ + +#include <avr/pgmspace.h> + +const char font5x7[] PROGMEM = { + 0x00, 0x00, 0x00, 0x00, 0x00, // SPACE + 0x00, 0x00, 0x5F, 0x00, 0x00, // ! + 0x00, 0x03, 0x00, 0x03, 0x00, // " + 0x14, 0x3E, 0x14, 0x3E, 0x14, // # + 0x24, 0x2A, 0x7F, 0x2A, 0x12, // $ + 0x43, 0x33, 0x08, 0x66, 0x61, // % + 0x36, 0x49, 0x55, 0x22, 0x50, // & + 0x00, 0x05, 0x03, 0x00, 0x00, // ' + 0x00, 0x1C, 0x22, 0x41, 0x00, // ( + 0x00, 0x41, 0x22, 0x1C, 0x00, // ) + 0x14, 0x08, 0x3E, 0x08, 0x14, // * + 0x08, 0x08, 0x3E, 0x08, 0x08, // + + 0x00, 0x50, 0x30, 0x00, 0x00, // , + 0x08, 0x08, 0x08, 0x08, 0x08, // - + 0x00, 0x60, 0x60, 0x00, 0x00, // . + 0x20, 0x10, 0x08, 0x04, 0x02, // / + 0x3E, 0x51, 0x49, 0x45, 0x3E, // 0 + 0x00, 0x04, 0x02, 0x7F, 0x00, // 1 + 0x42, 0x61, 0x51, 0x49, 0x46, // 2 + 0x22, 0x41, 0x49, 0x49, 0x36, // 3 + 0x18, 0x14, 0x12, 0x7F, 0x10, // 4 + 0x27, 0x45, 0x45, 0x45, 0x39, // 5 + 0x3E, 0x49, 0x49, 0x49, 0x32, // 6 + 0x01, 0x01, 0x71, 0x09, 0x07, // 7 + 0x36, 0x49, 0x49, 0x49, 0x36, // 8 + 0x26, 0x49, 0x49, 0x49, 0x3E, // 9 + 0x00, 0x36, 0x36, 0x00, 0x00, // : + 0x00, 0x56, 0x36, 0x00, 0x00, // ; + 0x08, 0x14, 0x22, 0x41, 0x00, // < + 0x14, 0x14, 0x14, 0x14, 0x14, // = + 0x00, 0x41, 0x22, 0x14, 0x08, // > + 0x02, 0x01, 0x51, 0x09, 0x06, // ? + 0x3E, 0x41, 0x59, 0x55, 0x5E, // @ + 0x7E, 0x09, 0x09, 0x09, 0x7E, // A + 0x7F, 0x49, 0x49, 0x49, 0x36, // B + 0x3E, 0x41, 0x41, 0x41, 0x22, // C + 0x7F, 0x41, 0x41, 0x41, 0x3E, // D + 0x7F, 0x49, 0x49, 0x49, 0x41, // E + 0x7F, 0x09, 0x09, 0x09, 0x01, // F + 0x3E, 0x41, 0x41, 0x49, 0x3A, // G + 0x7F, 0x08, 0x08, 0x08, 0x7F, // H + 0x00, 0x41, 0x7F, 0x41, 0x00, // I + 0x30, 0x40, 0x40, 0x40, 0x3F, // J + 0x7F, 0x08, 0x14, 0x22, 0x41, // K + 0x7F, 0x40, 0x40, 0x40, 0x40, // L + 0x7F, 0x02, 0x0C, 0x02, 0x7F, // M + 0x7F, 0x02, 0x04, 0x08, 0x7F, // N + 0x3E, 0x41, 0x41, 0x41, 0x3E, // O + 0x7F, 0x09, 0x09, 0x09, 0x06, // P + 0x1E, 0x21, 0x21, 0x21, 0x5E, // Q + 0x7F, 0x09, 0x09, 0x09, 0x76, // R + 0x26, 0x49, 0x49, 0x49, 0x32, // S + 0x01, 0x01, 0x7F, 0x01, 0x01, // T + 0x3F, 0x40, 0x40, 0x40, 0x3F, // U + 0x1F, 0x20, 0x40, 0x20, 0x1F, // V + 0x7F, 0x20, 0x10, 0x20, 0x7F, // W + 0x41, 0x22, 0x1C, 0x22, 0x41, // X + 0x07, 0x08, 0x70, 0x08, 0x07, // Y + 0x61, 0x51, 0x49, 0x45, 0x43, // Z + 0x00, 0x7F, 0x41, 0x00, 0x00, // [ + 0x02, 0x04, 0x08, 0x10, 0x20, // slash + 0x00, 0x00, 0x41, 0x7F, 0x00, // ] + 0x04, 0x02, 0x01, 0x02, 0x04, // ^ + 0x40, 0x40, 0x40, 0x40, 0x40, // _ + 0x00, 0x01, 0x02, 0x04, 0x00, // ` + 0x20, 0x54, 0x54, 0x54, 0x78, // a + 0x7F, 0x44, 0x44, 0x44, 0x38, // b + 0x38, 0x44, 0x44, 0x44, 0x44, // c + 0x38, 0x44, 0x44, 0x44, 0x7F, // d + 0x38, 0x54, 0x54, 0x54, 0x18, // e + 0x04, 0x04, 0x7E, 0x05, 0x05, // f + 0x08, 0x54, 0x54, 0x54, 0x3C, // g + 0x7F, 0x08, 0x04, 0x04, 0x78, // h + 0x00, 0x44, 0x7D, 0x40, 0x00, // i + 0x20, 0x40, 0x44, 0x3D, 0x00, // j + 0x7F, 0x10, 0x28, 0x44, 0x00, // k + 0x00, 0x41, 0x7F, 0x40, 0x00, // l + 0x7C, 0x04, 0x78, 0x04, 0x78, // m + 0x7C, 0x08, 0x04, 0x04, 0x78, // n + 0x38, 0x44, 0x44, 0x44, 0x38, // o + 0x7C, 0x14, 0x14, 0x14, 0x08, // p + 0x08, 0x14, 0x14, 0x14, 0x7C, // q + 0x00, 0x7C, 0x08, 0x04, 0x04, // r + 0x48, 0x54, 0x54, 0x54, 0x20, // s + 0x04, 0x04, 0x3F, 0x44, 0x44, // t + 0x3C, 0x40, 0x40, 0x20, 0x7C, // u + 0x1C, 0x20, 0x40, 0x20, 0x1C, // v + 0x3C, 0x40, 0x30, 0x40, 0x3C, // w + 0x44, 0x28, 0x10, 0x28, 0x44, // x + 0x0C, 0x50, 0x50, 0x50, 0x3C, // y + 0x44, 0x64, 0x54, 0x4C, 0x44, // z + 0x00, 0x08, 0x36, 0x41, 0x41, // { + 0x00, 0x00, 0x7F, 0x00, 0x00, // | + 0x41, 0x41, 0x36, 0x08, 0x00, // } + 0x02, 0x01, 0x02, 0x04, 0x02};// ~ + diff --git a/lib/lcd/ili934x.h b/lib/lcd/ili934x.h new file mode 100644 index 0000000..6629497 --- /dev/null +++ b/lib/lcd/ili934x.h @@ -0,0 +1,103 @@ +/* Author: Steve Gunn + * Licence: This work is licensed under the Creative Commons Attribution License. + * View this license at http://creativecommons.org/about/licenses/ + */ + +#define BLC 4 +#define RESET 7 + +#define CMD_ADDR 0x4000 +#define DATA_ADDR 0x4100 + +#define write_cmd(cmd) asm volatile("sts %0,%1" :: "i" (CMD_ADDR), "r" (cmd) : "memory"); +#define write_data(data) asm volatile("sts %0,%1" :: "i" (DATA_ADDR), "r" (data) : "memory"); +#define write_data16(data) asm volatile("sts %0,%B1 \n\t sts %0,%A1" :: "i" (DATA_ADDR), "r" (data) : "memory"); +#define write_cmd_data(cmd, data) asm volatile("sts %0,%1 \n\t sts %2,%3" :: "i" (CMD_ADDR), "r" (cmd), "i" (DATA_ADDR), "r" (data) : "memory"); + +/* Basic Commands */ +#define NO_OPERATION 0x00 +#define SOFTWARE_RESET 0x01 +#define READ_DISPLAY_IDENTIFICATION_INFORMATION 0x04 +#define READ_DISPLAY_STATUS 0x09 +#define READ_DISPLAY_POWER_MODE 0x0A +#define READ_DISPLAY_MADCTL 0x0B +#define READ_DISPLAY_PIXEL_FORMAT 0x0C +#define READ_DISPLAY_IMAGE_FORMAT 0x0D +#define READ_DISPLAY_SIGNAL_MODE 0x0E +#define READ_DISPLAY_SELF_DIAGNOSTIC_RESULT 0x0F +#define ENTER_SLEEP_MODE 0x10 +#define SLEEP_OUT 0x11 +#define PARTIAL_MODE_ON 0x12 +#define NORMAL_DISPLAY_MODE_ON 0x13 +#define DISPLAY_INVERSION_OFF 0x20 +#define DISPLAY_INVERSION_ON 0x21 +#define GAMMA_SET 0x26 +#define DISPLAY_OFF 0x28 +#define DISPLAY_ON 0x29 +#define COLUMN_ADDRESS_SET 0x2A +#define PAGE_ADDRESS_SET 0x2B +#define MEMORY_WRITE 0x2C +#define COLOR_SET 0x2D +#define MEMORY_READ 0x2E +#define PARTIAL_AREA 0x30 +#define VERTICAL_SCROLLING_DEFINITION 0x33 +#define TEARING_EFFECT_LINE_OFF 0x34 +#define TEARING_EFFECT_LINE_ON 0x35 +#define MEMORY_ACCESS_CONTROL 0x36 +#define VERTICAL_SCROLLING_START_ADDRESS 0x37 +#define IDLE_MODE_OFF 0x38 +#define IDLE_MODE_ON 0x39 +#define PIXEL_FORMAT_SET 0x3A +#define WRITE_MEMORY_CONTINUE 0x3C +#define READ_MEMORY_CONTINUE 0x3E +#define SET_TEAR_SCANLINE 0x44 +#define GET_SCANLINE 0x45 +#define WRITE_DISPLAY_BRIGHTNESS 0x51 +#define READ_DISPLAY_BRIGHTNESS 0x52 +#define WRITE_CTRL_DISPLAY 0x53 +#define READ_CTRL_DISPLAY 0x54 +#define WRITE_CONTENT_ADAPTIVE_BRIGHTNESS_CONTROL 0x55 +#define READ_CONTENT_ADAPTIVE_BRIGHTNESS_CONTROL 0x56 +#define WRITE_CABC_MINIMUM_BRIGHTNESS 0x5E +#define READ_CABC_MINIMUM_BRIGHTNESS 0x5F +#define READ_ID1 0xDA +#define READ_ID2 0xDB +#define READ_ID3 0xDC + +/* Extended Commands */ +#define RGB_INTERFACE_SIGNAL_CONTROL 0xB0 +#define FRAME_CONTROL_IN_NORMAL_MODE 0xB1 +#define FRAME_CONTROL_IN_IDLE_MODE 0xB2 +#define FRAME_CONTROL_IN_PARTIAL_MODE 0xB3 +#define DISPLAY_INVERSION_CONTROL 0xB4 +#define BLANKING_PORCH_CONTROL 0xB5 +#define DISPLAY_FUNCTION_CONTROL 0xB6 +#define ENTRY_MODE_SET 0xB7 +#define BACKLIGHT_CONTROL_1 0xB8 +#define BACKLIGHT_CONTROL_2 0xB9 +#define BACKLIGHT_CONTROL_3 0xBA +#define BACKLIGHT_CONTROL_4 0xBB +#define BACKLIGHT_CONTROL_5 0xBC +#define BACKLIGHT_CONTROL_7 0xBE +#define BACKLIGHT_CONTROL_8 0xBF +#define POWER_CONTROL_1 0xC0 +#define POWER_CONTROL_2 0xC1 +#define POWER_CONTROL3_(FOR_NORMAL_MODE) 0xC2 +#define POWER_CONTROL4_(FOR_IDLE_MODE) 0xC3 +#define POWER_CONTROL5_(FOR_PARTIAL_MODE) 0xC4 +#define VCOM_CONTROL_1 0xC5 +#define VCOM_CONTROL_2 0xC7 +#define NV_MEMORY_WRITE 0xD0 +#define NV_MEMORY_PROTECTION_KEY 0xD1 +#define NV_MEMORY_STATUS_READ 0xD2 +#define READ_ID4 0xD3 +#define POSITIVE_GAMM_CORRECTION 0xE0 +#define NEGATIVE_GAMMA_CORRECTION 0xE1 +#define DIGITAL_GAMMA_CONTROL 0xE2 +#define DIGITAL_GAMMA_CONTROL2 0xE3 +#define INTERFACE_CONTROL 0xF6 + +/* Undocumented commands */ +#define INTERNAL_IC_SETTING 0xCB +#define GAMMA_DISABLE 0xF2 + diff --git a/lib/lcd/lcd.c b/lib/lcd/lcd.c new file mode 100644 index 0000000..3eaf9cf --- /dev/null +++ b/lib/lcd/lcd.c @@ -0,0 +1,262 @@ +/* Author: Steve Gunn + * Licence: This work is licensed under the Creative Commons Attribution License. + * View this license at http://creativecommons.org/about/licenses/ + * + * + * - Jan 2015 Modified for LaFortuna (Rev A, black edition) [KPZ] + */ + +#include <avr/io.h> +#include <avr/interrupt.h> +#include <util/delay.h> +#include "font.h" +#include "ili934x.h" +#include "lcd.h" + +lcd display; + +void init_lcd() +{ + /* Enable extended memory interface with 10 bit addressing */ + XMCRB = _BV(XMM2) | _BV(XMM1); + XMCRA = _BV(SRE); + DDRC |= _BV(RESET); + DDRB |= _BV(BLC); + _delay_ms(1); + PORTC &= ~_BV(RESET); + _delay_ms(20); + PORTC |= _BV(RESET); + _delay_ms(120); + write_cmd(DISPLAY_OFF); + write_cmd(SLEEP_OUT); + _delay_ms(60); + write_cmd_data(INTERNAL_IC_SETTING, 0x01); + write_cmd(POWER_CONTROL_1); + write_data16(0x2608); + write_cmd_data(POWER_CONTROL_2, 0x10); + write_cmd(VCOM_CONTROL_1); + write_data16(0x353E); + write_cmd_data(VCOM_CONTROL_2, 0xB5); + write_cmd_data(INTERFACE_CONTROL, 0x01); + write_data16(0x0000); + write_cmd_data(PIXEL_FORMAT_SET, 0x55); /* 16bit/pixel */ + set_orientation(West); + clear_screen(); + display.x = 0; + display.y = 0; + display.background = BLACK; + display.foreground = WHITE; + write_cmd(DISPLAY_ON); + _delay_ms(50); + write_cmd_data(TEARING_EFFECT_LINE_ON, 0x00); + EICRB |= _BV(ISC61); + PORTB |= _BV(BLC); +} + +void lcd_brightness(uint8_t i) +{ + /* Configure Timer 2 Fast PWM Mode 3 */ + TCCR2A = _BV(COM2A1) | _BV(WGM21) | _BV(WGM20); + TCCR2B = _BV(CS20); + OCR2A = i; +} + +void set_orientation(orientation o) +{ + display.orient = o; + write_cmd(MEMORY_ACCESS_CONTROL); + if (o==North) { + display.width = LCDWIDTH; + display.height = LCDHEIGHT; + write_data(0x48); + } + else if (o==West) { + display.width = LCDHEIGHT; + display.height = LCDWIDTH; + write_data(0xE8); + } + else if (o==South) { + display.width = LCDWIDTH; + display.height = LCDHEIGHT; + write_data(0x88); + } + else if (o==East) { + display.width = LCDHEIGHT; + display.height = LCDWIDTH; + write_data(0x28); + } + write_cmd(COLUMN_ADDRESS_SET); + write_data16(0); + write_data16(display.width-1); + write_cmd(PAGE_ADDRESS_SET); + write_data16(0); + write_data16(display.height-1); +} + + + +void set_frame_rate_hz(uint8_t f) +{ + uint8_t diva, rtna, period; + if (f>118) + f = 118; + if (f<8) + f = 8; + if (f>60) { + diva = 0x00; + } else if (f>30) { + diva = 0x01; + } else if (f>15) { + diva = 0x02; + } else { + diva = 0x03; + } + /* !!! FIXME !!! [KPZ-30.01.2015] */ + /* Check whether this works for diva > 0 */ + /* See ILI9341 datasheet, page 155 */ + period = 1920.0/f; + rtna = period >> diva; + write_cmd(FRAME_CONTROL_IN_NORMAL_MODE); + write_data(diva); + write_data(rtna); +} + +void fill_rectangle(rectangle r, uint16_t col) +{ + write_cmd(COLUMN_ADDRESS_SET); + write_data16(r.left); + write_data16(r.right); + write_cmd(PAGE_ADDRESS_SET); + write_data16(r.top); + write_data16(r.bottom); + write_cmd(MEMORY_WRITE); +/* uint16_t x, y; + for(x=r.left; x<=r.right; x++) + for(y=r.top; y<=r.bottom; y++) + write_data16(col); +*/ + uint16_t wpixels = r.right - r.left + 1; + uint16_t hpixels = r.bottom - r.top + 1; + uint8_t mod8, div8; + uint16_t odm8, odd8; + if (hpixels > wpixels) { + mod8 = hpixels & 0x07; + div8 = hpixels >> 3; + odm8 = wpixels*mod8; + odd8 = wpixels*div8; + } else { + mod8 = wpixels & 0x07; + div8 = wpixels >> 3; + odm8 = hpixels*mod8; + odd8 = hpixels*div8; + } + uint8_t pix1 = odm8 & 0x07; + while(pix1--) + write_data16(col); + + uint16_t pix8 = odd8 + (odm8 >> 3); + while(pix8--) { + write_data16(col); + write_data16(col); + write_data16(col); + write_data16(col); + write_data16(col); + write_data16(col); + write_data16(col); + write_data16(col); + } +} + +void fill_rectangle_indexed(rectangle r, uint16_t* col) +{ + uint16_t x, y; + write_cmd(COLUMN_ADDRESS_SET); + write_data16(r.left); + write_data16(r.right); + write_cmd(PAGE_ADDRESS_SET); + write_data16(r.top); + write_data16(r.bottom); + write_cmd(MEMORY_WRITE); + for(x=r.left; x<=r.right; x++) + for(y=r.top; y<=r.bottom; y++) + write_data16(*col++); +} + +void clear_screen() +{ + display.x = 0; + display.y = 0; + rectangle r = {0, display.width-1, 0, display.height-1}; + fill_rectangle(r, display.background); +} + +void display_char(char c) +{ + uint16_t x, y; + PGM_P fdata; + uint8_t bits, mask; + uint16_t sc=display.x, ec=display.x + 4, sp=display.y, ep=display.y + 7; + + /* New line starts a new line, or if the end of the + display has been reached, clears the display. + */ + if (c == '\n') { + display.x=0; display.y+=8; + if (display.y >= display.height) { clear_screen(); } + return; + } + + if (c < 32 || c > 126) return; + fdata = (c - ' ')*5 + font5x7; + write_cmd(PAGE_ADDRESS_SET); + write_data16(sp); + write_data16(ep); + for(x=sc; x<=ec; x++) { + write_cmd(COLUMN_ADDRESS_SET); + write_data16(x); + write_data16(x); + write_cmd(MEMORY_WRITE); + bits = pgm_read_byte(fdata++); + for(y=sp, mask=0x01; y<=ep; y++, mask<<=1) + write_data16((bits & mask) ? display.foreground : display.background); + } + write_cmd(COLUMN_ADDRESS_SET); + write_data16(x); + write_data16(x); + write_cmd(MEMORY_WRITE); + for(y=sp; y<=ep; y++) + write_data16(display.background); + + display.x += 6; + if (display.x >= display.width) { display.x=0; display.y+=8; } +} + +void display_string(char *str) +{ + uint8_t i; + for(i=0; str[i]; i++) + display_char(str[i]); +} + +void display_string_xy(char *str, uint16_t x, uint16_t y) +{ + uint8_t i; + display.x = x; + display.y = y; + for(i=0; str[i]; i++) + display_char(str[i]); +} + +void display_register(uint8_t reg) +{ + uint8_t i; + + for(i = 0; i < 8; i++) { + if((reg & (_BV(7) >> i)) != 0) { + display_char( '1' ); + } else { + display_char( '.' ); + } + } +} + diff --git a/lib/lcd/lcd.h b/lib/lcd/lcd.h new file mode 100644 index 0000000..7366346 --- /dev/null +++ b/lib/lcd/lcd.h @@ -0,0 +1,49 @@ +/* Author: Steve Gunn + * Licence: This work is licensed under the Creative Commons Attribution License. + * View this license at http://creativecommons.org/about/licenses/ + */ + +#include <avr/io.h> +#include <stdint.h> + + +#define LCDWIDTH 240 +#define LCDHEIGHT 320 + +/* Colour definitions RGB565 */ +#define WHITE 0xFFFF +#define BLACK 0x0000 +#define BLUE 0x001F +#define GREEN 0x07E0 +#define CYAN 0x07FF +#define RED 0xF800 +#define MAGENTA 0xF81F +#define YELLOW 0xFFE0 + +typedef enum {North, West, South, East} orientation; + +typedef struct { + uint16_t width, height; + orientation orient; + uint16_t x, y; + uint16_t foreground, background; +} lcd; + +extern lcd display; + +typedef struct { + uint16_t left, right; + uint16_t top, bottom; +} rectangle; + +void init_lcd(); +void lcd_brightness(uint8_t i); +void set_orientation(orientation o); +void set_frame_rate_hz(uint8_t f); +void clear_screen(); +void fill_rectangle(rectangle r, uint16_t col); +void fill_rectangle_indexed(rectangle r, uint16_t* col); +void display_char(char c); +void display_string(char *str); +void display_string_xy(char *str, uint16_t x, uint16_t y); +void display_register(uint8_t reg); diff --git a/lib/led/led.c b/lib/led/led.c new file mode 100644 index 0000000..b57f737 --- /dev/null +++ b/lib/led/led.c @@ -0,0 +1,36 @@ +/* Author: Steve Gunn + * Licence: This work is licensed under the Creative Commons Attribution License. + * View this license at http://creativecommons.org/about/licenses/ + */ + +#include <avr/io.h> +#include "led.h" + +void init_led() +{ + DDRB |= _BV(LED); + PORTB &= ~_BV(LED); +} + +void led_on() +{ + PORTB |= _BV(LED); +} + +void led_off() +{ + TCCR0A = 0x00; + TCCR0B = 0x00; + PORTB &= ~_BV(LED); +} + +void led_brightness(uint8_t i) +{ + /* Configure Timer 0 Fast PWM Mode 3 */ + TCCR0A = _BV(COM0A1) | _BV(WGM01) | _BV(WGM00); + TCCR0B = _BV(CS20); + OCR0A = i; +} + + + diff --git a/lib/led/led.h b/lib/led/led.h new file mode 100644 index 0000000..76a7008 --- /dev/null +++ b/lib/led/led.h @@ -0,0 +1,14 @@ +/* Author: Steve Gunn + * Licence: This work is licensed under the Creative Commons Attribution License. + * View this license at http://creativecommons.org/about/licenses/ + */ + +#include <stdint.h> + +#define LED PB7 + +void init_led(); +void led_on(); +void led_off(); +void led_brightness(uint8_t i); + diff --git a/lib/rotary/rotary.c b/lib/rotary/rotary.c new file mode 100644 index 0000000..c1b1cfc --- /dev/null +++ b/lib/rotary/rotary.c @@ -0,0 +1,48 @@ +/* Author: Steve Gunn + * Licence: This work is licensed under the Creative Commons Attribution License. + * View this license at http://creativecommons.org/about/licenses/ + */ + +#include <avr/io.h> +#include <avr/interrupt.h> +#include <util/delay.h> +#include "rotary.h" + +volatile int8_t rotary = 0; + +void init_rotary() +{ + /* Ensure all pins are inputs with pull-ups enabled */ + DDRE &= ~_BV(ROTA) & ~_BV(ROTB) & ~_BV(SWC); + PORTE |= _BV(ROTA) | _BV(ROTB) | _BV(SWC); + DDRC &= ~_BV(SWN) & ~_BV(SWE) & ~_BV(SWS) & ~_BV(SWW); + PORTC |= _BV(SWN) | _BV(SWE) | _BV(SWS) | _BV(SWW); + /* Configure interrupt for any edge on rotary and falling edge for button */ + EICRB |= _BV(ISC40) | _BV(ISC50) | _BV(ISC71); +} + +int8_t get_rotary() +{ + static uint8_t lastAB = 0x00; + uint8_t AB = PINE & (_BV(ROTA) | _BV(ROTB)); + if ((AB == 0x00 && lastAB == 0x20) || (AB == 0x30 && lastAB == 0x10)) + rotary--; + if ((AB == 0x30 && lastAB == 0x20) || (AB == 0x00 && lastAB == 0x10)) + rotary++; + lastAB = AB; + return rotary; +} + +uint8_t get_switch() +{ + return PINC & (_BV(SWN) | _BV(SWE) | _BV(SWS) | _BV(SWW)); +} + +ISR(INT4_vect) +{ + get_rotary(); + _delay_us(100); +} + +ISR(INT5_vect, ISR_ALIASOF(INT4_vect)); + diff --git a/lib/rotary/rotary.h b/lib/rotary/rotary.h new file mode 100644 index 0000000..2decfce --- /dev/null +++ b/lib/rotary/rotary.h @@ -0,0 +1,21 @@ +/* Author: Steve Gunn + * Licence: This work is licensed under the Creative Commons Attribution License. + * View this license at http://creativecommons.org/about/licenses/ + */ + +#include <stdint.h> + +#define ROTA PE4 +#define ROTB PE5 +#define SWC PE7 +#define SWN PC2 +#define SWE PC3 +#define SWS PC4 +#define SWW PC5 + +extern volatile int8_t rotary; + +void init_rotary(); +int8_t get_rotary(); +uint8_t get_switch(); + diff --git a/main.c b/main.c new file mode 100644 index 0000000..db5adaa --- /dev/null +++ b/main.c @@ -0,0 +1,287 @@ +/* Configure I/O Ports */ + +/* For La Fortuna board + + | Port | Pin | Function | + |------+-----+------------------| + | C | 2 | Up Button | + | C | 3 | Right Button | + | C | 4 | Down Button | + | C | 5 | Left Button | + +*/ + +#include <stdio.h> +#include <avr/io.h> +#include <util/delay.h> +#include <avr/interrupt.h> +#include <time.h> +#include <stdlib.h> +#include "lib/lcd/lcd.h" +#include "lib/rotary/rotary.h" +#include "buttons.h" +#include "main.h" + +#define FPS 10 +#define BLOCK_SIZE 8 +#define SCREEN_WIDTH 320 +#define DIFFICULTY_INTERVAL 130 +#define SCREEN_HEIGHT 240 +#define UP_BUFFER 0 +#define RIGHT_BUFFER 1 +#define DOWN_BUFFER 2 +#define LEFT_BUFFER 3 +#define MAX_ENEMIES ((SCREEN_WIDTH / BLOCK_SIZE) * (SCREEN_HEIGHT / BLOCK_SIZE)) / 2 + +#define max(x,y) ((x) >= (y)) ? (x) : (y) +#define min(x,y) ((x) <= (y)) ? (x) : (y) + +/* Bits 0-3: Up, Right, Down, Left */ +volatile uint8_t MOVEMENT_BUFFER = 0; + +volatile uint16_t x = SCREEN_WIDTH/2; +volatile uint16_t y = SCREEN_HEIGHT/2; + +volatile uint16_t apple_x; +volatile uint16_t apple_y; + +volatile uint8_t enemy_spawn_chance = 1; + +struct coord {uint16_t x; uint16_t y;}; + +volatile struct coord enemies[MAX_ENEMIES]; +volatile uint16_t current_enemies = 0; + +volatile uint16_t current_difficulty_time = 0; + +volatile uint16_t score = 0; + +rectangle snake_head = {SCREEN_WIDTH/2, SCREEN_WIDTH/2 + BLOCK_SIZE, + SCREEN_HEIGHT/2, SCREEN_HEIGHT/2 + BLOCK_SIZE}; +rectangle previous_block; + +rectangle apple; + +volatile uint8_t tick = 0; + +enum move{Up, Right, Down, Left}; + +// uint8_t moves_buffered = 0; +// uint8_t moves[NUMBER_MOVES_BUFFERED]; +volatile enum move current_direction = Right; + +void init(void) { + + /* 8MHz clock, no prescaling (DS, p. 48) */ + CLKPR = (1 << CLKPCE); + CLKPR = 0; + + init_lcd(); + + set_frame_rate_hz(61); + /* Enable tearing interrupt to get flicker free display */ + EIMSK |= _BV(INT6); + + /* Set as input */ + DDRC &= ~_BV(SWN) & ~_BV(SWE) & ~_BV(SWS) & ~_BV(SWW); + /* Enable direction buttons */ + PORTC |= _BV(SWN) | _BV(SWE) | _BV(SWS) | _BV(SWW); + + /* Timer 0 for button listening interrupt: */ + TCCR0A = _BV(WGM01); + TCCR0B = _BV(CS02) | _BV(CS00); /* F_CPU / 1024 */ + + /* Timer 3 (16-bit) for frame counting */ + TCCR3A = 0; + TCCR3B |= _BV(WGM32); + TCCR3B |= _BV(CS32) | _BV(CS30); /* F_CPU / 1024 */ + + OCR0A = 78; /* 8MHz clock / 1024 (from TCCR0B flags) / 100 (for ~10ms delay) */ + OCR3A = 7812 / FPS; /* 8MHz clock / 1024 / FPS */ + + /* Enable timer interrupts */ + TIMSK0 |= _BV(OCIE0A); + TIMSK3 |= _BV(OCIE3A); + + /* Set seed for random numbers */ + srand(time(NULL)); +} + +ISR(TIMER3_COMPA_vect) { + tick = 1; +} + +ISR(TIMER0_COMPA_vect) { + if (is_up_pressed()) { + MOVEMENT_BUFFER |= _BV(UP_BUFFER); + } else if (is_right_pressed()) { + MOVEMENT_BUFFER |= _BV(RIGHT_BUFFER); + } else if (is_down_pressed()) { + MOVEMENT_BUFFER |= _BV(DOWN_BUFFER); + } else if (is_left_pressed()) { + MOVEMENT_BUFFER |= _BV(LEFT_BUFFER); + } +} + +void redraw_apple(void) { + apple_x = (rand() % (SCREEN_WIDTH / 8)) * 8; + apple_y = (rand() % (SCREEN_HEIGHT / 8)) * 8; + + if (apple_y == 0) { + apple_y = BLOCK_SIZE; + } + + apple.left = apple_x; + apple.right = apple_x + BLOCK_SIZE; + apple.top = apple_y; + apple.bottom = apple_y + BLOCK_SIZE; + + fill_rectangle(apple, 3000); +} + +void clear_enemies(void) { + for (uint16_t i = 0; i < current_enemies; i++) { + rectangle enemy; + enemy.left = enemies[i].x; + enemy.right = enemies[i].x + BLOCK_SIZE; + enemy.top = enemies[i].y; + enemy.bottom = enemies[i].y + BLOCK_SIZE; + fill_rectangle(enemy, 0); + } + + current_enemies = 0; +} + +void reset(void) { + _delay_ms(1000); + fill_rectangle(apple, 0); + clear_enemies(); + score = 0; + enemy_spawn_chance = 1; + current_direction = Right; + x = SCREEN_WIDTH/2; + y = SCREEN_HEIGHT/2; + redraw_apple(); + info_redraw_logic(); +} + +void snake_move_logic(void) { + switch (current_direction) { + case Up: + y -= BLOCK_SIZE; + break; + case Right: + x += BLOCK_SIZE; + break; + case Down: + y += BLOCK_SIZE; + break; + case Left: + x -= BLOCK_SIZE; + break; + } + + if (y > SCREEN_HEIGHT - BLOCK_SIZE || /* Don't need to handle < 0 as it's unsigned */ + x > SCREEN_WIDTH - BLOCK_SIZE) { + reset(); + } + + previous_block = snake_head; + + snake_head.left = x; + snake_head.right = x + BLOCK_SIZE; + snake_head.top = y; + snake_head.bottom = y + BLOCK_SIZE; +} + +void snake_direction_logic(void) { + if ((MOVEMENT_BUFFER >> UP_BUFFER) & 1) { + current_direction = Up; + MOVEMENT_BUFFER = 0; + } + if ((MOVEMENT_BUFFER >> RIGHT_BUFFER) & 1) { + current_direction = Right; + MOVEMENT_BUFFER = 0; + } + if ((MOVEMENT_BUFFER >> DOWN_BUFFER) & 1) { + current_direction = Down; + MOVEMENT_BUFFER = 0; + } + if (((MOVEMENT_BUFFER >> LEFT_BUFFER) & 1)) { + current_direction = Left; + MOVEMENT_BUFFER = 0; + } +} + +void enemy_spawn_logic(void) { + if (rand() % 180 <= enemy_spawn_chance) { + struct coord c = {(rand() % (SCREEN_WIDTH / 8)) * 8, (rand() % (SCREEN_HEIGHT / 8)) * 8}; + while ((c.x == x && c.y == y) || (c.x == apple_x && c.y == apple_y)) { + c.x = (rand() % (SCREEN_WIDTH / 8)) * 8; + c.y = (rand() % (SCREEN_HEIGHT / 8)) * 8; + } + enemies[current_enemies++] = c; + rectangle enemy; + enemy.left = c.x; + enemy.right = c.x + BLOCK_SIZE; + enemy.top = c.y; + enemy.bottom = c.y + BLOCK_SIZE; + fill_rectangle(enemy, RED); + } +} + +void snake_draw_logic(void) { + fill_rectangle(previous_block, 0); + fill_rectangle(snake_head, 5000); +} + +void info_redraw_logic(void) { + char str[50]; + sprintf(str, "Score: %05d Difficulty: %d", score, enemy_spawn_chance); + display_string_xy(str, 0, 0); +} + +ISR(INT6_vect) { + snake_draw_logic(); + info_redraw_logic(); +} + +void apple_draw_logic(void) { + if (apple_x == x && apple_y == y) { + clear_enemies(); + score += 200; + redraw_apple(); + } +} + +void enemy_collision_logic(void) { + for (uint16_t i = 0; i < current_enemies; i++) { + if (enemies[i].x == x && enemies[i].y == y) { + reset(); + } + } +} + +int main() { + init(); + + sei(); + + reset(); + + for (;;) { + if (tick) { + snake_direction_logic(); + snake_move_logic(); + apple_draw_logic(); + enemy_collision_logic(); + enemy_spawn_logic(); + if (current_difficulty_time++ >= DIFFICULTY_INTERVAL) { + enemy_spawn_chance++; + current_difficulty_time = 0; + } + score++; + tick = 0; + } + } +} diff --git a/main.h b/main.h new file mode 100644 index 0000000..b8da695 --- /dev/null +++ b/main.h @@ -0,0 +1,9 @@ +// +// Created by platelminto on 5/20/20. +// + +#ifndef SNAKE_MAIN_H +#define SNAKE_MAIN_H + +#endif //SNAKE_MAIN_H + -- GitLab