diff --git a/CMakeLists.txt b/CMakeLists.txt index 102a7ff..cd111ca 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -84,6 +84,7 @@ if(FAMILY STREQUAL "rp2040") pico_generate_pio_header(${PROJECT} ${CMAKE_CURRENT_SOURCE_DIR}/src/msp430/sbw.pio) pico_generate_pio_header(${PROJECT} ${CMAKE_CURRENT_SOURCE_DIR}/src/swim/swim.pio) pico_generate_pio_header(${PROJECT} ${CMAKE_CURRENT_SOURCE_DIR}/src/tool78/tool78.pio) + pico_generate_pio_header(${PROJECT} ${CMAKE_CURRENT_SOURCE_DIR}/src/glitch/trigctl.pio) pico_generate_pio_header(${PROJECT} ${CMAKE_CURRENT_SOURCE_DIR}/src/test/test.pio) pico_generate_pio_header(${PROJECT} ${CMAKE_CURRENT_SOURCE_DIR}/src/test/delay.pio) diff --git a/src/glitch/glitch.c b/src/glitch/glitch.c index 43de7b2..48b8fbf 100644 --- a/src/glitch/glitch.c +++ b/src/glitch/glitch.c @@ -8,6 +8,7 @@ #include #include #include + #include #include #include @@ -20,6 +21,8 @@ #include "glitch.h" +#include "trigctl.pio.h" + #define __STRINGIFY(f) #f #define STRINGIFY(f) __STRINGIFY(f) #define CORE0_FUNC(f) __scratch_x(STRINGIFY(f)) f @@ -33,6 +36,50 @@ volatile struct glitch_params glitch_param_cur = {0}; #define PCG_MULTIPLIER 6364136223846793005uLL static uint64_t mcg_state = 0xcafef00dd15ea5e5uLL; // Must be odd +static PIO trigctl_pio = NULL; +static uint trigctl_sm, trigctl_off; + +static int trigctl_pio_can_init(void) { + if (pio_can_add_program(pio0, &trigctl_program)) { + int r = pio_claim_unused_sm(pio0, false); + if (r >= 0) return r; + } + + if (pio_can_add_program(pio1, &trigctl_program)) { + int r = pio_claim_unused_sm(pio1, false); + if (r >= 0) return r + 4; + } + + return -1; +} +static void trigctl_pio_alloc_init(int piosm) { + trigctl_pio = (piosm & 4) ? pio1 : pio0; + trigctl_sm = piosm & 3; + + trigctl_off = pio_add_program(trigctl_pio, &trigctl_program); + + enum trigctl_source src = (param_cur.trigger_in_pin < 0) + ? trig_source_irq : trig_source_pin; + trigctl_pio_init(trigctl_pio, trigctl_sm, trigctl_off, + src, param_cur.glitch_out_pin, param_cur.trigger_in_pin, + //param_cur.trigger_in_polarity, param_cur.glitch_out_polarity + false // disabled by default; needs to be armed + ); + + param_cur.trigctl_pio = trigctl_pio; + param_cur.trigctl_sm = trigctl_sm; +} +static void trigctl_pio_deinit(void) { + if (trigctl_pio) { + pio_sm_set_enabled(trigctl_pio, trigctl_sm, false); + pio_sm_unclaim(trigctl_pio, trigctl_sm); + pio_remove_program(trigctl_pio, &trigctl_program, trigctl_off); + } + + trigctl_pio = NULL; + trigctl_off = trigctl_sm = ~(uint32_t)0; +} + static uint32_t CORE1_FUNC(pcg32_fast)(void) { uint64_t x = mcg_state; unsigned count = (unsigned)(x >> 61); // 61 = 64 - 3 @@ -76,98 +123,124 @@ static void CORE1_FUNC(pcg32_fast_init)(uint64_t seed) { param_cur.length_cur = len; \ } while (0) \ +__attribute__((__noreturn__)) +static void CORE1_FUNC(glitch_core1_thread_core1_fifoirq)(void) { + int32_t len_prev = param_cur.length_min_us - 1; + + SCB->SCR &= ~SCB_SCR_SEVONPEND_Msk; // don't resume WFE on interrupt + + const int irq = SIO_IRQ_PROC1; + + irq_set_enabled(irq, false); + multicore_fifo_clear_irq(); + irq_set_priority(irq, PICO_HIGHEST_IRQ_PRIORITY); + //delayt1_irq_enable(pio0); + //irq_set_exclusive_handler(irq, core1_irq); + __disable_irq(); + irq_set_enabled(irq, true); + + while (true) { + CORE1_PRE_CALC(); + bool arm = *(volatile bool*)¶m_cur.armed; + + __WFI(); + irq_set_enabled(irq, false); + if (!arm) goto continue_; + arm = *(volatile bool*)¶m_cur.armed; + if (!arm) goto continue_; + + CORE1_DO_GLITCH(); + multicore_fifo_drain(); + multicore_fifo_clear_irq(); + continue_: + irq_set_enabled(irq, true); + } +} +__attribute__((__noreturn__)) +static void CORE1_FUNC(glitch_core1_thread_core1_gpio)(void) { + int32_t len_prev = param_cur.length_min_us - 1; + + // init gpio irq + const int gpio = param_cur.trigger_in_pin; + const int irq = IO_IRQ_BANK0; + // always rising edge: already using input direction override in case + // of negative trigger input polarity + const int event = /*(param_cur.trigger_in_polarity == glitch_positive) + ?*/ GPIO_IRQ_EDGE_RISE /*: GPIO_IRQ_EDGE_FALL*/; + irq_set_enabled(irq, false); + iobank0_hw->intr[gpio>>3] = event << 4*(gpio&7); // acknowledge irq + irq_set_priority(irq, PICO_HIGHEST_IRQ_PRIORITY); + hw_set_bits(&iobank0_hw->proc1_irq_ctrl.inte[gpio>>3], event << 4*(gpio&7)); + irq_set_enabled(irq, true); + + while (true) { + CORE1_PRE_CALC(); + + __WFI(); + iobank0_hw->intr[gpio>>3] = event << 4*(gpio&7); // acknowledge irq + bool arm = *(volatile bool*)¶m_cur.armed; + if (!arm) continue; + + irq_set_enabled(irq, false); + //CORE1_DO_GLITCH(); + busy_wait_us_32(off); + if (!(sio_hw->gpio_in & (1u<gpio_set = iom; + asm volatile( + "1: sub %[counter], #1\n" + "cmp %[counter], #0\n" + "bne 1b\n" + :[counter]"+r"(len) + :: + ); + //busy_wait_us_32(len); + sio_hw->gpio_clr = iom; + + cont: + irq_set_enabled(irq, true); + } +} +__attribute__((__noreturn__)) +static void CORE1_FUNC(glitch_core1_thread_pio)(void) { + int32_t len_prev = param_cur.length_min_us - 1; + + const int irq = (trigctl_pio == pio0) ? PIO0_IRQ_1 : PIO1_IRQ_1; + irq_set_enabled(irq, false); + trigctl_ack_glitch_irq(trigctl_pio, trigctl_sm); + trigctl_set_glitch_irq_enabled(trigctl_pio, trigctl_sm, 1, true); + irq_set_priority(irq, PICO_HIGHEST_IRQ_PRIORITY); + irq_set_enabled(irq, true); + + while (true) { + CORE1_PRE_CALC(); + (void)iom; + trigctl_push_off_len(trigctl_pio, trigctl_sm, off, len); + + trigctl_wait_glitch_irq(trigctl_pio, trigctl_sm, true); + trigctl_ack_glitch_irq(trigctl_pio, trigctl_sm); + } +} + +__attribute__((__noreturn__)) static void CORE1_FUNC(glitch_core1_thread)(void) { // use stdlib randomness only for the seed, but use a custom rng sitting in // SRAM 5 to avoid bus contention pcg32_fast_init(random()); - int32_t len_prev = param_cur.length_min_us - 1; - __disable_irq(); - if (param_cur.trigger_in_pin < 0) { - SCB->SCR &= ~SCB_SCR_SEVONPEND_Msk; // don't resume WFE on interrupt - - const int irq = SIO_IRQ_PROC1; - - irq_set_enabled(irq, false); - multicore_fifo_clear_irq(); - irq_set_priority(irq, PICO_HIGHEST_IRQ_PRIORITY); - //delayt1_irq_enable(pio0); - //irq_set_exclusive_handler(irq, core1_irq); - __disable_irq(); - irq_set_enabled(irq, true); - - while (true) { - CORE1_PRE_CALC(); - bool arm = *(volatile bool*)¶m_cur.armed; - - __WFI(); - irq_set_enabled(irq, false); - if (!arm) goto continue_; - arm = *(volatile bool*)¶m_cur.armed; - if (!arm) goto continue_; - - CORE1_DO_GLITCH(); - multicore_fifo_drain(); - multicore_fifo_clear_irq(); - continue_: - irq_set_enabled(irq, true); - } - - /*while (true) { - CORE1_PRE_CALC(); - bool arm = *(volatile bool*)¶m_cur.armed; - - __WFE(); - if (!arm) continue; - arm = *(volatile bool*)¶m_cur.armed; - if (!arm) continue; - - CORE1_DO_GLITCH(); - }*/ - } else { - // init gpio irq - const int gpio = param_cur.trigger_in_pin; - const int irq = IO_IRQ_BANK0; - const int event = GPIO_IRQ_EDGE_RISE; - irq_set_enabled(irq, false); - iobank0_hw->intr[gpio>>3] = event << 4*(gpio&7); // acknowledge irq - irq_set_priority(irq, PICO_HIGHEST_IRQ_PRIORITY); - hw_set_bits(&iobank0_hw->proc1_irq_ctrl.inte[gpio>>3], event << 4*(gpio&7)); - irq_set_enabled(irq, true); - - while (true) { - CORE1_PRE_CALC(); - - __WFI(); - iobank0_hw->intr[gpio>>3] = event << 4*(gpio&7); // acknowledge irq - bool arm = *(volatile bool*)¶m_cur.armed; - if (!arm) continue; - - irq_set_enabled(irq, false); - //CORE1_DO_GLITCH(); - busy_wait_us_32(off); - if (!(sio_hw->gpio_in & (1u<gpio_set = iom; - asm volatile( - "1: sub %[counter], #1\n" - "cmp %[counter], #0\n" - "bne 1b\n" - :[counter]"+r"(len) - :: - ); - //busy_wait_us_32(len); - sio_hw->gpio_clr = iom; - - cont: - irq_set_enabled(irq, true); + if (param_cur.impl == glitch_impl_pio) { + glitch_core1_thread_pio(); + } else if (param_cur.impl == glitch_impl_core1) { + if (param_cur.trigger_in_pin < 0) { + glitch_core1_thread_core1_fifoirq(); + } else { + glitch_core1_thread_core1_gpio(); } } - // TODO: PIO variant? } #undef CORE1_DO_GLITCH @@ -178,7 +251,7 @@ static void CORE0_FUNC(glitch_stop_no_clock_chg)(void) { if (param_cur.impl != glitch_impl__none) { if (param_cur.impl == glitch_impl_pio) { - // TODO: deinit PIO when implemented + trigctl_pio_deinit(); } // deinit GPIO @@ -234,6 +307,12 @@ bool CORE0_FUNC(glitch_ready)(const struct glitch_params* params) { if (params->impl != glitch_impl_core1 && params->impl != glitch_impl_pio) return false; + int r = 0x99990; + if (params->impl == glitch_impl_pio) { + r = trigctl_pio_can_init(); + if (r < 0) return false; + } + glitch_stop(); memcpy(¶m_cur, params, sizeof param_cur); // apply new params @@ -248,9 +327,15 @@ bool CORE0_FUNC(glitch_ready)(const struct glitch_params* params) { vreg_set_voltage(VREG_VOLTAGE_1_15); set_sys_clock_khz(200*1000, true); - uint func = GPIO_FUNC_SIO; // TODO: PIO when implemented + uint func = GPIO_FUNC_SIO; + if (params->impl == glitch_impl_pio) { + trigctl_pio_alloc_init(r); + func = (trigctl_pio == pio0) ? GPIO_FUNC_PIO0 : GPIO_FUNC_PIO1; + } if (params->length_min_us < 0) { + // FIXME: use a more generic approach (using dragonzap adc) + // ADC1: ADC mode adc_init(); adc_gpio_init(27); @@ -287,7 +372,7 @@ bool CORE0_FUNC(glitch_ready)(const struct glitch_params* params) { } //gpio_put(params->glitch_out_pin, false); - // TODO: gpio_set_drive_strength(PIN_PULSE, GPIO_DRIVE_STRENGTH_12MA); + //gpio_set_drive_strength(PIN_PULSE, GPIO_DRIVE_STRENGTH_12MA); //gpio_set_slew_rate(params->glitch_out_pin, GPIO_SLEW_RATE_FAST); //gpio_set_dir(params->glitch_out_pin, GPIO_OUT); //gpio_set_outover(params->glitch_out_pin, diff --git a/src/glitch/glitch.h b/src/glitch/glitch.h index 04a61e8..8d75277 100644 --- a/src/glitch/glitch.h +++ b/src/glitch/glitch.h @@ -6,6 +6,8 @@ #include #include +#include + enum glitch_polarity { glitch_positive, glitch_negative, @@ -19,6 +21,8 @@ enum glitch_impl { struct glitch_params { uint32_t offset_min_us; uint32_t offset_max_us; + // FIXME: use a more generic approach (using dragonzap adc) + // for using user-tunable lengths (with physical knobs) int32_t length_min_us; int32_t length_max_us; int trigger_in_pin; // use -1 for a signal coming from core 0 @@ -27,6 +31,8 @@ struct glitch_params { enum glitch_polarity glitch_out_polarity; enum glitch_impl impl; uint32_t offset_cur, length_cur; + PIO trigctl_pio; + uint32_t trigctl_sm; bool armed; }; @@ -41,14 +47,25 @@ static inline void glitch_trigger_sw_core1(void) { sio_hw->fifo_wr = 1; } static inline void glitch_trigger_sw_pio(void) { - // TODO: implement + glitch_param_cur.trigctl_pio->irq_force = + 1 << ((glitch_param_cur.trigctl_sm + 1) & 3); + /*trigctl_send_trig_irq(glitch_param_cur.trigctl_pio, + glitch_param_cur.trigctl_sm);*/ } static inline void glitch_arm(void) { glitch_param_cur.armed = true; + if (glitch_param_cur.impl == glitch_impl_pio) { + pio_sm_set_enabled(glitch_param_cur.trigctl_pio, + glitch_param_cur.trigctl_sm, true); + } } static inline void glitch_disarm(void) { glitch_param_cur.armed = false; + if (glitch_param_cur.impl == glitch_impl_pio) { + pio_sm_set_enabled(glitch_param_cur.trigctl_pio, + glitch_param_cur.trigctl_sm, false); + } } #endif diff --git a/src/glitch/trigctl.pio b/src/glitch/trigctl.pio new file mode 100644 index 0000000..15e32cc --- /dev/null +++ b/src/glitch/trigctl.pio @@ -0,0 +1,101 @@ + +.program trigctl + +; autopull should be on, depth 32 +; +; input pin 0: trigger input +; +; set pin 0: glitch output +; +; irq 0 rel: PIO->CM0 "has glitched" signal +; irq 1 rel: CM0->PIO "do a glitch now" signal + +public _start: + out x, 32 ; offset + out y, 32 ; length + + irq clear 0 rel + +public waitinsn: + wait 1 pin 0 ; or "wait irq 1 rel" + +offloop: + jmp x-- offloop + + set pins, 1 + +lenloop: + jmp y-- lenloop + + set pins, 0 + + irq set 0 rel + +% c-sdk { + +enum trigctl_source { + trig_source_pin, + trig_source_irq +}; + +static inline void trigctl_pio_init(PIO pio, uint sm, uint prog_offs, + enum trigctl_source trigsrc, uint glitch_pin, uint trig_pin/*, + enum glitch_polarity trig_in_pol, enum glitch_polarity glitch_out_pol*/ + , bool enable) { + pio_sm_set_enabled(pio, sm, false); + + if (trigsrc == trig_source_irq) { + pio->instr_mem[prog_offs + trigctl_offset_waitinsn] = + pio_encode_wait_irq(true, true, 1); + } else { + pio->instr_mem[prog_offs + trigctl_offset_waitinsn] = + pio_encode_wait_pin(true, 0); + } + + pio_sm_config c = trigctl_program_get_default_config(prog_offs); + sm_config_set_set_pins(&c, glitch_pin, 1); + sm_config_set_in_pins(&c, trig_pin/*, 1*/); + sm_config_set_out_shift(&c, false, true, 32); + sm_config_set_in_shift(&c, false, true, 32); + sm_config_set_clkdiv(&c, 1); + pio_sm_init(pio, sm, prog_offs, &c); + + pio_sm_set_consecutive_pindirs(pio, sm, glitch_pin, 1, true ); + pio_sm_set_consecutive_pindirs(pio, sm, trig_pin , 1, false); + pio_sm_set_pins_with_mask(pio, sm, 0, 1u << glitch_pin); + + pio_sm_set_enabled(pio, sm, enable); + pio_gpio_init(pio, glitch_pin); + pio_gpio_init(pio, trig_pin); +} + +// ony use "use_wfi" when the corresponding IRQ is enabled in the NVIC +static inline void trigctl_wait_glitch_irq(PIO pio, uint sm, bool use_wfi) { + uint mask = 1u << ((sm + 0) & 3); + if (use_wfi) { + while (!(pio->irq & mask)) __WFI(); + } else { + while (!(pio->irq & mask)) ; + } +} +static inline void trigctl_ack_glitch_irq(PIO pio, uint sm) { + hw_set_bits(&pio->irq, 1 << ((sm + 0) & 3)); +} +// nvic_irqno: corresponding NVIC IRQ will be PIO${pio}_IRQ${nvic_irqno} +static inline void trigctl_set_glitch_irq_enabled(PIO pio, uint sm, uint nvic_irqno, bool en) { + pio_set_irqn_source_enabled(pio, nvic_irqno, (sm + 0) & 3, en); +} + +/*static inline void trigctl_send_trig_irq(PIO pio, uint sm) { + pio->irq_force = 1 << ((sm + 1) & 3); +}*/ + +static inline void trigctl_push_off_len(PIO pio, uint sm, uint32_t off, uint32_t len) { + while (pio_sm_is_tx_fifo_full(pio, sm)) ; + pio->txf[sm] = off; + while (pio_sm_is_tx_fifo_full(pio, sm)) ; + pio->txf[sm] = len; +} + +%} +