add display support

This commit is contained in:
Benjamin Wiegand
2025-09-01 14:07:02 -07:00
parent 172de30de5
commit 611d7c54ab
7 changed files with 519 additions and 6 deletions
+2 -1
View File
@@ -35,7 +35,7 @@ pico_sdk_init()
# Add executable. Default name is the project name, version 0.1
add_executable(BattMITM_2.0 main.c smbus.c static_queue.c mitm.c status.c )
add_executable(BattMITM_2.0 main.c smbus.c static_queue.c mitm.c status.c display.c font.c )
pico_set_program_name(BattMITM_2.0 "BattMITM_2.0")
pico_set_program_version(BattMITM_2.0 "0.1")
@@ -46,6 +46,7 @@ target_link_libraries(BattMITM_2.0
hardware_i2c
pico_i2c_slave
hardware_pwm
hardware_spi
)
# Add the standard include files to the build
+13
View File
@@ -46,3 +46,16 @@
#define LAPTOP_I2C_ADDR BATT_I2C_ADDR // use the same address
#define LAPTOP_I2C_BAUD BATT_I2C_BAUD // use the same baud (for now)
// spi display
#define DISPLAY_SPI spi0
#define DISPLAY_SPI_BAUD 8000
#define DISPLAY_SCL_PIN 6
#define DISPLAY_SDA_PIN 7
#define DISPLAY_CS_PIN 3
#define DISPLAY_DC_PIN 4
#define DISPLAY_RESET_PIN 5
#define DISPLAY_FLIP_180 false
+296
View File
@@ -0,0 +1,296 @@
/**
MIT License
Copyright (c) 2025 Benjamin Wiegand
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"
#include "config.h"
#include "hardware/spi.h"
#include "pico/stdlib.h"
#include <string.h>
#include <stdio.h>
#define DISPLAY_CMD_ROW_ADDRESS 0x75
#define DISPLAY_CMD_COLUMN_ADDRESS 0x15
#define DISPLAY_CMD_REMAP_AND_DATA_FORMAT 0xA0
#define DISPLAY_CMD_DISPLAY_ON 0xAF
#define DISPLAY_CMD_DISPLAY_OFF 0xAE
#define DISPLAY_CMD_DRAW_LINE 0x21
#define DISPLAY_CMD_DRAW_RECTANGLE 0x22
#define DISPLAY_CMD_COPY 0x23
#define DISPLAY_CMD_FILL 0x26
bool display_cs_state = 0;
bool display_dc_state = 0;
uint8_t text_start_x = 0;
uint8_t text_pos_x = 0;
uint8_t text_pos_y = FONT_HEIGHT;
uint8_t text_scale = 1;
uint16_t text_color = 0xFFFF;
void display_set_cs(bool state) {
#if DISPLAY_CS_PIN != -1
if (display_cs_state == state) return;
gpio_put(DISPLAY_CS_PIN, state);
display_cs_state = state;
#endif
}
void display_set_dc(bool state) {
if (display_dc_state == state) return;
gpio_put(DISPLAY_DC_PIN, state);
display_dc_state = state;
}
void display_send_cmd(uint8_t cmd) {
display_set_dc(0);
display_set_cs(0);
spi_write_blocking(DISPLAY_SPI, &cmd, 1);
}
void display_send_buffer(uint8_t* buffer, size_t length) {
display_set_dc(1);
display_set_cs(0);
spi_write_blocking(DISPLAY_SPI, buffer, length);
}
// converts rgb888 (24-bit) colors to rgb565 (16-bit) colors
// provided for convenience during development since some know rgb888 by heart
// avoid using this when you can, and just use rgb565 colors directly
uint16_t rgb888_to_565(uint32_t color24) {
uint16_t color16 = 0;
color16 += (((color24 >> 16) & 0xFF) * 0x1F / 0xFF) << 11; // red
color16 += (((color24 >> 8) & 0xFF) * 0x3F / 0xFF) << 5; // green
color16 += (color24 & 0xFF) * 0x1F / 0xFF; // blue
return color16;
}
uint8_t rgb565_red(uint16_t color16) {
return (color16 >> 10) & 0x3E;
}
uint8_t rgb565_green(uint16_t color16) {
return (color16 >> 5) & 0x3F;
}
uint8_t rgb565_blue(uint16_t color16) {
return (color16 & 0x1F) << 1;
}
void display_set_rectangle_fill(bool enabled) {
display_send_cmd(DISPLAY_CMD_FILL);
display_send_cmd(enabled);
}
void display_draw_rectangle(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2, uint16_t stroke_color, uint16_t fill_color) {
display_send_cmd(DISPLAY_CMD_DRAW_RECTANGLE);
display_send_cmd(x1);
display_send_cmd(y1);
display_send_cmd(x2);
display_send_cmd(y2);
display_send_cmd(rgb565_red(stroke_color));
display_send_cmd(rgb565_green(stroke_color));
display_send_cmd(rgb565_blue(stroke_color));
display_send_cmd(rgb565_red(fill_color));
display_send_cmd(rgb565_green(fill_color));
display_send_cmd(rgb565_blue(fill_color));
}
void display_draw_line(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2, uint16_t color) {
display_send_cmd(DISPLAY_CMD_DRAW_LINE);
display_send_cmd(x1);
display_send_cmd(y1);
display_send_cmd(x2);
display_send_cmd(y2);
display_send_cmd(rgb565_red(color));
display_send_cmd(rgb565_green(color));
display_send_cmd(rgb565_blue(color));
}
void display_copy(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2, uint8_t dest_x, uint8_t dest_y) {
display_send_cmd(DISPLAY_CMD_COPY);
display_send_cmd(x1);
display_send_cmd(y1);
display_send_cmd(x2);
display_send_cmd(y2);
display_send_cmd(dest_x);
display_send_cmd(dest_y);
}
void display_shift(int x, int y, uint16_t negative_color) {
uint x_offset, y_offset;
uint8_t x_start, y_start;
if (x > 95 || x < -95) x %= 96;
if (y > 63 || y < -63) x %= 64;
x_start = x < 0 ? -x : 0;
y_start = y < 0 ? -y : 0;
x_offset = x < 0 ? 0 : x;
y_offset = y < 0 ? 0 : y;
display_copy(x_start, y_start, 95, 63, x_offset, y_offset);
display_set_rectangle_fill(true);
if (x < 0) display_draw_rectangle(96 - x_start, 0, 95, 63, negative_color, negative_color);
else if (x > 0) display_draw_rectangle(0, 0, x_offset - 1, 63, negative_color, negative_color);
if (y < 0) display_draw_rectangle(0, 63 - y_start, 95, 63, negative_color, negative_color);
else if (y > 0) display_draw_rectangle(0, 0, 95, y_offset - 1, negative_color, negative_color);
}
void set_display_address_window(uint8_t x, uint8_t y, uint8_t width, uint8_t height) {
display_send_cmd(DISPLAY_CMD_COLUMN_ADDRESS);
display_send_cmd(x);
display_send_cmd(width);
display_send_cmd(DISPLAY_CMD_ROW_ADDRESS);
display_send_cmd(y);
display_send_cmd(height);
}
void draw_char(uint8_t x_pos, uint8_t y_pos, uint8_t scale_factor, uint16_t color, char c) {
uint8_t color_bytes[2] = {color >> 8, color & 0xFF};
uint8_t* char_data = font_get_char(c);
uint i;
// position relative to "text line"
y_pos -= scale_factor * FONT_HEIGHT;
// for whatever reason if I push it all as one big buffer it doesn't work
for (uint x = 0; x < FONT_WIDTH; x++) {
for (uint y = 0; y < FONT_HEIGHT; y++) {
i = x + y * FONT_WIDTH;
if (!((char_data[i / 8] >> (7 - i % 8)) & 1)) continue;
for (uint j = 0; j < scale_factor * scale_factor; j++) {
set_display_address_window(
x_pos + x * scale_factor + j % scale_factor,
y_pos + y * scale_factor + j / scale_factor,
1, 1);
display_send_buffer(color_bytes, 2);
}
}
}
}
void display_set_text_color(uint16_t color) {
text_color = color;
}
void display_set_text_scale(uint8_t scale_factor) {
text_scale = scale_factor;
}
void display_set_text_position(uint8_t x, uint8_t y) {
text_start_x = x;
text_pos_x = x;
text_pos_y = y;
}
void display_print(char* text) {
size_t length = strlen(text);
for (size_t i = 0; i < length; i++) {
if (text[i] == '\n') {
text_pos_y += FONT_HEIGHT * text_scale + text_scale;
text_pos_x = text_start_x;
continue;
}
draw_char(text_pos_x, text_pos_y, text_scale, text_color, text[i]);
text_pos_x += FONT_WIDTH * text_scale + text_scale;
}
}
void display_printf(char* text, ...) {
va_list args;
va_start(args, text);
// this is terrible, but I don't like wasting ram.
size_t len = vsprintf(NULL, text, args);
char formatted[len];
vsprintf(formatted, text, args);
va_end(args);
display_print(formatted);
}
void init_display() {
// data control
gpio_init(DISPLAY_DC_PIN);
gpio_set_dir(DISPLAY_DC_PIN, GPIO_OUT);
display_set_dc(0);
// chip select (optional)
#if DISPLAY_CS_PIN != -1
gpio_init(DISPLAY_CS_PIN);
gpio_set_dir(DISPLAY_CS_PIN, GPIO_OUT);
display_set_cs(0);
#endif
// spi
gpio_set_function(DISPLAY_SDA_PIN, GPIO_FUNC_SPI);
gpio_set_function(DISPLAY_SCL_PIN, GPIO_FUNC_SPI);
spi_init(DISPLAY_SPI, DISPLAY_SPI_BAUD);
spi_set_format(DISPLAY_SPI, 8, SPI_CPOL_0, SPI_CPHA_0, SPI_MSB_FIRST);
// reset
gpio_init(DISPLAY_RESET_PIN);
gpio_set_dir(DISPLAY_RESET_PIN, GPIO_OUT);
gpio_put(DISPLAY_RESET_PIN, 0);
sleep_ms(100);
gpio_put(DISPLAY_RESET_PIN, 1);
// setup
display_send_cmd(DISPLAY_CMD_DISPLAY_OFF);
display_send_cmd(DISPLAY_CMD_REMAP_AND_DATA_FORMAT);
uint8_t format = 0b01100000;
#if !DISPLAY_FLIP_180
format |= 0b00010010;
#endif
display_send_cmd(format);
display_send_cmd(DISPLAY_CMD_DISPLAY_ON);
// clear framebuffer
display_set_rectangle_fill(true);
display_draw_rectangle(0, 0, 95, 63, 0, 0);
}
+43
View File
@@ -0,0 +1,43 @@
/**
MIT License
Copyright (c) 2025 Benjamin Wiegand
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.
*/
uint16_t rgb888_to_565(uint32_t color24);
void display_set_rectangle_fill(bool enabled);
void display_draw_rectangle(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2, uint16_t stroke_color, uint16_t fill_color);
void display_draw_line(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2, uint16_t color);
void display_draw_char(uint8_t x_offset, uint8_t y_offset, uint8_t scale_factor, uint16_t color, char c);
void display_copy(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2, uint8_t dest_x, uint8_t dest_y);
void display_shift(int x, int y, uint16_t negative_color);
void display_set_text_color(uint16_t color);
void display_set_text_scale(uint8_t scale_factor);
void display_set_text_position(uint8_t x, uint8_t y);
void display_print(char* text);
void display_printf(char* text, ...);
void init_display();
+127
View File
@@ -0,0 +1,127 @@
/**
MIT License
Copyright (c) 2025 Benjamin Wiegand
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"
uint8_t font_data[] = {
0x00, 0x00, 0x00, 0x00, 0x00, // [space]
0x21, 0x08, 0x42, 0x00, 0x80, // !
0x52, 0x80, 0x00, 0x00, 0x00, // "
0x02, 0xBE, 0xAF, 0xA8, 0x00, // #
0x23, 0xE8, 0xE2, 0xF8, 0x80, // $
0x06, 0x74, 0x45, 0xCC, 0x00, // %
0x45, 0x28, 0x8A, 0xC9, 0xA0, // &
0x21, 0x00, 0x00, 0x00, 0x00, // '
0x11, 0x10, 0x84, 0x10, 0x40, // (
0x41, 0x04, 0x21, 0x11, 0x00, // )
0x05, 0x5D, 0xF7, 0x54, 0x00, // *
0x01, 0x09, 0xF2, 0x10, 0x00, // +
0x00, 0x00, 0x00, 0x11, 0x00, // ,
0x00, 0x00, 0xE0, 0x00, 0x00, // -
0x00, 0x00, 0x00, 0x00, 0x80, // .
0x10, 0x88, 0x42, 0x21, 0x00, // /
0x74, 0x67, 0x5C, 0xC5, 0xC0, // 0
0x23, 0x08, 0x42, 0x11, 0xC0, // 1
0x74, 0x42, 0xE8, 0x43, 0xE0, // 2
0x74, 0x42, 0x60, 0xC5, 0xC0, // 3
0x11, 0x95, 0x2F, 0x88, 0x40, // 4
0xFC, 0x3C, 0x10, 0xC5, 0xC0, // 5
0x74, 0x61, 0xE8, 0xC5, 0xC0, // 6
0xF8, 0x44, 0x42, 0x10, 0x80, // 7
0x74, 0x62, 0xE8, 0xC5, 0xC0, // 8
0x74, 0x62, 0xF0, 0xC5, 0xC0, // 9
0x00, 0x08, 0x00, 0x10, 0x00, // :
0x00, 0x08, 0x00, 0x11, 0x00, // ;
0x00, 0x88, 0x82, 0x08, 0x00, // <
0x00, 0x1C, 0x07, 0x00, 0x00, // =
0x02, 0x08, 0x22, 0x20, 0x00, // >
0x74, 0x42, 0x62, 0x00, 0x80, // ?
0x74, 0x6F, 0xBB, 0x41, 0xE0, // @
0x74, 0x63, 0xF8, 0xC6, 0x20, // A
0xF4, 0x63, 0xE8, 0xC7, 0xC0, // B
0xFC, 0x21, 0x08, 0x43, 0xE0, // C
0xF4, 0x63, 0x18, 0xC7, 0xC0, // D
0xFC, 0x21, 0xF8, 0x43, 0xE0, // E
0xFC, 0x21, 0xE8, 0x42, 0x00, // F
0xFC, 0x21, 0x38, 0xC7, 0xE0, // G
0x8C, 0x63, 0xF8, 0xC6, 0x20, // H
0xF9, 0x08, 0x42, 0x13, 0xE0, // I
0x38, 0x42, 0x10, 0xC5, 0xC0, // J
0x8C, 0xA9, 0x8A, 0x4A, 0x20, // K
0x84, 0x21, 0x08, 0x43, 0xE0, // L
0x8C, 0x77, 0x58, 0xC6, 0x20, // M
0x8C, 0x73, 0x59, 0xC6, 0x20, // N
0x74, 0x63, 0x18, 0xC5, 0xC0, // O
0xF4, 0x63, 0xE8, 0x42, 0x00, // P
0x74, 0x63, 0x1A, 0xCD, 0xE0, // Q
0xF4, 0x63, 0xEA, 0x4A, 0x20, // R
0xFC, 0x21, 0xF0, 0x87, 0xE0, // S
0xF9, 0x08, 0x42, 0x10, 0x80, // T
0x8C, 0x63, 0x18, 0xC7, 0xE0, // U
0x8C, 0x63, 0x15, 0x28, 0x80, // V
0x8C, 0x63, 0x5A, 0xEE, 0x20, // W
0x8C, 0x54, 0x45, 0x46, 0x20, // X
0x8C, 0x62, 0xA2, 0x10, 0x80, // Y
0xF8, 0x44, 0x44, 0x43, 0xE0, // Z
0x72, 0x10, 0x84, 0x21, 0xC0, // [
0x42, 0x08, 0x42, 0x08, 0x40, // "\"
0x70, 0x84, 0x21, 0x09, 0xC0, // ]
0x22, 0xA2, 0x00, 0x00, 0x00, // ^
0x00, 0x00, 0x00, 0x03, 0xE0, // _
0x41, 0x00, 0x00, 0x00, 0x00, // `
0x00, 0x1C, 0x17, 0xC5, 0xC0, // a
0x84, 0x21, 0xE8, 0xC7, 0xC0, // b
0x00, 0x1D, 0x18, 0x45, 0xC0, // c
0x08, 0x42, 0xF8, 0xC5, 0xE0, // d
0x00, 0x1D, 0x1F, 0x41, 0xC0, // e
0x22, 0x91, 0xC4, 0x21, 0x00, // f
0x00, 0x1F, 0x17, 0x85, 0xC0, // g
0x84, 0x21, 0xE8, 0xC6, 0x20, // h
0x00, 0x08, 0x02, 0x10, 0x80, // i
0x00, 0x80, 0x21, 0x28, 0x80, // j
0x84, 0x25, 0x4C, 0x52, 0x40, // k
0x21, 0x08, 0x42, 0x10, 0x80, // l
0x00, 0x01, 0xAA, 0xD6, 0xA0, // m
0x00, 0x01, 0xE8, 0xC6, 0x20, // n
0x00, 0x00, 0xE8, 0xC5, 0xC0, // o
0x03, 0xA3, 0x1F, 0x42, 0x00, // p
0x03, 0xA3, 0x17, 0x84, 0x20, // q
0x00, 0x1D, 0x18, 0x42, 0x00, // r
0x00, 0x1F, 0x07, 0x07, 0xC0, // s
0x01, 0x09, 0xF2, 0x10, 0x80, // t
0x00, 0x01, 0x18, 0xC5, 0xE0, // u
0x00, 0x01, 0x18, 0xA8, 0x80, // v
0x00, 0x01, 0x18, 0xD5, 0x40, // w
0x00, 0x22, 0xA2, 0x2A, 0x20, // x
0x00, 0x22, 0xA2, 0x22, 0x00, // y
0x00, 0x3E, 0x22, 0x23, 0xE0, // z
0x19, 0x08, 0x82, 0x10, 0x60, // {
0x21, 0x08, 0x42, 0x10, 0x80, // |
0xC1, 0x08, 0x22, 0x13, 0x00, // }
0x00, 0x11, 0x51, 0x00, 0x00, // ~
};
uint8_t* font_get_char(char c) {
if (c < 32 || c > 126) return font_data; // use space for invalid chars
return &font_data[(c - 32) * FONT_BYTES_PER_CHAR];
}
+30
View File
@@ -0,0 +1,30 @@
/**
MIT License
Copyright (c) 2025 Benjamin Wiegand
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 <stdint.h>
#define FONT_WIDTH 5
#define FONT_HEIGHT 7
#define FONT_BYTES_PER_CHAR 5
uint8_t* font_get_char(char c);
+8 -5
View File
@@ -25,18 +25,21 @@
#include "status.h"
#include "pico/stdlib.h"
#include <stdio.h>
#include "display.h"
int main() {
stdio_init_all();
sleep_ms(2000);
printf("\n\n\n======= init =======\n\n\n");
init_status();
init_display();
init_mitm();
display_print("hello world");
for (int i = 0; i < 95; i++)
display_shift(1, 1, 0x0000);
while (true) {
mitm_loop();
}