Picovision: Remove DV stick drivers to PV repo.

pull/821/head
Phil Howard 2023-08-21 12:49:51 +01:00
rodzic 211e0aa618
commit 1157e605a1
29 zmienionych plików z 1 dodań i 31642 usunięć

Wyświetl plik

@ -43,6 +43,4 @@ add_subdirectory(st7567)
add_subdirectory(psram_display)
add_subdirectory(inky73)
add_subdirectory(shiftregister)
add_subdirectory(mlx90640)
add_subdirectory(aps6404)
add_subdirectory(dv_display)
add_subdirectory(mlx90640)

Wyświetl plik

@ -1 +0,0 @@
include(aps6404.cmake)

Wyświetl plik

@ -1,12 +0,0 @@
set(DRIVER_NAME aps6404)
add_library(${DRIVER_NAME} INTERFACE)
target_sources(${DRIVER_NAME} INTERFACE
${CMAKE_CURRENT_LIST_DIR}/aps6404.cpp
)
pico_generate_pio_header(${DRIVER_NAME} ${CMAKE_CURRENT_LIST_DIR}/aps6404.pio)
target_include_directories(${DRIVER_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR})
target_link_libraries(${DRIVER_NAME} INTERFACE pico_stdlib hardware_pio hardware_dma hardware_irq)

Wyświetl plik

@ -1,299 +0,0 @@
#include <algorithm>
#include "aps6404.hpp"
#include "hardware/dma.h"
#include "hardware/irq.h"
#include "hardware/sync.h"
#include "hardware/clocks.h"
#include "pico/stdlib.h"
#include "aps6404.pio.h"
#ifndef MICROPY_BUILD_TYPE
#define mp_printf(_, ...) printf(__VA_ARGS__);
#else
extern "C" {
#include "py/runtime.h"
}
#endif
static const pio_program* pio_prog[2] = {nullptr, nullptr};
static uint16_t pio_offset[2] = {0xffff, 0xffff};
const void pio_remove_exclusive_program(PIO pio) {
uint8_t pio_index = pio == pio0 ? 0 : 1;
const pio_program* current_program = pio_prog[pio_index];
uint16_t current_offset = pio_offset[pio_index];
if(current_program) {
pio_remove_program(pio, current_program, current_offset);
pio_prog[pio_index] = nullptr;
pio_offset[pio_index] = 0xffff;
}
}
const uint16_t pio_change_exclusive_program(PIO pio, const pio_program* prog) {
pio_remove_exclusive_program(pio);
uint8_t pio_index = pio == pio0 ? 0 : 1;
pio_prog[pio_index] = prog;
pio_offset[pio_index] = pio_add_program(pio, prog);
return pio_offset[pio_index];
};
namespace pimoroni {
APS6404::APS6404(uint pin_csn, uint pin_d0, PIO pio)
: pin_csn(pin_csn)
, pin_d0(pin_d0)
, pio(pio)
{
// Initialize data pins
for (int i = 0; i < 4; ++i) {
gpio_init(pin_d0 + i);
gpio_disable_pulls(pin_d0 + i);
}
pio_sm = pio_claim_unused_sm(pio, true);
// Claim DMA channels
dma_channel = dma_claim_unused_channel(true);
read_cmd_dma_channel = dma_claim_unused_channel(true);
}
void APS6404::init() {
pio_sm_set_enabled(pio, pio_sm, false);
pio_offset = pio_change_exclusive_program(pio, &sram_reset_program);
aps6404_reset_program_init(pio, pio_sm, pio_offset, pin_csn, pin_d0);
sleep_us(200);
pio_sm_put_blocking(pio, pio_sm, 0x00000007u);
pio_sm_put_blocking(pio, pio_sm, 0x66000000u);
pio_sm_put_blocking(pio, pio_sm, 0x00000007u);
pio_sm_put_blocking(pio, pio_sm, 0x99000000u);
pio_sm_put_blocking(pio, pio_sm, 0x00000007u);
pio_sm_put_blocking(pio, pio_sm, 0x35000000u);
sleep_us(500);
adjust_clock();
}
void APS6404::set_qpi() {
pio_sm_set_enabled(pio, pio_sm, false);
pio_offset = pio_change_exclusive_program(pio, &sram_reset_program);
aps6404_reset_program_init(pio, pio_sm, pio_offset, pin_csn, pin_d0);
pio_sm_put_blocking(pio, pio_sm, 0x00000007u);
pio_sm_put_blocking(pio, pio_sm, 0x35000000u);
while (!pio_sm_is_tx_fifo_empty(pio, pio_sm) || pio->sm[pio_sm].addr != pio_offset);
adjust_clock();
}
void APS6404::set_spi() {
pio_sm_set_enabled(pio, pio_sm, false);
pio_offset = pio_change_exclusive_program(pio, &sram_reset_qpi_program);
aps6404_program_init(pio, pio_sm, pio_offset, pin_csn, pin_d0, false, false, true);
pio_sm_put_blocking(pio, pio_sm, 0x00000001u);
pio_sm_put_blocking(pio, pio_sm, 0xF5000000u);
}
void APS6404::adjust_clock() {
pio_sm_set_enabled(pio, pio_sm, false);
if (clock_get_hz(clk_sys) > 296000000) {
pio_offset = pio_change_exclusive_program(pio, &sram_fast_program);
aps6404_program_init(pio, pio_sm, pio_offset, pin_csn, pin_d0, false, true, false);
}
else if (clock_get_hz(clk_sys) < 130000000) {
pio_offset = pio_change_exclusive_program(pio, &sram_slow_program);
aps6404_program_init(pio, pio_sm, pio_offset, pin_csn, pin_d0, true, false, false);
}
else {
pio_offset = pio_change_exclusive_program(pio, &sram_program);
aps6404_program_init(pio, pio_sm, pio_offset, pin_csn, pin_d0, false, false, false);
}
last_cmd_was_write = false;
}
void APS6404::write(uint32_t addr, uint32_t* data, uint32_t len_in_bytes) {
if (!last_cmd_was_write) {
dma_channel_config c = dma_channel_get_default_config(dma_channel);
channel_config_set_read_increment(&c, true);
channel_config_set_write_increment(&c, false);
channel_config_set_dreq(&c, pio_get_dreq(pio, pio_sm, true));
channel_config_set_transfer_data_size(&c, DMA_SIZE_32);
channel_config_set_bswap(&c, true);
wait_for_finish_blocking();
setup_cmd_buffer_dma(true);
last_cmd_was_write = true;
dma_channel_configure(
dma_channel, &c,
&pio->txf[pio_sm],
nullptr,
1,
false
);
}
for (int len = len_in_bytes, page_len = std::min(PAGE_SIZE, len);
len > 0;
addr += page_len, data += page_len >> 2, len -= page_len, page_len = std::min(PAGE_SIZE, len))
{
wait_for_finish_blocking();
hw_set_bits(&dma_hw->ch[dma_channel].al1_ctrl, DMA_CH0_CTRL_TRIG_INCR_READ_BITS);
pio_sm_put_blocking(pio, pio_sm, (page_len << 1) - 1);
pio_sm_put_blocking(pio, pio_sm, 0x38000000u | addr);
pio_sm_put_blocking(pio, pio_sm, pio_offset + sram_offset_do_write);
dma_channel_transfer_from_buffer_now(dma_channel, data, (page_len >> 2) + 1);
}
}
void APS6404::write_repeat(uint32_t addr, uint32_t data, uint32_t len_in_bytes) {
if (!last_cmd_was_write) {
dma_channel_config c = dma_channel_get_default_config(dma_channel);
channel_config_set_read_increment(&c, false);
channel_config_set_write_increment(&c, false);
channel_config_set_dreq(&c, pio_get_dreq(pio, pio_sm, true));
channel_config_set_transfer_data_size(&c, DMA_SIZE_32);
channel_config_set_bswap(&c, true);
wait_for_finish_blocking();
setup_cmd_buffer_dma(true);
last_cmd_was_write = true;
dma_channel_configure(
dma_channel, &c,
&pio->txf[pio_sm],
nullptr,
1,
false
);
}
for (int len = len_in_bytes, page_len = std::min(PAGE_SIZE, len);
len > 0;
addr += page_len, len -= page_len, page_len = std::min(PAGE_SIZE, len))
{
wait_for_finish_blocking();
hw_clear_bits(&dma_hw->ch[dma_channel].al1_ctrl, DMA_CH0_CTRL_TRIG_INCR_READ_BITS);
repeat_data = data;
pio_sm_put_blocking(pio, pio_sm, (page_len << 1) - 1);
pio_sm_put_blocking(pio, pio_sm, 0x38000000u | addr);
pio_sm_put_blocking(pio, pio_sm, pio_offset + sram_offset_do_write);
dma_channel_transfer_from_buffer_now(dma_channel, &repeat_data, (page_len >> 2) + 1);
}
}
void APS6404::read(uint32_t addr, uint32_t* read_buf, uint32_t len_in_words) {
start_read(read_buf, len_in_words);
uint32_t first_page_len = (PAGE_SIZE - (addr & (PAGE_SIZE - 1)));
if (first_page_len >= len_in_words << 2) {
pio_sm_put_blocking(pio, pio_sm, (len_in_words * 8) - 4);
pio_sm_put_blocking(pio, pio_sm, 0xeb000000u | addr);
pio_sm_put_blocking(pio, pio_sm, pio_offset + sram_offset_do_read);
}
else {
// Must always reset the cmd buffer DMA because writes use the same DREQ
setup_cmd_buffer_dma();
uint32_t* cmd_buf = add_read_to_cmd_buffer(multi_read_cmd_buffer, addr, len_in_words);
dma_channel_transfer_from_buffer_now(read_cmd_dma_channel, multi_read_cmd_buffer, cmd_buf - multi_read_cmd_buffer);
}
}
void APS6404::multi_read(uint32_t* addresses, uint32_t* lengths, uint32_t num_reads, uint32_t* read_buf, int chain_channel) {
uint32_t total_len = 0;
uint32_t* cmd_buf = multi_read_cmd_buffer;
for (uint32_t i = 0; i < num_reads; ++i) {
total_len += lengths[i];
cmd_buf = add_read_to_cmd_buffer(cmd_buf, addresses[i], lengths[i]);
}
start_read(read_buf, total_len, chain_channel);
setup_cmd_buffer_dma();
dma_channel_transfer_from_buffer_now(read_cmd_dma_channel, multi_read_cmd_buffer, cmd_buf - multi_read_cmd_buffer);
}
void APS6404::start_read(uint32_t* read_buf, uint32_t total_len_in_words, int chain_channel) {
dma_channel_config c = dma_channel_get_default_config(dma_channel);
channel_config_set_read_increment(&c, false);
channel_config_set_write_increment(&c, true);
channel_config_set_dreq(&c, pio_get_dreq(pio, pio_sm, false));
channel_config_set_transfer_data_size(&c, DMA_SIZE_32);
channel_config_set_bswap(&c, true);
if (chain_channel >= 0) {
channel_config_set_chain_to(&c, chain_channel);
}
last_cmd_was_write = false;
wait_for_finish_blocking();
dma_channel_configure(
dma_channel, &c,
read_buf,
&pio->rxf[pio_sm],
total_len_in_words,
true
);
}
void APS6404::setup_cmd_buffer_dma(bool clear) {
dma_channel_config c = dma_channel_get_default_config(read_cmd_dma_channel);
channel_config_set_read_increment(&c, true);
channel_config_set_write_increment(&c, false);
if (!clear) channel_config_set_dreq(&c, pio_get_dreq(pio, pio_sm, true));
channel_config_set_transfer_data_size(&c, DMA_SIZE_32);
dma_channel_configure(
read_cmd_dma_channel, &c,
&pio->txf[pio_sm],
multi_read_cmd_buffer,
0,
false
);
}
uint32_t* APS6404::add_read_to_cmd_buffer(uint32_t* cmd_buf, uint32_t addr, uint32_t len_in_words) {
int32_t len_remaining = len_in_words << 2;
uint32_t len = std::min((PAGE_SIZE - (addr & (PAGE_SIZE - 1))), (uint32_t)len_remaining);
bool clear_isr = false;
while (true) {
if (len < 2) {
// This is guaranteed to leave at least one byte in the ISR,
// which we then clear with an additional command
len = 2;
clear_isr = true;
}
*cmd_buf++ = (len * 2) - 4;
*cmd_buf++ = 0xeb000000u | addr;
*cmd_buf++ = pio_offset + sram_offset_do_read;
len_remaining -= len;
addr += len;
if (len_remaining <= 0) break;
len = len_remaining;
if (len > PAGE_SIZE) len = PAGE_SIZE;
}
if (clear_isr) {
*cmd_buf++ = 0;
*cmd_buf++ = 0xeb000000u | addr;
*cmd_buf++ = pio_offset + sram_offset_do_clear;
}
return cmd_buf;
}
void APS6404::wait_for_finish_blocking() {
dma_channel_wait_for_finish_blocking(dma_channel);
}
}

