Initial working rotating nametag

This commit is contained in:
true 2023-11-04 07:42:38 -07:00
commit 07a0f30d72
17 changed files with 345089 additions and 0 deletions

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
.pio
.vscode/.browse.c_cpp.db*
.vscode/c_cpp_properties.json
.vscode/launch.json
.vscode/ipch

10
.vscode/extensions.json vendored Normal file
View File

@ -0,0 +1,10 @@
{
// See http://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format
"recommendations": [
"platformio.platformio-ide"
],
"unwantedRecommendations": [
"ms-vscode.cpptools-extension-pack"
]
}

39
include/README Normal file
View File

@ -0,0 +1,39 @@
This directory is intended for project header files.
A header file is a file containing C declarations and macro definitions
to be shared between several project source files. You request the use of a
header file in your project source file (C, C++, etc) located in `src` folder
by including it, with the C preprocessing directive `#include'.
```src/main.c
#include "header.h"
int main (void)
{
...
}
```
Including a header file produces the same results as copying the header file
into each source file that needs it. Such copying would be time-consuming
and error-prone. With a header file, the related declarations appear
in only one place. If they need to be changed, they can be changed in one
place, and programs that include the header file will automatically use the
new version when next recompiled. The header file eliminates the labor of
finding and changing all the copies as well as the risk that a failure to
find one copy will result in inconsistencies within a program.
In C, the usual convention is to give header files names that end with `.h'.
It is most portable to use only letters, digits, dashes, and underscores in
header file names, and at most one dot.
Read more about using header files in official GCC documentation:
* Include Syntax
* Include Operation
* Once-Only Headers
* Computed Includes
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html

36
include/gc9a01.h Normal file
View File

@ -0,0 +1,36 @@
#ifndef __GC9A01_H
#define __GC9A01_H
#include <stdint.h>
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
// Hardware abstraction layer
// Should be defined by the user of the library
void GC9A01_set_reset(uint8_t val);
void GC9A01_set_data_command(uint8_t val);
void GC9A01_set_chip_select(uint8_t val);
void GC9A01_delay(uint16_t ms);
void GC9A01_spi_tx(uint8_t *data, size_t len);
struct GC9A01_point {
uint16_t X, Y;
};
struct GC9A01_frame {
struct GC9A01_point start, end;
};
void GC9A01_init(void);
void GC9A01_set_frame(struct GC9A01_frame frame);
void GC9A01_write(uint8_t *data, size_t len);
void GC9A01_write_continue(uint8_t *data, size_t len);
#ifdef __cplusplus
}
#endif
#endif

98
include/hsv2rgb.h Normal file
View File

@ -0,0 +1,98 @@
#ifndef _INC_HSV2RGB_H
#define _INC_HSV2RGB_H
#include <stdint.h>
typedef struct color_rgb {
uint8_t r;
uint8_t g;
uint8_t b;
} color_rgb;
typedef struct color_hsv {
int16_t h;
uint8_t s;
uint8_t v;
} color_hsv;
#define HSV_HUE_SEXTANT 256
#define HSV_HUE_STEPS (6 * HSV_HUE_SEXTANT)
#define HSV_HUE_MIN 0
#define HSV_HUE_MAX (HSV_HUE_STEPS - 1)
#define HSV_SAT_MIN 0
#define HSV_SAT_MAX 255
#define HSV_VAL_MIN 0
#define HSV_VAL_MAX 255
/* Options: */
#define HSV_USE_SEXTANT_TEST /* Limit the hue to 0...360 degrees */
void hsv2rgb_8b(int16_t h, uint8_t s, uint8_t v, uint8_t *r, uint8_t *g , uint8_t *b);
/*
* Macros that are common to all implementations
*/
#ifdef HSV_USE_SEXTANT_TEST
#define HSV_SEXTANT_TEST(sextant) \
if((sextant) > 5) { \
(sextant) = 5; \
}
#else
#define HSV_SEXTANT_TEST(sextant)
#endif
/*
* Pointer swapping:
* sext. r g b r<>b g<>b r <> g result
* 0 0 0 v u c !u v c u v c
* 0 0 1 d v c d v c
* 0 1 0 c v u u v c u v c
* 0 1 1 c d v v d c d v c d v c
* 1 0 0 u c v u v c u v c
* 1 0 1 v c d v d c d v c d v c
*
* if(sextant & 2)
* r <-> b
*
* if(sextant & 4)
* g <-> b
*
* if(!(sextant & 6) {
* if(!(sextant & 1))
* r <-> g
* } else {
* if(sextant & 1)
* r <-> g
* }
*/
#define HSV_SWAPPTR(a,b) do { uint8_t *tmp = (a); (a) = (b); (b) = tmp; } while(0)
#define HSV_POINTER_SWAP(sextant,r,g,b) \
do { \
if((sextant) & 2) { \
HSV_SWAPPTR((r), (b)); \
} \
if((sextant) & 4) { \
HSV_SWAPPTR((g), (b)); \
} \
if(!((sextant) & 6)) { \
if(!((sextant) & 1)) { \
HSV_SWAPPTR((r), (g)); \
} \
} else { \
if((sextant) & 1) { \
HSV_SWAPPTR((r), (g)); \
} \
} \
} while(0)
#endif /* _INC_HSV2RGB_H */

