├── .gitignore
├── .gitmodules
├── README.md
├── firmware
├── .gitignore
├── 1bitsy-1up.sublime-project
├── LICENSE_GPLV3.txt
├── LICENSE_LGPLV3.txt
├── Makefile
├── README.md
├── libopencm3.rules.mk
├── libopencm3.target.mk
├── scripts
│ └── black_magic_probe_flash.scr
└── src
│ ├── 1bitsy-stm32f415rgt-gfx.ld
│ ├── Makefile
│ ├── README.md
│ ├── assets
│ ├── .gitignore
│ ├── 1bitsy-1up-game1.tmx
│ ├── README.md
│ ├── fblocks.png
│ ├── gen-assets.py
│ ├── spritesheet.png
│ └── tilesheet.png
│ ├── audio.c
│ ├── audio.h
│ ├── audio_app.c
│ ├── audio_app.h
│ ├── button_boot.c
│ ├── button_boot.h
│ ├── fblocks_app.c
│ ├── fblocks_app.h
│ ├── gamepad.c
│ ├── gamepad.h
│ ├── gfx-pixslice.c
│ ├── gfx-pixslice.h
│ ├── gfx-types.h
│ ├── gpio.c
│ ├── gpio.h
│ ├── i2c.c
│ ├── i2c.h
│ ├── intr.h
│ ├── lcd.c
│ ├── lcd.h
│ ├── led.c
│ ├── led.h
│ ├── main.c
│ ├── math-util.h
│ ├── munch_app.c
│ ├── munch_app.h
│ ├── pam8019.c
│ ├── pam8019.h
│ ├── systick.c
│ ├── systick.h
│ ├── text.c
│ ├── text.h
│ ├── tile_app.c
│ ├── tile_app.h
│ ├── touch.c
│ ├── touch.h
│ ├── volume.c
│ └── volume.h
└── hardware
├── NOTES.md
├── V0.1
├── 1bitsy-1up-cache.lib
├── 1bitsy-1up.kicad_pcb
├── 1bitsy-1up.pro
└── 1bitsy-1up.sch
├── contrib
└── 1up-mini
│ ├── 1up-mini-cache.lib
│ ├── 1up-mini.kicad_pcb
│ ├── 1up-mini.pro
│ ├── 1up-mini.sch
│ ├── README.md
│ └── fp-lib-table
└── v0.2
├── 1bitsy-1up-cache.lib
├── 1bitsy-1up.kicad_pcb
├── 1bitsy-1up.pro
├── 1bitsy-1up.sch
├── 1bitsy.sch
├── icebreaker.sch
└── sym-lib-table
/.gitignore:
--------------------------------------------------------------------------------
1 | *bak
2 | _autosave-*
3 | *.net
4 | *.zip
5 | .gdbinit
6 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "hardware/lib/pkl"]
2 | path = hardware/lib/pkl
3 | url = https://github.com/esden/pretty-kicad-libs.git
4 | [submodule "hardware/lib/1bitsy"]
5 | path = hardware/lib/1bitsy
6 | url = https://github.com/1Bitsy/1bitsy-hardware-lib.git
7 | [submodule "lib/pkl"]
8 | path = lib/pkl
9 | url = https://github.com/esden/pretty-kicad-libs.git
10 | [submodule "firmware/libopencm3"]
11 | path = firmware/libopencm3
12 | url = https://github.com/libopencm3/libopencm3.git
13 | [submodule "firmware/src/assets/miniwi"]
14 | path = firmware/src/assets/miniwi
15 | url = https://github.com/josuah/miniwi.git
16 | [submodule "hardware/lib/stm32"]
17 | path = hardware/lib/stm32
18 | url = https://github.com/esden/stm32-kicad-lib.git
19 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://gitter.im/1bitsy/1bitsy-1up?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
2 |
3 | This repository contains the board and code used on the 1Bitsy 1UP.
4 |
5 | ## Intro
6 |
7 | 1Bitsy 1UP is a retro inspired handheld game console, the design is based
8 | around the following __semi arbitrary constraints and requirements.__
9 |
10 | * Formfactor: PCB the size of the inside of a GB DMG (the gray one) This will
11 | hopefully eventually allow us to put the 1UP pcb inside a modified GB DMG
12 | case, either original or new molds sold by several online stores.
13 | * Main CPU: All code should be able to execute on a 1Bitsy that is fitted with
14 | an STM32F415RGT6. That particular chip (due to the package size) does not
15 | contain external ram support or LCD display engine. Making LCD drive little
16 | bit more tricky. It is a nice constraint that makes coding for the platform
17 | bit more of a challenge in the style of classic conloles and 8bit computers
18 | because it does not have enough memory for a full framebuffer. ("racing the
19 | beam" FTW)
20 | * Main CPU Mounting: The board contains the 1Bitsy compatible low profile
21 | socket using [SL-115-TT-19](https://www.samtec.com/products/sl-115-tt-19)
22 | and [BBL-115-T-E](https://www.samtec.com/products/bbl-115-t-e) Samtec
23 | connectors as well as one MillMax PogoPin spring loaded SMD connector.
24 | * LCD: The LCD is a 240x320 TFT display with capacitive touch, connected
25 | through the 8bit parallel interface to the 1Bitsy. This allows us to push the
26 | data speed to the display quite high and reach good framerates that would not
27 | be possible through the SPI interface. The capacitive touch screen adds an
28 | interesting aspect of control that was not available on classic consoles
29 | prior to DS. (That was also resistive not capacitive)
30 | * Audio: We are connecting the STM32F4 built in DAC lines for audio generation.
31 | This is not as slick and good as an i2s part but will likely make things
32 | "interesting".
33 | * Controls: The gamepad consists of the classic D-Pad, ABXY, Select, Start set
34 | of buttons. Because we have the capacitive touch no other analog controls are
35 | considered necessary.
36 | * Storage: To simplify storing games and data in large quantities we have
37 | connected a microSD card over the SDIO interface to the STM32, allowing for
38 | reasonabely fast load and save times and maybe even some other interesting
39 | hacks.
40 | * Expansion: The platform will receive future expansions and improvements that
41 | will strive to remain transparent. Meaning all code written for the first
42 | version of the platform should work either out of the box or only with very
43 | minor modifications.
44 |
45 | The display used is a TFT LCD with I2C CapTouch and ILI9341 driver.
46 |
47 | __The most basic design consists of:__
48 | * 1Bitsy STM32F415RGT6 (168MHz, 192kb RAM, 1MB Flash)
49 | * 240x320 2.8" TFT with capacitive touch and PWM backlight control
50 | * D-Pad, ABXY, Start, Select buttons
51 | * DAC audio out to headphones. (speakers optional)
52 | * SDCard connected over SDIO interface
53 |
54 | Second tier addons for quality of life:
55 | * Lipo battery and charger built in
56 | * Speaker audio
57 |
58 | __Future "transparent" expansions:__
59 | These expansions will contribute to new and interesting hacks possible on the
60 | platform, they are not considered forward compatible but backward compatible.
61 | This means that we do not anticipate the expansions to exist from the beginning
62 | of the platform life and the software written at that time will not support the
63 | future expansions, but the old software has to function as is or only with very
64 | minor changes on the new device that contains the new expansions.
65 |
66 | ## Hacking
67 |
68 | The board design is in the hardware subdirectory.
69 |
--------------------------------------------------------------------------------
/firmware/.gitignore:
--------------------------------------------------------------------------------
1 | *.d
2 | *.elf
3 | *.map
4 | *.o
5 | *.bin
6 | *.hex
7 | *.sublime-workspace
8 |
--------------------------------------------------------------------------------
/firmware/1bitsy-1up.sublime-project:
--------------------------------------------------------------------------------
1 | {
2 | "folders":
3 | [
4 | {
5 | "path": ".",
6 | "file_exclude_patterns": ["*.elf", "*.bin", "*.hex", "*.d", "*.o", "*.map"]
7 | },
8 | ]
9 | }
10 |
--------------------------------------------------------------------------------
/firmware/LICENSE_LGPLV3.txt:
--------------------------------------------------------------------------------
1 | GNU LESSER GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 |
9 | This version of the GNU Lesser General Public License incorporates
10 | the terms and conditions of version 3 of the GNU General Public
11 | License, supplemented by the additional permissions listed below.
12 |
13 | 0. Additional Definitions.
14 |
15 | As used herein, "this License" refers to version 3 of the GNU Lesser
16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU
17 | General Public License.
18 |
19 | "The Library" refers to a covered work governed by this License,
20 | other than an Application or a Combined Work as defined below.
21 |
22 | An "Application" is any work that makes use of an interface provided
23 | by the Library, but which is not otherwise based on the Library.
24 | Defining a subclass of a class defined by the Library is deemed a mode
25 | of using an interface provided by the Library.
26 |
27 | A "Combined Work" is a work produced by combining or linking an
28 | Application with the Library. The particular version of the Library
29 | with which the Combined Work was made is also called the "Linked
30 | Version".
31 |
32 | The "Minimal Corresponding Source" for a Combined Work means the
33 | Corresponding Source for the Combined Work, excluding any source code
34 | for portions of the Combined Work that, considered in isolation, are
35 | based on the Application, and not on the Linked Version.
36 |
37 | The "Corresponding Application Code" for a Combined Work means the
38 | object code and/or source code for the Application, including any data
39 | and utility programs needed for reproducing the Combined Work from the
40 | Application, but excluding the System Libraries of the Combined Work.
41 |
42 | 1. Exception to Section 3 of the GNU GPL.
43 |
44 | You may convey a covered work under sections 3 and 4 of this License
45 | without being bound by section 3 of the GNU GPL.
46 |
47 | 2. Conveying Modified Versions.
48 |
49 | If you modify a copy of the Library, and, in your modifications, a
50 | facility refers to a function or data to be supplied by an Application
51 | that uses the facility (other than as an argument passed when the
52 | facility is invoked), then you may convey a copy of the modified
53 | version:
54 |
55 | a) under this License, provided that you make a good faith effort to
56 | ensure that, in the event an Application does not supply the
57 | function or data, the facility still operates, and performs
58 | whatever part of its purpose remains meaningful, or
59 |
60 | b) under the GNU GPL, with none of the additional permissions of
61 | this License applicable to that copy.
62 |
63 | 3. Object Code Incorporating Material from Library Header Files.
64 |
65 | The object code form of an Application may incorporate material from
66 | a header file that is part of the Library. You may convey such object
67 | code under terms of your choice, provided that, if the incorporated
68 | material is not limited to numerical parameters, data structure
69 | layouts and accessors, or small macros, inline functions and templates
70 | (ten or fewer lines in length), you do both of the following:
71 |
72 | a) Give prominent notice with each copy of the object code that the
73 | Library is used in it and that the Library and its use are
74 | covered by this License.
75 |
76 | b) Accompany the object code with a copy of the GNU GPL and this license
77 | document.
78 |
79 | 4. Combined Works.
80 |
81 | You may convey a Combined Work under terms of your choice that,
82 | taken together, effectively do not restrict modification of the
83 | portions of the Library contained in the Combined Work and reverse
84 | engineering for debugging such modifications, if you also do each of
85 | the following:
86 |
87 | a) Give prominent notice with each copy of the Combined Work that
88 | the Library is used in it and that the Library and its use are
89 | covered by this License.
90 |
91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license
92 | document.
93 |
94 | c) For a Combined Work that displays copyright notices during
95 | execution, include the copyright notice for the Library among
96 | these notices, as well as a reference directing the user to the
97 | copies of the GNU GPL and this license document.
98 |
99 | d) Do one of the following:
100 |
101 | 0) Convey the Minimal Corresponding Source under the terms of this
102 | License, and the Corresponding Application Code in a form
103 | suitable for, and under terms that permit, the user to
104 | recombine or relink the Application with a modified version of
105 | the Linked Version to produce a modified Combined Work, in the
106 | manner specified by section 6 of the GNU GPL for conveying
107 | Corresponding Source.
108 |
109 | 1) Use a suitable shared library mechanism for linking with the
110 | Library. A suitable mechanism is one that (a) uses at run time
111 | a copy of the Library already present on the user's computer
112 | system, and (b) will operate properly with a modified version
113 | of the Library that is interface-compatible with the Linked
114 | Version.
115 |
116 | e) Provide Installation Information, but only if you would otherwise
117 | be required to provide such information under section 6 of the
118 | GNU GPL, and only to the extent that such information is
119 | necessary to install and execute a modified version of the
120 | Combined Work produced by recombining or relinking the
121 | Application with a modified version of the Linked Version. (If
122 | you use option 4d0, the Installation Information must accompany
123 | the Minimal Corresponding Source and Corresponding Application
124 | Code. If you use option 4d1, you must provide the Installation
125 | Information in the manner specified by section 6 of the GNU GPL
126 | for conveying Corresponding Source.)
127 |
128 | 5. Combined Libraries.
129 |
130 | You may place library facilities that are a work based on the
131 | Library side by side in a single library together with other library
132 | facilities that are not Applications and are not covered by this
133 | License, and convey such a combined library under terms of your
134 | choice, if you do both of the following:
135 |
136 | a) Accompany the combined library with a copy of the same work based
137 | on the Library, uncombined with any other library facilities,
138 | conveyed under the terms of this License.
139 |
140 | b) Give prominent notice with the combined library that part of it
141 | is a work based on the Library, and explaining where to find the
142 | accompanying uncombined form of the same work.
143 |
144 | 6. Revised Versions of the GNU Lesser General Public License.
145 |
146 | The Free Software Foundation may publish revised and/or new versions
147 | of the GNU Lesser General Public License from time to time. Such new
148 | versions will be similar in spirit to the present version, but may
149 | differ in detail to address new problems or concerns.
150 |
151 | Each version is given a distinguishing version number. If the
152 | Library as you received it specifies that a certain numbered version
153 | of the GNU Lesser General Public License "or any later version"
154 | applies to it, you have the option of following the terms and
155 | conditions either of that published version or of any later version
156 | published by the Free Software Foundation. If the Library as you
157 | received it does not specify a version number of the GNU Lesser
158 | General Public License, you may choose any version of the GNU Lesser
159 | General Public License ever published by the Free Software Foundation.
160 |
161 | If the Library as you received it specifies that a proxy can decide
162 | whether future versions of the GNU Lesser General Public License shall
163 | apply, that proxy's public statement of acceptance of any version is
164 | permanent authorization for you to choose that version for the
165 | Library.
166 |
167 |
--------------------------------------------------------------------------------
/firmware/Makefile:
--------------------------------------------------------------------------------
1 | ##
2 | ## This file is part of the libopencm3 project.
3 | ##
4 | ## Copyright (C) 2009 Uwe Hermann
5 | ##
6 | ## This library is free software: you can redistribute it and/or modify
7 | ## it under the terms of the GNU Lesser General Public License as published by
8 | ## the Free Software Foundation, either version 3 of the License, or
9 | ## (at your option) any later version.
10 | ##
11 | ## This library is distributed in the hope that it will be useful,
12 | ## but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | ## GNU Lesser General Public License for more details.
15 | ##
16 | ## You should have received a copy of the GNU Lesser General Public License
17 | ## along with this library. If not, see .
18 | ##
19 |
20 | PREFIX ?= arm-none-eabi
21 | #PREFIX ?= arm-elf
22 |
23 | # Be silent per default, but 'make V=1' will show all compiler calls.
24 | ifneq ($(V),1)
25 | Q := @
26 | # Do not print "Entering directory ...".
27 | MAKEFLAGS += --no-print-directory
28 | endif
29 |
30 | # In case you are using an older compiler or want to set the C standard to a
31 | # specific version globally for the project this is where that would go.
32 | #CFLAGS += -std=gnu11
33 |
34 | OPENCM3_DIR := $(realpath libopencm3)
35 | BUILD_RULES = elf
36 |
37 | all: build
38 |
39 | bin: BUILD_RULES += bin
40 | hex: BUILD_RULES += hex
41 | srec: BUILD_RULES += srec
42 | list: BUILD_RULES += list
43 | images: BUILD_RULES += images
44 |
45 | bin: build
46 | hex: build
47 | srec: build
48 | list: build
49 | images: build
50 |
51 | build: lib src
52 |
53 | lib:
54 | $(Q)if [ ! "`ls -A libopencm3`" ] ; then \
55 | printf "######## ERROR ########\n"; \
56 | printf "\tlibopencm3 is not initialized.\n"; \
57 | printf "\tPlease run:\n"; \
58 | printf "\t$$ git submodule init\n"; \
59 | printf "\t$$ git submodule update\n"; \
60 | printf "\tbefore running make.\n"; \
61 | printf "######## ERROR ########\n"; \
62 | exit 1; \
63 | fi
64 | $(Q)$(MAKE) -C libopencm3 lib TARGETS="stm32/f4"
65 |
66 | src: lib
67 | @printf " BUILD $@\n";
68 | $(Q)$(MAKE) --directory=$@ OPENCM3_DIR=$(OPENCM3_DIR) $(BUILD_RULES)
69 |
70 | flash: src
71 | @printf " FLASH $@\n";
72 | $(Q)$(MAKE) --directory=src flash
73 |
74 | clean:
75 | $(Q)$(MAKE) -C libopencm3 clean
76 | $(Q)$(MAKE) -C src clean
77 |
78 | stylecheck: src.stylecheck
79 | styleclean: src.styleclean
80 |
81 |
82 | %.clean:
83 | $(Q)if [ -d $* ]; then \
84 | printf " CLEAN $*\n"; \
85 | $(MAKE) -C $* clean OPENCM3_DIR=$(OPENCM3_DIR) || exit $?; \
86 | fi;
87 |
88 | %.styleclean:
89 | $(Q)$(MAKE) -C $* styleclean OPENCM3_DIR=$(OPENCM3_DIR)
90 |
91 | %.stylecheck:
92 | $(Q)$(MAKE) -C $* stylecheck OPENCM3_DIR=$(OPENCM3_DIR)
93 |
94 |
95 | .PHONY: build lib examples install clean stylecheck styleclean \
96 | bin hex srec list images
97 |
98 |
--------------------------------------------------------------------------------
/firmware/README.md:
--------------------------------------------------------------------------------
1 | # README
2 |
3 | This repository/directory contains code for the 1Bitsy 1UP retro inspired
4 | handheld game console. Expect it to morph and change as the time goes by. Feel
5 | free to rip out the code you need for your 1bitsy projects. But respect the
6 | licenses of the files.
7 |
8 | 1UP is a retro inspired handheld game console subproject of the 1Bitsy dev
9 | board project.
10 |
11 | For more information visit https://hackaday.io/project/25632-1bitsy-1up
12 |
13 | The 1Bitsy is an open hardware stm32F415 based small microcontroller development
14 | board.
15 |
16 | For more information visit http://1bitsy.org
17 |
18 | The libopencm3 project aims to create an open-source firmware library for
19 | various ARM Cortex-M3 microcontrollers.
20 |
21 | For more information visit http://libopencm3.org
22 |
23 | ## Usage
24 |
25 | You will have to fetch the libopencm3 submodule by running:
26 |
27 | git submodule init
28 | git submodule update
29 |
30 | You compile the needed part of the library and the project firmware by invoking
31 | "make" in the toplevel directory.
32 |
33 | Executing "make flash" will try to use arm-none-eabi-gdb to connect ta a Black
34 | Magic Probe and upload the firmware to your target.
35 |
36 | ## Notes
37 |
38 | If you are using an older GCC compiler. (pre V5) You may need to provide the C
39 | standard to the compiler. Otherwise the compiler might complain. To solve the
40 | issue you can invoke the `make` command in the top level directory by setting the
41 | `CFLAGS` variable:
42 | ```
43 | CFLAGS=-std=c99 make
44 | ```
45 |
46 | If your own project is using some specific extensions to the C standard you can
47 | add the necessary `CFLAGS` variable setting to your project Makefile in the src
48 | subdirectory.
49 |
50 | ## Contributions
51 |
52 | Pull requests simplifying improving modularizing and all the polish possible
53 | are very welcome! Join the 1Bitsy 1UP community at:
54 | https://gitter.im/1bitsy/1bitsy-1up
55 |
--------------------------------------------------------------------------------
/firmware/libopencm3.rules.mk:
--------------------------------------------------------------------------------
1 | ##
2 | ## This file is part of the libopencm3 project.
3 | ##
4 | ## Copyright (C) 2009 Uwe Hermann
5 | ## Copyright (C) 2010 Piotr Esden-Tempski
6 | ## Copyright (C) 2013 Frantisek Burian
7 | ##
8 | ## This library is free software: you can redistribute it and/or modify
9 | ## it under the terms of the GNU Lesser General Public License as published by
10 | ## the Free Software Foundation, either version 3 of the License, or
11 | ## (at your option) any later version.
12 | ##
13 | ## This library is distributed in the hope that it will be useful,
14 | ## but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 | ## GNU Lesser General Public License for more details.
17 | ##
18 | ## You should have received a copy of the GNU Lesser General Public License
19 | ## along with this library. If not, see .
20 | ##
21 |
22 | # Be silent per default, but 'make V=1' will show all compiler calls.
23 | ifneq ($(V),1)
24 | Q := @
25 | NULL := 2>/dev/null
26 | endif
27 |
28 | ###############################################################################
29 | # Executables
30 |
31 | PREFIX ?= arm-none-eabi
32 |
33 | CC := $(PREFIX)-gcc
34 | CXX := $(PREFIX)-g++
35 | LD := $(PREFIX)-gcc
36 | AR := $(PREFIX)-ar
37 | AS := $(PREFIX)-as
38 | OBJCOPY := $(PREFIX)-objcopy
39 | OBJDUMP := $(PREFIX)-objdump
40 | GDB := $(PREFIX)-gdb
41 | STFLASH = $(shell which st-flash)
42 | STYLECHECK := /checkpatch.pl
43 | STYLECHECKFLAGS := --no-tree -f --terse --mailback
44 | STYLECHECKFILES := $(shell find . -name '*.[ch]')
45 |
46 |
47 | ###############################################################################
48 | # Source files
49 |
50 | LDSCRIPT ?= $(BINARY).ld
51 |
52 | OBJS +=
53 |
54 |
55 | ifeq ($(strip $(OPENCM3_DIR)),)
56 | # user has not specified the library path, so we try to detect it
57 |
58 | # where we search for the library
59 | LIBPATHS := ./libopencm3 ../libopencm3
60 |
61 | OPENCM3_DIR := $(wildcard $(LIBPATHS:=/locm3.sublime-project))
62 | OPENCM3_DIR := $(firstword $(dir $(OPENCM3_DIR)))
63 |
64 | ifeq ($(strip $(OPENCM3_DIR)),)
65 | $(warning Cannot find libopencm3 library in the standard search paths.)
66 | $(error Please specify it through OPENCM3_DIR variable!)
67 | endif
68 | endif
69 |
70 | ifeq ($(V),1)
71 | $(info Using $(OPENCM3_DIR) path to library)
72 | endif
73 |
74 | INCLUDE_DIR = $(OPENCM3_DIR)/include
75 | LIB_DIR = $(OPENCM3_DIR)/lib
76 | SCRIPT_DIR = ../scripts
77 |
78 | ###############################################################################
79 | # C flags
80 |
81 | CFLAGS += -g
82 | CFLAGS += -Wextra -Wshadow -Wimplicit-function-declaration
83 | CFLAGS += -Wredundant-decls -Wmissing-prototypes -Wstrict-prototypes
84 | CFLAGS += -fno-common -ffunction-sections -fdata-sections
85 |
86 | ###############################################################################
87 | # C++ flags
88 |
89 | CXXFLAGS += -Os -g
90 | CXXFLAGS += -Wextra -Wshadow -Wredundant-decls -Weffc++
91 | CXXFLAGS += -fno-common -ffunction-sections -fdata-sections
92 |
93 | ###############################################################################
94 | # C & C++ preprocessor common flags
95 |
96 | CPPFLAGS += -MD
97 | CPPFLAGS += -Wall -Wundef
98 | CPPFLAGS += -I$(INCLUDE_DIR) $(DEFS)
99 |
100 | ###############################################################################
101 | # Linker flags
102 |
103 | LDFLAGS += --static -nostartfiles
104 | LDFLAGS += -L$(LIB_DIR)
105 | LDFLAGS += -T$(LDSCRIPT)
106 | LDFLAGS += -Wl,-Map=$(*).map
107 | LDFLAGS += -Wl,--gc-sections
108 | ifeq ($(V),99)
109 | LDFLAGS += -Wl,--print-gc-sections
110 | endif
111 |
112 | ###############################################################################
113 | # Used libraries
114 |
115 | LDLIBS += -l$(LIBNAME)
116 | LDLIBS += -Wl,--start-group -lc -lgcc -lnosys -Wl,--end-group
117 |
118 | ###############################################################################
119 | ###############################################################################
120 | ###############################################################################
121 |
122 | .SUFFIXES: .elf .bin .hex .srec .list .map .images
123 | .SECONDEXPANSION:
124 | .SECONDARY:
125 |
126 | all: elf
127 |
128 | elf: $(BINARY).elf
129 | bin: $(BINARY).bin
130 | hex: $(BINARY).hex
131 | srec: $(BINARY).srec
132 | list: $(BINARY).list
133 |
134 | images: $(BINARY).images
135 | flash: $(BINARY).flash
136 | stlink-flash: $(BINARY).stlink-flash
137 |
138 | %.images: %.bin %.hex %.srec %.list %.map
139 | @printf "*** $* images generated ***\n"
140 |
141 | %.bin: %.elf
142 | @printf " OBJCOPY $(*).bin\n"
143 | $(Q)$(OBJCOPY) -Obinary $(*).elf $(*).bin
144 |
145 | %.hex: %.elf
146 | @printf " OBJCOPY $(*).hex\n"
147 | $(Q)$(OBJCOPY) -Oihex $(*).elf $(*).hex
148 |
149 | %.srec: %.elf
150 | @printf " OBJCOPY $(*).srec\n"
151 | $(Q)$(OBJCOPY) -Osrec $(*).elf $(*).srec
152 |
153 | %.list: %.elf
154 | @printf " OBJDUMP $(*).list\n"
155 | $(Q)$(OBJDUMP) -S $(*).elf > $(*).list
156 |
157 | %.elf %.map: $(OBJS) $(LDSCRIPT) $(LIB_DIR)/lib$(LIBNAME).a
158 | @printf " LD $(*).elf\n"
159 | $(Q)$(LD) $(LDFLAGS) $(ARCH_FLAGS) $(OBJS) $(LDLIBS) -o $(*).elf
160 |
161 | %.o: %.c
162 | @printf " CC $(*).c\n"
163 | $(Q)$(CC) $(CFLAGS) $(CPPFLAGS) $(ARCH_FLAGS) -o $(*).o -c $(*).c
164 |
165 | %.o: %.cxx
166 | @printf " CXX $(*).cxx\n"
167 | $(Q)$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(ARCH_FLAGS) -o $(*).o -c $(*).cxx
168 |
169 | %.o: %.cpp
170 | @printf " CXX $(*).cpp\n"
171 | $(Q)$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(ARCH_FLAGS) -o $(*).o -c $(*).cpp
172 |
173 | clean::
174 | @printf " CLEAN\n"
175 | $(Q)$(RM) *.o *.d *.elf *.bin *.hex *.srec *.list *.map
176 |
177 | stylecheck: $(STYLECHECKFILES:=.stylecheck)
178 | styleclean: $(STYLECHECKFILES:=.styleclean)
179 |
180 | # the cat is due to multithreaded nature - we like to have consistent chunks of text on the output
181 | %.stylecheck: %
182 | $(Q)$(SCRIPT_DIR)$(STYLECHECK) $(STYLECHECKFLAGS) $* > $*.stylecheck; \
183 | if [ -s $*.stylecheck ]; then \
184 | cat $*.stylecheck; \
185 | else \
186 | rm -f $*.stylecheck; \
187 | fi;
188 |
189 | %.styleclean:
190 | $(Q)rm -f $*.stylecheck;
191 |
192 |
193 | %.stlink-flash: %.bin
194 | @printf " FLASH $<\n"
195 | $(Q)$(STFLASH) write $(*).bin 0x8000000
196 |
197 | ifeq ($(OOCD_SERIAL),)
198 | %.oocd-flash: %.hex
199 | @printf " FLASH $<\n"
200 | @# IMPORTANT: Don't use "resume", only "reset" will work correctly!
201 | $(Q)$(OOCD) -f interface/$(OOCD_INTERFACE).cfg \
202 | -f board/$(OOCD_BOARD).cfg \
203 | -c "init" -c "reset init" \
204 | -c "flash write_image erase $(*).hex" \
205 | -c "reset" \
206 | -c "shutdown" $(NULL)
207 | else
208 | %.oocd-flash: %.hex
209 | @printf " FLASH $<\n"
210 | @# IMPORTANT: Don't use "resume", only "reset" will work correctly!
211 | $(Q)$(OOCD) -f interface/$(OOCD_INTERFACE).cfg \
212 | -f board/$(OOCD_BOARD).cfg \
213 | -c "ft2232_serial $(OOCD_SERIAL)" \
214 | -c "init" -c "reset init" \
215 | -c "flash write_image erase $(*).hex" \
216 | -c "reset" \
217 | -c "shutdown" $(NULL)
218 | endif
219 |
220 | ifeq ($(BMP_PORT),)
221 | BMP_PORT_CANDIDATES := $(wildcard \
222 | /dev/serial/by-id/usb-Black_Sphere_Technologies_Black_Magic_Probe_*-if00 \
223 | /dev/cu.usbmodem*1)
224 | ifeq ($(words $(BMP_PORT_CANDIDATES)),1)
225 | BMP_PORT := $(BMP_PORT_CANDIDATES)
226 | else
227 | BMP_PORT = $(error Black Magic Probe gdb serial port not found, please provide the device name via the BMP_PORT variable parameter$(if \
228 | $(BMP_PORT_CANDIDATES), (found $(BMP_PORT_CANDIDATES))))
229 | endif
230 | endif
231 | %.flash: %.elf
232 | @printf " BMP $(BMP_PORT) $(*).elf (flash)\n"
233 | $(Q)$(GDB) -nx --batch \
234 | -ex 'target extended-remote $(BMP_PORT)' \
235 | -x $(SCRIPT_DIR)/black_magic_probe_flash.scr \
236 | $(*).elf
237 |
238 | .PHONY: images clean stylecheck styleclean elf bin hex srec list
239 |
240 | -include $(OBJS:.o=.d)
241 |
--------------------------------------------------------------------------------
/firmware/libopencm3.target.mk:
--------------------------------------------------------------------------------
1 | ##
2 | ## This file is part of the libopencm3 project.
3 | ##
4 | ## Copyright (C) 2009 Uwe Hermann
5 | ## Copyright (C) 2010 Piotr Esden-Tempski
6 | ## Copyright (C) 2011 Fergus Noble
7 | ##
8 | ## This library is free software: you can redistribute it and/or modify
9 | ## it under the terms of the GNU Lesser General Public License as published by
10 | ## the Free Software Foundation, either version 3 of the License, or
11 | ## (at your option) any later version.
12 | ##
13 | ## This library is distributed in the hope that it will be useful,
14 | ## but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 | ## GNU Lesser General Public License for more details.
17 | ##
18 | ## You should have received a copy of the GNU Lesser General Public License
19 | ## along with this library. If not, see .
20 | ##
21 |
22 | LIBNAME = opencm3_stm32f4
23 | DEFS = -DSTM32F4
24 |
25 | FP_FLAGS ?= -mfloat-abi=hard -mfpu=fpv4-sp-d16
26 | ARCH_FLAGS = -mthumb -mcpu=cortex-m4 $(FP_FLAGS)
27 |
28 | ################################################################################
29 | # OpenOCD specific variables
30 |
31 | OOCD ?= openocd
32 | OOCD_INTERFACE ?= stlink-v2
33 | OOCD_BOARD ?= stm32f4discovery
34 |
35 | ################################################################################
36 | # Black Magic Probe specific variables
37 | # Set the BMP_PORT to a serial port and then BMP is used for flashing
38 | BMP_PORT ?=
39 |
40 | ################################################################################
41 | # texane/stlink specific variables
42 | #STLINK_PORT ?= :4242
43 |
44 |
45 | include ../libopencm3.rules.mk
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/firmware/scripts/black_magic_probe_flash.scr:
--------------------------------------------------------------------------------
1 | # Disable asking for confirmation. (All questions are automatically answered
2 | # with y if ran in batch mode, but it still prints warnings that don't look
3 | # very good. :D )
4 | set confirm off
5 | # Print the Black Magic Probe firmware version
6 | monitor version
7 | # Optional: Enable target power
8 | #monitor tpwr enable
9 | # Optional: Enable system Reset on connect
10 | #monitor connect_srst enable
11 | # Alternative: Use JTAG protocol to talk to the target
12 | #monitor jtag_scan
13 | # Scan for targets using SWD protocol
14 | monitor swdp_scan
15 | # Attach to the first device found
16 | attach 1
17 | # Erase and load the provided binary to flash
18 | load
19 | # Compare the loaded sections to the ones in the provided binary
20 | compare-sections
21 | # Reset and disconnect from the target
22 | kill
23 |
--------------------------------------------------------------------------------
/firmware/src/1bitsy-stm32f415rgt-gfx.ld:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the libopencm3 project.
3 | *
4 | * Copyright (C) 2009 Uwe Hermann
5 | * Copyright (C) 2011 Stephen Caudle
6 | *
7 | * This library is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Lesser General Public License as published by
9 | * the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This library is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Lesser General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Lesser General Public License
18 | * along with this library. If not, see .
19 | */
20 |
21 | /* Linker script for 1Bitsy (STM32F415RGT, 1024K flash, 128K RAM). */
22 |
23 | /* Define memory regions. */
24 | MEMORY
25 | {
26 | rom (rx) : ORIGIN = 0x08000000, LENGTH = 1024K
27 | ram (rwx) : ORIGIN = 0x10000000, LENGTH = 64K /* Core Coupled RAM */
28 | sram1 (rwx) : ORIGIN = 0x20000000, LENGTH = 112K /* System RAM 1 */
29 | sram2 (rwx) : ORIGIN = 0x2001C000, LENGTH = 16K /* System RAM 2 */
30 | }
31 |
32 | SECTIONS
33 | {
34 | .sram1 (NOLOAD) : {
35 | sram1_start = .;
36 | sram1_end = . + 112K;
37 | *(.sram1)
38 | } >sram1
39 | .sram2 (NOLOAD) : {
40 | sram2_start = .;
41 | sram2_end = . + 16K;
42 | *(.sram2)
43 | } >sram2
44 | }
45 |
46 | /* Include the common ld script. */
47 | INCLUDE libopencm3_stm32f4.ld
48 |
49 |
--------------------------------------------------------------------------------
/firmware/src/Makefile:
--------------------------------------------------------------------------------
1 | ##
2 | ## This file is part of the libopencm3 project.
3 | ##
4 | ## Copyright (C) 2017 Piotr Esden-Tempski
5 | ##
6 | ## This library is free software: you can redistribute it and/or modify
7 | ## it under the terms of the GNU Lesser General Public License as published by
8 | ## the Free Software Foundation, either version 3 of the License, or
9 | ## (at your option) any later version.
10 | ##
11 | ## This library is distributed in the hope that it will be useful,
12 | ## but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | ## GNU Lesser General Public License for more details.
15 | ##
16 | ## You should have received a copy of the GNU Lesser General Public License
17 | ## along with this library. If not, see .
18 | ##
19 |
20 | BINARY = 1up-native
21 |
22 | OBJS := main.o audio.o audio_app.o button_boot.o gamepad.o \
23 | gfx-pixslice.o gpio.o i2c.o lcd.o led.o munch_app.o systick.o \
24 | text.o tile_app.o volume.o touch.o pam8019.o fblocks_app.o
25 |
26 | LDSCRIPT = 1bitsy-stm32f415rgt-gfx.ld
27 |
28 | V = 1
29 | include ../libopencm3.target.mk
30 |
31 | # You can enable size optimization for project deployment, but it can get
32 | # in the way of debugging your code
33 | cflags := $(filter_out -O%, $(CFLAGS)) -Werror -g
34 | # In theory this -O should be valid for everything but video.o but somehow it
35 | # affects everything? :(
36 | OPT := -O3
37 | CFLAGS = $(cflags) $(OPT)
38 |
39 | # If your project is using a specific C standard you can set it by uncommenting
40 | # the following line and adjusting the -std flag accordingly
41 | #CFLAGS += -std=gnu11 -pedantic
42 |
43 | LDLIBS += -lm
44 |
45 | lcd.o: OPT := -O0
46 |
47 | text.o tile_app.o: assets/assets.h
48 |
49 | assets/assets.h: assets/gen-assets.py assets/*.png assets/*.tmx assets/*/*.bdf
50 | @printf " ASSETS $?\n"
51 | $(Q)cd assets; python3 ./gen-assets.py > assets.h.new
52 | $(Q)mv assets/assets.h.new assets/assets.h
53 |
54 | clean::
55 | $(Q)$(RM) -f assets/assets.h assets/assets.h.new
56 |
57 |
58 |
--------------------------------------------------------------------------------
/firmware/src/README.md:
--------------------------------------------------------------------------------
1 | # README
2 |
3 | This is the default firmware of the 1bitsy 1UP.
4 |
5 | It's intended for the 1Bitsy 1UP retro inspired handheld game console.
6 |
7 | ## Board connections
8 |
9 | *none required*
10 |
--------------------------------------------------------------------------------
/firmware/src/assets/.gitignore:
--------------------------------------------------------------------------------
1 | assets.h
2 |
--------------------------------------------------------------------------------
/firmware/src/assets/1bitsy-1up-game1.tmx:
--------------------------------------------------------------------------------
1 |
2 |
27 |
--------------------------------------------------------------------------------
/firmware/src/assets/README.md:
--------------------------------------------------------------------------------
1 | The graphic assets are based on the kenney.nl abstract-platformer tile set. It
2 | is licensed under CC0 1.0 Universal.
3 |
4 | You can find the original tileset at:
5 | http://www.kenney.nl/assets/abstract-platformer
6 |
7 | The assets created based on the kenny.nl abstract-platformer found in this
8 | directory are also licensed under CC0 1.0 Universal.
9 |
--------------------------------------------------------------------------------
/firmware/src/assets/fblocks.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/1Bitsy/1bitsy-1up/54eddf3494c8faadea9018ee24a5c296e54b57db/firmware/src/assets/fblocks.png
--------------------------------------------------------------------------------
/firmware/src/assets/gen-assets.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | from itertools import groupby
4 | import sys
5 |
6 | from PIL import Image
7 | from PIL import BdfFontFile
8 | from xml.etree import ElementTree
9 |
10 | white_pixel = 255
11 |
12 | defs = []
13 |
14 | ########################################################################
15 | # General helper functions
16 | ########################################################################
17 |
18 |
19 | def by_n(n, seq):
20 | return ((x for (i, x) in g)
21 | for (k, g) in groupby(enumerate(seq), lambda x: x[0] // n))
22 |
23 |
24 | def pack_rgb565(tup):
25 | return (tup[0] >> 3 << 11 |
26 | tup[1] >> 2 << 5 |
27 | tup[2] >> 3 << 0)
28 |
29 |
30 | def rgb888_to_rgb565(val):
31 | return (((val & 0xFF0000) >> 19) << 11 |
32 | ((val & 0x00FF00) >> 10) << 5 |
33 | ((val & 0x0000FF) >> 3) << 0)
34 |
35 | ########################################################################
36 | # Definition functions
37 | ########################################################################
38 |
39 | def pixmap(path, name):
40 | img = Image.open(path)
41 | img = img.convert("RGBA")
42 | pix = img.load()
43 | w, h = img.size
44 | packed = [[pack_rgb565(pix[x, y])
45 | for x in range(w)]
46 | for y in range(h)]
47 | data = ',\n'.join(' {{ {} }}'
48 | .format(',\n '.join(', '.join('{:3d}'.format(b)
49 | for b in line)
50 | for line in by_n(8, row)))
51 | for row in packed)
52 | template = '''
53 | #define {NAME}_PIXMAP_HEIGHT {h}
54 | #define {NAME}_PIXMAP_WIDTH {w}
55 |
56 | static const uint16_t {name}_pixmap[{NAME}_PIXMAP_HEIGHT][{NAME}_PIXMAP_WIDTH] = {{
57 | {data}
58 | }};'''.lstrip()
59 | return template.format(name=name, NAME=name.upper(), h=h, w=w, data=data)
60 |
61 | def tilemap(path, name):
62 | e = ElementTree.parse(path).getroot()
63 | w = int(e.attrib['width'])
64 | h = int(e.attrib['height'])
65 | background = rgb888_to_rgb565(int(e.attrib['backgroundcolor']
66 | .replace("#", ""), 16))
67 | def filter_empty(x):
68 | return list(filter(lambda d: len(d) > 0, x))
69 | # Split the data apart and remove empty stuff while doing it and convert the numbers to ints.
70 | layers = list(map(lambda l: list(map(lambda d: list(map(lambda i: int(i), filter_empty(d.split(",")))),
71 | filter_empty(l.find('data').text.split("\n")))), e.findall('layer')))
72 | # Convert the gathered layer data into a usable C array.
73 | struct = ',\n'.join('{{ {} }}'
74 | .format(',\n '
75 | .join('{{ {} }}'
76 | .format(',\n '.join(','.join('{:3d}'.format(b)
77 | for b in line)
78 | for line in by_n(16, row)))
79 | for row in layer))
80 | for layer in layers)
81 | # We should restrict the tile indexes to 8bit, we can have multiple tilesets if needed... I don't think we need more
82 | # Than 255 tiles per tilemap.
83 | template = '''
84 | #define {NAME}_TILEMAP_LAYERS {l}
85 | #define {NAME}_TILEMAP_HEIGHT {h}
86 | #define {NAME}_TILEMAP_WIDTH {w}
87 | #define {NAME}_TILEMAP_BG_COLOR {bg_color}
88 |
89 | static const uint16_t {name}_tilemap[{NAME}_TILEMAP_LAYERS][{NAME}_TILEMAP_HEIGHT][{NAME}_TILEMAP_WIDTH] = {{
90 | {struct}
91 | }};'''.lstrip()
92 | return template.format(name=name, NAME=name.upper(), l=len(layers), h=h, w=w,
93 | bg_color=background, struct=struct)
94 |
95 | def font(path, name):
96 | ff = BdfFontFile.BdfFontFile(open(path, 'rb'))
97 | glyphs = []
98 | for c in range(33, 127):
99 | glyph = []
100 | glyph_pix = ff.glyph[c][3].load()
101 | for col in range(0, 4):
102 | col_byte = 0
103 | for row in range(0, 8):
104 | if glyph_pix[col, row] != 0:
105 | col_byte = col_byte | (0x1 << row)
106 | glyph.append(col_byte)
107 | glyphs.append(glyph)
108 | struct = ",\n".join('{{ {} }}'.format(", ".join('{:#04x}'.format(b)
109 | for b in glyph))
110 | for glyph in glyphs)
111 | template = '''
112 | #define {NAME}_FONT_WIDTH 4
113 | #define {NAME}_FONT_HEIGHT 8
114 | #define {NAME}_FONT_OFFSET 33
115 | #define {NAME}_FONT_GLYPH_COUNT {l}
116 |
117 | static const uint8_t {name}_font[{NAME}_FONT_GLYPH_COUNT][{NAME}_FONT_WIDTH] = {{
118 | {struct}
119 | }};'''.lstrip()
120 | return template.format(name=name, NAME=name.upper(), l=len(glyphs),
121 | struct=struct)
122 |
123 | ########################################################################
124 | # Game 1
125 | ########################################################################
126 |
127 | defs += [
128 | pixmap('tilesheet.png', 'ts'),
129 | pixmap('spritesheet.png', 'ss'),
130 | tilemap('1bitsy-1up-game1.tmx', 'tml1'),
131 | ]
132 |
133 | ########################################################################
134 | # Falling blocks
135 | ########################################################################
136 |
137 | defs += [
138 | pixmap('fblocks.png', 'fblocks'),
139 | ]
140 |
141 | ########################################################################
142 | # Miniwi font
143 | ########################################################################
144 |
145 | defs += [
146 | font('miniwi/miniwi-8.bdf', 'miniwi'),
147 | ]
148 |
149 | ########################################################################
150 | # Asset header body and output
151 | ########################################################################
152 |
153 | template = '''
154 | #ifndef ASSETS_H
155 | #define ASSETS_H
156 |
157 | /* This file was automatically generated by {program}. Do not edit. */
158 |
159 | #include
160 |
161 | {defs}
162 |
163 | #endif /* ASSETS_H */
164 | '''.lstrip()
165 |
166 | print(template.format(program=sys.argv[0], defs='\n\n'.join(defs)))
167 |
--------------------------------------------------------------------------------
/firmware/src/assets/spritesheet.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/1Bitsy/1bitsy-1up/54eddf3494c8faadea9018ee24a5c296e54b57db/firmware/src/assets/spritesheet.png
--------------------------------------------------------------------------------
/firmware/src/assets/tilesheet.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/1Bitsy/1bitsy-1up/54eddf3494c8faadea9018ee24a5c296e54b57db/firmware/src/assets/tilesheet.png
--------------------------------------------------------------------------------
/firmware/src/audio.c:
--------------------------------------------------------------------------------
1 | #include "audio.h"
2 |
3 | #include
4 |
5 | #include
6 | #ifndef DAC_SR // XXX DAC_SR is missing?
7 | #define DAC_SR MMIO32(DAC_BASE + 0x34)
8 | #define DAC_SR_DMAUDR2 (1 << 29)
9 | #define DAC_SR_DMAUDR1 (1 << 13)
10 | #endif
11 | #include
12 | #include
13 | #include
14 |
15 | // The Reference Manual says TIM6 and TIM7 are for the DACs. We only
16 | // need one, so we use TIM6.
17 | //
18 | // 20.1 TIM6&TIM7 introduction
19 | //
20 | // They may be used as generic timers for time-base generation but
21 | // they are also specifically used to drive the digial-to-analog
22 | // converter (DAC). In fact, the timers are internally connected
23 | // to the DAC and are able to drive it through their trigger outputs.
24 | //
25 | // [Reference manual, Document RM0090]
26 |
27 | static uint32_t sample_rate;
28 | static audio_channel_count channel_count;
29 | static audio_sample_depth sample_depth;
30 | static void *sample_buffer;
31 | static size_t buffer_bytes;
32 |
33 | static audio_callback_fn *registered_callback;
34 |
35 |
36 | // -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
37 |
38 |
39 | uint32_t audio_get_sample_rate(void)
40 | {
41 | return sample_rate;
42 | }
43 |
44 | audio_channel_count audio_get_channel_count(void)
45 | {
46 | return channel_count;
47 | }
48 |
49 | audio_sample_depth audio_get_sample_depth(void)
50 | {
51 | return sample_depth;
52 | }
53 |
54 | void *audio_get_sample_buffer(void)
55 | {
56 | return sample_buffer;
57 | }
58 |
59 | size_t audio_get_frame_bytes(void)
60 | {
61 | return channel_count * sample_depth;
62 | }
63 |
64 | size_t audio_get_frame_count(void)
65 | {
66 | return buffer_bytes / audio_get_frame_bytes();
67 | }
68 |
69 | size_t audio_get_byte_count(void)
70 | {
71 | return buffer_bytes;
72 | }
73 |
74 |
75 | // -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
76 |
77 |
78 | static void init_timer(void)
79 | {
80 | // XXX This happens to work but doesn't take into account all
81 | // XXX the ways the clocks could be configured.
82 | // XXX RCC_DCKCFGR.TIMPRE description:
83 | // XXX
84 | // XXX 0: If the APB prescaler (PPRE1, PPRE2 in the RCC_CFGR
85 | // XXX register) is configured to a division factor of 1,
86 | // XXX TIMxCLK = PCLKx. Otherwise, the timer clock
87 | // XXX frequencies are set to twice the frequency of the
88 | // XXX APB domain to which the timers are connected:
89 | // XXX TIMxCLK = 2xPCLKx.
90 | // XXX 1: If the APB prescaler (PPRE1, PPRE2 in the RCC_CFGR
91 | // XXX register) is configured to a division factor of 1,
92 | // XXX 2, or 4, TIMxCLK = HCLK. Otherwise, the timer clock
93 | // XXX frequencies are set to four times to the frequency
94 | // XXX [sic] of the APB domain to which the timers are
95 | // XXX connected: TIMxCLK = 4xPCLKx.
96 |
97 | uint32_t period = (2 * rcc_apb1_frequency + sample_rate / 2) / sample_rate;
98 |
99 | /* Enable TIM6 clock. */
100 | rcc_periph_clock_enable(RCC_TIM6);
101 | rcc_periph_reset_pulse(RST_TIM6);
102 | /* Timer global mode: - No divider, Alignment edge, Direction up */
103 | timer_set_mode(TIM6, TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP);
104 | timer_disable_preload(TIM6);
105 | timer_continuous_mode(TIM6);
106 | timer_update_on_overflow(TIM6);
107 | timer_set_period(TIM6, period);
108 | timer_set_master_mode(TIM6, TIM_CR2_MMS_UPDATE);
109 | }
110 |
111 | static void start_timer(void)
112 | {
113 | timer_enable_counter(TIM6);
114 | }
115 |
116 | static void stop_timer(void)
117 | {
118 | timer_disable_counter(TIM6);
119 | }
120 |
121 |
122 | // -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
123 |
124 |
125 | static void init_dma(void)
126 | {
127 | uint32_t mono_msize = 0, mono_psize = 0;
128 | uint32_t stereo_msize = 0, stereo_psize = 0;
129 | uint32_t cr_msize = 0, cr_psize = 0;
130 | volatile void *dhr1a = 0, *dhr2a = 0, *dhrda = 0;
131 |
132 | if (sample_depth == ASD_8BIT) {
133 | mono_msize = DMA_SxCR_MSIZE_8BIT;
134 | mono_psize = DMA_SxCR_PSIZE_8BIT;
135 | stereo_msize = DMA_SxCR_MSIZE_16BIT;
136 | stereo_psize = DMA_SxCR_PSIZE_16BIT;
137 | dhr1a = &DAC_DHR8R1;
138 | dhr2a = &DAC_DHR8R2;
139 | dhrda = &DAC_DHR8RD;
140 | } else if (sample_depth == ASD_12BIT) {
141 | mono_msize = DMA_SxCR_MSIZE_16BIT;
142 | mono_psize = DMA_SxCR_PSIZE_16BIT;
143 | stereo_msize = DMA_SxCR_MSIZE_32BIT;
144 | stereo_psize = DMA_SxCR_PSIZE_32BIT;
145 | dhr1a = &DAC_DHR12R1;
146 | dhr2a = &DAC_DHR12R2;
147 | dhrda = &DAC_DHR12RD;
148 | }
149 |
150 | if (channel_count == ACC_STEREO) {
151 | dhr1a = dhrda;
152 | cr_msize = stereo_msize;
153 | cr_psize = stereo_psize;
154 | } else if (channel_count == ACC_MONO) {
155 | cr_msize = mono_msize;
156 | cr_psize = mono_psize;
157 | }
158 |
159 | /* DAC channel 1 uses DMA controller 1 Stream 5 Channel 7. */
160 | /* Enable DMA1 clock and IRQ */
161 | rcc_periph_clock_enable(RCC_DMA1);
162 |
163 | /* Setup Stream5 Channel7 for DAC1 (mono) or both DACs (stereo) */
164 | nvic_enable_irq(NVIC_DMA1_STREAM5_IRQ);
165 | dma_stream_reset(DMA1, DMA_STREAM5);
166 | dma_set_priority(DMA1, DMA_STREAM5, DMA_SxCR_PL_LOW);
167 | dma_set_memory_size(DMA1, DMA_STREAM5, cr_msize);
168 | dma_set_peripheral_size(DMA1, DMA_STREAM5, cr_psize);
169 | dma_enable_memory_increment_mode(DMA1, DMA_STREAM5);
170 | dma_enable_circular_mode(DMA1, DMA_STREAM5);
171 | dma_set_transfer_mode(DMA1, DMA_STREAM5, DMA_SxCR_DIR_MEM_TO_PERIPHERAL);
172 | dma_set_peripheral_address(DMA1, DMA_STREAM5, (uint32_t) dhr1a);
173 | dma_set_memory_address(DMA1, DMA_STREAM5, (uint32_t) sample_buffer);
174 | dma_set_number_of_data(DMA1, DMA_STREAM5, audio_get_frame_count());
175 | dma_enable_half_transfer_interrupt(DMA1, DMA_STREAM5);
176 | dma_enable_transfer_complete_interrupt(DMA1, DMA_STREAM5);
177 | dma_channel_select(DMA1, DMA_STREAM5, DMA_SxCR_CHSEL_7);
178 | dma_enable_stream(DMA1, DMA_STREAM5);
179 |
180 | if (channel_count == ACC_MONO) {
181 | /* Setup Stream6 Channel7 for DAC2 */
182 | dma_stream_reset(DMA1, DMA_STREAM6);
183 | dma_set_priority(DMA1, DMA_STREAM6, DMA_SxCR_PL_LOW);
184 | dma_set_memory_size(DMA1, DMA_STREAM6, cr_msize);
185 | dma_set_peripheral_size(DMA1, DMA_STREAM6, cr_psize);
186 | dma_enable_memory_increment_mode(DMA1, DMA_STREAM6);
187 | dma_enable_circular_mode(DMA1, DMA_STREAM6);
188 | dma_set_transfer_mode(DMA1, DMA_STREAM6,
189 | DMA_SxCR_DIR_MEM_TO_PERIPHERAL);
190 | dma_set_peripheral_address(DMA1, DMA_STREAM6, (uint32_t) dhr2a);
191 | dma_set_memory_address(DMA1, DMA_STREAM6, (uint32_t)sample_buffer);
192 | dma_set_number_of_data(DMA1, DMA_STREAM6, audio_get_frame_count());
193 | dma_channel_select(DMA1, DMA_STREAM6, DMA_SxCR_CHSEL_7);
194 | dma_enable_stream(DMA1, DMA_STREAM6);
195 | }
196 | }
197 |
198 | static void stop_dma(void)
199 | {
200 | dma_disable_stream(DMA1, DMA_STREAM5);
201 | dma_disable_stream(DMA1, DMA_STREAM6);
202 | }
203 |
204 | void dma1_stream5_isr(void)
205 | {
206 | size_t half_frames = audio_get_frame_count() / 2;
207 | if (dma_get_interrupt_flag(DMA1, DMA_STREAM5, DMA_HTIF)) {
208 | dma_clear_interrupt_flags(DMA1, DMA_STREAM5, DMA_HTIF);
209 | (*registered_callback)(sample_buffer, half_frames);
210 | }
211 | if (dma_get_interrupt_flag(DMA1, DMA_STREAM5, DMA_TCIF)) {
212 | dma_clear_interrupt_flags(DMA1, DMA_STREAM5, DMA_TCIF);
213 | (*registered_callback)(sample_buffer + buffer_bytes / 2, half_frames);
214 | }
215 | }
216 |
217 |
218 | // -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
219 |
220 |
221 | static void init_dac()
222 | {
223 | uint32_t mamp1 = 0, mamp2 = 0;
224 | if (sample_depth == ASD_12BIT) {
225 | mamp1 = DAC_CR_MAMP1_1;
226 | mamp2 = DAC_CR_MAMP2_1;
227 | } else if (sample_depth == ASD_8BIT) {
228 | // Avoid quantization noise with a high masking noise.
229 | mamp1 = DAC_CR_MAMP1_5;
230 | mamp2 = DAC_CR_MAMP2_5;
231 | }
232 |
233 | /* Enable the DAC clock on APB1 */
234 | rcc_periph_clock_enable(RCC_DAC);
235 |
236 | /* Setup the DAC channel 1 with timer 6 as trigger source. */
237 | dac_trigger_enable(CHANNEL_1);
238 | dac_set_trigger_source(DAC_CR_TSEL1_T6);
239 | dac_dma_enable(CHANNEL_1);
240 | dac_enable(CHANNEL_1);
241 | dac_set_waveform_generation(DAC_CR_WAVE1_NOISE);
242 | dac_set_waveform_characteristics(mamp1);
243 |
244 | /* Setup the DAC channel 2 with timer 6 as trigger source. */
245 | dac_trigger_enable(CHANNEL_2);
246 | dac_set_trigger_source(DAC_CR_TSEL2_T6);
247 | dac_dma_enable(CHANNEL_2);
248 | dac_enable(CHANNEL_2);
249 | dac_set_waveform_generation(DAC_CR_WAVE2_NOISE);
250 | dac_set_waveform_characteristics(mamp2);
251 | }
252 |
253 | static void stop_dac(void)
254 | {
255 | dac_load_data_buffer_dual(0, 0, RIGHT12);
256 | // Don't actually stop the DAC. Leave it running but stop feeding
257 | // it new samples. Otherwise it will probably click.
258 | }
259 |
260 |
261 | void audio_init(uint32_t Fs,
262 | audio_channel_count nchan,
263 | audio_sample_depth depth,
264 | void *buffer,
265 | size_t byte_count)
266 | {
267 | audio_stop();
268 |
269 | sample_rate = Fs;
270 | channel_count = nchan;
271 | sample_depth = depth;
272 | if (buffer) {
273 | sample_buffer = buffer;
274 | buffer_bytes = byte_count;
275 | }
276 | }
277 |
278 | audio_callback_fn *audio_register_callback(audio_callback_fn *new)
279 | {
280 | audio_callback_fn *prev = registered_callback;
281 | registered_callback = new;
282 | return prev;
283 | }
284 |
285 | void audio_start(void)
286 | {
287 | init_timer();
288 | init_dma();
289 | init_dac();
290 | start_timer();
291 | }
292 |
293 | void audio_stop(void)
294 | {
295 | stop_dma();
296 | stop_dac();
297 | stop_timer();
298 | }
299 |
--------------------------------------------------------------------------------
/firmware/src/audio.h:
--------------------------------------------------------------------------------
1 | #ifndef AUDIO_included
2 | #define AUDIO_included
3 |
4 | #include
5 | #include
6 |
7 |
8 | // Terminology:
9 | // A `sample` is a single 8 or 12 bit PCM value.
10 | // A `frame` is a set of samples that should be emitted at the same instant.
11 | // (one sample for mono, two samples for stereo).
12 | // The sample rate is actually the number of frames per second, not samples.
13 | //
14 | // 12 bit samples are right-aligned: they come from the least
15 | // significant 12 bits of each 16 bit word.
16 | //
17 | // N.B., stereo mode causes less memory contention than mono.
18 | // So stereo may allow a higher video frame rate.
19 |
20 |
21 | typedef enum audio_channel_count {
22 | ACC_MONO = 1,
23 | ACC_STEREO = 2,
24 | } audio_channel_count;
25 |
26 | typedef enum audio_sample_depth {
27 | ASD_8BIT = 1,
28 | ASD_12BIT = 2,
29 | } audio_sample_depth;
30 |
31 |
32 | // Audio callback fills buffer with new frames.
33 | //
34 | // Type of buffer and number of samples depends on how audio was
35 | // initialized.
36 | //
37 | // Stereo channels are interleaved: even samples are left channel, odd
38 | // samples are right channel.
39 | //
40 | // sample_depth channel_count bytes_per_frame
41 | // 8 1 1
42 | // 8 2 2
43 | // 12 1 2
44 | // 12 2 4
45 |
46 |
47 | typedef void audio_callback_fn(void *frames_out, size_t frame_count);
48 |
49 | #define DEFINE_AUDIO_BUFFER(name, frames, channels, depth) \
50 | static uint8_t name[2 * (frames) * (channels) * (depth)] \
51 | __attribute__((section(".sram2")));
52 |
53 | // Pass NULL for buffer to reuse existing buffer.
54 | extern void audio_init (uint32_t sample_rate,
55 | audio_channel_count,
56 | audio_sample_depth,
57 | void *buffer,
58 | size_t byte_count);
59 |
60 | extern uint32_t audio_get_sample_rate (void);
61 | extern audio_channel_count audio_get_channel_count (void);
62 | extern audio_sample_depth audio_get_sample_depth (void);
63 | extern void *audio_get_sample_buffer (void);
64 | extern size_t audio_get_frame_bytes (void);
65 | extern size_t audio_get_frame_count (void);
66 | extern size_t audio_get_byte_count (void);
67 |
68 | /* returns previous callback. */
69 | extern audio_callback_fn *audio_register_callback (audio_callback_fn *);
70 |
71 | extern void audio_start (void);
72 | extern void audio_stop (void);
73 |
74 | #endif /* !AUDIO_included */
75 |
--------------------------------------------------------------------------------
/firmware/src/audio_app.c:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the 1Bitsy 1UP retro inspired game console project.
3 | *
4 | * Copyright (C) 2017 Piotr Esden-Tempski
5 | *
6 | * This program is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This program is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | */
19 |
20 | #include "audio_app.h"
21 |
22 | #include
23 |
24 | #include "audio.h"
25 | #include "button_boot.h"
26 | #include "gamepad.h"
27 | #include "lcd.h"
28 | #include "led.h"
29 | #include "math-util.h"
30 | #include "pam8019.h"
31 | #include "systick.h"
32 | #include "text.h"
33 | #include "volume.h"
34 |
35 | // Define these to test other audio paths.
36 | //#define MONO
37 | //#define BIT8
38 |
39 | #define Fs (44100.0)
40 | #define FREQ0 (440.0 / 8) // A1, 55Hz
41 | #define FREQ1 (523.3 / 8) // C2, 64 Hz
42 |
43 | #ifdef MONO
44 | #define ACC ACC_MONO
45 | #else
46 | #define ACC ACC_STEREO
47 | #endif
48 |
49 | #ifdef BIT8
50 | typedef uint8_t sample;
51 | #define SAMP_MAX 255
52 | #define ASD ASD_8BIT
53 | #else
54 | typedef uint16_t sample;
55 | #define SAMP_MAX 4095
56 | #define ASD ASD_12BIT
57 | #endif
58 |
59 | typedef enum text_row {
60 | TR_HEADER = 3,
61 | TR_INSTR = 5,
62 | TR_MODE = 7,
63 | TR_OUTPUT = 8,
64 | TR_VOL = 10,
65 | TR_VOLBAR = 11,
66 | TR_RAWVOL = 12,
67 | TR_RVBAR = 13,
68 | } text_row;
69 |
70 | typedef enum text_col {
71 | TC_LEFT = 4,
72 | } text_col;
73 |
74 | static const gfx_rgb565 bg_color = 0xF81F;
75 | static const gfx_rgb565 vol_color = 0x07E0;
76 |
77 | static bool vol_is_visible;
78 | static pam8019_mode cur_mode;
79 | static uint8_t vol;
80 | static uint8_t prev_vol;
81 | static uint16_t raw_vol;
82 |
83 | // char abuf[704] __attribute__((section(".sram2")));
84 | #define FRAMES ((int)Fs / 250)
85 | DEFINE_AUDIO_BUFFER(abuf, FRAMES, ACC, ASD);
86 |
87 | #ifdef MONO
88 |
89 | static void audio_callback(void *buf, size_t frame_count)
90 | {
91 | sample *frames = buf;
92 | static float phase;
93 |
94 | for (size_t i = 0; i < frame_count; i++) {
95 | frames[i] = phase * SAMP_MAX;
96 | phase += FREQ0 / Fs;
97 | if (phase >= 1.0)
98 | phase -= 1.0;
99 | }
100 | }
101 |
102 | #else
103 |
104 | static void audio_callback(void *buf, size_t frame_count)
105 | {
106 | sample (*frames)[2] = buf;
107 | static float phase[2];
108 |
109 | for (size_t i = 0; i < frame_count; i++) {
110 | frames[i][0] = phase[0] * SAMP_MAX;
111 | frames[i][1] = SAMP_MAX - phase[1] * SAMP_MAX;
112 | phase[0] += FREQ0 / Fs;
113 | phase[1] += FREQ1 / Fs;
114 | if (phase[0] >= 1.0)
115 | phase[0] -= 1.0;
116 | if (phase[1] >= 1.0)
117 | phase[1] -= 1.0;
118 | }
119 | }
120 |
121 | #endif
122 |
123 | void audio_app_init(void)
124 | {
125 | audio_init(44100, ACC, ASD, abuf, sizeof abuf);
126 | audio_register_callback(audio_callback);
127 | pam8019_set_mode(PM_NORMAL);
128 | audio_start();
129 | prev_vol = volume_get();
130 | }
131 |
132 | void audio_app_end(void)
133 | {
134 | audio_stop();
135 | pam8019_set_mode(PM_SHUTDOWN);
136 | }
137 |
138 | void audio_animate(void)
139 | {
140 | // Volume control is visible if volume changed in last 800 msec.
141 |
142 | const uint32_t VOL_FADE_TIME = 800;
143 | static uint32_t vol_change_time = 0xF0000000; // large negative
144 |
145 | cur_mode = pam8019_get_mode();
146 | vol = volume_get();
147 | raw_vol = volume_get_raw();
148 |
149 | if (prev_vol != vol) {
150 | prev_vol = vol;
151 | vol_change_time = system_millis;
152 | }
153 | vol_is_visible = system_millis - vol_change_time < VOL_FADE_TIME;
154 |
155 | uint16_t buttons = gamepad_get();
156 | static uint16_t prev_buttons;
157 |
158 | if ((buttons & ~prev_buttons) & GAMEPAD_BSELECT) {
159 |
160 | cur_mode = pam8019_get_mode() + 1;
161 | if (cur_mode == PM_END)
162 | cur_mode = PM_START;
163 | pam8019_set_mode(cur_mode);
164 | }
165 | prev_buttons = buttons;
166 | }
167 |
168 | static void audio_draw_vol(gfx_pixslice *slice)
169 | {
170 | const int text_y = TR_VOL;
171 | const int text_x = TC_LEFT;
172 | const int bar_x = 8 * text_x;
173 | const int bar_y = TR_VOLBAR * 16;
174 | const int bar_h = 15;
175 |
176 | if (!vol_is_visible) {
177 | return;
178 | }
179 |
180 |
181 | int xoff = text_x;
182 | xoff = text_draw_str16(slice, "Volume: ", xoff, text_y, vol_color);
183 |
184 | /* hundreds place */
185 | char h = vol < 100 ? ' ' : '0' + vol / 100 % 10;
186 | text_draw_char16(slice, h, xoff, text_y, vol_color);
187 | xoff++;
188 |
189 | /* tens place */
190 | char t = vol < 10 ? ' ' : '0' + vol / 10 % 10;
191 | text_draw_char16(slice, t, xoff, text_y, vol_color);
192 | xoff++;
193 |
194 | /* ones place */
195 | char o = '0' + vol / 1 % 10;
196 | text_draw_char16(slice, o, xoff, text_y, vol_color);
197 | xoff++;
198 |
199 | /* outline volume bar */
200 | for (int y = bar_y; y < bar_y + bar_h; y++) {
201 | gfx_rgb565 *px = gfx_pixel_address(slice, bar_x, y);
202 | px[0] = px[VOLUME_MAX * 4] = vol_color;
203 | }
204 | gfx_rgb565 *px0 = gfx_pixel_address(slice, bar_x, bar_y);
205 | gfx_rgb565 *px1 = gfx_pixel_address(slice, bar_x, bar_y + bar_h - 1);
206 | if (px0) {
207 | for (int x = 4 * vol + 1; x < 4 * VOLUME_MAX; x++) {
208 | px0[x] = vol_color;
209 | }
210 | }
211 | if (px1) {
212 | for (int x = 4 * vol + 1; x < 4 * VOLUME_MAX; x++) {
213 | px1[x] = vol_color;
214 | }
215 | }
216 |
217 | /* fill volume bar */
218 | for (int y = bar_y; y < bar_y + bar_h; y++) {
219 | gfx_rgb565 *px = gfx_pixel_address(slice, bar_x, y);
220 | if (px) {
221 | for (int x = 0; x < 4 * vol; x++) {
222 | if (x % 6) {
223 | px[x] = vol_color;
224 | }
225 | }
226 | }
227 | }
228 | }
229 |
230 | static void audio_draw_raw_vol(gfx_pixslice *slice)
231 | {
232 | const int text_y = TR_RAWVOL;
233 | const int text_x = TC_LEFT;
234 | const int bar_x = 8 * text_x;
235 | const int bar_y = TR_RVBAR * 16;
236 | const int bar_h = 15;
237 |
238 | if (!vol_is_visible) {
239 | return;
240 | }
241 |
242 | char *prefix = "raw vol: ";
243 |
244 | int xoff = text_x;
245 | for (const char *p = prefix; *p; p++) {
246 | text_draw_char16(slice, *p, xoff, text_y, vol_color);
247 | xoff++;
248 | }
249 |
250 | /* thousands place */
251 | char k = raw_vol < 1000 ? ' ' : '0' + raw_vol / 1000 % 10;
252 | text_draw_char16(slice, k, xoff, text_y, vol_color);
253 | xoff++;
254 |
255 | /* hundreds place */
256 | char h = raw_vol < 100 ? ' ' : '0' + raw_vol / 100 % 10;
257 | text_draw_char16(slice, h, xoff, text_y, vol_color);
258 | xoff++;
259 |
260 | /* tens place */
261 | char t = raw_vol < 10 ? ' ' : '0' + raw_vol / 10 % 10;
262 | text_draw_char16(slice, t, xoff, text_y, vol_color);
263 | xoff++;
264 |
265 | /* ones place */
266 | char o = '0' + raw_vol / 1 % 10;
267 | text_draw_char16(slice, o, xoff, text_y, vol_color);
268 | xoff++;
269 |
270 | /* outline volume bar */
271 | for (int y = bar_y; y < bar_y + bar_h; y++) {
272 | gfx_rgb565 *px = gfx_pixel_address(slice, bar_x, y);
273 | px[0] = px[VOLUME_RAW_MAX >> 4] = vol_color;
274 | }
275 | gfx_rgb565 *px0 = gfx_pixel_address(slice, bar_x, bar_y);
276 | gfx_rgb565 *px1 = gfx_pixel_address(slice, bar_x, bar_y + bar_h - 1);
277 | if (px0) {
278 | for (int x = 1; x < VOLUME_RAW_MAX >> 4; x++) {
279 | px0[x] = vol_color;
280 | }
281 | }
282 | if (px1) {
283 | for (int x = 1; x < VOLUME_RAW_MAX >> 4; x++) {
284 | px1[x] = vol_color;
285 | }
286 | }
287 |
288 | /* fill volume bar */
289 | for (int y = bar_y + 1; y < bar_y + bar_h - 1; y++) {
290 | gfx_rgb565 *px = gfx_pixel_address(slice, bar_x, y);
291 | if (px) {
292 | for (int x = 0; x < raw_vol >> 4; x++) {
293 | px[x] = vol_color;
294 | }
295 | }
296 | }
297 | }
298 |
299 | static void audio_draw_header(gfx_pixslice *slice)
300 | {
301 | int text_y = TR_HEADER;
302 | int text_x = TC_LEFT;
303 | text_draw_str16(slice, "Audio Saw Test", text_x, text_y, vol_color);
304 | }
305 |
306 | static void audio_draw_instructions(gfx_pixslice *slice)
307 | {
308 | int text_y = TR_INSTR;
309 | int text_x = TC_LEFT;
310 | text_draw_str16(slice, "Press SELECT to change mode.",
311 | text_x, text_y, vol_color);
312 | }
313 |
314 | static void audio_draw_mode(gfx_pixslice *slice)
315 | {
316 | const char *mode_str;
317 | switch (cur_mode) {
318 | case PM_SHUTDOWN:
319 | mode_str = "Shutdown";
320 | break;
321 |
322 | case PM_MUTED:
323 | mode_str = "Muted";
324 | break;
325 |
326 | case PM_NORMAL:
327 | mode_str = "Normal";
328 | break;
329 |
330 | case PM_OVERRIDE_HP:
331 | mode_str = "Force Headphones";
332 | break;
333 |
334 | case PM_OVERRIDE_SPKR:
335 | mode_str = "Force Speaker";
336 | break;
337 |
338 | default:
339 | assert(false);
340 | }
341 | int text_y = TR_MODE;
342 | int text_x = TC_LEFT;
343 | int xoff = text_draw_str16(slice, "Mode: ", text_x, text_y, vol_color);
344 | xoff = text_draw_str16(slice, mode_str, xoff, text_y, vol_color);
345 |
346 | }
347 |
348 | static void audio_draw_output(gfx_pixslice *slice)
349 | {
350 | int text_y = TR_OUTPUT;
351 | int text_x = TC_LEFT;
352 | int xoff = text_draw_str16(slice, "Output: ", text_x, text_y, vol_color);
353 | const char *out = pam8019_output_is_headphones() ? "Headphones" : "Speaker";
354 | xoff = text_draw_str16(slice, out, xoff, text_y, vol_color);
355 | }
356 |
357 | static void audio_render_slice(gfx_pixslice *slice)
358 | {
359 | audio_draw_header(slice);
360 | audio_draw_instructions(slice);
361 | audio_draw_mode(slice);
362 | audio_draw_output(slice);
363 | audio_draw_vol(slice);
364 | audio_draw_raw_vol(slice);
365 | }
366 |
367 | void audio_render(void)
368 | {
369 | if (lcd_bg_color() != bg_color) {
370 | lcd_set_bg_color(bg_color, true);
371 | }
372 |
373 | for (size_t y = 0, h; y < LCD_HEIGHT; y += h) {
374 | h = MIN(LCD_MAX_SLICE_ROWS, LCD_HEIGHT - y);
375 | gfx_pixslice *slice = lcd_alloc_pixslice(0, y, LCD_WIDTH, h);
376 | audio_render_slice(slice);
377 | lcd_send_pixslice(slice);
378 | }
379 | }
380 |
--------------------------------------------------------------------------------
/firmware/src/audio_app.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the 1Bitsy 1UP retro inspired game console project.
3 | *
4 | * Copyright (C) 2017 Piotr Esden-Tempski
5 | *
6 | * This program is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This program is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | */
19 |
20 | #ifndef AUDIO_APP_H
21 | #define AUDIO_APP_H
22 |
23 | extern void audio_app_init(void);
24 | extern void audio_animate(void);
25 | extern void audio_render(void);
26 | extern void audio_app_end(void);
27 |
28 | #endif /* AUDIO_APP_H */
29 |
--------------------------------------------------------------------------------
/firmware/src/button_boot.c:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the libopencm3 project.
3 | *
4 | * Copyright (C) 2016 Piotr Esden-Tempski
5 | *
6 | * This library is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU Lesser General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This library is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU Lesser General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU Lesser General Public License
17 | * along with this library. If not, see .
18 | */
19 |
20 | #include "button_boot.h" // module's own include is always first.
21 |
22 | #include
23 |
24 | #include
25 | #include
26 | #include
27 |
28 | #include "gpio.h"
29 |
30 | #define BLDR_ADDRESS 0x1FFF0000
31 |
32 | static const gpio_pin button_pin = {
33 | .gp_port = GPIOC,
34 | .gp_pin = GPIO1,
35 | .gp_mode = GPIO_MODE_INPUT,
36 | };
37 |
38 | static uint32_t button_debounce = 0;
39 |
40 | void button_boot(void) {
41 | #if 0
42 | /* Enable GPIOC clock. */
43 | rcc_periph_clock_enable(RCC_GPIOC);
44 | rcc_periph_clock_enable(RCC_GPIOA);
45 | /* Set GPIO1 (in GPIO port C) to 'input open-drain'. */
46 | gpio_mode_setup(GPIOC, GPIO_MODE_INPUT, GPIO_PUPD_NONE, GPIO1);
47 | gpio_mode_setup(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO8);
48 | #else
49 | gpio_init_pin(&button_pin);
50 | #endif
51 |
52 | /* Check if the user button is depressed, if so launch the factory bootloader */
53 | #if 0
54 | if ((GPIOC_IDR & (1 << 1)) == 0) {
55 | #else
56 | if (button_pressed()) {
57 | #endif
58 | /* Set vector table base address. */
59 | SCB_VTOR = BLDR_ADDRESS & 0xFFFF;
60 | /* Initialise master stack pointer. */
61 | asm volatile("msr msp, %0"::"g"
62 | (*(volatile uint32_t *)BLDR_ADDRESS));
63 | /* Jump to bootloader. */
64 | (*(void (**)())(BLDR_ADDRESS + 4))();
65 | }
66 | }
67 |
68 | bool button_pressed(void) {
69 | return gpio_get(button_pin.gp_port, button_pin.gp_pin) == 0;
70 | }
71 |
72 | bool button_pressed_debounce(void) {
73 |
74 | if (button_pressed()) {
75 | button_debounce <<= 1;
76 | button_debounce |= 1;
77 | } else {
78 | button_debounce = 0;
79 | }
80 |
81 | return (button_debounce == 0xFFFFFFFF);
82 | }
83 |
84 | bool button_released_debounce(void) {
85 |
86 | if (!button_pressed()) {
87 | button_debounce <<= 1;
88 | } else {
89 | button_debounce = 0xFFFFFFFF;
90 | }
91 |
92 | return (button_debounce == 0);
93 | }
94 |
--------------------------------------------------------------------------------
/firmware/src/button_boot.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the libopencm3 project.
3 | *
4 | * Copyright (C) 2016 Piotr Esden-Tempski
5 | *
6 | * This library is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU Lesser General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This library is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU Lesser General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU Lesser General Public License
17 | * along with this library. If not, see .
18 | */
19 |
20 | #ifndef COMMON_BUTTON_BOOT_H
21 | #define COMMON_BUTTON_BOOT_H
22 |
23 | #include
24 |
25 | /* This function sets up and checks the state of the user button.
26 | * If the user button is depressed the built in factory bootloader is launched.
27 | */
28 | void button_boot(void);
29 |
30 | /* As we are already messing around with the user button in this driver we can
31 | * also check if it is depressed in the user code too. "it is fine" :D
32 | */
33 | bool button_pressed(void);
34 |
35 | /* A version of button_pressed with built in debouncer state. It will only return
36 | * true when after 32 calls of the function the button is still depressed.
37 | */
38 | bool button_pressed_debounce(void);
39 |
40 | /* A version of button_released with built in debouncer state. It will only return
41 | * true when after 32 calls of the function the button is still released.
42 | */
43 | bool button_released_debounce(void);
44 |
45 | #endif /* COMMON_BUTTON_BOOT_H */
46 |
--------------------------------------------------------------------------------
/firmware/src/fblocks_app.c:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the 1Bitsy 1UP retro inspired game console project.
3 | *
4 | * Copyright (C) 2017 Nicolas Schodet
5 | *
6 | * This program is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This program is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | */
19 |
20 | #include "gamepad.h"
21 | #include "lcd.h"
22 | #include "math-util.h"
23 | #include "systick.h"
24 | #include "text.h"
25 |
26 | #include
27 | #include
28 | #include
29 | #include
30 |
31 | #include "assets/assets.h"
32 |
33 | #define FBLOCKS_COLS 10
34 | #define FBLOCKS_ROWS 22
35 | #define FBLOCKS_VISIBLE_ROWS 20
36 |
37 | struct fblocks_shape_t {
38 | int rows, cols;
39 | uint8_t grid[4][4];
40 | };
41 |
42 | struct fblocks_piece_t {
43 | int shape_count;
44 | struct fblocks_shape_t shapes[4];
45 | };
46 |
47 | #define FBLOCKS_PIECES 7
48 |
49 | static const struct fblocks_piece_t fblocks_pieces[FBLOCKS_PIECES] = {
50 | /* {{{ */
51 | { 2, {
52 | { 1, 4, {
53 | { 2, 2, 2, 2 },
54 | { 0, 0, 0, 0 },
55 | { 0, 0, 0, 0 },
56 | { 0, 0, 0, 0 },
57 | } },
58 | { 4, 1, {
59 | { 2, 0, 0, 0 },
60 | { 2, 0, 0, 0 },
61 | { 2, 0, 0, 0 },
62 | { 2, 0, 0, 0 },
63 | } },
64 | } },
65 | { 1, {
66 | { 2, 2, {
67 | { 3, 3, 0, 0 },
68 | { 3, 3, 0, 0 },
69 | { 0, 0, 0, 0 },
70 | { 0, 0, 0, 0 },
71 | } },
72 | } },
73 | { 2, {
74 | { 2, 3, {
75 | { 0, 4, 4, 0 },
76 | { 4, 4, 0, 0 },
77 | { 0, 0, 0, 0 },
78 | { 0, 0, 0, 0 },
79 | } },
80 | { 3, 2, {
81 | { 4, 0, 0, 0 },
82 | { 4, 4, 0, 0 },
83 | { 0, 4, 0, 0 },
84 | { 0, 0, 0, 0 },
85 | } },
86 | } },
87 | { 2, {
88 | { 2, 3, {
89 | { 8, 8, 0, 0 },
90 | { 0, 8, 8, 0 },
91 | { 0, 0, 0, 0 },
92 | { 0, 0, 0, 0 },
93 | } },
94 | { 3, 2, {
95 | { 0, 8, 0, 0 },
96 | { 8, 8, 0, 0 },
97 | { 8, 0, 0, 0 },
98 | { 0, 0, 0, 0 },
99 | } },
100 | } },
101 | { 4, {
102 | { 2, 3, {
103 | { 5, 5, 5, 0 },
104 | { 5, 0, 0, 0 },
105 | { 0, 0, 0, 0 },
106 | { 0, 0, 0, 0 },
107 | } },
108 | { 3, 2, {
109 | { 5, 5, 0, 0 },
110 | { 0, 5, 0, 0 },
111 | { 0, 5, 0, 0 },
112 | { 0, 0, 0, 0 },
113 | } },
114 | { 2, 3, {
115 | { 0, 0, 5, 0 },
116 | { 5, 5, 5, 0 },
117 | { 0, 0, 0, 0 },
118 | { 0, 0, 0, 0 },
119 | } },
120 | { 3, 2, {
121 | { 5, 0, 0, 0 },
122 | { 5, 0, 0, 0 },
123 | { 5, 5, 0, 0 },
124 | { 0, 0, 0, 0 },
125 | } },
126 | } },
127 | { 4, {
128 | { 2, 3, {
129 | { 6, 6, 6, 0 },
130 | { 0, 0, 6, 0 },
131 | { 0, 0, 0, 0 },
132 | { 0, 0, 0, 0 },
133 | } },
134 | { 3, 2, {
135 | { 0, 6, 0, 0 },
136 | { 0, 6, 0, 0 },
137 | { 6, 6, 0, 0 },
138 | { 0, 0, 0, 0 },
139 | } },
140 | { 2, 3, {
141 | { 6, 0, 0, 0 },
142 | { 6, 6, 6, 0 },
143 | { 0, 0, 0, 0 },
144 | { 0, 0, 0, 0 },
145 | } },
146 | { 3, 2, {
147 | { 6, 6, 0, 0 },
148 | { 6, 0, 0, 0 },
149 | { 6, 0, 0, 0 },
150 | { 0, 0, 0, 0 },
151 | } },
152 | } },
153 | { 4, {
154 | { 2, 3, {
155 | { 7, 7, 7, 0 },
156 | { 0, 7, 0, 0 },
157 | { 0, 0, 0, 0 },
158 | { 0, 0, 0, 0 },
159 | } },
160 | { 3, 2, {
161 | { 0, 7, 0, 0 },
162 | { 7, 7, 0, 0 },
163 | { 0, 7, 0, 0 },
164 | { 0, 0, 0, 0 },
165 | } },
166 | { 2, 3, {
167 | { 0, 7, 0, 0 },
168 | { 7, 7, 7, 0 },
169 | { 0, 0, 0, 0 },
170 | { 0, 0, 0, 0 },
171 | } },
172 | { 3, 2, {
173 | { 7, 0, 0, 0 },
174 | { 7, 7, 0, 0 },
175 | { 7, 0, 0, 0 },
176 | { 0, 0, 0, 0 },
177 | } },
178 | } },
179 | /* }}} */
180 | };
181 |
182 | #define FBLOCKS_SCREEN_AREA_X (5 * 12)
183 | #define FBLOCKS_SCREEN_AREA_Y (0 * 12)
184 | #define FBLOCKS_SCREEN_AREA_W (FBLOCKS_COLS * 12)
185 | #define FBLOCKS_SCREEN_AREA_H (FBLOCKS_VISIBLE_ROWS * 12)
186 | #define FBLOCKS_SCREEN_PREVIEW_X (16 * 12)
187 | #define FBLOCKS_SCREEN_PREVIEW_Y (1 * 12)
188 | #define FBLOCKS_SCREEN_PREVIEW_W (5 * 12)
189 | #define FBLOCKS_SCREEN_PREVIEW_H (3 * 12)
190 | #define FBLOCKS_SCREEN_SCORE_X (16 * 12)
191 | #define FBLOCKS_SCREEN_SCORE_Y (5 * 12)
192 | #define FBLOCKS_SCREEN_SCORE_W (7 * 12)
193 | #define FBLOCKS_SCREEN_SCORE_H (2 * 12)
194 |
195 | static const uint8_t fblocks_screen[LCD_HEIGHT / 12][LCD_WIDTH / 12 + 1] = {
196 | { 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
197 | { 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1 },
198 | { 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1 },
199 | { 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1 },
200 | { 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
201 | { 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1 },
202 | { 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1 },
203 | { 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
204 | { 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
205 | { 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
206 | { 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
207 | { 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
208 | { 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
209 | { 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
210 | { 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
211 | { 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
212 | { 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
213 | { 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
214 | { 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
215 | { 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
216 | };
217 |
218 | #define FBLOCKS_START_FALL_SPEED 800
219 | #define FBLOCKS_AUTO_REPEAT_SPEED 100
220 | #define FBLOCKS_PREVIEW_COUNT 1
221 |
222 | struct fblocks_game_t;
223 |
224 | typedef bool (*fblocks_animation_t)(struct fblocks_game_t *game,
225 | gfx_pixslice *slice, int millis);
226 |
227 | struct fblocks_game_t {
228 | /* Playing area, row 0 is at bottom of screen. */
229 | uint8_t area[FBLOCKS_ROWS][FBLOCKS_COLS];
230 | /* Current score. */
231 | int score;
232 | /* Score to obtain to reach the next level. */
233 | int next_level_score;
234 | /* Current level. */
235 | int level;
236 | /* Current piece and shape. */
237 | const struct fblocks_piece_t *piece;
238 | const struct fblocks_shape_t *shape;
239 | /* Base of current piece position. */
240 | int row, col;
241 | /* Speed of fall. */
242 | int fall_speed;
243 | /* Date of last fall action. */
244 | uint32_t last_fall_millis;
245 | /* Date of last move action. */
246 | uint32_t last_move_millis;
247 | /* Previous gamepad state. */
248 | uint16_t last_gamepad;
249 | /* Animation. */
250 | fblocks_animation_t animation;
251 | uint32_t animation_start_millis;
252 | /* Bag of random pieces. */
253 | unsigned int bag;
254 | /* Future pieces. */
255 | const struct fblocks_piece_t *preview[FBLOCKS_PREVIEW_COUNT];
256 | /* Full row being removed or -1. */
257 | int full_row;
258 | /* You lose. */
259 | bool over;
260 | };
261 |
262 | static struct fblocks_game_t game;
263 |
264 | /* Initialise/reset game. */
265 | void fblocks_init(void) {
266 | memset(game.area, 0, sizeof(game.area));
267 | game.score = 0;
268 | game.next_level_score = 0;
269 | game.level = 1;
270 | game.piece = NULL;
271 | game.fall_speed = FBLOCKS_START_FALL_SPEED;
272 | game.last_fall_millis = system_millis;
273 | game.last_move_millis = system_millis;
274 | game.last_gamepad = 0;
275 | game.animation = NULL;
276 | game.animation_start_millis = 0;
277 | game.bag = 0;
278 | game.full_row = -1;
279 | game.over = true;
280 | }
281 |
282 | /* Undraw shape in area. */
283 | static void fblocks_unblit(struct fblocks_game_t *game) {
284 | const struct fblocks_shape_t *shape = game->shape;
285 | int row = game->row, col = game->col;
286 | for (int r = 0; r < shape->rows; r++) {
287 | for (int c = 0; c < shape->cols; c++) {
288 | if (shape->grid[r][c]) {
289 | game->area[row + r][col + c] = 0;
290 | }
291 | }
292 | }
293 | }
294 |
295 | /* Draw shape in area. */
296 | static void fblocks_blit(struct fblocks_game_t *game) {
297 | const struct fblocks_shape_t *shape = game->shape;
298 | int row = game->row, col = game->col;
299 | for (int r = 0; r < shape->rows; r++) {
300 | for (int c = 0; c < shape->cols; c++) {
301 | int s = shape->grid[r][c];
302 | if (s) {
303 | game->area[row + r][col + c] = s;
304 | }
305 | }
306 | }
307 | }
308 |
309 | /* Return true if there is a collision between play area and shape. */
310 | static bool fblocks_test(struct fblocks_game_t *game,
311 | const struct fblocks_shape_t *shape, int row, int col) {
312 | for (int r = 0; r < shape->rows; r++) {
313 | for (int c = 0; c < shape->cols; c++) {
314 | int s = shape->grid[r][c];
315 | if (s && game->area[row + r][col + c]) {
316 | return true;
317 | }
318 | }
319 | }
320 | return false;
321 | }
322 |
323 | /* Remove a row. */
324 | static void fblocks_remove_row(struct fblocks_game_t *game, int row) {
325 | for (int r = row; r < FBLOCKS_ROWS - 1; r++) {
326 | for (int c = 0; c < FBLOCKS_COLS; c++) {
327 | game->area[r][c] = game->area[r + 1][c];
328 | }
329 | }
330 | for (int c = 0; c < FBLOCKS_COLS; c++) {
331 | game->area[FBLOCKS_ROWS - 1][c] = 0;
332 | }
333 | }
334 |
335 | /* Find first full row or return -1. */
336 | static int fblocks_full_row(struct fblocks_game_t *game) {
337 | for (int r = 0; r < FBLOCKS_ROWS; r++) {
338 | bool full = true;
339 | for (int c = 0; full && c < FBLOCKS_COLS; c++) {
340 | if (!game->area[r][c]) {
341 | full = false;
342 | }
343 | }
344 | if (full) {
345 | return r;
346 | }
347 | }
348 | return -1;
349 | }
350 |
351 | /* Choose a random piece from the bag. */
352 | static int fblocks_random(struct fblocks_game_t *game) {
353 | if (!game->bag) {
354 | game->bag = (1 << FBLOCKS_PIECES) - 1;
355 | }
356 | int piece = rand() % FBLOCKS_PIECES;
357 | while (!(game->bag & (1 << piece))) {
358 | piece = (piece + 1) % FBLOCKS_PIECES;
359 | }
360 | game->bag &= ~(1 << piece);
361 | return piece;
362 | }
363 |
364 | static bool fblocks_animation_full_row(struct fblocks_game_t *game,
365 | gfx_pixslice *slice, int millis);
366 |
367 | static bool fblocks_animation_game_over(struct fblocks_game_t *game,
368 | gfx_pixslice *slice, int millis);
369 |
370 | /* Apply rules. */
371 | static void fblocks_rules(struct fblocks_game_t *game) {
372 | /* Restart? */
373 | if (game->over) {
374 | fblocks_init();
375 | for (int i = 0; i < FBLOCKS_PREVIEW_COUNT; i++) {
376 | game->preview[i] = &fblocks_pieces[fblocks_random(game)];
377 | }
378 | game->next_level_score = 10;
379 | game->over = false;
380 | }
381 | /* Remove full row after animation. */
382 | if (game->full_row != -1) {
383 | game->score++;
384 | if (game->score >= game->next_level_score) {
385 | game->level++;
386 | game->next_level_score += game->level * 10;
387 | game->fall_speed = game->fall_speed * 7 / 10;
388 | }
389 | fblocks_remove_row(game, game->full_row);
390 | game->full_row = -1;
391 | }
392 | /* New piece? */
393 | if (!game->piece) {
394 | /* Test for full rows. */
395 | game->full_row = fblocks_full_row(game);
396 | if (game->full_row != -1) {
397 | game->animation = fblocks_animation_full_row;
398 | game->animation_start_millis = system_millis;
399 | } else {
400 | /* New piece. */
401 | game->piece = game->preview[0];
402 | for (int i = 0; i < FBLOCKS_PREVIEW_COUNT - 1; i++) {
403 | game->preview[i] = game->preview[i + 1];
404 | }
405 | game->preview[FBLOCKS_PREVIEW_COUNT - 1] =
406 | &fblocks_pieces[fblocks_random(game)];
407 | game->shape = &game->piece->shapes[0];
408 | game->row = FBLOCKS_VISIBLE_ROWS - game->shape->rows;
409 | game->col = (FBLOCKS_COLS - game->shape->cols) / 2;
410 | game->last_fall_millis = system_millis;
411 | /* Game over? */
412 | if (fblocks_test(game, game->shape, game->row, game->col)) {
413 | game->over = true;
414 | game->animation = fblocks_animation_game_over;
415 | game->animation_start_millis = system_millis;
416 | }
417 | fblocks_blit(game);
418 | }
419 | }
420 | }
421 |
422 | /* Game & control logic. */
423 | void fblocks_animate(void) {
424 | /* Animation running? */
425 | if (game.animation) {
426 | return;
427 | }
428 | /* Apply rules. */
429 | fblocks_rules(&game);
430 | if (!game.piece) {
431 | return;
432 | }
433 | /* Key? */
434 | uint16_t gamepad = gamepad_get();
435 | uint16_t gamepad_new = gamepad & (gamepad ^ game.last_gamepad);
436 | uint16_t gamepad_old = gamepad & game.last_gamepad;
437 | bool repeat_move = (int) (system_millis - game.last_move_millis
438 | - FBLOCKS_AUTO_REPEAT_SPEED) > 0;
439 | int new_col = game.col;
440 | int rotate = 0;
441 | if ((gamepad_new & GAMEPAD_BLEFT)
442 | || ((gamepad_old & GAMEPAD_BLEFT) && repeat_move)) {
443 | new_col--;
444 | }
445 | if ((gamepad_new & GAMEPAD_BRIGHT)
446 | || ((gamepad_old & GAMEPAD_BRIGHT) && repeat_move)) {
447 | new_col++;
448 | }
449 | if (gamepad_new & GAMEPAD_BA) {
450 | rotate--;
451 | }
452 | if (gamepad_new & GAMEPAD_BB) {
453 | rotate++;
454 | }
455 | game.last_gamepad = gamepad;
456 | /* Rotate. */
457 | if (rotate) {
458 | /* Compute rotation. */
459 | const struct fblocks_shape_t *new_shape = game.shape + rotate;
460 | if (new_shape == &game.piece->shapes[-1]) {
461 | new_shape = &game.piece->shapes[game.piece->shape_count - 1];
462 | } else if (new_shape == &game.piece->shapes[game.piece->shape_count]) {
463 | new_shape = &game.piece->shapes[0];
464 | }
465 | /* Compute new position. */
466 | int new_row = game.row;
467 | new_row -= (new_shape->rows - game.shape->rows) / 2;
468 | new_row = CLAMP(0, FBLOCKS_ROWS - new_shape->rows, new_row);
469 | int new_col = game.col;
470 | new_col -= (new_shape->cols - game.shape->cols) / 2;
471 | new_col = CLAMP(0, FBLOCKS_COLS - new_shape->cols, new_col);
472 | /* Is there room to rotate. */
473 | fblocks_unblit(&game);
474 | if (!fblocks_test(&game, new_shape, new_row, new_col)) {
475 | /* OK, there is room. */
476 | game.shape = new_shape;
477 | game.row = new_row;
478 | game.col = new_col;
479 | }
480 | fblocks_blit(&game);
481 | /* Move. */
482 | } else if (new_col != game.col && new_col >= 0
483 | && new_col + game.shape->cols <= FBLOCKS_COLS) {
484 | /* Is there room to move? */
485 | fblocks_unblit(&game);
486 | if (!fblocks_test(&game, game.shape, game.row, new_col)) {
487 | /* OK, there is room. */
488 | game.col = new_col;
489 | game.last_move_millis = system_millis;
490 | }
491 | fblocks_blit(&game);
492 | }
493 | /* Faster down? */
494 | bool drop = gamepad & GAMEPAD_BDOWN;
495 | int speed = game.fall_speed;
496 | if (drop) {
497 | speed /= 20;
498 | }
499 | /* Fall? */
500 | if ((int) (system_millis - game.last_fall_millis - speed) > 0) {
501 | /* Erase previous position, test new one... */
502 | fblocks_unblit(&game);
503 | if (game.row == 0
504 | || fblocks_test(&game, game.shape, game.row - 1, game.col)) {
505 | /* Revert, there is no room! */
506 | fblocks_blit(&game);
507 | game.piece = NULL;
508 | } else {
509 | /* OK use new position. */
510 | game.row--;
511 | fblocks_blit(&game);
512 | }
513 | game.last_fall_millis = system_millis;
514 | }
515 | }
516 |
517 | /* Draw one tile from the pixmap. */
518 | static void fblocks_draw_tile(gfx_pixslice *slice, int id, size_t x, size_t y) {
519 | gfx_pixslice tile;
520 | gfx_init_pixslice(&tile, (void *) &fblocks_pixmap[id * 12][0],
521 | 0, 0, 12, 12, 12);
522 | gfx_ipoint p = { .x = x, .y = y };
523 | gfx_copy_pixslice(slice, &tile, p);
524 | }
525 |
526 | /* Default area drawing. */
527 | static bool fblocks_animation_default(struct fblocks_game_t *game,
528 | gfx_pixslice *slice, int millis) {
529 | for (int r = 0; r < FBLOCKS_VISIBLE_ROWS; r++) {
530 | int y = FBLOCKS_SCREEN_AREA_Y + (FBLOCKS_VISIBLE_ROWS - r - 1) * 12;
531 | if (y >= slice->y - 12 && y < slice->y + slice->h) {
532 | for (int c = 0; c < FBLOCKS_COLS; c++) {
533 | int x = FBLOCKS_SCREEN_AREA_X + c * 12;
534 | int s = game->area[r][c];
535 | if (s) {
536 | fblocks_draw_tile(slice, s, x, y);
537 | }
538 | }
539 | }
540 | }
541 | return false;
542 | }
543 |
544 | /* Drawing when a full row is being removed. */
545 | static bool fblocks_animation_full_row(struct fblocks_game_t *game,
546 | gfx_pixslice *slice, int millis) {
547 | int collapse = millis < 500 ? millis * 12 / 500 : 12;
548 | for (int r = 0; r < FBLOCKS_VISIBLE_ROWS; r++) {
549 | int y = FBLOCKS_SCREEN_AREA_Y + (FBLOCKS_VISIBLE_ROWS - r - 1) * 12;
550 | if (r > game->full_row)
551 | y += collapse;
552 | if (y >= slice->y - 12 && y < slice->y + slice->h) {
553 | for (int c = 0; c < FBLOCKS_COLS; c++) {
554 | int x = FBLOCKS_SCREEN_AREA_X + c * 12;
555 | int s = game->area[r][c];
556 | fblocks_draw_tile(slice, s, x, y);
557 | }
558 | }
559 | }
560 | return millis >= 800;
561 | }
562 |
563 | /* Game over drawing. */
564 | static bool fblocks_animation_game_over(struct fblocks_game_t *game,
565 | gfx_pixslice *slice, int millis) {
566 | float anim = millis / 3000.0f;
567 | if (anim < 1.0f) {
568 | float radius = (1.0f - anim);
569 | float angle = anim * 6.0f * M_PI;
570 | float ca = cos(angle);
571 | float sa = sin(angle);
572 | const int cy = FBLOCKS_SCREEN_AREA_Y + FBLOCKS_SCREEN_AREA_H / 2;
573 | const int cx = FBLOCKS_SCREEN_AREA_X + FBLOCKS_SCREEN_AREA_W / 2;
574 | for (int r = 0; r < FBLOCKS_ROWS; r++) {
575 | int y = FBLOCKS_SCREEN_AREA_Y + (FBLOCKS_VISIBLE_ROWS - r - 1) * 12;
576 | for (int c = 0; c < FBLOCKS_COLS; c++) {
577 | int s = game->area[r][c];
578 | if (s) {
579 | int x = FBLOCKS_SCREEN_AREA_X + c * 12;
580 | int dx = x + 6 - cx;
581 | int dy = y + 6 - cy;
582 | int rx = cx + radius * (dx * ca - dy * sa) - 6;
583 | int ry = cy + radius * (dx * sa + dy * ca) - 6;
584 | fblocks_draw_tile(slice, s, rx, ry);
585 | }
586 | }
587 | }
588 | } else {
589 | text_draw_str16(slice, "Game Over",
590 | (FBLOCKS_SCREEN_AREA_X + FBLOCKS_SCREEN_AREA_W / 2) / 8 - 5,
591 | (FBLOCKS_SCREEN_AREA_Y + FBLOCKS_SCREEN_AREA_H / 2) / 16, 0x0000);
592 | }
593 | return anim > 2.0f;
594 | }
595 |
596 | static bool fblocks_render_slice(gfx_pixslice *slice) {
597 | /* Background. */
598 | for (size_t y = slice->y / 12; y <= (slice->y + slice->h) / 12; y++) {
599 | for (size_t x = 0; x <= slice->w / 12 + 1; x++) {
600 | fblocks_draw_tile(slice, fblocks_screen[y][x], x * 12, y * 12);
601 | }
602 | }
603 | /* Preview. */
604 | if (slice->y < FBLOCKS_SCREEN_PREVIEW_Y + FBLOCKS_SCREEN_PREVIEW_H && game.preview[0]) {
605 | const struct fblocks_shape_t *shape = &game.preview[0]->shapes[0];
606 | int sx = FBLOCKS_SCREEN_PREVIEW_X + FBLOCKS_SCREEN_PREVIEW_W / 2
607 | - shape->cols * 12 / 2;
608 | int sy = FBLOCKS_SCREEN_PREVIEW_Y + FBLOCKS_SCREEN_PREVIEW_H / 2
609 | - shape->rows * 12 / 2;
610 | for (int r = 0; r < shape->rows; r++) {
611 | int dy = (shape->rows - r - 1) * 12;
612 | for (int c = 0; c < shape->cols; c++) {
613 | int s = shape->grid[r][c];
614 | if (s) {
615 | fblocks_draw_tile(slice, s, sx + c * 12, sy + dy);
616 | }
617 | }
618 | }
619 | }
620 | /* Score. */
621 | if (slice->y < FBLOCKS_SCREEN_SCORE_Y + FBLOCKS_SCREEN_SCORE_H) {
622 | char score[11];
623 | sprintf(score, "%d", game.score);
624 | int score_len = strlen(score);
625 | text_draw_str16(slice, score,
626 | (FBLOCKS_SCREEN_SCORE_X + FBLOCKS_SCREEN_SCORE_W) / 8 - score_len - 1,
627 | (FBLOCKS_SCREEN_SCORE_Y + FBLOCKS_SCREEN_SCORE_H / 2) / 16, 0x0000);
628 | }
629 | /* Area. */
630 | fblocks_animation_t animation = game.animation ? game.animation
631 | : fblocks_animation_default;
632 | return animation(&game, slice,
633 | system_millis - game.animation_start_millis);
634 | }
635 |
636 | void fblocks_render(void) {
637 | size_t h;
638 | bool animation_stop = false;
639 | for (size_t y = 0; y < LCD_HEIGHT; y += h) {
640 | h = MIN(LCD_MAX_SLICE_ROWS, LCD_HEIGHT - y);
641 | gfx_pixslice *slice = lcd_alloc_pixslice(0, y, LCD_WIDTH, h);
642 | animation_stop = fblocks_render_slice(slice);
643 | lcd_send_pixslice(slice);
644 | }
645 | if (animation_stop) {
646 | game.animation = NULL;
647 | }
648 | }
649 |
--------------------------------------------------------------------------------
/firmware/src/fblocks_app.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the 1Bitsy 1UP retro inspired game console project.
3 | *
4 | * Copyright (C) 2017 Nicolas Schodet
5 | *
6 | * This program is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This program is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | */
19 |
20 | #ifndef FBLOCKS_APP_H
21 | #define FBLOCKS_APP_H
22 |
23 | void fblocks_init(void);
24 | void fblocks_animate(void);
25 | void fblocks_render(void);
26 |
27 | #endif /* FBLOCKS_APP_H */
28 |
--------------------------------------------------------------------------------
/firmware/src/gamepad.c:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the 1Bitsy 1UP retro inspired game console project.
3 | *
4 | * Copyright (C) 2017 Piotr Esden-Tempski
5 | *
6 | * This program is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This program is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | */
19 |
20 | #include
21 |
22 | #include "gamepad.h"
23 |
24 | void gamepad_init(void)
25 | {
26 | /* LATCH */
27 | gpio_mode_setup(GPIOC, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO4);
28 | gpio_clear(GPIOC, GPIO4);
29 | /* CLOCK */
30 | gpio_mode_setup(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO7);
31 | gpio_clear(GPIOA, GPIO4);
32 | /* DATA */
33 | gpio_mode_setup(GPIOA, GPIO_MODE_INPUT, GPIO_PUPD_PULLDOWN, GPIO6);
34 | }
35 |
36 | bool gamepad_present(void)
37 | {
38 | return (gamepad_get() != 0xFFFFF );
39 | }
40 |
41 | uint16_t gamepad_get(void)
42 | {
43 | uint16_t ret = 0;
44 |
45 | /* assert latch */
46 | gpio_clear(GPIOC, GPIO4);
47 | for (int i = 0; i < 30; i++) asm("nop");
48 | gpio_set(GPIOC, GPIO4);
49 | for (int i = 0; i < 30; i++) asm("nop");
50 |
51 | /* read bit 1 */
52 | if (gpio_get(GPIOA, GPIO6) != 0) {
53 | ret <<= 1;
54 | ret |= 1;
55 | } else {
56 | ret <<= 1;
57 | }
58 |
59 | /* Read another 16 bit */
60 | for (int i = 0; i < 15; i++) {
61 | gpio_set(GPIOA, GPIO7);
62 | for (int d = 0; d < 30; d++) asm("nop");
63 | gpio_clear(GPIOA, GPIO7);
64 | for (int d = 0; d < 30; d++) asm("nop");
65 | if (gpio_get(GPIOA, GPIO6) != 0) {
66 | ret <<= 1;
67 | ret |= 1;
68 | } else {
69 | ret <<= 1;
70 | }
71 | }
72 |
73 | return (ret ^ 0xFFFFF);
74 | }
--------------------------------------------------------------------------------
/firmware/src/gamepad.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the 1Bitsy 1UP retro inspired game console project.
3 | *
4 | * Copyright (C) 2017 Piotr Esden-Tempski
5 | *
6 | * This program is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This program is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | */
19 |
20 | #ifndef GAMEPAD_H
21 | #define GAMEPAD_H
22 |
23 | #include
24 | #include
25 |
26 | /* SNES Controller buttons */
27 | #define GAMEPAD_BB_BIT 15
28 | #define GAMEPAD_BY_BIT 14
29 | #define GAMEPAD_BSELECT_BIT 13
30 | #define GAMEPAD_BSTART_BIT 12
31 | #define GAMEPAD_BUP_BIT 11
32 | #define GAMEPAD_BDOWN_BIT 10
33 | #define GAMEPAD_BLEFT_BIT 9
34 | #define GAMEPAD_BRIGHT_BIT 8
35 | #define GAMEPAD_BA_BIT 7
36 | #define GAMEPAD_BX_BIT 6
37 | #define GAMEPAD_BL_BIT 5
38 | #define GAMEPAD_BR_BIT 4
39 | #define GAMEPAD_BRES1_BIT 3
40 | #define GAMEPAD_BRES2_BIT 2
41 | #define GAMEPAD_BVOLM_BIT 1
42 | #define GAMEPAD_BVOLP_BIT 0
43 |
44 | #define GAMEPAD_BB (1 << GAMEPAD_BB_BIT)
45 | #define GAMEPAD_BY (1 << GAMEPAD_BY_BIT)
46 | #define GAMEPAD_BSELECT (1 << GAMEPAD_BSELECT_BIT)
47 | #define GAMEPAD_BSTART (1 << GAMEPAD_BSTART_BIT)
48 | #define GAMEPAD_BUP (1 << GAMEPAD_BUP_BIT)
49 | #define GAMEPAD_BDOWN (1 << GAMEPAD_BDOWN_BIT)
50 | #define GAMEPAD_BLEFT (1 << GAMEPAD_BLEFT_BIT)
51 | #define GAMEPAD_BRIGHT (1 << GAMEPAD_BRIGHT_BIT)
52 | #define GAMEPAD_BA (1 << GAMEPAD_BA_BIT)
53 | #define GAMEPAD_BX (1 << GAMEPAD_BX_BIT)
54 | #define GAMEPAD_BL (1 << GAMEPAD_BL_BIT)
55 | #define GAMEPAD_BR (1 << GAMEPAD_BR_BIT)
56 | #define GAMEPAD_BRES1 (1 << GAMEPAD_BRES1_BIT)
57 | #define GAMEPAD_BRES2 (1 << GAMEPAD_BRES2_BIT)
58 | #define GAMEPAD_BVOLM (1 << GAMEPAD_BVOLM_BIT)
59 | #define GAMEPAD_BVOLP (1 << GAMEPAD_BVOLP_BIT)
60 |
61 | void gamepad_init(void);
62 | bool gamepad_present(void);
63 | uint16_t gamepad_get(void);
64 |
65 | #endif /* GAMEPAD_H */
66 |
--------------------------------------------------------------------------------
/firmware/src/gfx-pixslice.c:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the 1Bitsy lcd graphics library.
3 | *
4 | * Copyright (C) 2017 Bob Miller
5 | *
6 | * This library is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU Lesser General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This library is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU Lesser General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU Lesser General Public License
17 | * along with this library. If not, see .
18 | */
19 |
20 | #include "gfx-pixslice.h"
21 |
22 | #include
23 |
24 | #include "math-util.h"
25 |
26 | extern void gfx_init_pixslice(gfx_pixslice *slice,
27 | void *buffer,
28 | int x, int y,
29 | size_t w, size_t h,
30 | size_t stride)
31 | {
32 | slice->pixels = (gfx_rgb565 *)buffer - y * stride - x;
33 | slice->x = x;
34 | slice->y = y;
35 | slice->w = w;
36 | slice->h = h;
37 | slice->stride = stride;
38 | }
39 |
40 | extern gfx_rgb565 *gfx_pixel_address(gfx_pixslice *slice, int x, int y)
41 | {
42 | if (x < slice->x || x >= (ssize_t)(slice->x + slice->w))
43 | return NULL;
44 | if (y < slice->y || y >= (ssize_t)(slice->y + slice->h))
45 | return NULL;
46 | return gfx_pixel_address_unchecked(slice, x, y);
47 | }
48 |
49 | void gfx_copy_pixslice(gfx_pixslice *dest,
50 | gfx_pixslice const *src,
51 | gfx_ipoint offset)
52 | {
53 | int x0s = MAX(src->x, dest->x - offset.x);
54 | int x1s = MIN(src->x + (int)src->w, dest->x + (int)dest->w - offset.x);
55 | if (x0s >= x1s)
56 | return;
57 | int x0d = x0s + offset.x;
58 | int nx = x1s - x0s;
59 | int y0s = MAX(src->y, dest->y - offset.y);
60 | int y1s = MIN(src->y + (int)src->h, dest->y + (int)dest->h - offset.y);
61 | if (y0s >= y1s)
62 | return;
63 | int y0d = y0s + offset.y;
64 | for (int ys = y0s, yd = y0d; ys < y1s; ys++, yd++) {
65 | const gfx_rgb565 *ps =
66 | gfx_pixel_address_unchecked((gfx_pixslice *)src, x0s, ys);
67 | gfx_rgb565 *pd = gfx_pixel_address_unchecked(dest, x0d, yd);
68 | memcpy(pd, ps, nx * sizeof *pd);
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/firmware/src/gfx-pixslice.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the 1Bitsy lcd graphics library.
3 | *
4 | * Copyright (C) 2017 Bob Miller
5 | *
6 | * This library is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU Lesser General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This library is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU Lesser General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU Lesser General Public License
17 | * along with this library. If not, see .
18 | */
19 |
20 | #ifndef GFX_PIXSLICE_H
21 | #define GFX_PIXSLICE_H
22 |
23 | #include
24 |
25 | #include "gfx-types.h"
26 |
27 | struct gfx_pixslice {
28 | gfx_rgb565 *pixels; // N.B., points to (0, 0) which may not exist.
29 | int x, y; // origin
30 | size_t w, h; // size
31 | ssize_t stride; // row stride in pixels
32 | };
33 |
34 | void gfx_init_pixslice(gfx_pixslice *slice,
35 | void *buffer,
36 | int x, int y,
37 | size_t w, size_t h,
38 | size_t stride);
39 |
40 | static inline gfx_rgb565 *gfx_pixel_address_unchecked(gfx_pixslice *slice,
41 | int x, int y)
42 | {
43 | return slice->pixels + y * slice->stride + x;
44 | }
45 |
46 | gfx_rgb565 *gfx_pixel_address(gfx_pixslice *slice, int x, int y);
47 |
48 | // Copy source pixmap into destination.
49 | // offset translates src coordinates to dest.
50 | // dest coord = src coord + offset.
51 | void gfx_copy_pixslice(gfx_pixslice *dest,
52 | gfx_pixslice const *src,
53 | gfx_ipoint offset);
54 |
55 | #endif /* GFX_PIXSLICE_H */
56 |
--------------------------------------------------------------------------------
/firmware/src/gfx-types.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the 1Bitsy lcd graphics library.
3 | *
4 | * Copyright (C) 2017 Bob Miller
5 | *
6 | * This library is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU Lesser General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This library is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU Lesser General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU Lesser General Public License
17 | * along with this library. If not, see .
18 | */
19 |
20 | #ifndef GFX_TYPES_H
21 | #define GFX_TYPES_H
22 |
23 | #include
24 | #include
25 |
26 | typedef uint16_t gfx_rgb565;
27 | typedef uint32_t gfx_rgb888;
28 | typedef uint8_t gfx_alpha8;
29 |
30 | typedef struct gfx_pixslice gfx_pixslice;
31 |
32 | typedef union gfx_point {
33 | struct {
34 | float x, y; // use p.x, p.y
35 | };
36 | float c[2]; // use p.c[i]
37 | } gfx_point;
38 |
39 | typedef union gfx_ipoint {
40 | struct {
41 | int x, y; // use p.x, p.y
42 | };
43 | int c[2]; // use p.c[i]
44 | } gfx_ipoint;
45 |
46 | typedef struct gfx_trapezoid {
47 | float xl0, xr0, y0;
48 | float xl1, xr1, y1;
49 | } gfx_trapezoid;
50 |
51 | typedef struct gfx_triangle {
52 | gfx_point v[3];
53 | } gfx_triangle;
54 |
55 | #endif /* GFX_TYPES_H */
56 |
--------------------------------------------------------------------------------
/firmware/src/gpio.c:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the 1Bitsy lcd graphics library.
3 | *
4 | * Copyright (C) 2017 Bob Miller
5 | *
6 | * This library is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU Lesser General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This library is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU Lesser General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU Lesser General Public License
17 | * along with this library. If not, see .
18 | */
19 |
20 | #include "gpio.h"
21 |
22 | #include
23 | #include
24 |
25 | #include
26 |
27 | #define GPIO_PORT_COUNT 11
28 |
29 | static uint16_t gpio_pins_used[GPIO_PORT_COUNT];
30 |
31 | void gpio_init_pin(const gpio_pin *pin)
32 | {
33 | uint32_t port = pin->gp_port;
34 | uint16_t pinmask = pin->gp_pin;
35 | uint32_t index = ((uint32_t)port - (uint32_t)PERIPH_BASE_AHB1) >> 10;
36 | assert(index < GPIO_PORT_COUNT);
37 |
38 | if (!gpio_pins_used[index])
39 | rcc_periph_clock_enable((0x30 << 5) | index);
40 |
41 | assert(!(gpio_pins_used[index] & pinmask));
42 | gpio_pins_used[index] |= pinmask;
43 |
44 | gpio_config_pin(pin);
45 | }
46 |
47 | void gpio_config_pin(const gpio_pin *pin)
48 | {
49 | uint32_t port = pin->gp_port;
50 | uint16_t pinmask = pin->gp_pin;
51 |
52 | gpio_mode_setup(port,
53 | pin->gp_mode,
54 | pin->gp_pupd,
55 | pinmask);
56 |
57 | if (pin->gp_mode == GPIO_MODE_OUTPUT) {
58 | if (pin->gp_level)
59 | gpio_set(port, pinmask);
60 | else
61 | gpio_clear(port, pinmask);
62 | }
63 |
64 | if (pin->gp_mode == GPIO_MODE_OUTPUT || pin->gp_mode == GPIO_MODE_AF)
65 | gpio_set_output_options(port,
66 | pin->gp_otype,
67 | pin->gp_ospeed,
68 | pinmask);
69 |
70 | if (pin->gp_mode == GPIO_MODE_AF)
71 | gpio_set_af(port,
72 | pin->gp_af,
73 | pinmask);
74 | }
75 |
76 | void gpio_init_pins(const gpio_pin *pins, size_t count)
77 | {
78 | for (size_t i = 0; i < count; i++)
79 | gpio_init_pin(&pins[i]);
80 | }
81 |
82 | void gpio_config_pins(const gpio_pin *pins, size_t count)
83 | {
84 | for (size_t i = 0; i < count; i++)
85 | gpio_config_pin(&pins[i]);
86 | }
87 |
--------------------------------------------------------------------------------
/firmware/src/gpio.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the 1Bitsy lcd graphics library.
3 | *
4 | * Copyright (C) 2017 Bob Miller
5 | *
6 | * This library is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU Lesser General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This library is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU Lesser General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU Lesser General Public License
17 | * along with this library. If not, see .
18 | */
19 |
20 | #ifndef GPIO_H
21 | #define GPIO_H
22 |
23 | #include
24 |
25 | #include
26 |
27 | typedef struct gpio_pin {
28 | uint32_t gp_port; // GPIOA .. GPIOF
29 | uint16_t gp_pin; // GPIO0 .. GPIO15 (may OR pins)
30 | uint8_t gp_mode : 2; // GPIO_MODE_INPUT/OUTPUT/AF/ANALOG
31 | uint8_t gp_pupd : 2; // GPIO_PUPD_NONE/PULLUP/PULLDOWN
32 | uint8_t gp_af : 4; // GPIO_AF0 .. GPIO_AF15
33 | uint8_t gp_ospeed : 2; // GPIO_OSPEED_2/25/60/100MHZ
34 | uint8_t gp_otype : 1; // GPIO_OTYPE_PP/OD (push-pull, open drain)
35 | uint8_t gp_level : 1; // 0 or 1
36 | } gpio_pin;
37 |
38 | // Initialization asserts that each pin is not yet used and
39 | // enables RCC peripheral clocks as needed before configuring
40 | // the pin(s).
41 | //
42 | // Configuration just sets the mode and other attributes.
43 | // Does not init the clock or check for uniqueness.
44 |
45 | void gpio_init_pin(const gpio_pin *);
46 | void gpio_config_pin(const gpio_pin *);
47 |
48 |
49 | // Convenience functions to init/config several pins at once.
50 | void gpio_init_pins(const gpio_pin *, size_t count);
51 | void gpio_config_pins(const gpio_pin *, size_t count);
52 |
53 | #endif /* GPIO_H */
54 |
--------------------------------------------------------------------------------
/firmware/src/i2c.c:
--------------------------------------------------------------------------------
1 | #include "i2c.h"
2 |
3 | #include
4 | #include
5 |
6 | #include
7 | #include
8 | #include
9 |
10 | #include "systick.h"
11 |
12 | #define I2C_BAUD 100000
13 | #define TIMEOUT_MSEC 25
14 |
15 | void i2c_init(i2c_config const *ip)
16 | {
17 | // Enable periph clock.
18 | // Configure GPIO.
19 | // Reset I²C.
20 |
21 | uint32_t base = ip->i_base_address;
22 |
23 | enum rcc_periph_clken clken;
24 | switch (base) {
25 | case I2C1:
26 | clken = RCC_I2C1;
27 | break;
28 | case I2C2:
29 | clken = RCC_I2C2;
30 | break;
31 | default:
32 | assert(false && "unknown I2C base address");
33 | }
34 | rcc_periph_clock_enable(clken);
35 |
36 | gpio_init_pins(ip->i_pins, (&ip->i_pins)[1] - ip->i_pins);
37 |
38 | uint32_t i2c_freq_mhz = rcc_apb1_frequency / 1000000;
39 | uint32_t ccr = rcc_apb1_frequency / I2C_BAUD / 2 + 1;
40 | if (ccr < 4)
41 | ccr = 4;
42 |
43 | i2c_peripheral_disable(base);
44 | i2c_set_clock_frequency(base, i2c_freq_mhz);
45 | i2c_set_trise(base, i2c_freq_mhz + 1);
46 | i2c_set_ccr(base, ccr);
47 | I2C_CR1(base) = 0;
48 | I2C_OAR1(base) = ip->i_own_address;
49 | i2c_peripheral_enable(base);
50 | }
51 |
52 | void i2c_transmit(const i2c_channel *cp, const uint8_t *data, size_t count)
53 | {
54 | uint32_t base = cp->i_base_address;
55 |
56 | if (cp->i_is_master) {
57 |
58 | // Send start condition.
59 | I2C_CR1(base) |= I2C_CR1_START;
60 | uint32_t t0 = system_millis;
61 | while (!(I2C_SR1(base) & I2C_SR1_SB)) {
62 | if (system_millis >= t0 + TIMEOUT_MSEC) {
63 | fprintf(stderr, "i2c: timeout on SB\n");
64 | return;
65 | }
66 | }
67 |
68 | // Send slave address.
69 | I2C_DR(base) = cp->i_address & ~0x01;
70 | t0 = system_millis;
71 | while (!(I2C_SR1(base) & I2C_SR1_ADDR)) {
72 | if (I2C_SR1(base) & I2C_SR1_AF) {
73 | I2C_CR1(base) |= I2C_CR1_STOP;
74 | I2C_SR1(base) = ~I2C_SR1_AF;
75 | fprintf(stderr,
76 | "i2c @ %ld: ack failure on addr\n",
77 | system_millis / 1000);
78 | return;
79 | }
80 | if (system_millis >= t0 + TIMEOUT_MSEC) {
81 | fprintf(stderr, "i2c: timeout on ADDR\n");
82 | return;
83 | }
84 | }
85 |
86 | // Clear ADDR flag by reading SR1 and SR2 registers.
87 | uint16_t unused;
88 | unused = I2C_SR1(base);
89 | unused = I2C_SR2(base);
90 | unused = unused;
91 |
92 | // Write each data byte; wait for BTF.
93 | for (size_t i = 0; i < count; i++) {
94 | I2C_DR(base) = data[i];
95 | t0 = system_millis;
96 | while (!(I2C_SR1(base) & I2C_SR1_BTF)) {
97 | if (system_millis >= t0 + TIMEOUT_MSEC) {
98 | fprintf(stderr, "i2c: timeout on BTF\n");
99 | return;
100 | }
101 | }
102 | }
103 | I2C_CR1(base) |= I2C_CR1_STOP;
104 | fprintf(stderr, "i2c @ %lu: transmit complete\n", system_millis / 1000);
105 | } else {
106 | assert(false && "slave transmission not implemented");
107 | }
108 | }
109 |
110 | void i2c_receive(const i2c_channel *cp, uint8_t *data, size_t count)
111 | {
112 | uint32_t base = cp->i_base_address;
113 |
114 | if (cp->i_is_master) {
115 |
116 | I2C_CR1(base) |= I2C_CR1_ACK;
117 |
118 | // Send start condition.
119 | I2C_CR1(base) |= I2C_CR1_START;
120 | uint32_t t0 = system_millis;
121 | while (!(I2C_SR1(base) & I2C_SR1_SB)) {
122 | if (system_millis >= t0 + TIMEOUT_MSEC) {
123 | fprintf(stderr, "i2c: timeout on SB\n");
124 | printf("SR1 = %#lx\n", I2C_SR1(base));
125 | return;
126 | }
127 | }
128 |
129 | // Send slave address.
130 | I2C_DR(base) = cp->i_address | 0x01;
131 | t0 = system_millis;
132 | while (!(I2C_SR1(base) & I2C_SR1_ADDR)) {
133 | if (I2C_SR1(base) & I2C_SR1_AF) {
134 | I2C_CR1(base) |= I2C_CR1_STOP;
135 | I2C_SR1(base) = ~I2C_SR1_AF;
136 | fprintf(stderr,
137 | "i2c @ %ld: ack failure on addr\n",
138 | system_millis / 1000);
139 | return;
140 | }
141 | if (system_millis >= t0 + TIMEOUT_MSEC) {
142 | fprintf(stderr, "i2c: timeout on ADDR\n");
143 | return;
144 | }
145 | }
146 |
147 | // Clear ADDR flag by reading SR1 and SR2 registers.
148 | uint16_t unused;
149 | unused = I2C_SR1(base);
150 | unused = I2C_SR2(base);
151 | unused = unused;
152 |
153 | // Read each data byte; wait for BTF.
154 | for (size_t i = 0; i < count; i++) {
155 | if (i + 1 == count)
156 | I2C_CR1(base) &= ~I2C_CR1_ACK;
157 | t0 = system_millis;
158 | while (true) {
159 | uint32_t sr1 = I2C_SR1(base);
160 | if (sr1 & (I2C_SR1_OVR | I2C_SR1_BERR)) {
161 | fprintf(stderr, "i2c: receive error\n");
162 | break;
163 | }
164 | if (sr1 & I2C_SR1_RxNE)
165 | break;
166 | if (system_millis >= t0 + TIMEOUT_MSEC) {
167 | fprintf(stderr, "i2c: timeout on receive\n");
168 | }
169 | }
170 | data[i] = I2C_DR(base);
171 | I2C_DR(base) = data[i];
172 | }
173 | printf("%lu: I2C receive complete\n", system_millis / 1000);
174 | } else {
175 | assert(false && "slave reception not implemented");
176 | }
177 | }
178 |
--------------------------------------------------------------------------------
/firmware/src/i2c.h:
--------------------------------------------------------------------------------
1 | #ifndef I2C_included
2 | #define I2C_included
3 |
4 | #include
5 | #include
6 |
7 | #include "gpio.h"
8 |
9 | typedef struct i2c_config {
10 | uint32_t i_base_address;
11 | uint16_t i_own_address;
12 | gpio_pin i_pins[2];
13 | } i2c_config;
14 |
15 | typedef struct i2c_channel {
16 | uint32_t i_base_address;
17 | bool i_is_master;
18 | bool i_stop;
19 | uint16_t i_address;
20 | } i2c_channel;
21 |
22 | extern void i2c_init (i2c_config const *ip);
23 |
24 | extern void i2c_transmit (i2c_channel const *ip,
25 | uint8_t const *data,
26 | size_t count);
27 | extern void i2c_receive (i2c_channel const *ip,
28 | uint8_t *data,
29 | size_t count);
30 |
31 | #endif /* !I2C_included */
32 |
--------------------------------------------------------------------------------
/firmware/src/intr.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the 1Bitsy lcd graphics library.
3 | *
4 | * Copyright (C) 2017 Bob Miller
5 | *
6 | * This library is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU Lesser General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This library is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU Lesser General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU Lesser General Public License
17 | * along with this library. If not, see .
18 | */
19 |
20 | #ifndef INTR_H
21 | #define INTR_H
22 |
23 | #include
24 |
25 | #define WITH_INTERRUPTS_MASKED \
26 | for (bool wim_interrupts_are_masked = cm_is_masked_interrupts(), \
27 | wim_first_time = (cm_disable_interrupts(), true); \
28 | wim_first_time; \
29 | wim_interrupts_are_masked ? (void)0 : cm_enable_interrupts(), \
30 | wim_first_time = false)
31 |
32 | #endif /* INTR_H */
33 |
--------------------------------------------------------------------------------
/firmware/src/lcd.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the 1Bitsy lcd graphics library.
3 | *
4 | * Copyright (C) 2017 Bob Miller
5 | *
6 | * This library is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU Lesser General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This library is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU Lesser General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU Lesser General Public License
17 | * along with this library. If not, see .
18 | */
19 |
20 | #ifndef LCD_H
21 | #define LCD_H
22 |
23 | #include
24 |
25 | #include "gfx-pixslice.h"
26 |
27 | #define LCD_WIDTH 320
28 | #define LCD_HEIGHT 240
29 | #define LCD_MAX_SLICE_ROWS (LCD_HEIGHT / 5)
30 | #define LCD_MAX_SLICE_PIXELS (LCD_MAX_SLICE_ROWS * LCD_WIDTH)
31 | #define LCD_MAX_SLICE_BYTES (LCD_MAX_SLICE_PIXELS * sizeof (gfx_rgb565))
32 |
33 | // Init the clocks, GPIO pins, timer, DMA controller, ILI9341 chip,
34 | // and pixslice DMA buffers.
35 | void lcd_init(void);
36 |
37 | // Use alloc_pixslice to get DMA-capable slices.
38 | // Maximum size is 64 KB (32 Kpixels).
39 | // Slices are pre-cleared to the background color.
40 | gfx_pixslice *lcd_alloc_pixslice(int x, int y, size_t w, size_t h);
41 |
42 | // Send pixels to screen and deallocate slice.
43 | void lcd_send_pixslice(gfx_pixslice *);
44 |
45 | // Set the background pixel color.
46 | //
47 | // If immediate, the next slice allocated will have the new color.
48 | // Otherwise, color change will take effect after 0-2 allocations.
49 | void lcd_set_bg_color(gfx_rgb565 color, bool immediate);
50 |
51 | // Get the background pixel color.
52 | gfx_rgb565 lcd_bg_color(void);
53 |
54 | // Backlight control
55 | void lcd_bl_on(void);
56 | void lcd_bl_off(void);
57 | void lcd_bl_toggle(void);
58 |
59 | #endif /* !LCD_H */
60 |
--------------------------------------------------------------------------------
/firmware/src/led.c:
--------------------------------------------------------------------------------
1 | #include "led.h"
2 |
3 | #include "gpio.h"
4 |
5 | static const gpio_pin led_pin = {
6 | .gp_port = GPIOA,
7 | .gp_pin = GPIO8,
8 | .gp_mode = GPIO_MODE_OUTPUT,
9 | .gp_level = 1,
10 | };
11 |
12 | void led_init(void)
13 | {
14 | gpio_init_pin(&led_pin);
15 | }
16 |
17 | bool led_get(void)
18 | {
19 | return !gpio_get(led_pin.gp_port, led_pin.gp_pin);
20 | }
21 |
22 | void led_set(bool on_off)
23 | {
24 | if (on_off) {
25 | led_on();
26 | } else {
27 | led_off();
28 | }
29 | }
30 |
31 | void led_on(void)
32 | {
33 | gpio_clear(led_pin.gp_port, led_pin.gp_pin);
34 | }
35 |
36 | void led_off(void)
37 | {
38 | gpio_set(led_pin.gp_port, led_pin.gp_pin);
39 | }
40 |
41 | void led_toggle(void)
42 | {
43 | gpio_toggle(led_pin.gp_port, led_pin.gp_pin);
44 | }
45 |
--------------------------------------------------------------------------------
/firmware/src/led.h:
--------------------------------------------------------------------------------
1 | #ifndef LED_included
2 | #define LED_included
3 |
4 | // Control the LED on the 1Bitsy board.
5 |
6 | #include
7 |
8 | extern void led_init(void);
9 |
10 | extern bool led_get(void);
11 |
12 | extern void led_set(bool);
13 | extern void led_on(void);
14 | extern void led_off(void);
15 | extern void led_toggle(void);
16 |
17 | #endif /* ! LED_included */
18 |
--------------------------------------------------------------------------------
/firmware/src/main.c:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the 1Bitsy 1UP retro inspired game console project.
3 | *
4 | * Copyright (C) 2017 Bob Miller
5 | * Copyright (C) 2017 Piotr Esden-Tempski
6 | *
7 | * This program is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | #include
22 |
23 | #include
24 | #include
25 | #include
26 | #include
27 |
28 | #include "button_boot.h"
29 | #include "gamepad.h"
30 | #include "touch.h"
31 | #include "i2c.h"
32 | #include "lcd.h"
33 | #include "led.h"
34 | #include "math-util.h"
35 | #include "pam8019.h"
36 | #include "volume.h"
37 | #include "systick.h"
38 | #include "text.h"
39 |
40 | /* "Apps" */
41 | #include "munch_app.h"
42 | #include "tile_app.h"
43 | #include "audio_app.h"
44 | #include "fblocks_app.h"
45 |
46 | #define MY_CLOCK (rcc_hse_25mhz_3v3[RCC_CLOCK_3V3_168MHZ])
47 | #define BG_COLOR 0x0000 // black
48 |
49 | uint32_t fps;
50 |
51 | enum app_ids {
52 | munch_app,
53 | tile_app,
54 | audio_app,
55 | fblocks_app,
56 | end_app
57 | } active_app = munch_app;
58 |
59 | /* Function pointers to available apps. The first one executes by default.
60 | * Do not forget to adjust the enum if you are messing around with this list.
61 | */
62 | struct app {
63 | void (*init)(void);
64 | void (*animate)(void);
65 | void (*render)(void);
66 | void (*end)(void);
67 | } apps[] = {
68 | [munch_app] = {
69 | .init = munch_init,
70 | .animate = munch_animate,
71 | .render = munch_render,
72 | .end = NULL,
73 | },
74 | [tile_app] = {
75 | .init = tile_init,
76 | .animate = tile_animate,
77 | .render = tile_render,
78 | .end = NULL,
79 | },
80 | [audio_app] = {
81 | .init = audio_app_init,
82 | .animate = audio_animate,
83 | .render = audio_render,
84 | .end = audio_app_end,
85 | },
86 | [fblocks_app] = {
87 | .init = fblocks_init,
88 | .animate = fblocks_animate,
89 | .render = fblocks_render,
90 | .end = NULL,
91 | },
92 | };
93 |
94 | static void handle_systick(uint32_t millis)
95 | {
96 | button_pressed_debounce();
97 | }
98 |
99 | static void setup(void)
100 | {
101 | rcc_clock_setup_hse_3v3(&MY_CLOCK);
102 | flash_prefetch_enable();
103 | flash_icache_enable();
104 | flash_dcache_enable();
105 |
106 | setup_systick(MY_CLOCK.ahb_frequency);
107 | register_systick_handler(handle_systick);
108 |
109 | led_init();
110 |
111 | lcd_set_bg_color(BG_COLOR, false);
112 | lcd_init();
113 |
114 | pam8019_init();
115 |
116 | text_init();
117 |
118 | gamepad_init();
119 | touch_init();
120 |
121 | /* Disabling debug outputs, as the audio repair board uses these pins.
122 | * At present (11/2017), the pins PC5 and PC13 are available for debug.
123 | */
124 |
125 | /* Raise ~SHUTDOWN to enable audio output. */
126 | pam8019_set_mode(PM_SHUTDOWN);
127 | // gpio_mode_setup(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO3);
128 | // gpio_set(GPIOA, GPIO3);
129 | // gpio_mode_setup(GPIOA, GPIO_MODE_INPUT, GPIO_PUPD_NONE, GPIO0);
130 | }
131 |
132 | static void calc_fps(void)
133 | {
134 | static uint32_t next_time;
135 | static uint32_t frame_count;
136 | frame_count++;
137 | /* gpio_toggle(GPIOA, GPIO1); */
138 | if (system_millis >= next_time) {
139 | fps = frame_count;
140 | frame_count = 0;
141 | next_time += 1000;
142 | }
143 | }
144 |
145 | static void check_app_switch(void)
146 | {
147 | static bool state = false;
148 |
149 | if (!state) {
150 | if (button_pressed_debounce()) {
151 | if (apps[active_app].end) {
152 | apps[active_app].end();
153 | }
154 | active_app++;
155 | if (active_app == end_app) {
156 | active_app = 0;
157 | }
158 | if (apps[active_app].init) {
159 | apps[active_app].init();
160 | }
161 | state = true;
162 | gpio_clear(GPIOA, GPIO8);
163 | }
164 | } else {
165 | if (button_released_debounce()) {
166 | state = false;
167 | gpio_set(GPIOA, GPIO8);
168 | }
169 | }
170 | }
171 |
172 | static void run(void)
173 | {
174 | if (apps[active_app].init) {
175 | apps[active_app].init();
176 | }
177 | while (true) {
178 | apps[active_app].animate();
179 | apps[active_app].render();
180 | check_app_switch();
181 | calc_fps();
182 | }
183 | }
184 |
185 | int main(void)
186 | {
187 | /* Launch the ROM DFU bootloader if the user button is pressed just after
188 | * reset.
189 | */
190 | button_boot();
191 |
192 | setup();
193 | run();
194 | }
195 |
196 |
--------------------------------------------------------------------------------
/firmware/src/math-util.h:
--------------------------------------------------------------------------------
1 | #ifndef UTIL_H
2 | #define UTIL_H
3 |
4 | #define CAT2_H(a, b) a##b
5 | #define CAT_H(a, b) CAT2_H(a, b)
6 | #define TMPVAR_H() CAT_H(tmp__, __COUNTER__)
7 |
8 |
9 | #define MIN(a, b) MIN_H(a, b, TMPVAR_H(), TMPVAR_H())
10 | #define MIN_H(a, b, t1, t2) ({ \
11 | __typeof__ (a) t1 = (a); \
12 | __typeof__ (b) t2 = (b); \
13 | t1 < t2 ? t1 : t2; \
14 | })
15 |
16 | #define MAX(a, b) MAX_H(a, b, TMPVAR_H(), TMPVAR_H())
17 | #define MAX_H(a, b, t1, t2) ({ \
18 | __typeof__ (a) t1 = (a); \
19 | __typeof__ (b) t2 = (b); \
20 | t1 > t2 ? t1 : t2; \
21 | })
22 |
23 | #define CLAMP(min, max, x) MAX(min, MIN(max, x))
24 |
25 | // SIGN(x) * ABS(x) == x
26 |
27 | #define ABS(a) ABS_H(a, TMPVAR_H())
28 | #define ABS_H(a, t) ({ \
29 | __typeof__ (a) t = (a); \
30 | t >= 0 ? t: -t; \
31 | })
32 |
33 | #define SIGN(x) SIGN_H(x, TMPVAR_H())
34 | #define SIGN_H(x, t) ({ \
35 | __typeof__ (x) t = (x); \
36 | t < 0 ? -1 : t > 0 ? +1 : 0; \
37 | })
38 |
39 | // FLOOR(x) + FRAC(x) == x
40 |
41 | #define FLOOR(x) FLOOR_H(x, TMPVAR_H())
42 | #define FLOOR_H(x, t) ({ \
43 | __typeof__ (x) t = (x); \
44 | t >= 0 ? (int)t : -(int)-t; \
45 | })
46 |
47 | #define CEIL(x) CEIL_H(x, TMPVAR_H())
48 | #define CEIL_H(x, t) ({ \
49 | __typeof__ (x) t = (x); \
50 | t >= 0 ? -(int)-t : (int)t; \
51 | })
52 |
53 | #define FRAC(x) FRAC_H(x, TMPVAR_H())
54 | #define FRAC_H(x, t) ({ \
55 | __typeof__ (x) t = (x); \
56 | t >= 0 ? t - (int)t : t + (int)-t; \
57 | })
58 |
59 | // FRAC(x) + RFRAC(x) == 1
60 | #define RFRAC(x) (1 - FRAC(x))
61 |
62 | #define ROUND(x) FLOOR(x + 0.5)
63 |
64 | #endif /* UTIL_H */
65 |
--------------------------------------------------------------------------------
/firmware/src/munch_app.c:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the 1Bitsy 1UP retro inspired game console project.
3 | *
4 | * Copyright (C) 2017 Bob Miller
5 | *
6 | * This program is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This program is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | */
19 |
20 | #include
21 |
22 | #include "munch_app.h"
23 |
24 | #include "lcd.h"
25 | #include "math-util.h"
26 |
27 | /* The classic Munching Square eye candy app. */
28 |
29 | gfx_rgb565 munch_base_color;
30 |
31 | // uint16_t munch_magic = 27; // try different values
32 | uint16_t munch_magic = 20 << 11 | 27; // This is more colorful.
33 |
34 |
35 | void munch_init(void)
36 | {
37 |
38 | }
39 |
40 | void munch_animate(void)
41 | {
42 | /* We want to change the magic number on every color overflow. */
43 | // #pragma GCC diagnostic push
44 | // #pragma GCC diagnostic ignored "-Wstrict-overflow"
45 | // if (munch_base_color > (munch_base_color + 0x0021)) {
46 | // #pragma GCC diagnostic pop
47 | // munch_magic+=10;
48 | // if (munch_magic > 100) {
49 | // munch_magic = 10;
50 | // }
51 | // }
52 | munch_base_color += 0x0021;
53 | }
54 |
55 | /* Borrow the framerate function from tile app. */
56 | extern void tile_draw_fps(gfx_pixslice *slice);
57 |
58 | static void munch_render_slice(gfx_pixslice *slice)
59 | {
60 | const int y_off = -8;
61 | const int x_off = 32;
62 |
63 | gpio_set(GPIOA, GPIO3);
64 |
65 | int y0 = MAX(0, slice->y - y_off);
66 | int y1 = MIN(256, slice->y + (int)slice->h - y_off);
67 | int x0 = MAX(0, slice->x - x_off);
68 | int x1 = MIN(256, x0 + slice->w - x_off);
69 | gfx_rgb565 base = munch_base_color;
70 | for (int y = y0; y < y1; y++) {
71 | gfx_rgb565 *p =
72 | gfx_pixel_address_unchecked(slice, x0 + x_off, y + y_off);
73 | for (int x = x0; x < x1; x++)
74 | *p++ = base + munch_magic * (x ^ y);
75 | }
76 |
77 | if (slice->y == 0) {
78 | tile_draw_fps(slice);
79 | }
80 |
81 | gpio_clear(GPIOA, GPIO3);
82 | }
83 |
84 | void munch_render(void)
85 | {
86 | size_t h;
87 |
88 | for (size_t y = 0; y < LCD_HEIGHT; y += h) {
89 | h = MIN(LCD_MAX_SLICE_ROWS, LCD_HEIGHT - y);
90 | gfx_pixslice *slice = lcd_alloc_pixslice(0, y, LCD_WIDTH, h);
91 | munch_render_slice(slice);
92 | lcd_send_pixslice(slice);
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/firmware/src/munch_app.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the 1Bitsy 1UP retro inspired game console project.
3 | *
4 | * Copyright (C) 2017 Bob Miller
5 | *
6 | * This program is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This program is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | */
19 |
20 | #ifndef MUNCH_APP_H
21 | #define MUNCH_APP_H
22 |
23 | void munch_init(void);
24 | void munch_animate(void);
25 | void munch_render(void);
26 |
27 | #endif /* MUNCH_APP_H */
--------------------------------------------------------------------------------
/firmware/src/pam8019.c:
--------------------------------------------------------------------------------
1 | #include "pam8019.h"
2 |
3 | #include
4 |
5 | #include
6 | #include
7 |
8 | #include "gpio.h"
9 |
10 | #define HP_SENSE_PORT GPIOA
11 | #define HP_SENSE_PIN GPIO0
12 | #define VOL_PORT GPIOA
13 | #define VOL_PIN GPIO1
14 | #define VOL_ADC_CHAN 1
15 | #define MUTE_PORT GPIOA
16 | #define MUTE_PIN GPIO2
17 | #define SHUTDOWN_PORT GPIOA
18 | #define SHUTDOWN_PIN GPIO3
19 |
20 |
21 | static const gpio_pin pam8019_pins[] = {
22 | { // HP SENSE (bidirectional, initially input)
23 | .gp_port = HP_SENSE_PORT,
24 | .gp_pin = HP_SENSE_PIN,
25 | .gp_mode = GPIO_MODE_INPUT,
26 | },
27 | { // VOL_ADC
28 | .gp_port = VOL_PORT,
29 | .gp_pin = VOL_PIN,
30 | .gp_mode = GPIO_MODE_ANALOG,
31 | },
32 | { // MUTE
33 | .gp_port = MUTE_PORT,
34 | .gp_pin = MUTE_PIN,
35 | .gp_mode = GPIO_MODE_OUTPUT,
36 | .gp_level = 0,
37 | },
38 | { // SHUTDOWN
39 | .gp_port = SHUTDOWN_PORT,
40 | .gp_pin = SHUTDOWN_PIN,
41 | .gp_mode = GPIO_MODE_OUTPUT,
42 | .gp_level = 0, // default is shut down.
43 | },
44 | };
45 |
46 | static const size_t pam8019_pin_count = (&pam8019_pins)[1] - pam8019_pins;
47 |
48 | static void enable_override(void)
49 | {
50 | #if 0
51 | gpio_mode_setup(HP_SENSE_PORT,
52 | GPIO_MODE_OUTPUT,
53 | GPIO_PUPD_NONE,
54 | HP_SENSE_PIN);
55 | #else
56 | static const gpio_pin sense_output = {
57 | .gp_port = HP_SENSE_PORT,
58 | .gp_pin = HP_SENSE_PIN,
59 | .gp_mode = GPIO_MODE_OUTPUT,
60 | .gp_otype = GPIO_OTYPE_PP,
61 | };
62 | gpio_config_pin(&sense_output);
63 | #endif
64 | }
65 |
66 | static void disable_override(void)
67 | {
68 | #if 0
69 | gpio_mode_setup(HP_SENSE_PORT,
70 | GPIO_MODE_INPUT,
71 | GPIO_PUPD_NONE,
72 | HP_SENSE_PIN);
73 | #else
74 | static const gpio_pin sense_input = {
75 | .gp_port = HP_SENSE_PORT,
76 | .gp_pin = HP_SENSE_PIN,
77 | .gp_mode = GPIO_MODE_INPUT,
78 | };
79 | gpio_config_pin(&sense_input);
80 | #endif
81 | }
82 |
83 | void pam8019_init(void)
84 | {
85 | gpio_init_pins(pam8019_pins, pam8019_pin_count);
86 |
87 | rcc_periph_clock_enable(RCC_ADC1);
88 |
89 | adc_power_off(ADC1);
90 | adc_disable_scan_mode(ADC1);
91 | adc_set_sample_time_on_all_channels(ADC1, ADC_SMPR_SMP_3CYC);
92 | adc_power_on(ADC1);
93 | }
94 |
95 | pam8019_mode pam8019_get_mode(void)
96 | {
97 | if (!gpio_get(SHUTDOWN_PORT, SHUTDOWN_PIN))
98 | return PM_SHUTDOWN;
99 |
100 | if (gpio_get(MUTE_PORT, MUTE_PIN))
101 | return PM_MUTED;
102 |
103 | uint32_t mode = GPIO_MODER(HP_SENSE_PORT);
104 | mode /= HP_SENSE_PIN * HP_SENSE_PIN;
105 | if ((mode & 0x03) == GPIO_MODE_INPUT)
106 | return PM_NORMAL;
107 |
108 | if (gpio_get(HP_SENSE_PORT, HP_SENSE_PIN))
109 | return PM_OVERRIDE_HP;
110 | else
111 | return PM_OVERRIDE_SPKR;
112 | }
113 |
114 | void pam8019_set_mode(pam8019_mode new_mode)
115 | {
116 | // N.B., SHUTDOWN is active low. MUTE is active high.
117 |
118 | switch (new_mode) {
119 |
120 | case PM_NORMAL:
121 | gpio_set(SHUTDOWN_PORT, SHUTDOWN_PIN);
122 | gpio_clear(MUTE_PORT, MUTE_PIN);
123 | disable_override();
124 | break;
125 |
126 | case PM_SHUTDOWN:
127 | gpio_clear(SHUTDOWN_PORT, SHUTDOWN_PIN);
128 | break;
129 |
130 | case PM_MUTED:
131 | gpio_set(SHUTDOWN_PORT, SHUTDOWN_PIN);
132 | gpio_set(MUTE_PORT, MUTE_PIN);
133 | break;
134 |
135 | case PM_OVERRIDE_HP:
136 | gpio_set(SHUTDOWN_PORT, SHUTDOWN_PIN);
137 | gpio_clear(MUTE_PORT, MUTE_PIN);
138 | enable_override();
139 | gpio_set(HP_SENSE_PORT, HP_SENSE_PIN);
140 | break;
141 |
142 | case PM_OVERRIDE_SPKR:
143 | gpio_set(SHUTDOWN_PORT, SHUTDOWN_PIN);
144 | gpio_clear(MUTE_PORT, MUTE_PIN);
145 | enable_override();
146 | gpio_clear(HP_SENSE_PORT, HP_SENSE_PIN);
147 | break;
148 |
149 | default:
150 | assert(false);
151 | }
152 | }
153 |
154 | bool pam8019_output_is_headphones(void)
155 | {
156 | return (bool)gpio_get(HP_SENSE_PORT, HP_SENSE_PIN);
157 | }
158 |
159 | uint16_t pam8019_get_raw_volume(void)
160 | {
161 | uint8_t channel_array[16] = { VOL_ADC_CHAN };
162 | adc_set_regular_sequence(ADC1, 1, channel_array);
163 | adc_start_conversion_regular(ADC1);
164 | while (!adc_eoc(ADC1))
165 | continue;
166 | return 4095 - adc_read_regular(ADC1);
167 | }
168 |
--------------------------------------------------------------------------------
/firmware/src/pam8019.h:
--------------------------------------------------------------------------------
1 | #ifndef PAM8019_included
2 | #define PAM8019_included
3 |
4 | // Driver for PAM8019 audio and headphone amplifier by Diodes
5 | // Incorporated, as found on the 1UP audio repair board.
6 |
7 | #include
8 | #include
9 |
10 | typedef enum pam8019_mode {
11 | PM_SHUTDOWN,
12 | PM_MUTED,
13 | PM_NORMAL,
14 | PM_OVERRIDE_HP, // force output to headphones.
15 | PM_OVERRIDE_SPKR, // force output to speakers
16 | PM_END,
17 | PM_START = PM_SHUTDOWN,
18 | } pam8019_mode;
19 |
20 | extern void pam8019_init (void);
21 |
22 | // N.B., You will get no souond until you set the mode
23 | // to NORMAL or OVERRIDE_*.
24 |
25 | extern pam8019_mode pam8019_get_mode (void);
26 | extern void pam8019_set_mode (pam8019_mode);
27 |
28 | extern bool pam8019_output_is_headphones (void);
29 |
30 | extern uint16_t pam8019_get_raw_volume (void);
31 |
32 | #endif /* !PAM8019_included */
33 |
--------------------------------------------------------------------------------
/firmware/src/systick.c:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the 1Bitsy lcd graphics library.
3 | *
4 | * Copyright (C) 2017 Bob Miller
5 | *
6 | * This library is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU Lesser General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This library is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU Lesser General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU Lesser General Public License
17 | * along with this library. If not, see .
18 | */
19 |
20 | #include "systick.h"
21 |
22 | #include
23 |
24 | #include
25 |
26 | volatile uint32_t system_millis;
27 | static systick_handler *current_handler;
28 |
29 | // This is the systick ISR.
30 | void sys_tick_handler(void);
31 | void sys_tick_handler(void)
32 | {
33 | system_millis++;
34 | if (current_handler)
35 | (*current_handler)(system_millis);
36 | }
37 |
38 | void setup_systick(uint32_t cpu_freq)
39 | {
40 | // set tick rate to 1 KHz.
41 | systick_set_reload(cpu_freq / 1000);
42 | systick_set_clocksource(STK_CSR_CLKSOURCE_AHB);
43 | systick_counter_enable();
44 | systick_interrupt_enable();
45 | }
46 |
47 | void register_systick_handler(systick_handler *handler)
48 | {
49 | assert(!current_handler);
50 | current_handler = handler;
51 | }
52 |
53 | void delay_msec(uint32_t msec)
54 | {
55 | uint32_t t0 = system_millis;
56 | while ((system_millis - t0) < msec)
57 | continue;
58 | }
59 |
--------------------------------------------------------------------------------
/firmware/src/systick.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the 1Bitsy lcd graphics library.
3 | *
4 | * Copyright (C) 2017 Bob Miller
5 | *
6 | * This library is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU Lesser General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This library is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU Lesser General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU Lesser General Public License
17 | * along with this library. If not, see .
18 | */
19 |
20 | #ifndef SYSTICK_H
21 | #define SYSTICK_H
22 |
23 | #include
24 |
25 | #ifdef __cplusplus
26 | extern "C" {
27 | #endif
28 |
29 | typedef void systick_handler(uint32_t millis);
30 |
31 | extern volatile uint32_t system_millis;
32 |
33 |
34 | void setup_systick(uint32_t cpu_freq);
35 |
36 | void register_systick_handler(systick_handler *);
37 |
38 | void delay_msec(uint32_t msec);
39 |
40 | #ifdef __cplusplus
41 | }
42 | #endif
43 |
44 | #endif /* SYSTICK_H */
45 |
--------------------------------------------------------------------------------
/firmware/src/text.c:
--------------------------------------------------------------------------------
1 | #include "text.h"
2 |
3 | #include "assets/assets.h"
4 |
5 | void text_init(void)
6 | {
7 | }
8 |
9 | int text_draw_str16(gfx_pixslice *slice,
10 | const char *str,
11 | int x, int y,
12 | gfx_rgb565 color)
13 | {
14 | while (*str) {
15 | text_draw_char16(slice, *str, x, y, color);
16 | x++;
17 | str++;
18 | }
19 | return x;
20 | }
21 |
22 | void text_draw_char16(gfx_pixslice *slice,
23 | char ch,
24 | int x, int y,
25 | gfx_rgb565 color)
26 | {
27 | int xoff = x * 8;
28 | int yoff = y * 16;
29 |
30 | if ((ch < MINIWI_FONT_OFFSET) ||
31 | (ch >= MINIWI_FONT_OFFSET + MINIWI_FONT_GLYPH_COUNT)) {
32 | return;
33 | }
34 |
35 | for (int py = 0; py < MINIWI_FONT_HEIGHT; py++) {
36 | gfx_rgb565 *px0 = gfx_pixel_address(slice, xoff, yoff + (py * 2));
37 | gfx_rgb565 *px1 = gfx_pixel_address(slice, xoff, yoff + (py * 2) + 1);
38 | for (int px = 0; px < MINIWI_FONT_WIDTH; px++) {
39 | if (miniwi_font[ch - MINIWI_FONT_OFFSET][px] & (1 << py)) {
40 | if (px0) {
41 | px0[0] = color;
42 | px0[1] = color;
43 | }
44 | if (px1) {
45 | px1[0] = color;
46 | px1[1] = color;
47 | }
48 | }
49 | if (px0) {
50 | px0 += 2;
51 | }
52 | if (px1) {
53 | px1 += 2;
54 | }
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/firmware/src/text.h:
--------------------------------------------------------------------------------
1 | #ifndef TEXT_included
2 | #define TEXT_included
3 |
4 | #include "gfx-types.h"
5 | #include "gfx-pixslice.h"
6 |
7 | extern void text_init(void);
8 |
9 | extern int text_draw_str16 (gfx_pixslice *,
10 | const char *str,
11 | int x, int y,
12 | gfx_rgb565 color);
13 |
14 |
15 | extern void text_draw_char16(gfx_pixslice *,
16 | char,
17 | int x, int y,
18 | gfx_rgb565 color);
19 |
20 | #endif /* !TEXT_included */
21 |
--------------------------------------------------------------------------------
/firmware/src/tile_app.c:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the 1Bitsy 1UP retro inspired game console project.
3 | *
4 | * Copyright (C) 2017 Piotr Esden-Tempski
5 | *
6 | * This program is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This program is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | */
19 |
20 | #include
21 | #include
22 | #include
23 |
24 | #include "tile_app.h"
25 |
26 | #include "gamepad.h"
27 | #include "touch.h"
28 | #include "lcd.h"
29 | #include "math-util.h"
30 | #include "text.h"
31 |
32 | #include "assets/assets.h"
33 |
34 | gfx_rgb565 color = 0;
35 |
36 | static int16_t map_x_off = 0;
37 | static int16_t map_x_dir = +1;
38 | static int16_t map_y_off = 3 * 8;
39 |
40 | static int16_t spr_x = 10;
41 | static int16_t spr_y = 10;
42 | static int16_t spr_x_dir = +1;
43 | static int16_t spr_y_dir = +1;
44 |
45 | static struct tile_video_state {
46 | uint16_t const *tilemap;
47 | uint16_t tilemap_w;
48 | uint16_t tilemap_h;
49 | uint16_t const *tilesheet;
50 | uint16_t tilesheet_w;
51 | uint16_t tilesheet_h;
52 | uint16_t x_off;
53 | uint16_t y_off;
54 | uint32_t frames; /* just a counter of frames since time began. */
55 | uint32_t idle; /* time since no gamepad input */
56 | } tile_video_state;
57 |
58 | /* Selects type of the sprite including fully disabled. */
59 | enum sprite_type {
60 | S_off,
61 | S_8x8,
62 | S_8x16,
63 | S_16x8,
64 | S_16x16,
65 | };
66 |
67 | /* Sprite attributes. */
68 | /* We are using up to 4 tiles from the sprite sheet to represent a single
69 | * sprite object. */
70 | struct sprite {
71 | uint16_t tiles[4];
72 | enum sprite_type type;
73 | uint16_t x;
74 | uint16_t y;
75 | };
76 |
77 | #define SPRITE_MAX_COUNT 16
78 |
79 | struct sprite sprites[SPRITE_MAX_COUNT];
80 |
81 | void tile_init(void)
82 | {
83 | tile_video_state.tilemap = &tml1_tilemap[0][0][0];
84 | tile_video_state.tilemap_w = TML1_TILEMAP_WIDTH;
85 | tile_video_state.tilemap_h = TML1_TILEMAP_HEIGHT;
86 |
87 | tile_video_state.tilesheet = &ts_pixmap[0][0];
88 | tile_video_state.tilesheet_w = TS_PIXMAP_WIDTH;
89 | tile_video_state.tilesheet_h = TS_PIXMAP_HEIGHT;
90 |
91 | tile_video_state.x_off = 0;
92 | tile_video_state.y_off = 0;
93 |
94 | tile_video_state.frames = 0; /* reset time */
95 |
96 | for(int i = 0; i < SPRITE_MAX_COUNT; i++) {
97 | sprites[i].type = S_off;
98 | }
99 |
100 | sprites[0].type = S_8x16;
101 | sprites[0].tiles[0] = 22;
102 | sprites[0].tiles[1] = 64;
103 | sprites[0].x = 10;
104 | sprites[0].y = 10;
105 | }
106 |
107 | void tile_draw_tile(gfx_pixslice *slice, uint16_t tile_id, int px, int py)
108 | {
109 | int tile_x = (tile_id * 8) % TS_PIXMAP_WIDTH;
110 | int tile_y = ((tile_id * 8) / TS_PIXMAP_WIDTH) * 8;
111 |
112 | if (tile_x >= TS_PIXMAP_WIDTH)
113 | {
114 | return;
115 | }
116 |
117 | if (tile_y >= TS_PIXMAP_HEIGHT)
118 | {
119 | return;
120 | }
121 |
122 | int tile_x0 = 0;
123 | int tile_w = 8;
124 | if (px < 0) {
125 | tile_x0 += -px / 2;
126 | px = 0;
127 | }
128 | else if (px + 16 > LCD_WIDTH) {
129 | tile_w -= (px + 16 - LCD_WIDTH) / 2;
130 | }
131 |
132 | int tile_y0 = 0;
133 | int tile_h = 8;
134 | if (py < 0) {
135 | tile_y0 += -py / 2;
136 | py = 0;
137 | }
138 | else if (py + 16 > LCD_HEIGHT) {
139 | tile_h -= (py + 16 - LCD_HEIGHT) / 2;
140 | }
141 |
142 |
143 | for (int y = tile_y0; y < tile_h; y++) {
144 | gfx_rgb565 *px0 =
145 | gfx_pixel_address(slice, px, py + ((y - tile_y0) * 2));
146 | gfx_rgb565 *px1 =
147 | gfx_pixel_address(slice, px, py + ((y - tile_y0) * 2) + 1);
148 |
149 | for (int x = tile_x0; x < tile_w; x++) {
150 | uint16_t c = ts_pixmap[tile_y + y][tile_x + x];
151 |
152 | if (c != 0xF81F) {
153 | if (px0) {
154 | *px0++ = c;
155 | *px0++ = c;
156 | }
157 | if (px1) {
158 | *px1++ = c;
159 | *px1++ = c;
160 | }
161 | } else {
162 | if (px0) px0+=2;
163 | if (px1) px1+=2;
164 | }
165 | }
166 | }
167 |
168 | #if 0
169 | int tile_x = (tile_id * 8) % tile_video_state.tilesheet_w;
170 | int tile_y = ((tile_id * 8) / tile_video_state.tilesheet_w) * 8;
171 |
172 | for (int y = 0; y < 8; y++) {
173 | gfx_rgb565 *px0 =
174 | gfx_pixel_address_unchecked(slice, px, py + (y * 2));
175 | gfx_rgb565 *px1 =
176 | gfx_pixel_address_unchecked(slice, px, py + (y * 2) + 1);
177 | for (int x = 0; x < 8; x++) {
178 | int tile_pix =
179 | ((tile_y + y) * tile_video_state.tilesheet_w) +
180 | (tile_x + x);
181 | *px0++ = tile_video_state.tilesheet[tile_pix];
182 | *px0++ = tile_video_state.tilesheet[tile_pix];
183 | *px1++ = tile_video_state.tilesheet[tile_pix];
184 | *px1++ = tile_video_state.tilesheet[tile_pix];
185 | }
186 | }
187 | #endif
188 | }
189 |
190 | void tile_draw_sprite_tile(gfx_pixslice *slice, uint16_t tile_id, int px, int py)
191 | {
192 | int tile_x = (tile_id * 8) % SS_PIXMAP_WIDTH;
193 | int tile_y = ((tile_id * 8) / SS_PIXMAP_WIDTH) * 8;
194 |
195 | /* Check if the tile exists. */
196 | if (tile_x >= SS_PIXMAP_WIDTH)
197 | {
198 | return;
199 | }
200 |
201 | if (tile_y >= SS_PIXMAP_HEIGHT)
202 | {
203 | return;
204 | }
205 |
206 | /* Trying to draw out of bounds. */
207 | if ((px < -16) ||
208 | (px >= LCD_WIDTH) ||
209 | (py < (slice->y - 16)) ||
210 | (py >= (slice->y + slice->h))) {
211 | return;
212 | }
213 |
214 | /* Trim draw bounds. */
215 | int tile_x0 = 0;
216 | int tile_w = 8;
217 | if (px < 0) {
218 | tile_x0 += -px / 2;
219 | px = 0;
220 | }
221 | else if (px + 16 > LCD_WIDTH) {
222 | tile_w -= (px + 16 - LCD_WIDTH) / 2;
223 | }
224 |
225 | int tile_y0 = 0;
226 | int tile_h = 8;
227 | if (py < 0) {
228 | tile_y0 += -py / 2;
229 | py = 0;
230 | }
231 | else if (py + 16 > LCD_HEIGHT) {
232 | tile_h -= (py + 16 - LCD_HEIGHT) / 2;
233 | }
234 |
235 | /* Draw tile. */
236 | for (int y = tile_y0; y < tile_h; y++) {
237 | gfx_rgb565 *px0 =
238 | gfx_pixel_address(slice, px, py + ((y - tile_y0) * 2));
239 | gfx_rgb565 *px1 =
240 | gfx_pixel_address(slice, px, py + ((y - tile_y0) * 2) + 1);
241 |
242 | for (int x = tile_x0; x < tile_w; x++) {
243 | uint16_t c = ss_pixmap[tile_y + y][tile_x + x];
244 |
245 | if (c != 0xF81F) {
246 | if (px0) {
247 | *px0++ = c;
248 | *px0++ = c;
249 | }
250 | if (px1) {
251 | *px1++ = c;
252 | *px1++ = c;
253 | }
254 | } else {
255 | if (px0) px0+=2;
256 | if (px1) px1+=2;
257 | }
258 | }
259 | }
260 | }
261 |
262 | void tile_draw_sprite(gfx_pixslice *slice, struct sprite *sprite)
263 | {
264 | switch(sprite->type) {
265 | case S_off:
266 | return;
267 | case S_8x8:
268 | tile_draw_sprite_tile(slice, sprite->tiles[0],
269 | sprite->x, sprite->y);
270 | break;
271 | case S_8x16:
272 | tile_draw_sprite_tile(slice, sprite->tiles[0],
273 | sprite->x, sprite->y);
274 | tile_draw_sprite_tile(slice, sprite->tiles[1],
275 | sprite->x, sprite->y + 16);
276 | break;
277 | case S_16x8:
278 | tile_draw_sprite_tile(slice, sprite->tiles[0],
279 | sprite->x, sprite->y);
280 | tile_draw_sprite_tile(slice, sprite->tiles[1],
281 | sprite->x + 16, sprite->y);
282 | break;
283 | case S_16x16:
284 | tile_draw_sprite_tile(slice, sprite->tiles[0],
285 | sprite->x, sprite->y);
286 | tile_draw_sprite_tile(slice, sprite->tiles[1],
287 | sprite->x + 16, sprite->y);
288 | tile_draw_sprite_tile(slice, sprite->tiles[2],
289 | sprite->x, sprite->y + 16);
290 | tile_draw_sprite_tile(slice, sprite->tiles[3],
291 | sprite->x + 16, sprite->y + 16);
292 | break;
293 | }
294 | }
295 |
296 | void tile_draw_sprites(gfx_pixslice *slice)
297 | {
298 | for(int i=SPRITE_MAX_COUNT; i > 0; i--) {
299 | tile_draw_sprite(slice, &sprites[i-1]);
300 | }
301 | }
302 |
303 | void tile_draw_char8(gfx_pixslice *slice, char ch, int x, int y, gfx_rgb565 color)
304 | {
305 | int xoff = x * 4;
306 | int yoff = y * 8;
307 |
308 | if ((ch < MINIWI_FONT_OFFSET) || (ch >= (MINIWI_FONT_OFFSET + MINIWI_FONT_GLYPH_COUNT))) {
309 | return;
310 | }
311 |
312 | for (int py = 0; py < 8; py++) {
313 | gfx_rgb565 *px0 =
314 | gfx_pixel_address_unchecked(slice, xoff, yoff + py);
315 | for (int px = 0; px < 4; px++) {
316 | if ((miniwi_font[(int)ch - MINIWI_FONT_OFFSET][px] & (1 << py)) != 0) {
317 | *px0++ = color;
318 | } else {
319 | px0++;
320 | }
321 | }
322 | }
323 | }
324 |
325 | extern uint32_t fps;
326 |
327 | void tile_draw_fps(gfx_pixslice *slice)
328 | {
329 | if (slice->y >= 16)
330 | return;
331 |
332 | uint32_t lfps = fps;
333 | int pos = 0;
334 | char *prefix = "fps: ";
335 |
336 | for (; lfps > 0; lfps /= 10) {
337 | //tile_draw_char8(slice, (lfps % 10) + '0', LCD_WIDTH / 4 - (pos + 1), 0, 0x0000);
338 | text_draw_char16(slice, (lfps % 10) + '0', LCD_WIDTH / 8 - (pos + 1), 0, 0x0000);
339 | pos++;
340 | }
341 |
342 | for (int i = 0; i < 5; i++) {
343 | //tile_draw_char8(slice, prefix[4 - i], LCD_WIDTH / 4 - (pos + 1), 0, 0x0000);
344 | text_draw_char16(slice, prefix[4 - i], LCD_WIDTH / 8 - (pos + 1), 0, 0x0000);
345 | pos++;
346 | }
347 | }
348 |
349 | void tile_draw_gamepad(gfx_pixslice *slice)
350 | {
351 | if (slice->y >= 32)
352 | return;
353 |
354 | char *prefix = "gamepad: ";
355 | uint16_t gamepad = gamepad_get();
356 |
357 | for (int i = 0; i < 16; i++) {
358 | if ((gamepad & (1 << i)) != 0) {
359 | //tile_draw_char8(slice, '1', LCD_WIDTH / 4 - (i + 1), 1, 0x0000);
360 | text_draw_char16(slice, '1', LCD_WIDTH / 8 - (i + 1), 1, 0x0000);
361 | } else {
362 | //tile_draw_char8(slice, '0', LCD_WIDTH / 4 - (i + 1), 1, 0x0000);
363 | text_draw_char16(slice, '0', LCD_WIDTH / 8 - (i + 1), 1, 0x0000);
364 | }
365 | }
366 |
367 | for (int i = 0; prefix[i] != 0; i++) {
368 | //tile_draw_char8(slice, prefix[i],
369 | // LCD_WIDTH / 4 - (16 + strlen(prefix)) + i, 1, 0x0000);
370 | text_draw_char16(slice, prefix[i],
371 | LCD_WIDTH / 8 - (16 + strlen(prefix)) + i, 1, 0x0000);
372 | }
373 | }
374 |
375 | void tile_draw_touch(gfx_pixslice *slice)
376 | {
377 | if (slice->y >= 48)
378 | return;
379 |
380 | int tx, ty;
381 | bool touched = touch_get(&tx, &ty);
382 | if (!touched)
383 | return;
384 |
385 | char text[16];
386 | sprintf(text, "touch: %3d, %3d", tx, ty);
387 |
388 | for (int i = 0; text[i] != 0; i++) {
389 | text_draw_char16(slice, text[i],
390 | LCD_WIDTH / 8 - (strlen(text)) + i, 2, 0x0000);
391 | }
392 | }
393 |
394 | void tile_animate(void)
395 | {
396 | #if 0
397 | tile_y += tile_y_inc;
398 | if (tile_y + (TS_PIXMAP_HEIGHT*2) > LCD_HEIGHT) {
399 | tile_y_inc = -1;
400 | tile_y -= 2;
401 | } else if (tile_y < 0) {
402 | tile_y_inc = +1;
403 | tile_y += 1;
404 | }
405 | #endif
406 | static uint16_t delay = 0;
407 | static uint16_t stay = 0;
408 | uint16_t gamepad = gamepad_get();
409 | int tx, ty;
410 | bool touched = touch_get(&tx, &ty);
411 |
412 | if (gamepad != 0x0000 || touched) {
413 | tile_video_state.idle = 0;
414 | }
415 |
416 | if (touched) {
417 | spr_x = tx - 4;
418 | spr_y = ty - 4;
419 | if (spr_x < 0) {
420 | spr_x = 0;
421 | } else if (spr_x > (19 * 8 * 2)) {
422 | spr_x = 19 * 8 * 2;
423 | }
424 | if (spr_y < 0) {
425 | spr_y = 0;
426 | } else if (spr_y > (19 * 8 * 2)) {
427 | spr_y = 13 * 8 * 2;
428 | }
429 | }
430 |
431 | if ((gamepad != 0xFFFF) && (tile_video_state.idle < (80 * 10))) {
432 | if ((gamepad & GAMEPAD_BLEFT) != 0) {
433 | if (map_x_off > 0) {
434 | map_x_off--;
435 | }
436 | } else if ((gamepad & GAMEPAD_BRIGHT) != 0) {
437 | if (map_x_off < (108 * 8)) {
438 | map_x_off++;
439 | }
440 | }
441 | if ((gamepad & GAMEPAD_BUP) != 0) {
442 | if (map_y_off > 0) {
443 | map_y_off--;
444 | }
445 | } else if ((gamepad & GAMEPAD_BDOWN) != 0) {
446 | if (map_y_off < (3 * 8)) {
447 | map_y_off++;
448 | }
449 | }
450 |
451 | if ((gamepad & GAMEPAD_BY) != 0) {
452 | if (spr_x > 0) {
453 | spr_x--;
454 | }
455 | } else if ((gamepad & GAMEPAD_BA) != 0) {
456 | if (spr_x < (19 * 8 * 2)) {
457 | spr_x++;
458 | }
459 | }
460 | if ((gamepad & GAMEPAD_BX) != 0) {
461 | if (spr_y > 0) {
462 | spr_y--;
463 | }
464 | } else if ((gamepad & GAMEPAD_BB) != 0) {
465 | if (spr_y < (13 * 8 * 2)) {
466 | spr_y++;
467 | }
468 | }
469 | } else {
470 | if (delay == 1) {
471 | delay = 0;
472 | map_x_off += map_x_dir;
473 | if (map_x_off == 108*8) {
474 | map_x_dir = 0;
475 | stay++;
476 | if (stay == 10) {
477 | stay = 0;
478 | map_x_dir = -1;
479 | }
480 | }
481 | if (map_x_off == 0) {
482 | map_x_dir = 0;
483 | stay++;
484 | if (stay == 10) {
485 | stay = 0;
486 | map_x_dir = +1;
487 | }
488 | }
489 | } else {
490 | delay++;
491 | }
492 |
493 | spr_x += spr_x_dir;
494 | spr_y += spr_y_dir;
495 |
496 | if ((spr_x + 14) == (LCD_WIDTH-1)) {
497 | spr_x_dir = -1;
498 | }
499 |
500 | if (spr_x == 0) {
501 | spr_x_dir = 1;
502 | }
503 |
504 | if ((spr_y + 22) == (LCD_HEIGHT-1)) {
505 | spr_y_dir = -1;
506 | }
507 |
508 | if (spr_y == 0) {
509 | spr_y_dir = 1;
510 | }
511 | }
512 |
513 | if ((tile_video_state.frames / 40) % 2) { /* every 80 frames */
514 | sprites[0].tiles[0] = 43;
515 | sprites[0].tiles[1] = 64;
516 | } else {
517 | sprites[0].tiles[0] = 21;
518 | sprites[0].tiles[1] = 63;
519 | }
520 |
521 | sprites[0].x = spr_x;
522 | sprites[0].y = spr_y;
523 | }
524 |
525 | static void tile_render_slice(gfx_pixslice *slice)
526 | {
527 |
528 | #if 0
529 | /* Draw some lines to indicate drawing direction and pixslice start/end */
530 | XXX must check pixel address. NULL is out of bounds.
531 | gfx_rgb565 *px =
532 | gfx_pixel_address_unchecked(slice, 0, slice->y);
533 | for (size_t x = 0; x < 10; x++) {
534 | *px++ = 0xFFFF;
535 | }
536 | XXX must check pixel address. NULL is out of bounds.
537 | px =
538 | gfx_pixel_address_unchecked(slice, 0, slice->y + slice->h - 2);
539 | for (size_t x = 0; x < 10; x++) {
540 | *px++ = 0xF800;
541 | }
542 | #endif
543 |
544 | #if 0
545 | for (size_t y = slice->y; y < (slice->y + slice->h); y++ ) {
546 | int32_t yy = (int32_t)y - tile_y;
547 | if (yy < 0 || yy >= (TS_PIXMAP_HEIGHT*2))
548 | continue;
549 | XXX must check pixel address. NULL is out of bounds.
550 | gfx_rgb565 *px =
551 | gfx_pixel_address_unchecked(slice, 0, y);
552 | for (size_t x = 0; x < slice->w; x++) {
553 | if (x < (TS_PIXMAP_WIDTH*2)) {
554 | if(ts_pixmap[yy/2][x/2]!=0xF81F) {
555 | *px++ = ts_pixmap[yy/2][x/2];
556 | } else {
557 | px++;
558 | }
559 | }
560 | }
561 | }
562 | #endif
563 |
564 | // if(slice->y == 0) {
565 | // tile_draw_tile(slice, 1, 10, 10);
566 | // }
567 |
568 | /* gpio_set(GPIOA, GPIO3); */
569 |
570 | /* Tilemap */
571 | for (size_t y = slice->y / 16; y <= (slice->y + slice->h)/16; y++) {
572 | for (size_t x = 0; x <= slice->w / 16; x++) {
573 | const uint16_t tid =
574 | tml1_tilemap[0][y + map_y_off / 8][x + map_x_off / 8];
575 | if (tid) {
576 | tile_draw_tile(slice,
577 | tid - 1,
578 | x * 16 - (map_x_off % 8) * 2,
579 | y * 16 - (map_y_off % 8) * 2);
580 | }
581 | }
582 | }
583 |
584 | /* Sprites */
585 | tile_draw_sprites(slice);
586 |
587 | /* Text */
588 | if(slice->y == 0) {
589 | tile_draw_fps(slice);
590 | tile_draw_gamepad(slice);
591 | tile_draw_touch(slice);
592 | }
593 |
594 | /* gpio_clear(GPIOA, GPIO3); */
595 | }
596 |
597 | void tile_render(void)
598 | {
599 | size_t h;
600 | size_t slice_max_h = LCD_MAX_SLICE_ROWS;
601 | color = 0;
602 |
603 | if (lcd_bg_color() != TML1_TILEMAP_BG_COLOR) {
604 | lcd_set_bg_color(TML1_TILEMAP_BG_COLOR, true);
605 | }
606 |
607 | for (size_t y = 0; y < LCD_HEIGHT; y += h) {
608 | h = MIN(slice_max_h, LCD_HEIGHT - y);
609 | gfx_pixslice *slice = lcd_alloc_pixslice(0, y, LCD_WIDTH, h);
610 | tile_render_slice(slice);
611 | lcd_send_pixslice(slice);
612 | }
613 |
614 | tile_video_state.frames++; /* increment time */
615 | tile_video_state.idle++; /* increment idle time */
616 | }
617 |
--------------------------------------------------------------------------------
/firmware/src/tile_app.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the 1Bitsy 1UP retro inspired game console project.
3 | *
4 | * Copyright (C) 2017 Piotr Esden-Tempski
5 | *
6 | * This program is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This program is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | */
19 |
20 | #ifndef TILE_APP_H
21 | #define TILE_APP_H
22 |
23 | void tile_init(void);
24 | void tile_animate(void);
25 | void tile_render(void);
26 |
27 | #endif /* TILE_APP_H */
--------------------------------------------------------------------------------
/firmware/src/touch.c:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the 1Bitsy 1UP retro inspired game console project.
3 | *
4 | * Copyright (C) 2017 Nicolas Schodet
5 | *
6 | * This program is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This program is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | */
19 |
20 | #include
21 | #include
22 | #include
23 | #include
24 | #include
25 |
26 | #include "i2c.h"
27 | #include "lcd.h"
28 |
29 | #include "touch.h"
30 |
31 | static const i2c_channel touch_i2c = {
32 | .i_base_address = I2C1,
33 | .i_is_master = true,
34 | .i_stop = true,
35 | .i_address = 0b01110000,
36 | };
37 |
38 | static volatile bool touch_event = true;
39 |
40 | static bool touch_touched = false;
41 | static int touch_x = 0;
42 | static int touch_y = 0;
43 |
44 | void exti9_5_isr(void)
45 | {
46 | touch_event = true;
47 | exti_reset_request(EXTI5);
48 | }
49 |
50 | void touch_init(void)
51 | {
52 | rcc_periph_clock_enable(RCC_SYSCFG);
53 |
54 | gpio_mode_setup(GPIOB, GPIO_MODE_INPUT, GPIO_PUPD_NONE, GPIO5);
55 | exti_select_source(EXTI5, GPIOB);
56 | exti_set_trigger(EXTI5, EXTI_TRIGGER_FALLING);
57 | exti_enable_request(EXTI5);
58 | exti_reset_request(EXTI5);
59 | nvic_enable_irq(NVIC_EXTI9_5_IRQ);
60 | }
61 |
62 | static void touch_update(void)
63 | {
64 | static const uint8_t req[] = { 0x02 };
65 | i2c_transmit(&touch_i2c, req, sizeof(req));
66 | uint8_t rsp[5] = { 0 };
67 | i2c_receive(&touch_i2c, rsp, sizeof(rsp));
68 | int count = rsp[0] & 0xf;
69 | if (count && count <= 5) {
70 | touch_touched = true;
71 | touch_y = LCD_HEIGHT - ((rsp[1] & 0xf) << 8 | rsp[2]);
72 | touch_x = ((rsp[3] & 0xf) << 8 | rsp[4]);
73 | } else {
74 | touch_touched = false;
75 | }
76 | }
77 |
78 | bool touch_get(int *x, int *y)
79 | {
80 | if (touch_event) {
81 | touch_event = false;
82 | touch_update ();
83 | }
84 | *x = touch_x;
85 | *y = touch_y;
86 | return touch_touched;
87 | }
88 |
--------------------------------------------------------------------------------
/firmware/src/touch.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the 1Bitsy 1UP retro inspired game console project.
3 | *
4 | * Copyright (C) 2017 Nicolas Schodet
5 | *
6 | * This program is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This program is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | */
19 |
20 | #ifndef TOUCH_H
21 | #define TOUCH_H
22 |
23 | #include
24 |
25 | // Install touch IRQ.
26 | void touch_init(void);
27 |
28 | // Return current state of touch screen, touched (true) or not (false), and
29 | // if touched, fill coordinates.
30 | bool touch_get(int *x, int *y);
31 |
32 | #endif /* TOUCH_H */
33 |
--------------------------------------------------------------------------------
/firmware/src/volume.c:
--------------------------------------------------------------------------------
1 | #include "volume.h"
2 |
3 | #include "pam8019.h"
4 |
5 | static uint16_t volume_raw_min = 600; // raw volume doesn't go below 570-ish.
6 |
7 | static uint16_t smooth(uint32_t numer, uint32_t denom, uint16_t expected)
8 | {
9 | if (numer + denom / 2 >= expected * denom &&
10 | numer - denom / 2 <= (expected + 1) * denom)
11 | return expected;
12 | return numer / denom;
13 | }
14 |
15 | void volume_init(void)
16 | {
17 | }
18 |
19 | uint8_t volume_get(void)
20 | {
21 | uint16_t raw = volume_get_raw();
22 |
23 | if (volume_raw_min > raw)
24 | volume_raw_min = raw;
25 | uint32_t numerator = raw - volume_raw_min;
26 | uint32_t denominator = VOLUME_RAW_MAX - volume_raw_min;
27 | numerator *= VOLUME_MAX - VOLUME_MIN + 1;
28 |
29 | static uint16_t smoothed_vol = UINT16_MAX;
30 | smoothed_vol = smooth(numerator, denominator, smoothed_vol);
31 | // smoothed_vol = numerator / denominator;
32 |
33 |
34 | return smoothed_vol;
35 | }
36 |
37 | uint16_t volume_get_raw(void)
38 | {
39 | return pam8019_get_raw_volume();
40 | }
41 |
--------------------------------------------------------------------------------
/firmware/src/volume.h:
--------------------------------------------------------------------------------
1 | #ifndef VOLUME_included
2 | #define VOLUME_included
3 |
4 | #include
5 |
6 | #define VOLUME_MIN 0
7 | #define VOLUME_MAX 64
8 | #define VOLUME_RAW_MAX 4095
9 |
10 | extern void volume_init (void);
11 | extern uint8_t volume_get (void);
12 |
13 | extern uint16_t volume_get_raw (void);
14 |
15 | #endif /* !VOLUME_included */
16 |
--------------------------------------------------------------------------------
/hardware/NOTES.md:
--------------------------------------------------------------------------------
1 | # Other Projects
2 | * [Circuit Sword (RPi)](https://github.com/kiteretro/Circuit-Sword/wiki/GB-Original-Case-Mod-Guide)
3 | * [uGame (ATSAMD21)](https://hackaday.io/project/27629-game)
4 | * [Lameboy (ESP8266)](https://hackaday.io/project/26823-lameboy-another-esp12-handheld)
5 |
6 | # Possible tact switch options
7 | * If we use an existing industrial design we should consider using the original membrane switches
8 | * If we work on a micro tiny board we should look into SKPMAPE010 from ALPS used also by uGame
9 |
--------------------------------------------------------------------------------
/hardware/V0.1/1bitsy-1up-cache.lib:
--------------------------------------------------------------------------------
1 | EESchema-LIBRARY Version 2.3
2 | #encoding utf-8
3 | #
4 | # +3V3
5 | #
6 | DEF +3V3 #PWR 0 0 Y Y 1 F P
7 | F0 "#PWR" 0 -150 50 H I C CNN
8 | F1 "+3V3" 0 140 50 H V C CNN
9 | F2 "" 0 0 50 H I C CNN
10 | F3 "" 0 0 50 H I C CNN
11 | ALIAS +3.3V
12 | DRAW
13 | P 2 0 1 0 -30 50 0 100 N
14 | P 2 0 1 0 0 0 0 100 N
15 | P 2 0 1 0 0 100 30 50 N
16 | X +3V3 1 0 0 0 U 50 50 1 1 W N
17 | ENDDRAW
18 | ENDDEF
19 | #
20 | # +5V
21 | #
22 | DEF +5V #PWR 0 0 Y Y 1 F P
23 | F0 "#PWR" 0 -150 50 H I C CNN
24 | F1 "+5V" 0 140 50 H V C CNN
25 | F2 "" 0 0 50 H I C CNN
26 | F3 "" 0 0 50 H I C CNN
27 | DRAW
28 | P 2 0 1 0 -30 50 0 100 N
29 | P 2 0 1 0 0 0 0 100 N
30 | P 2 0 1 0 0 100 30 50 N
31 | X +5V 1 0 0 0 U 50 50 1 1 W N
32 | ENDDRAW
33 | ENDDEF
34 | #
35 | # +BATT
36 | #
37 | DEF +BATT #PWR 0 0 Y Y 1 F P
38 | F0 "#PWR" 0 -150 50 H I C CNN
39 | F1 "+BATT" 0 140 50 H V C CNN
40 | F2 "" 0 0 50 H I C CNN
41 | F3 "" 0 0 50 H I C CNN
42 | DRAW
43 | P 2 0 1 0 -30 50 0 100 N
44 | P 2 0 1 0 0 0 0 100 N
45 | P 2 0 1 0 0 100 30 50 N
46 | X +BATT 1 0 0 0 U 50 50 1 1 W N
47 | ENDDRAW
48 | ENDDEF
49 | #
50 | # 1bitsy-complete-concise
51 | #
52 | DEF 1bitsy-complete-concise U 0 40 Y Y 1 F N
53 | F0 "U" 0 100 60 H V C CNN
54 | F1 "1bitsy-complete-concise" 0 0 60 H V C CNN
55 | F2 "" 0 100 60 H I C CNN
56 | F3 "" 0 100 60 H I C CNN
57 | DRAW
58 | S -2400 1300 2400 -1300 0 1 0 N
59 | X GND 1 -2600 1200 200 R 50 50 1 1 P
60 | X PC10/SPI3SCK/I2S3CK/USART3&4_TX/SDIOD2 2 -2600 1100 200 R 50 50 1 1 P
61 | X PC11/ADCEXTI11/I2S3EXTSD/SPI3MISO/USART3&4_RX/SDIOD3 3 -2600 1000 200 R 50 50 1 1 P
62 | X PC12/SPI3MOSI/I2S3SD/USART3CK/UART5TX/SDIOCK 4 -2600 900 200 R 50 50 1 1 P
63 | X PD2/T2ETR/UART5RX/SDIOCMD 5 -2600 800 200 R 50 50 1 1 P
64 | X PB4/~JTRST~/T3C1/SPI1&3_MISO/I2S3EXTSD 6 -2600 700 200 R 50 50 1 1 P
65 | X PB5/T3C2/I2C1SMBA/SPI1&3_MOSI/I2S3SD/CAN2RX/ULPID7 7 -2600 600 200 R 50 50 1 1 P
66 | X PB6/T4C1/I2C1SCL/USART1TX/CAN2TX 8 -2600 500 200 R 50 50 1 1 P
67 | X PB7/T4C2/I2C1SDA/USART1RX 9 -2600 400 200 R 50 50 1 1 P
68 | X PB8/T4C3/TI0C1/I2C1SCL/CAN2RX/SDIOD4 10 -2600 300 200 R 50 50 1 1 P
69 | X PB11/T2C4/I2C2SDA/USART3RX/ULPID4 20 2600 200 200 L 50 50 1 1 P
70 | X VIN 30 2600 1200 200 L 50 50 1 1 P
71 | X PC5/ADC15 40 2600 -400 200 L 50 50 1 1 P
72 | X PB9/T4C4/T1C1/I2C1SDA/SPI2NSS/I2S2WS/CAN2TX/SDIOD5 11 -2600 200 200 R 50 50 1 1 P
73 | X PB12/T1BK/I2C2SMBA/SPI2NSS/I2S2WS/USART3CK/CAN2RX/ULPID5/HSID 21 2600 300 200 L 50 50 1 1 P
74 | X PA0-WKUP/ADC0/T2C1ETR/T5C1/T8ETR/USART2CTS/UART4TX 31 -2600 -400 200 R 50 50 1 1 P
75 | X LED|PA8-MCO1/T1C1/I2C3SCL/USART1CK/OTGFSSOF 41 -2600 -1000 200 R 50 50 1 1 P
76 | X PC2/ADC12/SPI2MISO/I2S2EXTSD/ULPIDIR 12 -2600 100 200 R 50 50 1 1 P
77 | X PB13/T1C1N/SPI2SCK/12S2CK/USART3CTS/CAN2TX/ULPID6 22 2600 400 200 L 50 50 1 1 P
78 | X PA1/ADC1/T2C2/T5C2/USART2RTS/UART4RX 32 -2600 -500 200 R 50 50 1 1 P
79 | X PC13 42 -2600 -1100 200 R 50 50 1 1 P
80 | X PC3/ADC13/SPI2MOSI/I2S2SD/ULPINXT 13 -2600 0 200 R 50 50 1 1 P
81 | X PB14/T1&8C2N/SPI2MISO/I2S2EXTSD/USART3RTS/T12C1/HSDM 23 2600 500 200 L 50 50 1 1 P
82 | X PA2/ADC2/T2C3/T5C3/T9C1/USART2TX 33 -2600 -600 200 R 50 50 1 1 P
83 | X PC0/ADC10/ULPISTP 43 -2600 -1200 200 R 50 50 1 1 P
84 | X VBAT 14 -2600 -100 200 R 50 50 1 1 P
85 | X PB15/T1&8C3N/SPI2MOSI/I2S2SD/T12C2/HSDP 24 2600 600 200 L 50 50 1 1 P
86 | X PA3/ADC3/T2C4/T5C4/T9C2/USART2RX/ULPID0 34 -2600 -700 200 R 50 50 1 1 P
87 | X PB2 44 2600 -1000 200 L 50 50 1 1 P
88 | X +3V3 15 -2600 -200 200 R 50 50 1 1 P
89 | X PC6/T3&8C1/I2S2MCK/USART6TX/SDIOD6 25 2600 700 200 L 50 50 1 1 P
90 | X PA4/ADC4/DAC1/SPI1NSS/SPI3NSS/I2S3WS/USART2CK 35 -2600 -800 200 R 50 50 1 1 P
91 | X GND 16 2600 -200 200 L 50 50 1 1 P
92 | X PC7/T3&8C2/I2S3MCK/USART6RX/SDIOD7 26 2600 800 200 L 50 50 1 1 P
93 | X PA5/ADC5/DAC2/T2C1ETR/T8C1N/SPI1SCK/ULPICK 36 2600 -800 200 L 50 50 1 1 P
94 | X PB0/ADC8/T1C2N/T3C3/T8C2N/ULPID1 17 2600 -100 200 L 50 50 1 1 P
95 | X PC8/T3&8C3/USART6CK/SDIOD0 27 2600 900 200 L 50 50 1 1 P
96 | X PA6/ADC6/T1BK/T3C1/T8BK/SPI1MISO/T13C1 37 2600 -700 200 L 50 50 1 1 P
97 | X PB1/ADC9/T1C3N/T3C4/T8C3N 18 2600 0 200 L 50 50 1 1 P
98 | X PC9-MCO2/DACEXTI9/T3&8C4/I2C3SDA/I2S2CHIN/SDIOD1 28 2600 1000 200 L 50 50 1 1 P
99 | X PA7/ADC7/T1C1N/T3C2/T8C1N/SPI1MOSI/T12C2 38 2600 -600 200 L 50 50 1 1 P
100 | X PB10/T2C3/I2C2SCL/SPI2SCK/I2S2CK/USART3TX/ULPID3 19 2600 100 200 L 50 50 1 1 P
101 | X +3V3 29 2600 1100 200 L 50 50 1 1 P
102 | X PC4/ADC14 39 2600 -500 200 L 50 50 1 1 P
103 | ENDDRAW
104 | ENDDEF
105 | #
106 | # 74HC165
107 | #
108 | DEF 74HC165 U 0 40 Y Y 1 F N
109 | F0 "U" 0 -800 60 H V C CNN
110 | F1 "74HC165" 0 750 60 H V C CNN
111 | F2 "" 2190 -1220 60 H I C CNN
112 | F3 "" 2190 -1220 60 H I C CNN
113 | DRAW
114 | S -400 700 400 -700 0 1 0 N
115 | X SH/~LD 1 -600 -600 200 R 50 50 1 1 P
116 | X CLK 2 -600 -400 200 R 50 50 1 1 P
117 | X D4 3 -600 100 200 R 50 50 1 1 P
118 | X D5 4 -600 0 200 R 50 50 1 1 P
119 | X D6 5 -600 -100 200 R 50 50 1 1 P
120 | X D7 6 -600 -200 200 R 50 50 1 1 P
121 | X ~QH 7 600 -400 200 L 50 50 1 1 P
122 | X GND 8 600 -650 200 L 50 50 1 1 P
123 | X QH 9 600 -200 200 L 50 50 1 1 P
124 | X SER 10 -600 600 200 R 50 50 1 1 P
125 | X D0 11 -600 500 200 R 50 50 1 1 P
126 | X D1 12 -600 400 200 R 50 50 1 1 P
127 | X D2 13 -600 300 200 R 50 50 1 1 P
128 | X D3 14 -600 200 200 R 50 50 1 1 P
129 | X CLK_INH 15 -600 -500 200 R 50 50 1 1 P
130 | X VCC 16 600 650 200 L 50 50 1 1 P
131 | ENDDRAW
132 | ENDDEF
133 | #
134 | # BQ24075
135 | #
136 | DEF BQ24075 U 0 40 Y Y 1 F N
137 | F0 "U" 0 -650 60 H V C CNN
138 | F1 "BQ24075" 0 750 60 H V C CNN
139 | F2 "" 2150 -1050 60 H I C CNN
140 | F3 "" 2150 -1050 60 H I C CNN
141 | F4 "ANY" 0 0 60 H I C CNN "Source"
142 | DRAW
143 | S -400 700 400 -600 0 0 0 N
144 | X TS 1 -600 200 200 R 50 50 1 1 P
145 | X BAT 2 -600 400 200 R 50 50 1 1 P
146 | X BAT 3 -600 300 200 R 50 50 1 1 P
147 | X ~CE 4 600 -100 200 L 50 50 1 1 P
148 | X EN2 5 600 200 200 L 50 50 1 1 P
149 | X EN1 6 600 100 200 L 50 50 1 1 P
150 | X ~PGOOD 7 600 -500 200 L 50 50 1 1 P
151 | X VSS 8 -600 -400 200 R 50 50 1 1 P
152 | X ~CHG 9 600 -400 200 L 50 50 1 1 P
153 | X OUT 10 600 500 200 L 50 50 1 1 P
154 | X OUT 11 600 600 200 L 50 50 1 1 P
155 | X ILIM 12 -600 -200 200 R 50 50 1 1 P
156 | X IN 13 -600 600 200 R 50 50 1 1 P
157 | X TMR 14 -600 0 200 R 50 50 1 1 P
158 | X SYSOFF 15 600 0 200 L 50 50 1 1 P
159 | X ISET 16 -600 -100 200 R 50 50 1 1 P
160 | X PAD 17 -600 -500 200 R 50 50 1 1 P
161 | ENDDRAW
162 | ENDDEF
163 | #
164 | # Battery_Cell
165 | #
166 | DEF Battery_Cell BT 0 0 N N 1 F N
167 | F0 "BT" 100 100 50 H V L CNN
168 | F1 "Battery_Cell" 100 0 50 H V L CNN
169 | F2 "" 0 60 50 V I C CNN
170 | F3 "" 0 60 50 V I C CNN
171 | DRAW
172 | S -90 70 90 60 0 1 0 F
173 | S -62 47 58 27 0 1 0 F
174 | P 2 0 1 0 0 30 0 0 N
175 | P 2 0 1 0 0 70 0 100 N
176 | P 2 0 1 10 20 135 60 135 N
177 | P 2 0 1 10 40 155 40 115 N
178 | X + 1 0 200 100 D 50 50 1 1 P
179 | X - 2 0 -100 100 U 50 50 1 1 P
180 | ENDDRAW
181 | ENDDEF
182 | #
183 | # CONN_01X02
184 | #
185 | DEF CONN_01X02 J 0 40 Y N 1 F N
186 | F0 "J" 0 150 50 H V C CNN
187 | F1 "CONN_01X02" 100 0 50 V V C CNN
188 | F2 "" 0 0 50 H I C CNN
189 | F3 "" 0 0 50 H I C CNN
190 | $FPLIST
191 | Pin_Header_Straight_1X*
192 | Pin_Header_Angled_1X*
193 | Socket_Strip_Straight_1X*
194 | Socket_Strip_Angled_1X*
195 | $ENDFPLIST
196 | DRAW
197 | S -50 -45 10 -55 0 1 0 N
198 | S -50 55 10 45 0 1 0 N
199 | S -50 100 50 -100 0 1 0 N
200 | X P1 1 -200 50 150 R 50 50 1 1 P
201 | X P2 2 -200 -50 150 R 50 50 1 1 P
202 | ENDDRAW
203 | ENDDEF
204 | #
205 | # GND
206 | #
207 | DEF GND #PWR 0 0 Y Y 1 F P
208 | F0 "#PWR" 0 -250 50 H I C CNN
209 | F1 "GND" 0 -150 50 H V C CNN
210 | F2 "" 0 0 50 H I C CNN
211 | F3 "" 0 0 50 H I C CNN
212 | DRAW
213 | P 6 0 1 0 0 0 0 -50 50 -50 0 -100 -50 -50 0 -50 N
214 | X GND 1 0 0 0 D 50 50 1 1 W N
215 | ENDDRAW
216 | ENDDEF
217 | #
218 | # Jumper_Dual
219 | #
220 | DEF Jumper_Dual J 0 40 Y Y 1 F N
221 | F0 "J" 100 -100 60 H V C CNN
222 | F1 "Jumper_Dual" 0 150 60 H V C CNN
223 | F2 "" 0 0 60 H V C CNN
224 | F3 "" 0 0 60 H V C CNN
225 | DRAW
226 | S -100 50 -50 -50 0 1 0 N
227 | S -25 50 25 -50 0 1 0 N
228 | S 50 50 100 -50 0 1 0 N
229 | X ~ 1 -200 0 100 R 50 50 1 1 P
230 | X ~ 2 0 -100 50 U 50 50 1 1 P
231 | X ~ 3 200 0 100 L 50 50 1 1 P
232 | ENDDRAW
233 | ENDDEF
234 | #
235 | # LCD_CAP_TOUCH
236 | #
237 | DEF LCD_CAP_TOUCH U 0 40 Y Y 1 F N
238 | F0 "U" 0 250 60 H V C CNN
239 | F1 "LCD_CAP_TOUCH" 0 -350 60 H V C CNN
240 | F2 "" 0 0 60 H I C CNN
241 | F3 "" 0 0 60 H I C CNN
242 | DRAW
243 | S -300 200 300 -300 0 1 0 N
244 | X GND 1 500 -200 200 L 50 50 1 1 I
245 | X SDA 2 -500 -200 200 R 50 50 1 1 I
246 | X SCL 3 -500 -100 200 R 50 50 1 1 I
247 | X ~RESET 4 -500 0 200 R 50 50 1 1 I
248 | X ~INT 5 -500 100 200 R 50 50 1 1 I
249 | X VDD 6 500 100 200 L 50 50 1 1 I
250 | ENDDRAW
251 | ENDDEF
252 | #
253 | # MCP4661-ML
254 | #
255 | DEF MCP4661-ML U 0 40 Y Y 1 F N
256 | F0 "U" 0 -650 60 H V C CNN
257 | F1 "MCP4661-ML" 0 650 60 H V C CNN
258 | F2 "" 1900 -500 60 H I C CNN
259 | F3 "" 1900 -500 60 H I C CNN
260 | DRAW
261 | S -400 600 400 -600 0 1 0 N
262 | X SCL 1 -600 0 200 R 50 50 1 1 P
263 | X SDA 2 -600 -100 200 R 50 50 1 1 P
264 | X VSS 3 -600 -400 200 R 50 50 1 1 P
265 | X VSS 4 -600 -500 200 R 50 50 1 1 P
266 | X P1B 5 600 -100 200 L 50 50 1 1 P
267 | X P1W 6 600 0 200 L 50 50 1 1 P
268 | X P1A 7 600 100 200 L 50 50 1 1 P
269 | X P0A 8 600 500 200 L 50 50 1 1 P
270 | X P0W 9 600 400 200 L 50 50 1 1 P
271 | X P0B 10 600 300 200 L 50 50 1 1 P
272 | X NC 11 600 -400 200 L 50 50 1 1 P
273 | X ~WP 12 -600 -200 200 R 50 50 1 1 P
274 | X A2 13 -600 300 200 R 50 50 1 1 P
275 | X A1 14 -600 200 200 R 50 50 1 1 P
276 | X VDD 15 -600 500 200 R 50 50 1 1 P
277 | X HVC/A0 16 -600 100 200 R 50 50 1 1 P
278 | X PAD 17 600 -500 200 L 50 50 1 1 P
279 | ENDDRAW
280 | ENDDEF
281 | #
282 | # PAD_SMD
283 | #
284 | DEF PAD_SMD P 0 40 Y N 1 F N
285 | F0 "P" 0 -150 60 H V C CNN
286 | F1 "PAD_SMD" 0 150 60 H V C CNN
287 | F2 "" 0 -250 60 H V C CNN
288 | F3 "" 0 -150 60 H V C CNN
289 | DRAW
290 | S -50 50 50 -50 0 1 0 N
291 | X PAD 1 -200 0 150 R 50 50 1 1 I
292 | ENDDRAW
293 | ENDDEF
294 | #
295 | # PWR_FLAG
296 | #
297 | DEF PWR_FLAG #FLG 0 0 N N 1 F P
298 | F0 "#FLG" 0 75 50 H I C CNN
299 | F1 "PWR_FLAG" 0 150 50 H V C CNN
300 | F2 "" 0 0 50 H I C CNN
301 | F3 "" 0 0 50 H I C CNN
302 | DRAW
303 | X pwr 1 0 0 0 U 50 50 0 0 w
304 | P 6 0 1 0 0 0 0 50 -40 75 0 100 40 75 0 50 N
305 | ENDDRAW
306 | ENDDEF
307 | #
308 | # TACT
309 | #
310 | DEF TACT SW 0 40 N N 1 F N
311 | F0 "SW" 150 -75 60 H V L CNN
312 | F1 "TACT" 150 75 60 H V L CNN
313 | F2 "" 0 -25 60 H V C CNN
314 | F3 "" 0 -25 60 H V C CNN
315 | DRAW
316 | C 0 0 150 0 1 10 N
317 | P 2 0 1 10 -75 200 75 200 N
318 | P 2 0 1 10 0 25 0 50 N
319 | P 2 0 1 10 0 75 0 125 N
320 | P 2 0 1 10 0 150 0 200 N
321 | P 2 0 1 10 100 0 75 0 N
322 | P 3 0 1 10 -100 0 -75 0 75 50 N
323 | X ~ 1 -200 0 100 R 50 50 1 1 P
324 | X ~ 2 200 0 100 L 50 50 1 1 P
325 | ENDDRAW
326 | ENDDEF
327 | #
328 | # TPA6135A2
329 | #
330 | DEF TPA6135A2 U 0 40 Y Y 1 F N
331 | F0 "U" 0 -750 60 H V C CNN
332 | F1 "TPA6135A2" 0 550 60 H V C CNN
333 | F2 "" 1750 -850 60 H I C CNN
334 | F3 "" 1750 -850 60 H I C CNN
335 | DRAW
336 | S -400 500 400 -700 0 0 0 N
337 | X INL- 1 -600 200 200 R 50 50 1 1 P
338 | X INL+ 2 -600 100 200 R 50 50 1 1 P
339 | X INR+ 3 -600 300 200 R 50 50 1 1 P
340 | X INR- 4 -600 400 200 R 50 50 1 1 P
341 | X OUTR 5 600 300 200 L 50 50 1 1 P
342 | X HI-Z 6 -600 -200 200 R 50 50 1 1 P
343 | X GAIN 7 -600 -300 200 R 50 50 1 1 P
344 | X HPVSS 8 -600 -600 200 R 50 50 1 1 P
345 | X CPN 9 600 -300 200 L 50 50 1 1 P
346 | X PGND 10 600 -100 200 L 50 50 1 1 P
347 | X CPP 11 600 -400 200 L 50 50 1 1 P
348 | X HPVDD 12 -600 -500 200 R 50 50 1 1 P
349 | X EN 13 -600 -100 200 R 50 50 1 1 P
350 | X VDD 14 -600 -400 200 R 50 50 1 1 P
351 | X SGND 15 600 0 200 L 50 50 1 1 P
352 | X OUTL 16 600 200 200 L 50 50 1 1 P
353 | X PAD 17 600 -600 200 L 50 50 1 1 P
354 | ENDDRAW
355 | ENDDEF
356 | #
357 | # lcd_50pin_logic
358 | #
359 | DEF lcd_50pin_logic U 0 40 Y Y 1 F N
360 | F0 "U" 0 -1650 60 H V C CNN
361 | F1 "lcd_50pin_logic" 0 1700 60 H V C CNN
362 | F2 "" 0 900 60 H I C CNN
363 | F3 "" 0 900 60 H I C CNN
364 | DRAW
365 | T 900 -100 -1150 60 0 0 0 POWER Normal 0 C C
366 | S 500 -800 50 -1550 0 0 0 N
367 | S 500 -300 50 -800 0 0 0 N
368 | S 500 1550 50 -300 0 0 0 N
369 | P 2 0 0 0 -500 -700 -500 -200 N
370 | P 2 0 0 0 -50 1550 50 1550 N
371 | P 2 0 0 0 50 -1550 -50 -1550 N
372 | T 900 -100 100 60 0 1 0 BACKLIGHT Normal 0 C C
373 | T 900 -100 1350 60 0 1 0 BUS~SEL Normal 0 C C
374 | T 900 100 650 60 0 1 0 DATA~BUS Normal 0 C C
375 | T 900 100 -550 60 0 1 0 RGB Normal 0 C C
376 | T 900 -100 1000 60 0 1 0 RST Normal 0 C C
377 | T 900 100 -1200 60 0 1 0 SERIAL~LOGIC Normal 0 C C
378 | T 900 -100 650 60 0 1 0 TOUCH Normal 0 C C
379 | S -700 900 -50 400 0 1 0 N
380 | S -500 -700 -50 -1550 0 1 0 N
381 | S -500 400 -50 -200 0 1 0 N
382 | S -500 1100 -50 900 0 1 0 N
383 | S -500 1550 -50 1100 0 1 0 N
384 | X LEDK 1 -700 300 200 R 50 50 1 1 P
385 | X LEDA 2 -700 200 200 R 50 50 1 1 P
386 | X LEDA 3 -700 100 200 R 50 50 1 1 P
387 | X LEDA 4 -700 0 200 R 50 50 1 1 P
388 | X LEDA 5 -700 -100 200 R 50 50 1 1 P
389 | X IM0 6 -700 1500 200 R 50 50 1 1 P
390 | X IM1 7 -700 1400 200 R 50 50 1 1 P
391 | X IM2 8 -700 1300 200 R 50 50 1 1 P
392 | X IM3 9 -700 1200 200 R 50 50 1 1 P
393 | X ~RESET 10 -700 1000 200 R 50 50 1 1 P
394 | X DB12 20 700 300 200 L 50 50 1 1 P
395 | X DB2 30 700 1300 200 L 50 50 1 1 P
396 | X IOVCC 40 -700 -800 200 R 50 50 1 1 P
397 | X GND 50 -700 -1500 200 R 50 50 1 1 P
398 | X VSYNC 11 700 -700 200 L 50 50 1 1 P
399 | X DB11 21 700 400 200 L 50 50 1 1 P
400 | X DB1 31 700 1400 200 L 50 50 1 1 P
401 | X IOVCC 41 -700 -900 200 R 50 50 1 1 P
402 | X HSYNC 12 700 -600 200 L 50 50 1 1 P
403 | X DB10 22 700 500 200 L 50 50 1 1 P
404 | X DB0 32 700 1500 200 L 50 50 1 1 P
405 | X VCI 42 -700 -1000 200 R 50 50 1 1 P
406 | X DOTCLK 13 700 -500 200 L 50 50 1 1 P
407 | X DB9 23 700 600 200 L 50 50 1 1 P
408 | X SDO 33 700 -1500 200 L 50 50 1 1 P
409 | X GND 43 -700 -1200 200 R 50 50 1 1 P
410 | X DE 14 700 -400 200 L 50 50 1 1 P
411 | X DB8 24 700 700 200 L 50 50 1 1 P
412 | X SDI 34 700 -1400 200 L 50 50 1 1 P
413 | X X+(XR)/SCK 44 -900 800 200 R 50 50 1 1 P
414 | X DB17 15 700 -200 200 L 50 50 1 1 P
415 | X DB7 25 700 800 200 L 50 50 1 1 P
416 | X ~RD 35 700 -1300 200 L 50 50 1 1 P
417 | X Y+(YD)/SDA 45 -900 700 200 R 50 50 1 1 P
418 | X DB16 16 700 -100 200 L 50 50 1 1 P
419 | X DB6 26 700 900 200 L 50 50 1 1 P
420 | X ~WR_RS 36 700 -1200 200 L 50 50 1 1 P
421 | X X-(XL)/IRQ 46 -900 600 200 R 50 50 1 1 P
422 | X DB15 17 700 0 200 L 50 50 1 1 P
423 | X DB5 27 700 1000 200 L 50 50 1 1 P
424 | X RS_SCL 37 700 -1100 200 L 50 50 1 1 P
425 | X Y-(YU)/RES 47 -900 500 200 R 50 50 1 1 P
426 | X DB14 18 700 100 200 L 50 50 1 1 P
427 | X DB4 28 700 1100 200 L 50 50 1 1 P
428 | X ~CS 38 700 -1000 200 L 50 50 1 1 P
429 | X GND 48 -700 -1300 200 R 50 50 1 1 P
430 | X DB13 19 700 200 200 L 50 50 1 1 P
431 | X DB3 29 700 1200 200 L 50 50 1 1 P
432 | X TE 39 700 -900 200 L 50 50 1 1 P
433 | X GND 49 -700 -1400 200 R 50 50 1 1 P
434 | ENDDRAW
435 | ENDDEF
436 | #
437 | # pkl_C
438 | #
439 | DEF pkl_C C 0 10 N Y 1 F N
440 | F0 "C" 25 100 50 H V L CNN
441 | F1 "pkl_C" 25 -100 50 H V L CNN
442 | F2 "" 38 -150 30 H V C CNN
443 | F3 "" 0 0 60 H V C CNN
444 | $FPLIST
445 | C?
446 | C_????_*
447 | C_????
448 | SMD*_c
449 | Capacitor*
450 | $ENDFPLIST
451 | DRAW
452 | P 2 0 1 20 -80 -30 80 -30 N
453 | P 2 0 1 20 -80 30 80 30 N
454 | X ~ 1 0 100 60 D 40 40 1 1 P
455 | X ~ 2 0 -100 60 U 40 40 1 1 P
456 | ENDDRAW
457 | ENDDEF
458 | #
459 | # pkl_C_Small
460 | #
461 | DEF pkl_C_Small C 0 10 N N 1 F N
462 | F0 "C" 10 70 50 H V L CNN
463 | F1 "pkl_C_Small" 10 -80 50 H V L CNN
464 | F2 "" 0 0 60 H V C CNN
465 | F3 "" 0 0 60 H V C CNN
466 | $FPLIST
467 | C?
468 | C_????_*
469 | C_????
470 | SMD*_c
471 | Capacitor*
472 | $ENDFPLIST
473 | DRAW
474 | P 2 0 1 13 -60 -20 60 -20 N
475 | P 2 0 1 12 -60 20 60 20 N
476 | X ~ 1 0 100 75 D 40 40 1 1 P
477 | X ~ 2 0 -100 80 U 40 40 1 1 P
478 | ENDDRAW
479 | ENDDEF
480 | #
481 | # pkl_JACK_3C1S
482 | #
483 | DEF pkl_JACK_3C1S J 0 40 Y Y 1 F N
484 | F0 "J" -350 -300 50 H V C CNN
485 | F1 "pkl_JACK_3C1S" -150 350 50 H V C CNN
486 | F2 "" 0 0 50 H I C CNN
487 | F3 "" 0 0 50 H I C CNN
488 | DRAW
489 | S -450 200 -400 -100 0 1 0 F
490 | S -325 175 -275 -75 0 1 10 F
491 | S 300 -150 -400 250 0 1 10 N
492 | P 3 0 1 0 150 0 300 0 300 0 N
493 | P 3 0 1 10 300 200 -300 200 -300 175 N
494 | P 4 0 1 0 0 -100 -50 -50 -100 -100 -100 -100 N
495 | P 4 0 1 0 0 -100 300 -100 300 -100 300 -100 N
496 | P 4 0 1 0 50 -50 100 -100 150 -50 150 -50 N
497 | P 4 0 1 0 150 0 100 0 100 -100 100 -100 N
498 | P 4 0 1 10 300 100 -100 100 -150 50 -200 100 N
499 | X ~ 1 450 200 150 L 50 50 1 1 P
500 | X ~ 2 450 -100 150 L 50 50 1 1 P
501 | X ~ 3 450 100 150 L 50 50 1 1 P
502 | X ~ 4 450 0 150 L 50 50 1 1 P
503 | ENDDRAW
504 | ENDDEF
505 | #
506 | # pkl_LED
507 | #
508 | DEF pkl_LED D 0 40 Y N 1 F N
509 | F0 "D" 0 100 50 H V C CNN
510 | F1 "pkl_LED" 0 -100 50 H V C CNN
511 | F2 "" 0 0 60 H V C CNN
512 | F3 "" 0 0 60 H V C CNN
513 | $FPLIST
514 | LED-3MM
515 | LED-5MM
516 | LED-10MM
517 | LED-0603
518 | LED-0805
519 | LED-1206
520 | LEDV
521 | $ENDFPLIST
522 | DRAW
523 | P 2 0 1 0 50 50 50 -50 N
524 | P 3 0 1 0 -50 50 50 0 -50 -50 F
525 | P 3 0 1 0 65 -40 110 -80 105 -55 N
526 | P 3 0 1 0 80 -25 125 -65 120 -40 N
527 | X A A -200 0 150 R 40 40 1 1 P
528 | X C C 200 0 150 L 40 40 1 1 P
529 | ENDDRAW
530 | ENDDEF
531 | #
532 | # pkl_Micro_SD
533 | #
534 | DEF pkl_Micro_SD CON 0 40 Y Y 1 F N
535 | F0 "CON" -650 550 50 H V C CNN
536 | F1 "pkl_Micro_SD" 600 -550 50 H V C CNN
537 | F2 "" 150 300 50 H V C CNN
538 | F3 "" 0 0 60 H V C CNN
539 | $FPLIST
540 | Micro_SD_Card_Receptacle
541 | $ENDFPLIST
542 | DRAW
543 | S -350 -375 -250 -425 0 1 0 F
544 | S -350 -275 -250 -325 0 1 0 F
545 | S -350 -175 -250 -225 0 1 0 F
546 | S -350 -75 -250 -125 0 1 0 F
547 | S -350 25 -250 -25 0 1 0 F
548 | S -350 125 -250 75 0 1 0 F
549 | S -350 225 -250 175 0 1 0 F
550 | S -350 325 -250 275 0 1 0 F
551 | P 6 0 1 0 650 450 650 500 -800 500 -800 -500 650 -500 650 -450 N
552 | P 11 0 1 0 -400 350 -100 350 0 450 150 450 150 400 250 400 300 450 800 450 800 -450 -400 -450 -400 350 f
553 | X DAT2 1 -900 300 100 R 50 50 1 1 I
554 | X CD/DAT3 2 -900 200 100 R 50 50 1 1 I
555 | X CMD 3 -900 100 100 R 50 50 1 1 I
556 | X VDD 4 -900 0 100 R 50 50 1 1 I
557 | X CLK 5 -900 -100 100 R 50 50 1 1 I
558 | X VSS 6 -900 -200 100 R 50 50 1 1 I
559 | X DAT0 7 -900 -300 100 R 50 50 1 1 I
560 | X DAT1 8 -900 -400 100 R 50 50 1 1 I
561 | X CARD_DETECT 9 900 200 100 L 50 50 1 1 I
562 | X CARD_DETECT_GND 10 900 100 100 L 50 50 1 1 I
563 | X SHELL 11 900 -200 100 L 50 50 1 1 I
564 | ENDDRAW
565 | ENDDEF
566 | #
567 | # pkl_Q_NMOS_BD_GSD
568 | #
569 | DEF pkl_Q_NMOS_BD_GSD Q 0 0 Y N 1 F N
570 | F0 "Q" 200 50 50 H V L CNN
571 | F1 "pkl_Q_NMOS_BD_GSD" 200 -50 50 H V L CNN
572 | F2 "" 200 100 29 H V C CNN
573 | F3 "" 0 0 60 H V C CNN
574 | $FPLIST
575 | LFPAK*
576 | SO*
577 | SOT669*
578 | $ENDFPLIST
579 | DRAW
580 | C 50 0 111 0 1 10 N
581 | C 100 -70 4 0 1 0 N
582 | C 100 70 4 0 1 0 N
583 | P 2 0 1 0 30 -70 100 -70 N
584 | P 2 0 1 10 30 -50 30 -90 N
585 | P 2 0 1 0 30 0 100 0 N
586 | P 2 0 1 10 30 20 30 -20 N
587 | P 2 0 1 0 30 70 100 70 N
588 | P 2 0 1 10 30 90 30 50 N
589 | P 2 0 1 0 100 -70 100 -100 N
590 | P 2 0 1 0 100 -70 100 0 N
591 | P 2 0 1 0 100 100 100 70 N
592 | P 2 0 1 0 108 12 132 12 N
593 | P 3 0 1 10 10 75 10 -75 10 -75 N
594 | P 4 0 1 0 40 0 80 15 80 -15 40 0 F
595 | P 4 0 1 0 100 -70 120 -70 120 70 100 70 N
596 | P 4 0 1 0 110 -16 130 -16 120 14 110 -16 F
597 | X G 1 -200 0 210 R 50 50 1 1 I
598 | X S 2 100 -200 100 U 50 50 1 1 E
599 | X D 3 100 200 100 D 50 50 1 1 C
600 | ENDDRAW
601 | ENDDEF
602 | #
603 | # pkl_R4_Small
604 | #
605 | DEF pkl_R4_Small R 0 10 N N 4 F N
606 | F0 "R" 30 20 50 H V L CNN
607 | F1 "pkl_R4_Small" 30 -40 50 H V L CNN
608 | F2 "" 0 0 60 H V C CNN
609 | F3 "" 0 0 60 H V C CNN
610 | $FPLIST
611 | Resistor_*
612 | R_*
613 | $ENDFPLIST
614 | DRAW
615 | S -30 70 30 -70 0 1 8 N
616 | X ~ 1 0 100 30 D 40 40 1 1 P
617 | X ~ 2 0 -100 30 U 40 40 1 1 P
618 | X ~ 3 0 100 30 D 40 40 2 1 P
619 | X ~ 4 0 -100 30 U 40 40 2 1 P
620 | X ~ 5 0 100 30 D 40 40 3 1 P
621 | X ~ 6 0 -100 30 U 40 40 3 1 P
622 | X ~ 7 0 100 30 D 40 40 4 1 P
623 | X ~ 8 0 -100 30 U 40 40 4 1 P
624 | ENDDRAW
625 | ENDDEF
626 | #
627 | # pkl_R_Small
628 | #
629 | DEF pkl_R_Small R 0 10 N N 1 F N
630 | F0 "R" 30 20 50 H V L CNN
631 | F1 "pkl_R_Small" 30 -40 50 H V L CNN
632 | F2 "" 0 0 60 H V C CNN
633 | F3 "" 0 0 60 H V C CNN
634 | $FPLIST
635 | Resistor_*
636 | R_*
637 | $ENDFPLIST
638 | DRAW
639 | S -30 70 30 -70 0 1 8 N
640 | X ~ 1 0 100 30 D 40 40 1 1 P
641 | X ~ 2 0 -100 30 U 40 40 1 1 P
642 | ENDDRAW
643 | ENDDEF
644 | #
645 | # pkl_SWITCH-SPDT
646 | #
647 | DEF pkl_SWITCH-SPDT SW 0 40 N N 1 F N
648 | F0 "SW" 150 -75 60 H V L CNN
649 | F1 "pkl_SWITCH-SPDT" 150 75 60 H V L CNN
650 | F2 "" 0 -25 60 H V C CNN
651 | F3 "" 0 -25 60 H V C CNN
652 | DRAW
653 | C -100 0 10 0 0 0 N
654 | C 0 -100 10 0 0 0 N
655 | C 0 100 10 0 0 0 N
656 | P 2 0 0 0 -100 0 0 75 N
657 | C 0 0 150 0 1 10 N
658 | X ~ 1 0 200 100 D 50 50 1 1 P
659 | X ~ 2 -200 0 100 R 50 50 1 1 P
660 | X ~ 3 0 -200 100 U 50 50 1 1 P
661 | ENDDRAW
662 | ENDDEF
663 | #
664 | # pkl_jumper
665 | #
666 | DEF pkl_jumper J 0 40 Y Y 1 F N
667 | F0 "J" 100 -100 60 H V C CNN
668 | F1 "pkl_jumper" 0 150 60 H V C CNN
669 | F2 "" 0 0 60 H V C CNN
670 | F3 "" 0 0 60 H V C CNN
671 | DRAW
672 | S -50 30 -10 -30 0 1 0 N
673 | S 10 30 50 -30 0 1 0 N
674 | X ~ 1 -100 0 50 R 50 50 1 1 P
675 | X ~ 2 100 0 50 L 50 50 1 1 P
676 | ENDDRAW
677 | ENDDEF
678 | #
679 | #End Library
680 |
--------------------------------------------------------------------------------
/hardware/V0.1/1bitsy-1up.pro:
--------------------------------------------------------------------------------
1 | update=Fri 23 Jun 2017 02:45:08 PM PDT
2 | version=1
3 | last_client=kicad
4 | [pcbnew]
5 | version=1
6 | LastNetListRead=
7 | UseCmpFile=1
8 | PadDrill=0.600000000000
9 | PadDrillOvalY=0.600000000000
10 | PadSizeH=1.500000000000
11 | PadSizeV=1.500000000000
12 | PcbTextSizeV=1.500000000000
13 | PcbTextSizeH=1.500000000000
14 | PcbTextThickness=0.300000000000
15 | ModuleTextSizeV=1.000000000000
16 | ModuleTextSizeH=1.000000000000
17 | ModuleTextSizeThickness=0.150000000000
18 | SolderMaskClearance=0.000000000000
19 | SolderMaskMinWidth=0.000000000000
20 | DrawSegmentWidth=0.200000000000
21 | BoardOutlineThickness=0.100000000000
22 | ModuleOutlineThickness=0.150000000000
23 | [cvpcb]
24 | version=1
25 | NetIExt=net
26 | [general]
27 | version=1
28 | [eeschema]
29 | version=1
30 | LibDir=../lib/pkl;../lib/1bitsy/kicad
31 | [eeschema/libraries]
32 | LibName1=power
33 | LibName2=device
34 | LibName3=transistors
35 | LibName4=conn
36 | LibName5=linear
37 | LibName6=regul
38 | LibName7=74xx
39 | LibName8=cmos4000
40 | LibName9=adc-dac
41 | LibName10=memory
42 | LibName11=xilinx
43 | LibName12=microcontrollers
44 | LibName13=dsp
45 | LibName14=microchip
46 | LibName15=analog_switches
47 | LibName16=motorola
48 | LibName17=texas
49 | LibName18=intel
50 | LibName19=audio
51 | LibName20=interface
52 | LibName21=digital-audio
53 | LibName22=philips
54 | LibName23=display
55 | LibName24=cypress
56 | LibName25=siliconi
57 | LibName26=opto
58 | LibName27=atmel
59 | LibName28=contrib
60 | LibName29=valves
61 | LibName30=pkl_conn
62 | LibName31=pkl_device
63 | LibName32=pkl_ftdi
64 | LibName33=pkl_linear
65 | LibName34=pkl_logos
66 | LibName35=pkl_maxim
67 | LibName36=pkl_misc
68 | LibName37=pkl_molex
69 | LibName38=pkl_power
70 | LibName39=pkl_sensor
71 | LibName40=pkl_tag_connect
72 | LibName41=pkl_texas
73 | LibName42=1bitsy
74 | LibName43=pkl_lattice
75 | LibName44=pkl_memory
76 | [schematic_editor]
77 | version=1
78 | PageLayoutDescrFile=
79 | PlotDirectoryName=
80 | SubpartIdSeparator=0
81 | SubpartFirstId=65
82 | NetFmtName=
83 | SpiceForceRefPrefix=0
84 | SpiceUseNetNumbers=0
85 | LabSize=60
86 |
--------------------------------------------------------------------------------
/hardware/contrib/1up-mini/1up-mini-cache.lib:
--------------------------------------------------------------------------------
1 | EESchema-LIBRARY Version 2.3
2 | #encoding utf-8
3 | #
4 | # +3V3
5 | #
6 | DEF +3V3 #PWR 0 0 Y Y 1 F P
7 | F0 "#PWR" 0 -150 50 H I C CNN
8 | F1 "+3V3" 0 140 50 H V C CNN
9 | F2 "" 0 0 50 H V C CNN
10 | F3 "" 0 0 50 H V C CNN
11 | ALIAS +3.3V
12 | DRAW
13 | P 2 0 1 0 -30 50 0 100 N
14 | P 2 0 1 0 0 0 0 100 N
15 | P 2 0 1 0 0 100 30 50 N
16 | X +3V3 1 0 0 0 U 50 50 1 1 W N
17 | ENDDRAW
18 | ENDDEF
19 | #
20 | # +5V
21 | #
22 | DEF +5V #PWR 0 0 Y Y 1 F P
23 | F0 "#PWR" 0 -150 50 H I C CNN
24 | F1 "+5V" 0 140 50 H V C CNN
25 | F2 "" 0 0 50 H V C CNN
26 | F3 "" 0 0 50 H V C CNN
27 | DRAW
28 | P 2 0 1 0 -30 50 0 100 N
29 | P 2 0 1 0 0 0 0 100 N
30 | P 2 0 1 0 0 100 30 50 N
31 | X +5V 1 0 0 0 U 50 50 1 1 W N
32 | ENDDRAW
33 | ENDDEF
34 | #
35 | # +BATT
36 | #
37 | DEF +BATT #PWR 0 0 Y Y 1 F P
38 | F0 "#PWR" 0 -150 50 H I C CNN
39 | F1 "+BATT" 0 140 50 H V C CNN
40 | F2 "" 0 0 50 H V C CNN
41 | F3 "" 0 0 50 H V C CNN
42 | DRAW
43 | P 2 0 1 0 -30 50 0 100 N
44 | P 2 0 1 0 0 0 0 100 N
45 | P 2 0 1 0 0 100 30 50 N
46 | X +BATT 1 0 0 0 U 50 50 1 1 W N
47 | ENDDRAW
48 | ENDDEF
49 | #
50 | # 1bitsy-complete-concise
51 | #
52 | DEF 1bitsy-complete-concise U 0 40 Y Y 1 F N
53 | F0 "U" 0 100 60 H V C CNN
54 | F1 "1bitsy-complete-concise" 0 0 60 H V C CNN
55 | F2 "" 0 100 60 H I C CNN
56 | F3 "" 0 100 60 H I C CNN
57 | DRAW
58 | S -2400 1300 2400 -1300 0 1 0 N
59 | X GND 1 -2600 1200 200 R 50 50 1 1 P
60 | X PC10/SPI3SCK/I2S3CK/USART3&4_TX/SDIOD2 2 -2600 1100 200 R 50 50 1 1 P
61 | X PC11/ADCEXTI11/I2S3EXTSD/SPI3MISO/USART3&4_RX/SDIOD3 3 -2600 1000 200 R 50 50 1 1 P
62 | X PC12/SPI3MOSI/I2S3SD/USART3CK/UART5TX/SDIOCK 4 -2600 900 200 R 50 50 1 1 P
63 | X PD2/T2ETR/UART5RX/SDIOCMD 5 -2600 800 200 R 50 50 1 1 P
64 | X PB4/~JTRST~/T3C1/SPI1&3_MISO/I2S3EXTSD 6 -2600 700 200 R 50 50 1 1 P
65 | X PB5/T3C2/I2C1SMBA/SPI1&3_MOSI/I2S3SD/CAN2RX/ULPID7 7 -2600 600 200 R 50 50 1 1 P
66 | X PB6/T4C1/I2C1SCL/USART1TX/CAN2TX 8 -2600 500 200 R 50 50 1 1 P
67 | X PB7/T4C2/I2C1SDA/USART1RX 9 -2600 400 200 R 50 50 1 1 P
68 | X PB8/T4C3/TI0C1/I2C1SCL/CAN2RX/SDIOD4 10 -2600 300 200 R 50 50 1 1 P
69 | X PB11/T2C4/I2C2SDA/USART3RX/ULPID4 20 2600 200 200 L 50 50 1 1 P
70 | X VIN 30 2600 1200 200 L 50 50 1 1 P
71 | X PC5/ADC15 40 2600 -400 200 L 50 50 1 1 P
72 | X PB9/T4C4/T1C1/I2C1SDA/SPI2NSS/I2S2WS/CAN2TX/SDIOD5 11 -2600 200 200 R 50 50 1 1 P
73 | X PB12/T1BK/I2C2SMBA/SPI2NSS/I2S2WS/USART3CK/CAN2RX/ULPID5/HSID 21 2600 300 200 L 50 50 1 1 P
74 | X PA0-WKUP/ADC0/T2C1ETR/T5C1/T8ETR/USART2CTS/UART4TX 31 -2600 -400 200 R 50 50 1 1 P
75 | X LED|PA8-MCO1/T1C1/I2C3SCL/USART1CK/OTGFSSOF 41 -2600 -1000 200 R 50 50 1 1 P
76 | X PC2/ADC12/SPI2MISO/I2S2EXTSD/ULPIDIR 12 -2600 100 200 R 50 50 1 1 P
77 | X PB13/T1C1N/SPI2SCK/12S2CK/USART3CTS/CAN2TX/ULPID6 22 2600 400 200 L 50 50 1 1 P
78 | X PA1/ADC1/T2C2/T5C2/USART2RTS/UART4RX 32 -2600 -500 200 R 50 50 1 1 P
79 | X PC13 42 -2600 -1100 200 R 50 50 1 1 P
80 | X PC3/ADC13/SPI2MOSI/I2S2SD/ULPINXT 13 -2600 0 200 R 50 50 1 1 P
81 | X PB14/T1&8C2N/SPI2MISO/I2S2EXTSD/USART3RTS/T12C1/HSDM 23 2600 500 200 L 50 50 1 1 P
82 | X PA2/ADC2/T2C3/T5C3/T9C1/USART2TX 33 -2600 -600 200 R 50 50 1 1 P
83 | X PC0/ADC10/ULPISTP 43 -2600 -1200 200 R 50 50 1 1 P
84 | X VBAT 14 -2600 -100 200 R 50 50 1 1 P
85 | X PB15/T1&8C3N/SPI2MOSI/I2S2SD/T12C2/HSDP 24 2600 600 200 L 50 50 1 1 P
86 | X PA3/ADC3/T2C4/T5C4/T9C2/USART2RX/ULPID0 34 -2600 -700 200 R 50 50 1 1 P
87 | X PB2 44 2600 -1000 200 L 50 50 1 1 P
88 | X +3V3 15 -2600 -200 200 R 50 50 1 1 P
89 | X PC6/T3&8C1/I2S2MCK/USART6TX/SDIOD6 25 2600 700 200 L 50 50 1 1 P
90 | X PA4/ADC4/DAC1/SPI1NSS/SPI3NSS/I2S3WS/USART2CK 35 -2600 -800 200 R 50 50 1 1 P
91 | X GND 16 2600 -200 200 L 50 50 1 1 P
92 | X PC7/T3&8C2/I2S3MCK/USART6RX/SDIOD7 26 2600 800 200 L 50 50 1 1 P
93 | X PA5/ADC5/DAC2/T2C1ETR/T8C1N/SPI1SCK/ULPICK 36 2600 -800 200 L 50 50 1 1 P
94 | X PB0/ADC8/T1C2N/T3C3/T8C2N/ULPID1 17 2600 -100 200 L 50 50 1 1 P
95 | X PC8/T3&8C3/USART6CK/SDIOD0 27 2600 900 200 L 50 50 1 1 P
96 | X PA6/ADC6/T1BK/T3C1/T8BK/SPI1MISO/T13C1 37 2600 -700 200 L 50 50 1 1 P
97 | X PB1/ADC9/T1C3N/T3C4/T8C3N 18 2600 0 200 L 50 50 1 1 P
98 | X PC9-MCO2/DACEXTI9/T3&8C4/I2C3SDA/I2S2CHIN/SDIOD1 28 2600 1000 200 L 50 50 1 1 P
99 | X PA7/ADC7/T1C1N/T3C2/T8C1N/SPI1MOSI/T12C2 38 2600 -600 200 L 50 50 1 1 P
100 | X PB10/T2C3/I2C2SCL/SPI2SCK/I2S2CK/USART3TX/ULPID3 19 2600 100 200 L 50 50 1 1 P
101 | X +3V3 29 2600 1100 200 L 50 50 1 1 P
102 | X PC4/ADC14 39 2600 -500 200 L 50 50 1 1 P
103 | ENDDRAW
104 | ENDDEF
105 | #
106 | # 74HC165
107 | #
108 | DEF 74HC165 U 0 40 Y Y 1 F N
109 | F0 "U" 0 -800 60 H V C CNN
110 | F1 "74HC165" 0 750 60 H V C CNN
111 | F2 "" 2190 -1220 60 H I C CNN
112 | F3 "" 2190 -1220 60 H I C CNN
113 | DRAW
114 | S -400 700 400 -700 0 1 0 N
115 | X SH/~LD 1 -600 -600 200 R 50 50 1 1 P
116 | X CLK 2 -600 -400 200 R 50 50 1 1 P
117 | X D4 3 -600 100 200 R 50 50 1 1 P
118 | X D5 4 -600 0 200 R 50 50 1 1 P
119 | X D6 5 -600 -100 200 R 50 50 1 1 P
120 | X D7 6 -600 -200 200 R 50 50 1 1 P
121 | X ~QH 7 600 -400 200 L 50 50 1 1 P
122 | X GND 8 600 -650 200 L 50 50 1 1 P
123 | X QH 9 600 -200 200 L 50 50 1 1 P
124 | X SER 10 -600 600 200 R 50 50 1 1 P
125 | X D0 11 -600 500 200 R 50 50 1 1 P
126 | X D1 12 -600 400 200 R 50 50 1 1 P
127 | X D2 13 -600 300 200 R 50 50 1 1 P
128 | X D3 14 -600 200 200 R 50 50 1 1 P
129 | X CLK_INH 15 -600 -500 200 R 50 50 1 1 P
130 | X VCC 16 600 650 200 L 50 50 1 1 P
131 | ENDDRAW
132 | ENDDEF
133 | #
134 | # BQ21040
135 | #
136 | DEF BQ21040 U 0 40 Y Y 1 F N
137 | F0 "U" 0 -300 60 H V C CNN
138 | F1 "BQ21040" 0 300 60 H V C CNN
139 | F2 "" 2150 -1050 60 H I C CNN
140 | F3 "" 2150 -1050 60 H I C CNN
141 | F4 "ANY" 0 0 60 H I C CNN "Source"
142 | DRAW
143 | S -400 250 400 -250 0 0 0 N
144 | X TS 1 -600 50 200 R 50 50 1 1 P
145 | X OUT 2 600 150 200 L 50 50 1 1 P
146 | X ~CHG 3 600 -150 200 L 50 50 1 1 P
147 | X ISET 4 -600 -50 200 R 50 50 1 1 P
148 | X GND 5 -600 -150 200 R 50 50 1 1 P
149 | X VIN 6 -600 150 200 R 50 50 1 1 P
150 | ENDDRAW
151 | ENDDEF
152 | #
153 | # CONN_01X01
154 | #
155 | DEF CONN_01X01 P 0 40 Y N 1 F N
156 | F0 "P" 0 100 50 H V C CNN
157 | F1 "CONN_01X01" 100 0 50 V V C CNN
158 | F2 "" 0 0 50 H V C CNN
159 | F3 "" 0 0 50 H V C CNN
160 | $FPLIST
161 | Pin_Header_Straight_1X01
162 | Pin_Header_Angled_1X01
163 | Socket_Strip_Straight_1X01
164 | Socket_Strip_Angled_1X01
165 | $ENDFPLIST
166 | DRAW
167 | S -50 5 10 -5 0 1 0 N
168 | S -50 50 50 -50 0 1 0 N
169 | X P1 1 -200 0 150 R 50 50 1 1 P
170 | ENDDRAW
171 | ENDDEF
172 | #
173 | # GND
174 | #
175 | DEF GND #PWR 0 0 Y Y 1 F P
176 | F0 "#PWR" 0 -250 50 H I C CNN
177 | F1 "GND" 0 -150 50 H V C CNN
178 | F2 "" 0 0 50 H V C CNN
179 | F3 "" 0 0 50 H V C CNN
180 | DRAW
181 | P 6 0 1 0 0 0 0 -50 50 -50 0 -100 -50 -50 0 -50 N
182 | X GND 1 0 0 0 D 50 50 1 1 W N
183 | ENDDRAW
184 | ENDDEF
185 | #
186 | # LCD_CAP_TOUCH
187 | #
188 | DEF LCD_CAP_TOUCH U 0 40 Y Y 1 F N
189 | F0 "U" 0 250 60 H V C CNN
190 | F1 "LCD_CAP_TOUCH" 0 -350 60 H V C CNN
191 | F2 "" 0 0 60 H I C CNN
192 | F3 "" 0 0 60 H I C CNN
193 | DRAW
194 | S -300 200 300 -300 0 1 0 N
195 | X GND 1 500 -200 200 L 50 50 1 1 I
196 | X SDA 2 -500 -200 200 R 50 50 1 1 I
197 | X SCL 3 -500 -100 200 R 50 50 1 1 I
198 | X ~RESET 4 -500 0 200 R 50 50 1 1 I
199 | X ~INT 5 -500 100 200 R 50 50 1 1 I
200 | X VDD 6 500 100 200 L 50 50 1 1 I
201 | ENDDRAW
202 | ENDDEF
203 | #
204 | # MCP4661-ST
205 | #
206 | DEF MCP4661-ST U 0 40 Y Y 1 F N
207 | F0 "U" 0 -550 60 H V C CNN
208 | F1 "MCP4661-ST" 0 650 60 H V C CNN
209 | F2 "" 1900 -500 60 H I C CNN
210 | F3 "" 1900 -500 60 H I C CNN
211 | DRAW
212 | S -400 600 400 -500 0 1 0 N
213 | X HVC/A0 1 -600 100 200 R 50 50 1 1 P
214 | X SCL 2 -600 0 200 R 50 50 1 1 P
215 | X SDA 3 -600 -100 200 R 50 50 1 1 P
216 | X VSS 4 -600 -400 200 R 50 50 1 1 P
217 | X P1B 5 600 -100 200 L 50 50 1 1 P
218 | X P1W 6 600 0 200 L 50 50 1 1 P
219 | X P1A 7 600 100 200 L 50 50 1 1 P
220 | X P0A 8 600 500 200 L 50 50 1 1 P
221 | X P0W 9 600 400 200 L 50 50 1 1 P
222 | X P0B 10 600 300 200 L 50 50 1 1 P
223 | X ~WP 11 -600 -200 200 R 50 50 1 1 P
224 | X A2 12 -600 300 200 R 50 50 1 1 P
225 | X A1 13 -600 200 200 R 50 50 1 1 P
226 | X VDD 14 -600 500 200 R 50 50 1 1 P
227 | ENDDRAW
228 | ENDDEF
229 | #
230 | # PAD_SMD
231 | #
232 | DEF PAD_SMD P 0 40 Y N 1 F N
233 | F0 "P" 0 -150 60 H V C CNN
234 | F1 "PAD_SMD" 0 150 60 H V C CNN
235 | F2 "" 0 -250 60 H V C CNN
236 | F3 "" 0 -150 60 H V C CNN
237 | DRAW
238 | S -50 50 50 -50 0 1 0 N
239 | X PAD 1 -200 0 150 R 50 50 1 1 I
240 | ENDDRAW
241 | ENDDEF
242 | #
243 | # PWR_FLAG
244 | #
245 | DEF PWR_FLAG #FLG 0 0 N N 1 F P
246 | F0 "#FLG" 0 95 50 H I C CNN
247 | F1 "PWR_FLAG" 0 180 50 H V C CNN
248 | F2 "" 0 0 50 H V C CNN
249 | F3 "" 0 0 50 H V C CNN
250 | DRAW
251 | X pwr 1 0 0 0 U 50 50 0 0 w
252 | P 6 0 1 0 0 0 0 50 -75 100 0 150 75 100 0 50 N
253 | ENDDRAW
254 | ENDDEF
255 | #
256 | # TACT
257 | #
258 | DEF TACT SW 0 40 N N 1 F N
259 | F0 "SW" 150 -75 60 H V L CNN
260 | F1 "TACT" 150 75 60 H V L CNN
261 | F2 "" 0 -25 60 H V C CNN
262 | F3 "" 0 -25 60 H V C CNN
263 | DRAW
264 | C 0 0 150 0 1 10 N
265 | P 2 0 1 10 -75 200 75 200 N
266 | P 2 0 1 10 0 25 0 50 N
267 | P 2 0 1 10 0 75 0 125 N
268 | P 2 0 1 10 0 150 0 200 N
269 | P 2 0 1 10 100 0 75 0 N
270 | P 3 0 1 10 -100 0 -75 0 75 50 N
271 | X ~ 1 -200 0 100 R 50 50 1 1 P
272 | X ~ 2 200 0 100 L 50 50 1 1 P
273 | ENDDRAW
274 | ENDDEF
275 | #
276 | # TPA6139A2-PW
277 | #
278 | DEF TPA6139A2-PW U 0 40 Y Y 1 F N
279 | F0 "U" 0 -650 60 H V C CNN
280 | F1 "TPA6139A2-PW" 0 550 60 H V C CNN
281 | F2 "" 1750 -850 60 H I C CNN
282 | F3 "" 1750 -850 60 H I C CNN
283 | $FPLIST
284 | TSSOP-14
285 | $ENDFPLIST
286 | DRAW
287 | S -400 500 400 -600 0 0 0 N
288 | X INL- 1 -600 300 200 R 50 50 1 1 P
289 | X OUTL 2 600 300 200 L 50 50 1 1 P
290 | X GND 3 -600 -400 200 R 50 50 1 1 P
291 | X MUTE 4 -600 100 200 R 50 50 1 1 P
292 | X VSS 5 600 -500 200 L 50 50 1 1 P
293 | X CN 6 600 -200 200 L 50 50 1 1 P
294 | X NC 7 600 0 200 L 50 50 1 1 N
295 | X NC 8 600 100 200 L 50 50 1 1 N
296 | X CP 9 600 -300 200 L 50 50 1 1 P
297 | X VDD 10 -600 -200 200 R 50 50 1 1 P
298 | X GND 11 -600 -500 200 R 50 50 1 1 P
299 | X GAIN 12 -600 0 200 R 50 50 1 1 P
300 | X OUTR 13 600 400 200 L 50 50 1 1 P
301 | X INR- 14 -600 400 200 R 50 50 1 1 P
302 | ENDDRAW
303 | ENDDEF
304 | #
305 | # TPS2111A
306 | #
307 | DEF TPS2111A U 0 40 Y Y 1 F N
308 | F0 "U" 0 -550 60 H V C CNN
309 | F1 "TPS2111A" 0 550 60 H V C CNN
310 | F2 "" 2150 -1050 60 H I C CNN
311 | F3 "" 2150 -1050 60 H I C CNN
312 | F4 "ANY" 0 0 60 H I C CNN "Source"
313 | DRAW
314 | S -400 500 400 -500 0 0 0 N
315 | X D0 1 -600 -100 200 R 50 50 1 1 P
316 | X D1 2 -600 -200 200 R 50 50 1 1 P
317 | X VSNS 3 -600 100 200 R 50 50 1 1 P
318 | X ILIM 4 -600 0 200 R 50 50 1 1 P
319 | X GND 5 -600 -400 200 R 50 50 1 1 P
320 | X IN2 6 -600 300 200 R 50 50 1 1 P
321 | X OUT 7 600 400 200 L 50 50 1 1 P
322 | X IN1 8 -600 400 200 R 50 50 1 1 P
323 | ENDDRAW
324 | ENDDEF
325 | #
326 | # lcd_50pin_logic
327 | #
328 | DEF lcd_50pin_logic U 0 40 Y Y 1 F N
329 | F0 "U" 0 -1650 60 H V C CNN
330 | F1 "lcd_50pin_logic" 0 1700 60 H V C CNN
331 | F2 "" 0 900 60 H I C CNN
332 | F3 "" 0 900 60 H I C CNN
333 | DRAW
334 | T 900 -100 -1150 60 0 0 0 POWER Normal 0 C C
335 | S 500 -800 50 -1550 0 0 0 N
336 | S 500 -300 50 -800 0 0 0 N
337 | S 500 1550 50 -300 0 0 0 N
338 | P 2 0 0 0 -500 -700 -500 -200 N
339 | P 2 0 0 0 -50 1550 50 1550 N
340 | P 2 0 0 0 50 -1550 -50 -1550 N
341 | T 900 -100 100 60 0 1 0 BACKLIGHT Normal 0 C C
342 | T 900 -100 1350 60 0 1 0 BUS~SEL Normal 0 C C
343 | T 900 100 650 60 0 1 0 DATA~BUS Normal 0 C C
344 | T 900 100 -550 60 0 1 0 RGB Normal 0 C C
345 | T 900 -100 1000 60 0 1 0 RST Normal 0 C C
346 | T 900 100 -1200 60 0 1 0 SERIAL~LOGIC Normal 0 C C
347 | T 900 -100 650 60 0 1 0 TOUCH Normal 0 C C
348 | S -700 900 -50 400 0 1 0 N
349 | S -500 -700 -50 -1550 0 1 0 N
350 | S -500 400 -50 -200 0 1 0 N
351 | S -500 1100 -50 900 0 1 0 N
352 | S -500 1550 -50 1100 0 1 0 N
353 | X LEDK 1 -700 300 200 R 50 50 1 1 P
354 | X LEDA 2 -700 200 200 R 50 50 1 1 P
355 | X LEDA 3 -700 100 200 R 50 50 1 1 P
356 | X LEDA 4 -700 0 200 R 50 50 1 1 P
357 | X LEDA 5 -700 -100 200 R 50 50 1 1 P
358 | X IM0 6 -700 1500 200 R 50 50 1 1 P
359 | X IM1 7 -700 1400 200 R 50 50 1 1 P
360 | X IM2 8 -700 1300 200 R 50 50 1 1 P
361 | X IM3 9 -700 1200 200 R 50 50 1 1 P
362 | X ~RESET 10 -700 1000 200 R 50 50 1 1 P
363 | X DB12 20 700 300 200 L 50 50 1 1 P
364 | X DB2 30 700 1300 200 L 50 50 1 1 P
365 | X IOVCC 40 -700 -800 200 R 50 50 1 1 P
366 | X GND 50 -700 -1500 200 R 50 50 1 1 P
367 | X VSYNC 11 700 -700 200 L 50 50 1 1 P
368 | X DB11 21 700 400 200 L 50 50 1 1 P
369 | X DB1 31 700 1400 200 L 50 50 1 1 P
370 | X IOVCC 41 -700 -900 200 R 50 50 1 1 P
371 | X HSYNC 12 700 -600 200 L 50 50 1 1 P
372 | X DB10 22 700 500 200 L 50 50 1 1 P
373 | X DB0 32 700 1500 200 L 50 50 1 1 P
374 | X VCI 42 -700 -1000 200 R 50 50 1 1 P
375 | X DOTCLK 13 700 -500 200 L 50 50 1 1 P
376 | X DB9 23 700 600 200 L 50 50 1 1 P
377 | X SDO 33 700 -1500 200 L 50 50 1 1 P
378 | X GND 43 -700 -1200 200 R 50 50 1 1 P
379 | X DE 14 700 -400 200 L 50 50 1 1 P
380 | X DB8 24 700 700 200 L 50 50 1 1 P
381 | X SDI 34 700 -1400 200 L 50 50 1 1 P
382 | X X+(XR)/SCK 44 -900 800 200 R 50 50 1 1 P
383 | X DB17 15 700 -200 200 L 50 50 1 1 P
384 | X DB7 25 700 800 200 L 50 50 1 1 P
385 | X ~RD 35 700 -1300 200 L 50 50 1 1 P
386 | X Y+(YD)/SDA 45 -900 700 200 R 50 50 1 1 P
387 | X DB16 16 700 -100 200 L 50 50 1 1 P
388 | X DB6 26 700 900 200 L 50 50 1 1 P
389 | X ~WR_RS 36 700 -1200 200 L 50 50 1 1 P
390 | X X-(XL)/IRQ 46 -900 600 200 R 50 50 1 1 P
391 | X DB15 17 700 0 200 L 50 50 1 1 P
392 | X DB5 27 700 1000 200 L 50 50 1 1 P
393 | X RS_SCL 37 700 -1100 200 L 50 50 1 1 P
394 | X Y-(YU)/RES 47 -900 500 200 R 50 50 1 1 P
395 | X DB14 18 700 100 200 L 50 50 1 1 P
396 | X DB4 28 700 1100 200 L 50 50 1 1 P
397 | X ~CS 38 700 -1000 200 L 50 50 1 1 P
398 | X GND 48 -700 -1300 200 R 50 50 1 1 P
399 | X DB13 19 700 200 200 L 50 50 1 1 P
400 | X DB3 29 700 1200 200 L 50 50 1 1 P
401 | X TE 39 700 -900 200 L 50 50 1 1 P
402 | X GND 49 -700 -1400 200 R 50 50 1 1 P
403 | ENDDRAW
404 | ENDDEF
405 | #
406 | # pkl_C
407 | #
408 | DEF pkl_C C 0 10 N Y 1 F N
409 | F0 "C" 25 100 50 H V L CNN
410 | F1 "pkl_C" 25 -100 50 H V L CNN
411 | F2 "" 38 -150 30 H V C CNN
412 | F3 "" 0 0 60 H V C CNN
413 | $FPLIST
414 | C?
415 | C_????_*
416 | C_????
417 | SMD*_c
418 | Capacitor*
419 | $ENDFPLIST
420 | DRAW
421 | P 2 0 1 20 -80 -30 80 -30 N
422 | P 2 0 1 20 -80 30 80 30 N
423 | X ~ 1 0 100 60 D 40 40 1 1 P
424 | X ~ 2 0 -100 60 U 40 40 1 1 P
425 | ENDDRAW
426 | ENDDEF
427 | #
428 | # pkl_C_Small
429 | #
430 | DEF pkl_C_Small C 0 10 N N 1 F N
431 | F0 "C" 10 70 50 H V L CNN
432 | F1 "pkl_C_Small" 10 -80 50 H V L CNN
433 | F2 "" 0 0 60 H V C CNN
434 | F3 "" 0 0 60 H V C CNN
435 | $FPLIST
436 | C?
437 | C_????_*
438 | C_????
439 | SMD*_c
440 | Capacitor*
441 | $ENDFPLIST
442 | DRAW
443 | P 2 0 1 13 -60 -20 60 -20 N
444 | P 2 0 1 12 -60 20 60 20 N
445 | X ~ 1 0 100 75 D 40 40 1 1 P
446 | X ~ 2 0 -100 80 U 40 40 1 1 P
447 | ENDDRAW
448 | ENDDEF
449 | #
450 | # pkl_JACK_3C1S
451 | #
452 | DEF pkl_JACK_3C1S J 0 40 Y Y 1 F N
453 | F0 "J" -350 -300 50 H V C CNN
454 | F1 "pkl_JACK_3C1S" -150 350 50 H V C CNN
455 | F2 "" 0 0 50 H I C CNN
456 | F3 "" 0 0 50 H I C CNN
457 | DRAW
458 | S -450 200 -400 -100 0 1 0 F
459 | S -325 175 -275 -75 0 1 10 F
460 | S 300 -150 -400 250 0 1 10 N
461 | P 3 0 1 0 150 0 300 0 300 0 N
462 | P 3 0 1 10 300 200 -300 200 -300 175 N
463 | P 4 0 1 0 0 -100 -50 -50 -100 -100 -100 -100 N
464 | P 4 0 1 0 0 -100 300 -100 300 -100 300 -100 N
465 | P 4 0 1 0 50 -50 100 -100 150 -50 150 -50 N
466 | P 4 0 1 0 150 0 100 0 100 -100 100 -100 N
467 | P 4 0 1 10 300 100 -100 100 -150 50 -200 100 N
468 | X ~ 1 450 200 150 L 50 50 1 1 P
469 | X ~ 2 450 -100 150 L 50 50 1 1 P
470 | X ~ 3 450 100 150 L 50 50 1 1 P
471 | X ~ 4 450 0 150 L 50 50 1 1 P
472 | ENDDRAW
473 | ENDDEF
474 | #
475 | # pkl_LED
476 | #
477 | DEF pkl_LED D 0 40 Y N 1 F N
478 | F0 "D" 0 100 50 H V C CNN
479 | F1 "pkl_LED" 0 -100 50 H V C CNN
480 | F2 "" 0 0 60 H V C CNN
481 | F3 "" 0 0 60 H V C CNN
482 | $FPLIST
483 | LED-3MM
484 | LED-5MM
485 | LED-10MM
486 | LED-0603
487 | LED-0805
488 | LED-1206
489 | LEDV
490 | $ENDFPLIST
491 | DRAW
492 | P 2 0 1 0 50 50 50 -50 N
493 | P 3 0 1 0 -50 50 50 0 -50 -50 F
494 | P 3 0 1 0 65 -40 110 -80 105 -55 N
495 | P 3 0 1 0 80 -25 125 -65 120 -40 N
496 | X A A -200 0 150 R 40 40 1 1 P
497 | X C C 200 0 150 L 40 40 1 1 P
498 | ENDDRAW
499 | ENDDEF
500 | #
501 | # pkl_Micro_SD
502 | #
503 | DEF pkl_Micro_SD CON 0 40 Y Y 1 F N
504 | F0 "CON" -650 550 50 H V C CNN
505 | F1 "pkl_Micro_SD" 600 -550 50 H V C CNN
506 | F2 "" 150 300 50 H V C CNN
507 | F3 "" 0 0 60 H V C CNN
508 | $FPLIST
509 | Micro_SD_Card_Receptacle
510 | $ENDFPLIST
511 | DRAW
512 | S -350 -375 -250 -425 0 1 0 F
513 | S -350 -275 -250 -325 0 1 0 F
514 | S -350 -175 -250 -225 0 1 0 F
515 | S -350 -75 -250 -125 0 1 0 F
516 | S -350 25 -250 -25 0 1 0 F
517 | S -350 125 -250 75 0 1 0 F
518 | S -350 225 -250 175 0 1 0 F
519 | S -350 325 -250 275 0 1 0 F
520 | P 6 0 1 0 650 450 650 500 -800 500 -800 -500 650 -500 650 -450 N
521 | P 11 0 1 0 -400 350 -100 350 0 450 150 450 150 400 250 400 300 450 800 450 800 -450 -400 -450 -400 350 f
522 | X DAT2 1 -900 300 100 R 50 50 1 1 I
523 | X CD/DAT3 2 -900 200 100 R 50 50 1 1 I
524 | X CMD 3 -900 100 100 R 50 50 1 1 I
525 | X VDD 4 -900 0 100 R 50 50 1 1 I
526 | X CLK 5 -900 -100 100 R 50 50 1 1 I
527 | X VSS 6 -900 -200 100 R 50 50 1 1 I
528 | X DAT0 7 -900 -300 100 R 50 50 1 1 I
529 | X DAT1 8 -900 -400 100 R 50 50 1 1 I
530 | X CARD_DETECT 9 900 200 100 L 50 50 1 1 I
531 | X CARD_DETECT_GND 10 900 100 100 L 50 50 1 1 I
532 | X SHELL 11 900 -200 100 L 50 50 1 1 I
533 | ENDDRAW
534 | ENDDEF
535 | #
536 | # pkl_Q_NMOS_BD_GSD
537 | #
538 | DEF pkl_Q_NMOS_BD_GSD Q 0 0 Y N 1 F N
539 | F0 "Q" 200 50 50 H V L CNN
540 | F1 "pkl_Q_NMOS_BD_GSD" 200 -50 50 H V L CNN
541 | F2 "" 200 100 29 H V C CNN
542 | F3 "" 0 0 60 H V C CNN
543 | $FPLIST
544 | LFPAK*
545 | SO*
546 | SOT669*
547 | $ENDFPLIST
548 | DRAW
549 | C 50 0 111 0 1 10 N
550 | C 100 -70 4 0 1 0 N
551 | C 100 70 4 0 1 0 N
552 | P 2 0 1 0 30 -70 100 -70 N
553 | P 2 0 1 10 30 -50 30 -90 N
554 | P 2 0 1 0 30 0 100 0 N
555 | P 2 0 1 10 30 20 30 -20 N
556 | P 2 0 1 0 30 70 100 70 N
557 | P 2 0 1 10 30 90 30 50 N
558 | P 2 0 1 0 100 -70 100 -100 N
559 | P 2 0 1 0 100 -70 100 0 N
560 | P 2 0 1 0 100 100 100 70 N
561 | P 2 0 1 0 108 12 132 12 N
562 | P 3 0 1 10 10 75 10 -75 10 -75 N
563 | P 4 0 1 0 40 0 80 15 80 -15 40 0 F
564 | P 4 0 1 0 100 -70 120 -70 120 70 100 70 N
565 | P 4 0 1 0 110 -16 130 -16 120 14 110 -16 F
566 | X G 1 -200 0 210 R 50 50 1 1 I
567 | X S 2 100 -200 100 U 50 50 1 1 E
568 | X D 3 100 200 100 D 50 50 1 1 C
569 | ENDDRAW
570 | ENDDEF
571 | #
572 | # pkl_R4_Small
573 | #
574 | DEF pkl_R4_Small R 0 10 N N 4 F N
575 | F0 "R" 30 20 50 H V L CNN
576 | F1 "pkl_R4_Small" 30 -40 50 H V L CNN
577 | F2 "" 0 0 60 H V C CNN
578 | F3 "" 0 0 60 H V C CNN
579 | $FPLIST
580 | Resistor_*
581 | R_*
582 | $ENDFPLIST
583 | DRAW
584 | S -30 70 30 -70 0 1 8 N
585 | X ~ 1 0 100 30 D 40 40 1 1 P
586 | X ~ 2 0 -100 30 U 40 40 1 1 P
587 | X ~ 3 0 100 30 D 40 40 2 1 P
588 | X ~ 4 0 -100 30 U 40 40 2 1 P
589 | X ~ 5 0 100 30 D 40 40 3 1 P
590 | X ~ 6 0 -100 30 U 40 40 3 1 P
591 | X ~ 7 0 100 30 D 40 40 4 1 P
592 | X ~ 8 0 -100 30 U 40 40 4 1 P
593 | ENDDRAW
594 | ENDDEF
595 | #
596 | # pkl_R_Small
597 | #
598 | DEF pkl_R_Small R 0 10 N N 1 F N
599 | F0 "R" 30 20 50 H V L CNN
600 | F1 "pkl_R_Small" 30 -40 50 H V L CNN
601 | F2 "" 0 0 60 H V C CNN
602 | F3 "" 0 0 60 H V C CNN
603 | $FPLIST
604 | Resistor_*
605 | R_*
606 | $ENDFPLIST
607 | DRAW
608 | S -30 70 30 -70 0 1 8 N
609 | X ~ 1 0 100 30 D 40 40 1 1 P
610 | X ~ 2 0 -100 30 U 40 40 1 1 P
611 | ENDDRAW
612 | ENDDEF
613 | #
614 | # pkl_SWITCH-SPDT
615 | #
616 | DEF pkl_SWITCH-SPDT SW 0 40 N N 1 F N
617 | F0 "SW" 150 -75 60 H V L CNN
618 | F1 "pkl_SWITCH-SPDT" 150 75 60 H V L CNN
619 | F2 "" 0 -25 60 H V C CNN
620 | F3 "" 0 -25 60 H V C CNN
621 | DRAW
622 | C -100 0 10 0 0 0 N
623 | C 0 -100 10 0 0 0 N
624 | C 0 100 10 0 0 0 N
625 | P 2 0 0 0 -100 0 0 75 N
626 | C 0 0 150 0 1 10 N
627 | X ~ 1 0 200 100 D 50 50 1 1 P
628 | X ~ 2 -200 0 100 R 50 50 1 1 P
629 | X ~ 3 0 -200 100 U 50 50 1 1 P
630 | ENDDRAW
631 | ENDDEF
632 | #
633 | #End Library
634 |
--------------------------------------------------------------------------------
/hardware/contrib/1up-mini/1up-mini.pro:
--------------------------------------------------------------------------------
1 | update=lun. 24 juil. 2017 23:53:16 CEST
2 | version=1
3 | last_client=kicad
4 | [pcbnew]
5 | version=1
6 | LastNetListRead=
7 | UseCmpFile=1
8 | PadDrill=0.600000000000
9 | PadDrillOvalY=0.600000000000
10 | PadSizeH=1.500000000000
11 | PadSizeV=1.500000000000
12 | PcbTextSizeV=1.500000000000
13 | PcbTextSizeH=1.500000000000
14 | PcbTextThickness=0.300000000000
15 | ModuleTextSizeV=1.000000000000
16 | ModuleTextSizeH=1.000000000000
17 | ModuleTextSizeThickness=0.150000000000
18 | SolderMaskClearance=0.000000000000
19 | SolderMaskMinWidth=0.000000000000
20 | DrawSegmentWidth=0.200000000000
21 | BoardOutlineThickness=0.100000000000
22 | ModuleOutlineThickness=0.150000000000
23 | [cvpcb]
24 | version=1
25 | NetIExt=net
26 | [general]
27 | version=1
28 | [schematic_editor]
29 | version=1
30 | PageLayoutDescrFile=
31 | PlotDirectoryName=
32 | SubpartIdSeparator=0
33 | SubpartFirstId=65
34 | NetFmtName=Pcbnew
35 | SpiceForceRefPrefix=0
36 | SpiceUseNetNumbers=0
37 | LabSize=60
38 | [eeschema]
39 | version=1
40 | LibDir=../../lib/pkl;../../lib/stm32;../../lib/1bitsy/kicad
41 | [eeschema/libraries]
42 | LibName1=power
43 | LibName2=device
44 | LibName3=transistors
45 | LibName4=conn
46 | LibName5=linear
47 | LibName6=regul
48 | LibName7=74xx
49 | LibName8=cmos4000
50 | LibName9=adc-dac
51 | LibName10=memory
52 | LibName11=xilinx
53 | LibName12=microcontrollers
54 | LibName13=dsp
55 | LibName14=microchip
56 | LibName15=analog_switches
57 | LibName16=motorola
58 | LibName17=texas
59 | LibName18=intel
60 | LibName19=audio
61 | LibName20=interface
62 | LibName21=digital-audio
63 | LibName22=philips
64 | LibName23=display
65 | LibName24=cypress
66 | LibName25=siliconi
67 | LibName26=opto
68 | LibName27=atmel
69 | LibName28=contrib
70 | LibName29=valves
71 | LibName30=pkl_conn
72 | LibName31=pkl_device
73 | LibName32=pkl_ftdi
74 | LibName33=pkl_logos
75 | LibName34=pkl_misc
76 | LibName35=pkl_molex
77 | LibName36=pkl_power
78 | LibName37=pkl_sensor
79 | LibName38=pkl_tag_connect
80 | LibName39=pkl_texas
81 | LibName40=stm32
82 | LibName41=1bitsy
83 |
--------------------------------------------------------------------------------
/hardware/contrib/1up-mini/README.md:
--------------------------------------------------------------------------------
1 | # 1up-mini
2 |
3 | This is a board based on 1up v0.2, with horizontal form factor and easier to
4 | solder by hand.
5 |
6 | It is not supported by 1bit squared.
7 |
8 | ## What changed?
9 |
10 | It aims to be fully compatible with 1up board. Some of the components are
11 | changed to avoid hard to solder packages:
12 |
13 | - Headphone amplifier reference is changed. It consumes more power than the
14 | one used on the original board.
15 | - Volume control is the same component, with a different package.
16 | - Battery charger and power path is split in two components.
17 | - 0402 footprints are replaced with 0603.
18 | - Touch screen signals are only connected to 6 pin connector.
19 |
20 | Board shape is horizontal with symmetric buttons on both sides.
21 |
22 | ## What to change for the next iteration?
23 |
24 | - 0603 and resistor network footprints are a little bit to small for hand
25 | soldering.
26 | - SD card slot must be changed for something easier to solder.
27 | - Headphone jack could be changed for something more solid.
28 | - Hole for pogo pin is too small. Add a large pad so that it can be replaced
29 | with a cable.
30 | - Switch are hard to source. Also the one I ordered are not so good.
31 |
32 | ## Assembly
33 |
34 | Some tricky points:
35 |
36 | - You will need solder paste, flux and hot air to solder the SD card slot.
37 | - Surface under the LCD should be flat. Cut the pin used to mount the 1bitsy
38 | before soldering. Use isolating tape to avoid short circuits (there is a
39 | metal shield under the LCD).
40 | - You can replace the pogo pin with a cable.
41 |
42 | ## BOM
43 |
44 | | Reference | Package | Qty. | Designation | Mouser/URL |
45 | | ---------------------- | ---------- | ---- | --------------- | -------------------- |
46 | | C[19,26,27,29,30] | 0603 | 5 | 100 nF | |
47 | | C[20,21,24,25,31..33] | 0603 | 7 | 1 µF | |
48 | | C[22,23] | 0603 | 2 | 2.2 µF | |
49 | | C28 | 0805 | 1 | 10 µF | |
50 | | CON1 | SCHA4B0419 | 1 | Micro SD | 688-SCHA4B0419 |
51 | | D2 | 0603 | 1 | Yellow LED | |
52 | | J3 | Jack | 1 | JACK_3C1S | 490-SJ2-35853BSMT-TR |
53 | | P1 | PogoPin | 1 | PogoPin | 575-906115 or cable |
54 | | P[2..4] | | 3 | Battery conn. | |
55 | | Q1 | SOT-23 | 1 | NMOS | 726-BSS806NH6327XT |
56 | | R11 | 0603 | 1 | 49 kΩ | |
57 | | R[12..15] | 4x0603 | 4 | 10 kΩ | 667-EXB-38V103JV |
58 | | R[17,18] | 0603 | 2 | 2.7 kΩ | |
59 | | R[20..23] | 0603 | 4 | 10 Ω | |
60 | | R24 | 0603 | 1 | 1 kΩ | |
61 | | R6 | 0603 | 1 | 4.7 kΩ | |
62 | | R[7,10,16,19,25,26,30] | 0603 | 7 | 10 kΩ | |
63 | | R[8,9] | 0603 | 2 | 50 Ω | |
64 | | SW[12,13] | Switch | 2 | Side Switch | 653-B3U-3000P |
65 | | SW14 | Switch | 1 | SPDT Switch | 611-PCM12SMTR |
66 | | SW[2..11] | Switch | 1 | Switch | [aliexpress][] |
67 | | U10 | TSSOP-8 | 1 | TPS2111A | 595-TPS2111APWR |
68 | | U2 | 1bitsy | 1 | 1bitsy | |
69 | | U3 | TSSOP-14 | 1 | MCP4661-103E/ST | 579-MCP4661-103E/ST |
70 | | U4 | TSSOP-14 | 1 | TPA6139A2-PW | 595-TPA6139A2PWR |
71 | | U[5,6] | TSSOP-16 | 2 | 74HC165 | 771-74HC165PW-T |
72 | | U7 | SOT-23-6 | 1 | BQ21040 | 595-BQ21040DBVR |
73 | | U8 | ER-CON50HT | 1 | 50 pin conn. | sold with LCD |
74 | | U9 | ER-CON06HB | 1 | 6 pin conn. | sold with LCD |
75 | | LCD | | 1 | LCD | [buydisplay][] |
76 |
77 | [buydisplay]:
78 | http://www.buydisplay.com/default/serial-spi-2-8-tft-lcd-module-display-320x240-optional-touch-screen
79 | [aliexpress]:
80 | https://www.aliexpress.com/store/product/Original-new-100-Japan-conductive-rubber-head-waterproof-touch-switch-8-8-5-silent-key-micro/828867_32724415032.html
81 |
--------------------------------------------------------------------------------
/hardware/contrib/1up-mini/fp-lib-table:
--------------------------------------------------------------------------------
1 | (fp_lib_table
2 | (lib (name pkl_logos)(type KiCad)(uri ${KIPRJMOD}/../../lib/pkl/pkl_logos.pretty)(options "")(descr ""))
3 | (lib (name pkl_pads)(type KiCad)(uri ${KIPRJMOD}/../../lib/pkl/pkl_pads.pretty)(options "")(descr ""))
4 | (lib (name pkl_misc)(type KiCad)(uri ${KIPRJMOD}/../../lib/pkl/pkl_misc.pretty)(options "")(descr ""))
5 | (lib (name pkl_buttons_switches)(type KiCad)(uri ${KIPRJMOD}/../../lib/pkl/pkl_buttons_switches.pretty)(options "")(descr ""))
6 | (lib (name pkl_connectors)(type KiCad)(uri ${KIPRJMOD}/../../lib/pkl/pkl_connectors.pretty)(options "")(descr ""))
7 | (lib (name pkl_dipol)(type KiCad)(uri ${KIPRJMOD}/../../lib/pkl/pkl_dipol.pretty)(options "")(descr ""))
8 | (lib (name pkl_housings_dfn_qfn)(type KiCad)(uri ${KIPRJMOD}/../../lib/pkl/pkl_housings_dfn_qfn.pretty)(options "")(descr ""))
9 | (lib (name pkl_housings_sop)(type KiCad)(uri ${KIPRJMOD}/../../lib/pkl/pkl_housings_sop.pretty)(options "")(descr ""))
10 | (lib (name pkl_jumpers)(type KiCad)(uri ${KIPRJMOD}/../../lib/pkl/pkl_jumpers.pretty)(options "")(descr ""))
11 | (lib (name pkl_housings_sot)(type KiCad)(uri ${KIPRJMOD}/../../lib/pkl/pkl_housings_sot.pretty)(options "")(descr ""))
12 | (lib (name pkl_pin_headers)(type KiCad)(uri ${KIPRJMOD}/../../lib/pkl/pkl_pin_headers.pretty)(options "")(descr ""))
13 | (lib (name 1bitsy)(type KiCad)(uri ${KIPRJMOD}/../../lib/1bitsy/kicad/1bitsy.pretty)(options "")(descr ""))
14 | )
15 |
--------------------------------------------------------------------------------
/hardware/v0.2/1bitsy-1up.pro:
--------------------------------------------------------------------------------
1 | update=Sat 24 Mar 2018 03:29:19 PM PDT
2 | version=1
3 | last_client=kicad
4 | [pcbnew]
5 | version=1
6 | LastNetListRead=
7 | UseCmpFile=1
8 | PadDrill=0.600000000000
9 | PadDrillOvalY=0.600000000000
10 | PadSizeH=1.500000000000
11 | PadSizeV=1.500000000000
12 | PcbTextSizeV=1.500000000000
13 | PcbTextSizeH=1.500000000000
14 | PcbTextThickness=0.300000000000
15 | ModuleTextSizeV=1.000000000000
16 | ModuleTextSizeH=1.000000000000
17 | ModuleTextSizeThickness=0.150000000000
18 | SolderMaskClearance=0.000000000000
19 | SolderMaskMinWidth=0.000000000000
20 | DrawSegmentWidth=0.200000000000
21 | BoardOutlineThickness=0.100000000000
22 | ModuleOutlineThickness=0.150000000000
23 | [cvpcb]
24 | version=1
25 | NetIExt=net
26 | [general]
27 | version=1
28 | [schematic_editor]
29 | version=1
30 | PageLayoutDescrFile=
31 | PlotDirectoryName=
32 | SubpartIdSeparator=0
33 | SubpartFirstId=65
34 | NetFmtName=
35 | SpiceForceRefPrefix=0
36 | SpiceUseNetNumbers=0
37 | LabSize=60
38 | [eeschema]
39 | version=1
40 | LibDir=
41 |
--------------------------------------------------------------------------------
/hardware/v0.2/sym-lib-table:
--------------------------------------------------------------------------------
1 | (sym_lib_table
2 | (lib (name 74xx)(type Legacy)(uri ${KICAD_SYMBOL_DIR}/74xx.lib)(options "")(descr ""))
3 | (lib (name pkl_conn)(type Legacy)(uri ${KIPRJMOD}/../lib/pkl/pkl_conn.lib)(options "")(descr ""))
4 | (lib (name pkl_device)(type Legacy)(uri ${KIPRJMOD}/../lib/pkl/pkl_device.lib)(options "")(descr ""))
5 | (lib (name pkl_ftdi)(type Legacy)(uri ${KIPRJMOD}/../lib/pkl/pkl_ftdi.lib)(options "")(descr ""))
6 | (lib (name pkl_linear)(type Legacy)(uri ${KIPRJMOD}/../lib/pkl/pkl_linear.lib)(options "")(descr ""))
7 | (lib (name pkl_logos)(type Legacy)(uri ${KIPRJMOD}/../lib/pkl/pkl_logos.lib)(options "")(descr ""))
8 | (lib (name pkl_maxim)(type Legacy)(uri ${KIPRJMOD}/../lib/pkl/pkl_maxim.lib)(options "")(descr ""))
9 | (lib (name pkl_misc)(type Legacy)(uri ${KIPRJMOD}/../lib/pkl/pkl_misc.lib)(options "")(descr ""))
10 | (lib (name pkl_molex)(type Legacy)(uri ${KIPRJMOD}/../lib/pkl/pkl_molex.lib)(options "")(descr ""))
11 | (lib (name pkl_power)(type Legacy)(uri ${KIPRJMOD}/../lib/pkl/pkl_power.lib)(options "")(descr ""))
12 | (lib (name pkl_sensor)(type Legacy)(uri ${KIPRJMOD}/../lib/pkl/pkl_sensor.lib)(options "")(descr ""))
13 | (lib (name pkl_tag_connect)(type Legacy)(uri ${KIPRJMOD}/../lib/pkl/pkl_tag_connect.lib)(options "")(descr ""))
14 | (lib (name pkl_texas)(type Legacy)(uri ${KIPRJMOD}/../lib/pkl/pkl_texas.lib)(options "")(descr ""))
15 | (lib (name 1bitsy)(type Legacy)(uri ${KIPRJMOD}/../lib/1bitsy/kicad/1bitsy.lib)(options "")(descr ""))
16 | (lib (name pkl_lattice)(type Legacy)(uri ${KIPRJMOD}/../lib/pkl/pkl_lattice.lib)(options "")(descr ""))
17 | (lib (name pkl_memory)(type Legacy)(uri ${KIPRJMOD}/../lib/pkl/pkl_memory.lib)(options "")(descr ""))
18 | (lib (name stm32)(type Legacy)(uri ${KIPRJMOD}/../lib/stm32/stm32.lib)(options "")(descr ""))
19 | )
20 |
--------------------------------------------------------------------------------