Wyświetl plik

@ -1,66 +0,0 @@
#pragma once
#include <stdint.h>
#include "hardware/pio.h"
namespace pimoroni {
class APS6404 {
public:
static constexpr int RAM_SIZE = 8 * 1024 * 1024;
static constexpr int PAGE_SIZE = 1024;
APS6404(uint pin_csn = 17, uint pin_d0 = 19, PIO pio = pio1);
void init();
void set_qpi();
void set_spi();
// Must be called if the system clock rate is changed after init().
void adjust_clock();
// Start a write, this completes asynchronously, this function blocks if another
// transfer is already in progress
// Writes should always be <= 1KB.
void write(uint32_t addr, uint32_t* data, uint32_t len_in_bytes);
void write_repeat(uint32_t addr, uint32_t data, uint32_t len_in_bytes);
// Start a read, this completes asynchronously, this function only blocks if another
// transfer is already in progress
void read(uint32_t addr, uint32_t* read_buf, uint32_t len_in_words);
// Start multiple reads to the same buffer. They completes asynchronously,
// this function only blocks if another transfer is already in progress
void multi_read(uint32_t* addresses, uint32_t* lengths, uint32_t num_addresses, uint32_t* read_buf, int chain_channel = -1);
// Read and block until completion
void read_blocking(uint32_t addr, uint32_t* read_buf, uint32_t len_in_words) {
read(addr, read_buf, len_in_words);
wait_for_finish_blocking();
}
// Block until any outstanding read or write completes
void wait_for_finish_blocking();
private:
void start_read(uint32_t* read_buf, uint32_t total_len_in_words, int chain_channel = -1);
void setup_cmd_buffer_dma(bool clear = false);
uint32_t* add_read_to_cmd_buffer(uint32_t* cmd_buf, uint32_t addr, uint32_t len_in_words);
uint pin_csn; // CSn, SCK must be next pin after CSn
uint pin_d0; // D0, D1, D2, D3 must be consecutive
PIO pio;
uint16_t pio_sm;
uint16_t pio_offset;
const pio_program* pio_prog;
uint dma_channel;
uint read_cmd_dma_channel;
bool last_cmd_was_write = false;
static constexpr int MULTI_READ_MAX_PAGES = 128;
uint32_t multi_read_cmd_buffer[3 * MULTI_READ_MAX_PAGES];
uint32_t repeat_data;
};
}

Wyświetl plik

@ -1,228 +0,0 @@
; Pins:
; - CSn is side-set 0
; - SCK is side-set 1
; - D0 is IN/OUT/SET pin 0
;
; DMA is 32 bit. Stream takes form:
; 32 bits For read: length of read in nibbles, minus 4
; For write: length of write in nibbles, minus 1
; Original data length in bits must be a multiple of 32
; 8 bits AP6404 cmd (0xeb = read, 0x38 = write)
; 24 bits address
; 32 bits sram_offset_do_read or sram_offset_do_write
; For write, data
; Program for running at high frequencies (130MHz-290MHz RP2040 system clock)
; Waits an extra half cycle on read as the data back from the PSRAM appears a fixed
; amount of *time* after the CLK
.program sram
.side_set 2
.wrap_target
top:
set x, 6 side 0b01
out y, 32 side 0b01
set pindirs, 0xf side 0b01
; Write command, followed by data
addr_lp:
out pins, 4 side 0b00
jmp x--, addr_lp side 0b10
out pins, 4 side 0b00
out pc, 32 side 0b10
PUBLIC do_write:
out pins, 4 side 0b00
jmp y--, do_write side 0b10
set pindirs, 0 side 0b00
out null, 32 side 0b01
PUBLIC do_clear:
mov isr, null side 0b01
jmp top side 0b01
; Read command
PUBLIC do_read:
; Wait for 8.5 clocks (6 + 2.5 for latencies)
set x, 7 side 0b00
rwt_lp:
set pindirs, 0 side 0b10
jmp x-- rwt_lp side 0b00
set x, 2 side 0b10
rd_lp:
in pins, 4 side 0b00
jmp y--, rd_lp side 0b10
; Read the remaining 3 nibbles, but no more clocks so we don't read beyond
; the requested length from the SRAM.
rd_rem:
in pins, 4 side 0b01
jmp x--, rd_rem side 0b01
.wrap
; Program for running at low frequencies (<130MHz RP2040 system clock)
.program sram_slow
.side_set 2
.wrap_target
top:
set x, 6 side 0b01
out y, 32 side 0b01
set pindirs, 0xf side 0b01
; Write command, followed by data
addr_lp:
out pins, 4 side 0b00
jmp x--, addr_lp side 0b10
out pins, 4 side 0b00
out pc, 32 side 0b10
PUBLIC do_write:
out pins, 4 side 0b00
jmp y--, do_write side 0b10
set pindirs, 0 side 0b00
out null, 32 side 0b01
PUBLIC do_clear:
mov isr, null side 0b01
jmp top side 0b01
; Read command
PUBLIC do_read:
set pindirs, 0 side 0b00
; Wait for 8 clocks (6 + 2 for latencies)
set x, 6 side 0b10
rwt_lp:
nop side 0b00
jmp x-- rwt_lp side 0b10
set x, 2 side 0b00
rd_lp:
in pins, 4 side 0b10
jmp y--, rd_lp side 0b00
; Read the remaining 3 nibbles, but no more clocks so we don't read beyond
; the requested length from the SRAM.
rd_rem:
in pins, 4 side 0b01
jmp x--, rd_rem side 0b01
.wrap
; Program for running at extreme frequencies (>290MHz RP2040 system clock)
; Runs clock at 1/3rd RP2040 clock with 66% duty cycle. Out of spec but
; then everything we are doing here is!
.program sram_fast
.side_set 2
.wrap_target
top:
set x, 6 side 0b01
out y, 32 side 0b01
set pindirs, 0xf side 0b01
; Write command, followed by data
addr_lp:
out pins, 4 side 0b00
jmp x--, addr_lp [1] side 0b10
out pins, 4 side 0b00
out pc, 32 [1] side 0b10
PUBLIC do_write:
out pins, 4 side 0b00
jmp y--, do_write [1] side 0b10
set pindirs, 0 side 0b00
out null, 32 side 0b01
PUBLIC do_clear:
mov isr, null side 0b01
jmp top side 0b01
; Read command
PUBLIC do_read:
set pindirs, 0 side 0b00
; Wait for 8 clocks (6 + 2 for latencies)
set x, 6 [1] side 0b10
rwt_lp:
nop side 0b00
jmp x-- rwt_lp [1] side 0b10
set x, 2 side 0b00
rd_lp:
nop side 0b10
in pins, 4 side 0b10
jmp y--, rd_lp side 0b00
; Read the remaining 2 nibbles, but no more clocks so we don't read beyond
; the requested length from the SRAM.
rd_rem:
in pins, 4 [1] side 0b01
jmp x--, rd_rem side 0b01
.wrap
; Write only program that writes a short (<32 bit) command,
; ignoring the rest of the 32 bit input word.
; This is used to write the reset command and enter QPI mode.
.program sram_reset
.side_set 2
.wrap_target
out y, 32 side 0b01
pull side 0b01
wr_lp:
out pins, 1 side 0b00
jmp y--, wr_lp side 0b10
out null, 32 [7] side 0b01 ; Ensure large enough gap between commands for reset time
nop [7] side 0b01
.wrap
.program sram_reset_qpi
.side_set 2
.wrap_target
out y, 32 side 0b01
pull side 0b01
set pindirs, 0xF side 0b01
wr_lp:
out pins, 4 side 0b00
jmp y--, wr_lp side 0b10
out null, 32 [7] side 0b01 ; Ensure large enough gap between commands for reset time
set pindirs, 0 [7] side 0b01
.wrap
% c-sdk {
void aps6404_reset_program_init(PIO pio, uint sm, uint offset, uint csn, uint mosi) {
uint miso = mosi + 1;
pio_gpio_init(pio, csn);
pio_gpio_init(pio, csn + 1);
pio_gpio_init(pio, mosi);
pio_sm_set_consecutive_pindirs(pio, sm, csn, 2, true);
pio_sm_set_consecutive_pindirs(pio, sm, mosi, 1, true);
pio_sm_set_consecutive_pindirs(pio, sm, miso, 1, false);
pio_sm_config c = sram_reset_program_get_default_config(offset);
sm_config_set_in_pins(&c, miso);
sm_config_set_in_shift(&c, false, true, 32);
sm_config_set_out_pins(&c, mosi, 1);
sm_config_set_out_shift(&c, false, true, 32);
sm_config_set_sideset_pins(&c, csn);
sm_config_set_clkdiv(&c, 4.f);
pio_sm_init(pio, sm, offset, &c);
pio_sm_set_enabled(pio, sm, true);
}
void aps6404_program_init(PIO pio, uint sm, uint offset, uint csn, uint mosi, bool slow, bool fast, bool reset) {
pio_gpio_init(pio, csn);
pio_gpio_init(pio, csn + 1);
pio_gpio_init(pio, mosi);
pio_gpio_init(pio, mosi + 1);
pio_gpio_init(pio, mosi + 2);
pio_gpio_init(pio, mosi + 3);
pio_sm_set_consecutive_pindirs(pio, sm, csn, 2, true);
pio_sm_set_consecutive_pindirs(pio, sm, mosi, 4, false);
pio_sm_config c = slow ? sram_slow_program_get_default_config(offset) :
fast ? sram_fast_program_get_default_config(offset) :
reset ? sram_reset_qpi_program_get_default_config(offset) :
sram_program_get_default_config(offset);
sm_config_set_in_pins(&c, mosi);
sm_config_set_in_shift(&c, false, true, 32);
sm_config_set_out_pins(&c, mosi, 4);
sm_config_set_out_shift(&c, false, true, 32);
sm_config_set_set_pins(&c, mosi, 4);
sm_config_set_sideset_pins(&c, csn);
pio_sm_init(pio, sm, offset, &c);
pio_sm_set_enabled(pio, sm, true);
}
%}

Wyświetl plik

@ -1 +0,0 @@
include(dv_display.cmake)

Wyświetl plik

@ -1,13 +0,0 @@
set(DRIVER_NAME dv_display)
add_library(${DRIVER_NAME} INTERFACE)
target_sources(${DRIVER_NAME} INTERFACE
${CMAKE_CURRENT_LIST_DIR}/${DRIVER_NAME}.cpp
${CMAKE_CURRENT_LIST_DIR}/swd_load.cpp)
target_include_directories(${DRIVER_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR})
pico_generate_pio_header(${DRIVER_NAME} ${CMAKE_CURRENT_LIST_DIR}/swd.pio)
# Pull in pico libraries that we need
target_link_libraries(${DRIVER_NAME} INTERFACE pico_stdlib aps6404 pimoroni_i2c)

Wyświetl plik

