240 lines
7.7 KiB
C
240 lines
7.7 KiB
C
|
|
/*
|
|
Copyright (C) 2020 Ein Terakawa
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
#include "hal.h"
|
|
#include "ssd1306.h"
|
|
|
|
static const uint8_t logo_bits[] = {
|
|
0x00, 0x00, 0x00, 0x80, 0xF0, 0xF8, 0xFC, 0xFC,
|
|
0xFE, 0x3E, 0x1E, 0x1E, 0x7E, 0x7C, 0x7C, 0x78,
|
|
0x70, 0x40, 0x00, 0x00, 0xFE, 0xFE, 0xFE, 0xFE,
|
|
0xFE, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xC0, 0x00,
|
|
0x00, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0x00, 0x00,
|
|
0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xC0, 0xE0, 0xE0,
|
|
0xE0, 0xC0, 0x00, 0x00, 0xEE, 0xEE, 0xEE, 0xEE,
|
|
0xEE, 0x00, 0x80, 0xF0, 0xF8, 0xFC, 0xFC, 0xFE,
|
|
0x1E, 0x1E, 0x1E, 0xFE, 0xFC, 0xFC, 0xF8, 0xF0,
|
|
0x80, 0x60, 0xF8, 0xFC, 0xFC, 0xFE, 0xFE, 0xDE,
|
|
0x9E, 0xBE, 0xBC, 0xBC, 0x38, 0x20, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x01, 0x0F, 0x1F, 0x3F, 0x3F,
|
|
0x7F, 0x7C, 0x78, 0x78, 0x7E, 0x3E, 0x3E, 0x3E,
|
|
0x0E, 0x02, 0x00, 0x00, 0x7F, 0x7F, 0x7F, 0x7F,
|
|
0x7F, 0x00, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x00,
|
|
0x00, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x00, 0x00,
|
|
0x7F, 0x7F, 0x7F, 0x7F, 0x1F, 0x79, 0x7F, 0x7F,
|
|
0x7F, 0x3F, 0x0F, 0x00, 0x7F, 0x7F, 0x7F, 0x7F,
|
|
0x7F, 0x00, 0x01, 0x0F, 0x1F, 0x3F, 0x3F, 0x7F,
|
|
0x78, 0x78, 0x78, 0x7F, 0x3F, 0x3F, 0x1F, 0x0F,
|
|
0x01, 0x04, 0x1C, 0x3D, 0x3D, 0x7D, 0x79, 0x7B,
|
|
0x7B, 0x7F, 0x7F, 0x3F, 0x1F, 0x0C, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0xFE, 0xFE,
|
|
0xFE, 0xFE, 0xF8, 0xC0, 0xFE, 0xFE, 0xFE, 0xFE,
|
|
0xFE, 0x00, 0x00, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
|
|
0xFE, 0x00, 0x00, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
|
|
0xFE, 0x00, 0x80, 0xF0, 0xF8, 0xFC, 0xFC, 0xFE,
|
|
0x3E, 0x1E, 0x1E, 0x7E, 0x7C, 0x7C, 0x78, 0x70,
|
|
0x40, 0x00, 0x38, 0x38, 0x38, 0xFE, 0xFE, 0xFE,
|
|
0xFE, 0xFE, 0xFE, 0x00, 0x00, 0x20, 0x38, 0x3C,
|
|
0x3C, 0x3E, 0x9E, 0x9E, 0xFE, 0xFE, 0xFC, 0xF8,
|
|
0x70, 0x00, 0x20, 0x38, 0x3C, 0xFC, 0xFE, 0xDE,
|
|
0xDE, 0xFE, 0xFE, 0x7C, 0x78, 0x20, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x7F, 0x7F, 0x7F, 0x7F,
|
|
0x7F, 0x01, 0x07, 0x1F, 0x7F, 0x7F, 0x7F, 0x7F,
|
|
0x7F, 0x00, 0x00, 0x03, 0x0F, 0x1F, 0x3F, 0x7F,
|
|
0x7F, 0x7C, 0x7C, 0x7F, 0x7F, 0x3F, 0x3F, 0x1F,
|
|
0x03, 0x00, 0x01, 0x0F, 0x1F, 0x3F, 0x3F, 0x7F,
|
|
0x7C, 0x78, 0x78, 0x7E, 0x3E, 0x3E, 0x3E, 0x0E,
|
|
0x02, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x7F, 0x7F,
|
|
0x7F, 0x7F, 0x7F, 0x00, 0x00, 0x70, 0x7C, 0x7E,
|
|
0x7F, 0x7F, 0x7F, 0x7F, 0x7B, 0x7B, 0x79, 0x79,
|
|
0x78, 0x00, 0x04, 0x1C, 0x3C, 0x7D, 0x79, 0x79,
|
|
0x79, 0x7F, 0x7F, 0x3F, 0x3F, 0x0E, 0x00, 0x00,
|
|
};
|
|
|
|
static void draw_logo(SSD1306_DRIVER *ssd1306, bool invert, char xx) {
|
|
uint8_t width = ssd1306->width;
|
|
uint8_t height = ssd1306->height;
|
|
uint8_t num_pages = height / 8;
|
|
uint8_t invert_bits = invert ? 0xff : 0x00;
|
|
uint8_t *buf = SSD1306_GET_FRAMEBUFFER(ssd1306);
|
|
|
|
for (uint8_t row = 0; row < num_pages; ++row) {
|
|
for (uint8_t x = 0; x < width; ++x) {
|
|
uint8_t dat = logo_bits[(128 - xx + x) % 128 + (row % 4) * width];
|
|
if (row / 2 % 2 == 0) {
|
|
dat ^= 0xff;
|
|
}
|
|
dat ^= invert_bits; /* Invert Imeage Bits */
|
|
if (true) {
|
|
/* Horizontal Addressing Mode */
|
|
buf[row * width + x] = dat;
|
|
} else {
|
|
/* Vertical Addressing Mode */
|
|
buf[x * num_pages + row] = dat;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#define I2C_CLK_FREQ 1000000
|
|
static const I2CConfig i2ccfg = { I2C_CLK_FREQ };
|
|
#if NUC123_I2C_USE_I2C0
|
|
DEFINE_SSD1306_DRIVER(ssd1306_128x64, &I2CD0, SSD1306_ADDRESS, 128, 64, false);
|
|
#endif
|
|
#if NUC123_I2C_USE_I2C1
|
|
DEFINE_SSD1306_DRIVER(ssd1306_128x32, &I2CD1, SSD1306_ADDRESS, 128, 32, true);
|
|
#endif
|
|
|
|
#if I2C_USE_MUTUAL_EXCLUSION
|
|
#define ACQUIRE_BUS(oled_driver) i2cAcquireBus((oled_driver)->i2cd)
|
|
#define RELEASE_BUS(oled_driver) i2cReleaseBus((oled_driver)->i2cd)
|
|
#else
|
|
#define ACQUIRE_BUS(oled_driver)
|
|
#define RELEASE_BUS(oled_driver)
|
|
#endif
|
|
|
|
thread_reference_t thread1_ref = NULL;
|
|
|
|
static THD_WORKING_AREA(waThread1, 128);
|
|
static THD_FUNCTION(Thread1, arg) {
|
|
chRegSetThreadName("blinker");
|
|
|
|
(void)arg;
|
|
while (true) {
|
|
if(osalThreadSuspendS(&thread1_ref) == MSG_OK) {
|
|
OnboardLED_On();
|
|
}else{
|
|
OnboardLED_Off();
|
|
}
|
|
}
|
|
}
|
|
|
|
#define I2C_THREAD_STACK_SIZE 256
|
|
#if NUC123_I2C_USE_I2C0
|
|
static THD_WORKING_AREA(waThread2, I2C_THREAD_STACK_SIZE);
|
|
static THD_FUNCTION(Thread2, arg) {
|
|
chRegSetThreadName("oled1");
|
|
|
|
SSD1306_DRIVER *ssd1306 = (SSD1306_DRIVER *)arg;
|
|
ssd1306->i2ccfg = &i2ccfg;
|
|
ACQUIRE_BUS(ssd1306);
|
|
ssd1306_init(ssd1306);
|
|
RELEASE_BUS(ssd1306);
|
|
char x = 0;
|
|
while (true) {
|
|
osalThreadSleepMilliseconds(127);
|
|
bool invert = false;
|
|
draw_logo(ssd1306, invert, x);
|
|
ACQUIRE_BUS(ssd1306);
|
|
ssd1306_data(ssd1306);
|
|
/* RELEASE_BUS(ssd1306); */
|
|
/* ACQUIRE_BUS(ssd1306); */
|
|
if (x % 16 == 12) {
|
|
ssd1306_display_off(ssd1306);
|
|
} else if (x % 16 == 0) {
|
|
ssd1306_display_on(ssd1306);
|
|
}
|
|
RELEASE_BUS(ssd1306);
|
|
x = (x + 1) % 128;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if NUC123_I2C_USE_I2C1
|
|
static THD_WORKING_AREA(waThread3, I2C_THREAD_STACK_SIZE);
|
|
static THD_FUNCTION(Thread3, arg) {
|
|
chRegSetThreadName("oled2");
|
|
|
|
SSD1306_DRIVER *ssd1306 = (SSD1306_DRIVER *)arg;
|
|
ssd1306->i2ccfg = &i2ccfg;
|
|
ACQUIRE_BUS(ssd1306);
|
|
#if true
|
|
/* Workaround for some 128x32 OLED modules typically with black PCB. */
|
|
while (!ssd1306_init(ssd1306)) {
|
|
RELEASE_BUS(ssd1306);
|
|
osalThreadSleepMilliseconds(100);
|
|
ACQUIRE_BUS(ssd1306);
|
|
}
|
|
#endif
|
|
ssd1306_init(ssd1306);
|
|
RELEASE_BUS(ssd1306);
|
|
char x = 0;
|
|
while (true) {
|
|
osalThreadSleepMilliseconds(131);
|
|
bool invert = true;
|
|
draw_logo(ssd1306, invert, x);
|
|
ACQUIRE_BUS(ssd1306);
|
|
ssd1306_data(ssd1306);
|
|
RELEASE_BUS(ssd1306);
|
|
x = (x - 1) % 128;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* Application entry point.
|
|
*/
|
|
int main(void) {
|
|
|
|
/*
|
|
* System initializations.
|
|
* - HAL initialization, this also initializes the configured device drivers
|
|
* and performs the board-specific initializations.
|
|
*/
|
|
halInit();
|
|
|
|
/*
|
|
* chSysInit() will also enable interrupts.
|
|
*/
|
|
chSysInit();
|
|
|
|
chThdCreateStatic(waThread1, sizeof(waThread1), NORMALPRIO + 2, Thread1, NULL);
|
|
#if NUC123_I2C_USE_I2C0
|
|
chThdCreateStatic(waThread2, sizeof(waThread2), NORMALPRIO + 1, Thread2, &ssd1306_128x64);
|
|
#endif
|
|
#if NUC123_I2C_USE_I2C1
|
|
chThdCreateStatic(waThread3, sizeof(waThread3), NORMALPRIO + 1, Thread3, &ssd1306_128x32);
|
|
#endif
|
|
|
|
while (true) {
|
|
osalThreadResumeS(&thread1_ref, MSG_OK);
|
|
osalThreadSleepMilliseconds(100);
|
|
osalThreadResumeS(&thread1_ref, MSG_RESET);
|
|
osalThreadSleepMilliseconds(400);
|
|
}
|
|
}
|