43
include/sin1.h Normal file
View File

@ -0,0 +1,43 @@
/**
* Example for a interpolated sine/cosine table lookup
*
* @file sin1.h
* @author stfwi
*
*/
#ifndef __SW__SIN1_H__
#define __SW__SIN1_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <sys/types.h>
/**
* Sine calculation using interpolated table lookup.
* Instead of radiants or degrees we use "turns" here. Means this
* sine does NOT return one phase for 0 to 2*PI, but for 0 to 1.
* Input: -1 to 1 as int16 Q15 == -32768 to 32767.
* Output: -1 to 1 as int16 Q15 == -32768 to 32767.
*
* @param int16_t angle Q15
* @return int16_t Q15
*/
int16_t sin1(int16_t angle);
/**
* Cosine calculation using interpolated table lookup.
* Instead of radiants or degrees we use "turns" here. Means this
* cosine does NOT return one phase for 0 to 2*PI, but for 0 to 1.
* Input: -1 to 1 as int16 Q15 == -32768 to 32767.
* Output: -1 to 1 as int16 Q15 == -32768 to 32767.
*
* @param int16_t angle Q15
* @return int16_t Q15
*/
int16_t cos1(int16_t angle);
#ifdef __cplusplus
}
#endif
#endif

43
include/sin7.h Normal file
View File

@ -0,0 +1,43 @@
/**
* Example for a interpolated sine/cosine table lookup
*
* modified by true to work in 8 bits, and to fix cos7 function
*
*/
#ifndef INC_MATH_SIN7_H_
#define INC_MATH_SIN7_H_
#include <stdint.h>
/**
* Sine calculation using interpolated table lookup.
* Instead of radians or degrees we use "turns" here. Means this
* sine does NOT return one phase for 0 to 2*PI, but for 0 to 1.
* Input: -1 to 1 as int8 "Q7" == -128 to 127.
* Output: -1 to 1 as int8 "Q7" == -128 to 127.
*
* @param int8_t angle Q7
* @return int8_t Q7
*/
int8_t sin7(int8_t angle);
/**
* Cosine calculation using interpolated table lookup.
* Instead of radians or degrees we use "turns" here. Means this
* cosine does NOT return one phase for 0 to 2*PI, but for 0 to 1.
* Input: -1 to 1 as int8 "Q7" == -128 to 127.
* Output: -1 to 1 as int8 "Q7" == -128 to 127.
*
* @param int8_t angle Q7
* @return int8_t Q7
*/
int8_t cos7(int8_t angle);
#endif /* INC_MATH_SIN7_H_ */

46
lib/README Normal file
View File

@ -0,0 +1,46 @@
This directory is intended for project specific (private) libraries.
PlatformIO will compile them to static libraries and link into executable file.
The source code of each library should be placed in a an own separate directory
("lib/your_library_name/[here are source files]").
For example, see a structure of the following two libraries `Foo` and `Bar`:
|--lib
| |
| |--Bar
| | |--docs
| | |--examples
| | |--src
| | |- Bar.c
| | |- Bar.h
| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
| |
| |--Foo
| | |- Foo.c
| | |- Foo.h
| |
| |- README --> THIS FILE
|
|- platformio.ini
|--src
|- main.c
and a contents of `src/main.c`:
```
#include <Foo.h>
#include <Bar.h>
int main (void)
{
...
}
```
PlatformIO Library Dependency Finder will find automatically dependent
libraries scanning project source files.
More information about PlatformIO Library Dependency Finder
- https://docs.platformio.org/page/librarymanager/ldf.html

26
platformio.ini Normal file
View File

@ -0,0 +1,26 @@
; PlatformIO Project Configuration File
;
; Build options: build flags, source filter
; Upload options: custom upload port, speed and extra flags
; Library options: dependencies, extra library storages
; Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html
[env:supercon7-badge-pico]
platform = https://github.com/maxgerhardt/platform-raspberrypi.git
board = rpipico
framework = arduino
board_build.filesystem_size = 1m
debug_build_flags =
-g
-Os
lib_deps =
moononournation/GFX Library for Arduino@^1.3.8
platform_packages =
toolchain-gccarmnoneeabi@1.100301.220327

316
src/gc9a01.c Normal file
View File

