Happy times: things work on real hardware!
This commit is contained in:
@@ -19,6 +19,8 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include "DisplayDriver.h"
|
||||
#include "macros.h"
|
||||
#include "font.h"
|
||||
@@ -51,11 +53,11 @@ NextTime DisplayDriver::execute()
|
||||
void DisplayDriver::buffer_init()
|
||||
{
|
||||
for (size_t i = 0; i < ARRAY_SIZE(m_buffer.lines); i++) {
|
||||
struct display_line *line = &m_buffer.lines[i];
|
||||
line->mode = 1; // Update display
|
||||
line->line = i + 1; // Line numbers start at 1
|
||||
for (size_t j = 0; j < ARRAY_SIZE(line->data); j++) {
|
||||
line->data[j] = 0xFF;
|
||||
struct display_line &line = m_buffer.lines[i];
|
||||
line.mode = 1; // Update display
|
||||
line.line = i + 1; // Line numbers start at 1
|
||||
for (size_t j = 0; j < ARRAY_SIZE(line.data); j++) {
|
||||
line.data[j] = 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,8 +82,8 @@ void DisplayDriver::set_bit(unsigned int x, unsigned int y, uint8_t val)
|
||||
return;
|
||||
}
|
||||
|
||||
struct display_line *line = &m_buffer.lines[y];
|
||||
uint8_t *byte = &line->data[x >> 3];
|
||||
struct display_line &line = m_buffer.lines[y];
|
||||
uint8_t *byte = &line.data[x >> 3];
|
||||
if (val) {
|
||||
CLR_POS(*byte, x & 7);
|
||||
} else {
|
||||
@@ -93,19 +95,172 @@ void DisplayDriver::set_bit(unsigned int x, unsigned int y, uint8_t val)
|
||||
|
||||
void DisplayDriver::set_byte(unsigned int x, unsigned int y, uint8_t val)
|
||||
{
|
||||
if (x >= DISPLAY_WIDTH || y >= DISPLAY_HEIGHT) {
|
||||
return;
|
||||
}
|
||||
// if (x >= DISPLAY_WIDTH || y >= DISPLAY_HEIGHT) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
if (x & 7) {
|
||||
return;
|
||||
}
|
||||
// if (x & 7) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
struct display_line *line = &m_buffer.lines[y];
|
||||
line->data[x >> 3] = val;
|
||||
struct display_line &line = m_buffer.lines[y];
|
||||
line.data[x >> 3] = val;
|
||||
set_dirty(y);
|
||||
}
|
||||
|
||||
|
||||
// TODO: write my own implementation
|
||||
#define R2(n) n, n + 2*64, n + 1*64, n + 3*64
|
||||
#define R4(n) R2(n), R2(n + 2*16), R2(n + 1*16), R2(n + 3*16)
|
||||
#define R6(n) R4(n), R4(n + 2*4 ), R4(n + 1*4 ), R4(n + 3*4 )
|
||||
|
||||
static const unsigned char BitReverseTable256[256] =
|
||||
{
|
||||
R6(0), R6(2), R6(1), R6(3)
|
||||
};
|
||||
|
||||
unsigned char ReverseBitsLookupTable(unsigned char v)
|
||||
{
|
||||
return BitReverseTable256[v];
|
||||
}
|
||||
|
||||
/**
|
||||
* This variant is ~4x faster than the unaligned version, but
|
||||
* (obviously) requires that everything is aligned correctly.
|
||||
*/
|
||||
|
||||
void DisplayDriver::clear_glyph_aligned(int x_off, int y_off, const struct font *, const struct glyph *g)
|
||||
{
|
||||
for (int16_t y = y_off; y < y_off + g->rows && y < DISPLAY_HEIGHT; y++) {
|
||||
uint8_t *start = (uint8_t *) &m_buffer.lines[y].data[(x_off) >> 3];
|
||||
uint8_t *end = (uint8_t *) &m_buffer.lines[y].data[(x_off + g->advance) >> 3];
|
||||
memset(start, 0xFF, end - start);
|
||||
}
|
||||
}
|
||||
|
||||
// void DisplayDriver::bit_copy(uint8_t *src, unsigned int src_bit_offset,
|
||||
// uint8_t *dst, unsigned int dst_bit_offset,
|
||||
// unsigned int bit_len)
|
||||
// {
|
||||
// uint8_t buffer;
|
||||
|
||||
// if (src_bit_offset == && dst_bit_offset == 0) {
|
||||
// /* The "happy" case, where both src and dst are byte-aligned */
|
||||
// unsigned int byte_count = bit_len / 8;
|
||||
// memcpy(dst, src, byte_count);
|
||||
// if (bit_len & 7) {
|
||||
// uint8_t mask = (1 << bit_len & 7) - 1;
|
||||
// dst[byte_count] &= ~mask;
|
||||
// dst[byte_count] |= mask & src[byte_count];
|
||||
// }
|
||||
// return;
|
||||
// }
|
||||
|
||||
// if (bit_len >= 8) {
|
||||
|
||||
// // Start the initial byte
|
||||
// buffer = *(src++) >> src_bit_offset;
|
||||
// buffer |= *(src) << (8 - src_bit_offset);
|
||||
|
||||
|
||||
// // The main copy loop
|
||||
|
||||
|
||||
// // Set the last byte/bits
|
||||
|
||||
// }
|
||||
|
||||
// for (bits_copied = 0; bits_copied + 8 < bit_len; bits_copied += 8) {
|
||||
// *dst
|
||||
// }
|
||||
|
||||
// }
|
||||
|
||||
void DisplayDriver::clear_glyph_unaligned(int x_off, int y_off, const struct font *font, const struct glyph *g)
|
||||
{
|
||||
int16_t x = 0;
|
||||
if (x & 7) {
|
||||
while ((x & 7) && x < g->advance) {
|
||||
// TODO: use a switch on (x & 7) instead?
|
||||
for (int16_t y = 0; y < g->rows && y < DISPLAY_HEIGHT; y++) {
|
||||
set_bit(x_off + x, y_off + y + font->size - g->top, 0);
|
||||
}
|
||||
x++;
|
||||
}
|
||||
}
|
||||
|
||||
while (g->advance - x > 0) {
|
||||
for (int16_t y = 0; y < g->rows && y < DISPLAY_HEIGHT; y++) {
|
||||
set_bit(x_off + x, y_off + y + font->size - g->top, 0);
|
||||
}
|
||||
x++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void DisplayDriver::write_glyph_unaligned(int x_off, int y_off, const struct font *font, const struct glyph *g)
|
||||
{
|
||||
int byte_cols = g->cols / 8;
|
||||
if (g->cols & 7) {
|
||||
byte_cols++;
|
||||
}
|
||||
|
||||
for (size_t x = 0; x < g->cols; x++) {
|
||||
for (size_t y = 0; y < g->rows && y < DISPLAY_HEIGHT; y++) {
|
||||
int byte_x = x / 8;
|
||||
int byte_y = y;
|
||||
uint8_t bit = (g->bitmap[byte_y * byte_cols + byte_x] >> (7 - (x & 7))) & 1;
|
||||
set_bit(g->left + x_off + x,
|
||||
y_off + y + font->size - g->top,
|
||||
bit);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// void DisplayDriver::write_glyph_unaligned2(int *x_off, int y_off, const struct font *font, const struct glyph *g)
|
||||
// {
|
||||
// int byte_cols = g->cols / 8;
|
||||
// if (g->cols & 7) {
|
||||
// byte_cols++;
|
||||
// }
|
||||
|
||||
// for (size_t x = 0; x < g->cols; x++) {
|
||||
// for (size_t y = 0; y < g->rows && y < DISPLAY_HEIGHT; y++) {
|
||||
// int byte_x = x / 8;
|
||||
// int byte_y = y;
|
||||
// uint8_t bit = (g->bitmap[byte_y * byte_cols + byte_x] >> (7 - (x & 7))) & 1;
|
||||
// set_bit(g->left + *x_off + x, y_off + y + font->size - g->top, bit);
|
||||
// }
|
||||
// }
|
||||
|
||||
// }
|
||||
|
||||
/**
|
||||
* This variant is ~4x faster than the unaligned version, but
|
||||
* requires that everything is aligned correctly.
|
||||
*/
|
||||
void DisplayDriver::write_glyph_aligned(int x_off, int y_off,
|
||||
const struct font *font, const struct glyph *g)
|
||||
{
|
||||
int byte_cols = g->cols / 8;
|
||||
if (g->cols & 7) {
|
||||
byte_cols++;
|
||||
}
|
||||
|
||||
|
||||
for (size_t x = 0; x < g->cols; x += 8) {
|
||||
for (size_t y = 0, byte_y = 0; y < g->rows && y < DISPLAY_HEIGHT; y++, byte_y += byte_cols) {
|
||||
int byte_x = x / 8;
|
||||
uint8_t byte = g->bitmap[byte_y + byte_x];
|
||||
set_byte(g->left + x_off + x,
|
||||
y_off + y + font->size - g->top,
|
||||
~ReverseBitsLookupTable(byte));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DisplayDriver::char_at(int *x_off, int y_off, char c, const struct font *font)
|
||||
{
|
||||
const struct glyph *g = glyph_for_char(font, c);
|
||||
@@ -113,34 +268,22 @@ void DisplayDriver::char_at(int *x_off, int y_off, char c, const struct font *fo
|
||||
return;
|
||||
}
|
||||
|
||||
int byte_cols = g->cols / 8;
|
||||
if (g->cols & 7) {
|
||||
byte_cols++;
|
||||
}
|
||||
if (byte_cols & 1) {
|
||||
byte_cols++;
|
||||
if (!(*x_off & 7) && !((*x_off + g->advance) & 7)) {
|
||||
clear_glyph_aligned(*x_off, y_off, font, g);
|
||||
} else {
|
||||
clear_glyph_unaligned(*x_off, y_off, font, g);
|
||||
}
|
||||
|
||||
for (size_t x = 0; x < g->left; x++) {
|
||||
for (size_t y = 0; y < g->rows; y++) {
|
||||
set_bit(*x_off + x, y_off + y + font->size - g->top, 0);
|
||||
}
|
||||
// TODO: Check the right glyph boundary (g->left + g->cols)
|
||||
if (!((*x_off + g->left) & 7)) {
|
||||
write_glyph_aligned(*x_off, y_off, font, g);
|
||||
} else {
|
||||
write_glyph_unaligned(*x_off, y_off, font, g);
|
||||
}
|
||||
|
||||
for (size_t x = g->left + g->cols; x < g->advance; x++) {
|
||||
for (size_t y = 0; y < g->rows; y++) {
|
||||
set_bit(*x_off + x, y_off + y + font->size - g->top, 0);
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t x = 0; x < g->cols; x++) {
|
||||
for (size_t y = 0; y < g->rows; y++) {
|
||||
int byte_x = x / 8;
|
||||
int byte_y = y;
|
||||
uint8_t bit = (g->bitmap[byte_y * byte_cols + byte_x] >> (7 - (x & 7))) & 1;
|
||||
set_bit(g->left + *x_off + x, y_off + y + font->size - g->top, bit);
|
||||
}
|
||||
}
|
||||
m_dirty_line_min = MIN(m_dirty_line_min, y_off);
|
||||
m_dirty_line_max = MAX(m_dirty_line_max, y_off + g->rows);
|
||||
m_is_dirty = true;
|
||||
*x_off += g->advance;
|
||||
}
|
||||
|
||||
@@ -167,6 +310,8 @@ void DisplayDriver::refresh()
|
||||
|
||||
m_spi.tx_blocking(start, size);
|
||||
m_is_dirty = false;
|
||||
m_dirty_line_min = DISPLAY_HEIGHT - 1;
|
||||
m_dirty_line_max = 0;
|
||||
}
|
||||
|
||||
void DisplayDriver::clear()
|
||||
|
||||
@@ -61,6 +61,10 @@ private:
|
||||
void buffer_init();
|
||||
void set_dirty(unsigned int y);
|
||||
const struct glyph *glyph_for_char(const struct font *font, char c);
|
||||
void clear_glyph_aligned(int x_off, int y_off, const struct font * font, const struct glyph *g);
|
||||
void clear_glyph_unaligned(int x_off, int y_off, const struct font * font, const struct glyph *g);
|
||||
void write_glyph_aligned(int x_off, int y_off, const struct font * font, const struct glyph *g);
|
||||
void write_glyph_unaligned(int x_off, int y_off, const struct font * font, const struct glyph *g);
|
||||
|
||||
static constexpr uint32_t DISPLAY_WIDTH = 144;
|
||||
static constexpr uint32_t DISPLAY_HEIGHT = 168;
|
||||
|
||||
@@ -22,15 +22,15 @@
|
||||
#include "DisplayTimeTask.h"
|
||||
#include "SystemTime.h"
|
||||
|
||||
#include "font-notomono-24.h"
|
||||
#include "font-notomono-64.h"
|
||||
#include "font-notomono-29.h"
|
||||
#include "font-notomono-68.h"
|
||||
|
||||
using Common::ReturnCode;
|
||||
using Common::Time;
|
||||
using Common::Schedule::NextTime;
|
||||
|
||||
static const font &font_large = font_notomono_64;
|
||||
static const font &font_default = font_notomono_24;
|
||||
static const font &font_large = font_notomono_68;
|
||||
static const font &font_default = font_notomono_29;
|
||||
|
||||
DisplayTimeTask::DisplayTimeTask(BSP::DisplayDriver &driver)
|
||||
: m_driver(driver)
|
||||
@@ -50,6 +50,13 @@ static char get_char_for_digit(uint8_t bcd_digit)
|
||||
|
||||
ReturnCode DisplayTimeTask::init()
|
||||
{
|
||||
|
||||
SET_TO(GPIOA->MODER, GPIO_MODER_MODE0, 1u << GPIO_MODER_MODE1_Pos);
|
||||
|
||||
GPIOA->OTYPER &= ~GPIO_OTYPER_OT_1;
|
||||
GPIOA->PUPDR &= ~GPIO_PUPDR_PUPD1;
|
||||
GPIOA->PUPDR |= 2u << GPIO_PUPDR_PUPD1_Pos;
|
||||
|
||||
return ReturnCode::OK;
|
||||
}
|
||||
|
||||
@@ -66,9 +73,6 @@ void DisplayTimeTask::display_number(uint32_t x, uint32_t y, uint32_t tens, uint
|
||||
|
||||
void DisplayTimeTask::display_time()
|
||||
{
|
||||
uint32_t width = m_driver.get_width();
|
||||
uint32_t height = m_driver.get_height();
|
||||
|
||||
BSP::time_bcd time;
|
||||
BSP::RtcDriver::get_time(time);
|
||||
|
||||
@@ -78,40 +82,57 @@ void DisplayTimeTask::display_time()
|
||||
|
||||
int i = 0;
|
||||
|
||||
SET(GPIOA->ODR, GPIO_ODR_OD1);
|
||||
CLR(GPIOA->ODR, GPIO_ODR_OD1);
|
||||
|
||||
if (m_last_time.hour_tens != time.hour_tens ||
|
||||
m_last_time.hour_ones != time.hour_ones ||
|
||||
!m_has_cleared) {
|
||||
display_number(0, (i * font_large.size) + (i + 1) * 4, time.hour_tens, time.hour_ones, font_large);
|
||||
display_number(8, (i * font_default.size) + (i + 1) * 4, time.hour_tens, time.hour_ones, font_default);
|
||||
}
|
||||
|
||||
SET(GPIOA->ODR, GPIO_ODR_OD1);
|
||||
CLR(GPIOA->ODR, GPIO_ODR_OD1);
|
||||
|
||||
i++;
|
||||
if (m_last_time.minute_tens != time.minute_tens ||
|
||||
m_last_time.minute_ones != time.minute_ones ||
|
||||
!m_has_cleared) {
|
||||
display_number(0, (i * font_large.size) + (i + 1) * 4, time.minute_tens, time.minute_ones, font_large);
|
||||
display_number(8, (i * font_default.size) + (i + 1) * 4, time.minute_tens, time.minute_ones, font_default);
|
||||
}
|
||||
|
||||
SET(GPIOA->ODR, GPIO_ODR_OD1);
|
||||
CLR(GPIOA->ODR, GPIO_ODR_OD1);
|
||||
|
||||
i++;
|
||||
if (m_display_seconds) {
|
||||
if (m_last_time.second_tens != time.second_tens ||
|
||||
m_last_time.second_ones != time.second_ones ||
|
||||
!m_has_cleared) {
|
||||
display_number(0, (i * font_large.size) + (i + 1) * 4, time.second_tens, time.second_ones, font_default);
|
||||
display_number(8, (i * font_default.size) + (i + 1) * 4, time.second_tens, time.second_ones, font_default);
|
||||
}
|
||||
}
|
||||
|
||||
m_has_cleared = true;
|
||||
// m_has_cleared = true;
|
||||
m_last_time = time;
|
||||
|
||||
SET(GPIOA->ODR, GPIO_ODR_OD1);
|
||||
CLR(GPIOA->ODR, GPIO_ODR_OD1);
|
||||
|
||||
m_driver.refresh();
|
||||
|
||||
SET(GPIOA->ODR, GPIO_ODR_OD1);
|
||||
CLR(GPIOA->ODR, GPIO_ODR_OD1);
|
||||
}
|
||||
|
||||
NextTime DisplayTimeTask::execute()
|
||||
{
|
||||
display_time();
|
||||
|
||||
Common::time_t now;
|
||||
BSP::SystemTimer::get_time(now);
|
||||
uint32_t next_secs = Time::to_seconds(now) + 1;
|
||||
|
||||
display_time();
|
||||
|
||||
return NextTime::at(Time::seconds(next_secs));
|
||||
}
|
||||
|
||||
@@ -46,5 +46,4 @@ private:
|
||||
BSP::time_bcd m_last_time;
|
||||
|
||||
const bool m_display_seconds;
|
||||
|
||||
};
|
||||
|
||||
@@ -32,7 +32,8 @@ using Common::ReturnCode;
|
||||
ReturnCode LowPower::init()
|
||||
{
|
||||
/* Enable Clocks */
|
||||
SET(RCC->APB1ENR, RCC_APB1ENR_PWREN);
|
||||
SET(RCC->APB2ENR, RCC_APB2ENR_DBGEN);
|
||||
SET(RCC->APB2SMENR, RCC_APB2SMENR_DBGSMEN);
|
||||
|
||||
// FIXME: Make these configurable, will mess with power consumption
|
||||
SET(DBGMCU->CR, DBGMCU_CR_DBG_STOP);
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Max Regan
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Task.h"
|
||||
#include "LowPower.h"
|
||||
|
||||
class LowPowerDelay : public Common::Schedule::Task {
|
||||
|
||||
public:
|
||||
LowPowerDelay()
|
||||
: m_is_first(true)
|
||||
{}
|
||||
Common::Schedule::NextTime execute() {
|
||||
|
||||
if (m_is_first) {
|
||||
m_is_first = false;
|
||||
} else {
|
||||
BSP::LowPower::stop();
|
||||
}
|
||||
|
||||
return Common::Schedule::NextTime::in(Common::Time::millis(200));
|
||||
}
|
||||
|
||||
private:
|
||||
bool m_is_first;
|
||||
};
|
||||
41
Main.cpp.bak
41
Main.cpp.bak
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Max Regan
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
// TODO: Make a better "system" include
|
||||
#include "stm32l0xx.h"
|
||||
|
||||
#include "ConcreteTaskScheduler.h"
|
||||
#include "SpiDriver.h"
|
||||
#include "DisplayDriver.h"
|
||||
|
||||
using Common::Schedule::TaskScheduler;
|
||||
|
||||
static Common::Schedule::ConcreteTaskScheduler<10> g_scheduler;
|
||||
static BSP::SpiDriver g_spi1(g_scheduler, SPI1);
|
||||
static BSP::DisplayDriver g_display(g_scheduler, g_spi1);
|
||||
|
||||
[[noreturn]] void main()
|
||||
{
|
||||
g_spi1.init();
|
||||
g_display.init();
|
||||
g_scheduler.run();
|
||||
}
|
||||
4
Makefile
4
Makefile
@@ -78,7 +78,7 @@ CPU_FLAGS = -mthumb -mcpu=cortex-m0 -mfloat-abi=soft
|
||||
# C pedantism
|
||||
CFLAGS = -Wall -Wextra -Wpedantic
|
||||
# Debug/optimization
|
||||
CFLAGS += -ggdb -g3 -Os
|
||||
CFLAGS += -Os -ggdb -g3
|
||||
CFLAGS += -fdata-sections -ffunction-sections
|
||||
# Architecture
|
||||
CFLAGS += $(CPU_FLAGS)
|
||||
@@ -141,7 +141,7 @@ STM32FLASH_DEVICE = /dev/ttyUSB0
|
||||
.PHONY: flash
|
||||
flash: $(OUTPUT_BIN)
|
||||
@echo "FLASH $(OUTPUT_BIN)"
|
||||
$(STM32_PROG) --connect port=SWD reset=Hwrst -w $(OUTPUT_BIN) 0x8000000 -v --go
|
||||
$(STM32_PROG) -vb 3 --connect port=SWD reset=Hwrst -w $(OUTPUT_BIN) 0x8000000 -v --go
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
|
||||
@@ -38,7 +38,7 @@ void RtcDriver::enable_rtc_write()
|
||||
|
||||
void RtcDriver::disable_rtc_write()
|
||||
{
|
||||
/*<! Disable write protection */
|
||||
/*<! Enable write protection */
|
||||
RTC->WPR = 0x00;
|
||||
}
|
||||
|
||||
@@ -47,10 +47,14 @@ void RtcDriver::enable_periodic_alarm()
|
||||
|
||||
SET(RTC->ALRMAR, RTC_ALRMAR_MSK4 | RTC_ALRMAR_MSK3 | RTC_ALRMAR_MSK2 | RTC_ALRMAR_MSK1);
|
||||
|
||||
SET(RTC->ALRMASSR, RTC_ALRMASSR_MASKSS);
|
||||
CLR(RTC->ALRMASSR, RTC_ALRMASSR_SS);
|
||||
// Only calculate alarms when second rolls over
|
||||
SET_TO(RTC->ALRMASSR, RTC_ALRMASSR_MASKSS, 0);
|
||||
|
||||
SET(RTC->CR, RTC_CR_ALRAE | RTC_CR_ALRAIE);
|
||||
SET(EXTI->IMR, EXTI_IMR_IM17);
|
||||
SET(EXTI->EMR, EXTI_EMR_EM17);
|
||||
SET(EXTI->RTSR, EXTI_RTSR_RT17);
|
||||
|
||||
SET(RTC->CR, RTC_CR_ALRAE);
|
||||
}
|
||||
|
||||
ReturnCode RtcDriver::init_hw()
|
||||
@@ -226,14 +230,12 @@ void RtcDriver::increment_seconds()
|
||||
|
||||
extern "C" void RTC_IRQHandler()
|
||||
{
|
||||
// Clear the interrupt in the EXTI
|
||||
SET(EXTI->PR, EXTI_PR_PIF20);
|
||||
// Clear the wakeup and alarm interrupts in the EXTI
|
||||
SET(EXTI->PR, EXTI_PR_PIF20 | EXTI_PR_PIF17);
|
||||
|
||||
if (RTC->ISR & RTC_ISR_ALRAF) {
|
||||
RtcDriver::increment_seconds();
|
||||
|
||||
CLR(RTC->ISR, RTC_ISR_ALRAF);
|
||||
|
||||
}
|
||||
|
||||
if (RTC->ISR & RTC_ISR_WUTF) {
|
||||
|
||||
@@ -37,25 +37,24 @@ SpiDriver::SpiDriver(TaskScheduler &scheduler)
|
||||
void SpiDriver::init()
|
||||
{
|
||||
SET(RCC->IOPENR, RCC_IOPENR_IOPAEN);
|
||||
SET(RCC->IOPENR, RCC_IOPENR_IOPBEN);
|
||||
RCC->APB2ENR |= RCC_APB2ENR_SPI1EN;
|
||||
|
||||
/* Assign SPI_MOSI to PA12 (AFRH5), since PA7 is taken by LPTIM_OUT */
|
||||
GPIOA->AFR[1] &= ~GPIO_AFRH_AFRH4;
|
||||
/* Assign SPI_MOSI to PB1, since PA7 is taken by LPTIM_OUT */
|
||||
GPIOB->AFR[0] &= ~GPIO_AFRH_AFRH1;
|
||||
GPIOB->AFR[0] |= 1u << GPIO_AFRH_AFRH1_Pos;
|
||||
|
||||
SET_TO(GPIOA->MODER, GPIO_MODER_MODE12, 2u << GPIO_MODER_MODE12_Pos);
|
||||
SET_TO(GPIOB->MODER, GPIO_MODER_MODE1, 2u << GPIO_MODER_MODE1_Pos);
|
||||
|
||||
GPIOA->OTYPER &= ~GPIO_OTYPER_OT_12;
|
||||
GPIOA->PUPDR &= ~GPIO_PUPDR_PUPD12;
|
||||
GPIOB->OTYPER &= ~GPIO_OTYPER_OT_1;
|
||||
GPIOB->PUPDR &= ~GPIO_PUPDR_PUPD12;
|
||||
|
||||
// SPI1 NSS (PA4)
|
||||
//GPIOA->AFR[0] &= ~GPIO_AFRL_AFRL4;
|
||||
|
||||
SET_TO(GPIOA->MODER, GPIO_MODER_MODE4, 1u << GPIO_MODER_MODE4_Pos);
|
||||
|
||||
GPIOA->OTYPER &= ~GPIO_OTYPER_OT_4;
|
||||
GPIOA->PUPDR &= ~GPIO_PUPDR_PUPD4;
|
||||
// enable pullup, since the pin doesn't seem to stay up
|
||||
GPIOA->PUPDR |= 2u << GPIO_PUPDR_PUPD4_Pos;
|
||||
|
||||
// SPI1 SCK (PA5)
|
||||
GPIOA->AFR[0] &= ~GPIO_AFRL_AFRL5;
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Max Regan
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
namespace BSP {
|
||||
|
||||
namespace Application {
|
||||
|
||||
};
|
||||
|
||||
class ApplicationManager {
|
||||
public:
|
||||
Common::ReturnCode set_next_display(&DisplayBW);
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
class TimedTaskManager {
|
||||
|
||||
public:
|
||||
|
||||
|
||||
};
|
||||
|
||||
class Task {
|
||||
|
||||
public:
|
||||
execute();
|
||||
|
||||
};
|
||||
|
||||
|
||||
class DisplayBW {
|
||||
|
||||
public:
|
||||
uint32_t get_width() const virtual = 0;
|
||||
uint32_t get_height() const virtual = 0;
|
||||
void set_bit(bool set, uint32 x, uint32_t y) virtual = 0;
|
||||
uint8_t *get_row(uint32_t y) const virtual = 0;
|
||||
void clear(uint32_t y) const virtual = 0;
|
||||
int start_refresh(uint32_t y) const virtual = 0;
|
||||
|
||||
};
|
||||
|
||||
class DisplayBWScreen {
|
||||
|
||||
void display() virtual = 0;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
202
display.c
202
display.c
@@ -1,202 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Max Regan
|
||||
*
|
||||
* 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 "display.h"
|
||||
#include "macros.h"
|
||||
|
||||
static void display_buffer_init(struct display_buffer *buffer)
|
||||
{
|
||||
for (size_t i = 0; i < ARRAY_SIZE(buffer->lines); i++) {
|
||||
struct display_line *line = &buffer->lines[i];
|
||||
line->mode = 1; // Update display
|
||||
line->line = i;
|
||||
for (size_t j = 0; j < ARRAY_SIZE(line->data); j++) {
|
||||
line->data[j] = 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
buffer->dummy = 0;
|
||||
}
|
||||
|
||||
|
||||
static void display_spi_init(struct display *display)
|
||||
{
|
||||
// TODO: Not all of this should be in here, probably
|
||||
|
||||
RCC->APB2ENR = RCC_APB2ENR_SPI1EN;
|
||||
|
||||
GPIOB->OSPEEDR = ~0;
|
||||
|
||||
/* Assign SPI_MOSI to PA12 (AFRH5), since PA7 is taken by LPTIM_OUT */
|
||||
GPIOA->AFR[1] &= ~GPIO_AFRH_AFRH4;
|
||||
|
||||
SET_TO(GPIOA->MODER, GPIO_MODER_MODE12, 2u << GPIO_MODER_MODE12_Pos);
|
||||
|
||||
GPIOA->OTYPER &= ~GPIO_OTYPER_OT_12;
|
||||
GPIOA->PUPDR &= ~GPIO_PUPDR_PUPD12;
|
||||
|
||||
// SPI1 NSS (PA4)
|
||||
GPIOA->AFR[0] &= ~GPIO_AFRL_AFRL4;
|
||||
|
||||
SET_TO(GPIOA->MODER, GPIO_MODER_MODE4, 2u << GPIO_MODER_MODE4_Pos);
|
||||
|
||||
GPIOA->OTYPER &= ~GPIO_OTYPER_OT_4;
|
||||
GPIOA->PUPDR &= ~GPIO_PUPDR_PUPD4;
|
||||
// enable pullup, since the pin doesn't seem to stay up
|
||||
GPIOA->PUPDR |= 2u << GPIO_PUPDR_PUPD4_Pos;
|
||||
|
||||
// SPI1 SCK (PA5)
|
||||
GPIOA->AFR[0] &= ~GPIO_AFRL_AFRL5;
|
||||
|
||||
SET_TO(GPIOA->MODER, GPIO_MODER_MODE5, 2u << GPIO_MODER_MODE5_Pos);
|
||||
|
||||
GPIOA->OTYPER &= ~GPIO_OTYPER_OT_5;
|
||||
GPIOA->PUPDR &= ~GPIO_PUPDR_PUPD5;
|
||||
|
||||
// SPI1 MISO (PA6)
|
||||
GPIOA->AFR[0] &= ~GPIO_AFRL_AFRL6;
|
||||
|
||||
SET_TO(GPIOA->MODER, GPIO_MODER_MODE6, 2u << GPIO_MODER_MODE6_Pos);
|
||||
|
||||
GPIOA->OTYPER &= ~GPIO_OTYPER_OT_6;
|
||||
GPIOA->PUPDR &= ~GPIO_PUPDR_PUPD6;
|
||||
|
||||
// Enable Master mode and half the baud rate, so it's set to ~1MHz
|
||||
display->spi->CR1 |= SPI_CR1_MSTR | SPI_CR1_LSBFIRST;
|
||||
display->spi->CR1 |= 1u << SPI_CR1_BR_Pos;
|
||||
display->spi->CR2 |= SPI_CR2_SSOE;
|
||||
}
|
||||
|
||||
void display_init(struct display *display, SPI_TypeDef* spi)
|
||||
{
|
||||
display->spi = spi;
|
||||
display->is_dirty = true;
|
||||
display->dirty_line_min = 0;
|
||||
display->dirty_line_max = DISPLAY_HEIGHT - 1;
|
||||
display_buffer_init(&display->buffer);
|
||||
display_spi_init(display);
|
||||
}
|
||||
|
||||
static void display_set_dirty(struct display *display, unsigned int y)
|
||||
{
|
||||
if (!display->is_dirty) {
|
||||
display->is_dirty = true;
|
||||
display->dirty_line_min = y;
|
||||
display->dirty_line_max = y;
|
||||
} else {
|
||||
display->dirty_line_min = MIN(y, display->dirty_line_min);
|
||||
display->dirty_line_max = MAX(y, display->dirty_line_max);
|
||||
}
|
||||
}
|
||||
|
||||
void display_set_bit(struct display *display, unsigned int x, unsigned int y, uint8_t val)
|
||||
{
|
||||
if (x >= DISPLAY_WIDTH || y >= DISPLAY_HEIGHT) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct display_line *line = &display->buffer.lines[y];
|
||||
uint8_t *byte = &line->data[x >> 3];
|
||||
if (val) {
|
||||
CLR_POS(*byte, x & 7);
|
||||
} else {
|
||||
SET_POS(*byte, x & 7);
|
||||
}
|
||||
|
||||
display_set_dirty(display, y);
|
||||
}
|
||||
|
||||
void display_set_byte(struct display *display, unsigned int x, unsigned int y, uint8_t val)
|
||||
{
|
||||
if (x >= DISPLAY_WIDTH || y >= DISPLAY_HEIGHT) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (x & 7) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct display_line *line = &display->buffer.lines[y];
|
||||
line->data[x >> 3] = val;
|
||||
display_set_dirty(display, y);
|
||||
}
|
||||
|
||||
void display_char_at(struct display *display, int *x_off, int y_off, char c, const struct font *font)
|
||||
{
|
||||
const struct glyph *g = glyph_for_char(font, c);
|
||||
if (g == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Don't hardcode this
|
||||
int byte_cols = (g->cols / 8);
|
||||
if (g->cols & 7) {
|
||||
byte_cols++;
|
||||
}
|
||||
if (byte_cols & 1) {
|
||||
byte_cols++;
|
||||
}
|
||||
for (size_t x = 0; x < g->cols; x++) {
|
||||
for (size_t y = 0; y < g->rows; y++) {
|
||||
int byte_x = x >> 3;
|
||||
int byte_y = y;
|
||||
uint8_t bit = (g->bitmap[byte_y * byte_cols + byte_x] >> (7 - (x & 7))) & 1;
|
||||
/* 16 is font max height */
|
||||
display_set_bit(display, g->left + *x_off + x, y_off + y + 16 - g->top, bit);
|
||||
}
|
||||
}
|
||||
*x_off += g->advance;
|
||||
}
|
||||
|
||||
void display_string_at(struct display *display, int x_off, int y_off, const char *string, const struct font *font)
|
||||
{
|
||||
int i = 0;
|
||||
while (string[i]) {
|
||||
display_char_at(display, &x_off, y_off, string[i], font);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
void display_refresh(struct display *display)
|
||||
{
|
||||
if (!display->is_dirty) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t *start = (uint8_t *) &display->buffer.lines[display->dirty_line_min];
|
||||
// Data size
|
||||
size_t size = sizeof(display->buffer.lines[0]) *
|
||||
(display->dirty_line_max - display->dirty_line_min + 1);
|
||||
// Trailer dummy data
|
||||
size += 2;
|
||||
|
||||
spi_send_blocking(display->spi, start , size);
|
||||
display->is_dirty = false;
|
||||
}
|
||||
|
||||
void display_clear(struct display *display)
|
||||
{
|
||||
display_buffer_init(&display->buffer);
|
||||
display->is_dirty = true;
|
||||
display->dirty_line_min = 0;
|
||||
display->dirty_line_max = DISPLAY_HEIGHT - 1;
|
||||
}
|
||||
78
display.h
78
display.h
@@ -1,78 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Max Regan
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _DISPLAY_H_
|
||||
#define _DISPLAY_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "spi.h"
|
||||
#include "font.h"
|
||||
|
||||
#define DISPLAY_WIDTH 144
|
||||
#define DISPLAY_HEIGHT 168
|
||||
|
||||
struct display_line
|
||||
{
|
||||
uint8_t mode;
|
||||
uint8_t line;
|
||||
uint8_t data[DISPLAY_WIDTH / 8];
|
||||
};
|
||||
|
||||
struct display_buffer
|
||||
{
|
||||
struct display_line lines[DISPLAY_HEIGHT];
|
||||
uint16_t dummy;
|
||||
};
|
||||
|
||||
static_assert(sizeof(struct display_buffer) == (DISPLAY_WIDTH / 8 + 2) * DISPLAY_HEIGHT + 2,
|
||||
"The display buffer structure must be packed");
|
||||
|
||||
struct display
|
||||
{
|
||||
SPI_TypeDef *spi;
|
||||
struct display_buffer buffer;
|
||||
|
||||
bool is_dirty;
|
||||
uint8_t dirty_line_min;
|
||||
uint8_t dirty_line_max;
|
||||
};
|
||||
|
||||
|
||||
void display_init(struct display *display, SPI_TypeDef *spi);
|
||||
|
||||
void display_set_bit(struct display *display, unsigned int x, unsigned int y, uint8_t val);
|
||||
|
||||
void display_set_byte(struct display *display, unsigned int x, unsigned int y, uint8_t val);
|
||||
|
||||
void display_char_at(struct display *display, int *x_off, int y_off, char c, const struct font *font);
|
||||
|
||||
void display_string_at(struct display *display, int x_off, int y_off, const char *string, const struct font *font);
|
||||
|
||||
void display_refresh(struct display *display);
|
||||
|
||||
// TODO
|
||||
void display_clear(struct display *display);
|
||||
|
||||
#endif
|
||||
39
font.c
39
font.c
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Max Regan
|
||||
*
|
||||
* 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 "font.h"
|
||||
|
||||
const struct glyph *glyph_for_char(const struct font *font, char c)
|
||||
{
|
||||
// TODO: This is almost the least efficient way imaginable to implement this
|
||||
for (int i = 0; i < font->max; i++) {
|
||||
const struct glyph *g = font->glyphs[i];
|
||||
if (g == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (g->glyph == c) {
|
||||
return g;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
4444
lib/fonts/font-notomono-29.c
Normal file
4444
lib/fonts/font-notomono-29.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -5,11 +5,11 @@
|
||||
* be found at http://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#ifndef _FONTEM_notomono_10_H
|
||||
#define _FONTEM_notomono_10_H
|
||||
#ifndef _FONTEM_notomono_29_H
|
||||
#define _FONTEM_notomono_29_H
|
||||
|
||||
#include "fontem.h"
|
||||
|
||||
extern const struct font font_notomono_10;
|
||||
extern const struct font font_notomono_29;
|
||||
|
||||
#endif /* _FONTEM_notomono_10_H */
|
||||
#endif /* _FONTEM_notomono_29_H */
|
||||
File diff suppressed because it is too large
Load Diff
1206
lib/fonts/font-notomono-68.c
Normal file
1206
lib/fonts/font-notomono-68.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -5,11 +5,11 @@
|
||||
* be found at http://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#ifndef _FONTEM_notomono_16_H
|
||||
#define _FONTEM_notomono_16_H
|
||||
#ifndef _FONTEM_notomono_68_H
|
||||
#define _FONTEM_notomono_68_H
|
||||
|
||||
#include "fontem.h"
|
||||
|
||||
extern const struct font font_notomono_16;
|
||||
extern const struct font font_notomono_68;
|
||||
|
||||
#endif /* _FONTEM_notomono_16_H */
|
||||
#endif /* _FONTEM_notomono_68_H */
|
||||
120
rtc.c
120
rtc.c
@@ -1,120 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Max Regan
|
||||
*
|
||||
* 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 "rtc.h"
|
||||
#include "stm32l0xx.h"
|
||||
#include "macros.h"
|
||||
|
||||
static void enable_rtc_write()
|
||||
{
|
||||
/*<! Disable write protection */
|
||||
RTC->WPR = 0xCA;
|
||||
RTC->WPR = 0x53;
|
||||
}
|
||||
|
||||
static void disable_rtc_write()
|
||||
{
|
||||
/*<! Disable write protection */
|
||||
RTC->WPR = 0x00;
|
||||
}
|
||||
|
||||
uint32_t bin_to_bcd(uint32_t bin)
|
||||
{
|
||||
uint32_t bcd = 0;
|
||||
while (bin > 0) {
|
||||
bcd <<= 4;
|
||||
bcd |= bin % 10;
|
||||
bin /= 10;
|
||||
}
|
||||
|
||||
return bcd;
|
||||
}
|
||||
|
||||
void rtc_init()
|
||||
{
|
||||
uint32_t temp = RCC->CSR;
|
||||
|
||||
SET(RCC->CSR, RCC_CSR_RTCRST);
|
||||
SET(RCC->APB1ENR, RCC_APB1ENR_PWREN);
|
||||
SET(PWR->CR, PWR_CR_DBP);
|
||||
|
||||
/*<! Set RTC input clock to the LSI (low-speed internal 32.768kHz) clock */
|
||||
SET(temp, RCC_CSR_LSEON);
|
||||
SET_TO(temp, RCC_CSR_RTCSEL, RCC_CSR_RTCSEL_0);
|
||||
SET(temp, RCC_CSR_RTCEN);
|
||||
RCC->CSR = temp;
|
||||
|
||||
while (!(RCC->CSR & RCC_CSR_LSERDY)) {}
|
||||
|
||||
enable_rtc_write();
|
||||
|
||||
RTC->ISR = RTC_ISR_INIT;
|
||||
while (!(RTC->ISR & RTC_ISR_INITF)) {}
|
||||
|
||||
/*<! Set the Clock Prescalers (32.768kHz / 128 / 256 = 1Hz */
|
||||
/*<! Set the Async prescaler to the Maximum (divide the clock by 128) */
|
||||
SET_TO(RTC->PRER, RTC_PRER_PREDIV_A, RTC_PRER_PREDIV_A);
|
||||
/*<! Set the Syncronous scaler (divide the clock by 255 + 1) */
|
||||
SET_TO(RTC->PRER, RTC_PRER_PREDIV_S, 255);
|
||||
|
||||
|
||||
/*<! Load initial date and time */
|
||||
// TODO
|
||||
/* uint32_t time = 0; */
|
||||
/* uint32_t date = 0; */
|
||||
/*<! Set the date and time format */
|
||||
// TODO: currently defaults to 24hr
|
||||
|
||||
// 12-Hour format
|
||||
SET(RTC->CR, RTC_CR_FMT);
|
||||
|
||||
uint32_t time = 0;
|
||||
SET(time, RTC_TR_PM);
|
||||
SET_TO(time, RTC_TR_HT, 1 << RTC_TR_HT_Pos);
|
||||
SET_TO(time, RTC_TR_HU, 2 << RTC_TR_HU_Pos);
|
||||
SET_TO(time, RTC_TR_MNT, 5 << RTC_TR_MNT_Pos);
|
||||
SET_TO(time, RTC_TR_MNU, 9 << RTC_TR_MNU_Pos);
|
||||
SET_TO(time, RTC_TR_ST, 0 << RTC_TR_ST_Pos);
|
||||
SET_TO(time, RTC_TR_SU, 0 << RTC_TR_SU_Pos);
|
||||
RTC->TR = time;
|
||||
|
||||
|
||||
CLR(RTC->ISR, RTC_ISR_INIT);
|
||||
|
||||
disable_rtc_write();
|
||||
}
|
||||
|
||||
|
||||
void rtc_get_time_bcd(struct time_bcd *tm_bcd)
|
||||
{
|
||||
uint32_t time = RTC->TR;
|
||||
|
||||
tm_bcd->hour_tens = STM32_GET_FIELD(time, RTC_TR_HT);
|
||||
tm_bcd->hour_ones = STM32_GET_FIELD(time, RTC_TR_HU);
|
||||
|
||||
tm_bcd->minute_tens = STM32_GET_FIELD(time, RTC_TR_MNT);
|
||||
tm_bcd->minute_ones = STM32_GET_FIELD(time, RTC_TR_MNU);
|
||||
|
||||
tm_bcd->second_tens = STM32_GET_FIELD(time, RTC_TR_ST);
|
||||
tm_bcd->second_ones = STM32_GET_FIELD(time, RTC_TR_SU);
|
||||
|
||||
tm_bcd->pm = STM32_GET_FIELD(time, RTC_TR_PM);
|
||||
}
|
||||
43
rtc.h
43
rtc.h
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Max Regan
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _RTC_H_
|
||||
#define _RTC_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
struct time_bcd {
|
||||
uint8_t hour_tens;
|
||||
uint8_t hour_ones;
|
||||
uint8_t minute_tens;
|
||||
uint8_t minute_ones;
|
||||
uint8_t second_tens;
|
||||
uint8_t second_ones;
|
||||
bool pm;
|
||||
};
|
||||
|
||||
void rtc_init();
|
||||
|
||||
void rtc_get_time_bcd(struct time_bcd *tm_bcd);
|
||||
|
||||
#endif
|
||||
46
spi.c
46
spi.c
@@ -1,46 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Max Regan
|
||||
*
|
||||
* 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 "spi.h"
|
||||
|
||||
#include "stm32l0xx.h"
|
||||
#include "macros.h"
|
||||
|
||||
void spi_send_blocking(SPI_TypeDef *spi, const uint8_t *data, size_t len)
|
||||
{
|
||||
if (len <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
spi->CR1 |= SPI_CR1_SPE;
|
||||
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
while (!(spi->SR & SPI_SR_TXE)) {}
|
||||
spi->DR = data[i];
|
||||
}
|
||||
|
||||
while (!(spi->SR & SPI_SR_TXE)) {}
|
||||
|
||||
// Ensure that NSS is held for long enough to meet the display's thSCS
|
||||
for (int i = 0; i < 4; i++);
|
||||
|
||||
spi->CR1 &= ~SPI_CR1_SPE;
|
||||
}
|
||||
35
spi.h
35
spi.h
@@ -1,35 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Max Regan
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _SPI_H_
|
||||
#define _SPI_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
// TODO: Include something more general (only needed for SPI typedef)
|
||||
#include "stm32l0xx.h"
|
||||
|
||||
void spi_send_blocking(SPI_TypeDef *spi, const uint8_t *data, size_t len);
|
||||
|
||||
void spi_send_dma(SPI_TypeDef *spi);
|
||||
|
||||
#endif
|
||||
29
system.c
29
system.c
@@ -1,29 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Max Regan
|
||||
*
|
||||
* 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 "system.h"
|
||||
|
||||
uint32_t system_clk_freq = 0;
|
||||
|
||||
uint32_t system_get_clk_freq()
|
||||
{
|
||||
return system_clk_freq;
|
||||
}
|
||||
Reference in New Issue
Block a user