kopia lustrzana https://github.com/Wren6991/PicoDVI
74 wiersze
2.3 KiB
C
74 wiersze
2.3 KiB
C
#include "pico.h"
|
|
#include "hardware/pio.h"
|
|
#include "hardware/gpio.h"
|
|
#include "hardware/pwm.h"
|
|
#include "hardware/structs/padsbank0.h"
|
|
|
|
#include "dvi.h"
|
|
#include "dvi_serialiser.h"
|
|
#include "dvi_serialiser.pio.h"
|
|
|
|
static void dvi_configure_pad(uint gpio, bool invert) {
|
|
// 2 mA drive, enable slew rate limiting (this seems fine even at 720p30, and
|
|
// the 3V3 LDO doesn't get warm like when turning all the GPIOs up to 11).
|
|
// Also disable digital receiver.
|
|
hw_write_masked(
|
|
&padsbank0_hw->io[gpio],
|
|
(0 << PADS_BANK0_GPIO0_DRIVE_LSB),
|
|
PADS_BANK0_GPIO0_DRIVE_BITS | PADS_BANK0_GPIO0_SLEWFAST_BITS | PADS_BANK0_GPIO0_IE_BITS
|
|
);
|
|
gpio_set_outover(gpio, invert ? GPIO_OVERRIDE_INVERT : GPIO_OVERRIDE_NORMAL);
|
|
}
|
|
|
|
void dvi_serialiser_init(struct dvi_serialiser_cfg *cfg) {
|
|
#if DVI_SERIAL_DEBUG
|
|
uint offset = pio_add_program(cfg->pio, &dvi_serialiser_debug_program);
|
|
#else
|
|
uint offset = pio_add_program(cfg->pio, &dvi_serialiser_program);
|
|
#endif
|
|
cfg->prog_offs = offset;
|
|
|
|
for (int i = 0; i < N_TMDS_LANES; ++i) {
|
|
pio_sm_claim(cfg->pio, cfg->sm_tmds[i]);
|
|
dvi_serialiser_program_init(
|
|
cfg->pio,
|
|
cfg->sm_tmds[i],
|
|
offset,
|
|
cfg->pins_tmds[i],
|
|
DVI_SERIAL_DEBUG
|
|
);
|
|
dvi_configure_pad(cfg->pins_tmds[i], cfg->invert_diffpairs);
|
|
dvi_configure_pad(cfg->pins_tmds[i] + 1, cfg->invert_diffpairs);
|
|
}
|
|
|
|
// Use a PWM slice to drive the pixel clock. Both GPIOs must be on the same
|
|
// slice (lower-numbered GPIO must be even).
|
|
assert(cfg->pins_clk % 2 == 0);
|
|
uint slice = pwm_gpio_to_slice_num(cfg->pins_clk);
|
|
// 5 cycles high, 5 low. Invert one channel so that we get complementary outputs.
|
|
pwm_config pwm_cfg = pwm_get_default_config();
|
|
pwm_config_set_output_polarity(&pwm_cfg, true, false);
|
|
pwm_config_set_wrap(&pwm_cfg, 9);
|
|
pwm_init(slice, &pwm_cfg, false);
|
|
pwm_set_both_levels(slice, 5, 5);
|
|
|
|
for (uint i = cfg->pins_clk; i <= cfg->pins_clk + 1; ++i) {
|
|
gpio_set_function(i, GPIO_FUNC_PWM);
|
|
dvi_configure_pad(i, cfg->invert_diffpairs);
|
|
}
|
|
}
|
|
|
|
void dvi_serialiser_enable(struct dvi_serialiser_cfg *cfg, bool enable) {
|
|
uint mask = 0;
|
|
for (int i = 0; i < N_TMDS_LANES; ++i)
|
|
mask |= 1u << (cfg->sm_tmds[i] + PIO_CTRL_SM_ENABLE_LSB);
|
|
if (enable) {
|
|
hw_set_bits(&cfg->pio->ctrl, mask);
|
|
pwm_set_enabled(pwm_gpio_to_slice_num(cfg->pins_clk), true);
|
|
}
|
|
else {
|
|
hw_clear_bits(&cfg->pio->ctrl, mask);
|
|
pwm_set_enabled(pwm_gpio_to_slice_num(cfg->pins_clk), false);
|
|
}
|
|
}
|