Skip to main content Link Menu Expand (external link) Document Search Copy Copied

一种基于ESP32丰富连接能力的移动存储设备 – 验证屏幕显示

前言

我新设计的PCB包含了一个SPI接口,可支持SPI接口的显示模块。本文尝试使用Rust在屏幕上显示信息。 img

本系列其他文章

  1. 基于ESP32的移动存储设备
  2. 一种基于ESP32丰富连接能力的移动存储设备 – 电路设计
  3. 一种基于ESP32丰富连接能力的移动存储设备 – 测试SD卡读写

屏幕显示程序

屏幕显示程序分为三个步骤,先使用esp-idf-hal库配置SPI接口,然后创建显示芯片ST7789的驱动程序,最后通过图形库embedded-graphics在屏幕上显示图形、文字、图像等内容。 img

配置SPI接口

配置SPI接口比较简单,通过esp-idf-hal库的spi::SpiDeviceDriver对象就可配置SPI接口。

let peripherals = peripherals::Peripherals::take().unwrap();

let blk = peripherals.pins.gpio14;
let dc = peripherals.pins.gpio13;
let scl = peripherals.pins.gpio12;
let sda = peripherals.pins.gpio11;
let cs = peripherals.pins.gpio10;
let rst = peripherals.pins.gpio9;

let mut backlight = gpio::PinDriver::output(blk)?;
backlight.set_high()?;

let spi_drv = spi::SpiDeviceDriver::new_single(
    peripherals.spi2,
    scl,
    sda,
    Option::<gpio::Gpio13>::None,
    Some(cs),
    &spi::SpiDriverConfig::new().dma(spi::Dma::Disabled),
    &spi::SpiConfig::new().baudrate(26u32.MHz().into()),
)?;

管脚的分配要和硬件设计一致,电路设计时使用了ESP32S3的FSPI作为显示接口。其实这里只有scl和sda必须使用FSPICLK和FSPID对应的GPIO口,除了cs的其他信号可以自由选择GPIO口。至于cs是否可以使用一般的GPIO口我不太确定,为了保险我还是给cs信号分配了FSPICS0对应的GPIO口。

创建ST7789芯片驱动

芯片驱动主要使用display_interface_spi和mipidsi库,创建一个display对象。该对象可以接受指令和数据,控制屏幕上每个像素颜色与亮度。

let spi_intf = SPIInterface::new(spi_drv, gpio::PinDriver::output(dc)?);

let mut display = mipidsi::Builder::new(mipidsi::models::ST7789, spi_intf)
    .reset_pin(gpio::PinDriver::output(rst)?)
    .color_order(mipidsi::options::ColorOrder::Rgb)
    .invert_colors(mipidsi::options::ColorInversion::Inverted)
    .display_size(240, 300) // display area is 240*280, but there is a -20 pixels offset
    .init(&mut delay::Ets).map_err(|e| {
        log::error!("Error initializing display: {:?}", e);
        EspError::from(-1).unwrap()
    })?;

display.clear(RgbColor::BLACK)
    .map_err(|e| {
        log::error!("Error clear background: {:?}", e);
        EspError::from(-1).unwrap()
    })?;

上面代码段的最后一行代码display.clear使用纯色填充整个屏幕。display还支持set_pixel、draw_iter等接口,会被上层图形函数库如embedded_graphics调用。

另外需要注意的是,ST7789的分辨率其实是240*320,网上的显示模块有的只有240*280个像素。制作显示模块的厂家可能会选取ST7789显示范围的中间部分,这样的显示模块上下各有一个240*20的区域是无法显示的,有效的y坐标位于20到280之间。

使用图形库绘制内容

这里我使用了embedded_graphics来绘制图形,具体的接口文档请参考doc.rs

let text = "大家好";

let style = MonoTextStyle::new(&NOTO_SANS_MONO_CJK_SC_REGULAR_36, Rgb565::WHITE);

Text::new(text, Point::new(60, 50), style).draw(&mut display)
    .map_err(|e| {
        log::error!("Error drawing text: {:?}", e);
        EspError::from(-1).unwrap()
    })?;

let tri_style = PrimitiveStyleBuilder::new()
    .fill_color(Rgb565::BLACK)
    .stroke_color(Rgb565::RED)
    .stroke_width(3)
    .build();

Triangle::new(Point::new(60, 200), Point::new(80, 235), Point::new(40, 235))
    .into_styled(tri_style)
    .draw(&mut display)
    .map_err(|e| {
        log::error!("Error drawing triangle: {:?}", e);
        EspError::from(-1).unwrap()
    })?;

let rect_style = PrimitiveStyleBuilder::new()
    .fill_color(Rgb565::BLACK)
    .stroke_color(Rgb565::GREEN)
    .stroke_width(3)
    .build();

Rectangle::new(Point::new(100, 200), Size::new(40, 40))
    .into_styled(rect_style)
    .draw(&mut display)
    .map_err(|e| {
        log::error!("Error drawing rectangle: {:?}", e);
        EspError::from(-1).unwrap()
    })?;

let circle_style = PrimitiveStyleBuilder::new()
    .fill_color(Rgb565::BLACK)
    .stroke_color(Rgb565::BLUE)
    .stroke_width(3)
    .build();

Circle::new(Point::new(160, 200), 40)
    .into_styled(circle_style)
    .draw(&mut display)
    .map_err(|e| {
        log::error!("Error drawing circle: {:?}", e);
        EspError::from(-1).unwrap()
    })?;

这段代码向屏幕上显示了一行文字,然后在这行文字的下面显示了一个红色三角形、一个绿色正方形和一个蓝色圆形。几何图形的显示比较直接,要显示汉字相对麻烦一点。因为embedded-graphics目前只支持简单的等宽字体,而大部分汉字字体库的格式是TrueType字体,embedded-graphics并不支持。目前智能使用折中的方案,将包含汉字的TrueType字体转换成等宽的位图字体。这里使用了一个开源项目rust-embedded-graphics-cjk,这个项目把TrueType字体转换成embedded-graphics支持的等宽字体。

后记

以上就是如何使用Rust控制LED屏幕显示的关键技术点,验证了使用Rust可以比较方便地使用显示屏显示信息。有兴趣的读者可以到sd_card_rust项目中查看完整代码,此项目需要使用一个经过修改的rust-embedded-graphics-cjk项目。

链接

  1. doc.rs - https://docs.rs/embedded-graphics/latest/embedded_graphics/
  2. sd_card_rust - https://github.com/paul356/sd_card_rust
  3. rust-embedded-graphics-cjk - https://github.com/paul356/rust-embedded-graphics-cjk