Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HW Trigger #22

Open
X-Ryl669 opened this issue Jul 7, 2022 · 2 comments
Open

HW Trigger #22

X-Ryl669 opened this issue Jul 7, 2022 · 2 comments

Comments

@X-Ryl669
Copy link

X-Ryl669 commented Jul 7, 2022

This project seems to have a very smart implementation of HW trigger that's using PIO code to handle many triggering conditions in only 2 cycles (so 100Msps is achievable).

@pico-coder
Copy link
Owner

Tracking this here:
gusmanb/logicanalyzer#4

@rgrr
Copy link

rgrr commented Jan 15, 2023

If you are interested, I have implemented some kind of auto trigger for my sigrok-pico module. Auto triggering works til 1/7 of system clock, on my probe these are 24MHz.

See here: https://github.com/rgrr/yapicoprobe, especially https://github.com/rgrr/yapicoprobe/blob/master/src/pico-sigrok/sigrok.pio

Code fragment to switch between the generated fetch and the above:

/**
 * Setup PIO operation.
 * PIO is configured, so that it reads input in \a sr_dev.pin_count chunks and writes the data in 32bit words.
 * That means, that 4bit reads require 8 samples to do one 32bit write and so on.
 *
 * \note
 *    used PIO is \a SIGROK_PIO.
 *
 * \pre
 *    - sr_dev.d_mask != 0
 *    - sr_dev.pin_count (4/8/16/32) and sr_dev.sample_rate must be set
 *    - sr_dev.sample_rate must be a multiple of 1000
 *
 * \post
 *    - PIO is configured but not started
 *    - unused pins within pincount are pulled down to prevent those lines from false triggers
 */
static void setup_pio(void)
{
    const uint32_t trigger_delay = 7;      // see sigrok.pio
    uint32_t sample_rate_khz = 0;
    pio_sm_config pio_conf;
    uint offset;
    uint32_t f_clk_sys = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_SYS);

    assert(sr_dev.d_mask != 0);
    assert(sr_dev.pin_count == 4  ||  sr_dev.pin_count == 8  ||  sr_dev.pin_count == 16  || sr_dev.pin_count == 32);

    pio_clear_instruction_memory(SIGROK_PIO);

    if (sr_dev.sample_rate / 1000 <= f_clk_sys / trigger_delay  &&  sr_dev.a_mask == 0) {
        //
        // Auto triggering for 4/8/16bit: acquisition is triggered if there are changes on the enabled input lines
        // TODO currently no auto trigger with analog/digital signal mix
        //
        Dprintf("Capturing with auto trigger\n");
        if (sr_dev.pin_count == 4) {
            offset = pio_add_program(SIGROK_PIO, &sigrok_d4_triggered_program);
            pio_conf = sigrok_d4_triggered_program_get_default_config(offset);
            sample_rate_khz = (trigger_delay * sr_dev.sample_rate) / 1000;
        }
        else if (sr_dev.pin_count == 8) {
            offset = pio_add_program(SIGROK_PIO, &sigrok_1b_triggered_program);
            pio_conf = sigrok_1b_triggered_program_get_default_config(offset);
            sample_rate_khz = (trigger_delay * sr_dev.sample_rate) / 1000;
        }
        else if (sr_dev.pin_count == 16) {
            offset = pio_add_program(SIGROK_PIO, &sigrok_2b_triggered_program);
            pio_conf = sigrok_2b_triggered_program_get_default_config(offset);
            sample_rate_khz = (trigger_delay * sr_dev.sample_rate) / 1000;
        }
    }

    if (sample_rate_khz == 0) {
        //
        // this is too fast for auto triggering: just do sampling of the input
        //
        uint16_t capture_prog_instr;

        Dprintf("Fast immediate capturing\n");
        capture_prog_instr = pio_encode_in(pio_pins, sr_dev.pin_count);
        struct pio_program capture_prog = {
                .instructions = &capture_prog_instr,
                .length = 1,
                .origin = -1
        };
        offset = pio_add_program(SIGROK_PIO, &capture_prog);
        // Configure state machine to loop over this `in` instruction forever,
        // with autopush enabled.
        pio_conf = pio_get_default_sm_config();
        sm_config_set_wrap(&pio_conf, offset, offset);
        sample_rate_khz = sr_dev.sample_rate / 1000;
    }

    uint32_t div_256 = (256 * f_clk_sys + sample_rate_khz / 2) / sample_rate_khz;
    uint32_t div_int  = div_256 >> 8;
    uint32_t div_frac = div_256 & 0xff;
    if (div_int == 0) {
        div_int  = 1;
        div_frac = 0;
    }
    else if (div_int > 0xffff) {
        div_int  = 0xffff;
        div_frac = 0xff;
    }
    Dprintf("PIO sample clk %lukHz / (%lu + %lu/256) = %lukHz, requested %lukHz\n",
            f_clk_sys, div_int, div_frac, sample_rate_khz, sr_dev.sample_rate / 1000);
    sm_config_set_clkdiv_int_frac(&pio_conf, div_int, div_frac);

    sm_config_set_in_pins(&pio_conf, SR_BASE_D_CHAN);                                // start at SR_BASE_D_CHAN
                                                                                     // enable pull-down on unused pins within pin_count
    for (int i = 0;  i < (sr_dev.pin_count < SR_NUM_D_CHAN ? sr_dev.pin_count : SR_NUM_D_CHAN);  ++i) {
        if ((sr_dev.d_mask & (1 << i)) == 0) {
            // pull down seems to be less noise sensitive
            gpio_pull_down(SR_BASE_D_CHAN + i);
        }
    }

    sm_config_set_in_shift(&pio_conf, true, true, 32);                               // shift right, autopush, threshold=32
    sm_config_set_fifo_join(&pio_conf, PIO_FIFO_JOIN_RX);
    pio_sm_init(SIGROK_PIO, SIGROK_SM, offset, &pio_conf);
    pio_sm_set_enabled(SIGROK_PIO, SIGROK_SM, false);
    pio_sm_clear_fifos(SIGROK_PIO, SIGROK_SM);
    pio_sm_restart(SIGROK_PIO, SIGROK_SM);
}   // setup_pio

And in the CMakeLists.txt one has to add:

pico_generate_pio_header(picoprobe ${CMAKE_CURRENT_LIST_DIR}/src/pico-sigrok/sigrok.pio)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants