WIP refactoring

This commit is contained in:
Triss 2021-07-18 01:22:56 +02:00
parent 7056224c4f
commit 4eea88b4f1
5 changed files with 571 additions and 548 deletions

View File

@ -13,6 +13,7 @@ add_executable(picoprobe
src/probe.c
src/cdc_uart.c
src/cdc_sump.c
src/cdc_sump_pico.c
src/get_serial.c
)

File diff suppressed because it is too large Load Diff

View File

@ -53,10 +53,124 @@ inline static int SUMP_CMD_IS_SHORT(int cmd) {
return !(cmd & 0x80); // crude but works
}
void __isr sump_dma_irq_handler(void);
/* **** */
#if 0
#define sump_irq_debug(format,args...) picoprobe_debug(format, ## args)
#else
#define sump_irq_debug(format,...) ((void)0)
#endif
#define CDC_INTF 1
#define SAMPLING_DIVIDER 4 // minimal sysclk sampling divider
#define SAMPLING_GPIO_FIRST 6
#define SAMPLING_GPIO_LAST 21
#define SAMPLING_BITS (SAMPLING_GPIO_LAST-SAMPLING_GPIO_FIRST+1)
#define SAMPLING_BYTES ((SAMPLING_BITS+7)/8)
#define SAMPLING_GPIO_MASK (((1 << SAMPLING_BITS) - 1) << SAMPLING_GPIO_FIRST)
#define SAMPLING_GPIO_TEST 22
#if SAMPLING_BITS != 8 && SAMPLING_BITS != 16
#error "Correct sampling width (8 or 16 bits)"
#endif
#define SAMPLING_PIO pio1
#define SAMPLING_PIO_SM 0u
#define SAMPLING_DMA_IRQ DMA_IRQ_1
#define sump_dma_set_irq_channel_mask_enabled dma_set_irq1_channel_mask_enabled
#define sump_dma_ints (dma_hw->ints1)
#define SUMP_SAMPLE_MASK ((1<<SAMPLING_BITS)-1)
#define SUMP_BYTE0_OR ((~SUMP_SAMPLE_MASK) & 0xff)
#define SUMP_BYTE1_OR ((~SUMP_SAMPLE_MASK >> 8) & 0xff)
#define SUMP_DMA_CH_FIRST 0
#define SUMP_DMA_CH_LAST 7
#define SUMP_DMA_CHANNELS (SUMP_DMA_CH_LAST-SUMP_DMA_CH_FIRST+1)
#define SUMP_DMA_MASK (((1<<SUMP_DMA_CHANNELS)-1) << SUMP_DMA_CH_FIRST)
#if PICO_NO_FLASH
#define SUMP_MEMORY_SIZE 102400 // 100kB
#else
#define SUMP_MEMORY_SIZE 204800 // 200kB
#endif
#define SUMP_MAX_CHUNK_SIZE 4096
#if (SUMP_MEMORY_SIZE % SUMP_MAX_CHUNK_SIZE) != 0
#error "Invalid maximal chunk size!"
#endif
#if (SUMP_MEMORY_SIZE / SUMP_MAX_CHUNK_SIZE) < SUMP_DMA_CHANNELS
#error "DMA buffer and DMA channels out of sync!"
#endif
#define SUMP_STATE_CONFIG 0
#define SUMP_STATE_INIT 1
#define SUMP_STATE_TRIGGER 2
#define SUMP_STATE_SAMPLING 3
#define SUMP_STATE_DUMP 4
#define SUMP_STATE_ERROR 5
#define ONE_MHZ 1000000u
/* **** */
void sump_set_chunk_size(void);
uint32_t sump_calc_sysclk_divider();
void sump_rx(uint8_t *buf, uint count);
void cdc_sump_init(void);
void cdc_sump_task(void);
void cdc_sump_line_coding(cdc_line_coding_t const *line_coding);
void sump_hw_init(void);
void sump_hw_stop(void);
uint32_t sump_hw_get_sysclk(void);
uint64_t sump_hw_xfer_start(uint8_t width, int flags);
void sump_hw_xfer_stop(void);
void __isr sump_dma_irq_handler(void);
struct _trigger {
uint32_t mask;
uint32_t value;
uint16_t delay;
uint8_t channel;
uint8_t level;
bool serial;
bool start;
};
struct _sump {
/* internal states */
bool cdc_connected;
uint8_t cmd[5]; // command
uint8_t cmd_pos; // command buffer position
uint8_t state; // SUMP_STATE_*
uint8_t width; // in bytes, 1 = 8 bits, 2 = 16 bits
uint8_t trigger_index;
uint32_t pio_prog_offset;
uint32_t read_start;
uint64_t timestamp_start;
/* protocol config */
uint32_t divider; // clock divider
uint32_t read_count;
uint32_t delay_count;
uint32_t flags;
struct _trigger trigger[4];
/* DMA buffer */
uint32_t chunk_size; // in bytes
uint32_t dma_start;
uint32_t dma_count;
uint32_t dma_curr_idx; // current DMA channel (index)
uint32_t dma_pos;
uint32_t next_count;
uint8_t buffer[SUMP_MEMORY_SIZE];
};
extern struct _sump sump;
#endif

