First init.

This commit is contained in:
2025-10-12 09:13:56 +02:00
commit 1548aeaf9b
458 changed files with 118808 additions and 0 deletions

View File

@@ -0,0 +1,33 @@
{
"build": {
"cpu": "cortex-m3",
"extra_flags": "-DSTM32 -DSTM32F1 -DSTM32F103x8",
"f_cpu": "72000000L",
"mcu": "stm32f103c8t6",
"product_line": "STM32F103x8"
},
"debug": {
"default_tools": [
"stlink"
],
"openocd_target": "stm32f1x",
"svd_path": "STM32F103xx.svd"
},
"frameworks": [
"libopencm3"
],
"name": "STM32F103C8",
"upload": {
"maximum_ram_size": 20480,
"maximum_size": 65536,
"protocol": "stlink",
"protocols": [
"cmsis-dap",
"stlink",
"blackmagic"
]
},
"url": "https://www.st.com/",
"vendor": "ST"
}

View File

@@ -0,0 +1,6 @@
[env:bluepill]
platform = ststm32
board = stm32f103c8
framework = libopencm3
lib_deps =
FooLib=symlink://../../../mcu-renderer

View File

@@ -0,0 +1,154 @@
/*
* MCU renderer
* ST7789 on STM32
*
* (C) 2023-2024 Gissio
*
* License: MIT
*/
#include <libopencm3/stm32/gpio.h>
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/spi.h>
#include "display.h"
#include "system.h"
// Connections
#define DISPLAY_RESX_PORT GPIOB
#define DISPLAY_RESX_PIN GPIO0
#define DISPLAY_CSX_PORT GPIOB
#define DISPLAY_CSX_PIN GPIO1
#define DISPLAY_DCX_PORT GPIOB
#define DISPLAY_DCX_PIN GPIO10
#define DISPLAY_SCL_PORT GPIOA
#define DISPLAY_SCL_PIN GPIO5
#define DISPLAY_SDA_PORT GPIOA
#define DISPLAY_SDA_PIN GPIO7
// Display
static uint8_t display_text_buffer[80 * 80];
static const uint8_t display_init_sequence[] = {
MR_SEND_COMMAND(MR_ST7789_INVON), // Inverse for IPS displays
MR_END(),
};
void on_display_sleep(uint32_t value);
void on_display_set_reset(bool value);
void on_display_set_command(bool value);
void on_display_send(uint16_t value);
void on_display_send16(uint16_t value);
void on_display_sleep(uint32_t value)
{
sleep(value);
}
void on_display_set_reset(bool value)
{
if (value)
gpio_clear(DISPLAY_RESX_PORT,
DISPLAY_RESX_PIN);
else
gpio_set(DISPLAY_RESX_PORT,
DISPLAY_RESX_PIN);
}
void on_display_set_command(bool value)
{
if (value)
{
// Trigger CS before command
gpio_set(DISPLAY_CSX_PORT,
DISPLAY_CSX_PIN);
gpio_clear(DISPLAY_CSX_PORT,
DISPLAY_CSX_PIN);
gpio_clear(DISPLAY_DCX_PORT,
DISPLAY_DCX_PIN);
}
else
gpio_set(DISPLAY_DCX_PORT,
DISPLAY_DCX_PIN);
}
void on_display_send(uint16_t value)
{
spi_send(SPI1, value);
}
void on_display_send16(uint16_t value)
{
spi_send(SPI1, (value >> 8) & 0xff);
spi_send(SPI1, (value >> 0) & 0xff);
}
void init_display(mr_t *mr)
{
// Setup GPIO
gpio_set(DISPLAY_RESX_PORT,
DISPLAY_RESX_PIN);
gpio_set(DISPLAY_CSX_PORT,
DISPLAY_CSX_PIN);
gpio_set_mode(DISPLAY_RESX_PORT,
GPIO_MODE_OUTPUT_50_MHZ,
GPIO_CNF_OUTPUT_PUSHPULL,
DISPLAY_RESX_PIN);
gpio_set_mode(DISPLAY_CSX_PORT,
GPIO_MODE_OUTPUT_50_MHZ,
GPIO_CNF_OUTPUT_PUSHPULL,
DISPLAY_CSX_PIN);
gpio_set_mode(DISPLAY_DCX_PORT,
GPIO_MODE_OUTPUT_50_MHZ,
GPIO_CNF_OUTPUT_PUSHPULL,
DISPLAY_DCX_PIN);
gpio_set_mode(DISPLAY_SCL_PORT,
GPIO_MODE_OUTPUT_50_MHZ,
GPIO_CNF_OUTPUT_ALTFN_PUSHPULL,
DISPLAY_SCL_PIN);
gpio_set_mode(DISPLAY_SDA_PORT,
GPIO_MODE_OUTPUT_50_MHZ,
GPIO_CNF_OUTPUT_ALTFN_PUSHPULL,
DISPLAY_SDA_PIN);
// Setup SPI
rcc_periph_clock_enable(RCC_SPI1);
spi_init_master(SPI1,
SPI_CR1_BAUDRATE_FPCLK_DIV_2,
SPI_CR1_CPOL_CLK_TO_1_WHEN_IDLE,
SPI_CR1_CPHA_CLK_TRANSITION_2,
SPI_CR1_DFF_8BIT,
SPI_CR1_MSBFIRST);
spi_enable_software_slave_management(SPI1);
spi_set_nss_high(SPI1);
spi_enable(SPI1);
// Setup display
mr_st7789_init(mr,
DISPLAY_HEIGHT,
DISPLAY_WIDTH,
MR_DISPLAY_ROTATION_270,
display_text_buffer,
sizeof(display_text_buffer),
on_display_sleep,
on_display_set_reset,
on_display_set_command,
on_display_send,
on_display_send16);
mr_send_sequence(mr, display_init_sequence);
}
void set_display(mr_t *mr, bool value)
{
mr_st7789_set_display(mr, value);
mr_st7789_set_sleep(mr, !value);
}
void update_display(mr_t *mr)
{
}

