Hi,
I have a question about a DMA not fireing an IRQ upon completion. This is a part of a library that aims to use the RP2040/RP2350 as a bridge between an 8080 display data input and RGB ("DPI") display output.
Now, a PIO is busy receiving data from the input. The DMA reads the incoming data. Once a line is received, an interrupt should be triggered to start some data processing and restart the DMA. However, this never happens. In the code below, I expect the IRQ handler to assert zero but that never happens. I am sure that the PIO is working correctly and delivering data as the program is working as expected when using a loop, waiting for the DMA to complete and then retrigger the DMA "manually" (without interrupt).
I guess it must be something stupid as I have used a DMA in conjunction with an IRQ many times before but I just can find the error. I hope that a fresh pair of eyes might immediatly point me to the cause of the error. I have attached the code below, the part of interest is probably in lcd_dma_init; that's where the interrupt handler gets installed (apologies for the messiness as it's at a very early stage of development).
Thank you for any input in advance and best regards
I have a question about a DMA not fireing an IRQ upon completion. This is a part of a library that aims to use the RP2040/RP2350 as a bridge between an 8080 display data input and RGB ("DPI") display output.
Now, a PIO is busy receiving data from the input. The DMA reads the incoming data. Once a line is received, an interrupt should be triggered to start some data processing and restart the DMA. However, this never happens. In the code below, I expect the IRQ handler to assert zero but that never happens. I am sure that the PIO is working correctly and delivering data as the program is working as expected when using a loop, waiting for the DMA to complete and then retrigger the DMA "manually" (without interrupt).
I guess it must be something stupid as I have used a DMA in conjunction with an IRQ many times before but I just can find the error. I hope that a fresh pair of eyes might immediatly point me to the cause of the error. I have attached the code below, the part of interest is probably in lcd_dma_init; that's where the interrupt handler gets installed (apologies for the messiness as it's at a very early stage of development).
Thank you for any input in advance and best regards
Code:
#include <stdio.h>#include "pico/stdlib.h"#include "hardware/vreg.h"#include "hardware/resets.h"#include "hardware/dma.h"#include "hardware/irq.h"#include "pico/mutex.h"#include "lcd_pio_receive.h"#define LED_BUILTIN (25)#define LCD_RES_X (320)#define LCD_PIN_DB0 (4)#define LCD_PIN_CLK (20)/******************************* PIO ****************************/typedef enum { LCD_SUCCESS = 0, /**< @brief Command completed successfully */ LCD_UNKNOWN_ERROR = -1, /**< @brief An unknown error occured. */ LCD_NOT_INIT = -3, /**< @brief The LCD interface has not yet * been setup.*/ LCD_DMA_ERR = -4,/**< @brief An error has occcured setup up or * using the DMA.*/ LCD_PIO_ERR = -5 /**< @brief An error has occcured setup up or * using the PIO.*/} lcd_error_t ; PIO lcd_pio[2] = {pio0, pio1};int8_t lcd_pio_sm_rx[3];bool lcd_pio_enabled = false;/******************************* DMA ****************************/mutex_t line_rxed;#define LCD_DMA_IRQ (DMA_IRQ_0) // 0 or 1int32_t lcd_dma_chan_rx;dma_channel_config lcd_dma_config_rx;bool lcd_dma_enabled = false;#define NUM_RX_BUF 2uint16_t __aligned(32) linebuf_rx[NUM_RX_BUF][LCD_RES_X];volatile int curlinebuf_rx = 0;/******************************* Implementation ****************************/void __isr lcd_dma_handler_rx() { assert(0);} // lcd_dma_handler_rxlcd_error_t lcd_dma_init() { if (!lcd_pio_enabled) return LCD_PIO_ERR; if (lcd_dma_enabled) return LCD_SUCCESS; lcd_dma_chan_rx = dma_claim_unused_channel(true); if (lcd_dma_chan_rx < 0) return LCD_DMA_ERR; lcd_dma_config_rx = dma_channel_get_default_config(lcd_dma_chan_rx); channel_config_set_transfer_data_size(&lcd_dma_config_rx, DMA_SIZE_32); channel_config_set_read_increment(&lcd_dma_config_rx, false); channel_config_set_dreq(&lcd_dma_config_rx, pio_get_dreq(lcd_pio[1], lcd_pio_sm_rx[0], false /* false = rx */)); dma_irqn_set_channel_enabled(LCD_DMA_IRQ, lcd_dma_chan_rx, true); // PIO if (irq_get_exclusive_handler(LCD_DMA_IRQ) == NULL) irq_set_exclusive_handler(LCD_DMA_IRQ, lcd_dma_handler_rx); irq_set_enabled(LCD_DMA_IRQ, true); dma_channel_configure(lcd_dma_chan_rx, &lcd_dma_config_rx, linebuf_rx[curlinebuf_rx], &lcd_pio[1]->rxf[lcd_pio_sm_rx[0]], LCD_RES_X / 2, true /* trigger now */); lcd_dma_enabled = true; return LCD_SUCCESS;} // lcd_dma_initlcd_error_t lcd_pio_init() { if (lcd_pio_enabled) return LCD_SUCCESS; for (int i = 0; i < 2; i++) { lcd_pio_sm_rx[i] = pio_claim_unused_sm(lcd_pio[1], false); if (lcd_pio_sm_rx[i] < 0) return LCD_PIO_ERR; } // clear GPIO states (high-impedance, no pullups etc) gpio_init (LCD_PIN_CLK); for (int i = 0; i < 8; i++) gpio_init (LCD_PIN_DB0 + i); /****************************** data input sm ******************************/ uint32_t program_offset = pio_add_program(lcd_pio[1], &lcd_rx_main_program); pio_sm_config pio_cfg = lcd_rx_main_program_get_default_config(program_offset); // setup data pins sm_config_set_in_pin_base(&pio_cfg, LCD_PIN_DB0); // configure the SM sm_config_set_fifo_join(&pio_cfg, PIO_FIFO_JOIN_RX); sm_config_set_clkdiv_int_frac(&pio_cfg, 1, 0); sm_config_set_in_shift(&pio_cfg, true, true, 32); // ISR shifts in to the right (true) = default, autopush, pull threshold pio_sm_init(lcd_pio[1], lcd_pio_sm_rx[0], program_offset, &pio_cfg);#if 1 // clear FIFO & ISR for (int i = 0; i < 8; i++) pio_sm_get(lcd_pio[1], lcd_pio_sm_rx[0]); pio_sm_exec(lcd_pio[1], lcd_pio_sm_rx[0], pio_encode_in(pio_null, 32));#endif /****************************** clock sm ******************************/ program_offset = pio_add_program(lcd_pio[1], &lcd_rx_irq_program); pio_cfg = lcd_rx_irq_program_get_default_config(program_offset); // setup pins (CLK only) sm_config_set_in_pin_base(&pio_cfg, LCD_PIN_CLK); // configure the SM sm_config_set_clkdiv_int_frac(&pio_cfg, 1, 0); pio_sm_init(lcd_pio[1], lcd_pio_sm_rx[1], program_offset, &pio_cfg); // start all SMs for (int i = 0; i < 2; i++) pio_sm_set_enabled(lcd_pio[1], lcd_pio_sm_rx[i], true /* enable */); lcd_pio_enabled = true; return LCD_SUCCESS;} // lcd_pio_initlcd_error_t lcd_init() { lcd_error_t res = LCD_SUCCESS; curlinebuf_rx = 0; res = lcd_pio_init(); if (res != LCD_SUCCESS) return res; res = lcd_dma_init(); if (res != LCD_SUCCESS) return res; return res;} // lcd_initint main() { stdio_init_all(); gpio_init(LED_BUILTIN); gpio_set_dir(LED_BUILTIN, GPIO_OUT); mutex_init(&line_rxed); lcd_init(); while (1) { while(dma_channel_is_busy(lcd_dma_chan_rx)); dma_channel_configure(lcd_dma_chan_rx, &lcd_dma_config_rx, linebuf_rx[curlinebuf_rx], // dst &lcd_pio[1]->rxf[lcd_pio_sm_rx[0]], // src LCD_RES_X / 2, true /* trigger now */); curlinebuf_rx = (curlinebuf_rx + 1) % 2; }}
Statistics: Posted by fcipaq — Fri Dec 06, 2024 9:15 am — Replies 0 — Views 35