Compare commits
5 commits
main
...
drivers_re
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
350a5aa1d7 | ||
|
|
d5f93199c9 | ||
|
|
9d6c356c66 | ||
|
|
a3264fdf95 | ||
|
|
e0fda41105 |
10 changed files with 1759 additions and 1991 deletions
2
.github/workflows/githubci.yml
vendored
2
.github/workflows/githubci.yml
vendored
|
|
@ -20,7 +20,7 @@ jobs:
|
|||
run: bash ci/actions_install.sh
|
||||
|
||||
- name: test platforms
|
||||
run: python3 ci/build_platform.py feather_rp2350 feather_rp2350_tinyusb metro_rp2350 metro_rp2350_tinyusb
|
||||
run: python3 ci/build_platform.py feather_rp2350 metro_rp2350
|
||||
|
||||
- name: clang
|
||||
run: python3 ci/run-clang-format.py -e "ci/*" -e "bin/*" -r .
|
||||
|
|
|
|||
|
|
@ -4,11 +4,15 @@
|
|||
|
||||
// If your board definition has PIN_CKP and related defines,
|
||||
// DVHSTX_PINOUT_DEFAULT is available
|
||||
DVHSTX16 display(DVHSTX_PINOUT_DEFAULT, DVHSTX_RESOLUTION_320x240);
|
||||
// If you get the message "error: 'DVHSTX_PINOUT_DEFAULTx' was not declared"
|
||||
// then you need to give the pins numbers explicitly, like the example below.
|
||||
// The order is: {CKP, D0P, D1P, D2P} DVHSTX16 display({12, 14, 16, 18},
|
||||
// DVHSTX_RESOLUTION_320x240);
|
||||
#ifdef PIN_CKP
|
||||
DVHSTX16 display(DVHSTX_PINOUT_DEFAULT, DVHSTX_RESOLUTION_320x240);
|
||||
#else
|
||||
DVHSTX16 display({14, 18, 16, 12}, DVHSTX_RESOLUTION_320x240);
|
||||
#endif
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
|
|
|
|||
|
|
@ -4,11 +4,15 @@
|
|||
|
||||
// If your board definition has PIN_CKP and related defines,
|
||||
// DVHSTX_PINOUT_DEFAULT is available
|
||||
DVHSTX8 display(DVHSTX_PINOUT_DEFAULT, DVHSTX_RESOLUTION_640x360);
|
||||
// If you get the message "error: 'DVHSTX_PINOUT_DEFAULTx' was not declared"
|
||||
// then you need to give the pins numbers explicitly, like the example below.
|
||||
// The order is: {CKP, D0P, D1P, D2P} DVHSTX8 display({12, 14, 16, 18},
|
||||
// DVHSTX_RESOLUTION_640x360);
|
||||
#ifdef PIN_CKP
|
||||
DVHSTX16 display(DVHSTX_PINOUT_DEFAULT, DVHSTX_RESOLUTION_320x240);
|
||||
#else
|
||||
DVHSTX16 display({14, 18, 16, 12}, DVHSTX_RESOLUTION_320x240);
|
||||
#endif
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
|
|
|
|||
|
|
@ -4,12 +4,16 @@
|
|||
|
||||
// If your board definition has PIN_CKP and related defines,
|
||||
// DVHSTX_PINOUT_DEFAULT is available
|
||||
DVHSTXText3 display(DVHSTX_PINOUT_DEFAULT);
|
||||
// If you get the message "error: 'DVHSTX_PINOUT_DEFAULTx' was not declared"
|
||||
// then you need to give the pins numbers explicitly, like the example below.
|
||||
// The order is: {CKP, D0P, D1P, D2P}.
|
||||
//
|
||||
// DVHSTXText3 display({12, 14, 16, 18});
|
||||
#ifdef PIN_CKP
|
||||
DVHSTX16 display(DVHSTX_PINOUT_DEFAULT, DVHSTX_RESOLUTION_320x240);
|
||||
#else
|
||||
DVHSTX16 display({14, 18, 16, 12}, DVHSTX_RESOLUTION_320x240);
|
||||
#endif
|
||||
|
||||
const static TextColor colors[] = {
|
||||
TextColor::TEXT_BLACK, TextColor::TEXT_RED, TextColor::TEXT_GREEN,
|
||||
|
|
|
|||
|
|
@ -1,15 +1,15 @@
|
|||
#include <pico/stdlib.h>
|
||||
#include <string.h>
|
||||
#include <pico/stdlib.h>
|
||||
|
||||
#if F_CPU != 150000000
|
||||
#error \
|
||||
"Adafruit_DVHSTX controls overclocking (setting CPU frequency to 264MHz). However, the Tools > CPU Speed selector *MUST* be set to 150MHz"
|
||||
#error "Adafruit_DVHSTX controls overclocking (setting CPU frequency to 264MHz). However, the Tools > CPU Speed selector *MUST* be set to 150MHz"
|
||||
#endif
|
||||
|
||||
extern "C" {
|
||||
#include <pico/lock_core.h>
|
||||
}
|
||||
|
||||
#include <algorithm>
|
||||
#include "hardware/dma.h"
|
||||
#include "hardware/gpio.h"
|
||||
#include "hardware/irq.h"
|
||||
|
|
@ -17,31 +17,27 @@ extern "C" {
|
|||
#include "hardware/structs/hstx_ctrl.h"
|
||||
#include "hardware/structs/hstx_fifo.h"
|
||||
#include "hardware/structs/sio.h"
|
||||
#include <algorithm>
|
||||
|
||||
#include "hardware/clocks.h"
|
||||
#include "hardware/pll.h"
|
||||
#include "hardware/structs/ioqspi.h"
|
||||
#include "hardware/structs/qmi.h"
|
||||
#include "hardware/vreg.h"
|
||||
#include "hardware/structs/qmi.h"
|
||||
#include "hardware/pll.h"
|
||||
#include "hardware/clocks.h"
|
||||
|
||||
#include "dvhstx.hpp"
|
||||
#include "dvi.hpp"
|
||||
#include "dvhstx.hpp"
|
||||
|
||||
using namespace pimoroni;
|
||||
|
||||
#ifdef MICROPY_BUILD_TYPE
|
||||
#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"))) static uint8_t frame_buffer_a[FRAME_BUFFER_SIZE];
|
||||
__attribute__((section(".uninitialized_data"))) static uint8_t frame_buffer_b[FRAME_BUFFER_SIZE];
|
||||
#endif
|
||||
|
||||
#include "font.h"
|
||||
|
||||
// If changing the font, note this code will not handle glyphs wider than 13
|
||||
// pixels
|
||||
// If changing the font, note this code will not handle glyphs wider than 13 pixels
|
||||
#define FONT (&intel_one_mono)
|
||||
|
||||
#ifdef MICROPY_BUILD_TYPE
|
||||
|
|
@ -57,20 +53,18 @@ void dvhstx_debug(const char *fmt, ...);
|
|||
#define dvhstx_debug printf
|
||||
#endif
|
||||
|
||||
static inline __attribute__((always_inline)) uint32_t render_char_line(int c,
|
||||
int y) {
|
||||
if (c < 0x20 || c > 0x7e)
|
||||
return 0;
|
||||
static inline __attribute__((always_inline)) uint32_t render_char_line(int c, int y) {
|
||||
if (c < 0x20 || c > 0x7e) return 0;
|
||||
const lv_font_fmt_txt_glyph_dsc_t* g = &FONT->dsc->glyph_dsc[c - 0x20 + 1];
|
||||
const uint8_t *b = FONT->dsc->glyph_bitmap + g->bitmap_index;
|
||||
const int ey = y - FONT_HEIGHT + FONT->base_line + g->ofs_y + g->box_h;
|
||||
if (ey < 0 || ey >= g->box_h || g->box_w == 0) {
|
||||
return 0;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
int bi = (g->box_w * ey);
|
||||
|
||||
uint32_t bits = (b[bi >> 2] << 24) | (b[(bi >> 2) + 1] << 16) |
|
||||
(b[(bi >> 2) + 2] << 8) | b[(bi >> 2) + 3];
|
||||
uint32_t bits = (b[bi >> 2] << 24) | (b[(bi >> 2) + 1] << 16) | (b[(bi >> 2) + 2] << 8) | b[(bi >> 2) + 3];
|
||||
bits >>= 6 - ((bi & 3) << 1);
|
||||
bits &= 0x3ffffff & (0x3ffffff << ((13 - g->box_w) << 1));
|
||||
bits >>= g->ofs_x << 1;
|
||||
|
|
@ -86,27 +80,53 @@ static inline __attribute__((always_inline)) uint32_t render_char_line(int c,
|
|||
// pingponging and tripping up the IRQs.
|
||||
|
||||
static const uint32_t vblank_line_vsync_off_src[] = {
|
||||
HSTX_CMD_RAW_REPEAT, SYNC_V1_H1, HSTX_CMD_RAW_REPEAT,
|
||||
SYNC_V1_H0, HSTX_CMD_RAW_REPEAT, SYNC_V1_H1};
|
||||
HSTX_CMD_RAW_REPEAT,
|
||||
SYNC_V1_H1,
|
||||
HSTX_CMD_RAW_REPEAT,
|
||||
SYNC_V1_H0,
|
||||
HSTX_CMD_RAW_REPEAT,
|
||||
SYNC_V1_H1
|
||||
};
|
||||
static uint32_t vblank_line_vsync_off[count_of(vblank_line_vsync_off_src)];
|
||||
|
||||
static const uint32_t vblank_line_vsync_on_src[] = {
|
||||
HSTX_CMD_RAW_REPEAT, SYNC_V0_H1, HSTX_CMD_RAW_REPEAT,
|
||||
SYNC_V0_H0, HSTX_CMD_RAW_REPEAT, SYNC_V0_H1};
|
||||
HSTX_CMD_RAW_REPEAT,
|
||||
SYNC_V0_H1,
|
||||
HSTX_CMD_RAW_REPEAT,
|
||||
SYNC_V0_H0,
|
||||
HSTX_CMD_RAW_REPEAT,
|
||||
SYNC_V0_H1
|
||||
};
|
||||
static uint32_t vblank_line_vsync_on[count_of(vblank_line_vsync_on_src)];
|
||||
|
||||
static const uint32_t vactive_line_header_src[] = {
|
||||
HSTX_CMD_RAW_REPEAT, SYNC_V1_H1, HSTX_CMD_RAW_REPEAT, SYNC_V1_H0,
|
||||
HSTX_CMD_RAW_REPEAT, SYNC_V1_H1, HSTX_CMD_TMDS};
|
||||
HSTX_CMD_RAW_REPEAT,
|
||||
SYNC_V1_H1,
|
||||
HSTX_CMD_RAW_REPEAT,
|
||||
SYNC_V1_H0,
|
||||
HSTX_CMD_RAW_REPEAT,
|
||||
SYNC_V1_H1,
|
||||
HSTX_CMD_TMDS
|
||||
};
|
||||
static uint32_t vactive_line_header[count_of(vactive_line_header_src)];
|
||||
|
||||
static const uint32_t vactive_text_line_header_src[] = {
|
||||
HSTX_CMD_RAW_REPEAT, SYNC_V1_H1, HSTX_CMD_RAW_REPEAT, SYNC_V1_H0,
|
||||
HSTX_CMD_RAW_REPEAT, SYNC_V1_H1, HSTX_CMD_RAW | 6, BLACK_PIXEL_A,
|
||||
BLACK_PIXEL_B, BLACK_PIXEL_A, BLACK_PIXEL_B, BLACK_PIXEL_A,
|
||||
BLACK_PIXEL_B, HSTX_CMD_TMDS};
|
||||
static uint32_t
|
||||
vactive_text_line_header[count_of(vactive_text_line_header_src)];
|
||||
HSTX_CMD_RAW_REPEAT,
|
||||
SYNC_V1_H1,
|
||||
HSTX_CMD_RAW_REPEAT,
|
||||
SYNC_V1_H0,
|
||||
HSTX_CMD_RAW_REPEAT,
|
||||
SYNC_V1_H1,
|
||||
HSTX_CMD_RAW | 6,
|
||||
BLACK_PIXEL_A,
|
||||
BLACK_PIXEL_B,
|
||||
BLACK_PIXEL_A,
|
||||
BLACK_PIXEL_B,
|
||||
BLACK_PIXEL_A,
|
||||
BLACK_PIXEL_B,
|
||||
HSTX_CMD_TMDS
|
||||
};
|
||||
static uint32_t vactive_text_line_header[count_of(vactive_text_line_header_src)];
|
||||
|
||||
#define NUM_FRAME_LINES 2
|
||||
#define NUM_CHANS 3
|
||||
|
|
@ -116,18 +136,18 @@ static DVHSTX *display = nullptr;
|
|||
// ----------------------------------------------------------------------------
|
||||
// DMA logic
|
||||
|
||||
void __scratch_x("display") dma_irq_handler() { display->gfx_dma_handler(); }
|
||||
void __scratch_x("display") dma_irq_handler() {
|
||||
display->gfx_dma_handler();
|
||||
}
|
||||
|
||||
void __scratch_x("display") DVHSTX::gfx_dma_handler() {
|
||||
// ch_num indicates the channel that just finished, which is the one
|
||||
// we're about to reload.
|
||||
dma_channel_hw_t *ch = &dma_hw->ch[ch_num];
|
||||
dma_hw->intr = 1u << ch_num;
|
||||
if (++ch_num == NUM_CHANS)
|
||||
ch_num = 0;
|
||||
if (++ch_num == NUM_CHANS) ch_num = 0;
|
||||
|
||||
if (v_scanline >= timing_mode->v_front_porch &&
|
||||
v_scanline < (timing_mode->v_front_porch + timing_mode->v_sync_width)) {
|
||||
if (v_scanline >= timing_mode->v_front_porch && v_scanline < (timing_mode->v_front_porch + timing_mode->v_sync_width)) {
|
||||
ch->read_addr = (uintptr_t)vblank_line_vsync_on;
|
||||
ch->transfer_count = count_of(vblank_line_vsync_on);
|
||||
} else if (v_scanline < v_inactive_total) {
|
||||
|
|
@ -135,56 +155,52 @@ void __scratch_x("display") DVHSTX::gfx_dma_handler() {
|
|||
ch->transfer_count = count_of(vblank_line_vsync_off);
|
||||
} else {
|
||||
const int y = (v_scanline - v_inactive_total) >> v_repeat_shift;
|
||||
const int new_line_num =
|
||||
(v_repeat_shift == 0) ? ch_num : (y & (NUM_FRAME_LINES - 1));
|
||||
const uint line_buf_total_len =
|
||||
((timing_mode->h_active_pixels * line_bytes_per_pixel) >> 2) +
|
||||
count_of(vactive_line_header);
|
||||
const int new_line_num = (v_repeat_shift == 0) ? ch_num : (y & (NUM_FRAME_LINES - 1));
|
||||
const uint line_buf_total_len = ((timing_mode->h_active_pixels * line_bytes_per_pixel) >> 2) + count_of(vactive_line_header);
|
||||
|
||||
ch->read_addr = (uintptr_t)&line_buffers[new_line_num * line_buf_total_len];
|
||||
ch->transfer_count = line_buf_total_len;
|
||||
|
||||
// Fill line buffer
|
||||
if (line_num != new_line_num) {
|
||||
if (line_num != new_line_num)
|
||||
{
|
||||
line_num = new_line_num;
|
||||
uint32_t *dst_ptr = &line_buffers[line_num * line_buf_total_len +
|
||||
count_of(vactive_line_header)];
|
||||
uint32_t* dst_ptr = &line_buffers[line_num * line_buf_total_len + count_of(vactive_line_header)];
|
||||
|
||||
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)];
|
||||
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) {
|
||||
uint32_t val = (uint32_t)(*src_ptr++) * 0x10001;
|
||||
*dst_ptr++ = val;
|
||||
*dst_ptr++ = val;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
for (int i = 0; i < timing_mode->h_active_pixels >> 1; ++i) {
|
||||
uint32_t val = (uint32_t)(*src_ptr++) * 0x10001;
|
||||
*dst_ptr++ = val;
|
||||
}
|
||||
}
|
||||
} else if (line_bytes_per_pixel == 1) {
|
||||
uint8_t *src_ptr =
|
||||
&frame_buffer_display[y * (timing_mode->h_active_pixels >>
|
||||
h_repeat_shift)];
|
||||
}
|
||||
else if (line_bytes_per_pixel == 1) {
|
||||
uint8_t* src_ptr = &frame_buffer_display[y * (timing_mode->h_active_pixels >> h_repeat_shift)];
|
||||
if (h_repeat_shift == 2) {
|
||||
for (int i = 0; i < timing_mode->h_active_pixels >> 2; ++i) {
|
||||
uint32_t val = (uint32_t)(*src_ptr++) * 0x01010101;
|
||||
*dst_ptr++ = val;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
for (int i = 0; i < timing_mode->h_active_pixels >> 2; ++i) {
|
||||
uint32_t val = ((uint32_t)(*src_ptr++) * 0x0101);
|
||||
val |= ((uint32_t)(*src_ptr++) * 0x01010000);
|
||||
*dst_ptr++ = val;
|
||||
}
|
||||
}
|
||||
} else if (line_bytes_per_pixel == 4) {
|
||||
uint8_t *src_ptr =
|
||||
&frame_buffer_display[y * (timing_mode->h_active_pixels >>
|
||||
h_repeat_shift)];
|
||||
}
|
||||
else if (line_bytes_per_pixel == 4) {
|
||||
uint8_t* src_ptr = &frame_buffer_display[y * (timing_mode->h_active_pixels >> h_repeat_shift)];
|
||||
if (h_repeat_shift == 2) {
|
||||
for (int i = 0; i < timing_mode->h_active_pixels; i += 4) {
|
||||
uint32_t val = display_palette[*src_ptr++];
|
||||
|
|
@ -193,7 +209,8 @@ void __scratch_x("display") DVHSTX::gfx_dma_handler() {
|
|||
*dst_ptr++ = val;
|
||||
*dst_ptr++ = val;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
for (int i = 0; i < timing_mode->h_active_pixels; i += 2) {
|
||||
uint32_t val = display_palette[*src_ptr++];
|
||||
*dst_ptr++ = val;
|
||||
|
|
@ -224,8 +241,14 @@ uint8_t color_lut[8] = {
|
|||
#define CLUT_R CLUT_ENTRY(1 << 6)
|
||||
#define CLUT_G CLUT_ENTRY(1 << 3)
|
||||
#define CLUT_B CLUT_ENTRY(1 << 0)
|
||||
0, CLUT_R, CLUT_G, CLUT_R | CLUT_G,
|
||||
CLUT_B, CLUT_R | CLUT_B, CLUT_G | CLUT_B, CLUT_R | CLUT_G | CLUT_B,
|
||||
0,
|
||||
CLUT_R,
|
||||
CLUT_G,
|
||||
CLUT_R | CLUT_G,
|
||||
CLUT_B,
|
||||
CLUT_R | CLUT_B,
|
||||
CLUT_G | CLUT_B,
|
||||
CLUT_R | CLUT_G | CLUT_B,
|
||||
#undef CLUT_R
|
||||
#undef CLUT_G
|
||||
#undef CLUT_B
|
||||
|
|
@ -237,11 +260,9 @@ void __scratch_x("display") DVHSTX::text_dma_handler() {
|
|||
// we're about to reload.
|
||||
dma_channel_hw_t *ch = &dma_hw->ch[ch_num];
|
||||
dma_hw->intr = 1u << ch_num;
|
||||
if (++ch_num == NUM_CHANS)
|
||||
ch_num = 0;
|
||||
if (++ch_num == NUM_CHANS) ch_num = 0;
|
||||
|
||||
if (v_scanline >= timing_mode->v_front_porch &&
|
||||
v_scanline < (timing_mode->v_front_porch + timing_mode->v_sync_width)) {
|
||||
if (v_scanline >= timing_mode->v_front_porch && v_scanline < (timing_mode->v_front_porch + timing_mode->v_sync_width)) {
|
||||
ch->read_addr = (uintptr_t)vblank_line_vsync_on;
|
||||
ch->transfer_count = count_of(vblank_line_vsync_on);
|
||||
} else if (v_scanline < v_inactive_total) {
|
||||
|
|
@ -249,9 +270,7 @@ void __scratch_x("display") DVHSTX::text_dma_handler() {
|
|||
ch->transfer_count = count_of(vblank_line_vsync_off);
|
||||
} else {
|
||||
const int y = (v_scanline - v_inactive_total);
|
||||
const uint line_buf_total_len =
|
||||
(frame_width * line_bytes_per_pixel + 3) / 4 +
|
||||
count_of(vactive_text_line_header);
|
||||
const uint line_buf_total_len = (frame_width * line_bytes_per_pixel + 3) / 4 + count_of(vactive_text_line_header);
|
||||
|
||||
ch->read_addr = (uintptr_t)&line_buffers[ch_num * line_buf_total_len];
|
||||
ch->transfer_count = line_buf_total_len;
|
||||
|
|
@ -259,16 +278,15 @@ void __scratch_x("display") DVHSTX::text_dma_handler() {
|
|||
// Fill line buffer
|
||||
int char_y = y % 24;
|
||||
if (line_bytes_per_pixel == 4) {
|
||||
uint32_t *dst_ptr = &line_buffers[ch_num * line_buf_total_len +
|
||||
count_of(vactive_text_line_header)];
|
||||
uint32_t* dst_ptr = &line_buffers[ch_num * line_buf_total_len + count_of(vactive_text_line_header)];
|
||||
uint8_t* src_ptr = &frame_buffer_display[(y / 24) * frame_width];
|
||||
for (int i = 0; i < frame_width; ++i) {
|
||||
*dst_ptr++ = render_char_line(*src_ptr++, char_y);
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
uint8_t* src_ptr = &frame_buffer_display[(y / 24) * frame_width * 2];
|
||||
uint32_t *dst_ptr = &line_buffers[ch_num * line_buf_total_len +
|
||||
count_of(vactive_text_line_header)];
|
||||
uint32_t* dst_ptr = &line_buffers[ch_num * line_buf_total_len + count_of(vactive_text_line_header)];
|
||||
for (int i = 0; i < frame_width; i += 2) {
|
||||
uint32_t tmp_h, tmp_l;
|
||||
|
||||
|
|
@ -278,10 +296,8 @@ void __scratch_x("display") DVHSTX::text_dma_handler() {
|
|||
uint32_t bg = color_lut[(attr >> 3) & 7];
|
||||
uint32_t colour = color_lut[attr & 7] ^ bg;
|
||||
uint32_t bg_xor = bg * 0x3030303;
|
||||
if (attr & ATTR_LOW_INTEN)
|
||||
bits = bits & 0xaaaaaaaa;
|
||||
if ((attr & ATTR_V_LOW_INTEN) == ATTR_V_LOW_INTEN)
|
||||
bits >>= 1;
|
||||
if (attr & ATTR_LOW_INTEN) bits = bits & 0xaaaaaaaa;
|
||||
if ((attr & ATTR_V_LOW_INTEN) == ATTR_V_LOW_INTEN) bits >>= 1;
|
||||
|
||||
*dst_ptr++ = colour * ((bits >> 6) & 0x3030303) ^ bg_xor;
|
||||
*dst_ptr++ = colour * ((bits >> 4) & 0x3030303) ^ bg_xor;
|
||||
|
|
@ -296,10 +312,8 @@ void __scratch_x("display") DVHSTX::text_dma_handler() {
|
|||
c = (*src_ptr++ - 0x20);
|
||||
bits = (c < 95) ? font_cache[c * 24 + char_y] : 0;
|
||||
attr = *src_ptr++;
|
||||
if (attr & ATTR_LOW_INTEN)
|
||||
bits = bits & 0xaaaaaaaa;
|
||||
if ((attr & ATTR_V_LOW_INTEN) == ATTR_V_LOW_INTEN)
|
||||
bits >>= 1;
|
||||
if (attr & ATTR_LOW_INTEN) bits = bits & 0xaaaaaaaa;
|
||||
if ((attr & ATTR_V_LOW_INTEN) == ATTR_V_LOW_INTEN) bits >>= 1;
|
||||
bg = color_lut[(attr >> 3) & 7] ;
|
||||
colour = color_lut[attr & 7] ^ bg;
|
||||
bg_xor = bg * 0x3030303;
|
||||
|
|
@ -317,10 +331,7 @@ void __scratch_x("display") DVHSTX::text_dma_handler() {
|
|||
*dst_ptr++ = tmp_l & 0xffff | (tmp_h << 16);
|
||||
}
|
||||
if (y / 24 == cursor_y) {
|
||||
uint8_t *dst_ptr =
|
||||
(uint8_t *)&line_buffers[ch_num * line_buf_total_len +
|
||||
count_of(vactive_text_line_header)] +
|
||||
14 * cursor_x;
|
||||
uint8_t* dst_ptr = (uint8_t*)&line_buffers[ch_num * line_buf_total_len + count_of(vactive_text_line_header)] + 14 * cursor_x;
|
||||
*dst_ptr++ ^= 0xff;
|
||||
*dst_ptr++ ^= 0xff;
|
||||
*dst_ptr++ ^= 0xff;
|
||||
|
|
@ -355,9 +366,7 @@ void __scratch_x("display") DVHSTX::text_dma_handler() {
|
|||
#ifndef MICROPY_BUILD_TYPE
|
||||
static void __no_inline_not_in_flash_func(set_qmi_timing)() {
|
||||
// Make sure flash is deselected - QMI doesn't appear to have a busy flag(!)
|
||||
while (
|
||||
(ioqspi_hw->io[1].status & IO_QSPI_GPIO_QSPI_SS_STATUS_OUTTOPAD_BITS) !=
|
||||
IO_QSPI_GPIO_QSPI_SS_STATUS_OUTTOPAD_BITS)
|
||||
while ((ioqspi_hw->io[1].status & IO_QSPI_GPIO_QSPI_SS_STATUS_OUTTOPAD_BITS) != IO_QSPI_GPIO_QSPI_SS_STATUS_OUTTOPAD_BITS)
|
||||
;
|
||||
|
||||
qmi_hw->m[0].timing = 0x40000202;
|
||||
|
|
@ -377,19 +386,15 @@ extern "C" void __no_inline_not_in_flash_func(display_setup_clock_preinit)() {
|
|||
// We're going to go fast, boost the voltage a little
|
||||
vreg_set_voltage(VREG_VOLTAGE_1_15);
|
||||
|
||||
// Force a read through XIP to ensure the timing is applied before raising the
|
||||
// clock rate
|
||||
// Force a read through XIP to ensure the timing is applied before raising the clock rate
|
||||
volatile uint32_t* ptr = (volatile uint32_t*)0x14000000;
|
||||
(void) *ptr;
|
||||
|
||||
// Before we touch PLLs, switch sys and ref cleanly away from their aux
|
||||
// sources.
|
||||
// Before we touch PLLs, switch sys and ref cleanly away from their aux sources.
|
||||
hw_clear_bits(&clocks_hw->clk[clk_sys].ctrl, CLOCKS_CLK_SYS_CTRL_SRC_BITS);
|
||||
while (clocks_hw->clk[clk_sys].selected != 0x1)
|
||||
tight_loop_contents();
|
||||
hw_write_masked(&clocks_hw->clk[clk_ref].ctrl,
|
||||
CLOCKS_CLK_REF_CTRL_SRC_VALUE_XOSC_CLKSRC,
|
||||
CLOCKS_CLK_REF_CTRL_SRC_BITS);
|
||||
hw_write_masked(&clocks_hw->clk[clk_ref].ctrl, CLOCKS_CLK_REF_CTRL_SRC_VALUE_XOSC_CLKSRC, CLOCKS_CLK_REF_CTRL_SRC_BITS);
|
||||
while (clocks_hw->clk[clk_ref].selected != 0x4)
|
||||
tight_loop_contents();
|
||||
|
||||
|
|
@ -405,9 +410,10 @@ extern "C" void __no_inline_not_in_flash_func(display_setup_clock_preinit)() {
|
|||
const uint32_t usb_pll_freq = 528 * MHZ;
|
||||
|
||||
// CLK SYS = PLL USB 528MHz / 2 = 264MHz
|
||||
clock_configure(clk_sys, CLOCKS_CLK_SYS_CTRL_SRC_VALUE_CLKSRC_CLK_SYS_AUX,
|
||||
CLOCKS_CLK_SYS_CTRL_AUXSRC_VALUE_CLKSRC_PLL_USB, usb_pll_freq,
|
||||
usb_pll_freq / 2);
|
||||
clock_configure(clk_sys,
|
||||
CLOCKS_CLK_SYS_CTRL_SRC_VALUE_CLKSRC_CLK_SYS_AUX,
|
||||
CLOCKS_CLK_SYS_CTRL_AUXSRC_VALUE_CLKSRC_PLL_USB,
|
||||
usb_pll_freq, usb_pll_freq / 2);
|
||||
|
||||
// CLK PERI = PLL USB 528MHz / 4 = 132MHz
|
||||
clock_configure(clk_peri,
|
||||
|
|
@ -418,13 +424,15 @@ extern "C" void __no_inline_not_in_flash_func(display_setup_clock_preinit)() {
|
|||
// CLK USB = PLL USB 528MHz / 11 = 48MHz
|
||||
clock_configure(clk_usb,
|
||||
0, // No GLMUX
|
||||
CLOCKS_CLK_USB_CTRL_AUXSRC_VALUE_CLKSRC_PLL_USB, usb_pll_freq,
|
||||
CLOCKS_CLK_USB_CTRL_AUXSRC_VALUE_CLKSRC_PLL_USB,
|
||||
usb_pll_freq,
|
||||
USB_CLK_KHZ * KHZ);
|
||||
|
||||
// CLK ADC = PLL USB 528MHz / 11 = 48MHz
|
||||
clock_configure(clk_adc,
|
||||
0, // No GLMUX
|
||||
CLOCKS_CLK_ADC_CTRL_AUXSRC_VALUE_CLKSRC_PLL_USB, usb_pll_freq,
|
||||
CLOCKS_CLK_ADC_CTRL_AUXSRC_VALUE_CLKSRC_PLL_USB,
|
||||
usb_pll_freq,
|
||||
USB_CLK_KHZ * KHZ);
|
||||
|
||||
// Now we are running fast set fast QSPI clock and read delay
|
||||
|
|
@ -441,10 +449,12 @@ extern "C" void __no_inline_not_in_flash_func(display_setup_clock_preinit)() {
|
|||
namespace {
|
||||
class DV_preinit {
|
||||
public:
|
||||
DV_preinit() { display_setup_clock_preinit(); }
|
||||
DV_preinit() {
|
||||
display_setup_clock_preinit();
|
||||
}
|
||||
};
|
||||
DV_preinit dv_preinit __attribute__ ((init_priority (101))) ;
|
||||
} // namespace
|
||||
}
|
||||
#endif
|
||||
|
||||
void DVHSTX::display_setup_clock() {
|
||||
|
|
@ -458,21 +468,26 @@ void DVHSTX::display_setup_clock() {
|
|||
pll_init(pll_sys, PLL_COMMON_REFDIV, vco_freq, post_div1, post_div2);
|
||||
|
||||
// CLK HSTX = Requested freq
|
||||
clock_configure(clk_hstx, 0, CLOCKS_CLK_HSTX_CTRL_AUXSRC_VALUE_CLKSRC_PLL_SYS,
|
||||
clock_configure(clk_hstx,
|
||||
0,
|
||||
CLOCKS_CLK_HSTX_CTRL_AUXSRC_VALUE_CLKSRC_PLL_SYS,
|
||||
freq, freq);
|
||||
}
|
||||
|
||||
RGB888 *DVHSTX::get_palette() { return palette; }
|
||||
RGB888* DVHSTX::get_palette()
|
||||
{
|
||||
return palette;
|
||||
}
|
||||
|
||||
DVHSTX::DVHSTX() {
|
||||
DVHSTX::DVHSTX()
|
||||
{
|
||||
// Always use the bottom channels
|
||||
dma_claim_mask((1 << NUM_CHANS) - 1);
|
||||
}
|
||||
|
||||
bool DVHSTX::init(uint16_t width, uint16_t height, Mode mode_,
|
||||
bool double_buffered, const DVHSTXPinout &pinout) {
|
||||
if (inited)
|
||||
reset();
|
||||
bool DVHSTX::init(uint16_t width, uint16_t height, Mode mode_, bool double_buffered, const DVHSTXPinout &pinout)
|
||||
{
|
||||
if (inited) reset();
|
||||
|
||||
cursor_y = -1;
|
||||
ch_num = 0;
|
||||
|
|
@ -497,19 +512,24 @@ bool DVHSTX::init(uint16_t width, uint16_t height, Mode mode_,
|
|||
h_repeat_shift = 0;
|
||||
v_repeat_shift = 0;
|
||||
timing_mode = &dvi_timing_1280x720p_rb_50hz;
|
||||
} else if (width == 320 && height == 180) {
|
||||
}
|
||||
else if (width == 320 && height == 180) {
|
||||
h_repeat_shift = 2;
|
||||
v_repeat_shift = 2;
|
||||
timing_mode = &dvi_timing_1280x720p_rb_50hz;
|
||||
} else if (width == 640 && height == 360) {
|
||||
}
|
||||
else if (width == 640 && height == 360) {
|
||||
h_repeat_shift = 1;
|
||||
v_repeat_shift = 1;
|
||||
timing_mode = &dvi_timing_1280x720p_rb_50hz;
|
||||
} else if (width == 480 && height == 270) {
|
||||
}
|
||||
else if (width == 480 && height == 270) {
|
||||
h_repeat_shift = 2;
|
||||
v_repeat_shift = 2;
|
||||
timing_mode = &dvi_timing_1920x1080p_rb2_30hz;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
uint16_t full_width = display_width;
|
||||
uint16_t full_height = display_height;
|
||||
h_repeat_shift = 0;
|
||||
|
|
@ -526,28 +546,23 @@ 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 == 720) {
|
||||
if (full_height == 480)
|
||||
timing_mode = &dvi_timing_720x480p_60hz;
|
||||
else if (full_height == 400)
|
||||
timing_mode = &dvi_timing_720x400p_70hz;
|
||||
else if (full_height == 576)
|
||||
timing_mode = &dvi_timing_720x576p_50hz;
|
||||
} else if (full_width == 800) {
|
||||
if (full_height == 600)
|
||||
timing_mode = &dvi_timing_800x600p_60hz;
|
||||
else if (full_height == 480)
|
||||
timing_mode = &dvi_timing_800x480p_60hz;
|
||||
else if (full_height == 450)
|
||||
timing_mode = &dvi_timing_800x450p_60hz;
|
||||
} else if (full_width == 960) {
|
||||
if (full_height == 540)
|
||||
timing_mode = &dvi_timing_960x540p_60hz;
|
||||
} else if (full_width == 1024) {
|
||||
if (full_height == 768)
|
||||
timing_mode = &dvi_timing_1024x768_rb_60hz;
|
||||
if (full_height == 480) timing_mode = &dvi_timing_640x480p_60hz;
|
||||
}
|
||||
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;
|
||||
else if (full_height == 576) timing_mode = &dvi_timing_720x576p_50hz;
|
||||
}
|
||||
else if (full_width == 800) {
|
||||
if (full_height == 600) timing_mode = &dvi_timing_800x600p_60hz;
|
||||
else if (full_height == 480) timing_mode = &dvi_timing_800x480p_60hz;
|
||||
else if (full_height == 450) timing_mode = &dvi_timing_800x450p_60hz;
|
||||
}
|
||||
else if (full_width == 960) {
|
||||
if (full_height == 540) timing_mode = &dvi_timing_960x540p_60hz;
|
||||
}
|
||||
else if (full_width == 1024) {
|
||||
if (full_height == 768) timing_mode = &dvi_timing_1024x768_rb_60hz;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -567,35 +582,28 @@ bool DVHSTX::init(uint16_t width, uint16_t height, Mode mode_,
|
|||
#endif
|
||||
dvhstx_debug("Clock setup done\n");
|
||||
|
||||
v_inactive_total = timing_mode->v_front_porch + timing_mode->v_sync_width +
|
||||
timing_mode->v_back_porch;
|
||||
v_inactive_total = timing_mode->v_front_porch + timing_mode->v_sync_width + timing_mode->v_back_porch;
|
||||
v_total_active_lines = v_inactive_total + timing_mode->v_active_lines;
|
||||
v_repeat = 1 << v_repeat_shift;
|
||||
h_repeat = 1 << h_repeat_shift;
|
||||
|
||||
memcpy(vblank_line_vsync_off, vblank_line_vsync_off_src,
|
||||
sizeof(vblank_line_vsync_off_src));
|
||||
memcpy(vblank_line_vsync_off, vblank_line_vsync_off_src, sizeof(vblank_line_vsync_off_src));
|
||||
vblank_line_vsync_off[0] |= timing_mode->h_front_porch;
|
||||
vblank_line_vsync_off[2] |= timing_mode->h_sync_width;
|
||||
vblank_line_vsync_off[4] |=
|
||||
timing_mode->h_back_porch + timing_mode->h_active_pixels;
|
||||
vblank_line_vsync_off[4] |= timing_mode->h_back_porch + timing_mode->h_active_pixels;
|
||||
|
||||
memcpy(vblank_line_vsync_on, vblank_line_vsync_on_src,
|
||||
sizeof(vblank_line_vsync_on_src));
|
||||
memcpy(vblank_line_vsync_on, vblank_line_vsync_on_src, sizeof(vblank_line_vsync_on_src));
|
||||
vblank_line_vsync_on[0] |= timing_mode->h_front_porch;
|
||||
vblank_line_vsync_on[2] |= timing_mode->h_sync_width;
|
||||
vblank_line_vsync_on[4] |=
|
||||
timing_mode->h_back_porch + timing_mode->h_active_pixels;
|
||||
vblank_line_vsync_on[4] |= timing_mode->h_back_porch + timing_mode->h_active_pixels;
|
||||
|
||||
memcpy(vactive_line_header, vactive_line_header_src,
|
||||
sizeof(vactive_line_header_src));
|
||||
memcpy(vactive_line_header, vactive_line_header_src, sizeof(vactive_line_header_src));
|
||||
vactive_line_header[0] |= timing_mode->h_front_porch;
|
||||
vactive_line_header[2] |= timing_mode->h_sync_width;
|
||||
vactive_line_header[4] |= timing_mode->h_back_porch;
|
||||
vactive_line_header[6] |= timing_mode->h_active_pixels;
|
||||
|
||||
memcpy(vactive_text_line_header, vactive_text_line_header_src,
|
||||
sizeof(vactive_text_line_header_src));
|
||||
memcpy(vactive_text_line_header, vactive_text_line_header_src, sizeof(vactive_text_line_header_src));
|
||||
vactive_text_line_header[0] |= timing_mode->h_front_porch;
|
||||
vactive_text_line_header[2] |= timing_mode->h_sync_width;
|
||||
vactive_text_line_header[4] |= timing_mode->h_back_porch;
|
||||
|
|
@ -628,48 +636,34 @@ bool DVHSTX::init(uint16_t width, uint16_t height, Mode mode_,
|
|||
}
|
||||
|
||||
#ifdef MICROPY_BUILD_TYPE
|
||||
if (frame_width * frame_height * frame_bytes_per_pixel >
|
||||
sizeof(frame_buffer_a)) {
|
||||
if (frame_width * frame_height * frame_bytes_per_pixel > sizeof(frame_buffer_a)) {
|
||||
panic("Frame buffer too large");
|
||||
}
|
||||
|
||||
frame_buffer_display = frame_buffer_a;
|
||||
frame_buffer_back = double_buffered ? frame_buffer_b : frame_buffer_a;
|
||||
#else
|
||||
frame_buffer_display =
|
||||
(uint8_t *)malloc(frame_width * frame_height * frame_bytes_per_pixel);
|
||||
frame_buffer_back = double_buffered
|
||||
? (uint8_t *)malloc(frame_width * frame_height *
|
||||
frame_bytes_per_pixel)
|
||||
: frame_buffer_display;
|
||||
frame_buffer_display = (uint8_t*)malloc(frame_width * frame_height * frame_bytes_per_pixel);
|
||||
frame_buffer_back = double_buffered ? (uint8_t*)malloc(frame_width * frame_height * frame_bytes_per_pixel) : frame_buffer_display;
|
||||
#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(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]));
|
||||
|
||||
frame_buffer_display = frame_buffer_display;
|
||||
dvhstx_debug("Frame buffers inited\n");
|
||||
|
||||
const bool is_text_mode =
|
||||
(mode == MODE_TEXT_MONO || mode == MODE_TEXT_RGB111);
|
||||
const int frame_pixel_words =
|
||||
(frame_width * h_repeat * line_bytes_per_pixel + 3) >> 2;
|
||||
const int frame_line_words =
|
||||
frame_pixel_words + (is_text_mode ? count_of(vactive_text_line_header)
|
||||
: count_of(vactive_line_header));
|
||||
const bool is_text_mode = (mode == MODE_TEXT_MONO || mode == MODE_TEXT_RGB111);
|
||||
const int frame_pixel_words = (frame_width * h_repeat * line_bytes_per_pixel + 3) >> 2;
|
||||
const int frame_line_words = frame_pixel_words + (is_text_mode ? count_of(vactive_text_line_header) : count_of(vactive_line_header));
|
||||
const int frame_lines = (v_repeat == 1) ? NUM_CHANS : NUM_FRAME_LINES;
|
||||
line_buffers = (uint32_t*)malloc(frame_line_words * 4 * frame_lines);
|
||||
|
||||
for (int i = 0; i < frame_lines; ++i) {
|
||||
if (is_text_mode)
|
||||
memcpy(&line_buffers[i * frame_line_words], vactive_text_line_header,
|
||||
count_of(vactive_text_line_header) * sizeof(uint32_t));
|
||||
else
|
||||
memcpy(&line_buffers[i * frame_line_words], vactive_line_header,
|
||||
count_of(vactive_line_header) * sizeof(uint32_t));
|
||||
for (int i = 0; i < frame_lines; ++i)
|
||||
{
|
||||
if (is_text_mode) memcpy(&line_buffers[i * frame_line_words], vactive_text_line_header, count_of(vactive_text_line_header) * sizeof(uint32_t));
|
||||
else memcpy(&line_buffers[i * frame_line_words], vactive_line_header, count_of(vactive_line_header) * sizeof(uint32_t));
|
||||
}
|
||||
|
||||
if (mode == MODE_TEXT_RGB111) {
|
||||
|
|
@ -677,10 +671,22 @@ bool DVHSTX::init(uint16_t width, uint16_t height, Mode mode_,
|
|||
auto take = [b](int shift1, int shift2) {
|
||||
return ((b >> shift1) & 3) << shift2;
|
||||
};
|
||||
return take(0, 0) | take(2, 26) | take(4, 18) | take(6, 10) | take(8, 2) |
|
||||
take(10, 28) | take(12, 20) | take(14, 12) | take(16, 4) |
|
||||
take(18, 30) | take(20, 22) | take(22, 14) | take(24, 6) |
|
||||
return
|
||||
take( 0, 0) |
|
||||
take( 2, 26) |
|
||||
take( 4, 18) |
|
||||
take( 6, 10) |
|
||||
take( 8, 2) |
|
||||
take(10, 28) |
|
||||
take(12, 20) |
|
||||
take(14, 12) |
|
||||
take(16, 4) |
|
||||
take(18, 30) |
|
||||
take(20, 22) |
|
||||
take(22, 14) |
|
||||
take(24, 6) |
|
||||
take(26, 28);
|
||||
|
||||
};
|
||||
// Need to pre-render the font to RAM to be fast enough.
|
||||
font_cache = (uint32_t*)malloc(4 * FONT->line_height * 96);
|
||||
|
|
@ -701,7 +707,8 @@ bool DVHSTX::init(uint16_t width, uint16_t height, Mode mode_,
|
|||
switch (mode) {
|
||||
case MODE_RGB565:
|
||||
// Configure HSTX's TMDS encoder for RGB565
|
||||
hstx_ctrl_hw->expand_tmds = 4 << HSTX_CTRL_EXPAND_TMDS_L2_NBITS_LSB |
|
||||
hstx_ctrl_hw->expand_tmds =
|
||||
4 << HSTX_CTRL_EXPAND_TMDS_L2_NBITS_LSB |
|
||||
8 << HSTX_CTRL_EXPAND_TMDS_L2_ROT_LSB |
|
||||
5 << HSTX_CTRL_EXPAND_TMDS_L1_NBITS_LSB |
|
||||
3 << HSTX_CTRL_EXPAND_TMDS_L1_ROT_LSB |
|
||||
|
|
@ -710,7 +717,8 @@ bool DVHSTX::init(uint16_t width, uint16_t height, Mode mode_,
|
|||
|
||||
// Pixels (TMDS) come in 2 16-bit chunks. Control symbols (RAW) are an
|
||||
// entire 32-bit word.
|
||||
hstx_ctrl_hw->expand_shift = 2 << HSTX_CTRL_EXPAND_SHIFT_ENC_N_SHIFTS_LSB |
|
||||
hstx_ctrl_hw->expand_shift =
|
||||
2 << HSTX_CTRL_EXPAND_SHIFT_ENC_N_SHIFTS_LSB |
|
||||
16 << HSTX_CTRL_EXPAND_SHIFT_ENC_SHIFT_LSB |
|
||||
1 << HSTX_CTRL_EXPAND_SHIFT_RAW_N_SHIFTS_LSB |
|
||||
0 << HSTX_CTRL_EXPAND_SHIFT_RAW_SHIFT_LSB;
|
||||
|
|
@ -718,7 +726,8 @@ bool DVHSTX::init(uint16_t width, uint16_t height, Mode mode_,
|
|||
|
||||
case MODE_PALETTE:
|
||||
// Configure HSTX's TMDS encoder for RGB888
|
||||
hstx_ctrl_hw->expand_tmds = 7 << HSTX_CTRL_EXPAND_TMDS_L2_NBITS_LSB |
|
||||
hstx_ctrl_hw->expand_tmds =
|
||||
7 << HSTX_CTRL_EXPAND_TMDS_L2_NBITS_LSB |
|
||||
16 << HSTX_CTRL_EXPAND_TMDS_L2_ROT_LSB |
|
||||
7 << HSTX_CTRL_EXPAND_TMDS_L1_NBITS_LSB |
|
||||
8 << HSTX_CTRL_EXPAND_TMDS_L1_ROT_LSB |
|
||||
|
|
@ -727,7 +736,8 @@ bool DVHSTX::init(uint16_t width, uint16_t height, Mode mode_,
|
|||
|
||||
// Pixels and control symbols (RAW) are an
|
||||
// entire 32-bit word.
|
||||
hstx_ctrl_hw->expand_shift = 1 << HSTX_CTRL_EXPAND_SHIFT_ENC_N_SHIFTS_LSB |
|
||||
hstx_ctrl_hw->expand_shift =
|
||||
1 << HSTX_CTRL_EXPAND_SHIFT_ENC_N_SHIFTS_LSB |
|
||||
0 << HSTX_CTRL_EXPAND_SHIFT_ENC_SHIFT_LSB |
|
||||
1 << HSTX_CTRL_EXPAND_SHIFT_RAW_N_SHIFTS_LSB |
|
||||
0 << HSTX_CTRL_EXPAND_SHIFT_RAW_SHIFT_LSB;
|
||||
|
|
@ -735,7 +745,8 @@ bool DVHSTX::init(uint16_t width, uint16_t height, Mode mode_,
|
|||
|
||||
case MODE_TEXT_MONO:
|
||||
// Configure HSTX's TMDS encoder for 2bpp
|
||||
hstx_ctrl_hw->expand_tmds = 1 << HSTX_CTRL_EXPAND_TMDS_L2_NBITS_LSB |
|
||||
hstx_ctrl_hw->expand_tmds =
|
||||
1 << HSTX_CTRL_EXPAND_TMDS_L2_NBITS_LSB |
|
||||
18 << HSTX_CTRL_EXPAND_TMDS_L2_ROT_LSB |
|
||||
1 << HSTX_CTRL_EXPAND_TMDS_L1_NBITS_LSB |
|
||||
18 << HSTX_CTRL_EXPAND_TMDS_L1_ROT_LSB |
|
||||
|
|
@ -744,7 +755,8 @@ bool DVHSTX::init(uint16_t width, uint16_t height, Mode mode_,
|
|||
|
||||
// Pixels and control symbols (RAW) are an
|
||||
// entire 32-bit word.
|
||||
hstx_ctrl_hw->expand_shift = 14 << HSTX_CTRL_EXPAND_SHIFT_ENC_N_SHIFTS_LSB |
|
||||
hstx_ctrl_hw->expand_shift =
|
||||
14 << HSTX_CTRL_EXPAND_SHIFT_ENC_N_SHIFTS_LSB |
|
||||
30 << HSTX_CTRL_EXPAND_SHIFT_ENC_SHIFT_LSB |
|
||||
1 << HSTX_CTRL_EXPAND_SHIFT_RAW_N_SHIFTS_LSB |
|
||||
0 << HSTX_CTRL_EXPAND_SHIFT_RAW_SHIFT_LSB;
|
||||
|
|
@ -752,7 +764,8 @@ bool DVHSTX::init(uint16_t width, uint16_t height, Mode mode_,
|
|||
|
||||
case MODE_TEXT_RGB111:
|
||||
// Configure HSTX's TMDS encoder for RGB222
|
||||
hstx_ctrl_hw->expand_tmds = 1 << HSTX_CTRL_EXPAND_TMDS_L2_NBITS_LSB |
|
||||
hstx_ctrl_hw->expand_tmds =
|
||||
1 << HSTX_CTRL_EXPAND_TMDS_L2_NBITS_LSB |
|
||||
0 << HSTX_CTRL_EXPAND_TMDS_L2_ROT_LSB |
|
||||
1 << HSTX_CTRL_EXPAND_TMDS_L1_NBITS_LSB |
|
||||
29 << HSTX_CTRL_EXPAND_TMDS_L1_ROT_LSB |
|
||||
|
|
@ -761,7 +774,8 @@ bool DVHSTX::init(uint16_t width, uint16_t height, Mode mode_,
|
|||
|
||||
// Pixels (TMDS) come in 4 8-bit chunks. Control symbols (RAW) are an
|
||||
// entire 32-bit word.
|
||||
hstx_ctrl_hw->expand_shift = 4 << HSTX_CTRL_EXPAND_SHIFT_ENC_N_SHIFTS_LSB |
|
||||
hstx_ctrl_hw->expand_shift =
|
||||
4 << HSTX_CTRL_EXPAND_SHIFT_ENC_N_SHIFTS_LSB |
|
||||
8 << HSTX_CTRL_EXPAND_SHIFT_ENC_SHIFT_LSB |
|
||||
1 << HSTX_CTRL_EXPAND_SHIFT_RAW_N_SHIFTS_LSB |
|
||||
0 << HSTX_CTRL_EXPAND_SHIFT_RAW_SHIFT_LSB;
|
||||
|
|
@ -775,29 +789,30 @@ bool DVHSTX::init(uint16_t width, uint16_t height, Mode mode_,
|
|||
// Serial output config: clock period of 5 cycles, pop from command
|
||||
// expander every 5 cycles, shift the output shiftreg by 2 every cycle.
|
||||
hstx_ctrl_hw->csr = 0;
|
||||
hstx_ctrl_hw->csr = HSTX_CTRL_CSR_EXPAND_EN_BITS |
|
||||
hstx_ctrl_hw->csr =
|
||||
HSTX_CTRL_CSR_EXPAND_EN_BITS |
|
||||
5u << HSTX_CTRL_CSR_CLKDIV_LSB |
|
||||
5u << HSTX_CTRL_CSR_N_SHIFTS_LSB |
|
||||
2u << HSTX_CTRL_CSR_SHIFT_LSB | HSTX_CTRL_CSR_EN_BITS;
|
||||
2u << HSTX_CTRL_CSR_SHIFT_LSB |
|
||||
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[(pinout.clk_p ) - HSTX_FIRST_PIN] = HSTX_CTRL_BIT0_CLK_BITS;
|
||||
hstx_ctrl_hw->bit[(pinout.clk_p ^ 1) - HSTX_FIRST_PIN] =
|
||||
HSTX_CTRL_BIT0_CLK_BITS | HSTX_CTRL_BIT0_INV_BITS;
|
||||
hstx_ctrl_hw->bit[(pinout.clk_p ^ 1) - HSTX_FIRST_PIN] = 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:
|
||||
int bit = pinout.rgb_p[lane];
|
||||
// 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 |
|
||||
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 ) - HSTX_FIRST_PIN] = lane_data_sel_bits;
|
||||
hstx_ctrl_hw->bit[(bit ^ 1) - HSTX_FIRST_PIN] =
|
||||
lane_data_sel_bits | HSTX_CTRL_BIT0_INV_BITS;
|
||||
hstx_ctrl_hw->bit[(bit ^ 1) - HSTX_FIRST_PIN] = lane_data_sel_bits | HSTX_CTRL_BIT0_INV_BITS;
|
||||
}
|
||||
|
||||
for (int i = 12; i <= 19; ++i) {
|
||||
|
|
@ -816,19 +831,37 @@ bool DVHSTX::init(uint16_t width, uint16_t height, Mode mode_,
|
|||
c = dma_channel_get_default_config(0);
|
||||
channel_config_set_chain_to(&c, 1);
|
||||
channel_config_set_dreq(&c, DREQ_HSTX);
|
||||
dma_channel_configure(0, &c, &hstx_fifo_hw->fifo, vblank_line_vsync_off,
|
||||
count_of(vblank_line_vsync_off), false);
|
||||
dma_channel_configure(
|
||||
0,
|
||||
&c,
|
||||
&hstx_fifo_hw->fifo,
|
||||
vblank_line_vsync_off,
|
||||
count_of(vblank_line_vsync_off),
|
||||
false
|
||||
);
|
||||
c = dma_channel_get_default_config(1);
|
||||
channel_config_set_chain_to(&c, 2);
|
||||
channel_config_set_dreq(&c, DREQ_HSTX);
|
||||
dma_channel_configure(1, &c, &hstx_fifo_hw->fifo, vblank_line_vsync_off,
|
||||
count_of(vblank_line_vsync_off), false);
|
||||
dma_channel_configure(
|
||||
1,
|
||||
&c,
|
||||
&hstx_fifo_hw->fifo,
|
||||
vblank_line_vsync_off,
|
||||
count_of(vblank_line_vsync_off),
|
||||
false
|
||||
);
|
||||
for (int i = 2; i < NUM_CHANS; ++i) {
|
||||
c = dma_channel_get_default_config(i);
|
||||
channel_config_set_chain_to(&c, (i+1) % NUM_CHANS);
|
||||
channel_config_set_dreq(&c, DREQ_HSTX);
|
||||
dma_channel_configure(i, &c, &hstx_fifo_hw->fifo, vblank_line_vsync_off,
|
||||
count_of(vblank_line_vsync_off), false);
|
||||
dma_channel_configure(
|
||||
i,
|
||||
&c,
|
||||
&hstx_fifo_hw->fifo,
|
||||
vblank_line_vsync_off,
|
||||
count_of(vblank_line_vsync_off),
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
dvhstx_debug("DMA channels claimed\n");
|
||||
|
|
@ -836,10 +869,8 @@ bool DVHSTX::init(uint16_t width, uint16_t height, Mode mode_,
|
|||
dma_hw->intr = (1 << NUM_CHANS) - 1;
|
||||
dma_hw->ints2 = (1 << NUM_CHANS) - 1;
|
||||
dma_hw->inte2 = (1 << NUM_CHANS) - 1;
|
||||
if (is_text_mode)
|
||||
irq_set_exclusive_handler(DMA_IRQ_2, dma_irq_handler_text);
|
||||
else
|
||||
irq_set_exclusive_handler(DMA_IRQ_2, dma_irq_handler);
|
||||
if (is_text_mode) irq_set_exclusive_handler(DMA_IRQ_2, dma_irq_handler_text);
|
||||
else irq_set_exclusive_handler(DMA_IRQ_2, dma_irq_handler);
|
||||
irq_set_priority(DMA_IRQ_2, PICO_HIGHEST_IRQ_PRIORITY);
|
||||
irq_set_enabled(DMA_IRQ_2, true);
|
||||
|
||||
|
|
@ -852,8 +883,7 @@ bool DVHSTX::init(uint16_t width, uint16_t height, Mode mode_,
|
|||
}
|
||||
|
||||
void DVHSTX::reset() {
|
||||
if (!inited)
|
||||
return;
|
||||
if (!inited) return;
|
||||
inited = false;
|
||||
|
||||
hstx_ctrl_hw->csr = 0;
|
||||
|
|
@ -894,8 +924,7 @@ void DVHSTX::flip_now() {
|
|||
}
|
||||
|
||||
void DVHSTX::wait_for_vsync() {
|
||||
while (v_scanline >= timing_mode->v_front_porch)
|
||||
__wfe();
|
||||
while (v_scanline >= timing_mode->v_front_porch) __wfe();
|
||||
}
|
||||
|
||||
void DVHSTX::flip_async() {
|
||||
|
|
@ -907,6 +936,5 @@ void DVHSTX::flip_async() {
|
|||
void DVHSTX::wait_for_flip() {
|
||||
if (get_single_buffered())
|
||||
return;
|
||||
while (flip_next)
|
||||
__wfe();
|
||||
while (flip_next) __wfe();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
#include <string.h>
|
||||
|
||||
#include "hardware/gpio.h"
|
||||
#include "pico/stdlib.h"
|
||||
#include "hardware/gpio.h"
|
||||
|
||||
// DVI HSTX driver for use with Pimoroni PicoGraphics
|
||||
|
||||
|
|
@ -17,24 +17,22 @@ typedef uint32_t RGB888;
|
|||
|
||||
// Digital Video using HSTX
|
||||
// Valid screen modes are:
|
||||
// Pixel doubled: 640x480 (60Hz), 720x480 (60Hz), 720x400 (70Hz), 720x576
|
||||
// (50Hz),
|
||||
// 800x600 (60Hz), 800x480 (60Hz), 800x450 (60Hz), 960x540
|
||||
// (60Hz), 1024x768 (60Hz)
|
||||
// Pixel doubled: 640x480 (60Hz), 720x480 (60Hz), 720x400 (70Hz), 720x576 (50Hz),
|
||||
// 800x600 (60Hz), 800x480 (60Hz), 800x450 (60Hz), 960x540 (60Hz), 1024x768 (60Hz)
|
||||
// Pixel doubled or quadrupled: 1280x720 (50Hz)
|
||||
//
|
||||
// Giving valid resolutions:
|
||||
// 320x180, 640x360 (well supported, square pixels on a 16:9 display)
|
||||
// 480x270, 400x225 (sometimes supported, square pixels on a 16:9 display)
|
||||
// 320x240, 360x240, 360x200, 360x288, 400x300, 512x384 (well supported, but
|
||||
// pixels aren't square) 400x240 (sometimes supported, pixels aren't square)
|
||||
// 320x240, 360x240, 360x200, 360x288, 400x300, 512x384 (well supported, but pixels aren't square)
|
||||
// 400x240 (sometimes supported, pixels aren't square)
|
||||
//
|
||||
// Note that the double buffer is in RAM, so 640x360 uses almost all of the
|
||||
// available RAM.
|
||||
// Note that the double buffer is in RAM, so 640x360 uses almost all of the available RAM.
|
||||
class DVHSTX {
|
||||
public:
|
||||
static constexpr int PALETTE_SIZE = 256;
|
||||
|
||||
|
||||
enum Mode {
|
||||
MODE_PALETTE = 2,
|
||||
MODE_RGB565 = 1,
|
||||
|
|
@ -89,25 +87,20 @@ public:
|
|||
// Methods
|
||||
//--------------------------------------------------
|
||||
public:
|
||||
bool get_single_buffered() {
|
||||
return frame_buffer_display && frame_buffer_display == frame_buffer_back;
|
||||
}
|
||||
bool get_double_buffered() {
|
||||
return frame_buffer_display && frame_buffer_display != frame_buffer_back;
|
||||
}
|
||||
bool get_single_buffered() { return frame_buffer_display && frame_buffer_display == frame_buffer_back; }
|
||||
bool get_double_buffered() { return frame_buffer_display && frame_buffer_display != frame_buffer_back; }
|
||||
|
||||
template <class T> T *get_back_buffer() { return (T *)(frame_buffer_back); }
|
||||
template <class T> T *get_front_buffer() {
|
||||
return (T *)(frame_buffer_display);
|
||||
}
|
||||
template<class T>
|
||||
T *get_back_buffer() { return (T*)(frame_buffer_back); }
|
||||
template<class T>
|
||||
T *get_front_buffer() { return (T*)(frame_buffer_display); }
|
||||
|
||||
uint16_t get_width() const { return frame_width; }
|
||||
uint16_t get_height() const { return frame_height; }
|
||||
|
||||
RGB888* get_palette();
|
||||
|
||||
bool init(uint16_t width, uint16_t height, Mode mode, bool double_buffered,
|
||||
const DVHSTXPinout &pinout);
|
||||
bool init(uint16_t width, uint16_t height, Mode mode, bool double_buffered, const DVHSTXPinout &pinout);
|
||||
void reset();
|
||||
|
||||
// Wait for vsync and then flip the buffers
|
||||
|
|
@ -119,8 +112,7 @@ public:
|
|||
void wait_for_vsync();
|
||||
|
||||
// flip_async queues a flip to happen next vsync but returns without blocking.
|
||||
// You should call wait_for_flip before doing any more reads or writes,
|
||||
// defining sprites, etc.
|
||||
// You should call wait_for_flip before doing any more reads or writes, defining sprites, etc.
|
||||
void flip_async();
|
||||
void wait_for_flip();
|
||||
|
||||
|
|
@ -128,10 +120,7 @@ public:
|
|||
void gfx_dma_handler();
|
||||
void text_dma_handler();
|
||||
|
||||
void set_cursor(int x, int y) {
|
||||
cursor_x = x;
|
||||
cursor_y = y;
|
||||
}
|
||||
void set_cursor(int x, int y) { cursor_x = x; cursor_y = y; }
|
||||
void cursor_off(void) { cursor_y = -1; }
|
||||
|
||||
private:
|
||||
|
|
@ -165,4 +154,4 @@ private:
|
|||
|
||||
int cursor_x, cursor_y;
|
||||
};
|
||||
} // namespace pimoroni
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,8 @@
|
|||
#include "dvi.hpp"
|
||||
|
||||
// VGA -- we do this mode properly, with a pretty comfortable clk_sys (252 MHz)
|
||||
const struct dvi_timing dvi_timing_640x480p_60hz = {.h_sync_polarity = false,
|
||||
const struct dvi_timing dvi_timing_640x480p_60hz = {
|
||||
.h_sync_polarity = false,
|
||||
.h_front_porch = 16,
|
||||
.h_sync_width = 96,
|
||||
.h_back_porch = 48,
|
||||
|
|
@ -15,10 +16,12 @@ const struct dvi_timing dvi_timing_640x480p_60hz = {.h_sync_polarity = false,
|
|||
.v_back_porch = 33,
|
||||
.v_active_lines = 480,
|
||||
|
||||
.bit_clk_khz = 252000};
|
||||
.bit_clk_khz = 252000
|
||||
};
|
||||
|
||||
// SVGA -- completely by-the-book but requires 400 MHz clk_sys
|
||||
const struct dvi_timing dvi_timing_800x600p_60hz = {.h_sync_polarity = false,
|
||||
const struct dvi_timing dvi_timing_800x600p_60hz = {
|
||||
.h_sync_polarity = false,
|
||||
.h_front_porch = 44,
|
||||
.h_sync_width = 128,
|
||||
.h_back_porch = 88,
|
||||
|
|
@ -30,10 +33,12 @@ const struct dvi_timing dvi_timing_800x600p_60hz = {.h_sync_polarity = false,
|
|||
.v_back_porch = 23,
|
||||
.v_active_lines = 600,
|
||||
|
||||
.bit_clk_khz = 400000};
|
||||
.bit_clk_khz = 400000
|
||||
};
|
||||
|
||||
// 720x480 - timings from dumping the EDID of my monitor
|
||||
const struct dvi_timing dvi_timing_720x480p_60hz = {.h_sync_polarity = false,
|
||||
const struct dvi_timing dvi_timing_720x480p_60hz = {
|
||||
.h_sync_polarity = false,
|
||||
.h_front_porch = 16,
|
||||
.h_sync_width = 62,
|
||||
.h_back_porch = 60,
|
||||
|
|
@ -45,10 +50,12 @@ const struct dvi_timing dvi_timing_720x480p_60hz = {.h_sync_polarity = false,
|
|||
.v_back_porch = 30,
|
||||
.v_active_lines = 480,
|
||||
|
||||
.bit_clk_khz = 270000};
|
||||
.bit_clk_khz = 270000
|
||||
};
|
||||
|
||||
// 720x576@50Hz - CEA timing
|
||||
const struct dvi_timing dvi_timing_720x576p_50hz = {.h_sync_polarity = false,
|
||||
const struct dvi_timing dvi_timing_720x576p_50hz = {
|
||||
.h_sync_polarity = false,
|
||||
.h_front_porch = 12,
|
||||
.h_sync_width = 64,
|
||||
.h_back_porch = 68,
|
||||
|
|
@ -60,10 +67,12 @@ const struct dvi_timing dvi_timing_720x576p_50hz = {.h_sync_polarity = false,
|
|||
.v_back_porch = 39,
|
||||
.v_active_lines = 576,
|
||||
|
||||
.bit_clk_khz = 270000};
|
||||
.bit_clk_khz = 270000
|
||||
};
|
||||
|
||||
// 720x400@70Hz - "IBM" timing
|
||||
const struct dvi_timing dvi_timing_720x400p_70hz = {.h_sync_polarity = false,
|
||||
const struct dvi_timing dvi_timing_720x400p_70hz = {
|
||||
.h_sync_polarity = false,
|
||||
.h_front_porch = 18,
|
||||
.h_sync_width = 108,
|
||||
.h_back_porch = 54,
|
||||
|
|
@ -75,11 +84,13 @@ const struct dvi_timing dvi_timing_720x400p_70hz = {.h_sync_polarity = false,
|
|||
.v_back_porch = 34,
|
||||
.v_active_lines = 400,
|
||||
|
||||
.bit_clk_khz = 283200};
|
||||
.bit_clk_khz = 283200
|
||||
};
|
||||
|
||||
// 800x480p 60 Hz (note this doesn't seem to be a CEA mode, I just used the
|
||||
// output of `cvt 800 480 60`), 295 MHz bit clock
|
||||
const struct dvi_timing dvi_timing_800x480p_60hz = {.h_sync_polarity = false,
|
||||
const struct dvi_timing dvi_timing_800x480p_60hz = {
|
||||
.h_sync_polarity = false,
|
||||
.h_front_porch = 24,
|
||||
.h_sync_width = 72,
|
||||
.h_back_porch = 96,
|
||||
|
|
@ -91,10 +102,12 @@ const struct dvi_timing dvi_timing_800x480p_60hz = {.h_sync_polarity = false,
|
|||
.v_back_porch = 7,
|
||||
.v_active_lines = 480,
|
||||
|
||||
.bit_clk_khz = 295200};
|
||||
.bit_clk_khz = 295200
|
||||
};
|
||||
|
||||
// 800x450p 60 Hz Similarly not a CEA mode, but is 16:9
|
||||
const struct dvi_timing dvi_timing_800x450p_60hz = {.h_sync_polarity = false,
|
||||
const struct dvi_timing dvi_timing_800x450p_60hz = {
|
||||
.h_sync_polarity = false,
|
||||
.h_front_porch = 24,
|
||||
.h_sync_width = 72,
|
||||
.h_back_porch = 96,
|
||||
|
|
@ -106,7 +119,8 @@ const struct dvi_timing dvi_timing_800x450p_60hz = {.h_sync_polarity = false,
|
|||
.v_back_porch = 10,
|
||||
.v_active_lines = 450,
|
||||
|
||||
.bit_clk_khz = 278400};
|
||||
.bit_clk_khz = 278400
|
||||
};
|
||||
|
||||
// SVGA reduced blanking (355 MHz bit clock) -- valid CVT mode, less common
|
||||
// than fully-blanked SVGA, but doesn't require such a high system clock
|
||||
|
|
@ -123,11 +137,13 @@ const struct dvi_timing dvi_timing_800x600p_reduced_60hz = {
|
|||
.v_back_porch = 11,
|
||||
.v_active_lines = 600,
|
||||
|
||||
.bit_clk_khz = 354000};
|
||||
.bit_clk_khz = 354000
|
||||
};
|
||||
|
||||
// Also known as qHD, bit uncommon, but it's a nice modest-resolution 16:9
|
||||
// aspect mode. Pixel clock 40.75 MHz for full CVT mode (no reduced blanking)
|
||||
const struct dvi_timing dvi_timing_960x540p_60hz = {.h_sync_polarity = false,
|
||||
const struct dvi_timing dvi_timing_960x540p_60hz = {
|
||||
.h_sync_polarity = false,
|
||||
.h_front_porch = 32,
|
||||
.h_sync_width = 96,
|
||||
.h_back_porch = 128,
|
||||
|
|
@ -139,11 +155,13 @@ const struct dvi_timing dvi_timing_960x540p_60hz = {.h_sync_polarity = false,
|
|||
.v_back_porch = 14,
|
||||
.v_active_lines = 540,
|
||||
|
||||
.bit_clk_khz = 408000};
|
||||
.bit_clk_khz = 408000
|
||||
};
|
||||
|
||||
// Also known as qHD, bit uncommon, but it's a nice modest-resolution 16:9
|
||||
// aspect mode. Pixel clock 33.5 MHz for 50Hz CVT mode (no reduced blanking)
|
||||
const struct dvi_timing dvi_timing_960x540p_50hz = {.h_sync_polarity = false,
|
||||
const struct dvi_timing dvi_timing_960x540p_50hz = {
|
||||
.h_sync_polarity = false,
|
||||
.h_front_porch = 24,
|
||||
.h_sync_width = 96,
|
||||
.h_back_porch = 120,
|
||||
|
|
@ -155,10 +173,12 @@ const struct dvi_timing dvi_timing_960x540p_50hz = {.h_sync_polarity = false,
|
|||
.v_back_porch = 11,
|
||||
.v_active_lines = 540,
|
||||
|
||||
.bit_clk_khz = 336000};
|
||||
.bit_clk_khz = 336000
|
||||
};
|
||||
|
||||
// 1024x768, CVT-RB
|
||||
const struct dvi_timing dvi_timing_1024x768_rb_60hz = {.h_sync_polarity = true,
|
||||
const struct dvi_timing dvi_timing_1024x768_rb_60hz = {
|
||||
.h_sync_polarity = true,
|
||||
.h_front_porch = 48,
|
||||
.h_sync_width = 32,
|
||||
.h_back_porch = 80,
|
||||
|
|
@ -170,44 +190,47 @@ const struct dvi_timing dvi_timing_1024x768_rb_60hz = {.h_sync_polarity = true,
|
|||
.v_back_porch = 15,
|
||||
.v_active_lines = 768,
|
||||
|
||||
.bit_clk_khz = 560000};
|
||||
.bit_clk_khz = 560000
|
||||
};
|
||||
|
||||
// 720p50, this is a standard HD mode, the CVT-RB variant
|
||||
// should be widely supported
|
||||
const struct dvi_timing dvi_timing_1280x720p_rb_50hz = {.h_sync_polarity = true,
|
||||
const struct dvi_timing dvi_timing_1280x720p_rb_50hz = {
|
||||
.h_sync_polarity = true,
|
||||
.h_front_porch = 48,
|
||||
.h_sync_width = 32,
|
||||
.h_back_porch = 80,
|
||||
.h_active_pixels = 1280,
|
||||
|
||||
.v_sync_polarity =
|
||||
false,
|
||||
.v_sync_polarity = false,
|
||||
.v_front_porch = 3,
|
||||
.v_sync_width = 5,
|
||||
.v_back_porch = 9,
|
||||
.v_active_lines = 720,
|
||||
|
||||
.bit_clk_khz = 528000};
|
||||
.bit_clk_khz = 528000
|
||||
};
|
||||
|
||||
// 720p60, this is the CVT-RB variant, again should be widely supported
|
||||
const struct dvi_timing dvi_timing_1280x720p_rb_60hz = {.h_sync_polarity = true,
|
||||
const struct dvi_timing dvi_timing_1280x720p_rb_60hz = {
|
||||
.h_sync_polarity = true,
|
||||
.h_front_porch = 48,
|
||||
.h_sync_width = 32,
|
||||
.h_back_porch = 80,
|
||||
.h_active_pixels = 1280,
|
||||
|
||||
.v_sync_polarity =
|
||||
false,
|
||||
.v_sync_polarity = false,
|
||||
.v_front_porch = 3,
|
||||
.v_sync_width = 5,
|
||||
.v_back_porch = 13,
|
||||
.v_active_lines = 720,
|
||||
|
||||
.bit_clk_khz = 640000};
|
||||
.bit_clk_khz = 640000
|
||||
};
|
||||
|
||||
// 1080p30 - not a normal mode but seems to work on a wide variety of hardware
|
||||
// Strictly speaking RB2 should have a clock speed matching the target frequency
|
||||
// more closely but it seems to work!
|
||||
// Strictly speaking RB2 should have a clock speed matching the target frequency more closely
|
||||
// but it seems to work!
|
||||
const struct dvi_timing dvi_timing_1920x1080p_rb2_30hz = {
|
||||
.h_sync_polarity = true,
|
||||
.h_front_porch = 8,
|
||||
|
|
@ -221,10 +244,10 @@ const struct dvi_timing dvi_timing_1920x1080p_rb2_30hz = {
|
|||
.v_back_porch = 6,
|
||||
.v_active_lines = 1080,
|
||||
|
||||
.bit_clk_khz = 660000};
|
||||
.bit_clk_khz = 660000
|
||||
};
|
||||
|
||||
// 1440p24 YOLO - works on my Dell Ultrasharp, that most forgiving of monitors.
|
||||
// May require a little more than 1.3V
|
||||
// 1440p24 YOLO - works on my Dell Ultrasharp, that most forgiving of monitors. May require a little more than 1.3V
|
||||
const struct dvi_timing dvi_timing_2560x1440p_yolo_24hz = {
|
||||
.h_sync_polarity = true,
|
||||
.h_front_porch = 8,
|
||||
|
|
@ -238,4 +261,5 @@ const struct dvi_timing dvi_timing_2560x1440p_yolo_24hz = {
|
|||
.v_back_porch = 2,
|
||||
.v_active_lines = 1440,
|
||||
|
||||
.bit_clk_khz = 912000};
|
||||
.bit_clk_khz = 912000
|
||||
};
|
||||
|
|
|
|||
|
|
@ -18,14 +18,10 @@
|
|||
#define SYNC_V0_H1 (TMDS_CTRL_01 | (TMDS_CTRL_00 << 10) | (TMDS_CTRL_00 << 20))
|
||||
#define SYNC_V1_H0 (TMDS_CTRL_10 | (TMDS_CTRL_00 << 10) | (TMDS_CTRL_00 << 20))
|
||||
#define SYNC_V1_H1 (TMDS_CTRL_11 | (TMDS_CTRL_00 << 10) | (TMDS_CTRL_00 << 20))
|
||||
#define MISSING_PIXEL \
|
||||
(TMDS_BALANCED_LOW | (TMDS_BALANCED_LOW << 10) | (TMDS_BALANCED_HIGH << 20))
|
||||
#define BLACK_PIXEL \
|
||||
(TMDS_BALANCED_LOW | (TMDS_BALANCED_LOW << 10) | (TMDS_BALANCED_LOW << 20))
|
||||
#define BLACK_PIXEL_A \
|
||||
(TMDS_BLACK_A | (TMDS_BLACK_A << 10) | (TMDS_BLACK_A << 20))
|
||||
#define BLACK_PIXEL_B \
|
||||
(TMDS_BLACK_B | (TMDS_BLACK_B << 10) | (TMDS_BLACK_B << 20))
|
||||
#define MISSING_PIXEL (TMDS_BALANCED_LOW | (TMDS_BALANCED_LOW << 10) | (TMDS_BALANCED_HIGH << 20))
|
||||
#define BLACK_PIXEL (TMDS_BALANCED_LOW | (TMDS_BALANCED_LOW << 10) | (TMDS_BALANCED_LOW << 20))
|
||||
#define BLACK_PIXEL_A (TMDS_BLACK_A | (TMDS_BLACK_A << 10) | (TMDS_BLACK_A << 20))
|
||||
#define BLACK_PIXEL_B (TMDS_BLACK_B | (TMDS_BLACK_B << 10) | (TMDS_BLACK_B << 20))
|
||||
|
||||
#define HSTX_CMD_RAW (0x0u << 12)
|
||||
#define HSTX_CMD_RAW_REPEAT (0x1u << 12)
|
||||
|
|
|
|||
|
|
@ -18,7 +18,9 @@ typedef struct {
|
|||
typedef struct {
|
||||
uint16_t range_start, range_length, glyph_id_start, list_length;
|
||||
void *unicode_list, *glyph_id_ofs_list;
|
||||
enum { LV_FONT_FMT_TXT_CMAP_FORMAT0_TINY } type;
|
||||
enum {
|
||||
LV_FONT_FMT_TXT_CMAP_FORMAT0_TINY
|
||||
} type;
|
||||
} lv_font_fmt_txt_cmap_t;
|
||||
|
||||
typedef struct {
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue