Skip to content

Commit

Permalink
Introduce LCD drivers and example program
Browse files Browse the repository at this point in the history
  • Loading branch information
nbdd0121 committed May 27, 2024
1 parent fbbf7b4 commit d8ba1e1
Show file tree
Hide file tree
Showing 7 changed files with 1,198 additions and 3 deletions.
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,6 @@
path = cheriot-rtos
url = https://github.com/lowrisc/cheriot-rtos
branch = sonata
[submodule "display_drivers"]
path = display_drivers
url = https://github.com/engdoreis/display_drivers.git
2 changes: 1 addition & 1 deletion cheriot-rtos
29 changes: 29 additions & 0 deletions compartments/lcd_test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright lowRISC Contributors.
// SPDX-License-Identifier: Apache-2.0

#include <compartment.h>
#include <thread.h>

#include "../library/lcd.hh"
#include "lowrisc_logo.h"

/// Thread entry point.
void __cheri_compartment("lcd_test") lcd_test()
{
using namespace sonata::lcd;

auto lcd = SonataLCD();
auto screen = Rect::from_point_and_size(Point::ORIGIN, lcd.resolution());
auto logo_rect = screen.centered_subrect({105, 80});
lcd.draw_image_rgb565(logo_rect, lowrisc_logo_105x80);
lcd.draw_str({1, 1},
"Hello world!",
sonata::lcd::font::m3x6_16pt,
Color::White,
Color::Black);

while (true)
{
thread_millisecond_wait(500);
}
}
893 changes: 893 additions & 0 deletions compartments/lowrisc_logo.h

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions display_drivers
Submodule display_drivers added at 26bae2
249 changes: 249 additions & 0 deletions library/lcd.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,249 @@
// Copyright lowRISC Contributors.
// SPDX-License-Identifier: Apache-2.0

#include <algorithm>
#include <platform-gpio.hh>
#include <platform-spi.hh>
#include <utility>

namespace sonata::lcd
{

extern "C"
{
#include "../display_drivers/core/m3x6_16pt.h"
#include "../display_drivers/st7735/lcd_st7735.h"
}

struct Point
{
uint32_t x;
uint32_t y;

static const Point ORIGIN;
};

inline constexpr const Point Point::ORIGIN{0, 0};

struct Size
{
uint32_t width;
uint32_t height;
};

struct Rect
{
uint32_t left;
uint32_t top;
uint32_t right;
uint32_t bottom;

static Rect from_points(Point a, Point b)
{
return {std::min(a.x, b.x),
std::min(a.y, b.y),
std::max(a.x, b.x),
std::max(a.y, b.y)};
}

static Rect from_point_and_size(Point point, Size size)
{
return {
point.x, point.y, point.x + size.width, point.y + size.height};
}

Rect centered_subrect(Size size)
{
return {(right + left - size.width) / 2,
(bottom + top - size.height) / 2,
(right + left + size.width) / 2,
(bottom + top + size.height) / 2};
}
};

namespace font
{
constexpr const Font &m3x6_16pt = m3x6_16ptFont;
}

enum class Color : uint32_t
{
Black = 0x000000,
White = 0xFFFFFF,
};

class SonataLCD
{
private:
static constexpr uint32_t LcdCsPin = 0;
static constexpr uint32_t LcdRstPin = 1;
static constexpr uint32_t LcdDcPin = 2;
static constexpr uint32_t LcdBlPin = 3;

/**
* Import the Capability helper from the CHERI namespace.
*/
template<typename T>
using Capability = CHERI::Capability<T>;

/**
* Helper. Returns a pointer to the SPI device.
*/
[[nodiscard, gnu::always_inline]] static Capability<volatile SonataSpi>
spi()
{
return MMIO_CAPABILITY(SonataSpi, spi1);
}

/**
* Helper. Returns a pointer to the GPIO device.
*/
[[nodiscard, gnu::always_inline]] static Capability<volatile SonataGPIO>
gpio()
{
return MMIO_CAPABILITY(SonataGPIO, gpio);
}

static inline void set_gpio_output_bit(uint32_t bit, bool value)
{
uint32_t output = gpio()->output;
output &= ~(1 << bit);
output |= value << bit;
gpio()->output = output;
}

LCD_Interface lcd_intf;
St7735Context ctx;

public:
SonataLCD()
{
// Set the initial state of the LCD control pins.
set_gpio_output_bit(LcdDcPin, false);
set_gpio_output_bit(LcdBlPin, true);
set_gpio_output_bit(LcdCsPin, false);

// Initialise SPI driver.
spi()->init(false, false, true, false);

// Reset LCD.
set_gpio_output_bit(LcdRstPin, false);
thread_millisecond_wait(150);
set_gpio_output_bit(LcdRstPin, true);

// Initialise LCD driverr.
lcd_intf.handle = nullptr;
lcd_intf.spi_write =
[](void *handle, uint8_t *data, size_t len) -> uint32_t {
spi()->tx(data, len);
return len;
};
lcd_intf.gpio_write =
[](void *handle, bool cs_high, bool dc_high) -> uint32_t {
set_gpio_output_bit(LcdCsPin, cs_high);
set_gpio_output_bit(LcdDcPin, dc_high);
return 0;
};
lcd_intf.timer_delay = [](uint32_t ms) {
thread_millisecond_wait(ms);
};
lcd_st7735_init(&ctx, &lcd_intf);

// Set the LCD orentiation.
lcd_st7735_set_orientation(&ctx, LCD_Rotate180);

clean();
}

~SonataLCD()
{
clean();

// Hold LCD in reset.
set_gpio_output_bit(LcdRstPin, false);
// Turn off backlight.
set_gpio_output_bit(LcdBlPin, false);
}

void clean()
{
// Clean the display with a white rectangle.
lcd_st7735_clean(&ctx);
}

Size resolution()
{
return {ctx.parent.width, ctx.parent.height};
}

void draw_pixel(Point point, Color color)
{
lcd_st7735_draw_pixel(
&ctx, {point.x, point.y}, static_cast<uint32_t>(color));
}

void draw_line(Point a, Point b, Color color)
{
if (a.y == b.y)
{
uint32_t x1 = std::min(a.x, b.x);
uint32_t x2 = std::max(a.x, b.x);
lcd_st7735_draw_horizontal_line(
&ctx, {{x1, a.y}, x2 - x1}, static_cast<uint32_t>(color));
}
else if (a.x == b.x)
{
uint32_t y1 = std::min(a.y, b.y);
uint32_t y2 = std::max(a.y, b.y);
lcd_st7735_draw_vertical_line(
&ctx, {{a.x, y1}, y2 - y1}, static_cast<uint32_t>(color));
}
else
{
// We currently only support horizontal and vertical lines.
panic();
}
}

void draw_image_bgr(Rect rect, const uint8_t *data)
{
lcd_st7735_draw_bgr(&ctx,
{{rect.left, rect.top},
rect.right - rect.left,
rect.bottom - rect.top},
data);
}

void draw_image_rgb565(Rect rect, const uint8_t *data)
{
lcd_st7735_draw_rgb565(&ctx,
{{rect.left, rect.top},
rect.right - rect.left,
rect.bottom - rect.top},
data);
}

void fill_rect(Rect rect, Color color)
{
lcd_st7735_fill_rectangle(&ctx,
{{rect.left, rect.top},
rect.right - rect.left,
rect.bottom - rect.top},
static_cast<uint32_t>(color));
}

void draw_str(Point point,
const char *str,
const Font &font,
Color background,
Color foreground)
{
lcd_st7735_set_font(&ctx, &font);
lcd_st7735_set_font_colors(&ctx,
static_cast<uint32_t>(background),
static_cast<uint32_t>(foreground));
lcd_st7735_puts(&ctx, {point.x, point.y}, str);
}
};

} // namespace sonata::lcd
24 changes: 22 additions & 2 deletions xmake.lua
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,19 @@ compartment("led_walk")
compartment("echo")
add_files("compartments/echo.cc")

compartment("lcd_test")
add_files("display_drivers/core/lcd_base.c")
add_files("display_drivers/core/m3x6_16pt.c")
add_files("display_drivers/st7735/lcd_st7735.c")
add_files("compartments/lcd_test.cc")

compartment("i2c_example")
add_deps("debug")
add_files("compartments/i2c_example.cc")

-- A simple demo using only devices on the Sonata board
firmware("sonata_simple_demo")
add_deps("freestanding", "led_walk", "echo")
add_deps("freestanding", "led_walk", "echo", "lcd_test")
on_load(function(target)
target:values_set("board", "$(board)")
target:values_set("threads", {
Expand All @@ -49,14 +55,21 @@ firmware("sonata_simple_demo")
entry_point = "entry_point",
stack_size = 0x200,
trusted_stack_frames = 1
},
{
compartment = "lcd_test",
priority = 2,
entry_point = "lcd_test",
stack_size = 0x1000,
trusted_stack_frames = 1
}
}, {expand = false})
end)
after_link(convert_to_uf2)

-- A demo that expects additional devices such as I2C devices
firmware("sonata_demo_everything")
add_deps("freestanding", "led_walk", "echo", "i2c_example")
add_deps("freestanding", "led_walk", "echo", "lcd_test", "i2c_example")
on_load(function(target)
target:values_set("board", "$(board)")
target:values_set("threads", {
Expand All @@ -74,6 +87,13 @@ firmware("sonata_demo_everything")
stack_size = 0x200,
trusted_stack_frames = 1
},
{
compartment = "lcd_test",
priority = 2,
entry_point = "lcd_test",
stack_size = 0x1000,
trusted_stack_frames = 1
},
{
compartment = "i2c_example",
priority = 2,
Expand Down

0 comments on commit d8ba1e1

Please sign in to comment.