initial draft of hw accel primitives
Hiya - here's an implementation of draw_hw_line and draw_hw_rect. I'm not sure it's really superior in any way to the buffered scheme currently in use, there are so few pixels on these displays anyway. If you think it might be helpful to implement delta updates of the buffer then maybe it would be useful?
The delay on the filled rectangles is also pretty annoying, 10us covered it for a handful of tests for me, could probably be less.
I found some issues when testing on hardware. What the test pattern should look like:

Drawing rectangles off the right of the screen causes them to wrap back round:

And drawing lines out of bounds does this weird thing:

The display is also not cleared of HW drawn items when it's reset, so that we should probably add that in somewhere too.
Complete example code for the tests above is:
#![no_std]
#![no_main]
use cortex_m_rt::{entry, exception, ExceptionFrame};
use panic_semihosting as _;
use ssd1331::{DisplayRotation::Rotate0, Ssd1331};
use stm32f1xx_hal::{
delay::Delay,
prelude::*,
spi::{Mode, Phase, Polarity, Spi},
stm32,
};
#[entry]
fn main() -> ! {
let cp = cortex_m::Peripherals::take().unwrap();
let dp = stm32::Peripherals::take().unwrap();
let mut flash = dp.FLASH.constrain();
let mut rcc = dp.RCC.constrain();
let clocks = rcc.cfgr.freeze(&mut flash.acr);
let mut afio = dp.AFIO.constrain(&mut rcc.apb2);
let mut gpioa = dp.GPIOA.split(&mut rcc.apb2);
let mut gpiob = dp.GPIOB.split(&mut rcc.apb2);
// SPI1
let sck = gpioa.pa5.into_alternate_push_pull(&mut gpioa.crl);
let miso = gpioa.pa6;
let mosi = gpioa.pa7.into_alternate_push_pull(&mut gpioa.crl);
let mut delay = Delay::new(cp.SYST, clocks);
let mut rst = gpiob.pb0.into_push_pull_output(&mut gpiob.crl);
let dc = gpiob.pb1.into_push_pull_output(&mut gpiob.crl);
let spi = Spi::spi1(
dp.SPI1,
(sck, miso, mosi),
&mut afio.mapr,
Mode {
polarity: Polarity::IdleLow,
phase: Phase::CaptureOnFirstTransition,
},
8.mhz(),
clocks,
&mut rcc.apb2,
);
let mut disp = Ssd1331::new(spi, dc, Rotate0);
disp.reset(&mut rst, &mut delay).unwrap();
disp.init().unwrap();
disp.flush().unwrap();
let white = 0xffff;
let red = 0xf800;
let green = 0x07e0;
let blue = 0x001f;
let h_x = 96 / 2;
let h_y = 64 / 2;
disp.draw_hw_rect(5, 5, 15, 15, white, Some(white), &mut delay);
disp.draw_hw_rect(10, 10, 20, 20, red, Some(red), &mut delay);
disp.draw_hw_rect(15, 15, 25, 25, green, Some(green), &mut delay);
disp.draw_hw_rect(20, 20, 30, 30, blue, Some(blue), &mut delay);
// // Goes off the right edge of the screen
// disp.draw_hw_rect(101, 5, 15, 15, white, Some(white), &mut delay);
// disp.draw_hw_rect(106, 10, 20, 20, red, Some(red), &mut delay);
// disp.draw_hw_rect(111, 15, 25, 25, green, Some(green), &mut delay);
// disp.draw_hw_rect(116, 20, 30, 30, blue, Some(blue), &mut delay);
disp.draw_hw_line(5, 5, 91, 59, white);
disp.draw_hw_line(91, 5, 5, 59, red);
disp.draw_hw_line(h_x, 5, h_x, 59, green);
disp.draw_hw_line(5, h_y, 91, h_y, blue);
// // Completely off screen lines
// disp.draw_hw_line(5 + 100, 5 + 100, 91 + 100, 59 + 100, white);
// disp.draw_hw_line(91 + 100, 5 + 100, 5 + 100, 59 + 100, red);
// disp.draw_hw_line(h_x + 100, 5 + 100, h_x + 100, 59 + 100, green);
// disp.draw_hw_line(5 + 100, h_y + 100, 91 + 100, h_y + 100, blue);
// NOTE: Flush will replace any HW-drawn pixels with the current buffer data.
loop {}
}
#[exception]
fn HardFault(ef: &ExceptionFrame) -> ! {
panic!("{:#?}", ef);
}
I haven't forgotten about this, just moved (again). I hope to update this PR soon per your comments.