@ -0,0 +1,316 @@
#include "GC9A01.h"
#define ORIENTATION 2 // Set the display orientation 0,1,2,3
// Command codes:
#define COL_ADDR_SET 0x2A
#define ROW_ADDR_SET 0x2B
#define MEM_WR 0x2C
#define COLOR_MODE 0x3A
#define COLOR_MODE__12_BIT 0x03
#define COLOR_MODE__16_BIT 0x05
#define COLOR_MODE__18_BIT 0x06
#define MEM_WR_CONT 0x3C
static void GC9A01_write_command(uint8_t cmd) {
GC9A01_set_data_command(0);
GC9A01_set_chip_select(0);
GC9A01_spi_tx(&cmd, sizeof(cmd));
GC9A01_set_chip_select(1);
}
static void GC9A01_write_data(uint8_t *data, size_t len) {
GC9A01_set_data_command(1);
GC9A01_set_chip_select(0);
GC9A01_spi_tx(data, len);
GC9A01_set_chip_select(1);
}
static inline void GC9A01_write_byte(uint8_t val) {
GC9A01_write_data(&val, sizeof(val));
}
void GC9A01_init(void) {
GC9A01_set_chip_select(1);
GC9A01_delay(5);
GC9A01_set_reset(0);
GC9A01_delay(10);
GC9A01_set_reset(1);
GC9A01_delay(120);
/* Initial Sequence */
GC9A01_write_command(0xEF);
GC9A01_write_command(0xEB);
GC9A01_write_byte(0x14);
GC9A01_write_command(0xFE);
GC9A01_write_command(0xEF);
GC9A01_write_command(0xEB);
GC9A01_write_byte(0x14);
GC9A01_write_command(0x84);
GC9A01_write_byte(0x40);
GC9A01_write_command(0x85);
GC9A01_write_byte(0xFF);
GC9A01_write_command(0x86);
GC9A01_write_byte(0xFF);
GC9A01_write_command(0x87);
GC9A01_write_byte(0xFF);
GC9A01_write_command(0x88);
GC9A01_write_byte(0x0A);
GC9A01_write_command(0x89);
GC9A01_write_byte(0x21);
GC9A01_write_command(0x8A);
GC9A01_write_byte(0x00);
GC9A01_write_command(0x8B);
GC9A01_write_byte(0x80);
GC9A01_write_command(0x8C);
GC9A01_write_byte(0x01);
GC9A01_write_command(0x8D);
GC9A01_write_byte(0x01);
GC9A01_write_command(0x8E);
GC9A01_write_byte(0xFF);
GC9A01_write_command(0x8F);
GC9A01_write_byte(0xFF);
GC9A01_write_command(0xB6);
GC9A01_write_byte(0x00);
GC9A01_write_byte(0x00);
GC9A01_write_command(0x36);
#if ORIENTATION == 0
GC9A01_write_byte(0x18);
#elif ORIENTATION == 1
GC9A01_write_byte(0x28);
#elif ORIENTATION == 2
GC9A01_write_byte(0x48);
#else
GC9A01_write_byte(0x88);
#endif
GC9A01_write_command(COLOR_MODE);
GC9A01_write_byte(COLOR_MODE__18_BIT);
GC9A01_write_command(0x90);
GC9A01_write_byte(0x08);
GC9A01_write_byte(0x08);
GC9A01_write_byte(0x08);
GC9A01_write_byte(0x08);
GC9A01_write_command(0xBD);
GC9A01_write_byte(0x06);
GC9A01_write_command(0xBC);
GC9A01_write_byte(0x00);
GC9A01_write_command(0xFF);
GC9A01_write_byte(0x60);
GC9A01_write_byte(0x01);
GC9A01_write_byte(0x04);
GC9A01_write_command(0xC3);
GC9A01_write_byte(0x13);
GC9A01_write_command(0xC4);
GC9A01_write_byte(0x13);
GC9A01_write_command(0xC9);
GC9A01_write_byte(0x22);
GC9A01_write_command(0xBE);
GC9A01_write_byte(0x11);
GC9A01_write_command(0xE1);
GC9A01_write_byte(0x10);
GC9A01_write_byte(0x0E);
GC9A01_write_command(0xDF);
GC9A01_write_byte(0x21);
GC9A01_write_byte(0x0c);
GC9A01_write_byte(0x02);
GC9A01_write_command(0xF0);
GC9A01_write_byte(0x45);
GC9A01_write_byte(0x09);
GC9A01_write_byte(0x08);
GC9A01_write_byte(0x08);
GC9A01_write_byte(0x26);
GC9A01_write_byte(0x2A);
GC9A01_write_command(0xF1);
GC9A01_write_byte(0x43);
GC9A01_write_byte(0x70);
GC9A01_write_byte(0x72);
GC9A01_write_byte(0x36);
GC9A01_write_byte(0x37);
GC9A01_write_byte(0x6F);
GC9A01_write_command(0xF2);
GC9A01_write_byte(0x45);
GC9A01_write_byte(0x09);
GC9A01_write_byte(0x08);
GC9A01_write_byte(0x08);
GC9A01_write_byte(0x26);
GC9A01_write_byte(0x2A);
GC9A01_write_command(0xF3);
GC9A01_write_byte(0x43);
GC9A01_write_byte(0x70);
GC9A01_write_byte(0x72);
GC9A01_write_byte(0x36);
GC9A01_write_byte(0x37);
GC9A01_write_byte(0x6F);
GC9A01_write_command(0xED);
GC9A01_write_byte(0x1B);
GC9A01_write_byte(0x0B);
GC9A01_write_command(0xAE);
GC9A01_write_byte(0x77);
GC9A01_write_command(0xCD);
GC9A01_write_byte(0x63);
GC9A01_write_command(0x70);
GC9A01_write_byte(0x07);
GC9A01_write_byte(0x07);
GC9A01_write_byte(0x04);
GC9A01_write_byte(0x0E);
GC9A01_write_byte(0x0F);
GC9A01_write_byte(0x09);
GC9A01_write_byte(0x07);
GC9A01_write_byte(0x08);
GC9A01_write_byte(0x03);
GC9A01_write_command(0xE8);
GC9A01_write_byte(0x34);
GC9A01_write_command(0x62);
GC9A01_write_byte(0x18);
GC9A01_write_byte(0x0D);
GC9A01_write_byte(0x71);
GC9A01_write_byte(0xED);
GC9A01_write_byte(0x70);
GC9A01_write_byte(0x70);
GC9A01_write_byte(0x18);
GC9A01_write_byte(0x0F);
GC9A01_write_byte(0x71);
GC9A01_write_byte(0xEF);
GC9A01_write_byte(0x70);
GC9A01_write_byte(0x70);
GC9A01_write_command(0x63);
GC9A01_write_byte(0x18);
GC9A01_write_byte(0x11);
GC9A01_write_byte(0x71);
GC9A01_write_byte(0xF1);
GC9A01_write_byte(0x70);
GC9A01_write_byte(0x70);
GC9A01_write_byte(0x18);
GC9A01_write_byte(0x13);
GC9A01_write_byte(0x71);
GC9A01_write_byte(0xF3);
GC9A01_write_byte(0x70);
GC9A01_write_byte(0x70);
GC9A01_write_command(0x64);
GC9A01_write_byte(0x28);
GC9A01_write_byte(0x29);
GC9A01_write_byte(0xF1);
GC9A01_write_byte(0x01);
GC9A01_write_byte(0xF1);
GC9A01_write_byte(0x00);
GC9A01_write_byte(0x07);
GC9A01_write_command(0x66);
GC9A01_write_byte(0x3C);
GC9A01_write_byte(0x00);
GC9A01_write_byte(0xCD);
GC9A01_write_byte(0x67);
GC9A01_write_byte(0x45);
GC9A01_write_byte(0x45);
GC9A01_write_byte(0x10);
GC9A01_write_byte(0x00);
GC9A01_write_byte(0x00);
GC9A01_write_byte(0x00);
GC9A01_write_command(0x67);
GC9A01_write_byte(0x00);
GC9A01_write_byte(0x3C);
GC9A01_write_byte(0x00);
GC9A01_write_byte(0x00);
GC9A01_write_byte(0x00);
GC9A01_write_byte(0x01);
GC9A01_write_byte(0x54);
GC9A01_write_byte(0x10);
GC9A01_write_byte(0x32);
GC9A01_write_byte(0x98);
GC9A01_write_command(0x74);
GC9A01_write_byte(0x10);
GC9A01_write_byte(0x85);
GC9A01_write_byte(0x80);
GC9A01_write_byte(0x00);
GC9A01_write_byte(0x00);
GC9A01_write_byte(0x4E);
GC9A01_write_byte(0x00);
GC9A01_write_command(0x98);
GC9A01_write_byte(0x3e);
GC9A01_write_byte(0x07);
GC9A01_write_command(0x35);
GC9A01_write_command(0x21);
GC9A01_write_command(0x11);
GC9A01_delay(120);
GC9A01_write_command(0x29);
GC9A01_delay(20);
}
void GC9A01_set_frame(struct GC9A01_frame frame) {
uint8_t data[4];
GC9A01_write_command(COL_ADDR_SET);
data[0] = (frame.start.X >> 8) & 0xFF;
data[1] = frame.start.X & 0xFF;
data[2] = (frame.end.X >> 8) & 0xFF;
data[3] = frame.end.X & 0xFF;
GC9A01_write_data(data, sizeof(data));
GC9A01_write_command(ROW_ADDR_SET);
data[0] = (frame.start.Y >> 8) & 0xFF;
data[1] = frame.start.Y & 0xFF;
data[2] = (frame.end.Y >> 8) & 0xFF;
data[3] = frame.end.Y & 0xFF;
GC9A01_write_data(data, sizeof(data));
}
void GC9A01_write(uint8_t *data, size_t len) {
GC9A01_write_command(MEM_WR);
GC9A01_write_data(data, len);
}
void GC9A01_write_continue(uint8_t *data, size_t len) {
GC9A01_write_command(MEM_WR_CONT);
GC9A01_write_data(data, len);
}

