From 52a107e6d6a3d0b2a34cd43b2a5c7661fc7f50cc Mon Sep 17 00:00:00 2001 From: ZodiusInfuser Date: Tue, 20 Sep 2022 12:42:18 +0100 Subject: [PATCH] Switched GU over to chained DMA to remove interrupt use --- .../galactic_unicorn/galactic_unicorn.cpp | 61 +++++++++++-------- .../galactic_unicorn/galactic_unicorn.hpp | 2 +- 2 files changed, 36 insertions(+), 27 deletions(-) diff --git a/libraries/galactic_unicorn/galactic_unicorn.cpp b/libraries/galactic_unicorn/galactic_unicorn.cpp index 66830313..54219239 100644 --- a/libraries/galactic_unicorn/galactic_unicorn.cpp +++ b/libraries/galactic_unicorn/galactic_unicorn.cpp @@ -43,6 +43,7 @@ static uint16_t g_gamma_lut[256] = {0}; static uint16_t b_gamma_lut[256] = {0}; static uint32_t dma_channel; +static uint32_t dma_ctrl_channel; static uint32_t audio_dma_channel; namespace pimoroni { @@ -58,39 +59,24 @@ namespace pimoroni { // once the dma transfer of the scanline is complete we move to the // next scanline (or quit if we're finished) void __isr GalacticUnicorn::dma_complete() { - if(unicorn != nullptr) { - if(dma_channel_get_irq0_status(dma_channel)) { - unicorn->next_bitstream_sequence(); - } - if(dma_channel_get_irq0_status(audio_dma_channel)) { - unicorn->next_audio_sequence(); - } + if(unicorn != nullptr && dma_channel_get_irq0_status(audio_dma_channel)) { + unicorn->next_audio_sequence(); } } - void GalacticUnicorn::next_bitstream_sequence() { - // Clear any interrupt request caused by our channel - //dma_channel_acknowledge_irq0(dma_channel); - // NOTE Temporary replacement of the above until this reaches pico-sdk main: - // https://github.com/raspberrypi/pico-sdk/issues/974 - dma_hw->ints0 = 1u << dma_channel; - - dma_channel_set_trans_count(dma_channel, BITSTREAM_LENGTH / 4, false); - dma_channel_set_read_addr(dma_channel, bitstream, true); - } - GalacticUnicorn::~GalacticUnicorn() { if(unicorn == this) { partial_teardown(); + dma_channel_unclaim(dma_ctrl_channel); // This works now the teardown behaves correctly dma_channel_unclaim(dma_channel); // This works now the teardown behaves correctly pio_sm_unclaim(bitstream_pio, bitstream_sm); pio_remove_program(bitstream_pio, &galactic_unicorn_program, bitstream_sm_offset); - irq_remove_handler(DMA_IRQ_0, dma_complete); dma_channel_unclaim(audio_dma_channel); // This works now the teardown behaves correctly pio_sm_unclaim(audio_pio, audio_sm); pio_remove_program(audio_pio, &audio_i2s_program, audio_sm_offset); + irq_remove_handler(DMA_IRQ_0, dma_complete); unicorn = nullptr; } @@ -104,7 +90,13 @@ namespace pimoroni { const uint pins_to_set = 1 << COLUMN_BLANK | 0b1111 << ROW_BIT_0; pio_sm_set_pins_with_mask(bitstream_pio, bitstream_sm, pins_to_set, pins_to_set); + + dma_hw->ch[dma_ctrl_channel].al1_ctrl = (dma_hw->ch[dma_ctrl_channel].al1_ctrl & ~DMA_CH0_CTRL_TRIG_CHAIN_TO_BITS) | (dma_ctrl_channel << DMA_CH0_CTRL_TRIG_CHAIN_TO_LSB); + dma_hw->ch[dma_channel].al1_ctrl = (dma_hw->ch[dma_channel].al1_ctrl & ~DMA_CH0_CTRL_TRIG_CHAIN_TO_BITS) | (dma_channel << DMA_CH0_CTRL_TRIG_CHAIN_TO_LSB); // Abort any in-progress DMA transfer + dma_safe_abort(dma_ctrl_channel); + //dma_channel_abort(dma_ctrl_channel); + //dma_channel_abort(dma_channel); dma_safe_abort(dma_channel); @@ -286,28 +278,47 @@ namespace pimoroni { sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX); // setup dma transfer for pixel data to the pio - if(unicorn == nullptr) { + //if(unicorn == nullptr) { dma_channel = dma_claim_unused_channel(true); - } + dma_ctrl_channel = dma_claim_unused_channel(true); + //} + dma_channel_config ctrl_config = dma_channel_get_default_config(dma_ctrl_channel); + channel_config_set_transfer_data_size(&ctrl_config, DMA_SIZE_32); + channel_config_set_read_increment(&ctrl_config, false); + channel_config_set_write_increment(&ctrl_config, false); + channel_config_set_chain_to(&ctrl_config, dma_channel); + + dma_channel_configure( + dma_ctrl_channel, + &ctrl_config, + &dma_hw->ch[dma_channel].read_addr, + &bitstream_addr, + 1, + false + ); + + dma_channel_config config = dma_channel_get_default_config(dma_channel); channel_config_set_transfer_data_size(&config, DMA_SIZE_32); channel_config_set_bswap(&config, false); // byte swap to reverse little endian channel_config_set_dreq(&config, pio_get_dreq(bitstream_pio, bitstream_sm, true)); + channel_config_set_chain_to(&config, dma_ctrl_channel); dma_channel_configure( dma_channel, &config, &bitstream_pio->txf[bitstream_sm], NULL, - 0, + BITSTREAM_LENGTH / 4, false); - dma_channel_set_irq0_enabled(dma_channel, true); - pio_sm_init(bitstream_pio, bitstream_sm, bitstream_sm_offset, &c); pio_sm_set_enabled(bitstream_pio, bitstream_sm, true); + // start the control channel + dma_start_channel_mask(1u << dma_ctrl_channel); + // setup audio pio program audio_pio = pio0; @@ -340,8 +351,6 @@ namespace pimoroni { } unicorn = this; - - next_bitstream_sequence(); } void GalacticUnicorn::clear() { diff --git a/libraries/galactic_unicorn/galactic_unicorn.hpp b/libraries/galactic_unicorn/galactic_unicorn.hpp index 00e52439..79b39fff 100644 --- a/libraries/galactic_unicorn/galactic_unicorn.hpp +++ b/libraries/galactic_unicorn/galactic_unicorn.hpp @@ -67,6 +67,7 @@ namespace pimoroni { // must be aligned for 32bit dma transfer alignas(4) uint8_t bitstream[BITSTREAM_LENGTH] = {0}; + const uint32_t bitstream_addr = (uint32_t)bitstream; static GalacticUnicorn* unicorn; static void dma_complete(); @@ -117,7 +118,6 @@ namespace pimoroni { AudioChannel& synth_channel(uint channel); private: - void next_bitstream_sequence(); void partial_teardown(); void dma_safe_abort(uint channel); void next_audio_sequence();