ftdi uart stuff (WIP)
This commit is contained in:
parent
1e9cac1ace
commit
3b76c6fb4a
|
@ -158,6 +158,9 @@ if(FAMILY STREQUAL "rp2040")
|
|||
pico_generate_pio_header(${PROJECT} ${CMAKE_CURRENT_SOURCE_DIR}/bsp/${FAMILY}/m_default/swo_uart_rx.pio)
|
||||
pico_generate_pio_header(${PROJECT} ${CMAKE_CURRENT_SOURCE_DIR}/bsp/${FAMILY}/m_default/swo_manchester_encoding.pio)
|
||||
|
||||
pico_generate_pio_header(${PROJECT} ${CMAKE_CURRENT_SOURCE_DIR}/bsp/${FAMILY}/m_ftdi/ftdi_uart_rx.pio)
|
||||
pico_generate_pio_header(${PROJECT} ${CMAKE_CURRENT_SOURCE_DIR}/bsp/${FAMILY}/m_ftdi/ftdi_uart_tx.pio)
|
||||
|
||||
pico_add_extra_outputs(${PROJECT})
|
||||
|
||||
else()
|
||||
|
|
|
@ -61,6 +61,7 @@ uint32_t SWO_Mode_UART(uint32_t enable) {
|
|||
mode_enabled = false;
|
||||
|
||||
if (swo_dmach >= 0) {
|
||||
dma_channel_abort(swo_dmach);
|
||||
dma_channel_unclaim(swo_dmach); // ugh why is it "dma_channel_xyz" and "dma_xyz_channel"
|
||||
swo_dmach = -1;
|
||||
}
|
||||
|
@ -189,6 +190,7 @@ uint32_t SWO_Mode_Manchester(uint32_t enable) {
|
|||
mode_enabled = false;
|
||||
|
||||
if (swo_dmach >= 0) {
|
||||
dma_channel_abort(swo_dmach);
|
||||
dma_channel_unclaim(swo_dmach); // ugh why is it "dma_channel_xyz" and "dma_xyz_channel"
|
||||
swo_dmach = -1;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// vim: set et ts=8:
|
||||
|
||||
#ifndef PINOUT_H_
|
||||
#define PINOUT_H_
|
||||
#ifndef BSP_PINOUT_M_DEFAULT_H_
|
||||
#define BSP_PINOUT_M_DEFAULT_H_
|
||||
|
||||
// UART config
|
||||
#define PINOUT_UART_TX 8
|
||||
|
|
|
@ -3,19 +3,25 @@
|
|||
#include "m_ftdi/ftdi.h"
|
||||
|
||||
void ftdi_if_asyncbb_init(struct ftdi_interface* itf) {
|
||||
(void)itf;
|
||||
|
||||
}
|
||||
void ftdi_if_asyncbb_deinit(struct ftdi_interface* itf) {
|
||||
(void)itf;
|
||||
|
||||
}
|
||||
void ftdi_if_asyncbb_set_baudrate(struct ftdi_interface* itf, uint32_t baudrate) {
|
||||
(void)itf; (void)baudrate;
|
||||
|
||||
}
|
||||
|
||||
void ftdi_if_asyncbb_write(struct ftdi_interface* itf, const uint8_t* data, size_t datasize) {
|
||||
(void)itf; (void)data; (void)datasize;
|
||||
|
||||
}
|
||||
size_t ftdi_if_asyncbb_read(struct ftdi_interface* itf, uint8_t* data, size_t maxsize) {
|
||||
(void)itf; (void)data; (void)maxsize;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -35,6 +35,7 @@ void ftdi_if_deinit(struct ftdi_interface* itf) {
|
|||
}
|
||||
|
||||
void ftdi_if_set_modemctrl(struct ftdi_interface* itf, uint8_t mask, uint8_t data) {
|
||||
(void)itf; (void)mask; (void)data;
|
||||
// TODO: what's this?
|
||||
}
|
||||
void ftdi_if_set_baudrate(struct ftdi_interface* itf, uint32_t baudrate) {
|
||||
|
@ -50,15 +51,21 @@ void ftdi_if_set_baudrate(struct ftdi_interface* itf, uint32_t baudrate) {
|
|||
}
|
||||
}
|
||||
enum ftdi_sio_modemstat ftdi_if_poll_modemstat(struct ftdi_interface* itf) {
|
||||
(void)itf;
|
||||
|
||||
return sio_modem_cts | sio_modem_dts; // TODO: use this to read part of UART flow ctrl?
|
||||
}
|
||||
void ftdi_if_set_eventchar(struct ftdi_interface* itf, bool enable, uint8_t evchar) {
|
||||
(void)itf; (void)enable; (void)evchar;
|
||||
// TODO: when is this used? bitmode0-only? also ftd2xx headers make this look like its not just an "event on char" thing
|
||||
}
|
||||
void ftdi_if_set_errorchar(struct ftdi_interface* itf, bool enable, uint8_t erchar) {
|
||||
(void)itf; (void)enable; (void)erchar;
|
||||
// TODO: when is this used? bitmode0-only? also ftd2xx headers make this look like its not just an "error on char" thing
|
||||
}
|
||||
uint8_t ftdi_if_read_pins(struct ftdi_interface* itf) {
|
||||
(void)itf;
|
||||
|
||||
return 0; // TODO: which pins does this return?
|
||||
}
|
||||
|
||||
|
@ -70,9 +77,9 @@ void ftdi_if_set_bitbang(struct ftdi_interface* itf, uint8_t dirmask,
|
|||
init_mode(itf, ftdi_if_get_mode(itf));
|
||||
}
|
||||
|
||||
void ftdi_if_sio_reset(struct ftdi_interface* itf) { /* TODO: ? */ }
|
||||
void ftdi_if_sio_tciflush(struct ftdi_interface* itf) { /* TODO: ? */ }
|
||||
void ftdi_if_sio_tcoflush(struct ftdi_interface* itf) { /* TODO: ? */ }
|
||||
void ftdi_if_set_latency(struct ftdi_interface* itf, uint8_t latency) { /* TODO: ? */ }
|
||||
void ftdi_if_sio_reset(struct ftdi_interface* itf) { (void)itf; /* TODO: ? */ }
|
||||
void ftdi_if_sio_tciflush(struct ftdi_interface* itf) { (void)itf; /* TODO: ? */ }
|
||||
void ftdi_if_sio_tcoflush(struct ftdi_interface* itf) { (void)itf; /* TODO: ? */ }
|
||||
void ftdi_if_set_latency(struct ftdi_interface* itf, uint8_t latency) { (void)itf; (void)latency; /* TODO: ? */ }
|
||||
uint8_t ftdi_if_get_latency(struct ftdi_interface* itf) { return itf->latency; /* TODO: ? */ }
|
||||
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
#define DBOARD_HAS_FTDI
|
||||
|
||||
/* TODO: more fine-grained FTDI support/not-support stuff? */
|
||||
|
||||
#include "bsp-info.h"
|
||||
|
||||
// not all that much here
|
||||
|
|
|
@ -3,19 +3,21 @@
|
|||
#include "m_ftdi/ftdi.h"
|
||||
|
||||
void ftdi_if_cpufifo_init(struct ftdi_interface* itf) {
|
||||
|
||||
(void)itf;
|
||||
}
|
||||
void ftdi_if_cpufifo_deinit(struct ftdi_interface* itf) {
|
||||
|
||||
(void)itf;
|
||||
}
|
||||
void ftdi_if_cpufifo_set_baudrate(struct ftdi_interface* itf, uint32_t baudrate) {
|
||||
|
||||
(void)itf; (void)baudrate;
|
||||
}
|
||||
|
||||
void ftdi_if_cpufifo_write(struct ftdi_interface* itf, const uint8_t* data, size_t datasize) {
|
||||
|
||||
(void)itf; (void)data; (void)datasize;
|
||||
}
|
||||
size_t ftdi_if_cpufifo_read(struct ftdi_interface* itf, uint8_t* data, size_t maxsize) {
|
||||
(void)itf; (void)data; (void)maxsize;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -3,19 +3,20 @@
|
|||
#include "m_ftdi/ftdi.h"
|
||||
|
||||
void ftdi_if_fifo_init(struct ftdi_interface* itf) {
|
||||
|
||||
(void)itf;
|
||||
}
|
||||
void ftdi_if_fifo_deinit(struct ftdi_interface* itf) {
|
||||
|
||||
(void)itf;
|
||||
}
|
||||
void ftdi_if_fifo_set_baudrate(struct ftdi_interface* itf, uint32_t baudrate) {
|
||||
|
||||
(void)itf; (void)baudrate;
|
||||
}
|
||||
|
||||
void ftdi_if_fifo_write(struct ftdi_interface* itf, const uint8_t* data, size_t datasize) {
|
||||
|
||||
(void)itf; (void)data; (void)datasize;
|
||||
}
|
||||
size_t ftdi_if_fifo_read(struct ftdi_interface* itf, uint8_t* data, size_t maxsize) {
|
||||
(void)itf; (void)data; (void)maxsize;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,94 @@
|
|||
;
|
||||
; Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
|
||||
;
|
||||
; SPDX-License-Identifier: BSD-3-Clause
|
||||
;
|
||||
|
||||
.program ftdi_uart_rx_mini
|
||||
|
||||
; Minimum viable 8n1 UART receiver. Wait for the start bit, then sample 8 bits
|
||||
; with the correct timing.
|
||||
; IN pin 0 is mapped to the GPIO used as UART RX.
|
||||
; Autopush must be enabled, with a threshold of 8.
|
||||
|
||||
wait 0 pin 0 ; Wait for start bit
|
||||
set x, 7 [10] ; Preload bit counter, delay until eye of first data bit
|
||||
bitloop: ; Loop 8 times
|
||||
in pins, 1 ; Sample data
|
||||
jmp x-- bitloop [6] ; Each iteration is 8 cycles
|
||||
|
||||
% c-sdk {
|
||||
#include "hardware/clocks.h"
|
||||
#include "hardware/gpio.h"
|
||||
|
||||
static inline void ftdi_uart_rx_mini_program_init(PIO pio, uint sm, uint offset, uint pin, uint baud) {
|
||||
pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, false);
|
||||
pio_gpio_init(pio, pin);
|
||||
gpio_pull_up(pin);
|
||||
|
||||
pio_sm_config c = ftdi_uart_rx_mini_program_get_default_config(offset);
|
||||
sm_config_set_in_pins(&c, pin); // for WAIT, IN
|
||||
// Shift to right, autopush enabled
|
||||
sm_config_set_in_shift(&c, true, true, 8);
|
||||
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_RX);
|
||||
// SM transmits 1 bit per 8 execution cycles.
|
||||
float div = (float)clock_get_hz(clk_sys) / (8 * baud);
|
||||
sm_config_set_clkdiv(&c, div);
|
||||
|
||||
pio_sm_init(pio, sm, offset, &c);
|
||||
pio_sm_set_enabled(pio, sm, true);
|
||||
}
|
||||
%}
|
||||
|
||||
.program ftdi_uart_rx
|
||||
|
||||
; Slightly more fleshed-out 8n1 UART receiver which handles framing errors and
|
||||
; break conditions more gracefully.
|
||||
; IN pin 0 and JMP pin are both mapped to the GPIO used as UART RX.
|
||||
|
||||
start:
|
||||
wait 0 pin 0 ; Stall until start bit is asserted
|
||||
set x, 7 [10] ; Preload bit counter, then delay until halfway through
|
||||
bitloop: ; the first data bit (12 cycles incl wait, set).
|
||||
in pins, 1 ; Shift data bit into ISR
|
||||
jmp x-- bitloop [6] ; Loop 8 times, each loop iteration is 8 cycles
|
||||
jmp pin good_stop ; Check stop bit (should be high)
|
||||
|
||||
irq 4 rel ; Either a framing error or a break. Set a sticky flag,
|
||||
wait 1 pin 0 ; and wait for line to return to idle state.
|
||||
jmp start ; Don't push data if we didn't see good framing.
|
||||
|
||||
good_stop: ; No delay before returning to start; a little slack is
|
||||
push ; important in case the TX clock is slightly too fast.
|
||||
|
||||
|
||||
% c-sdk {
|
||||
static inline void ftdi_uart_rx_program_init(PIO pio, uint sm, uint offset, uint pin, uint baud) {
|
||||
pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, false);
|
||||
pio_gpio_init(pio, pin);
|
||||
gpio_pull_up(pin);
|
||||
|
||||
pio_sm_config c = ftdi_uart_rx_program_get_default_config(offset);
|
||||
sm_config_set_in_pins(&c, pin); // for WAIT, IN
|
||||
sm_config_set_jmp_pin(&c, pin); // for JMP
|
||||
// Shift to right, autopull disabled
|
||||
sm_config_set_in_shift(&c, true, false, 32);
|
||||
// Deeper FIFO as we're not doing any TX
|
||||
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_RX);
|
||||
// SM transmits 1 bit per 8 execution cycles.
|
||||
float div = (float)clock_get_hz(clk_sys) / (8 * baud);
|
||||
sm_config_set_clkdiv(&c, div);
|
||||
|
||||
pio_sm_init(pio, sm, offset, &c);
|
||||
pio_sm_set_enabled(pio, sm, true);
|
||||
}
|
||||
|
||||
static inline char ftdi_uart_rx_program_getc(PIO pio, uint sm) {
|
||||
// 8-bit read from the uppermost byte of the FIFO, as data is left-justified
|
||||
io_rw_8 *rxfifo_shift = (io_rw_8*)&pio->rxf[sm] + 3;
|
||||
while (pio_sm_is_rx_fifo_empty(pio, sm))
|
||||
tight_loop_contents();
|
||||
return (char)*rxfifo_shift;
|
||||
}
|
||||
|
||||
%}
|
|
@ -0,0 +1,61 @@
|
|||
;
|
||||
; Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
|
||||
;
|
||||
; SPDX-License-Identifier: BSD-3-Clause
|
||||
;
|
||||
|
||||
.program ftdi_uart_tx
|
||||
.side_set 1 opt
|
||||
|
||||
; An 8n1 UART transmit program.
|
||||
; OUT pin 0 and side-set pin 0 are both mapped to UART TX pin.
|
||||
|
||||
pull side 1 [7] ; Assert stop bit, or stall with line in idle state
|
||||
set x, 7 side 0 [7] ; Preload bit counter, assert start bit for 8 clocks
|
||||
bitloop: ; This loop will run 8 times (8n1 UART)
|
||||
out pins, 1 ; Shift 1 bit from OSR to the first OUT pin
|
||||
jmp x-- bitloop [6] ; Each loop iteration is 8 cycles.
|
||||
|
||||
|
||||
% c-sdk {
|
||||
#include "hardware/clocks.h"
|
||||
|
||||
static inline void ftdi_uart_tx_program_init(PIO pio, uint sm, uint offset, uint pin_tx, uint baud) {
|
||||
// Tell PIO to initially drive output-high on the selected pin, then map PIO
|
||||
// onto that pin with the IO muxes.
|
||||
pio_sm_set_pins_with_mask(pio, sm, 1u << pin_tx, 1u << pin_tx);
|
||||
pio_sm_set_pindirs_with_mask(pio, sm, 1u << pin_tx, 1u << pin_tx);
|
||||
pio_gpio_init(pio, pin_tx);
|
||||
|
||||
pio_sm_config c = ftdi_uart_tx_program_get_default_config(offset);
|
||||
|
||||
// OUT shifts to right, no autopull
|
||||
sm_config_set_out_shift(&c, true, false, 32);
|
||||
|
||||
// We are mapping both OUT and side-set to the same pin, because sometimes
|
||||
// we need to assert user data onto the pin (with OUT) and sometimes
|
||||
// assert constant values (start/stop bit)
|
||||
sm_config_set_out_pins(&c, pin_tx, 1);
|
||||
sm_config_set_sideset_pins(&c, pin_tx);
|
||||
|
||||
// We only need TX, so get an 8-deep FIFO!
|
||||
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX);
|
||||
|
||||
// SM transmits 1 bit per 8 execution cycles.
|
||||
float div = (float)clock_get_hz(clk_sys) / (8 * baud);
|
||||
sm_config_set_clkdiv(&c, div);
|
||||
|
||||
pio_sm_init(pio, sm, offset, &c);
|
||||
pio_sm_set_enabled(pio, sm, true);
|
||||
}
|
||||
|
||||
static inline void ftdi_uart_tx_program_putc(PIO pio, uint sm, char c) {
|
||||
pio_sm_put_blocking(pio, sm, (uint32_t)c);
|
||||
}
|
||||
|
||||
static inline void ftdi_uart_tx_program_puts(PIO pio, uint sm, const char *s) {
|
||||
while (*s)
|
||||
ftdi_uart_tx_program_putc(pio, sm, *s++);
|
||||
}
|
||||
|
||||
%}
|
|
@ -3,32 +3,36 @@
|
|||
#include "m_ftdi/ftdi.h"
|
||||
|
||||
void ftdi_if_mcuhost_init(struct ftdi_interface* itf) {
|
||||
|
||||
(void)itf;
|
||||
}
|
||||
void ftdi_if_mcuhost_deinit(struct ftdi_interface* itf) {
|
||||
|
||||
(void)itf;
|
||||
}
|
||||
void ftdi_if_mcuhost_set_baudrate(struct ftdi_interface* itf, uint32_t baudrate) {
|
||||
|
||||
(void)itf; (void)baudrate;
|
||||
}
|
||||
|
||||
void ftdi_if_mcuhost_flush(struct ftdi_interface* itf) {
|
||||
|
||||
(void)itf;
|
||||
}
|
||||
void ftdi_if_mcuhost_wait_io(struct ftdi_interface* itf, bool level) {
|
||||
|
||||
(void)itf; (void)level;
|
||||
}
|
||||
|
||||
uint8_t ftdi_if_mcuhost_read8(struct ftdi_interface* itf, uint8_t addr) {
|
||||
(void)itf; (void)addr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
uint8_t ftdi_if_mcuhost_read16(struct ftdi_interface* itf, uint16_t addr) {
|
||||
(void)itf; (void)addr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
void ftdi_if_mcuhost_write8(struct ftdi_interface* itf, uint8_t addr, uint8_t value) {
|
||||
|
||||
(void)itf; (void)addr; (void)value;
|
||||
}
|
||||
void ftdi_if_mcuhost_write16(struct ftdi_interface* itf, uint16_t addr, uint8_t value) {
|
||||
|
||||
(void)itf; (void)addr; (void)value;
|
||||
}
|
||||
|
||||
|
|
|
@ -3,72 +3,80 @@
|
|||
#include "m_ftdi/ftdi.h"
|
||||
|
||||
void ftdi_if_mpsse_init(struct ftdi_interface* itf) {
|
||||
|
||||
(void)itf;
|
||||
}
|
||||
void ftdi_if_mpsse_deinit(struct ftdi_interface* itf) {
|
||||
|
||||
(void)itf;
|
||||
}
|
||||
void ftdi_if_mpsse_set_baudrate(struct ftdi_interface* itf, uint32_t baudrate) {
|
||||
|
||||
(void)itf; (void)baudrate;
|
||||
}
|
||||
|
||||
|
||||
void ftdi_if_mpsse_flush(struct ftdi_interface* itf) {
|
||||
|
||||
(void)itf;
|
||||
}
|
||||
void ftdi_if_mpsse_wait_io(struct ftdi_interface* itf, bool level) {
|
||||
|
||||
(void)itf; (void)level;
|
||||
}
|
||||
|
||||
void ftdi_if_mpsse_set_dirval_lo(struct ftdi_interface* itf, uint8_t dir, uint8_t val) {
|
||||
|
||||
(void)itf; (void)dir; (void)val;
|
||||
}
|
||||
void ftdi_if_mpsse_set_dirval_hi(struct ftdi_interface* itf, uint8_t dir, uint8_t val) {
|
||||
|
||||
(void)itf; (void)dir; (void)val;
|
||||
}
|
||||
uint8_t ftdi_if_mpsse_read_lo(struct ftdi_interface* itf) {
|
||||
(void)itf;
|
||||
|
||||
return 0;
|
||||
}
|
||||
uint8_t ftdi_if_mpsse_read_hi(struct ftdi_interface* itf) {
|
||||
(void)itf;
|
||||
|
||||
return 0;
|
||||
}
|
||||
void ftdi_if_mpsse_loopback(struct ftdi_interface* itf, bool enable) {
|
||||
|
||||
(void)itf; (void)enable;
|
||||
}
|
||||
void ftdi_if_mpsse_set_clkdiv(struct ftdi_interface* itf, uint16_t div) {
|
||||
|
||||
(void)itf; (void)div;
|
||||
}
|
||||
|
||||
uint8_t ftdi_if_mpsse_xfer_bits(struct ftdi_interface* itf, int flags, size_t nbits, uint8_t value) {
|
||||
(void)itf; (void)flags; (void)nbits; (void)value;
|
||||
|
||||
return 0;
|
||||
}
|
||||
void ftdi_if_mpsse_xfer_bytes(struct ftdi_interface* itf, int flags, size_t nbytes, uint8_t* dst, const uint8_t* src) {
|
||||
|
||||
(void)itf; (void)flags; (void)nbytes; (void)dst; (void)src;
|
||||
}
|
||||
uint8_t ftdi_if_mpsse_tms_xfer(struct ftdi_interface* itf, int flags, size_t nbits, uint8_t value) {
|
||||
(void)itf; (void)flags; (void)nbits; (void)value;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ftdi_if_mpsse_div5(struct ftdi_interface* itf, bool enable) {
|
||||
|
||||
(void)itf; (void)enable;
|
||||
}
|
||||
void ftdi_if_mpsse_data_3ph(struct ftdi_interface* itf, bool enable) {
|
||||
|
||||
(void)itf; (void)enable;
|
||||
}
|
||||
void ftdi_if_mpsse_adaptive(struct ftdi_interface* itf, bool enable) {
|
||||
|
||||
(void)itf; (void)enable;
|
||||
}
|
||||
|
||||
void ftdi_if_mpsse_clockonly(struct ftdi_interface* itf, uint32_t cycles) {
|
||||
|
||||
(void)itf; (void)cycles;
|
||||
}
|
||||
void ftdi_if_mpsse_clock_wait_io(struct ftdi_interface* itf, bool level) {
|
||||
|
||||
(void)itf; (void)level;
|
||||
}
|
||||
void ftdi_if_mpsse_clockonly_wait_io(struct ftdi_interface* itf, bool level, uint32_t cycles) {
|
||||
|
||||
(void)itf; (void)level; (void)cycles;
|
||||
}
|
||||
void ftdi_if_mpsse_hi_is_tristate(struct ftdi_interface* itf, uint16_t pinmask) {
|
||||
|
||||
(void)itf; (void)pinmask;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,133 @@
|
|||
|
||||
#ifndef BSP_PINOUT_M_FTDI_H_
|
||||
#define BSP_PINOUT_M_FTDI_H_
|
||||
|
||||
#define PINOUT_ITF_A_BASE 2
|
||||
#define PINOUT_ITF_B_BASE 14
|
||||
|
||||
// TODO: ? or just different SMs on the same PIO? would complicate things tho
|
||||
#define PINOUT_ITF_A_PIO pio0
|
||||
#define PINOUT_ITF_B_PIO pio1
|
||||
|
||||
#define PINOUT_DBUS0_OFF 0
|
||||
#define PINOUT_DBUS1_OFF 1
|
||||
#define PINOUT_DBUS2_OFF 2
|
||||
#define PINOUT_DBUS3_OFF 3
|
||||
#define PINOUT_DBUS4_OFF 4
|
||||
#define PINOUT_DBUS5_OFF 5
|
||||
#define PINOUT_DBUS6_OFF 6
|
||||
#define PINOUT_DBUS7_OFF 7
|
||||
#define PINOUT_CBUS0_OFF 8
|
||||
#define PINOUT_CBUS1_OFF 9
|
||||
#define PINOUT_CBUS2_OFF 10
|
||||
#define PINOUT_CBUS3_OFF 11
|
||||
|
||||
#define PINOUT_UART_TXD_OFF 0
|
||||
#define PINOUT_UART_RXD_OFF 1
|
||||
#define PINOUT_UART_nRTS_OFF 2
|
||||
#define PINOUT_UART_nCTS_OFF 3
|
||||
#define PINOUT_UART_nDTR_OFF 4
|
||||
#define PINOUT_UART_nDSR_OFF 5
|
||||
#define PINOUT_UART_nDCD_OFF 6
|
||||
#define PINOUT_UART_nRI_OFF 7
|
||||
#define PINOUT_UART_TXDEN_OFF 8
|
||||
#define PINOUT_UART_nSLEEP_OFF 9
|
||||
#define PINOUT_UART_nRXLED_OFF 10
|
||||
#define PINOUT_UART_nTXLED_OFF 11
|
||||
|
||||
#define PINOUT_FIFO_D0_OFF 0
|
||||
#define PINOUT_FIFO_D1_OFF 1
|
||||
#define PINOUT_FIFO_D2_OFF 2
|
||||
#define PINOUT_FIFO_D3_OFF 3
|
||||
#define PINOUT_FIFO_D4_OFF 4
|
||||
#define PINOUT_FIFO_D5_OFF 5
|
||||
#define PINOUT_FIFO_D6_OFF 6
|
||||
#define PINOUT_FIFO_D7_OFF 7
|
||||
#define PINOUT_FIFO_nRXF_OFF 8
|
||||
#define PINOUT_FIFO_nTXE_OFF 9
|
||||
#define PINOUT_FIFO_nRD_OFF 10
|
||||
#define PINOUT_FIFO_WR_OFF 11
|
||||
|
||||
#define PINOUT_BBANG_D0_OFF 0
|
||||
#define PINOUT_BBANG_D1_OFF 1
|
||||
#define PINOUT_BBANG_D2_OFF 2
|
||||
#define PINOUT_BBANG_D3_OFF 3
|
||||
#define PINOUT_BBANG_D4_OFF 4
|
||||
#define PINOUT_BBANG_D5_OFF 5
|
||||
#define PINOUT_BBANG_D6_OFF 6
|
||||
#define PINOUT_BBANG_D7_OFF 7
|
||||
#define PINOUT_BBANG_nWR0_OFF 8
|
||||
#define PINOUT_BBANG_nRD0_OFF 9
|
||||
#define PINOUT_BBANG_nWR1_OFF 10
|
||||
#define PINOUT_BBANG_nRD1_OFF 11
|
||||
|
||||
#define PINOUT_MPSSE_TCK_CK_OFF 0
|
||||
#define PINOUT_MPSSE_TDI_DO_OFF 1
|
||||
#define PINOUT_MPSSE_TDO_DI_OFF 2
|
||||
#define PINOUT_MPSSE_TMS_CS_OFF 3
|
||||
#define PINOUT_MPSSE_GPIOL0_OFF 4
|
||||
#define PINOUT_MPSSE_GPIOL1_OFF 5
|
||||
#define PINOUT_MPSSE_GPIOL2_OFF 6
|
||||
#define PINOUT_MPSSE_GPIOL3_OFF 7
|
||||
#define PINOUT_MPSSE_GPIOH0_OFF 8
|
||||
#define PINOUT_MPSSE_GPIOH1_OFF 9
|
||||
#define PINOUT_MPSSE_GPIOH2_OFF 10
|
||||
#define PINOUT_MPSSE_GPIOH3_OFF 11
|
||||
|
||||
#define PINOUT_MCUHOST_AD0_OFF 0
|
||||
#define PINOUT_MCUHOST_AD1_OFF 1
|
||||
#define PINOUT_MCUHOST_AD2_OFF 2
|
||||
#define PINOUT_MCUHOST_AD3_OFF 3
|
||||
#define PINOUT_MCUHOST_AD4_OFF 4
|
||||
#define PINOUT_MCUHOST_AD5_OFF 5
|
||||
#define PINOUT_MCUHOST_AD6_OFF 6
|
||||
#define PINOUT_MCUHOST_AD7_OFF 7
|
||||
#define PINOUT_MCUHOST_IO0_OFF 8
|
||||
#define PINOUT_MCUHOST_IO1_OFF 9
|
||||
#define PINOUT_MCUHOST_IORDY_OFF 10
|
||||
#define PINOUT_MCUHOST_OSC_OFF 11
|
||||
// ---
|
||||
#define PINOUT_MCUHOST_A8_OFF 0
|
||||
#define PINOUT_MCUHOST_A9_OFF 1
|
||||
#define PINOUT_MCUHOST_AA_OFF 2
|
||||
#define PINOUT_MCUHOST_AB_OFF 3
|
||||
#define PINOUT_MCUHOST_AC_OFF 4
|
||||
#define PINOUT_MCUHOST_AD_OFF 5
|
||||
#define PINOUT_MCUHOST_AE_OFF 6
|
||||
#define PINOUT_MCUHOST_AF_OFF 7
|
||||
#define PINOUT_MCUHOST_nCS_OFF 8
|
||||
#define PINOUT_MCUHOST_ALE_OFF 9
|
||||
#define PINOUT_MCUHOST_nRD_OFF 10
|
||||
#define PINOUT_MCUHOST_nWR_OFF 11
|
||||
|
||||
#define PINOUT_CPUFIFO_D0_OFF 0
|
||||
#define PINOUT_CPUFIFO_D1_OFF 1
|
||||
#define PINOUT_CPUFIFO_D2_OFF 2
|
||||
#define PINOUT_CPUFIFO_D3_OFF 3
|
||||
#define PINOUT_CPUFIFO_D4_OFF 4
|
||||
#define PINOUT_CPUFIFO_D5_OFF 5
|
||||
#define PINOUT_CPUFIFO_D6_OFF 6
|
||||
#define PINOUT_CPUFIFO_D7_OFF 7
|
||||
#define PINOUT_CPUFIFO_nCS_OFF 8
|
||||
#define PINOUT_CPUFIFO_A0_OFF 9
|
||||
#define PINOUT_CPUFIFO_nRD_OFF 10
|
||||
#define PINOUT_CPUFIFO_nWR_OFF 11
|
||||
|
||||
struct ftdi_interface;
|
||||
|
||||
static inline int PINOUT_idx_to_base(int itf_idx) {
|
||||
return itf_idx ? PINOUT_ITF_B_BASE : PINOUT_ITF_A_BASE;
|
||||
}
|
||||
static inline int PINOUT_itf_to_base(struct ftdi_interface* itf) {
|
||||
return PINOUT_idx_to_base(*(int*)itf); // can't access "index" directly here, so, shrug
|
||||
}
|
||||
|
||||
static inline void* PINOUT_idx_to_pio(int itf_idx) {
|
||||
return itf_idx ? PINOUT_ITF_A_PIO : PINOUT_ITF_B_PIO;
|
||||
}
|
||||
static inline void* PINOUT_itf_to_pio(struct ftdi_interface* itf) {
|
||||
return PINOUT_idx_to_pio(*(int*)itf); // can't access "index" directly here, so, shrug
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -3,13 +3,13 @@
|
|||
#include "m_ftdi/ftdi.h"
|
||||
|
||||
void ftdi_if_syncbb_init(struct ftdi_interface* itf) {
|
||||
|
||||
(void)itf;
|
||||
}
|
||||
void ftdi_if_syncbb_deinit(struct ftdi_interface* itf) {
|
||||
|
||||
(void)itf;
|
||||
}
|
||||
void ftdi_if_syncbb_set_baudrate(struct ftdi_interface* itf, uint32_t baudrate) {
|
||||
|
||||
(void)itf; (void)baudrate;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -2,22 +2,157 @@
|
|||
|
||||
#include "m_ftdi/ftdi.h"
|
||||
|
||||
void ftdi_if_uart_init(struct ftdi_interface* itf);
|
||||
void ftdi_if_uart_deinit(struct ftdi_interface* itf);
|
||||
void ftdi_if_uart_set_baudrate(struct ftdi_interface* itf, uint32_t baudrate);
|
||||
#include <hardware/dma.h>
|
||||
#include <hardware/gpio.h>
|
||||
#include <hardware/pio.h>
|
||||
#include <hardware/timer.h>
|
||||
#include <hardware/structs/dma.h>
|
||||
|
||||
#include "m_ftdi/pinout.h"
|
||||
#include "ftdi_uart_rx.pio.h"
|
||||
#include "ftdi_uart_tx.pio.h"
|
||||
|
||||
struct chdat {
|
||||
uint8_t off, sm, dmach;
|
||||
};
|
||||
struct uart_state {
|
||||
uint32_t baudrate;
|
||||
struct chdat rx, tx;
|
||||
bool enabled;
|
||||
};
|
||||
|
||||
static struct uart_state state[2] = {
|
||||
(struct uart_state){ .baudrate = 115200, .enabled = false },
|
||||
(struct uart_state){ .baudrate = 115200, .enabled = false },
|
||||
};
|
||||
|
||||
#define STATEOF(itf) (state[(itf)->index & 1])
|
||||
|
||||
static bool init_sm(PIO pio, struct chdat* d, const pio_program_t* prg) {
|
||||
int off, sm, dmach;
|
||||
sm = pio_claim_unused_sm(pio, false);
|
||||
if (sm == -1) return false;
|
||||
|
||||
dmach = dma_claim_unused_channel(false);
|
||||
if (dmach == -1) {
|
||||
pio_sm_unclaim(pio, sm);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!pio_can_add_program(pio, prg)) {
|
||||
dma_channel_unclaim(dmach);
|
||||
pio_sm_unclaim(pio, sm);
|
||||
return false;
|
||||
}
|
||||
|
||||
off = pio_add_program(pio, prg);
|
||||
|
||||
d->off = off;
|
||||
d->sm = sm;
|
||||
d->dmach = dmach;
|
||||
|
||||
return true;
|
||||
}
|
||||
static void deinit_sm(PIO pio, struct chdat* d, const pio_program_t* prg) {
|
||||
dma_channel_unclaim(d->dmach);
|
||||
pio_sm_set_enabled(pio, d->sm, false);
|
||||
pio_sm_unclaim(pio, d->sm);
|
||||
pio_remove_program(pio, prg, d->off);
|
||||
}
|
||||
|
||||
void ftdi_if_uart_init(struct ftdi_interface* itf) {
|
||||
if (STATEOF(itf).enabled) return; // shrug
|
||||
|
||||
PIO pio = PINOUT_itf_to_pio(itf);
|
||||
int pin_rx = PINOUT_itf_to_base(itf) + PINOUT_UART_RXD_OFF,
|
||||
pin_tx = PINOUT_itf_to_base(itf) + PINOUT_UART_TXD_OFF;
|
||||
|
||||
if (!init_sm(pio, &STATEOF(itf).rx, &ftdi_uart_rx_program)) return;
|
||||
if (!init_sm(pio, &STATEOF(itf).tx, &ftdi_uart_tx_program)) return;
|
||||
|
||||
ftdi_uart_rx_program_init(pio, STATEOF(itf).rx.sm, STATEOF(itf).rx.off,
|
||||
pin_rx, STATEOF(itf).baudrate);
|
||||
ftdi_uart_tx_program_init(pio, STATEOF(itf).tx.sm, STATEOF(itf).tx.off,
|
||||
pin_tx, STATEOF(itf).baudrate);
|
||||
|
||||
gpio_set_function(pin_rx, GPIO_FUNC_PIO0 + itf->index);
|
||||
gpio_set_function(pin_tx, GPIO_FUNC_PIO0 + itf->index);
|
||||
|
||||
/*dma_channel_start(STATEOF(itf).rx.dmach);
|
||||
dma_channel_start(STATEOF(itf).tx.dmach);*/
|
||||
|
||||
STATEOF(itf).enabled = true;
|
||||
}
|
||||
void ftdi_if_uart_deinit(struct ftdi_interface* itf) {
|
||||
if (!STATEOF(itf).enabled) return; // shrug
|
||||
|
||||
PIO pio = PINOUT_itf_to_pio(itf);
|
||||
int pin_rx = PINOUT_itf_to_base(itf) + PINOUT_UART_RXD_OFF,
|
||||
pin_tx = PINOUT_itf_to_base(itf) + PINOUT_UART_TXD_OFF;
|
||||
|
||||
dma_channel_abort(STATEOF(itf).rx.dmach);
|
||||
dma_channel_abort(STATEOF(itf).tx.dmach);
|
||||
|
||||
deinit_sm(pio, &STATEOF(itf).rx, &ftdi_uart_rx_program);
|
||||
deinit_sm(pio, &STATEOF(itf).tx, &ftdi_uart_tx_program);
|
||||
|
||||
gpio_set_function(pin_rx, GPIO_FUNC_NULL);
|
||||
gpio_set_function(pin_tx, GPIO_FUNC_NULL);
|
||||
gpio_set_pulls(pin_rx, false, false);
|
||||
gpio_set_pulls(pin_tx, false, false);
|
||||
|
||||
STATEOF(itf).enabled = false;
|
||||
}
|
||||
void ftdi_if_uart_set_baudrate(struct ftdi_interface* itf, uint32_t baudrate) {
|
||||
if (!STATEOF(itf).enabled) return;
|
||||
|
||||
PIO pio = PINOUT_itf_to_pio(itf);
|
||||
int pin_rx = PINOUT_itf_to_base(itf) + PINOUT_UART_RXD_OFF,
|
||||
pin_tx = PINOUT_itf_to_base(itf) + PINOUT_UART_TXD_OFF;
|
||||
|
||||
ftdi_uart_rx_program_init(pio, STATEOF(itf).rx.sm, STATEOF(itf).rx.off,
|
||||
pin_rx, baudrate);
|
||||
ftdi_uart_tx_program_init(pio, STATEOF(itf).tx.sm, STATEOF(itf).tx.off,
|
||||
pin_tx, baudrate);
|
||||
|
||||
STATEOF(itf).baudrate = baudrate;
|
||||
}
|
||||
|
||||
|
||||
void ftdi_if_set_flowctrl(struct ftdi_interface* itf, enum ftdi_flowctrl flow) {
|
||||
// TODO: bluh
|
||||
(void)itf; (void)flow; // TODO: bluh
|
||||
}
|
||||
void ftdi_if_set_lineprop(struct ftdi_interface* itf, enum ftdi_sio_lineprop lineprop) {
|
||||
// TODO: break, stop, parity, #bits
|
||||
(void)itf; (void)lineprop; // TODO: break, stop, parity, #bits
|
||||
}
|
||||
|
||||
void ftdi_if_uart_write(struct ftdi_interface* itf, const uint8_t* data, size_t datasize) {
|
||||
// for writes, we can simply do a blocking DMA for now
|
||||
// TODO: rewrite to use background DMA I guess
|
||||
// (TODO: what if prev DMA still busy? --> overrun error!)
|
||||
// TODO: ^ will need status bits!
|
||||
|
||||
PIO pio = PINOUT_itf_to_pio(itf);
|
||||
|
||||
dma_channel_config dcfg = dma_channel_get_default_config(STATEOF(itf).tx.dmach);
|
||||
channel_config_set_read_increment(&dcfg, true);
|
||||
channel_config_set_write_increment(&dcfg, false);
|
||||
channel_config_set_dreq(&dcfg,
|
||||
DREQ_PIO0_TX0 + itf->index*8/*PIO num*/ + STATEOF(itf).tx.sm);
|
||||
channel_config_set_transfer_data_size(&dcfg, DMA_SIZE_8);
|
||||
dma_channel_configure(STATEOF(itf).tx.dmach, &dcfg,
|
||||
&pio->txf[STATEOF(itf).tx.sm], data, datasize, true);
|
||||
|
||||
// TODO: not this
|
||||
dma_channel_wait_for_finish_blocking(STATEOF(itf).tx.dmach);
|
||||
}
|
||||
size_t ftdi_if_uart_read(struct ftdi_interface* itf, uint8_t* data, size_t maxsize) {
|
||||
(void)itf; (void)data; (void)maxsize;
|
||||
|
||||
// TODO: background thing going to a buffer which is then collected later
|
||||
// on by this function, needs some buffer mgmt
|
||||
// TODO: handle overruns
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue