Quantcast
Viewing all articles
Browse latest Browse all 4852

SDK • Re: ADC PIO 128bit read, DMA gets stuck after 200 transfers

1.
Does DMA automatically wait for fifo content? I thought it did not so I start the DMA transfer with rx fifo full.
Are you saying I should have the irq dma trigger after the busy wait?

2.
gpio is what intended to put.

3. 4.
ill fix that and try it

5.
I cant specify 16bit with push, so thats why i changed my code to work with 32bit chunks

6.
I was trying anything by that point, im only interesting in seeing successful reads atm, so the databuffer takes in the 128bits data and allows me to process it as a uint16 array.

7.
I was trying things to figure out where the stall/hang was coming from.

8.
I see. I was checking if it would go further with larger memory allocated, it did not.


So I changed it to autopush with 16bits, im only getting two samples.
18:36:34:414 -> hello
18:36:37:414 -> init
18:36:37:415 -> Initializing PIO SPI at offset:23
18:36:37:418 -> pio clkdiv: 20.833334
18:36:37:419 -> pwm f: 1000.000000 w: 500 c: 250.000000
18:36:37:423 -> piocount: 1, int: 0 1 0 0
18:36:37:426 -> 0 0 0 127 65535 49152 31 65024 dma handler 1
18:36:37:430 -> piocount: 2, int: 1 0 0 0
18:36:37:432 -> piocount: 3, int: 0 1 0 0
18:36:37:533 -> 0 0 0 127 65535 49152 31 65024 dma handler 1
18:36:37:536 -> dma: 1 9.198870/s, pio: 3 27.596611/s, fifo: 0 1
I also tried with tightened timings, dma reads all 0, so it doesnt seem to wait for fifo autopush/data.

Updated code:

ad7606_spi.pio.h

Code:

// -------------------------------------------------- //// This file is autogenerated by pioasm; do not edit! //// -------------------------------------------------- //#pragma once#if !PICO_NO_HARDWARE#include "hardware/pio.h"#endif// ---------------------- //// ad7606_spi_128bit_read //// ---------------------- //#define ad7606_spi_128bit_read_wrap_target 0#define ad7606_spi_128bit_read_wrap 8static const uint16_t ad7606_spi_128bit_read_program_instructions[] = {            //     .wrap_target    0x288a, //  0: wait   1 gpio, 10      side 1         0x280a, //  1: wait   0 gpio, 10      side 1         0xc821, //  2: irq    wait 1          side 1         0xe847, //  3: set    y, 7            side 1         0xe12f, //  4: set    x, 15           side 0 [1]     0x5101, //  5: in     pins, 1         side 2 [1]     0x0145, //  6: jmp    x--, 5          side 0 [1]     0x0884, //  7: jmp    y--, 4          side 1         0xcf20, //  8: irq    wait 0          side 1 [7]             //     .wrap};#if !PICO_NO_HARDWAREstatic const struct pio_program ad7606_spi_128bit_read_program = {    .instructions = ad7606_spi_128bit_read_program_instructions,    .length = 9,    .origin = -1,};static inline pio_sm_config ad7606_spi_128bit_read_program_get_default_config(uint offset) {    pio_sm_config c = pio_get_default_sm_config();    sm_config_set_wrap(&c, offset + ad7606_spi_128bit_read_wrap_target, offset + ad7606_spi_128bit_read_wrap);    sm_config_set_sideset(&c, 2, false, false);    return c;}// this is a raw helper function for use by the user which sets up the GPIO output, and configures the SM to output on a particular pinvoid ad7606_spi_128bit_init(PIO pio, uint sm, uint offset, float clkdiv, uint pin_sck, uint pin_miso, uint pin_cs, uint pin_busy) {pio_sm_config c = ad7606_spi_128bit_read_program_get_default_config(offset);pio_gpio_init(pio, pin_cs);pio_gpio_init(pio, pin_sck);pio_gpio_init(pio, pin_miso);pio_gpio_init(pio, pin_busy);sm_config_set_in_shift(&c, false, true, 16);sm_config_set_sideset_pins(&c, pin_cs);pio_sm_set_consecutive_pindirs(pio, sm, pin_cs, 2, true);pio_sm_set_consecutive_pindirs(pio, sm, pin_miso, 1, false);pio_sm_set_in_pins(pio, sm, pin_miso);sm_config_set_clkdiv(&c, clkdiv);pio_sm_init(pio, sm, offset, &c);}#endif
main.c

Code:

#include <stdio.h>#include <string.h>#include <math.h>#include <stdlib.h>#include "pico/stdlib.h"#include "pico/double.h"#include "hardware/pio.h"#include "hardware/dma.h"#include "hardware/pwm.h"#include "hardware/irq.h"#include "hardware/gpio.h"#include "hardware/clocks.h"#include "ad7606_spi.pio.h"// Define GPIO pins#define PIN_SCK 14#define PIN_MISO 12#define PIN_CS 13#define PIN_BUSY 10#define PIN_CONVST 9#define PIN_RESET 11// DMA buffer and ring buffer definitions#define CHANNELS 8#define PWM_FREQ 1000 // 7.5 - 200000.0#define PIO_FREQ 12000000.0 //125000000.0#define REF 5__attribute__((aligned(1024)))uint16_t databuffer[CHANNELS];uint dmacounter = 0;uint piocount = 0;PIO pio = pio0;uint sm = 0;int dma_chan;void pio_irq0_handler() {    piocount++;    bool int0 = pio_interrupt_get(pio, 0);    bool int1 = pio_interrupt_get(pio, 1);    bool int2 = pio_interrupt_get(pio, 2);    bool int3 = pio_interrupt_get(pio, 3);    printf("piocount: %d, int: %d %d %d %d\n", piocount, int0, int1, int2, int3);    // Clear the interrupt flag (if necessary)    if(int0) {        pio_interrupt_clear(pio, 0);    }    if(int1) {        pio_interrupt_clear(pio, 1);        dma_channel_start(dma_chan);    }    if(int2)        pio_interrupt_clear(pio, 2);    if(int3) {        pio_interrupt_clear(pio, 3);    }}// SPI PIO program initializationvoid init_pio_spi(PIO pio, uint sm, uint offset, uint pin_sck, uint pin_miso, uint pin_cs, uint pin_busy, float freq) {    printf("Initializing PIO SPI at offset:%d\n", offset);    uint32_t sysClock = clock_get_hz(clk_sys);float clkdiv = (sysClock / freq);    printf("pio clkdiv: %f \n", clkdiv);    ad7606_spi_128bit_init(pio, sm, offset, clkdiv, pin_sck, pin_miso, pin_cs, pin_busy);    pio_set_irq1_source_mask_enabled(pio, 3840, true); //setting all 4 at once    // Register the PIO interrupt handler    irq_set_exclusive_handler(PIO0_IRQ_1, pio_irq0_handler); // Use PIO1_IRQ_0 for pio1    irq_set_enabled(PIO0_IRQ_1, true); // Enable the interrupt    pio_sm_set_enabled(pio, sm, true);}// PWM setup for CONVSTvoid setup_pwm_for_convst(uint gpio, float freq, u_int16_t duty) {    gpio_set_function(gpio, GPIO_FUNC_PWM);    uint slice_num = pwm_gpio_to_slice_num(gpio);    u_int16_t wrap = freq < 1000 ? 65535 - ((freq * freq) / 1000000.0 * 65000) : 500;    printf("pwm f: %f w: %u c: %f\n", freq, wrap, 125000000.0 / (freq * wrap));    pwm_set_clkdiv(slice_num, 125000000.0 / (freq * wrap)); // Set the divider    pwm_set_wrap(slice_num, wrap - 1); // Set the wrap value    pwm_set_chan_level(slice_num, pwm_gpio_to_channel(gpio), ceil(wrap * (duty / 100.0))); // Set duty cycle    pwm_set_enabled(slice_num, true); // Enable PWM}// DMA IRQ handlervoid dma_irq_handler() {    dma_hw->ints0 = 1u << dma_chan;    dma_channel_set_read_addr(dma_chan, &databuffer/*&ring_buffer[ring_buffer_head].data*/, false);    // Record the timestamp and sample index for the completed DMA transfer    dmacounter++;    //if(dmacounter % 10 == 0) {        for (int i = 0; i < CHANNELS; i++) {            printf("%u ", databuffer[i]); ///65535 * 2 * REF        }        printf(" dma handler %d\n", dmacounter);    //}}// DMA setup for data transferint setup_dma() {    int dma_chan = dma_claim_unused_channel(true);    dma_channel_config config = dma_channel_get_default_config(dma_chan);    channel_config_set_transfer_data_size(&config, DMA_SIZE_16);    //channel_config_set_ring(&config, false, 0);    channel_config_set_read_increment(&config, false); //was false    channel_config_set_write_increment(&config, true); //was true    channel_config_set_dreq(&config, pio_get_dreq(pio, sm, false));    dma_channel_configure(        dma_chan,        &config,        &databuffer,                           // Destination pointer        &pio->rxf[sm],                    // Source pointer (PIO RX FIFO)        CHANNELS,                     // Transfer count (8 samples of uint16_t each)        false                             // Don't start yet    );    // Tell the DMA to raise IRQ line 0 when the channel finishes a block    dma_channel_set_irq0_enabled(dma_chan, true);    // Configure the processor to run dma_handler() when DMA IRQ 0 is asserted    irq_set_exclusive_handler(DMA_IRQ_0, dma_irq_handler);    irq_set_enabled(DMA_IRQ_0, true);    return dma_chan;}void setup_gpio() {    gpio_init(PIN_RESET);    gpio_set_dir(PIN_RESET, GPIO_OUT);    gpio_init(PIN_CONVST);    gpio_set_dir(PIN_CONVST, GPIO_OUT);    gpio_put(PIN_CONVST, 0); // Set the pin to low initially}int main() {    sleep_ms(100);    stdio_init_all();    printf("hello\n");    sleep_ms(3000);    printf("init\n");    absolute_time_t last_metric_time = get_absolute_time();    int64_t timediff;    setup_gpio();    // Load the PIO program into the PIO memory    uint offset = pio_add_program(pio, &ad7606_spi_128bit_read_program);    // Initialize the PIO and state machine    init_pio_spi(pio, sm, offset, PIN_SCK, PIN_MISO, PIN_CS, PIN_BUSY, PIO_FREQ);    // Initialize DMA for data transfer    dma_chan = setup_dma();    // Initialize PWM for CONVST    setup_pwm_for_convst(PIN_CONVST, PWM_FREQ, 96);    while (true) {        timediff = absolute_time_diff_us(last_metric_time, get_absolute_time());        sleep_ms(10);        if (timediff > 100000) {            if(dmacounter || piocount) {                for (int i = 0; i < CHANNELS; i++) {                    printf("%u ", databuffer[i]); ///65535 * 2 * REF                }                printf(" dma handler %d\n", dmacounter);                printf("dma: %d %f/s, pio: %d %f/s, fifo: %d %d\n", dmacounter, dmacounter/(timediff/1000000.0), piocount, piocount/(timediff/1000000.0),  pio_sm_is_rx_fifo_empty(pio, sm), pio_sm_is_tx_fifo_empty(pio, sm));                dmacounter = 0;                piocount = 0;            }            // Reset the timer            last_metric_time = get_absolute_time();        }    }    return 0;}

I dont think I need dma chaining for my use case.

Statistics: Posted by gaby_64 — Wed Jan 24, 2024 11:46 pm



Viewing all articles
Browse latest Browse all 4852

Trending Articles