kopia lustrzana https://github.com/Wren6991/PicoDVI
207 wiersze
6.3 KiB
C
207 wiersze
6.3 KiB
C
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include "hardware/clocks.h"
|
|
#include "hardware/dma.h"
|
|
#include "hardware/gpio.h"
|
|
#include "hardware/irq.h"
|
|
#include "hardware/pll.h"
|
|
#include "hardware/sync.h"
|
|
#include "hardware/structs/bus_ctrl.h"
|
|
#include "hardware/vreg.h"
|
|
#include "pico/multicore.h"
|
|
#include "pico/sem.h"
|
|
#include "pico/stdlib.h"
|
|
|
|
#include "tmds_encode.h"
|
|
|
|
#include "dvi.h"
|
|
#include "dvi_serialiser.h"
|
|
#include "common_dvi_pin_configs.h"
|
|
|
|
#include "mandelbrot.h"
|
|
|
|
// TMDS bit clock 252 MHz
|
|
// DVDD 1.2V (1.1V seems ok too)
|
|
#define FRAME_WIDTH 640
|
|
#define FRAME_HEIGHT 480
|
|
#define VREG_VSEL VREG_VOLTAGE_1_10
|
|
#define DVI_TIMING dvi_timing_640x480p_60hz
|
|
|
|
#define N_IMAGES 3
|
|
#define FRAMES_PER_IMAGE 300
|
|
|
|
uint8_t mandel[FRAME_WIDTH * (FRAME_HEIGHT / 2)];
|
|
|
|
#define PALETTE_BITS 8
|
|
#define PALETTE_SIZE (1 << PALETTE_BITS)
|
|
uint16_t palette[PALETTE_SIZE];
|
|
|
|
uint32_t tmds_palette[PALETTE_SIZE * 6];
|
|
|
|
struct dvi_inst dvi0;
|
|
struct semaphore dvi_start_sem;
|
|
|
|
FractalBuffer fractal;
|
|
|
|
static uint8_t palette_offset = 0;
|
|
|
|
void init_palette() {
|
|
palette[0] = 0;
|
|
for (int i = 1; i < PALETTE_SIZE; ++i) {
|
|
uint8_t c = i + palette_offset;
|
|
if (c < 0x20) palette[i] = c;
|
|
else if (c < 0x40) palette[i] = (c - 0x20) << 6;
|
|
else if (c < 0x60) palette[i] = (c - 0x40) << 11;
|
|
else if (c < 0x80) palette[i] = ((c - 0x60) & 0x1f) * 0x0840;
|
|
else if (c < 0xa0) palette[i] = ((c - 0x80) & 0x1f) * 0x0041;
|
|
else if (c < 0xc0) palette[i] = ((c - 0xa0) & 0x1f) * 0x0801;
|
|
else if (c < 0xe0) palette[i] = ((c - 0xc0) & 0x1f) * 0x0841;
|
|
else palette[i] = 0;
|
|
}
|
|
++palette_offset;
|
|
|
|
tmds_setup_palette_symbols(palette, tmds_palette, PALETTE_SIZE);
|
|
}
|
|
|
|
void init_mandel() {
|
|
for (int y = 0; y < (FRAME_HEIGHT / 2); ++y) {
|
|
uint8_t* buf = &mandel[y * FRAME_WIDTH];
|
|
for (int i = 0; i < FRAME_WIDTH; ++i) {
|
|
buf[i] = ((i + y) & 0x3f);
|
|
}
|
|
}
|
|
|
|
fractal.buff = mandel;
|
|
fractal.rows = FRAME_HEIGHT / 2;
|
|
fractal.cols = FRAME_WIDTH;
|
|
fractal.max_iter = PALETTE_SIZE;
|
|
fractal.iter_offset = 0;
|
|
fractal.minx = -2.25f;
|
|
fractal.maxx = 0.75f;
|
|
fractal.miny = -1.6f;
|
|
fractal.maxy = 0.f - (1.6f / FRAME_HEIGHT); // Half a row
|
|
fractal.use_cycle_check = true;
|
|
init_fractal(&fractal);
|
|
}
|
|
|
|
#define NUM_ZOOMS 64
|
|
static uint32_t zoom_count = 0;
|
|
|
|
void zoom_mandel() {
|
|
if (++zoom_count == NUM_ZOOMS)
|
|
{
|
|
init_mandel();
|
|
zoom_count = 0;
|
|
return;
|
|
}
|
|
|
|
printf("Zoom: %ld\n", zoom_count);
|
|
|
|
float zoomx = -.75f - .7f * ((float)zoom_count / (float)NUM_ZOOMS);
|
|
float sizex = fractal.maxx - fractal.minx;
|
|
float sizey = fractal.miny * -2.f;
|
|
float zoomr = 0.96f * 0.5f;
|
|
fractal.minx = zoomx - zoomr * sizex;
|
|
fractal.maxx = zoomx + zoomr * sizex;
|
|
fractal.miny = -zoomr * sizey;
|
|
fractal.maxy = 0.f + fractal.miny / FRAME_HEIGHT;
|
|
init_fractal(&fractal);
|
|
}
|
|
|
|
// Core 1 handles DMA IRQs and runs TMDS encode on scanline buffers it
|
|
// receives through the mailbox FIFO
|
|
void __not_in_flash("core1_main") core1_main() {
|
|
dvi_register_irqs_this_core(&dvi0, DMA_IRQ_0);
|
|
sem_acquire_blocking(&dvi_start_sem);
|
|
dvi_start(&dvi0);
|
|
|
|
while (1) {
|
|
const uint32_t *colourbuf = (const uint32_t*)multicore_fifo_pop_blocking();
|
|
uint32_t *tmdsbuf = (uint32_t*)multicore_fifo_pop_blocking();
|
|
tmds_encode_palette_data((const uint32_t*)colourbuf, tmds_palette, tmdsbuf, FRAME_WIDTH, PALETTE_BITS);
|
|
multicore_fifo_push_blocking(0);
|
|
while (!fractal.done && queue_get_level(&dvi0.q_tmds_valid) >= 5) generate_steal_one(&fractal);
|
|
}
|
|
__builtin_unreachable();
|
|
}
|
|
|
|
int __not_in_flash("main") main() {
|
|
vreg_set_voltage(VREG_VSEL);
|
|
sleep_ms(10);
|
|
set_sys_clock_khz(DVI_TIMING.bit_clk_khz, true);
|
|
|
|
setup_default_uart();
|
|
|
|
gpio_init(PICO_DEFAULT_LED_PIN);
|
|
gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT);
|
|
|
|
init_palette();
|
|
init_mandel();
|
|
|
|
printf("Configuring DVI\n");
|
|
|
|
dvi0.timing = &DVI_TIMING;
|
|
dvi0.ser_cfg = DVI_DEFAULT_SERIAL_CONFIG;
|
|
dvi_init(&dvi0, next_striped_spin_lock_num(), next_striped_spin_lock_num());
|
|
|
|
printf("Core 1 start\n");
|
|
sem_init(&dvi_start_sem, 0, 1);
|
|
hw_set_bits(&bus_ctrl_hw->priority, BUSCTRL_BUS_PRIORITY_PROC1_BITS);
|
|
multicore_launch_core1(core1_main);
|
|
|
|
uint heartbeat = 0;
|
|
uint32_t encode_time = 0;
|
|
|
|
sem_release(&dvi_start_sem);
|
|
while (1) {
|
|
if (++heartbeat >= 30) {
|
|
heartbeat = 0;
|
|
gpio_xor_mask(1u << PICO_DEFAULT_LED_PIN);
|
|
|
|
printf("Encode total time: %ldus\n", encode_time);
|
|
encode_time = 0;
|
|
}
|
|
if (fractal.done) zoom_mandel();
|
|
//if (heartbeat & 1) init_palette();
|
|
for (int y = 0; y < FRAME_HEIGHT / 2; y += 2) {
|
|
uint32_t *our_tmds_buf, *their_tmds_buf;
|
|
queue_remove_blocking_u32(&dvi0.q_tmds_free, &their_tmds_buf);
|
|
multicore_fifo_push_blocking((uint32_t)(&mandel[y*FRAME_WIDTH]));
|
|
multicore_fifo_push_blocking((uint32_t)their_tmds_buf);
|
|
|
|
queue_remove_blocking_u32(&dvi0.q_tmds_free, &our_tmds_buf);
|
|
absolute_time_t start_time = get_absolute_time();
|
|
tmds_encode_palette_data((const uint32_t*)(&mandel[(y+1)*FRAME_WIDTH]), tmds_palette, our_tmds_buf, FRAME_WIDTH, PALETTE_BITS);
|
|
encode_time += absolute_time_diff_us(start_time, get_absolute_time());
|
|
|
|
multicore_fifo_pop_blocking();
|
|
|
|
while (!fractal.done && queue_get_level(&dvi0.q_tmds_valid) >= 5) generate_one_forward(&fractal);
|
|
|
|
queue_add_blocking_u32(&dvi0.q_tmds_valid, &their_tmds_buf);
|
|
queue_add_blocking_u32(&dvi0.q_tmds_valid, &our_tmds_buf);
|
|
}
|
|
for (int y = FRAME_HEIGHT / 2 - 2; y >= 0; y -= 2) {
|
|
uint32_t *our_tmds_buf, *their_tmds_buf;
|
|
queue_remove_blocking_u32(&dvi0.q_tmds_free, &their_tmds_buf);
|
|
multicore_fifo_push_blocking((uint32_t)(&mandel[(y+1)*FRAME_WIDTH]));
|
|
multicore_fifo_push_blocking((uint32_t)their_tmds_buf);
|
|
|
|
queue_remove_blocking_u32(&dvi0.q_tmds_free, &our_tmds_buf);
|
|
absolute_time_t start_time = get_absolute_time();
|
|
tmds_encode_palette_data((const uint32_t*)(&mandel[y*FRAME_WIDTH]), tmds_palette, our_tmds_buf, FRAME_WIDTH, PALETTE_BITS);
|
|
encode_time += absolute_time_diff_us(start_time, get_absolute_time());
|
|
|
|
multicore_fifo_pop_blocking();
|
|
|
|
while (!fractal.done && queue_get_level(&dvi0.q_tmds_valid) >= 5) generate_one_forward(&fractal);
|
|
|
|
queue_add_blocking_u32(&dvi0.q_tmds_valid, &their_tmds_buf);
|
|
queue_add_blocking_u32(&dvi0.q_tmds_valid, &our_tmds_buf);
|
|
}
|
|
}
|
|
__builtin_unreachable();
|
|
}
|
|
|