-
-
Notifications
You must be signed in to change notification settings - Fork 9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
initial draft of hw accel primitives #8
base: master
Are you sure you want to change the base?
initial draft of hw accel primitives #8
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good so far! I don't have much free time at the moment, but I'll try and get round to testing this on real hardware asap.
/// hardware acceleration. This does no bounds checking. | ||
pub fn draw_hw_line(&mut self, x1: u32, y1: u32, x2: u32, y2: u32, value: u16 | ||
) -> Result<(), Error<CommE, PinE>> { | ||
// TODO: should we try to clip the line to the display here? that could be tricky. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What behaviour does the display have in clipping cases? If it goes offscreen and doesn't do anything like wrapping around, it should be fine to not bother clipping. Presumably this also applies to draw_hw_rect
too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok do we need to clip, or just abort, if any of it is off-screen? I am unfamiliar with what is the standard for these drivers.
Also, generally, do you think this is going to be helpful? I am still on the fence, since mixing blit and hw accel causes noticeable flashing (at least on my softcore).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I haven't done anything using both blitting and HW accel, so I can't comment on that. The draw_hw_rect
method may be useful for the new embedded-graphics 0.7 features so would be worth keeping in IMO, although I can see complications arising when using both HW and the software buffer in this driver.
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. |
Hiya - here's an implementation of
draw_hw_line
anddraw_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.