94
src/hsv2rgb.c Normal file
View File

@ -0,0 +1,94 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2016 B. Stultiens
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "hsv2rgb.h"
void hsv2rgb_8b(int16_t h, uint8_t s, uint8_t v, uint8_t *r, uint8_t *g , uint8_t *b)
{
uint8_t sextant;
uint8_t bb;
uint16_t ww;
uint8_t h_fraction;
if (!(s)) {
*(r) = *(g) = *(b) = (v);
return;
}
sextant = h >> 8;
HSV_SEXTANT_TEST(sextant); // Optional: Limit hue sextants to defined space
HSV_POINTER_SWAP(sextant, r, g, b); // Swap pointers depending which sextant we are in
*g = v; // Top level
// Perform actual calculations
/*
* Bottom level: v * (1.0 - s)
* --> (v * (255 - s) + error_corr) / 256
*/
bb = ~s;
ww = v * bb;
ww += 1; // Error correction
ww += ww >> 8; // Error correction
*b = ww >> 8;
h_fraction = h & 0xff; // 0...255
if(!(sextant & 1)) {
// *r = ...slope_up...;
/*
* Slope up: v * (1.0 - s * (1.0 - h))
* --> (v * (255 - (s * (256 - h) + error_corr1) / 256) + error_corr2) / 256
*/
ww = !h_fraction ? ((uint16_t)s << 8) : (s * (uint8_t)(-h_fraction));
ww += ww >> 8; // Error correction 1
bb = ww >> 8;
bb = ~bb;
ww = v * bb;
ww += v >> 1; // Error correction 2
*r = ww >> 8;
} else {
// *r = ...slope_down...;
/*
* Slope down: v * (1.0 - s * h)
* --> (v * (255 - (s * h + error_corr1) / 256) + error_corr2) / 256
*/
ww = s * h_fraction;
ww += ww >> 8; // Error correction 1
bb = ww >> 8;
bb = ~bb;
ww = v * bb;
ww += v >> 1; // Error correction 2
*r = ww >> 8;
/*
* A perfect match for h_fraction == 0 implies:
* *r = (ww >> 8) + (h_fraction ? 0 : 1)
* However, this is an extra calculation that may not be required.
*/
}
}