@ -1,509 +0,0 @@
#include "dv_display.hpp"
#include "swd_load.hpp"
#include "pico-stick.h"
#include <cstdlib>
#include <math.h>
#include <string.h>
#ifndef MICROPY_BUILD_TYPE
#define mp_printf(_, ...) printf(__VA_ARGS__);
#else
extern "C" {
#include "py/runtime.h"
}
#endif
namespace pimoroni {
void DVDisplay::init(uint16_t display_width_, uint16_t display_height_, Mode mode_, uint16_t frame_width_, uint16_t frame_height_) {
display_width = display_width_;
display_height = display_height_;
mode = mode_;
if (frame_width_ == 0) frame_width = display_width_;
else frame_width = frame_width_;
if (frame_height_ == 0) frame_height = display_height_;
else frame_height = frame_height_;
bank = 0;
h_repeat = 1;
v_repeat = 1;
uint8_t res_mode = 0xFF;
uint16_t full_width = display_width;
uint16_t full_height = display_height;
if (display_width < 640 || (display_width == 640 && (display_height == 360 || display_height == 720))) {
h_repeat = 2;
full_width *= 2;
}
if (display_height < 400) {
v_repeat = 2;
full_height *= 2;
}
if (full_width == 640) {
res_mode = 0;
}
else if (full_width == 720) {
if (full_height == 480) res_mode = 1;
else if (full_height == 400) res_mode = 2;
else if (full_height == 576) res_mode = 3;
}
else if (full_width == 800) {
if (full_height == 600) res_mode = 0x10;
else if (full_height == 480) res_mode = 0x11;
else if (full_height == 450) res_mode = 0x12;
}
else if (full_width == 960) {
if (full_height == 540) res_mode = 0x14;
}
else if (full_width == 1280) {
if (full_height == 720) res_mode = 0x15;
}
if (res_mode == 0xFF) {
mp_printf(&mp_plat_print, "Resolution %dx%d is not supported. Will use 720x480.\n", display_width, display_height);
}
gpio_init(RAM_SEL);
gpio_put(RAM_SEL, 0);
gpio_set_dir(RAM_SEL, GPIO_OUT);
gpio_init(VSYNC);
gpio_set_dir(VSYNC, GPIO_IN);
sleep_ms(200);
swd_load_program(section_addresses, section_data, section_data_len, sizeof(section_addresses) / sizeof(section_addresses[0]), 0x20000001, 0x15004000, true);
ram.init();
bank = 0;
write_header();
sleep_us(100);
gpio_put(RAM_SEL, 1);
ram.init();
bank = 1;
write_header();
sleep_us(100);
bank = 0;
gpio_put(RAM_SEL, 0);
sleep_ms(100);
mp_printf(&mp_plat_print, "Start I2C\n");
if (res_mode != 0xFF) {
i2c->reg_write_uint8(I2C_ADDR, I2C_REG_SET_RES, res_mode);
}
i2c->reg_write_uint8(I2C_ADDR, I2C_REG_START, 1);
mp_printf(&mp_plat_print, "Started\n");
}
void DVDisplay::flip() {
if (mode == MODE_PALETTE) {
write_palette();
if (pixel_buffer_location.y != -1) {
ram.write(point_to_address_palette(pixel_buffer_location), pixel_buffer, pixel_buffer_x);
pixel_buffer_location.y = -1;
}
}
else if (pixel_buffer_location.y != -1) {
ram.write(point_to_address16(pixel_buffer_location), pixel_buffer, pixel_buffer_x << 1);
pixel_buffer_location.y = -1;
}
bank ^= 1;
ram.wait_for_finish_blocking();
while (gpio_get(VSYNC) == 0);
gpio_put(RAM_SEL, bank);
if (rewrite_header) {
set_scroll_idx_for_lines(-1, 0, display_height);
rewrite_header = false;
}
}
void DVDisplay::reset() {
swd_reset();
}
void DVDisplay::set_display_offset(const Point& p, int idx) {
int32_t offset = (int32_t)point_to_address(p) - (int32_t)point_to_address({0,0});
i2c->write_bytes(I2C_ADDR, I2C_REG_SCROLL_BASE + 4*(idx-1), (uint8_t*)&offset, 4);
}
void DVDisplay::set_scroll_idx_for_lines(int idx, int miny, int maxy) {
constexpr int buf_size = 32;
uint32_t buf[buf_size];
uint addr = 4 * (7 + miny);
uint line_type = (uint)mode << 28;
if (idx >= 0) line_type |= (uint)idx << 30;
for (int i = miny; i < maxy; i += buf_size) {
int maxj = std::min(buf_size, maxy - i);
if (idx >= 0) {
for (int j = 0; j < maxj; ++j) {
buf[j] = line_type + ((uint32_t)h_repeat << 24) + ((i + j) * frame_width * 6) + base_address;
}
}
else {
ram.read_blocking(addr, buf, maxj);
for (int j = 0; j < maxj; ++j) {
buf[j] &= 0xC0000000;
buf[j] |= line_type + ((uint32_t)h_repeat << 24) + ((i + j) * frame_width * 6) + base_address;
}
}
ram.write(addr, buf, maxj * 4);
ram.wait_for_finish_blocking();
addr += 4 * maxj;
}
}
uint8_t DVDisplay::get_gpio() {
return i2c->reg_read_uint8(I2C_ADDR, I2C_REG_GPIO);
}
uint8_t DVDisplay::get_gpio_hi() {
return i2c->reg_read_uint8(I2C_ADDR, I2C_REG_GPIO_HI);
}
void DVDisplay::i2c_modify_bit(uint8_t reg, uint bit, bool enable) {
uint8_t val = i2c->reg_read_uint8(I2C_ADDR, reg);
if (enable) val |= 1u << bit;
else val &= ~(1u << bit);
i2c->reg_write_uint8(I2C_ADDR, reg, val);
}
void DVDisplay::set_gpio_hi_dir(uint pin, bool output) {
i2c_modify_bit(I2C_REG_GPIO_HI_OE, pin, output);
}
void DVDisplay::set_gpio_hi_dir_all(uint8_t val) {
i2c->reg_write_uint8(I2C_ADDR, I2C_REG_GPIO_HI_OE, val);
}
void DVDisplay::set_gpio_hi(uint pin, bool on) {
i2c_modify_bit(I2C_REG_GPIO_HI_OUT, pin, on);
}
void DVDisplay::set_gpio_hi_all(uint8_t val) {
i2c->reg_write_uint8(I2C_ADDR, I2C_REG_GPIO_HI_OUT, val);
}
void DVDisplay::set_gpio_hi_pull_up(uint pin, bool on) {
i2c_modify_bit(I2C_REG_GPIO_HI_PULL_UP, pin, on);
}
void DVDisplay::set_gpio_hi_pull_up_all(uint8_t val) {
i2c->reg_write_uint8(I2C_ADDR, I2C_REG_GPIO_HI_PULL_UP, val);
}
void DVDisplay::set_gpio_hi_pull_down(uint pin, bool on) {
i2c_modify_bit(I2C_REG_GPIO_HI_PULL_DOWN, pin, on);
}
void DVDisplay::set_gpio_hi_pull_down_all(uint8_t val) {
i2c->reg_write_uint8(I2C_ADDR, I2C_REG_GPIO_HI_PULL_DOWN, val);
}
void DVDisplay::set_led_level(uint8_t level) {
i2c->reg_write_uint8(I2C_ADDR, I2C_REG_LED, level | 0x80);
}
void DVDisplay::set_led_heartbeat() {
i2c->reg_write_uint8(I2C_ADDR, I2C_REG_LED, 2);
}
void DVDisplay::get_edid(uint8_t* edid) {
i2c->read_bytes(I2C_ADDR, I2C_REG_EDID, edid, 128);
}
void DVDisplay::write(uint32_t address, size_t len, const uint16_t colour)
{
uint32_t val = colour | ((uint32_t)colour << 16);
ram.write_repeat(address, val, len << 1);
}
void DVDisplay::write(uint32_t address, size_t len, const RGB888 colour)
{
const int VAL_BUFFER_LEN = 60;
const int VAL_BUFFER_LEN_IN_PIXELS = (VAL_BUFFER_LEN / 3) * 4;
uint32_t vals[VAL_BUFFER_LEN];
for (int i = 0, j = 0; i < VAL_BUFFER_LEN_IN_PIXELS && i < (int)len; i += 4) {
vals[j++] = colour | (colour << 24);
vals[j++] = (colour >> 8) | (colour << 16);
vals[j++] = (colour >> 16) | (colour << 8);
}
for (int len_bytes = len * 3; len_bytes > 0; len_bytes -= VAL_BUFFER_LEN_IN_PIXELS * 3) {
uint len_to_write = std::min(len_bytes, VAL_BUFFER_LEN_IN_PIXELS * 3);
ram.write(address, vals, len_to_write);
address += len_to_write;
}
ram.wait_for_finish_blocking();
}
void DVDisplay::read(uint32_t address, size_t len, uint16_t *data)
{
ram.read_blocking(address, (uint32_t*)data, (len + 1) >> 1);
}
void DVDisplay::write(uint32_t address, size_t len, const uint8_t colour)
{
uint32_t val = colour | ((uint32_t)colour << 16);
val |= val << 8;
ram.write_repeat(address, val, len);
}
void DVDisplay::read(uint32_t address, size_t len, uint8_t *data)
{
ram.read_blocking(address, (uint32_t*)data, len);
}
void DVDisplay::write_pixel(const Point &p, uint16_t colour)
{
if (pixel_buffer_location.y == p.y && pixel_buffer_location.x + pixel_buffer_x == p.x) {
if (pixel_buffer_x & 1) pixel_buffer[pixel_buffer_x >> 1] |= (uint32_t)colour << 16;
else pixel_buffer[pixel_buffer_x >> 1] = colour;
if (++pixel_buffer_x == PIXEL_BUFFER_LEN_IN_WORDS * 2) {
ram.write(point_to_address16(pixel_buffer_location), pixel_buffer, PIXEL_BUFFER_LEN_IN_WORDS * 4);
pixel_buffer_location.y = -1;
}
return;
}
else if (pixel_buffer_location.y != -1) {
ram.write(point_to_address16(pixel_buffer_location), pixel_buffer, pixel_buffer_x << 1);
}
pixel_buffer_location = p;
pixel_buffer_x = 1;
pixel_buffer[0] = colour;
}
void DVDisplay::write_pixel_span(const Point &p, uint l, uint16_t colour)
{
write(point_to_address16(p), l, colour);
}
void DVDisplay::write_pixel(const Point &p, RGB888 colour)
{
ram.write(point_to_address24(p), &colour, 3);
}
void DVDisplay::write_pixel_span(const Point &p, uint l, RGB888 colour)
{
write(point_to_address24(p), l, colour);
}
void DVDisplay::write_pixel_span(const Point &p, uint l, uint16_t *data)
{
uint32_t offset = 0;
if (((uintptr_t)data & 0x2) != 0) {
uint32_t val = *data++;
ram.write(point_to_address16(p), &val, 2);
--l;
offset = 2;
}
if (l > 0) {
ram.write(point_to_address16(p) + offset, (uint32_t*)data, l << 1);
}
}
void DVDisplay::read_pixel_span(const Point &p, uint l, uint16_t *data)
{
read(point_to_address16(p), l, data);
}
void DVDisplay::set_mode(Mode new_mode)
{
mode = new_mode;
rewrite_header = true;
set_scroll_idx_for_lines(-1, 0, display_height);
if (mode == MODE_PALETTE) {
write_palette();
}
}
void DVDisplay::set_palette(RGB888 new_palette[PALETTE_SIZE])
{
for (int i = 0; i < PALETTE_SIZE; ++i) {
set_palette_colour(i, new_palette[i]);
}
}
void DVDisplay::set_palette_colour(uint8_t entry, RGB888 colour)
{
palette[entry * 3] = (colour >> 16) & 0xFF;
palette[entry * 3 + 1] = (colour >> 8) & 0xFF;
palette[entry * 3 + 2] = colour & 0xFF;
}
void DVDisplay::write_palette()
{
uint addr = (display_height + 7) * 4;
ram.write(addr, (uint32_t*)palette, PALETTE_SIZE * 3);
}
void DVDisplay::write_palette_pixel(const Point &p, uint8_t colour)
{
if (pixel_buffer_location.y == p.y && pixel_buffer_location.x + pixel_buffer_x == p.x) {
if (pixel_buffer_x & 3) pixel_buffer[pixel_buffer_x >> 2] |= (uint32_t)colour << ((pixel_buffer_x & 3) << 3);
else pixel_buffer[pixel_buffer_x >> 2] = colour;
if (++pixel_buffer_x == PIXEL_BUFFER_LEN_IN_WORDS * 4) {
ram.write(point_to_address_palette(pixel_buffer_location), pixel_buffer, PIXEL_BUFFER_LEN_IN_WORDS * 4);
pixel_buffer_location.y = -1;
}
return;
}
else if (pixel_buffer_location.y != -1) {
ram.write(point_to_address_palette(pixel_buffer_location), pixel_buffer, pixel_buffer_x);
}
pixel_buffer_location = p;
pixel_buffer_x = 1;
pixel_buffer[0] = colour;
}
void DVDisplay::write_palette_pixel_span(const Point &p, uint l, uint8_t colour)
{
write(point_to_address_palette(p), l, colour);
}
void DVDisplay::write_palette_pixel_span(const Point &p, uint l, uint8_t* data)
{
uint32_t offset = 0;
while (((uintptr_t)data & 0x3) != 0 && l > 0) {
uint32_t val = *data++;
ram.write(point_to_address_palette(p), &val, 1);
--l;
offset++;
ram.wait_for_finish_blocking();
}
if (l > 0) {
ram.write(point_to_address_palette(p) + offset, (uint32_t*)data, l);
}
}
void DVDisplay::read_palette_pixel_span(const Point &p, uint l, uint8_t *data)
{
read(point_to_address_palette(p), l, data);
}
void DVDisplay::write_header_preamble()
{
uint32_t buf[8];
uint32_t full_width = display_width * h_repeat;
buf[0] = 0x4F434950;
buf[1] = 0x01000101 + ((uint32_t)v_repeat << 16);
buf[2] = full_width << 16;
buf[3] = (uint32_t)display_height << 16;
buf[4] = 0x00000001;
buf[5] = 0x00010000 + display_height + ((uint32_t)bank << 24);
buf[6] = 0x04000001;
ram.write(0, buf, 7 * 4);
ram.wait_for_finish_blocking();
}
void DVDisplay::write_sprite_table()
{
constexpr uint32_t buf_size = 32;
uint32_t buf[buf_size];
uint addr = (display_height + 7) * 4 + PALETTE_SIZE * 3;
uint sprite_type = (uint)mode << 28;
for (uint32_t i = 0; i < max_num_sprites; i += buf_size) {
for (uint32_t j = 0; j < buf_size; ++j) {
buf[j] = sprite_type + (i + j) * sprite_size + sprite_base_address;
}
ram.write(addr, buf, buf_size * 4);
ram.wait_for_finish_blocking();
addr += buf_size * 4;
}
}
void DVDisplay::write_header()
{
write_header_preamble();
set_scroll_idx_for_lines(1, 0, display_height);
write_sprite_table();
}
void DVDisplay::define_sprite_internal(uint16_t sprite_data_idx, uint16_t width, uint16_t height, uint32_t* data)
{
uint32_t buf[33];
uint16_t* buf_ptr = (uint16_t*)buf;
uint addr = sprite_base_address + sprite_data_idx * sprite_size;
*buf_ptr++ = (height << 8) + width;
for (uint16_t i = 0; i < height; ++i)
{
*buf_ptr++ = width << 8;
}
uint len = (uint8_t*)buf_ptr - (uint8_t*)buf;
ram.write(addr, buf, len);
addr += len;
if (len & 2) addr += 2;
ram.write(addr, (uint32_t*)data, width * height * 2);
}
void DVDisplay::define_sprite(uint16_t sprite_data_idx, uint16_t width, uint16_t height, uint16_t* data)
{
define_sprite_internal(sprite_data_idx, width, height, (uint32_t*)data);
ram.wait_for_finish_blocking();
}
void DVDisplay::define_palette_sprite(uint16_t sprite_data_idx, uint16_t width, uint16_t height, uint8_t* data)
{
define_sprite_internal(sprite_data_idx, width, height, (uint32_t*)data);
ram.wait_for_finish_blocking();
}
void DVDisplay::load_pvs_sprite(uint16_t sprite_data_idx, uint32_t* data, uint32_t len_in_bytes)
{
uint addr = sprite_base_address + sprite_data_idx * sprite_size;
ram.write(addr, data, len_in_bytes);
ram.wait_for_finish_blocking();
}
void DVDisplay::set_sprite(int sprite_num, uint16_t sprite_data_idx, const Point &p, SpriteBlendMode blend_mode)
{
uint8_t buf[7];
buf[0] = (uint8_t)blend_mode;
buf[1] = sprite_data_idx & 0xff;
buf[2] = sprite_data_idx >> 8;
buf[3] = p.x & 0xff;
buf[4] = p.x >> 8;
buf[5] = p.y & 0xff;
buf[6] = p.y >> 8;
i2c->write_bytes(I2C_ADDR, sprite_num, buf, 7);
}
void DVDisplay::clear_sprite(int sprite_num)
{
uint8_t buf[3] = {1, 0xFF, 0xFF};
i2c->write_bytes(I2C_ADDR, sprite_num, buf, 3);
}
uint32_t DVDisplay::point_to_address(const Point& p) const {
switch(mode) {
default:
case MODE_RGB555: return point_to_address16(p);
case MODE_PALETTE: return point_to_address_palette(p);
case MODE_RGB888: return point_to_address24(p);
}
}
int DVDisplay::pixel_size() const {
switch(mode) {
default:
case MODE_RGB555: return 2;
case MODE_PALETTE: return 1;
case MODE_RGB888: return 3;
}
}
}

