-
Notifications
You must be signed in to change notification settings - Fork 215
Description
I'm working on a small project combining an SSD1309 display driven by a SAMD21G18A mcu. I'm hoping to use embassy in order to display graphics until a user presses a button, but I'm having some strange issues with async:
bind_interrupts!(struct Irqs {
EIC => eic::InterruptHandler;
SERCOM0 => sercom::i2c::InterruptHandler<sercom::Sercom0>;
DMAC => dmac::InterruptHandler;
});
#[embassy_executor::main]
async fn main(_spawn: Spawner) {
// Setup
let mut peripherals = pac::Peripherals::take().unwrap();
let _core = pac::CorePeripherals::take().unwrap();
let mut clocks = clock::GenericClockController::with_internal_8mhz(
peripherals.gclk,
&mut peripherals.pm,
&mut peripherals.sysctrl,
&mut peripherals.nvmctrl,
);
let pins = gpio::Pins::new(peripherals.port);
// Initialize DMA Controller
let mut dmac =
dmac::DmaController::init(peripherals.dmac, &mut peripherals.pm).into_future(Irqs);
let channels: dmac::FutureChannels = dmac.split();
let channel: dmac::Channel<dmac::Ch0, dmac::ReadyFuture> =
channels.0.init(dmac::PriorityLevel::Lvl0);
// I2C
let gclk0 = clocks.gclk0();
let sercom0_clock = &clocks.sercom0_core(&gclk0).unwrap();
let pads = sercom::i2c::Pads::new(
pins.pa08.into_alternate::<gpio::C>(), // A4
pins.pa09.into_alternate::<gpio::C>(), // A5
);
let i2c = sercom::i2c::Config::new(
&peripherals.pm,
peripherals.sercom0,
pads,
sercom0_clock.freq(),
)
.baud(400.kHz())
.enable()
.into_future(Irqs)
.with_dma_channel(channel); // -- works if removed --
// Display
let di: I2CInterface<_> = display_interface_i2c::I2CInterface::new(i2c, 0x3C, 0x40);
let mut display: GraphicsMode<_, _> =
oled_async::Builder::new(oled_async::displays::ssd1309::Ssd1309_128_64 {})
.connect(di)
.into();
display.init().await.unwrap();
display.clear();
display.fill_solid(&display.bounding_box(), On).unwrap();
display.flush().await.unwrap();
loop {}
}I can see the display spring to life and display a block of white, however it doesn't fill the entire screen, and adding panics to the code shows me that it never reaches beyond display.flush().await.unwrap();. Interestingly, as soon as I remove .with_dma_channel(channel); from the i2c config, everything does work, though slow enough to see blocks of the screen update in sequence (exactly what I hoped to prevent by using DMA). Could this be an issue with the DMA implementation in atsamd hal not waking up the executor? From what I saw in the existing examples there doesn't seem to be any additional setup or interrupts that need to be configured to get DMA working.