305
src/main.cpp Normal file
View File

@ -0,0 +1,305 @@
#include <Arduino.h>
#include "SPI.h"
// #include "GC9A01.h"
#include <Arduino_GFX_Library.h>
#include <U8g2lib.h>
extern "C" {
#include "hsv2rgb.h"
#include "sin1.h"
#include "sin7.h"
}
const char name[] = "true";
#define SPI0_SCK 2
#define SPI0_MISO GFX_NOT_DEFINED
#define SPI0_MOSI 3
#define DISP_NSS 1
#define DISP_RESET 4
#define DISP_DC 5
#define TEXT_SIZE 5
#define ROT_SIZE 70
#define LETTER_SPACING 1898 // user-configurable
Arduino_DataBus *bus = new Arduino_RPiPicoSPI(DISP_DC, DISP_NSS, SPI0_SCK, SPI0_MOSI, SPI0_MISO, spi0);
Arduino_GFX *disp = new Arduino_GC9A01(bus, DISP_RESET, 0 /* rotation */, true /* IPS */);
Arduino_Canvas *dout = new Arduino_Canvas(240 /* width */, 240 /* height */, disp);
Arduino_Canvas *drot = new Arduino_Canvas(ROT_SIZE, ROT_SIZE, disp);
color_hsv hsv = {0, 255, 255};
color_rgb rgb;
/*
void GC9A01_set_reset(uint8_t val) {
digitalWrite(DISP_RESET, val);
}
void GC9A01_set_data_command(uint8_t val) {
digitalWrite(DISP_DC, val);
}
void GC9A01_set_chip_select(uint8_t val) {
digitalWrite(DISP_NSS, val);
}
void GC9A01_spi_tx(uint8_t *data, size_t len) {
while (len--) {
SPI.transfer(*data);
data++;
}
}
void GC9A01_delay(uint16_t ms) {
delay(ms);
}
void setup() {
pinMode(DISP_RESET, OUTPUT);
pinMode(DISP_DC, OUTPUT);
pinMode(DISP_NSS, OUTPUT);
SPI.setRX(SPI0_MISO);
SPI.setSCK(SPI0_SCK);
SPI.setTX(SPI0_MOSI);
SPI.begin();
GC9A01_init();
struct GC9A01_frame frame = {{0,0},{239,239}};
GC9A01_set_frame(frame);
}
void loop() {
uint8_t color[3];
// Triangle
color[0] = 0xFF;
color[1] = 0xFF;
for (int x = 0; x < 240; x++) {
for (int y = 0; y < 240; y++) {
if (x < y) {
color[2] = 0xFF;
} else {
color[2] = 0x00;
}
if (x == 0 && y == 0) {
GC9A01_write(color, sizeof(color));
} else {
GC9A01_write_continue(color, sizeof(color));
}
}
}
delay(1000);
// Rainbow
float frequency = 0.026;
for (int x = 0; x < 240; x++) {
color[0] = sin(frequency*x + 0) * 127 + 128;
color[1] = sin(frequency*x + 2) * 127 + 128;
color[2] = sin(frequency*x + 4) * 127 + 128;
for (int y = 0; y < 240; y++) {
if (x == 0 && y == 0) {
GC9A01_write(color, sizeof(color));
} else {
GC9A01_write_continue(color, sizeof(color));
}
}
}
delay(1000);
// Checkerboard
for (int x = 0; x < 240; x++) {
for (int y = 0; y < 240; y++) {
if ((x / 10) % 2 == (y / 10) % 2) {
color[0] = 0xFF;
color[1] = 0xFF;
color[2] = 0xFF;
} else {
color[0] = 0x00;
color[1] = 0x00;
color[2] = 0x00;
}
if (x == 0 && y == 0) {
GC9A01_write(color, sizeof(color));
} else {
GC9A01_write_continue(color, sizeof(color));
}
}
}
delay(1000);
}
*/
#define FONT_JUMPTABLE_BYTES 4
#define FONT_JUMPTABLE_MSB 0
#define FONT_JUMPTABLE_LSB 1
#define FONT_JUMPTABLE_SIZE 2
#define FONT_JUMPTABLE_WIDTH 3
#define FONT_JUMPTABLE_START 4
#define FONT_WIDTH_POS 0
#define FONT_HEIGHT_POS 1
#define FONT_FIRST_CHAR_POS 2
#define FONT_CHAR_NUM_POS 3
int16_t font_get_str_width(const uint8_t *font, const char *str, uint8_t len, int8_t extra_spacing)
{
uint8_t first = font[FONT_FIRST_CHAR_POS];
uint8_t chr_width;
uint8_t str_width = 0;
uint8_t w;
w = len;
while (w--) {
chr_width = font[FONT_JUMPTABLE_START + (str[w] - first) * FONT_JUMPTABLE_BYTES + FONT_JUMPTABLE_WIDTH];
str_width += chr_width;
}
str_width += extra_spacing * (len - 1);
return str_width;
}
void setup()
{
Serial.begin(115200);
Serial.println("starting...");
delay(50);
bus->begin(90000000);
if (!disp->begin()) {
Serial.println("failed to start disp");
}
dout->begin();
dout->fillScreen(BLACK);
dout->flush();
drot->begin();
drot->setFont(u8g2_font_cubic11_h_cjk); // u8g2_font_spleen16x32_mr
drot->setTextSize(TEXT_SIZE);
}
void rotate_letter(uint8_t idx, int16_t rot, int16_t out_x, int16_t out_y, uint16_t color)
{
int16_t x, y;
int16_t nx, ny;
int16_t sx, sy;
int16_t start_x, start_y;
int16_t x_width;
uint16_t *src, *dst;
uint16_t src_pxl;
uint16_t bgcolor = CYAN;
// clear the rotation buffer
drot->fillScreen(CYAN);
// print the letter to the center of the rotation buffer
drot->setCursor(0, TEXT_SIZE * 10);
drot->setTextColor(color);
drot->print(name[idx]);
x_width = drot->getCursorX() - TEXT_SIZE;
// framebuffers
src = drot->getFramebuffer();
dst = dout->getFramebuffer();
// position
start_x = out_x + 120;
start_y = out_y + 120;
// rotate+copy the buffer
for (y = 0; y < ROT_SIZE; y++) {
for (x = 0; x < x_width; x++) {
src_pxl = src[x + (y * ROT_SIZE)];
sx = x + 1 - (x_width >> 1);
sy = y - (ROT_SIZE/2) + 1;
if (src_pxl != bgcolor) {
nx = ((sx * cos1(rot)) - (sy * sin1(rot))) >> 15;
ny = ((sx * sin1(rot)) + (sy * cos1(rot))) >> 15;
nx += start_x;
ny += start_y;
if ((nx >= 0) && (nx < 240)) {
if ((ny >= 0) && (ny < 240)) {
dst[nx + (ny*240)] = src_pxl;
}
}
}
}
}
}
int16_t rot = 0;
void loop()
{
uint16_t hue;
hsv.h += 24;
// background fill
hue = hsv.h + 512;
hsv.h %= 1536;
hsv2rgb_8b(hue, 255, 128, &rgb.r, &rgb.g, &rgb.b);
// dout->fillScreen(dout->color565(rgb.r, rgb.g, rgb.b));
dout->fillScreen(BLACK);
hue = hsv.h;
for (int8_t i = 120; i > 0; i--) {
hue += 2;
hue %= 1536;
hsv2rgb_8b(hue, 220, (i * 2), &rgb.r, &rgb.g, &rgb.b);
dout->drawCircle(120, 120, i, dout->color565(rgb.r, rgb.g, rgb.b));
}
hue = hsv.h + 768;
hue %= 1536;
hsv2rgb_8b(hue, 224, 64, &rgb.r, &rgb.g, &rgb.b);
rot += 420 - 69;
int16_t x, y;
int16_t d;
d = rot;
for (uint8_t i = 0; i < strlen(name); i++) {
x = cos1(d);
x = (x >> 9) + (x >> 11) + (x >> 12);
y = sin1(d); // sin1(d) * 21) / 32;
y = (y >> 9) + (y >> 11) + (y >> 12);
rotate_letter(i, d + 0x6000, x, y, dout->color565(rgb.r, rgb.g, rgb.b));
// d -= 9; // for 7-bit version
d -= LETTER_SPACING; // for 15-bit version
}
dout->flush();
}