View File

@@ -0,0 +1,24 @@
/*
* MCU renderer
* ST7789 on STM32
*
* (C) 2023-2024 Gissio
*
* License: MIT
*/
#if !defined(DISPLAY_H)
#define DISPLAY_H
#include "stdint.h"
#include "mcu-renderer-st7789.h"
#define DISPLAY_WIDTH 320
#define DISPLAY_HEIGHT 240
void init_display(mr_t *mr);
void set_display(mr_t *mr, bool value);
void update_display(mr_t *mr);
#endif

View File

@@ -0,0 +1,140 @@
/*
* MCU renderer example
* Hello world
*
* (C) 2023-2024 Gissio
*
* License: MIT
*/
#include <stdint.h>
#include <string.h>
#include "display.h"
#include "system.h"
#include "mcu-renderer-fonts/font_material_symbolsR12_4.h"
#include "mcu-renderer-fonts/font_robotoM12_4.h"
#include "mcu-renderer-fonts/font_robotoM48_1.h"
#include "mcu-renderer-fonts/font_robotoM48_2.h"
#include "mcu-renderer-fonts/font_robotoM48_3.h"
#include "mcu-renderer-fonts/font_robotoM48_4.h"
#define STATUSBAR_X 0
#define STATUSBAR_Y 0
#define STATUSBAR_WIDTH DISPLAY_WIDTH
#define STATUSBAR_HEIGHT 40
#define STATUSBAR_ITEMS 4
#define CONTENT_X 0
#define CONTENT_Y STATUSBAR_HEIGHT
#define CONTENT_WIDTH DISPLAY_WIDTH
#define CONTENT_HEIGHT (DISPLAY_HEIGHT - STATUSBAR_HEIGHT)
#define CELL_WIDTH (CONTENT_WIDTH / 2)
#define CELL_HEIGHT (CONTENT_HEIGHT / 2)
int main(void)
{
mr_t mr;
init_system();
init_display(&mr);
// Draw content
mr_rectangle_t rectangle;
mr_point_t offset;
const char *test_strings[] = {
"1bit",
"2bit",
"3bit",
"4bit",
};
const uint8_t *test_fonts[] = {
font_robotoM48_1,
font_robotoM48_2,
font_robotoM48_3,
font_robotoM48_4,
};
for (uint32_t y = 0; y < 2; y++)
{
for (uint32_t x = 0; x < 2; x++)
{
uint32_t index = y * 2 + x;
mr_set_font(&mr, test_fonts[index]);
mr_set_fill_color(&mr,
mr_get_color((x != y) ? 0xf7f7f7 : 0xe8ecf2));
mr_set_text_color(&mr, mr_get_color(0xDF1B1B));
rectangle = (mr_rectangle_t){CONTENT_X + x * CELL_WIDTH,
CONTENT_Y + y * CELL_HEIGHT,
CELL_WIDTH,
CELL_HEIGHT};
offset = (mr_point_t){
(CELL_WIDTH - mr_get_utf8_text_width(&mr,
(uint8_t *)test_strings[index])) /
2,
(CELL_HEIGHT - mr_get_line_height(&mr)) / 2};
mr_draw_utf8_text(&mr,
(uint8_t *)test_strings[index],
&rectangle,
&offset);
}
}
// Draw status bar
mr_set_fill_color(&mr, mr_get_color(0xffffff));
const char *statusbar_items[] = {
"Hello world!",
"12:34",
"\xee\x86\xa7",
"\xee\x86\xa4"};
const uint32_t statusbar_x[] = {
0,
STATUSBAR_WIDTH - 124,
STATUSBAR_WIDTH - 68,
STATUSBAR_WIDTH - 40,
STATUSBAR_WIDTH};
rectangle = (mr_rectangle_t){STATUSBAR_X,
STATUSBAR_Y,
STATUSBAR_WIDTH / 2,
STATUSBAR_HEIGHT};
for (int i = 0; i < STATUSBAR_ITEMS; i++)
{
rectangle.x = statusbar_x[i];
rectangle.width = statusbar_x[i + 1] - statusbar_x[i];
if (i < 2)
mr_set_font(&mr, font_robotoM12_4);
else
mr_set_font(&mr, font_material_symbolsR12_4);
if (i < 1)
mr_set_text_color(&mr, mr_get_color(0x000000));
else
mr_set_text_color(&mr, mr_get_color(0x707070));
offset = (mr_point_t){
FONT_ROBOTOM12_4_CAP_HEIGHT,
(STATUSBAR_HEIGHT - mr_get_line_height(&mr)) / 2};
mr_draw_utf8_text(&mr,
(uint8_t *)statusbar_items[i],
&rectangle,
&offset);
}
set_display(&mr, true);
// Update screen
while (true)
update_display(&mr);
}

