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.
Updated code:
ad7606_spi.pio.hmain.c
I dont think I need dma chaining for my use case.
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.
I also tried with tightened timings, dma reads all 0, so it doesnt seem to wait for fifo autopush/data.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
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
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