92
src/sin1.c Normal file
View File

@ -0,0 +1,92 @@
/**
* Example for a sine/cosine table lookup
* Implementation of sin1() / cos1().
* We "outsource" this implementation so that the precompiler constants/macros
* are only defined here.
*
* @file sin1.c
* @author stfwi
**/
#include "sin1.h"
/*
* The number of bits of our data type: here 16 (sizeof operator returns bytes).
*/
#define INT16_BITS (8 * sizeof(int16_t))
#ifndef INT16_MAX
#define INT16_MAX ((1<<(INT16_BITS-1))-1)
#endif
/*
* "5 bit" large table = 32 values. The mask: all bit belonging to the table
* are 1, the all above 0.
*/
#define TABLE_BITS (5)
#define TABLE_SIZE (1<<TABLE_BITS)
#define TABLE_MASK (TABLE_SIZE-1)
/*
* The lookup table is to 90DEG, the input can be -360 to 360 DEG, where negative
* values are transformed to positive before further processing. We need two
* additional bits (*4) to represent 360 DEG:
*/
#define LOOKUP_BITS (TABLE_BITS+2)
#define LOOKUP_MASK ((1<<LOOKUP_BITS)-1)
#define FLIP_BIT (1<<TABLE_BITS)
#define NEGATE_BIT (1<<(TABLE_BITS+1))
#define INTERP_BITS (INT16_BITS-1-LOOKUP_BITS)
#define INTERP_MASK ((1<<INTERP_BITS)-1)
/**
* "5 bit" lookup table for the offsets. These are the sines for exactly
* at 0deg, 11.25deg, 22.5deg etc. The values are from -1 to 1 in Q15.
*/
static int16_t sin90[TABLE_SIZE+1] = {
0x0000,0x0647,0x0c8b,0x12c7,0x18f8,0x1f19,0x2527,0x2b1e,
0x30fb,0x36b9,0x3c56,0x41cd,0x471c,0x4c3f,0x5133,0x55f4,
0x5a81,0x5ed6,0x62f1,0x66ce,0x6a6c,0x6dc9,0x70e1,0x73b5,
0x7640,0x7883,0x7a7c,0x7c29,0x7d89,0x7e9c,0x7f61,0x7fd7,
0x7fff
};
/**
* Sine calculation using interpolated table lookup.
* Instead of radiants or degrees we use "turns" here. Means this
* sine does NOT return one phase for 0 to 2*PI, but for 0 to 1.
* Input: -1 to 1 as int16 Q15 == -32768 to 32767.
* Output: -1 to 1 as int16 Q15 == -32768 to 32767.
*
* See the full description at www.AtWillys.de for the detailed
* explanation.
*
* @param int16_t angle Q15
* @return int16_t Q15
*/
int16_t sin1(int16_t angle)
{
int16_t v0, v1;
if(angle < 0) { angle += INT16_MAX; angle += 1; }
v0 = (angle >> INTERP_BITS);
if(v0 & FLIP_BIT) { v0 = ~v0; v1 = ~angle; } else { v1 = angle; }
v0 &= TABLE_MASK;
v1 = sin90[v0] + (int16_t) (((int32_t) (sin90[v0+1]-sin90[v0]) * (v1 & INTERP_MASK)) >> INTERP_BITS);
if((angle >> INTERP_BITS) & NEGATE_BIT) v1 = -v1;
return v1;
}
/**
* Cosine calculation using interpolated table lookup.
* Instead of radiants or degrees we use "turns" here. Means this
* cosine does NOT return one phase for 0 to 2*PI, but for 0 to 1.
* Input: -1 to 1 as int16 Q15 == -32768 to 32767.
* Output: -1 to 1 as int16 Q15 == -32768 to 32767.
*
* @param int16_t angle Q15
* @return int16_t Q15
*/
int16_t cos1(int16_t angle)
{
if(angle < 0) { angle += INT16_MAX; angle += 1; }
return sin1(angle - (int16_t)(((int32_t)INT16_MAX * 3) / 4));
}

