pico-ice-video/main.cpp

146 lines
3.0 KiB
C++
Raw Normal View History

2024-09-25 00:52:23 +00:00
#include <ice_fpga.h>
#include <ice_led.h>
#include <ice_usb.h>
#include <ice_spi.h>
2024-09-25 00:52:23 +00:00
#include <tusb.h>
2024-09-26 14:28:41 +00:00
#include <boards/pico_ice.h>
2024-09-25 00:52:23 +00:00
#include <bsp/board_api.h>
2024-09-26 14:28:41 +00:00
#include <hardware/clocks.h>
2024-09-25 00:52:23 +00:00
#include <hardware/uart.h>
2024-09-26 14:28:41 +00:00
#include <pico/stdio.h>
#include "fpga.pio.h"
static const PIO pio = pio0;
2024-09-26 14:28:41 +00:00
static uint sm;
static uint8_t frame_buffer[FRAME_WIDTH * FRAME_HEIGHT * 2] = { };
static uint8_t command_buffer[256] = { };
2024-09-25 00:52:23 +00:00
static void video_task();
static void start_next_frame();
static bool finished = false;
2024-09-25 00:52:23 +00:00
int main()
{
2024-09-26 14:28:41 +00:00
tusb_init();
stdio_init_all();
2024-09-25 00:52:23 +00:00
ice_led_init();
ice_usb_init();
ice_fpga_init(4);
2024-09-25 00:52:23 +00:00
ice_fpga_start();
gpio_pull_up(DIR_PIN);
gpio_pull_up(REQ_PIN);
gpio_init(FIN_PIN);
gpio_pull_up(FIN_PIN);
2024-09-26 14:28:41 +00:00
const uint offset = pio_add_program(pio, &fpga_program);
sm = pio_claim_unused_sm(pio, true);
fpga_program_init(pio, sm, offset, 0, DIR_PIN, FIN_PIN);
pio_sm_set_enabled(pio, sm, true);
2024-09-26 14:28:41 +00:00
2024-09-25 00:52:23 +00:00
tud_init(0);
if (board_init_after_tusb)
{
board_init_after_tusb();
}
while (true)
{
2024-10-09 19:18:36 +00:00
uint8_t val = 0;
for (int i = 0; i < 8; i++)
{
val |= gpio_get(i) << i;
}
printf("%d %d %d | %3d |", gpio_get(DIR_PIN), gpio_get(REQ_PIN), gpio_get(FIN_PIN), val);
for (int i = 0; i < 12; i++)
{
printf(" %3d", frame_buffer[i]);
}
printf("\n");
2024-09-25 00:52:23 +00:00
tud_task();
video_task();
}
return 0;
}
static unsigned int interval_ms = 1000 / FRAME_RATE;
static bool tx_busy = false;
static bool rendering = false;
static bool is_rendering() { return rendering || !pio_interrupt_get(pio, 0); }
2024-09-25 00:52:23 +00:00
void video_task()
{
static bool already_sent = false;
static unsigned int start_ms = 0;
if (!tud_video_n_streaming(0, 0))
{
already_sent = false;
return;
}
if (!already_sent)
{
already_sent = true;
tx_busy = true;
start_ms = board_millis();
tud_video_n_frame_xfer(0, 0, frame_buffer, FRAME_WIDTH * FRAME_HEIGHT * 2);
return;
2024-09-25 00:52:23 +00:00
}
const unsigned int cur = board_millis();
if (cur - start_ms < interval_ms) { return; }
if (tx_busy) { return; }
if (is_rendering()) { return; }
2024-09-25 00:52:23 +00:00
start_ms += interval_ms;
tx_busy = true;
tud_video_n_frame_xfer(0, 0, frame_buffer, FRAME_WIDTH * FRAME_HEIGHT * 2);
}
void start_next_frame()
{
if (is_rendering()) { return; }
rendering = true;
command_buffer[0] = (command_buffer[0] + 4) % 256;
if (command_buffer[0] == 0)
{
command_buffer[1] = (command_buffer[1] + 16) % 256;
}
dma_channel_set_trans_count(frame_dma_channel, FRAME_WIDTH * FRAME_HEIGHT * 2, false);
dma_channel_set_write_addr(frame_dma_channel, frame_buffer, false);
dma_channel_set_trans_count(command_dma_channel, 2, false);
dma_channel_set_read_addr(command_dma_channel, command_buffer, true);
// clear irq to indicate ready
while (pio_interrupt_get(pio, 0))
{
pio_interrupt_clear(pio, 0);
}
rendering = false;
2024-09-25 00:52:23 +00:00
}
void tud_video_frame_xfer_complete_cb(uint_fast8_t ctl_idx, uint_fast8_t stm_idx)
{
tx_busy = false;
2024-09-26 14:28:41 +00:00
start_next_frame();
2024-09-25 00:52:23 +00:00
}
int tud_video_commit_cb(uint_fast8_t ctl_idx, uint_fast8_t stm_idx, const video_probe_and_commit_control_t* parameters)
{
interval_ms = parameters->dwFrameInterval / 10000;
return VIDEO_ERROR_NONE;
}