Load DV Stick Driver over SWD. Currently unreliable.

dv_stick
Mike Bell 2023-05-14 22:51:48 +01:00 zatwierdzone przez Phil Howard
rodzic 9acc270418
commit da36b0ad32
7 zmienionych plików z 11478 dodań i 2 usunięć

Wyświetl plik

@ -9,7 +9,7 @@ namespace pimoroni {
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 = pio0);
APS6404(uint pin_csn = 17, uint pin_d0 = 19, PIO pio = pio1);
void init();

Wyświetl plik

@ -2,9 +2,12 @@ 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}/${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,4 +1,6 @@
#include "dv_display.hpp"
#include "swd_load.hpp"
#include "pico-stick.h"
#include <cstdlib>
#include <math.h>
@ -14,6 +16,8 @@ namespace pimoroni {
gpio_init(VSYNC);
gpio_set_dir(VSYNC, GPIO_IN);
swd_load_program(section_addresses, section_data, section_data_len, sizeof(section_addresses) / sizeof(section_addresses[0]));
ram.init();
write_header(0);
@ -23,7 +27,17 @@ namespace pimoroni {
bank = 0;
gpio_put(RAM_SEL, 0);
sleep_ms(500);
printf("Start I2C\n");
//i2c_init(i2c0, 100000);
//gpio_set_function(I2C_SDA, GPIO_FUNC_I2C); gpio_pull_up(I2C_SDA);
//gpio_set_function(I2C_SCL, GPIO_FUNC_I2C); gpio_pull_up(I2C_SCL);
i2c.reg_write_uint8(I2C_ADDR, I2C_REG_START, 1);
//uint8_t i2c_cmd[] = {I2C_REG_START, 1};
//i2c_write_blocking(i2c0, I2C_ADDR, i2c_cmd, 2, false);
printf("Started\n");
}
void DVDisplay::flip() {

Plik diff jest za duży Load Diff

Wyświetl plik

@ -0,0 +1,219 @@
; 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

@ -0,0 +1,309 @@
#include "pico/stdlib.h"
#include "stdio.h"
#include "swd.pio.h"
#include <algorithm>
static uint pio_offset;
static uint pio_sm;
static const pio_program_t* pio_prog;
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(pio0, pio_sm) || pio0_hw->sm[pio_sm].addr != pio_offset + pull_offset);
}
static void switch_program(bool read, bool raw = false) {
wait_for_idle();
pio_sm_set_enabled(pio0, pio_sm, false);
pio_remove_program(pio0, pio_prog, pio_offset);
pio_prog = raw ? (read ? &swd_raw_read_program : &swd_raw_write_program) :
(read ? &swd_read_program : &swd_write_program);
pio_offset = pio_add_program(pio0, pio_prog);
if (raw) {
swd_raw_program_init(pio0, pio_sm, pio_offset, 2, 3, read);
} else {
swd_program_init(pio0, pio_sm, pio_offset, 2, 3, read);
wait_for_idle();
pio0_hw->irq = 1;
}
}
static void unload_pio() {
pio_sm_set_enabled(pio0, pio_sm, false);
pio_remove_program(pio0, pio_prog, pio_offset);
pio_sm_unclaim(pio0, pio_sm);
}
static bool write_cmd(uint cmd, uint data) {
if (pio_prog != &swd_write_program) {
switch_program(false);
}
pio_sm_put_blocking(pio0, pio_sm, cmd);
pio_sm_put_blocking(pio0, pio_sm, data);
wait_for_idle();
if (pio0_hw->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(pio0, pio_sm, cmd);
wait_for_idle();
if (pio0_hw->irq & 0x1) {
printf("Read ID failed\n");
return false;
}
data = pio_sm_get_blocking(pio0, 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(pio0, pio_sm, 7);
pio_sm_put_blocking(pio0, pio_sm, 0);
}
static bool connect(bool first = true) {
if (first) {
pio_prog = &swd_raw_write_program;
pio_offset = pio_add_program(pio0, &swd_raw_write_program);
pio_sm = pio_claim_unused_sm(pio0, true);
swd_initial_init(pio0, pio_sm, 2, 3);
swd_raw_program_init(pio0, pio_sm, pio_offset, 2, 3, false);
} else {
switch_program(false, true);
}
// Begin transaction: 8 clocks, data low
printf("Begin transaction\n");
pio_sm_put_blocking(pio0, pio_sm, 7);
pio_sm_put_blocking(pio0, pio_sm, 0);
// Go to SWD mode:
// 8 clocks, data high
// 0x6209F392, 0x86852D95, 0xE3DDAFE9, 0x19BC0EA2
// 4 clocks, data low
// 0x1A
printf("SWD Mode\n");
pio_sm_put_blocking(pio0, pio_sm, 8-1);
pio_sm_put_blocking(pio0, pio_sm, 0xFF);
printf("Tag\n");
pio_sm_put_blocking(pio0, pio_sm, 32*4+4+8-1);
pio_sm_put_blocking(pio0, pio_sm, 0x6209F392);
pio_sm_put_blocking(pio0, pio_sm, 0x86852D95);
pio_sm_put_blocking(pio0, pio_sm, 0xE3DDAFE9);
pio_sm_put_blocking(pio0, pio_sm, 0x19BC0EA2);
pio_sm_put_blocking(pio0, pio_sm, 0x1A0);
// Line Reset: 50 high, 8 low
printf("Line Reset\n");
pio_sm_put_blocking(pio0, pio_sm, 58-1);
pio_sm_put_blocking(pio0, pio_sm, 0xFFFFFFFF);
pio_sm_put_blocking(pio0, pio_sm, 0x003FFFF);
printf("Target Select\n"); // Must ignore error response
wait_for_idle();
pio_sm_set_enabled(pio0, pio_sm, false);
pio_remove_program(pio0, pio_prog, pio_offset);
pio_prog = &swd_write_ignore_error_program;
pio_offset = pio_add_program(pio0, pio_prog);
swd_program_init(pio0, pio_sm, pio_offset, 2, 3, false);
wait_for_idle();
pio0_hw->irq = 1;
pio_sm_put_blocking(pio0, pio_sm, 0x19);
pio_sm_put_blocking(pio0, pio_sm, 0x01002927);
printf("Read ID\n");
uint id;
if (!read_cmd(0x25, id)) {
printf("Read ID failed\n");
return false;
}
printf("Received ID: %08x\n", id);
if (id != 0x0bc12477) return false;
printf("Abort\n");
if (!write_cmd(0x01, 0x1E)) {
printf("Abort failed\n");
return false;
}
printf("Select\n");
if (!write_cmd(0x31, 0)) {
printf("Select failed\n");
return false;
}
printf("Ctrl/Stat\n");
if (!write_cmd(0x29, 0x50000001)) {
printf("Ctrl power up failed\n");
return false;
}
uint status;
if (!read_cmd(0x0D, status)) {
printf("Read status on power up failed\n");
return false;
}
printf("Status: %08x\n", status);
if ((status & 0xA0000000) != 0xA0000000) {
printf("Power up not acknowledged\n");
return false;
}
printf("Setup memory access\n");
if (!write_cmd(0x23, 0xA2000052)) {
printf("Memory access setup failed\n");
return false;
}
idle();
return true;
}
static bool load(uint address, const uint* data, uint len_in_bytes) {
printf("Loading %d bytes at %08x\n", len_in_bytes, address);
idle();
printf("Halt CPU\n");
if (!write_reg(0xe000edf0, 0xA05F0003)) {
printf("Halt failed\n");
return false;
}
idle();
constexpr uint BLOCK_SIZE = 1024;
for (uint i = 0; i < len_in_bytes; i += BLOCK_SIZE) {
uint block_len_in_words = std::min(BLOCK_SIZE >> 2, (len_in_bytes - i) >> 2);
if (!write_block(address + i, &data[i >> 2], block_len_in_words)) {
printf("Block write failed\n");
return false;
}
}
for (uint j = 0; j < len_in_bytes; j += 4) {
uint check_data;
if (!read_reg(address + j, check_data)) {
printf("Read failed\n");
return false;
}
if (check_data != data[j >> 2]) {
printf("Verify failed at %08x, %08x != %08x\n", address + j, check_data, data[j >> 2]);
return false;
}
}
idle();
return true;
}
static bool start(uint pc = 0x20000001) {
idle();
printf("Set PC\n");
if (!write_reg(0xe000edf8, pc) ||
!write_reg(0xe000edf4, 0x1000F))
{
printf("Failed to set PC\n");
return false;
}
printf("Set SP\n");
if (!write_reg(0xe000edf8, 0x15004000) || //0x20042000) ||
!write_reg(0xe000edf4, 0x1000D))
{
printf("Failed to set SP\n");
return false;
}
idle();
#if 1
uint data;
write_reg(0xe000edf4, 0x0000F);
idle();
read_reg(0xe000edf8, data);
printf("Set PC to %08x\n", data);
for (int i = 0; i < 16; ++i) {
write_reg(0xe000edf4, i);
idle();
read_reg(0xe000edf8, data);
printf("R%d is %08x\n", i, data);
}
for (int i = 0; i < 4; ++i) {
read_reg(0x4005801c + 4*i, data);
printf("WD%d is %08x\n", i, data);
}
#endif
//write_reg(0x40010008, 0xC000);
printf("Start CPU\n");
if (!write_reg(0xe000edf0, 0xA05F0001)) {
printf("Start failed\n");
return false;
}
idle();
wait_for_idle();
//sleep_us(100);
return true;
}
bool swd_load_program(const uint* addresses, const uint** data, const uint* data_len_in_bytes, uint num_sections) {
gpio_init(2);
gpio_init(3);
gpio_disable_pulls(2);
gpio_pull_up(3);
printf("Connecting\n");
bool ok = connect();
printf("Connected %s\n", ok ? "OK" : "Fail");
if (!ok) {
return false;
}
for (uint i = 0; i < num_sections; ++i)
{
if (!load(addresses[i], data[i], data_len_in_bytes[i])) {
printf("Failed to load section %d\n", i);
return false;
}
}
ok = start();
unload_pio();
return ok;
}

Wyświetl plik

@ -0,0 +1 @@
bool swd_load_program(const uint* addresses, const uint** data, const uint* data_len_in_bytes, uint num_sections);