108
src/sin7.c Normal file
View File

@ -0,0 +1,108 @@
/**
* Example for a sine/cosine table lookup
*
* butchered by true to work in 7 bits (int8_t, two turns), and to fix cos8 function
* copied / inspired more or less from
* https://www.atwillys.de/content/cc/sine-lookup-for-embedded-in-c/
**/
#include "sin7.h"
/*
* The number of bits of our data type: here 8 (sizeof operator returns bytes).
*/
#define INT8_BITS (8 * sizeof(int8_t))
#ifndef INT8_MAX
#define INT8_MAX ((1<<(INT8_BITS-1))-1)
#endif
/*
* "5 bit" large table = 32 values. The mask: all bit belonging to the table
* are 1, the all above 0.
*/
#define TABLE_BITS (5)
#define TABLE_SIZE (1<<TABLE_BITS)
#define TABLE_MASK (TABLE_SIZE-1)
/*
* The lookup table is to 90DEG, the input can be -360 to 360 DEG, where negative
* values are transformed to positive before further processing. We need two
* additional bits (*4) to represent 360 DEG:
*/
#define LOOKUP_BITS (TABLE_BITS+2)
#define LOOKUP_MASK ((1<<LOOKUP_BITS)-1)
#define FLIP_BIT (1<<TABLE_BITS)
#define NEGATE_BIT (1<<(TABLE_BITS+1))
#define INTERP_BITS (INT8_BITS-1-LOOKUP_BITS)
#define INTERP_MASK ((1<<INTERP_BITS)-1)
/**
* "5 bit" lookup table for the offsets. These are the sines for exactly
* at 0deg, 11.25deg, 22.5deg etc. The values are from -1 to 1 in Q8?.
*/
static const int8_t sin90[TABLE_SIZE + 1] = {
0x00, 0x06, 0x0c, 0x12, 0x18, 0x1e, 0x24, 0x2a,
0x30, 0x36, 0x3b, 0x41, 0x46, 0x4b, 0x50, 0x55,
0x59, 0x5e, 0x62, 0x66, 0x69, 0x6c, 0x70, 0x72,
0x75, 0x77, 0x79, 0x7b, 0x7c, 0x7d, 0x7e, 0x7e,
0x7f
};
/**
* Sine calculation using interpolated table lookup.
* Instead of radians or degrees we use "turns" here. Means this
* sine does NOT return one phase for 0 to 2*PI, but for 0 to 1.
* Input: -1 to 1 as int8 == -128 to 127
* Output: -1 to 1 as int8 == -128 to 127
*
* @param int8_t angle
* @return int8_t
*/
int8_t sin7(int8_t angle)
{
int8_t v0, v1;
if(angle < 0) {
angle += INT8_MAX;
angle += 1;
}
v0 = (angle >> INTERP_BITS);
if (v0 & FLIP_BIT) {
v0 = ~v0;
v1 = ~angle;
} else {
v1 = angle;
}
v0 &= TABLE_MASK;
v1 = sin90[v0] + (int8_t)(((int16_t)(sin90[v0+1]-sin90[v0]) * (v1 & INTERP_MASK)) >> INTERP_BITS);
if((angle >> INTERP_BITS) & NEGATE_BIT) {
v1 = -v1;
}
return v1;
}
/**
* Cosine calculation using interpolated table lookup.
* Instead of radians or degrees we use "turns" here. Means this
* cosine does NOT return one phase for 0 to 2*PI, but for 0 to 1.
* Input: -1 to 1 as int8 == -128 to 127
* Output: -1 to 1 as int8 == -128 to 127
*
* @param int8_t angle
* @return int8_t
*/
int8_t cos7(int8_t angle)
{
if (angle < 0) {
angle += INT8_MAX;
angle += 1;
}
return sin7(angle - ((INT8_MAX * 3) / 4));
}

