Compare commits
2 commits
main
...
line-callb
| Author | SHA1 | Date | |
|---|---|---|---|
| a7c1fe3f3c | |||
| 3e8ba7ca42 |
6 changed files with 161 additions and 24 deletions
|
|
@ -38,6 +38,13 @@ Wire up your DVI breakout as follows:
|
|||
|
||||
If using jumper jerky, twist the - and + wires for each signal together to help with signal integrity.
|
||||
|
||||
Other pinouts can be used by passing a `pinout` parameter to the `init`
|
||||
function.
|
||||
This pinout consists of 4 numbers giving the *positive* pin in each differential pair, in the order CK, D0, D1, D2, D3, using GPIO numbering.
|
||||
The default pinout is written `{13, 15, 17, 19}`.
|
||||
Only pin numbers from 12 to 20 are valid, as other pins are not connected to the HSTX peripheral.
|
||||
Using invalid pin numbers is an undignosed error.
|
||||
|
||||
TODO
|
||||
|
||||
## C/C++ Resources
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ using namespace pimoroni;
|
|||
#define FRAME_BUFFER_SIZE (640*360)
|
||||
__attribute__((section(".uninitialized_data"))) static uint8_t frame_buffer_a[FRAME_BUFFER_SIZE];
|
||||
__attribute__((section(".uninitialized_data"))) static uint8_t frame_buffer_b[FRAME_BUFFER_SIZE];
|
||||
__attribute__((section(".uninitialized_data"))) RGB888 *global_palette[PALETTE_SIZE];
|
||||
#endif
|
||||
|
||||
#include "font.h"
|
||||
|
|
@ -158,7 +159,9 @@ void __scratch_x("display") DVHSTX::gfx_dma_handler() {
|
|||
line_num = new_line_num;
|
||||
uint32_t* dst_ptr = &line_buffers[line_num * line_buf_total_len + count_of(vactive_line_header)];
|
||||
|
||||
if (line_bytes_per_pixel == 2) {
|
||||
if (callback) {
|
||||
callback(cb_data, y, dst_ptr);
|
||||
} else if (line_bytes_per_pixel == 2) {
|
||||
uint16_t* src_ptr = (uint16_t*)&frame_buffer_display[y * 2 * (timing_mode->h_active_pixels >> h_repeat_shift)];
|
||||
if (h_repeat_shift == 2) {
|
||||
for (int i = 0; i < timing_mode->h_active_pixels >> 1; i += 2) {
|
||||
|
|
@ -599,7 +602,7 @@ DVHSTX::DVHSTX()
|
|||
dma_claim_mask((1 << NUM_CHANS) - 1);
|
||||
}
|
||||
|
||||
bool DVHSTX::init(uint16_t width, uint16_t height, Mode mode_)
|
||||
bool DVHSTX::init(uint16_t width, uint16_t height, Mode mode_, Pinout pinout)
|
||||
{
|
||||
if (inited) reset();
|
||||
|
||||
|
|
@ -643,8 +646,8 @@ bool DVHSTX::init(uint16_t width, uint16_t height, Mode mode_)
|
|||
}
|
||||
else
|
||||
{
|
||||
uint16_t full_width = display_width;
|
||||
uint16_t full_height = display_height;
|
||||
volatile uint16_t full_width = display_width;
|
||||
volatile uint16_t full_height = display_height;
|
||||
h_repeat_shift = 0;
|
||||
v_repeat_shift = 0;
|
||||
|
||||
|
|
@ -661,6 +664,9 @@ bool DVHSTX::init(uint16_t width, uint16_t height, Mode mode_)
|
|||
if (full_width == 640) {
|
||||
if (full_height == 480) timing_mode = &dvi_timing_640x480p_60hz;
|
||||
}
|
||||
else if (full_width == 1280 && full_height == 720) {
|
||||
timing_mode = &dvi_timing_1280x720p_rb_50hz;
|
||||
}
|
||||
else if (full_width == 720) {
|
||||
if (full_height == 480) timing_mode = &dvi_timing_720x480p_60hz;
|
||||
else if (full_height == 400) timing_mode = &dvi_timing_720x400p_70hz;
|
||||
|
|
@ -681,11 +687,19 @@ bool DVHSTX::init(uint16_t width, uint16_t height, Mode mode_)
|
|||
|
||||
if (!timing_mode) {
|
||||
dvhstx_debug("Unsupported resolution %dx%d", width, height);
|
||||
__builtin_trap();
|
||||
return false;
|
||||
}
|
||||
|
||||
display = this;
|
||||
display_palette = get_palette();
|
||||
if (mode == MODE_PALETTE) {
|
||||
#ifdef MICROPY_BUILD_TYPE
|
||||
palette = global_palette;
|
||||
#else
|
||||
palette = (RGB888*)malloc(sizeof(RGB888) * PALETTE_SIZE);
|
||||
display_palette = get_palette();
|
||||
#endif
|
||||
}
|
||||
|
||||
dvhstx_debug("Setup clock\n");
|
||||
display_setup_clock();
|
||||
|
|
@ -731,6 +745,7 @@ bool DVHSTX::init(uint16_t width, uint16_t height, Mode mode_)
|
|||
frame_bytes_per_pixel = 1;
|
||||
line_bytes_per_pixel = 4;
|
||||
break;
|
||||
case MODE_LINE_CALLBACK:
|
||||
case MODE_RGB888:
|
||||
frame_bytes_per_pixel = 4;
|
||||
line_bytes_per_pixel = 4;
|
||||
|
|
@ -755,14 +770,29 @@ bool DVHSTX::init(uint16_t width, uint16_t height, Mode mode_)
|
|||
|
||||
frame_buffer_display = frame_buffer_a;
|
||||
frame_buffer_back = frame_buffer_b;
|
||||
palette = global_palette;
|
||||
#else
|
||||
frame_buffer_display = (uint8_t*)malloc(frame_width * frame_height * frame_bytes_per_pixel);
|
||||
frame_buffer_back = (uint8_t*)malloc(frame_width * frame_height * frame_bytes_per_pixel);
|
||||
if (mode != MODE_LINE_CALLBACK ) {
|
||||
frame_buffer_display = (uint8_t*)malloc(frame_width * frame_height * frame_bytes_per_pixel);
|
||||
frame_buffer_back = (uint8_t*)malloc(frame_width * frame_height * frame_bytes_per_pixel);
|
||||
if (!frame_buffer_display) return false;
|
||||
if (!frame_buffer_back) { free (frame_buffer_display); return false; }
|
||||
if (mode == MODE_PALETTE) {
|
||||
palette = (RGB888*)malloc(sizeof(RGB888) * PALETTE_SIZE);
|
||||
if (!palette) {
|
||||
free (frame_buffer_display);
|
||||
free (frame_buffer_back);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
memset(frame_buffer_display, 0, frame_width * frame_height * frame_bytes_per_pixel);
|
||||
memset(frame_buffer_back, 0, frame_width * frame_height * frame_bytes_per_pixel);
|
||||
|
||||
memset(palette, 0, PALETTE_SIZE * sizeof(palette[0]));
|
||||
if (mode != MODE_LINE_CALLBACK ) {
|
||||
memset(frame_buffer_display, 0, frame_width * frame_height * frame_bytes_per_pixel);
|
||||
memset(frame_buffer_back, 0, frame_width * frame_height * frame_bytes_per_pixel);
|
||||
}
|
||||
if(mode == MODE_PALETTE)
|
||||
memset(palette, 0, PALETTE_SIZE * sizeof(palette[0]));
|
||||
|
||||
frame_buffer_display = frame_buffer_display;
|
||||
dvhstx_debug("Frame buffers inited\n");
|
||||
|
|
@ -816,6 +846,7 @@ bool DVHSTX::init(uint16_t width, uint16_t height, Mode mode_)
|
|||
0 << HSTX_CTRL_EXPAND_SHIFT_RAW_SHIFT_LSB;
|
||||
break;
|
||||
|
||||
case MODE_LINE_CALLBACK:
|
||||
case MODE_PALETTE:
|
||||
// Configure HSTX's TMDS encoder for RGB888
|
||||
hstx_ctrl_hw->expand_tmds =
|
||||
|
|
@ -889,24 +920,28 @@ bool DVHSTX::init(uint16_t width, uint16_t height, Mode mode_)
|
|||
HSTX_CTRL_CSR_EN_BITS;
|
||||
|
||||
// HSTX outputs 0 through 7 appear on GPIO 12 through 19.
|
||||
constexpr int HSTX_FIRST_PIN = 12;
|
||||
|
||||
// Assign clock pair to two neighbouring pins:
|
||||
hstx_ctrl_hw->bit[1] = HSTX_CTRL_BIT0_CLK_BITS;
|
||||
hstx_ctrl_hw->bit[0] = HSTX_CTRL_BIT0_CLK_BITS | HSTX_CTRL_BIT0_INV_BITS;
|
||||
{
|
||||
int bit = pinout.clk_p - HSTX_FIRST_PIN;
|
||||
hstx_ctrl_hw->bit[bit ] = HSTX_CTRL_BIT0_CLK_BITS;
|
||||
hstx_ctrl_hw->bit[bit ^ 1] = HSTX_CTRL_BIT0_CLK_BITS | HSTX_CTRL_BIT0_INV_BITS;
|
||||
}
|
||||
|
||||
for (uint lane = 0; lane < 3; ++lane) {
|
||||
// For each TMDS lane, assign it to the correct GPIO pair based on the
|
||||
// desired pinout:
|
||||
static const int lane_to_output_bit[3] = {2, 4, 6};
|
||||
int bit = lane_to_output_bit[lane];
|
||||
int bit = pinout.rgb_p[lane] - HSTX_FIRST_PIN;
|
||||
// Output even bits during first half of each HSTX cycle, and odd bits
|
||||
// during second half. The shifter advances by two bits each cycle.
|
||||
uint32_t lane_data_sel_bits =
|
||||
(lane * 10 ) << HSTX_CTRL_BIT0_SEL_P_LSB |
|
||||
(lane * 10 + 1) << HSTX_CTRL_BIT0_SEL_N_LSB;
|
||||
// The two halves of each pair get identical data, but one pin is inverted.
|
||||
hstx_ctrl_hw->bit[bit ] = lane_data_sel_bits | HSTX_CTRL_BIT0_INV_BITS;
|
||||
hstx_ctrl_hw->bit[bit + 1] = lane_data_sel_bits;
|
||||
}
|
||||
hstx_ctrl_hw->bit[bit ] = lane_data_sel_bits;
|
||||
hstx_ctrl_hw->bit[bit ^ 1] = lane_data_sel_bits | HSTX_CTRL_BIT0_INV_BITS;
|
||||
}
|
||||
|
||||
for (int i = 12; i <= 19; ++i) {
|
||||
gpio_set_function(i, GPIO_FUNC_HSTX);
|
||||
|
|
@ -970,8 +1005,10 @@ bool DVHSTX::init(uint16_t width, uint16_t height, Mode mode_)
|
|||
|
||||
dvhstx_debug("DVHSTX started\n");
|
||||
|
||||
for (int i = 0; i < frame_height; ++i) {
|
||||
memset(&frame_buffer_display[i * frame_width * frame_bytes_per_pixel], i, frame_width * frame_bytes_per_pixel);
|
||||
if (frame_buffer_display) {
|
||||
for (int i = 0; i < frame_height; ++i) {
|
||||
memset(&frame_buffer_display[i * frame_width * frame_bytes_per_pixel], i, frame_width * frame_bytes_per_pixel);
|
||||
}
|
||||
}
|
||||
|
||||
dvhstx_debug("Frame buffer filled\n");
|
||||
|
|
@ -1001,6 +1038,9 @@ void DVHSTX::reset() {
|
|||
#ifndef MICROPY_BUILD_TYPE
|
||||
free(frame_buffer_display);
|
||||
free(frame_buffer_back);
|
||||
if (palette) {
|
||||
free(palette);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
@ -1024,3 +1064,7 @@ void DVHSTX::flip_async() {
|
|||
void DVHSTX::wait_for_flip() {
|
||||
while (flip_next) __wfe();
|
||||
}
|
||||
|
||||
int DVHSTX::get_h_active_pixels() const {
|
||||
return timing_mode->h_active_pixels;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,12 +29,17 @@ namespace pimoroni {
|
|||
public:
|
||||
static constexpr int PALETTE_SIZE = 256;
|
||||
|
||||
struct Pinout {
|
||||
uint8_t clk_p, rgb_p[3];
|
||||
};
|
||||
|
||||
enum Mode {
|
||||
MODE_PALETTE = 2,
|
||||
MODE_RGB565 = 1,
|
||||
MODE_RGB888 = 3,
|
||||
MODE_TEXT_MONO = 4,
|
||||
MODE_TEXT_RGB111 = 5,
|
||||
MODE_LINE_CALLBACK = 6,
|
||||
};
|
||||
|
||||
enum TextColour {
|
||||
|
|
@ -92,9 +97,21 @@ namespace pimoroni {
|
|||
|
||||
void clear();
|
||||
|
||||
bool init(uint16_t width, uint16_t height, Mode mode = MODE_RGB565);
|
||||
typedef void(*line_fun_t)(void *cb_data, int line_num, uint32_t *data);
|
||||
void set_callback(line_fun_t cb, void *data) {
|
||||
callback = cb;
|
||||
cb_data = data;
|
||||
}
|
||||
bool init(uint16_t width, uint16_t height, Mode mode = MODE_RGB565, Pinout pinout = {13, 15, 17, 19});
|
||||
bool init(uint16_t width, uint16_t height, line_fun_t cb, void *data, Pinout pinout = {13, 15, 17, 19}) {
|
||||
set_callback(cb, data);
|
||||
return init(width, height, MODE_LINE_CALLBACK, pinout);
|
||||
}
|
||||
void reset();
|
||||
|
||||
int get_h_repeat_shift() const { return h_repeat_shift; }
|
||||
int get_h_active_pixels() const;
|
||||
|
||||
// Wait for vsync and then flip the buffers
|
||||
void flip_blocking();
|
||||
|
||||
|
|
@ -113,7 +130,8 @@ namespace pimoroni {
|
|||
void text_dma_handler();
|
||||
|
||||
private:
|
||||
RGB888 palette[PALETTE_SIZE];
|
||||
bool do_init(uint16_t width, uint16_t height, line_fun_t cb, void *cb_data, Mode mode, Pinout pinout);
|
||||
RGB888 *palette;
|
||||
|
||||
uint8_t* frame_buffer_display;
|
||||
uint8_t* frame_buffer_back;
|
||||
|
|
@ -154,5 +172,8 @@ namespace pimoroni {
|
|||
int line_bytes_per_pixel;
|
||||
|
||||
uint32_t* display_palette = nullptr;
|
||||
|
||||
line_fun_t callback = nullptr;
|
||||
void *cb_data = nullptr;
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,15 @@
|
|||
add_executable(
|
||||
otf
|
||||
otf.cpp
|
||||
)
|
||||
|
||||
# Pull in pico libraries that we need
|
||||
target_link_libraries(otf pico_stdlib pico_multicore pico_dvhstx)
|
||||
pico_enable_stdio_usb(otf 1)
|
||||
|
||||
# create map/bin/hex file etc.
|
||||
pico_add_extra_outputs(otf)
|
||||
|
||||
add_executable(
|
||||
mandelbrot
|
||||
mandelbrot.cpp
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ void draw_mandel() {
|
|||
}
|
||||
|
||||
int main() {
|
||||
display.init(FRAME_WIDTH, FRAME_HEIGHT, DVHSTX::MODE_PALETTE);
|
||||
display.init(FRAME_WIDTH, FRAME_HEIGHT, DVHSTX::MODE_PALETTE, {13, 15, 17, 19});
|
||||
|
||||
stdio_init_all();
|
||||
|
||||
|
|
|
|||
53
examples/dvhstx/otf.cpp
Normal file
53
examples/dvhstx/otf.cpp
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
|
||||
#include <stdio.h>
|
||||
#include "hardware/uart.h"
|
||||
#include "pico/multicore.h"
|
||||
#include "drivers/dvhstx/dvhstx.hpp"
|
||||
#include "libraries/pico_graphics/pico_graphics_dvhstx.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include "mandelf.h"
|
||||
}
|
||||
|
||||
using namespace pimoroni;
|
||||
|
||||
#define FRAME_WIDTH 640
|
||||
#define FRAME_HEIGHT 240
|
||||
|
||||
static DVHSTX display;
|
||||
static PicoGraphics_PenDVHSTX_P8 graphics(FRAME_WIDTH, FRAME_HEIGHT, display);
|
||||
|
||||
inline constexpr uint32_t RGB_to_RGB888(const uint8_t r, const uint8_t g, const uint8_t b) {
|
||||
return ((uint32_t)r << 16) | ((uint32_t)g << 8) | b;
|
||||
}
|
||||
|
||||
static uint32_t palette[256];
|
||||
static void init_palette() {
|
||||
for (int i = 0; i < 256; ++i) {
|
||||
#if 0
|
||||
int h = i * (1.f / 255.f), s = 1.0f, v = 0.5f + (i & 7) * (0.5f / 7.f);
|
||||
RGB p = RGB::from_hsv(h, s, v);
|
||||
palette[i] = RGB_to_RGB888(p.r, p.g, p.b);
|
||||
#endif
|
||||
palette[i] = RGB_to_RGB888(i, i, i);
|
||||
}
|
||||
}
|
||||
|
||||
void gen_line(void *cb_data, int line_num, uint32_t *dest) {
|
||||
int y1 = line_num - FRAME_HEIGHT / 2;
|
||||
int ysq = y1*y1 * 4;
|
||||
for(int h=0; h<FRAME_WIDTH; h++) {
|
||||
int x = h - FRAME_WIDTH / 2;
|
||||
int r2 = x*x + ysq;
|
||||
#define LIM (320*320)
|
||||
*dest++ = palette[r2 / 256 % 256];
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
display.init(FRAME_WIDTH, FRAME_HEIGHT, gen_line, &display, {13, 15, 17, 19});
|
||||
init_palette();
|
||||
|
||||
while(true) {
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue