#include "crtc.h" #include #include "hardware/pio.h" #include "hardware/structs/pio.h" #include "hardware/dma.h" #include "framebuffer.h" #include "crtc.pio.h" typedef struct PIORun { PIO pio; //< executing PIO uint offset; //< PIO memory offset for program uint sm; //< executing SM } PIORun; static PIORun crtc_vsync, crtc_hsync, crtc_pixel; static int dma_channel; bool dma_ready = false; static void crtc_pixel_program_init(PIO pio, uint sm, uint offset) { pio_sm_config config = crtc_pixel_program_get_default_config(offset); pio_gpio_init(pio, 11); sm_config_set_in_pins(&config, 11); sm_config_set_in_shift(&config, true, true, 0); pio_sm_set_consecutive_pindirs(pio, sm, 11, 1, false); sm_config_set_wrap(&config, offset + crtc_pixel_wrap_target, offset + crtc_pixel_wrap); pio_sm_init(pio, sm, offset, &config); // not quite 4x pixel clock (2.1 = 2,25.6) pio_sm_set_clkdiv_int_frac(pio, sm, 2, 26); pio_sm_set_enabled(pio, sm, true); } static void crtc_hsync_program_init(PIO pio, uint sm, uint offset) { pio_sm_config config = crtc_hsync_program_get_default_config(offset); sm_config_set_wrap(&config, offset + crtc_hsync_wrap_target, offset + crtc_hsync_wrap); pio_sm_init(pio, sm, offset, &config); pio_sm_set_clkdiv_int_frac(pio, sm, 2, 26); pio_sm_set_enabled(pio, sm, true); } static void crtc_vsync_program_init(PIO pio, uint sm, uint offset) { pio_sm_config config = crtc_vsync_program_get_default_config(offset); pio_gpio_init(pio, 15); sm_config_set_wrap(&config, offset + crtc_vsync_wrap_target, offset + crtc_vsync_wrap); pio_sm_init(pio, sm, offset, &config); pio_sm_set_clkdiv_int_frac(pio, sm, 2, 26); pio_sm_set_enabled(pio, sm, true); } int dma_counter = 0; static void dma_handler(void) { dma_counter++; // reset DMA dma_channel_set_write_addr(dma_channel, &frame[2560], true); // acknoweledge DMA dma_hw->ints1 = 1 << dma_channel; } int crtc_frame_counter = 0; static void new_frame_handler(void) { pio_sm_clear_fifos(crtc_pixel.pio, crtc_pixel.sm); crtc_frame_counter++; pio_interrupt_clear(pio1_hw, 1); } void crtc_machines_init(void) { crtc_hsync.pio = crtc_vsync.pio = crtc_pixel.pio = pio1; printf("Starting CRTC pixel machine... "); if (!pio_can_add_program(crtc_pixel.pio, &crtc_pixel_program)) panic("cannot add program"); crtc_pixel.offset = pio_add_program(crtc_pixel.pio, &crtc_pixel_program); crtc_pixel.sm = pio_claim_unused_sm(crtc_pixel.pio, true); crtc_pixel_program_init(crtc_pixel.pio, crtc_pixel.sm, crtc_pixel.offset); pio_sm_put_blocking(crtc_pixel.pio, crtc_pixel.sm, 640 - 1); printf("OK\n"); printf("Starting CRTC vsync machine... "); if (!pio_can_add_program(crtc_vsync.pio, &crtc_vsync_program)) panic("cannot add program"); crtc_vsync.offset = pio_add_program(crtc_vsync.pio, &crtc_vsync_program); crtc_vsync.sm = pio_claim_unused_sm(crtc_vsync.pio, true); crtc_vsync_program_init(crtc_vsync.pio, crtc_vsync.sm, crtc_vsync.offset); printf("OK\n"); printf("Starting CRTC hsync machine... "); if (!pio_can_add_program(crtc_hsync.pio, &crtc_hsync_program)) panic("cannot add program"); crtc_hsync.offset = pio_add_program(crtc_hsync.pio, &crtc_hsync_program); crtc_hsync.sm = pio_claim_unused_sm(crtc_hsync.pio, true); crtc_hsync_program_init(crtc_hsync.pio, crtc_hsync.sm, crtc_hsync.offset); pio_sm_put_blocking(crtc_hsync.pio, crtc_hsync.sm, 128 - 1); printf("OK\n"); printf("Setting up new frame interrupt... "); // Frame interrupt is asserted on PIO1 interrupt 1 by SM1 pio_set_irq1_source_enabled(crtc_vsync.pio, pis_interrupt1, true); // allow SM1 of PIO to fire the interrupt irq_set_exclusive_handler(PIO1_IRQ_1, new_frame_handler); // set handler for IRQ1 of PIO irq_set_enabled(PIO1_IRQ_1, true); // enable interrupt printf("OK\n"); printf("Setting up CRTC DMA... "); dma_channel = dma_claim_unused_channel(true); printf("channel %d... ", dma_channel); dma_channel_config dma_config = dma_channel_get_default_config(dma_channel); channel_config_set_transfer_data_size(&dma_config, DMA_SIZE_32); channel_config_set_read_increment(&dma_config, false); channel_config_set_write_increment(&dma_config, true); channel_config_set_dreq(&dma_config, DREQ_PIO1_RX0); // setup transfer acknowledge interrupt dma_channel_set_irq1_enabled(dma_channel, true); irq_set_exclusive_handler(DMA_IRQ_1, dma_handler); irq_set_enabled(DMA_IRQ_1, true); dma_channel_configure(dma_channel, &dma_config, &frame[2560], &pio1_hw->rxf[0], 640 * 128 / 32, true); dma_ready = true; printf("OK\n"); }