11
test/README Normal file
View File

@ -0,0 +1,11 @@
This directory is intended for PlatformIO Test Runner and project tests.
Unit Testing is a software testing method by which individual units of
source code, sets of one or more MCU program modules together with associated
control data, usage procedures, and operating procedures, are tested to
determine whether they are fit for use. Unit testing finds problems early
in the development cycle.
More information about PlatformIO Unit Testing:
- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html

343732
unused/u8g2_fonts.c Normal file

File diff suppressed because it is too large Load Diff

85
unused/u8g2_fonts.h Normal file
View File

@ -0,0 +1,85 @@
/*
u8g2_fonts.h
Several definitions for the fonts, included and required for u8g2_fonts.c.
If the u8g2_fonts.c file is copied from u8g2 project, replace the include
from "u8g2.h" to "u8g2_fonts.h"
U8g2 for Adafruit GFX Lib (https://github.com/olikraus/U8g2_for_Adafruit_GFX)
Copyright (c) 2018, olikraus@gmail.com
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or other
materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _u8g2_fonts_h
#define _u8g2_fonts_h
#include <stdint.h>
#ifdef __GNUC__
# define U8X8_NOINLINE __attribute__((noinline))
# define U8X8_SECTION(name) __attribute__ ((section (name)))
# define U8X8_UNUSED __attribute__((unused))
#else
# define U8X8_SECTION(name)
# define U8X8_NOINLINE
# define U8X8_UNUSED
#endif
#if defined(__GNUC__) && defined(__AVR__)
# define U8X8_FONT_SECTION(name) U8X8_SECTION(".progmem." name)
# define u8x8_pgm_read(adr) pgm_read_byte_near(adr)
# define U8X8_PROGMEM PROGMEM
#endif
#ifndef U8X8_FONT_SECTION
# define U8X8_FONT_SECTION(name)
#endif
#ifndef u8x8_pgm_read
# define u8x8_pgm_read(adr) (*(const uint8_t *)(adr))
#endif
#ifndef U8X8_PROGMEM
# define U8X8_PROGMEM
#endif
#define U8G2_FONT_SECTION(name) U8X8_FONT_SECTION(name)
/* the macro U8G2_USE_LARGE_FONTS enables large fonts (>32K) */
/* it can be enabled for those uC supporting larger arrays */
#if defined(unix) || defined(__arm__) || defined(__arc__) || defined(ESP8266) || defined(ESP_PLATFORM)
#ifndef U8G2_USE_LARGE_FONTS
#define U8G2_USE_LARGE_FONTS
#endif
#endif
#endif /* _u8g2_fonts_h */