View File

@@ -0,0 +1,48 @@
/*
* MCU renderer
* STM32 system code
*
* (C) 2023-2024 Gissio
*
* License: MIT
*/
#include <libopencm3/cm3/nvic.h>
#include <libopencm3/cm3/systick.h>
#include <libopencm3/stm32/rcc.h>
#include "system.h"
static volatile uint32_t system_current_tick;
void sys_tick_handler(void)
{
system_current_tick++;
}
void init_system(void)
{
// Setup MCU clock
rcc_clock_setup_in_hse_8mhz_out_72mhz();
// Setup systick
systick_set_frequency(SYSTICK_FREQUENCY, rcc_ahb_frequency);
systick_clear();
nvic_set_priority(NVIC_SYSTICK_IRQ, 0xc0);
systick_interrupt_enable();
systick_counter_enable();
// Setup GPIO
rcc_periph_clock_enable(RCC_GPIOA);
rcc_periph_clock_enable(RCC_GPIOB);
rcc_periph_clock_enable(RCC_GPIOC);
}
void sleep(uint32_t value)
{
uint32_t start_tick = system_current_tick;
while ((system_current_tick - start_tick) < value)
;
}

View File

@@ -0,0 +1,21 @@
/*
* MCU renderer
* STM32 system code
*
* (C) 2023-2024 Gissio
*
* License: MIT
*/
#if !defined(SYSTEM_H)
#define SYSTEM_H
#include <stdint.h>
#define SYSTICK_FREQUENCY 1000
void init_system(void);
void sleep(uint32_t value);
#endif