PicoDVI/software/apps/mandel-full/main.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();
}