Wyświetl plik

@ -1,251 +0,0 @@
#pragma once
#include <cstring>
#include "pico/stdlib.h"
#include "hardware/gpio.h"
#include "common/pimoroni_common.hpp"
#include "common/pimoroni_i2c.hpp"
#include "drivers/aps6404/aps6404.hpp"
#include "libraries/pico_graphics/pico_graphics.hpp"
// Pimoroni DV Stick
namespace pimoroni {
// This is ARGB1555 only for now
class DVDisplay : public IDirectDisplayDriver<uint16_t>, public IDirectDisplayDriver<RGB888>, public IPaletteDisplayDriver {
public:
static constexpr int PALETTE_SIZE = 32;
enum Mode {
MODE_PALETTE = 2,
MODE_RGB555 = 1,
MODE_RGB888 = 3,
};
enum SpriteBlendMode : uint8_t {
BLEND_NONE = 0, // Sprite data always written to frame regardless of alpha
BLEND_DEPTH = 1, // Alpha represents depth. Order from back to front is: Sprite A0, Frame A0, Sprite A1, Frame A1
BLEND_DEPTH2 = 2, // Alpha represents depth. Order from back to front is: Sprite A0, Frame A0, Frame A1, Sprite A1
// Note that blend modes are only supported in RGB555 mode.
BLEND_BLEND = 3, // Use frame if Sprite A0 or Frame A1, additive blend if Sprite A1 and Frame A0
BLEND_BLEND2 = 4, // Use frame if Sprite A0, additive blend if Sprite A1
};
// I2C pins
static constexpr uint I2C_SDA = 6;
static constexpr uint I2C_SCL = 7;
// I2C address and registers
static constexpr uint I2C_ADDR = 0x0D;
static constexpr uint I2C_REG_SET_RES = 0xFC;
static constexpr uint I2C_REG_START = 0xFD;
static constexpr uint I2C_REG_GPIO = 0xC0;
static constexpr uint I2C_REG_LED = 0xC1;
static constexpr uint I2C_REG_GPIO_HI = 0xC8;
static constexpr uint I2C_REG_GPIO_HI_OUT = 0xC9;
static constexpr uint I2C_REG_GPIO_HI_OE = 0xCA;
static constexpr uint I2C_REG_GPIO_HI_PULL_UP = 0xCB;
static constexpr uint I2C_REG_GPIO_HI_PULL_DOWN = 0xCC;
static constexpr uint I2C_REG_EDID = 0xED;
static constexpr uint I2C_REG_SCROLL_BASE = 0xF0;
//--------------------------------------------------
// Variables
//--------------------------------------------------
protected:
// Ram accessed through the APS6404 driver
APS6404 ram;
// I2C interface to driver
I2C* i2c;
// interface pins
static constexpr uint CS = 17;
static constexpr uint D0 = 19;
static constexpr uint VSYNC = 16;
static constexpr uint RAM_SEL = 8;
static constexpr uint32_t base_address = 0x10000;
static constexpr uint32_t max_num_sprites = 1024;
static constexpr uint32_t sprite_size = 0x900;
static constexpr uint32_t sprite_base_address = 0x800000 - (max_num_sprites * sprite_size);
uint16_t display_width = 0;
uint16_t display_height = 0;
uint16_t frame_width = 0;
uint16_t frame_height = 0;
uint8_t bank = 0;
uint8_t h_repeat = 1;
uint8_t v_repeat = 1;
Mode mode = MODE_RGB555;
public:
// Valid resolutions are:
// 640x480 (60Hz), 720x480 (60Hz), 720x400 (70Hz), 720x576 (50Hz)
// 800x600 (60Hz), 800x480 (60Hz), 800x450 (60Hz), 960x540 (50Hz), 1280x720 (30Hz)
// Note resolutions on the second line require quite extreme overclocking and may not work on all hardware.
// Either or both of the horizontal or vertical component of any resolution may be halved.
DVDisplay()
: ram(CS, D0, pio1)
, i2c(new I2C(I2C_SDA, I2C_SCL))
, pixel_buffer_location(-1, -1)
{}
DVDisplay(I2C* i2c)
: ram(CS, D0, pio1)
, i2c(i2c)
, pixel_buffer_location(-1, -1)
{}
//--------------------------------------------------
// Methods
//--------------------------------------------------
public:
void test(void){
char writeBuffer[256];
char readBuffer[256];
uint mb = 8;
for (uint b = 0; b < 2; ++b) {
gpio_put(RAM_SEL, b);
for(uint k = 0; k < 1024*mb; k++) {
sprintf(writeBuffer, "%u-%u", b, k);
ram.write(k*1024, (uint32_t *)writeBuffer, strlen(writeBuffer)+1);
}
}
for (uint b = 0; b < 2; ++b) {
gpio_put(RAM_SEL, b);
bool bSame = true;
for(uint k = 0; k < 1024*mb && bSame; k++)
{
sprintf(writeBuffer, "%u-%u", b, k);
read(k*1024, strlen(writeBuffer)+1, (uint16_t *)readBuffer);
bSame = strcmp(writeBuffer, readBuffer) == 0;
printf("[%u] %s == %s ? %s\n", k, writeBuffer, readBuffer, bSame ? "Success" : "Failure");
}
}
}
// 16bpp interface
void write_pixel(const Point &p, uint16_t colour) override;
void write_pixel_span(const Point &p, uint l, uint16_t colour) override;
void write_pixel_span(const Point &p, uint l, uint16_t *data);
void read_pixel_span(const Point &p, uint l, uint16_t *data) override;
// 24bpp interface
void write_pixel(const Point &p, RGB888 colour) override;
void write_pixel_span(const Point &p, uint l, RGB888 colour) override;
void init(uint16_t width, uint16_t height, Mode mode = MODE_RGB555, uint16_t frame_width = 0, uint16_t frame_height = 0);
void flip();
void reset();
// Define the data for a sprite, the specified data index can then be supplied
// to set_sprite to use the sprite. Up to 1024 sprites can be defined.
// Each sprite can be up to 2KB big, with a maximum width or height of 64 pixels.
// So for ARGB1555 sprites 64x16, 32x32, 16x64 are examples of maximum sizes.
// You must define the sprite to each RAM bank.
void define_sprite(uint16_t sprite_data_idx, uint16_t width, uint16_t height, uint16_t* data);
// Palette mode sprites are defined with the colour number in bits 6-2 of each byte and alpha in bit 0.
// Because palette mode sprites only use 1 byte per pixel they can be bigger, up to 64x32, or 45x45, for example.
void define_palette_sprite(uint16_t sprite_data_idx, uint16_t width, uint16_t height, uint8_t* data);
// Load a sprite stored in PicoVision sprite format
void load_pvs_sprite(uint16_t sprite_data_idx, uint32_t* data, uint32_t len_in_bytes);
// Display/move a sprite to a given position.
// Note sprite positions are always display relative (not scrolled)
void set_sprite(int sprite_num, uint16_t sprite_data_idx, const Point &p, SpriteBlendMode blend_mode = BLEND_DEPTH);
void clear_sprite(int sprite_num);
// 32 colour palette mode. Note that palette entries range from 0-31,
// but when writing colour values the palette entry is in bits 6-2, so the
// entry value is effectively multiplied by 4.
void set_mode(Mode new_mode);
void set_palette(RGB888 palette[PALETTE_SIZE]);
void set_palette_colour(uint8_t entry, RGB888 colour);
void write_palette_pixel(const Point &p, uint8_t colour);
void write_palette_pixel_span(const Point &p, uint l, uint8_t colour);
void write_palette_pixel_span(const Point &p, uint l, uint8_t* data);
void read_palette_pixel_span(const Point &p, uint l, uint8_t *data);
// Set the scroll offset for a set of scanlines on the display. There are 3 scroll offsets, indexes 1-3.
// By default, all scanlines are offset by scroll idx 1, so setting this effectively moves the
// top left corner of the display within the frame.
void set_display_offset(const Point& p, int idx=1);
// Configure the scroll offset index to use for a set of scanlines (inclusive of miny, exclusive of maxy),
// this applies to the current bank only - you need to set again after flipping to apply the same setting to the other bank.
void set_scroll_idx_for_lines(int idx, int miny, int maxy);
uint8_t get_gpio();
uint8_t get_gpio_hi();
void set_gpio_hi_dir(uint pin, bool output);
void set_gpio_hi_dir_all(uint8_t output_enables);
void set_gpio_hi(uint pin, bool on);
void set_gpio_hi_all(uint8_t vals);
void set_gpio_hi_pull_up(uint pin, bool on);
void set_gpio_hi_pull_up_all(uint8_t vals);
void set_gpio_hi_pull_down(uint pin, bool on);
void set_gpio_hi_pull_down_all(uint8_t vals);
bool is_button_b_pressed() { return (get_gpio() & 0x1) != 0x1; }
bool is_button_c_pressed() { return (get_gpio() & 0x2) != 0x2; }
// Valid LED levels are from 0-127.
void set_led_level(uint8_t level);
void set_led_level(float level) { set_led_level((uint8_t)(level * 127.f)); }
void set_led_heartbeat();
// The supplied buffer must be at least 128 bytes long
void get_edid(uint8_t* edid);
protected:
uint8_t palette[PALETTE_SIZE * 3] alignas(4);
bool rewrite_header = false;
virtual void write_palette();
virtual void write_header();
virtual void write_sprite_table();
virtual void write_header_preamble();
void i2c_modify_bit(uint8_t reg, uint bit, bool enable);
private:
static constexpr int PIXEL_BUFFER_LEN_IN_WORDS = 32;
uint32_t pixel_buffer[PIXEL_BUFFER_LEN_IN_WORDS];
Point pixel_buffer_location;
int32_t pixel_buffer_x;
void write(uint32_t address, size_t len, const uint16_t colour);
void read(uint32_t address, size_t len, uint16_t *data);
void write(uint32_t address, size_t len, const uint8_t colour);
void read(uint32_t address, size_t len, uint8_t *data);
void write(uint32_t address, size_t len, const RGB888 colour);
void define_sprite_internal(uint16_t sprite_data_idx, uint16_t width, uint16_t height, uint32_t* data);
uint32_t point_to_address(const Point& p) const;
int pixel_size() const;
uint32_t point_to_address16(const Point &p) const {
return base_address + ((p.y * (uint32_t)frame_width * 3) + p.x) * 2;
}
uint32_t point_to_address_palette(const Point &p) const {
return base_address + (p.y * (uint32_t)frame_width * 6) + p.x;
}
uint32_t point_to_address24(const Point &p) const {
return base_address + ((p.y * (uint32_t)frame_width * 2) + p.x) * 3;
}
};
}