238
src/cdc_sump_pico.c Normal file
View File

@ -0,0 +1,238 @@
#include <pico/stdlib.h>
#include <hardware/clocks.h>
#include <hardware/irq.h>
#include <hardware/pio.h>
#include <hardware/dma.h>
#include <hardware/pwm.h>
#include <hardware/sync.h>
#include <hardware/structs/bus_ctrl.h>
#include "picoprobe_config.h"
#include "cdc_sump.h"
uint32_t pio_prog_offset;
uint32_t sump_hw_get_sysclk(void)
{
return clock_get_hz(clk_sys);
}
static void sump_pio_init(uint8_t width, bool nogr0)
{
pio_sm_config c;
uint off, gpio = SAMPLING_GPIO_FIRST, divider;
#if SAMPLING_BITS > 8
if (width == 1 && nogr0)
gpio += 8;
#endif
// loop the IN instruction forewer (8-bit and 16-bit version)
c = pio_get_default_sm_config();
sm_config_set_in_pins(&c, gpio);
off = pio_prog_offset + (width - 1);
sm_config_set_wrap(&c, off, off);
divider = sump_calc_sysclk_divider();
sm_config_set_clkdiv_int_frac(&c, divider >> 8, divider & 0xff);
sm_config_set_in_shift(&c, true, true, 32);
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_RX);
pio_sm_init(SAMPLING_PIO, SAMPLING_PIO_SM, off, &c);
picoprobe_debug("%s(): pc=0x%02x [0x%02x], gpio=%u\n", __func__,
off, pio_prog_offset, gpio);
}
static void sump_pio_program(void)
{
uint16_t prog[] = {
pio_encode_in(pio_pins, 8),
pio_encode_in(pio_pins, 16)
};
struct pio_program program = {
.instructions = prog,
.length = count_of(prog),
.origin = -1
};
picoprobe_debug("%s(): 0x%04x 0x%04x len=%u\n", __func__, prog[0], prog[1], program.length);
pio_prog_offset = pio_add_program(SAMPLING_PIO, &program); // TODO
}
static uint32_t sump_pwm_slice_init(uint gpio, uint clock, bool swap_levels)
{
uint32_t clksys = sump_hw_get_sysclk(), clkdiv, slice, tmp;
uint16_t top = 5, level_a = 1, level_b = 4;
// correction for low speed PWM
while ((clksys / clock / top) & ~0xff) {
top *= 1000;
level_a *= 1000;
level_b *= 1000;
}
clkdiv = clksys / clock / top;
// pwm setup
slice = pwm_gpio_to_slice_num(gpio);
gpio_set_function(gpio, GPIO_FUNC_PWM);
gpio_set_function(gpio + 1, GPIO_FUNC_PWM);
pwm_config c = pwm_get_default_config();
pwm_config_set_wrap(&c, top - 1);
pwm_config_set_clkdiv_int(&c, clkdiv);
pwm_init(slice, &c, false);
if (swap_levels) {
uint16_t tmp = level_a;
level_a = level_b;
level_b = tmp;
}
pwm_set_both_levels(slice, level_a, level_b);
picoprobe_debug("%s(): gpio=%u clkdiv=%u top=%u level=%u/%u freq=%.4fMhz (req %.4fMhz)\n",
__func__, gpio, clkdiv, top, level_a, level_b,
(float)clksys / (float)clkdiv / (float)top / 1000000.0,
(float)clock / 1000000.0);
return 1u << slice;
}
static uint32_t sump_calib_init(void)
{
uint32_t clksys = sump_hw_get_sysclk(), clkdiv, slice;
const uint32_t clock = 5 * ONE_MHZ;
const uint16_t top = 10, level_a = 5;
// set 5Mhz PWM on test pin
// should not go beyond 255!
clkdiv = clksys / clock / top;
// pwm setup
slice = pwm_gpio_to_slice_num(SAMPLING_GPIO_TEST);
gpio_set_function(SAMPLING_GPIO_TEST, GPIO_FUNC_PWM);
pwm_config c = pwm_get_default_config();
pwm_config_set_wrap(&c, top - 1);
pwm_config_set_clkdiv_int(&c, clkdiv);
pwm_init(slice, &c, false);
pwm_set_both_levels(slice, level_a, level_a);
picoprobe_debug("%s(): gpio=%u clkdiv=%u top=%u level=%u/%u freq=%.4fMhz (req %.4fMhz)\n",
__func__, SAMPLING_GPIO_TEST, clkdiv, top, level_a, level_a,
(float)clksys / (float)clkdiv / (float)top / 1000000.0,
(float)clock / 1000000.0);
return 1u << slice;
}
static uint32_t sump_test_init(void)
{
// Initialize test PWMs
const uint32_t gpio = SAMPLING_GPIO_FIRST;
uint32_t mask;
// 10Mhz PWM
mask = sump_pwm_slice_init(gpio, 10000000, false);
// 1Mhz PWM
mask |= sump_pwm_slice_init(gpio + 2, 1000000, false);
// 1kHz PWM
mask |= sump_pwm_slice_init(gpio + 4, 1000, false);
#if SAMPLING_BITS > 8
// 1kHz PWM (second byte)
mask |= sump_pwm_slice_init(gpio + 8, 1000, true);
#endif
return mask;
}
static void sump_test_done(void)
{
const uint32_t gpio = SAMPLING_GPIO_FIRST;
uint32_t i;
pwm_set_enabled(pwm_gpio_to_slice_num(gpio), false);
pwm_set_enabled(pwm_gpio_to_slice_num(gpio + 2), false);
pwm_set_enabled(pwm_gpio_to_slice_num(gpio + 4), false);
#if SAMPLING_BITS > 8
pwm_set_enabled(pwm_gpio_to_slice_num(gpio + 8), false);
#endif
for (i = SAMPLING_GPIO_FIRST; i <= SAMPLING_GPIO_LAST; i++)
gpio_set_function(i, GPIO_FUNC_NULL);
// test pin
pwm_set_enabled(SAMPLING_GPIO_TEST, false);
}
uint64_t sump_hw_xfer_start(uint8_t width, int flags)
{
uint32_t pwm_mask = 0, irq_state, i;
sump_pio_init(width, flags & SUMP_FLAG1_GR0_DISABLE);
pwm_mask = sump_calib_init();
if (flags & SUMP_FLAG1_EXT_TEST) {
pwm_mask |= sump_test_init();
} else {
sump_test_done();
}
// limit chunk size for slow sampling
sump_set_chunk_size();
for (i = 0; i < SUMP_DMA_CHANNELS; i++)
sump_dma_program(i, i * sump.chunk_size);
// let's go
irq_state = save_and_disable_interrupts();
pio_sm_set_enabled(SAMPLING_PIO, SAMPLING_PIO_SM, true);
if (pwm_mask)
pwm_set_mask_enabled(pwm_mask);
dma_channel_start(SUMP_DMA_CH_FIRST);
irq_set_enabled(SAMPLING_DMA_IRQ, true);
restore_interrupts(irq_state);
return time_us_64();
}
void sump_hw_xfer_stop(void)
{
pio_sm_set_enabled(SAMPLING_PIO, SAMPLING_PIO_SM, false);
irq_set_enabled(SAMPLING_DMA_IRQ, false);
}
void sump_hw_init(void)
{
uint i;
// claim DMA channels
dma_claim_mask(SUMP_DMA_MASK);
// claim PIO state machine and add program
pio_claim_sm_mask(SAMPLING_PIO, 1u << SAMPLING_PIO_SM);
sump_pio_program();
// high bus priority to the DMA
bus_ctrl_hw->priority = BUSCTRL_BUS_PRIORITY_DMA_W_BITS | BUSCTRL_BUS_PRIORITY_DMA_R_BITS;
// GPIO init
gpio_set_dir_in_masked(SAMPLING_GPIO_MASK);
gpio_put_masked(SAMPLING_GPIO_MASK, 0);
for (i = SAMPLING_GPIO_FIRST; i <= SAMPLING_GPIO_LAST; i++) {
gpio_set_function(i, GPIO_FUNC_NULL);
gpio_set_pulls(i, false, false);
}
// test GPIO pin
gpio_set_dir(SAMPLING_GPIO_TEST, true);
gpio_put(SAMPLING_GPIO_TEST, true);
gpio_set_function(SAMPLING_GPIO_TEST, GPIO_FUNC_PWM);
// set exclusive interrupt handler
irq_set_enabled(SAMPLING_DMA_IRQ, false);
irq_set_exclusive_handler(SAMPLING_DMA_IRQ, sump_dma_irq_handler);
sump_dma_set_irq_channel_mask_enabled(SUMP_DMA_MASK, true);
}
void sump_hw_stop(void)
{
uint32_t i;
// IRQ and PIO fast stop
irq_set_enabled(SAMPLING_DMA_IRQ, false);
pio_sm_set_enabled(SAMPLING_PIO, SAMPLING_PIO_SM, false);
// DMA abort
for (i = SUMP_DMA_CH_FIRST; i <= SUMP_DMA_CH_LAST; i++)
dma_channel_abort(i);
// IRQ status cleanup
sump_dma_ints = SUMP_DMA_MASK;
// PIO cleanup
pio_sm_clear_fifos(SAMPLING_PIO, SAMPLING_PIO_SM);
pio_sm_restart(SAMPLING_PIO, SAMPLING_PIO_SM);
// test
sump_test_done();
}

View File

@ -44,6 +44,7 @@
// UART0 for Picoprobe debug
// UART1 for picoprobe to target device
void cdc_sump_line_coding(cdc_line_coding_t const *line_coding);
void tud_cdc_line_coding_cb(uint8_t itf, cdc_line_coding_t const* line_coding) {
if (itf == 0)
cdc_uart_line_coding(line_coding);
@ -77,4 +78,4 @@ int main(void) {
}
return 0;
}
}