ftdi uart stuff (WIP)

This commit is contained in:
Triss 2021-09-16 03:33:46 +02:00
parent 1e9cac1ace
commit 3b76c6fb4a
15 changed files with 504 additions and 46 deletions

View File

@ -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()

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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: ? */ }

View File

@ -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

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}
%}

View File

@ -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++);
}
%}

View File

@ -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;
}

View File

@ -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;
}

133
bsp/rp2040/m_ftdi/pinout.h Normal file
View File

@ -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

View File

@ -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;
}

View File

@ -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;
}