Wyświetl plik

@ -1,219 +0,0 @@
; Pins:
; - SWC is side-set 0
; - SWD is IN/OUT/SET pin 0
;
; SWD write:
; 7 bits request (request parity set in input)
; 1 bit park
; 1 bit turn
; 3 bits response - fail if not 001 - sent LSB first
; 1 bit turn
; 32 bits data
; 1 bit parity (computed and sent from PIO)
;
.program swd_write
.side_set 1 opt
error:
irq 0 side 1
top:
; Wait driven
set pins, 0 side 1
set pindirs, 1 side 1
mov isr, null side 1
set y, 6 side 1
pull side 1
set pindirs, 1 side 1
; Send 7 bits
send_cmd:
out pins, 1 [1] side 0
jmp y--, send_cmd [1] side 1
set pindirs, 0 side 0
set y, 3 side 0
; Read 5 bits: park, turn, rsp
read_rsp:
in pins, 1 [1] side 1
jmp y--, read_rsp [1] side 0
in pins, 1 side 1
set x, 0x1C side 0
mov y, isr side 0
pull side 1
jmp x!=y, error side 1 ; Not OK
set pindirs, 1 side 1
set x, 0 side 1
send_data:
out y, 1 side 0
mov pins, y side 0
jmp y--, negate side 1
jmp !osre, send_data side 1
.wrap_target
mov pins, x [1] side 0
jmp top side 1
negate:
mov x, ~x side 1
jmp !osre, send_data side 1
; Must be identical to above, except ignoring error.
.program swd_write_ignore_error
.side_set 1 opt
error:
irq 0 side 1
top:
; Wait driven
set pins, 0 side 1
set pindirs, 1 side 1
mov isr, null side 1
set y, 6 side 1
pull side 1
set pindirs, 1 side 1
; Send 7 bits
send_cmd:
out pins, 1 [1] side 0
jmp y--, send_cmd [1] side 1
set pindirs, 0 side 0
set y, 3 side 0
; Read 5 bits: park, turn, rsp
read_rsp:
in pins, 1 [1] side 1
jmp y--, read_rsp [1] side 0
in pins, 1 side 1
set x, 0x1C side 0
mov y, isr side 0
pull side 1
nop side 1 ; Ignore
set pindirs, 1 side 1
set x, 0 side 1
send_data:
out y, 1 side 0
mov pins, y side 0
jmp y--, negate side 1
jmp !osre, send_data side 1
.wrap_target
mov pins, x [1] side 0
jmp top side 1
negate:
mov x, ~x side 1
jmp !osre, send_data side 1
.program swd_read
.side_set 1 opt
error:
irq 0 side 1
.wrap_target
top:
; Wait driven
set pins, 0 side 1
set pindirs, 1 side 1
mov isr, null side 1
set y, 6 side 1
pull side 1
set pindirs, 1 side 1
; Send 7 bits
send_cmd:
out pins, 1 [1] side 0
jmp y--, send_cmd [1] side 1
set pindirs, 0 side 0
set y, 3 side 0
; Read 5 bits: park, turn, rsp
read_rsp:
in pins, 1 [1] side 1
jmp y--, read_rsp [1] side 0
in pins, 1 side 1
set x, 0x1C side 1
mov y, isr side 1
jmp x!=y, error side 1 ; Not OK
; Read 32 bits
set y, 31 [1] side 0
read_data:
in pins, 1 [1] side 1
jmp y--, read_data [1] side 0
; Ignore parity and turn
mov isr, ::isr [1] side 1
push [1] side 0
.program swd_raw_write
.side_set 1 opt
; Wait undriven
set pins, 0 side 1
set pindirs, 1 side 1
out y, 32 side 1
send:
out pins, 1 [1] side 0
jmp y--, send [1] side 1
out null, 32 side 1
.program swd_raw_read
.side_set 1 opt
out y, 32 side 1
read:
in pins, 1 [1] side 1
jmp y--, read [1] side 0
push side 1
% c-sdk {
void swd_initial_init(PIO pio, uint sm, uint swc, uint swd) {
pio_gpio_init(pio, swc);
pio_gpio_init(pio, swd);
pio_sm_set_consecutive_pindirs(pio, sm, swc, 1, true);
pio_sm_set_consecutive_pindirs(pio, sm, swd, 1, false);
}
void swd_program_init(PIO pio, uint sm, uint offset, uint swc, uint swd, bool read) {
pio_sm_config c = read ? swd_read_program_get_default_config(offset) : swd_write_program_get_default_config(offset);
sm_config_set_in_pins(&c, swd);
sm_config_set_in_shift(&c, false, false, 32);
sm_config_set_set_pins(&c, swd, 1);
sm_config_set_out_pins(&c, swd, 1);
sm_config_set_out_shift(&c, true, false, 32);
sm_config_set_sideset_pins(&c, swc);
sm_config_set_clkdiv(&c, 60.f);
pio_sm_init(pio, sm, offset, &c);
pio_sm_set_enabled(pio, sm, true);
}
void swd_raw_program_init(PIO pio, uint sm, uint offset, uint swc, uint swd, bool read) {
pio_sm_config c = read ? swd_raw_read_program_get_default_config(offset) : swd_raw_write_program_get_default_config(offset);
sm_config_set_in_pins(&c, swd);
sm_config_set_in_shift(&c, false, false, 32);
sm_config_set_set_pins(&c, swd, 1);
sm_config_set_out_pins(&c, swd, 1);
sm_config_set_out_shift(&c, true, true, 32);
sm_config_set_sideset_pins(&c, swc);
sm_config_set_clkdiv(&c, 60.f);
pio_sm_init(pio, sm, offset, &c);
pio_sm_set_enabled(pio, sm, true);
}
%}

Wyświetl plik

@ -1,402 +0,0 @@
#include "pico/stdlib.h"
#include "stdio.h"
#include "swd.pio.h"
#include <algorithm>
#ifndef MICROPY_BUILD_TYPE
#define mp_printf(_, ...) printf(__VA_ARGS__);
#else
extern "C" {
#include "py/runtime.h"
}
#endif
static uint pio_offset;
static uint pio_sm;
static const pio_program_t* pio_prog;
PIO swd_pio = pio0;
extern const uint16_t pio_change_exclusive_program(PIO pio, const pio_program* prog);
extern const void pio_remove_exclusive_program(PIO pio);
static void wait_for_idle() {
uint pull_offset = (pio_prog == &swd_raw_write_program) ? 2 :
(pio_prog == &swd_raw_read_program) ? 0 : 5;
while (!pio_sm_is_tx_fifo_empty(swd_pio, pio_sm) || swd_pio->sm[pio_sm].addr != pio_offset + pull_offset);
}
static void switch_program(bool read, bool raw = false) {
wait_for_idle();
pio_sm_set_enabled(swd_pio, pio_sm, false);
pio_prog = raw ? (read ? &swd_raw_read_program : &swd_raw_write_program) :
(read ? &swd_read_program : &swd_write_program);
pio_offset = pio_change_exclusive_program(swd_pio, pio_prog);
if (raw) {
swd_raw_program_init(swd_pio, pio_sm, pio_offset, 2, 3, read);
} else {
swd_program_init(swd_pio, pio_sm, pio_offset, 2, 3, read);
wait_for_idle();
swd_pio->irq = 1;
}
}
static void unload_pio() {
pio_sm_set_enabled(swd_pio, pio_sm, false);
pio_remove_exclusive_program(swd_pio);
pio_sm_unclaim(swd_pio, pio_sm);
}
static bool write_cmd(uint cmd, uint data) {
if (pio_prog != &swd_write_program) {
switch_program(false);
}
pio_sm_put_blocking(swd_pio, pio_sm, cmd);
pio_sm_put_blocking(swd_pio, pio_sm, data);
wait_for_idle();
if (swd_pio->irq & 0x1) {
return false;
}
return true;
}
static bool write_block(uint addr, const uint* data, uint len_in_words) {
if (!write_cmd(0x0B, addr)) return false;
for (uint i = 0; i < len_in_words; ++i) {
if (!write_cmd(0x3B, *data++)) return false;
}
return true;
}
static bool write_reg(uint addr, uint data) {
return write_block(addr, &data, 1);
}
static bool read_cmd(uint cmd, uint& data) {
if (pio_prog != &swd_read_program) {
switch_program(true);
}
pio_sm_put_blocking(swd_pio, pio_sm, cmd);
wait_for_idle();
if (swd_pio->irq & 0x1) {
mp_printf(&mp_plat_print, "Read ID failed\n");
return false;
}
data = pio_sm_get_blocking(swd_pio, pio_sm);
return true;
}
static bool read_reg(uint addr, uint &data) {
if (!write_cmd(0x0B, addr)) return false;
if (!read_cmd(0x1F, data)) return false;
if (!read_cmd(0x3D, data)) return false;
return true;
}
static void idle() {
switch_program(false, true);
pio_sm_put_blocking(swd_pio, pio_sm, 7);
pio_sm_put_blocking(swd_pio, pio_sm, 0);
}
static bool connect(bool first = true, uint core = 0) {
if (first) {
pio_prog = &swd_raw_write_program;
pio_offset = pio_change_exclusive_program(swd_pio, &swd_raw_write_program);
pio_sm = pio_claim_unused_sm(swd_pio, true);
swd_initial_init(swd_pio, pio_sm, 2, 3);
swd_raw_program_init(swd_pio, pio_sm, pio_offset, 2, 3, false);
} else {
switch_program(false, true);
}
// Begin transaction: 8 clocks, data low
mp_printf(&mp_plat_print, "Begin transaction\n");
pio_sm_put_blocking(swd_pio, pio_sm, 7);
pio_sm_put_blocking(swd_pio, pio_sm, 0);
// Go to SWD mode:
// 8 clocks, data high
// 0x6209F392, 0x86852D95, 0xE3DDAFE9, 0x19BC0EA2
// 4 clocks, data low
// 0x1A
mp_printf(&mp_plat_print, "SWD Mode\n");
pio_sm_put_blocking(swd_pio, pio_sm, 8-1);
pio_sm_put_blocking(swd_pio, pio_sm, 0xFF);
mp_printf(&mp_plat_print, "Tag\n");
pio_sm_put_blocking(swd_pio, pio_sm, 32*4+4+8-1);
pio_sm_put_blocking(swd_pio, pio_sm, 0x6209F392);
pio_sm_put_blocking(swd_pio, pio_sm, 0x86852D95);
pio_sm_put_blocking(swd_pio, pio_sm, 0xE3DDAFE9);
pio_sm_put_blocking(swd_pio, pio_sm, 0x19BC0EA2);
pio_sm_put_blocking(swd_pio, pio_sm, 0x1A0);
// Line Reset: 50 high, 8 low
mp_printf(&mp_plat_print, "Line Reset\n");
pio_sm_put_blocking(swd_pio, pio_sm, 58-1);
pio_sm_put_blocking(swd_pio, pio_sm, 0xFFFFFFFF);
pio_sm_put_blocking(swd_pio, pio_sm, 0x003FFFF);
mp_printf(&mp_plat_print, "Target Select\n"); // Must ignore error response
wait_for_idle();
pio_sm_set_enabled(swd_pio, pio_sm, false);
pio_prog = &swd_write_ignore_error_program;
pio_offset = pio_change_exclusive_program(swd_pio, pio_prog);
swd_program_init(swd_pio, pio_sm, pio_offset, 2, 3, false);
wait_for_idle();
swd_pio->irq = 1;
pio_sm_put_blocking(swd_pio, pio_sm, 0x19);
pio_sm_put_blocking(swd_pio, pio_sm, 0x01002927 | (core << 28));
mp_printf(&mp_plat_print, "Read ID\n");
uint id;
if (!read_cmd(0x25, id)) {
mp_printf(&mp_plat_print, "Read ID failed\n");
return false;
}
mp_printf(&mp_plat_print, "Received ID: %08x\n", id);
if (core != 0xf && id != 0x0bc12477) return false;
mp_printf(&mp_plat_print, "Abort\n");
if (!write_cmd(0x01, 0x1E)) {
mp_printf(&mp_plat_print, "Abort failed\n");
return false;
}
mp_printf(&mp_plat_print, "Select\n");
if (!write_cmd(0x31, 0)) {
mp_printf(&mp_plat_print, "Select failed\n");
return false;
}
mp_printf(&mp_plat_print, "Ctrl/Stat\n");
if (!write_cmd(0x29, 0x50000001)) {
mp_printf(&mp_plat_print, "Ctrl power up failed\n");
return false;
}
uint status;
if (!read_cmd(0x0D, status)) {
mp_printf(&mp_plat_print, "Read status on power up failed\n");
return false;
}
mp_printf(&mp_plat_print, "Status: %08x\n", status);
if ((status & 0xA0000000) != 0xA0000000) {
mp_printf(&mp_plat_print, "Power up not acknowledged\n");
return false;
}
if (core != 0xf) {
mp_printf(&mp_plat_print, "Setup memory access\n");
if (!write_cmd(0x23, 0xA2000052)) {
mp_printf(&mp_plat_print, "Memory access setup failed\n");
return false;
}
mp_printf(&mp_plat_print, "Halt CPU\n");
if (!write_reg(0xe000edf0, 0xA05F0003)) {
mp_printf(&mp_plat_print, "Halt failed\n");
return false;
}
}
else {
if (!write_cmd(0x29, 0x00000001)) {
mp_printf(&mp_plat_print, "Clear reset failed\n");
return false;
}
}
idle();
return true;
}
static bool load(uint address, const uint* data, uint len_in_bytes) {
mp_printf(&mp_plat_print, "Loading %d bytes at %08x\n", len_in_bytes, address);
idle();
constexpr uint BLOCK_SIZE = 1024;
uint block_len_in_words = std::min((BLOCK_SIZE - (address & (BLOCK_SIZE - 1))) >> 2, len_in_bytes >> 2);
for (uint i = 0; i < len_in_bytes; ) {
if (!write_block(address + i, &data[i >> 2], block_len_in_words)) {
mp_printf(&mp_plat_print, "Block write failed\n");
return false;
}
i += block_len_in_words << 2;
block_len_in_words = std::min(BLOCK_SIZE >> 2, (len_in_bytes - i) >> 2);
}
#ifdef FULL_VERIFY
for (uint j = 0; j < len_in_bytes; j += 4)
#else
uint j = 0;
#endif
{
uint check_data;
if (!read_reg(address + j, check_data)) {
mp_printf(&mp_plat_print, "Read failed\n");
return false;
}
if (check_data != data[j >> 2]) {
mp_printf(&mp_plat_print, "Verify failed at %08x, %08x != %08x\n", address + j, check_data, data[j >> 2]);
return false;
}
}
idle();
return true;
}
static bool start(uint pc, uint sp) {
idle();
// Start from boot address, which can be read from ROM at 0x4
uint rom_pc, rom_sp;
read_reg(0x0, rom_sp);
read_reg(0x4, rom_pc);
mp_printf(&mp_plat_print, "Set PC\n");
if (!write_reg(0xe000edf8, rom_pc) ||
!write_reg(0xe000edf4, 0x1000F))
{
mp_printf(&mp_plat_print, "Failed to set PC\n");
return false;
}
mp_printf(&mp_plat_print, "Set SP\n");
if (!write_reg(0xe000edf8, rom_sp) ||
!write_reg(0xe000edf4, 0x1000D))
{
mp_printf(&mp_plat_print, "Failed to set SP\n");
return false;
}
idle();
// If a PC has been given, go through watchdog boot sequence to start there
if (pc != 0) {
uint watchdog_data[4] = {0xb007c0d3, 0x4ff83f2d ^ pc, sp, pc};
mp_printf(&mp_plat_print, "Setup watchdog\n");
if (!write_block(0x4005801c, watchdog_data, 4)) {
mp_printf(&mp_plat_print, "Failed to setup watchdog for reset\n");
}
}
#if 0
uint data;
write_reg(0xe000edf4, 0x0000F);
idle();
read_reg(0xe000edf8, data);
mp_printf(&mp_plat_print, "PC is %08x\n", data);
for (int i = 0; i < 16; ++i) {
write_reg(0xe000edf4, i);
idle();
read_reg(0xe000edf8, data);
mp_printf(&mp_plat_print, "R%d is %08x\n", i, data);
}
for (int i = 0; i < 4; ++i) {
read_reg(0x4005801c + 4*i, data);
mp_printf(&mp_plat_print, "WD%d is %08x\n", i, data);
}
#endif
mp_printf(&mp_plat_print, "Start CPU\n");
if (!write_reg(0xe000edf0, 0xA05F0001)) {
mp_printf(&mp_plat_print, "Start failed\n");
return false;
}
idle();
wait_for_idle();
#if 0
sleep_ms(10);
connect(false);
mp_printf(&mp_plat_print, "Halt CPU\n");
if (!write_reg(0xe000edf0, 0xA05F0003)) {
mp_printf(&mp_plat_print, "Halt failed\n");
return false;
}
for (int i = 0; i < 16; ++i) {
write_reg(0xe000edf4, i);
idle();
read_reg(0xe000edf8, data);
mp_printf(&mp_plat_print, "R%d is %08x\n", i, data);
}
for (int i = 0; i < 4; ++i) {
read_reg(0x4005801c + 4*i, data);
mp_printf(&mp_plat_print, "WD%d is %08x\n", i, data);
}
#endif
return true;
}
static bool swd_reset_internal() {
gpio_init(2);
gpio_init(3);
gpio_disable_pulls(2);
gpio_pull_up(3);
bool ok = connect(true, 0xf);
mp_printf(&mp_plat_print, "Reset %s\n", ok ? "OK" : "Fail");
return ok;
}
bool swd_reset() {
bool ok = swd_reset_internal();
unload_pio();
return ok;
}
static bool swd_load_program_internal(const uint* addresses, const uint** data, const uint* data_len_in_bytes, uint num_sections, uint pc, uint sp, bool use_xip_as_ram) {
bool ok = swd_reset_internal();
if (!ok) {
return false;
}
mp_printf(&mp_plat_print, "Connecting\n");
ok = connect(false, 0);
mp_printf(&mp_plat_print, "Connected core 0 %s\n", ok ? "OK" : "Fail");
if (!ok) {
return false;
}
if (use_xip_as_ram) {
mp_printf(&mp_plat_print, "Disable XIP\n");
if (!write_reg(0x14000000, 0)) {
mp_printf(&mp_plat_print, "Disable XIP failed\n");
return false;
}
}
for (uint i = 0; i < num_sections; ++i)
{
if (!load(addresses[i], data[i], data_len_in_bytes[i])) {
mp_printf(&mp_plat_print, "Failed to load section %d\n", i);
return false;
}
}
ok = start(pc, sp);
ok |= connect(false, 1);
ok |= start(0, 0x20041000);
return ok;
}
bool swd_load_program(const uint* addresses, const uint** data, const uint* data_len_in_bytes, uint num_sections, uint pc = 0x20000001, uint sp = 0x20042000, bool use_xip_as_ram = false) {
bool ok = swd_load_program_internal(addresses, data, data_len_in_bytes, num_sections, pc, sp, use_xip_as_ram);
unload_pio();
return ok;
}

Wyświetl plik

@ -1,2 +0,0 @@
bool swd_load_program(const uint* addresses, const uint** data, const uint* data_len_in_bytes, uint num_sections, uint pc = 0x20000001, uint sp = 0x20042000, bool use_xip_as_ram = false);
bool swd_reset();

Wyświetl plik

@ -62,4 +62,3 @@ add_subdirectory(galactic_unicorn)
add_subdirectory(gfx_pack)
add_subdirectory(cosmic_unicorn)
add_subdirectory(stellar_unicorn)
add_subdirectory(dv_stick)

Wyświetl plik

@ -1,3 +0,0 @@
include(dv_stick_test.cmake)
include(dv_sprite_test.cmake)
include(dv_slideshow.cmake)

Wyświetl plik

@ -1,21 +0,0 @@
set(OUTPUT_NAME dv_slideshow)
add_executable(
${OUTPUT_NAME}
dv_slideshow.cpp
)
target_compile_definitions(${OUTPUT_NAME} PRIVATE
SDCARD_SPI_BUS=spi1
SDCARD_PIN_SPI0_CS=15
SDCARD_PIN_SPI0_SCK=10
SDCARD_PIN_SPI0_MOSI=11
SDCARD_PIN_SPI0_MISO=12)
# Pull in pico libraries that we need
target_link_libraries(${OUTPUT_NAME} pico_stdlib dv_display hardware_i2c hardware_uart pico_graphics fatfs jpegdec sdcard)
pico_enable_stdio_usb(${OUTPUT_NAME} 1)
# create map/bin/hex file etc.
pico_add_extra_outputs(${OUTPUT_NAME})

Wyświetl plik

@ -1,172 +0,0 @@
#include <cstdio>
#include <math.h>
#include <stdio.h>
#include "hardware/gpio.h"
#include "hardware/uart.h"
#include "drivers/dv_display/dv_display.hpp"
#include "libraries/pico_graphics/pico_graphics.hpp"
#include "JPEGDEC.h"
#include "drivers/fatfs/ff.h"
using namespace pimoroni;
#define FRAME_WIDTH 640
#define FRAME_HEIGHT 720
FATFS fs;
FRESULT fr;
DVDisplay display;
PicoGraphics_PenDV_RGB888 graphics(FRAME_WIDTH, FRAME_HEIGHT, display);
JPEGDEC jpeg;
struct {
int x, y;
} jpeg_decode_options;
void *jpegdec_open_callback(const char *filename, int32_t *size) {
FIL *fil = new FIL;
if(f_open(fil, filename, FA_READ)) {return nullptr;}
*size = f_size(fil);
return (void *)fil;
}
void jpegdec_close_callback(void *handle) {
f_close((FIL *)handle);
delete (FIL *)handle;
}
int32_t jpegdec_read_callback(JPEGFILE *jpeg, uint8_t *p, int32_t c) {
uint br; f_read((FIL *)jpeg->fHandle, p, c, &br);
return br;
}
int32_t jpegdec_seek_callback(JPEGFILE *jpeg, int32_t p) {
return f_lseek((FIL *)jpeg->fHandle, p) == FR_OK ? 1 : 0;
}
int jpegdec_draw_callback(JPEGDRAW *draw) {
uint8_t *p = (uint8_t*)draw->pPixels;
int xo = jpeg_decode_options.x;
int yo = jpeg_decode_options.y;
for(int y = 0; y < draw->iHeight; y++) {
for(int x = 0; x < draw->iWidth; x+=2) {
int sx = ((draw->x + x) >> 1) + xo;
int sy = draw->y + y + yo;
if(sx >= 0 && sx < graphics.bounds.w && x < draw->iWidthUsed &&
sy >= 0 && sy < graphics.bounds.h) {
RGB888 col = ((((uint32_t)p[0] + (uint32_t)p[3]) << 15) & 0xff0000) |
((((uint32_t)p[1] + (uint32_t)p[4]) << 7) & 0xff00) |
(((uint32_t)p[2] + (uint32_t)p[5]) >> 1);
graphics.set_pen(col);
graphics.pixel({sx, sy});
}
p += 6;
}
}
return 1; // continue drawing
}
void draw_jpeg(std::string filename) {
jpeg.open(
filename.c_str(),
jpegdec_open_callback,
jpegdec_close_callback,
jpegdec_read_callback,
jpegdec_seek_callback,
jpegdec_draw_callback
);
jpeg_decode_options.x = (FRAME_WIDTH - (jpeg.getWidth() >> 1)) >> 1;
jpeg_decode_options.y = (FRAME_HEIGHT - jpeg.getHeight()) >> 1;
jpeg.setPixelType(RGB888_LITTLE_ENDIAN);
printf("- starting jpeg decode..");
int start = millis();
jpeg.decode(0, 0, 0);
printf("done in %d ms!\n", int(millis() - start));
jpeg.close();
}
void on_uart_rx() {
while (uart_is_readable(uart1)) {
uint8_t ch = uart_getc(uart1);
putc(ch, stdout);
}
}
int main() {
set_sys_clock_khz(216000, true);
stdio_init_all();
// Relay UART RX from the display driver
gpio_set_function(5, GPIO_FUNC_UART);
uart_init(uart1, 115200);
uart_set_hw_flow(uart1, false, false);
uart_set_format(uart1, 8, 1, UART_PARITY_NONE);
uart_set_fifo_enabled(uart1, false);
irq_set_exclusive_handler(UART1_IRQ, on_uart_rx);
irq_set_enabled(UART1_IRQ, true);
uart_set_irq_enables(uart1, true, false);
constexpr uint BUTTON_A = 9;
gpio_init(BUTTON_A);
gpio_set_dir(BUTTON_A, GPIO_IN);
gpio_pull_up(BUTTON_A);
sleep_ms(5000);
display.init(FRAME_WIDTH, FRAME_HEIGHT, DVDisplay::MODE_RGB888);
//display.test();
graphics.set_pen(0);
graphics.clear();
display.flip();
graphics.set_pen(0);
graphics.clear();
printf("mounting sd card.. ");
fr = f_mount(&fs, "", 1);
if (fr != FR_OK) {
printf("Failed to mount SD card, error: %d\n", fr);
return 0;
}
printf("done!\n");
printf("Listing sd card contents..\n");
FILINFO file;
auto dir = new DIR();
bool first = true;
constexpr int ms_per_image = 5000;
const TCHAR* dirname = "/images720/";
while (1) {
f_opendir(dir, dirname);
while(f_readdir(dir, &file) == FR_OK && file.fname[0]) {
printf("- %s %lld\n", file.fname, file.fsize);
draw_jpeg(std::string(dirname) + file.fname);
if (!first) {
for (int w = 0; w < ms_per_image && gpio_get(BUTTON_A) == 1; w += 10) {
sleep_ms(10);
}
}
first = false;
display.flip();
graphics.set_pen(0);
graphics.clear();
}
f_closedir(dir);
printf("done!\n");
}
}

Wyświetl plik

@ -1,15 +0,0 @@
set(OUTPUT_NAME dv_sprite_test)
add_executable(
${OUTPUT_NAME}
dv_sprite_test.cpp
edid-decode.c
)
# Pull in pico libraries that we need
target_link_libraries(${OUTPUT_NAME} pico_stdlib dv_display hardware_i2c hardware_uart pico_graphics)
pico_enable_stdio_usb(${OUTPUT_NAME} 1)
# create map/bin/hex file etc.
pico_add_extra_outputs(${OUTPUT_NAME})

Wyświetl plik

@ -1,122 +0,0 @@
#include <cstdio>
#include <math.h>
#include <stdio.h>
#include "hardware/gpio.h"
#include "hardware/uart.h"
#include "drivers/dv_display/dv_display.hpp"
#include "libraries/pico_graphics/pico_graphics.hpp"
using namespace pimoroni;
#define DISPLAY_WIDTH 720
#define DISPLAY_HEIGHT 480
#define FRAME_WIDTH 720
#define FRAME_HEIGHT 480
#define SPRITE_WIDTH 8
#define SPRITE_HEIGHT 8
#define USE_PALETTE 0
#if USE_PALETTE
static uint8_t sprite_data_pal[] = {
0x00, 0x00, 0x00, 0x05, 0x05, 0x00, 0x00, 0x00,
0x00, 0x00, 0x05, 0x05, 0x05, 0x05, 0x00, 0x00,
0x00, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x00,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x00, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x00,
0x00, 0x00, 0x05, 0x05, 0x05, 0x05, 0x00, 0x00,
0x00, 0x00, 0x00, 0x05, 0x05, 0x00, 0x00, 0x00,
};
#else
static uint16_t sprite_data[] = {
0x0000, 0x0000, 0x0000, 0xF000, 0xF000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0xF000, 0xF000, 0xF000, 0xF000, 0x0000, 0x0000,
0x0000, 0xF000, 0xF000, 0xF000, 0xF000, 0xF000, 0xF000, 0x0000,
0xF000, 0xF000, 0xF000, 0xF000, 0xF000, 0xF000, 0xF000, 0xF000,
0xF000, 0xF000, 0xF000, 0xF000, 0xF000, 0xF000, 0xF000, 0xF000,
0x0000, 0xF000, 0xF000, 0xF000, 0xF000, 0xF000, 0xF000, 0x0000,
0x0000, 0x0000, 0xF000, 0xF000, 0xF000, 0xF000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0xF000, 0xF000, 0x0000, 0x0000, 0x0000,
};
#endif
void on_uart_rx() {
while (uart_is_readable(uart1)) {
uint8_t ch = uart_getc(uart1);
putc(ch, stdout);
}
}
int main() {
stdio_init_all();
// Relay UART RX from the display driver
gpio_set_function(5, GPIO_FUNC_UART);
uart_init(uart1, 115200);
uart_set_hw_flow(uart1, false, false);
uart_set_format(uart1, 8, 1, UART_PARITY_NONE);
uart_set_fifo_enabled(uart1, false);
irq_set_exclusive_handler(UART1_IRQ, on_uart_rx);
irq_set_enabled(UART1_IRQ, true);
uart_set_irq_enables(uart1, true, false);
constexpr uint BUTTON_A = 9;
gpio_init(BUTTON_A);
gpio_set_dir(BUTTON_A, GPIO_IN);
gpio_pull_up(BUTTON_A);
//sleep_ms(5000);
DVDisplay display;
#if USE_PALETTE
display.init(DISPLAY_WIDTH, DISPLAY_HEIGHT, DVDisplay::MODE_PALETTE, FRAME_WIDTH, FRAME_HEIGHT);
PicoGraphics_PenDV_P5 graphics(FRAME_WIDTH, FRAME_HEIGHT, display);
display.define_palette_sprite(0, SPRITE_WIDTH, SPRITE_HEIGHT, sprite_data_pal);
graphics.create_pen(0, 0, 0x20);
graphics.create_pen(0xF0, 0, 0);
graphics.set_pen(0);
#else
display.init(DISPLAY_WIDTH, DISPLAY_HEIGHT, DVDisplay::MODE_RGB555, FRAME_WIDTH, FRAME_HEIGHT);
PicoGraphics_PenDV_RGB555 graphics(FRAME_WIDTH, FRAME_HEIGHT, display);
display.define_sprite(0, SPRITE_WIDTH, SPRITE_HEIGHT, sprite_data);
graphics.set_pen(0x000F);
#endif
graphics.clear();
display.flip();
constexpr int NUM_SPRITES = 32;
Point sprite_pos[NUM_SPRITES];
Point sprite_dir[NUM_SPRITES];
for (int i = 0; i < 32; ++i) {
sprite_pos[i].x = rand() % DISPLAY_WIDTH;
sprite_pos[i].y = rand() % DISPLAY_HEIGHT;
sprite_dir[i].x = (rand() & 1) ? 1 : -1;
sprite_dir[i].y = (rand() & 1) ? 1 : -1;
}
while (true)
{
for (int i = 0; i < 32; ++i) {
display.set_sprite(i, 0, sprite_pos[i], (i < 16) ? DVDisplay::BLEND_BLEND : DVDisplay::BLEND_DEPTH);
sprite_pos[i] += sprite_dir[i];
if (sprite_pos[i].x >= DISPLAY_WIDTH || sprite_pos[i].x <= 0) {
sprite_dir[i].x = -sprite_dir[i].x;
sprite_pos[i].x += sprite_dir[i].x;
}
if (sprite_pos[i].y >= DISPLAY_HEIGHT || sprite_pos[i].y <= 0) {
sprite_dir[i].y = -sprite_dir[i].y;
sprite_pos[i].y += sprite_dir[i].y;
}
}
sleep_ms(16);
}
}

Wyświetl plik

@ -1,15 +0,0 @@
set(OUTPUT_NAME dv_stick_test)
add_executable(
${OUTPUT_NAME}
dv_stick_test.cpp
edid-decode.c
)
# Pull in pico libraries that we need
target_link_libraries(${OUTPUT_NAME} pico_stdlib dv_display hardware_i2c hardware_uart pico_graphics)
pico_enable_stdio_usb(${OUTPUT_NAME} 1)
# create map/bin/hex file etc.
pico_add_extra_outputs(${OUTPUT_NAME})

Wyświetl plik

@ -1,231 +0,0 @@
#include <cstdio>
#include <math.h>
#include <stdio.h>
#include "hardware/gpio.h"
#include "hardware/uart.h"
#include "drivers/dv_display/dv_display.hpp"
#include "libraries/pico_graphics/pico_graphics.hpp"
using namespace pimoroni;
#define DISPLAY_WIDTH 360
#define DISPLAY_HEIGHT 480
#define FRAME_WIDTH 1000
#define FRAME_HEIGHT 600
#define READ_EDID 0
#if READ_EDID
extern "C" { int decode_edid(unsigned char* edid); }
#endif
#define USE_PALETTE 0
void on_uart_rx() {
while (uart_is_readable(uart1)) {
uint8_t ch = uart_getc(uart1);
putc(ch, stdout);
}
}
int main() {
set_sys_clock_khz(216000, true);
stdio_init_all();
// Relay UART RX from the display driver
gpio_set_function(5, GPIO_FUNC_UART);
uart_init(uart1, 115200);
uart_set_hw_flow(uart1, false, false);
uart_set_format(uart1, 8, 1, UART_PARITY_NONE);
uart_set_fifo_enabled(uart1, false);
irq_set_exclusive_handler(UART1_IRQ, on_uart_rx);
irq_set_enabled(UART1_IRQ, true);
uart_set_irq_enables(uart1, true, false);
constexpr uint BUTTON_A = 9;
gpio_init(BUTTON_A);
gpio_set_dir(BUTTON_A, GPIO_IN);
gpio_pull_up(BUTTON_A);
//sleep_ms(5000);
DVDisplay display;
display.init(DISPLAY_WIDTH, DISPLAY_HEIGHT, DVDisplay::MODE_RGB888, FRAME_WIDTH, FRAME_HEIGHT);
//display.test();
#if READ_EDID
sleep_ms(5000);
{
uint8_t edid[128];
display.get_edid(edid);
sleep_ms(50);
decode_edid(edid);
}
#endif
#if USE_PALETTE
display.set_mode(DVDisplay::MODE_PALETTE);
PicoGraphics_PenDV_P5 graphics(FRAME_WIDTH, FRAME_HEIGHT, display);
#else
//display.set_mode(DVDisplay::MODE_RGB888);
PicoGraphics_PenDV_RGB888 graphics(FRAME_WIDTH, FRAME_HEIGHT, display);
#endif
graphics.create_pen(0, 0, 0);
graphics.create_pen(0xFF, 0xFF, 0xFF);
#if USE_PALETTE
for (int i = 0; i < 25; ++i) {
graphics.create_pen_hsv(i * 0.04f, 1.0f, 1.0f);
}
for (int i = 0; i < 5; ++i) {
graphics.create_pen((i+3) * (255/8), 255, 255);
}
#endif
graphics.set_pen(0xFF, 0, 0);
printf(".\n");
graphics.clear();
printf("..\n");
display.set_scroll_idx_for_lines(0, 100, 200);
display.set_scroll_idx_for_lines(2, 300, FRAME_HEIGHT);
display.flip();
printf("...\n");
sleep_ms(2000);
graphics.set_pen(0, 0, 0xFF);
graphics.clear();
display.set_scroll_idx_for_lines(0, 100, 200);
display.set_scroll_idx_for_lines(2, 300, FRAME_HEIGHT);
display.flip();
printf("Starting\n");
graphics.set_font("bitmap8");
Point scroll1 = {0, 0};
Point scroll2 = {0, 0};
int scroll_dir[2] = {1,1};
constexpr int NUM_CIRCLES = 50;
struct Circle {
uint16_t x, y, size, grow;
uint32_t pen;
} circles[NUM_CIRCLES];
for(int i =0 ; i < 50 ; i++)
{
circles[i].size = (rand() % 50) + 1;
circles[i].grow = std::max(0, (rand() % 50) - 25);
circles[i].x = rand() % graphics.bounds.w;
circles[i].y = rand() % graphics.bounds.h;
#if USE_PALETTE
circles[i].pen = 2 + (i >> 1);
#else
circles[i].pen = graphics.create_pen_hsv(i * 0.02f, 1.0f, 1.0f);
#endif
}
int frames = 0;
while (true) {
//while(gpio_get(BUTTON_A) == 1) {
// sleep_ms(10);
//}
uint32_t render_start_time = time_us_32();
#if 1
for (int j = 0; j < FRAME_HEIGHT; ++j) {
graphics.set_pen(j & 0xFF, 0xFF, 0xFF);
graphics.pixel_span({0,j}, FRAME_WIDTH);
}
#else
graphics.set_pen(0xFF, 0xFF, 0xFF);
graphics.clear();
#endif
#if 0
for (uint i = 0; i < 128; i++) {
for (uint j = 0; j < 256; j++) {
RGB555 col = (j << 7) | i;
graphics.set_pen((col << 3) & 0xF8, (col >> 2) & 0xF8, (col >> 7) & 0xF8);
graphics.pixel(Point(j, i));
}
}
for (uint i = 0; i < 128; i++) {
for (uint j = 0; j < 256; j++) {
graphics.set_pen((j << 7) | i);
graphics.pixel(Point(i, j+128));
}
}
#endif
for(int i =0 ; i < NUM_CIRCLES ; i++)
{
graphics.set_pen(0, 0, 0);
graphics.circle(Point(circles[i].x, circles[i].y), circles[i].size);
//RGB col = RGB::from_hsv(i * 0.02f, 1.0f, 1.0f);
//graphics.set_pen(col.r, col.g, col.b);
graphics.set_pen(circles[i].pen);
graphics.circle(Point(circles[i].x, circles[i].y), circles[i].size-2);
if (circles[i].grow) {
circles[i].size++;
circles[i].grow--;
} else {
circles[i].size--;
if (circles[i].size == 0) {
circles[i].size = 1;
circles[i].grow = rand() % 75;
circles[i].x = rand() % graphics.bounds.w;
circles[i].y = rand() % graphics.bounds.h;
}
}
}
#if 0
uint x = 260; //rand() % graphics.bounds.w;
uint y = 468; //rand() % graphics.bounds.h;
printf("Circle at (%d, %d)\n", x, y);
graphics.set_pen(0);
graphics.circle(Point(x, y), 25);
#endif
uint32_t render_time = time_us_32() - render_start_time;
char buffer[8];
sprintf(buffer, "%s %s %s",
gpio_get(BUTTON_A) == 0 ? "A" : " ",
display.is_button_b_pressed() ? "B" : " ",
display.is_button_c_pressed() ? "C" : " ");
graphics.set_pen(0, 0, 0);
graphics.text(buffer, {500,10}, FRAME_WIDTH - 500, 3);
uint32_t flip_start_time = time_us_32();
display.flip();
uint32_t flip_time = time_us_32() - flip_start_time;
if (false) printf("Render: %.3f, flip: %.3f\n", render_time / 1000.f, flip_time / 1000.f);
//printf("%02x %02x\n", display.get_gpio(), display.get_gpio_hi());
display.set_display_offset(scroll1, 1);
display.set_display_offset(scroll2, 2);
scroll1.x += scroll_dir[0];
if (scroll1.x + DISPLAY_WIDTH > FRAME_WIDTH || scroll1.x < 0) {
scroll_dir[0] = -scroll_dir[0];
scroll1.x += scroll_dir[0];
}
scroll2.y += scroll_dir[1];
if (scroll2.y + DISPLAY_HEIGHT > FRAME_HEIGHT || scroll2.y < 0) {
scroll_dir[1] = -scroll_dir[1];
scroll2.y += scroll_dir[1];
}
++frames;
display.set_gpio_hi_pull_up_all(frames & 0x3F);
display.set_gpio_hi_pull_down_all(~(frames & 0x3F));
if (gpio_get(BUTTON_A) == 0) display.set_led_level((uint8_t)frames);
else display.set_led_heartbeat();
}
}

Wyświetl plik

@ -18,9 +18,6 @@ add_library(pico_graphics
${CMAKE_CURRENT_LIST_DIR}/pico_graphics_pen_rgb565.cpp
${CMAKE_CURRENT_LIST_DIR}/pico_graphics_pen_rgb888.cpp
${CMAKE_CURRENT_LIST_DIR}/pico_graphics_pen_inky7.cpp
${CMAKE_CURRENT_LIST_DIR}/pico_graphics_pen_dv_rgb555.cpp
${CMAKE_CURRENT_LIST_DIR}/pico_graphics_pen_dv_rgb888.cpp
${CMAKE_CURRENT_LIST_DIR}/pico_graphics_pen_dv_p5.cpp
)
target_include_directories(pico_graphics INTERFACE ${CMAKE_CURRENT_LIST_DIR})

Wyświetl plik

@ -597,73 +597,4 @@ namespace pimoroni {
return w * h;
}
};
class PicoGraphics_PenDV_RGB555 : public PicoGraphics {
public:
RGB555 color;
IDirectDisplayDriver<uint16_t> &driver;
PicoGraphics_PenDV_RGB555(uint16_t width, uint16_t height, IDirectDisplayDriver<uint16_t> &direct_display_driver);
void set_pen(uint c) override;
void set_pen(uint8_t r, uint8_t g, uint8_t b) override;
int create_pen(uint8_t r, uint8_t g, uint8_t b) override;
int create_pen_hsv(float h, float s, float v) override;
void set_pixel(const Point &p) override;
void set_pixel_span(const Point &p, uint l) override;
static size_t buffer_size(uint w, uint h) {
return w * h * sizeof(RGB555);
}
};
class PicoGraphics_PenDV_RGB888 : public PicoGraphics {
public:
RGB888 color;
IDirectDisplayDriver<RGB888> &driver;
PicoGraphics_PenDV_RGB888(uint16_t width, uint16_t height, IDirectDisplayDriver<RGB888> &direct_display_driver);
void set_pen(uint c) override;
void set_pen(uint8_t r, uint8_t g, uint8_t b) override;
int create_pen(uint8_t r, uint8_t g, uint8_t b) override;
int create_pen_hsv(float h, float s, float v) override;
void set_pixel(const Point &p) override;
void set_pixel_span(const Point &p, uint l) override;
static size_t buffer_size(uint w, uint h) {
return w * h * sizeof(RGB888);
}
};
class PicoGraphics_PenDV_P5 : public PicoGraphics {
public:
static const uint16_t palette_size = 32;
uint8_t color;
IPaletteDisplayDriver &driver;
RGB palette[palette_size];
bool used[palette_size];
std::array<std::array<uint8_t, 16>, 512> candidate_cache;
bool cache_built = false;
std::array<uint8_t, 16> candidates;
PicoGraphics_PenDV_P5(uint16_t width, uint16_t height, IPaletteDisplayDriver &dv_display);
void set_pen(uint c) override;
void set_pen(uint8_t r, uint8_t g, uint8_t b) override;
int update_pen(uint8_t i, uint8_t r, uint8_t g, uint8_t b) override;
int create_pen(uint8_t r, uint8_t g, uint8_t b) override;
int create_pen_hsv(float h, float s, float v) override;
int reset_pen(uint8_t i) override;
int get_palette_size() override {return palette_size;};
RGB* get_palette() override {return palette;};
void set_pixel(const Point &p) override;
void set_pixel_span(const Point &p, uint l) override;
void get_dither_candidates(const RGB &col, const RGB *palette, size_t len, std::array<uint8_t, 16> &candidates);
void set_pixel_dither(const Point &p, const RGB &c) override;
static size_t buffer_size(uint w, uint h) {
return w * h;
}
};
}

Wyświetl plik

@ -1,110 +0,0 @@
#include "pico_graphics.hpp"
namespace pimoroni {
PicoGraphics_PenDV_P5::PicoGraphics_PenDV_P5(uint16_t width, uint16_t height, IPaletteDisplayDriver &palette_display_driver)
: PicoGraphics(width, height, nullptr),
driver(palette_display_driver)
{
this->pen_type = PEN_DV_P5;
for(auto i = 0u; i < palette_size; i++) {
palette[i] = {
uint8_t(i << 3),
uint8_t(i << 3),
uint8_t(i << 3)
};
driver.set_palette_colour(i, palette[i].to_rgb888());
used[i] = false;
}
cache_built = false;
}
void PicoGraphics_PenDV_P5::set_pen(uint c) {
color = c & 0x1f;
}
void PicoGraphics_PenDV_P5::set_pen(uint8_t r, uint8_t g, uint8_t b) {
int pen = RGB(r, g, b).closest(palette, palette_size);
if(pen != -1) color = pen;
}
int PicoGraphics_PenDV_P5::update_pen(uint8_t i, uint8_t r, uint8_t g, uint8_t b) {
i &= 0x1f;
used[i] = true;
palette[i] = {r, g, b};
cache_built = false;
driver.set_palette_colour(i, palette[i].to_rgb888());
return i;
}
int PicoGraphics_PenDV_P5::create_pen(uint8_t r, uint8_t g, uint8_t b) {
// Create a colour and place it in the palette if there's space
for(auto i = 0u; i < palette_size; i++) {
if(!used[i]) {
palette[i] = {r, g, b};
used[i] = true;
cache_built = false;
driver.set_palette_colour(i, palette[i].to_rgb888());
return i;
}
}
return -1;
}
int PicoGraphics_PenDV_P5::create_pen_hsv(float h, float s, float v) {
RGB p = RGB::from_hsv(h, s, v);
return create_pen(p.r, p.g, p.b);
}
int PicoGraphics_PenDV_P5::reset_pen(uint8_t i) {
palette[i] = {0, 0, 0};
used[i] = false;
cache_built = false;
return i;
}
void PicoGraphics_PenDV_P5::set_pixel(const Point &p) {
driver.write_palette_pixel(p, color << 2);
}
void PicoGraphics_PenDV_P5::set_pixel_span(const Point &p, uint l) {
driver.write_palette_pixel_span(p, l, color << 2);
}
void PicoGraphics_PenDV_P5::get_dither_candidates(const RGB &col, const RGB *palette, size_t len, std::array<uint8_t, 16> &candidates) {
RGB error;
for(size_t i = 0; i < candidates.size(); i++) {
candidates[i] = (col + error).closest(palette, len);
error += (col - palette[candidates[i]]);
}
// sort by a rough approximation of luminance, this ensures that neighbouring
// pixels in the dither matrix are at extreme opposites of luminence
// giving a more balanced output
std::sort(candidates.begin(), candidates.end(), [palette](int a, int b) {
return palette[a].luminance() > palette[b].luminance();
});
}
void PicoGraphics_PenDV_P5::set_pixel_dither(const Point &p, const RGB &c) {
if(!bounds.contains(p)) return;
uint used_palette_entries = 0;
for(auto i = 0u; i < palette_size; i++) {
if(!used[i]) break;
used_palette_entries++;
}
if(!cache_built) {
for(uint i = 0; i < 512; i++) {
RGB cache_col((i & 0x1C0) >> 1, (i & 0x38) << 2, (i & 0x7) << 5);
get_dither_candidates(cache_col, palette, used_palette_entries, candidate_cache[i]);
}
cache_built = true;
}
uint cache_key = ((c.r & 0xE0) << 1) | ((c.g & 0xE0) >> 2) | ((c.b & 0xE0) >> 5);
//get_dither_candidates(c, palette, 256, candidates);
// find the pattern coordinate offset
uint pattern_index = (p.x & 0b11) | ((p.y & 0b11) << 2);
// set the pixel
//color = candidates[pattern[pattern_index]];
color = candidate_cache[cache_key][dither16_pattern[pattern_index]];
set_pixel(p);
}
}

Wyświetl plik

@ -1,29 +0,0 @@
#include "pico_graphics.hpp"
namespace pimoroni {
PicoGraphics_PenDV_RGB555::PicoGraphics_PenDV_RGB555(uint16_t width, uint16_t height, IDirectDisplayDriver<uint16_t> &direct_display_driver)
: PicoGraphics(width, height, nullptr),
driver(direct_display_driver)
{
this->pen_type = PEN_DV_RGB555;
}
void PicoGraphics_PenDV_RGB555::set_pen(uint c) {
color = c;
}
void PicoGraphics_PenDV_RGB555::set_pen(uint8_t r, uint8_t g, uint8_t b) {
RGB src_color{r, g, b};
color = src_color.to_rgb555();
}
int PicoGraphics_PenDV_RGB555::create_pen(uint8_t r, uint8_t g, uint8_t b) {
return RGB(r, g, b).to_rgb555();
}
int PicoGraphics_PenDV_RGB555::create_pen_hsv(float h, float s, float v) {
return RGB::from_hsv(h, s, v).to_rgb555();
}
void PicoGraphics_PenDV_RGB555::set_pixel(const Point &p) {
driver.write_pixel(p, color);
}
void PicoGraphics_PenDV_RGB555::set_pixel_span(const Point &p, uint l) {
driver.write_pixel_span(p, l, color);
}
}

Wyświetl plik

@ -1,29 +0,0 @@
#include "pico_graphics.hpp"
namespace pimoroni {
PicoGraphics_PenDV_RGB888::PicoGraphics_PenDV_RGB888(uint16_t width, uint16_t height, IDirectDisplayDriver<RGB888> &direct_display_driver)
: PicoGraphics(width, height, nullptr),
driver(direct_display_driver)
{
this->pen_type = PEN_DV_RGB888;
}
void PicoGraphics_PenDV_RGB888::set_pen(uint c) {
color = c;
}
void PicoGraphics_PenDV_RGB888::set_pen(uint8_t r, uint8_t g, uint8_t b) {
RGB src_color{r, g, b};
color = src_color.to_rgb888();
}
int PicoGraphics_PenDV_RGB888::create_pen(uint8_t r, uint8_t g, uint8_t b) {
return RGB(r, g, b).to_rgb888();
}
int PicoGraphics_PenDV_RGB888::create_pen_hsv(float h, float s, float v) {
return RGB::from_hsv(h, s, v).to_rgb888();
}
void PicoGraphics_PenDV_RGB888::set_pixel(const Point &p) {
driver.write_pixel(p, color);
}
void PicoGraphics_PenDV_RGB888::set_pixel_span(const Point &p, uint l) {
driver.write_pixel_span(p, l, color);
}
}