mirror of
https://github.com/gusmanb/logicanalyzer.git
synced 2024-12-22 01:39:30 +00:00
1220 lines
45 KiB
Plaintext
1220 lines
45 KiB
Plaintext
;--------------------------------------------------------------------------------------------
|
|
.program POSITIVE_CAPTURE
|
|
|
|
pull
|
|
out y 32 ;read loop count
|
|
pull
|
|
mov x, osr ;read capture length (use MOV instead of PULL so we can MOV it again on each loop)
|
|
|
|
.wrap_target
|
|
|
|
in pins 32 ;read sample
|
|
jmp pin POST_CAPTURE ;exit wrap if pin is set
|
|
|
|
.wrap
|
|
|
|
POST_CAPTURE:
|
|
|
|
in pins 32 ;read sample
|
|
jmp x-- POST_CAPTURE ;loop if more samples needed
|
|
|
|
jmp y-- LOOP ;jump to loop control
|
|
|
|
irq 0 ;notify to the main program that we have finished capturing
|
|
|
|
LOCK:
|
|
|
|
jmp LOCK ;block the program
|
|
|
|
LOOP:
|
|
mov x, osr ;read loop count
|
|
INNER_LOOP:
|
|
|
|
jmp pin POST_CAPTURE ;wait for trigger
|
|
jmp INNER_LOOP
|
|
|
|
;--------------------------------------------------------------------------------------------
|
|
.program NEGATIVE_CAPTURE
|
|
|
|
pull
|
|
out y 32 ;read loop count
|
|
pull
|
|
mov x, osr ;read capture length (use MOV instead of PULL so we can MOV it again on each loop)
|
|
|
|
PRE_CAPTURE:
|
|
|
|
in pins 32 ;read sample
|
|
jmp pin PRE_CAPTURE ;loop if pin is set
|
|
|
|
POST_CAPTURE:
|
|
|
|
.wrap_target
|
|
|
|
in pins 32 ;read sample
|
|
jmp x-- POST_CAPTURE ;loop if more samples needed
|
|
|
|
jmp y-- LOOP ;jump to loop control
|
|
|
|
irq 0 ;notify to the main program that we have finished capturing
|
|
|
|
LOCK:
|
|
|
|
jmp LOCK ;block the program
|
|
|
|
LOOP:
|
|
mov x, osr ;read loop count
|
|
INNER_LOOP:
|
|
jmp pin INNER_LOOP ;wait for trigger
|
|
|
|
.wrap
|
|
|
|
;--------------------------------------------------------------------------------------------
|
|
.program COMPLEX_CAPTURE
|
|
|
|
pull
|
|
out x 32 ;read capture length
|
|
|
|
wait irq 7 ;wait for trigger program to be ready
|
|
|
|
.wrap_target
|
|
|
|
in pins 29 ;read sample
|
|
jmp pin POST_CAPTURE ;exit wrap if pin is set
|
|
|
|
.wrap
|
|
|
|
POST_CAPTURE:
|
|
|
|
in pins 29 ;read sample
|
|
jmp x-- POST_CAPTURE ;loop if more samples needed
|
|
|
|
irq 0 ;notify to the main program that we have finished capturing
|
|
|
|
LOCK:
|
|
|
|
jmp LOCK ;block the program
|
|
|
|
;--------------------------------------------------------------------------------------------
|
|
.program FAST_CAPTURE
|
|
|
|
pull
|
|
out x 32 ;read capture length
|
|
|
|
.wrap_target
|
|
|
|
in pins 29 ;read sample
|
|
jmp pin POST_CAPTURE ;exit wrap if pin is set
|
|
|
|
.wrap
|
|
|
|
POST_CAPTURE:
|
|
|
|
in pins 29 ;read sample
|
|
jmp x-- POST_CAPTURE ;loop if more samples needed
|
|
|
|
irq 0 ;notify to the main program that we have finished capturing
|
|
|
|
LOCK:
|
|
|
|
jmp LOCK ;block the program
|
|
|
|
;--------------------------------------------------------------------------------------------
|
|
;--------Kept only for reference, the program is stored in volatile memory as it must--------
|
|
;---------be modified for concrete trigger parameters.---------------------------------------
|
|
;--------------------------------------------------------------------------------------------
|
|
;.program COMPLEX_TRIGGER
|
|
|
|
; pull
|
|
; out x 32 ;read trigger value
|
|
|
|
; set pins 0 ;set trigger pin to low
|
|
|
|
; irq 7 ;Release capture program
|
|
|
|
;TRIGGER_LOOP:
|
|
|
|
; mov osr, pins ;read pin status to output shift register
|
|
; out y, 4 ;output 4 bits to Y (writes 32 bits)
|
|
; jmp x!=y TRIGGER_LOOP ;loop if trigger not met
|
|
|
|
; set pins 1 ;set trigger pin to high (trigger met)
|
|
|
|
;LOCK:
|
|
|
|
; jmp LOCK ;block program
|
|
|
|
% c-sdk {
|
|
#include "../LogicAnalyzer_Board_Settings.h"
|
|
#include "hardware/gpio.h"
|
|
#include "hardware/dma.h"
|
|
#include "hardware/irq.h"
|
|
#include "string.h"
|
|
#include "hardware/sync.h"
|
|
|
|
#define CAPTURE_BUFFER_SIZE (128 * 1024)
|
|
|
|
typedef enum
|
|
{
|
|
MODE_8_CHANNEL,
|
|
MODE_16_CHANNEL,
|
|
MODE_24_CHANNEL
|
|
|
|
} CHANNEL_MODE;
|
|
|
|
//Static variables for the PIO programs
|
|
static PIO capturePIO;
|
|
static PIO triggerPIO;
|
|
|
|
static uint sm_Capture;
|
|
static uint captureOffset;
|
|
|
|
static uint sm_Trigger;
|
|
static uint triggerOffset;
|
|
|
|
//Static variables for DMA channels
|
|
static uint32_t dmaPingPong0;
|
|
static uint32_t dmaPingPong1;
|
|
static uint32_t dmaPingPong2;
|
|
static uint32_t dmaPingPong3;
|
|
|
|
//Static information of the last capture
|
|
static uint8_t lastCapturePins[24]; //List of captured pins
|
|
static uint8_t lastCapturePinCount; //Count of captured pins
|
|
static uint32_t lastTriggerCapture; //Moment where the trigger happened inside the circular pre buffer
|
|
static uint32_t lastPreSize; //Pre-trigger buffer size
|
|
static uint32_t lastPostSize; //Post-trigger buffer size
|
|
static uint32_t lastLoopCount; //Number of loops
|
|
static bool lastTriggerInverted; //Inverted?
|
|
static uint8_t lastTriggerPin;
|
|
static uint32_t lastStartPosition;
|
|
static bool lastCaptureComplexFast;
|
|
static uint8_t lastCaptureType;
|
|
static uint8_t lastTriggerPinBase;
|
|
static uint32_t lastTriggerPinCount;
|
|
static uint32_t lastTail;
|
|
static CHANNEL_MODE lastCaptureMode = MODE_8_CHANNEL;
|
|
|
|
//Static information of the current capture
|
|
static bool captureFinished;
|
|
static bool captureProcessed;
|
|
|
|
//Pin mapping, used to map the channels to the PIO program
|
|
//COMPLEX_TRIGGER_IN_PIN is added at the end of the array to support the chained mode
|
|
#if defined (BUILD_PICO)
|
|
const uint8_t pinMap[] = {2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,26,27,28,COMPLEX_TRIGGER_IN_PIN};
|
|
#elif defined (BUILD_PICO_W)
|
|
const uint8_t pinMap[] = {2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,26,27,28,COMPLEX_TRIGGER_IN_PIN};
|
|
#elif defined (BUILD_PICO_W_WIFI)
|
|
const uint8_t pinMap[] = {2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,26,27,28,COMPLEX_TRIGGER_IN_PIN};
|
|
#elif defined (BUILD_ZERO)
|
|
const uint8_t pinMap[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,26,27,28,29,22,23,24,25,COMPLEX_TRIGGER_IN_PIN};
|
|
#endif
|
|
|
|
//Main capture buffer, aligned at a 32k boundary, to use the maxixmum ring size supported by DMA channels
|
|
static uint8_t captureBuffer[CAPTURE_BUFFER_SIZE] __attribute__((aligned(32768)));
|
|
|
|
#define CAPTURE_TYPE_SIMPLE 0
|
|
#define CAPTURE_TYPE_COMPLEX 1
|
|
#define CAPTURE_TYPE_FAST 2
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//--------------Complex trigger PIO program------------------------------------
|
|
//-----------------------------------------------------------------------------
|
|
#ifdef SUPPORTS_COMPLEX_TRIGGER
|
|
|
|
#define COMPLEX_TRIGGER_wrap_target 0
|
|
#define COMPLEX_TRIGGER_wrap 8
|
|
|
|
uint16_t COMPLEX_TRIGGER_program_instructions[] = {
|
|
// .wrap_target
|
|
0x80a0, // 0: pull block
|
|
0x6020, // 1: out x, 32
|
|
0xe000, // 2: set pins, 0
|
|
0xc007, // 3: irq nowait 7
|
|
0xa0e0, // 4: mov osr, pins
|
|
0x6044, // 5: out y, 4
|
|
0x00a4, // 6: jmp x != y, 4
|
|
0xe001, // 7: set pins, 1
|
|
0x0008, // 8: jmp 8
|
|
// .wrap
|
|
};
|
|
|
|
struct pio_program COMPLEX_TRIGGER_program = {
|
|
.instructions = COMPLEX_TRIGGER_program_instructions,
|
|
.length = 9,
|
|
.origin = -1,
|
|
};
|
|
|
|
static inline pio_sm_config COMPLEX_TRIGGER_program_get_default_config(uint offset) {
|
|
pio_sm_config c = pio_get_default_sm_config();
|
|
sm_config_set_wrap(&c, offset + COMPLEX_TRIGGER_wrap_target, offset + COMPLEX_TRIGGER_wrap);
|
|
return c;
|
|
}
|
|
#endif
|
|
//-----------------------------------------------------------------------------
|
|
//--------------Complex trigger PIO program END--------------------------------
|
|
//-----------------------------------------------------------------------------
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//--------------Fast trigger PIO program---------------------------------------
|
|
//-----------------------------------------------------------------------------
|
|
#ifdef SUPPORTS_COMPLEX_TRIGGER
|
|
|
|
#define FAST_TRIGGER_wrap_target 0
|
|
#define FAST_TRIGGER_wrap 31
|
|
|
|
uint16_t FAST_TRIGGER_program_instructions[32];
|
|
|
|
struct pio_program FAST_TRIGGER_program = {
|
|
.instructions = FAST_TRIGGER_program_instructions,
|
|
.length = 32,
|
|
.origin = 0,
|
|
};
|
|
|
|
static inline pio_sm_config FAST_TRIGGER_program_get_default_config(uint offset) {
|
|
pio_sm_config c = pio_get_default_sm_config();
|
|
sm_config_set_wrap(&c, offset + FAST_TRIGGER_wrap_target, offset + FAST_TRIGGER_wrap);
|
|
sm_config_set_sideset(&c, 1, false, false);
|
|
return c;
|
|
}
|
|
|
|
//Creates the fast trigger PIO program
|
|
uint8_t create_fast_trigger_program(uint8_t pattern, uint8_t length)
|
|
{
|
|
//This creates a 32 instruction jump table. Each instruction is a MOV PC, PINS except for the addresses that
|
|
//match the specified pattern.
|
|
|
|
uint8_t i;
|
|
uint8_t mask = (1 << length) - 1; //Mask for testing address vs pattern
|
|
uint8_t first = 255;
|
|
|
|
for(i = 0; i < 32; i++)
|
|
{
|
|
if((i & mask) == pattern)
|
|
FAST_TRIGGER_program_instructions[i] = 0x1000 | i; //JMP i SIDE 1
|
|
else
|
|
{
|
|
FAST_TRIGGER_program_instructions[i] = 0xA0A0; //MOV PC, PINS SIDE 0
|
|
first = i;
|
|
}
|
|
}
|
|
|
|
return first;
|
|
}
|
|
#endif
|
|
//-----------------------------------------------------------------------------
|
|
//--------------Fast trigger PIO program END-----------------------------------
|
|
//-----------------------------------------------------------------------------
|
|
|
|
//Find the last captured sample index
|
|
uint32_t find_capture_tail()
|
|
{
|
|
int transferCount;
|
|
|
|
switch(lastCaptureMode)
|
|
{
|
|
case MODE_8_CHANNEL:
|
|
transferCount = 32768;
|
|
break;
|
|
case MODE_16_CHANNEL:
|
|
transferCount = 16384;
|
|
break;
|
|
case MODE_24_CHANNEL:
|
|
transferCount = 8192;
|
|
break;
|
|
}
|
|
|
|
//Add a delay in case the transfer is still in progress (just a safety measure, should not happen)
|
|
//This is a massive delay in comparison to the needs of the DMA channel, but hey, 5ms is not going to be noticed anywhere :D
|
|
busy_wait_ms(5);
|
|
|
|
uint32_t busy_channel = 0xFFFFFFFF;
|
|
uint32_t busy_offset = 0xFFFFFFFF;
|
|
|
|
//First we need to determine which DMA channel is busy (in the middle of a transfer)
|
|
if(dma_channel_is_busy(dmaPingPong0))
|
|
{
|
|
busy_channel = dmaPingPong0;
|
|
busy_offset = 0;
|
|
}
|
|
|
|
if(dma_channel_is_busy(dmaPingPong1))
|
|
{
|
|
busy_channel = dmaPingPong1;
|
|
busy_offset = transferCount;
|
|
}
|
|
|
|
if(dma_channel_is_busy(dmaPingPong2))
|
|
{
|
|
busy_channel = dmaPingPong2;
|
|
busy_offset = transferCount * 2;
|
|
}
|
|
|
|
if(dma_channel_is_busy(dmaPingPong3))
|
|
{
|
|
busy_channel = dmaPingPong3;
|
|
busy_offset = transferCount * 3;
|
|
}
|
|
|
|
//No channel busy?? WTF???
|
|
if(busy_channel == 0xFFFFFFFF)
|
|
return 0xFFFFFFFF;
|
|
|
|
//Ok, now we need to know at which transfer the DMA is. The value equals to MAX_TRANSFERS - TRANSFERS_LEFT - 1 (DMA channel decrements transfer_count when it starts :/).
|
|
int32_t transfer = transferCount - dma_channel_hw_addr(busy_channel)->transfer_count - 1;
|
|
|
|
//Now compute the last capture position
|
|
transfer = (transfer + busy_offset) - 1;
|
|
|
|
//Wrap around?
|
|
if(transfer < 0)
|
|
transfer = (transferCount * 4) - 1;
|
|
|
|
//Our capture absolute last position
|
|
return (uint32_t)transfer;
|
|
}
|
|
|
|
//Disable the trigger GPIOs to avoid triggering again a chained device
|
|
void disable_gpios()
|
|
{
|
|
#ifdef SUPPORTS_COMPLEX_TRIGGER
|
|
gpio_deinit(COMPLEX_TRIGGER_OUT_PIN);
|
|
gpio_deinit(COMPLEX_TRIGGER_IN_PIN);
|
|
#endif
|
|
|
|
for(uint8_t i = 0; i < lastCapturePinCount; i++)
|
|
gpio_deinit(lastCapturePins[i]);
|
|
}
|
|
|
|
#ifdef SUPPORTS_COMPLEX_TRIGGER
|
|
|
|
//Triggered when a fast capture ends
|
|
void fast_capture_completed()
|
|
{
|
|
//Disable the GPIO's
|
|
disable_gpios();
|
|
|
|
//Mark the capture as finished
|
|
captureFinished = true;
|
|
|
|
lastTail = find_capture_tail();
|
|
|
|
//Abort DMA channels
|
|
dma_channel_abort(dmaPingPong0);
|
|
dma_channel_abort(dmaPingPong1);
|
|
dma_channel_abort(dmaPingPong2);
|
|
dma_channel_abort(dmaPingPong3);
|
|
|
|
//Clear PIO interrupt 0 and unhook handler
|
|
pio_interrupt_clear(capturePIO, 0);
|
|
irq_set_enabled(pio_get_dreq(capturePIO, sm_Capture, false), false);
|
|
|
|
//Disable all DMA channels
|
|
dma_channel_unclaim(dmaPingPong0);
|
|
dma_channel_unclaim(dmaPingPong1);
|
|
dma_channel_unclaim(dmaPingPong2);
|
|
dma_channel_unclaim(dmaPingPong3);
|
|
|
|
//Stop PIO capture program and clear
|
|
pio_sm_set_enabled(capturePIO, sm_Capture, false);
|
|
pio_sm_unclaim(capturePIO, sm_Capture);
|
|
|
|
pio_remove_program(capturePIO, &FAST_CAPTURE_program, captureOffset);
|
|
|
|
//Stop PIO trigger program and clear
|
|
pio_sm_set_enabled(triggerPIO, sm_Trigger, false);
|
|
pio_sm_set_pins(triggerPIO, sm_Trigger, 0);
|
|
pio_sm_unclaim(triggerPIO, sm_Trigger);
|
|
|
|
pio_remove_program(triggerPIO, &FAST_TRIGGER_program, triggerOffset);
|
|
}
|
|
|
|
//Check if the capture has finished, this is done because the W messes the PIO interrupts
|
|
void check_fast_interrupt()
|
|
{
|
|
if(lastCaptureType == CAPTURE_TYPE_FAST && capturePIO->irq & 1)
|
|
fast_capture_completed();
|
|
}
|
|
|
|
//Triggered when a complex capture ends
|
|
void complex_capture_completed()
|
|
{
|
|
//Disable the GPIO's
|
|
disable_gpios();
|
|
|
|
//Mark the capture as finished
|
|
captureFinished = true;
|
|
|
|
lastTail = find_capture_tail();
|
|
|
|
//Abort DMA channels
|
|
dma_channel_abort(dmaPingPong0);
|
|
dma_channel_abort(dmaPingPong1);
|
|
dma_channel_abort(dmaPingPong2);
|
|
dma_channel_abort(dmaPingPong3);
|
|
|
|
//Clear PIO interrupt 0 and unhook handler
|
|
pio_interrupt_clear(capturePIO, 0);
|
|
irq_set_enabled(PIO0_IRQ_0, false);
|
|
irq_set_enabled(pio_get_dreq(capturePIO, sm_Capture, false), false);
|
|
irq_remove_handler(PIO0_IRQ_0, complex_capture_completed);
|
|
|
|
//Disable all DMA channels
|
|
dma_channel_unclaim(dmaPingPong0);
|
|
dma_channel_unclaim(dmaPingPong1);
|
|
dma_channel_unclaim(dmaPingPong2);
|
|
dma_channel_unclaim(dmaPingPong3);
|
|
|
|
//Stop PIO capture program and clear
|
|
pio_sm_set_enabled(capturePIO, sm_Capture, false);
|
|
pio_sm_unclaim(capturePIO, sm_Capture);
|
|
|
|
pio_remove_program(capturePIO, &COMPLEX_CAPTURE_program, captureOffset);
|
|
|
|
//Stop PIO trigger program and clear
|
|
pio_sm_set_enabled(capturePIO, sm_Trigger, false);
|
|
pio_sm_set_pins(capturePIO, sm_Trigger, 0);
|
|
pio_sm_unclaim(capturePIO, sm_Trigger);
|
|
|
|
pio_remove_program(capturePIO, &COMPLEX_TRIGGER_program, triggerOffset);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
//Triggered when a simple capture ends
|
|
void simple_capture_completed()
|
|
{
|
|
//Disable the GPIO's
|
|
disable_gpios();
|
|
|
|
//Mark the capture as finished
|
|
captureFinished = true;
|
|
|
|
lastTail = find_capture_tail();
|
|
|
|
//Abort DMA channels
|
|
dma_channel_abort(dmaPingPong0);
|
|
dma_channel_abort(dmaPingPong1);
|
|
dma_channel_abort(dmaPingPong2);
|
|
dma_channel_abort(dmaPingPong3);
|
|
|
|
//Clear PIO interrupt 0 and unhook handler
|
|
pio_interrupt_clear(capturePIO, 0);
|
|
irq_set_enabled(PIO0_IRQ_0, false);
|
|
irq_set_enabled(pio_get_dreq(capturePIO, sm_Capture, false), false);
|
|
irq_remove_handler(PIO0_IRQ_0, simple_capture_completed);
|
|
|
|
dma_channel_unclaim(dmaPingPong0);
|
|
dma_channel_unclaim(dmaPingPong1);
|
|
dma_channel_unclaim(dmaPingPong2);
|
|
dma_channel_unclaim(dmaPingPong3);
|
|
|
|
//Stop PIO program and clear
|
|
pio_sm_set_enabled(capturePIO, sm_Capture, false);
|
|
pio_sm_unclaim(capturePIO, sm_Capture);
|
|
|
|
if(lastTriggerInverted)
|
|
pio_remove_program(capturePIO, &POSITIVE_CAPTURE_program, captureOffset);
|
|
else
|
|
pio_remove_program(capturePIO, &NEGATIVE_CAPTURE_program, captureOffset);
|
|
|
|
}
|
|
|
|
//Configure the four DMA channels
|
|
void configureCaptureDMAs(CHANNEL_MODE channelMode)
|
|
{
|
|
|
|
enum dma_channel_transfer_size transferSize;
|
|
uint32_t transferCount;
|
|
|
|
switch(channelMode)
|
|
{
|
|
case MODE_8_CHANNEL:
|
|
transferSize = DMA_SIZE_8;
|
|
transferCount = 32768;
|
|
break;
|
|
case MODE_16_CHANNEL:
|
|
transferSize = DMA_SIZE_16;
|
|
transferCount = 16384;
|
|
break;
|
|
case MODE_24_CHANNEL:
|
|
transferSize = DMA_SIZE_32;
|
|
transferCount = 8192;
|
|
break;
|
|
}
|
|
|
|
//Claim four DMA channels, each channel writes to 32Kb of the buffer (8192 samples) as that's the maximum ring size supported
|
|
dmaPingPong0 = dma_claim_unused_channel(true);
|
|
dmaPingPong1 = dma_claim_unused_channel(true);
|
|
dmaPingPong2 = dma_claim_unused_channel(true);
|
|
dmaPingPong3 = dma_claim_unused_channel(true);
|
|
|
|
//Configure first capture DMA
|
|
dma_channel_config dmaPingPong0Config = dma_channel_get_default_config(dmaPingPong0);
|
|
channel_config_set_read_increment(&dmaPingPong0Config, false); //Do not increment read address
|
|
channel_config_set_write_increment(&dmaPingPong0Config, true); //Increment write address
|
|
channel_config_set_transfer_data_size(&dmaPingPong0Config, transferSize); //Transfer 32 bits each time
|
|
channel_config_set_chain_to(&dmaPingPong0Config, dmaPingPong1); //Chain to the second dma channel
|
|
channel_config_set_dreq(&dmaPingPong0Config, pio_get_dreq(capturePIO, sm_Capture, false)); //Set DREQ as RX FIFO
|
|
channel_config_set_ring(&dmaPingPong0Config, true, 15); //Ring at 32768 bytes
|
|
|
|
//Configure second capture DMA
|
|
dma_channel_config dmaPingPong1Config = dma_channel_get_default_config(dmaPingPong1);
|
|
channel_config_set_read_increment(&dmaPingPong1Config, false); //Do not increment read address
|
|
channel_config_set_write_increment(&dmaPingPong1Config, true); //Increment write address
|
|
channel_config_set_transfer_data_size(&dmaPingPong1Config, transferSize); //Transfer 32 bits each time
|
|
channel_config_set_chain_to(&dmaPingPong1Config, dmaPingPong2); //Chain to the third dma channel
|
|
channel_config_set_dreq(&dmaPingPong1Config, pio_get_dreq(capturePIO, sm_Capture, false)); //Set DREQ as RX FIFO
|
|
channel_config_set_ring(&dmaPingPong1Config, true, 15); //Ring at 32768 bytes
|
|
|
|
//Configure third capture DMA
|
|
dma_channel_config dmaPingPong2Config = dma_channel_get_default_config(dmaPingPong2);
|
|
channel_config_set_read_increment(&dmaPingPong2Config, false); //Do not increment read address
|
|
channel_config_set_write_increment(&dmaPingPong2Config, true); //Increment write address
|
|
channel_config_set_transfer_data_size(&dmaPingPong2Config, transferSize); //Transfer 32 bits each time
|
|
channel_config_set_chain_to(&dmaPingPong2Config, dmaPingPong3); //Chain to the fourth dma channel
|
|
channel_config_set_dreq(&dmaPingPong2Config, pio_get_dreq(capturePIO, sm_Capture, false)); //Set DREQ as RX FIFO
|
|
channel_config_set_ring(&dmaPingPong2Config, true, 15); //Ring at 32768 bytes
|
|
|
|
//Configure fourth capture DMA
|
|
dma_channel_config dmaPingPong3Config = dma_channel_get_default_config(dmaPingPong3);
|
|
channel_config_set_read_increment(&dmaPingPong3Config, false); //Do not increment read address
|
|
channel_config_set_write_increment(&dmaPingPong3Config, true); //Increment write address
|
|
channel_config_set_transfer_data_size(&dmaPingPong3Config, transferSize); //Transfer 32 bits each time
|
|
channel_config_set_chain_to(&dmaPingPong3Config, dmaPingPong0); //Chain to the first dma channel
|
|
channel_config_set_dreq(&dmaPingPong3Config, pio_get_dreq(capturePIO, sm_Capture, false)); //Set DREQ as RX FIFO
|
|
channel_config_set_ring(&dmaPingPong3Config, true, 15); //Ring at 32768 bytes
|
|
|
|
//Configure the DMA channels
|
|
dma_channel_configure(dmaPingPong3, &dmaPingPong3Config, &captureBuffer[32768 * 3], &capturePIO->rxf[sm_Capture], transferCount, false); //Configure the channel
|
|
dma_channel_configure(dmaPingPong2, &dmaPingPong2Config, &captureBuffer[32768 * 2], &capturePIO->rxf[sm_Capture], transferCount, false); //Configure the channel
|
|
dma_channel_configure(dmaPingPong1, &dmaPingPong1Config, &captureBuffer[32768], &capturePIO->rxf[sm_Capture], transferCount, false); //Configure the channel
|
|
dma_channel_configure(dmaPingPong0, &dmaPingPong0Config, captureBuffer, &capturePIO->rxf[sm_Capture], transferCount, true);
|
|
}
|
|
|
|
void stopCapture()
|
|
{
|
|
if(!captureFinished)
|
|
{
|
|
uint32_t int_status = save_and_disable_interrupts();
|
|
|
|
#ifdef SUPPORTS_COMPLEX_TRIGGER
|
|
|
|
if(lastCaptureType == CAPTURE_TYPE_SIMPLE)
|
|
simple_capture_completed();
|
|
else if(lastCaptureType == CAPTURE_TYPE_COMPLEX)
|
|
complex_capture_completed();
|
|
else if(lastCaptureType == CAPTURE_TYPE_FAST)
|
|
fast_capture_completed();
|
|
|
|
#else
|
|
|
|
simple_capture_completed();
|
|
|
|
#endif
|
|
|
|
restore_interrupts(int_status);
|
|
}
|
|
}
|
|
|
|
#ifdef SUPPORTS_COMPLEX_TRIGGER
|
|
|
|
bool startCaptureFast(uint32_t freq, uint32_t preLength, uint32_t postLength, const uint8_t* capturePins, uint8_t capturePinCount, uint8_t triggerPinBase, uint8_t triggerPinCount, uint16_t triggerValue, CHANNEL_MODE captureMode)
|
|
{
|
|
|
|
//ABOUT THE FAST TRIGGER
|
|
//
|
|
//The fast trigger is an evolution of the complex trigger.
|
|
//Like the complex trigger this is a sepparate program that checks for a pattern to trigger the capture program second stage.
|
|
//
|
|
//The main difference is the maximum length of the pattern to match and the sampling speed. This fast trigger
|
|
//can only use a pattern up to 5 bits, but it captures at maximum speed of 100Msps (it could even sample up to 200Mhz but to match the
|
|
//maximum speed of the sampling it is limited to 100Msps).
|
|
//To achieve this the program occupies all 32 instructions of a PIO module, this is basically a jump table, each
|
|
//instruction moves the pin values to the program counter except for the ones that match the pattern, which activate the
|
|
//trigger pin using the side pins and create an infinite loop jumping to itself (basically a JMP currentpc SIDE 1).
|
|
//
|
|
//This solves the speed and latency problem, the speed reaches 100Msps and the latency is reduced to a maximum of 2 cycles, but
|
|
//still can glitch on low speeds and also occupies a complete PIO module (but we have one unused, so its not a problem)
|
|
|
|
|
|
int maxSamples;
|
|
|
|
switch(captureMode)
|
|
{
|
|
case MODE_8_CHANNEL:
|
|
maxSamples = 131072;
|
|
break;
|
|
case MODE_16_CHANNEL:
|
|
maxSamples = 65536;
|
|
break;
|
|
case MODE_24_CHANNEL:
|
|
maxSamples = 32768;
|
|
break;
|
|
}
|
|
|
|
//Too many samples requested?
|
|
if(preLength + postLength >= maxSamples)
|
|
return false;
|
|
|
|
//Frequency too high?
|
|
if(freq > 100000000)
|
|
return false;
|
|
|
|
//Incorrect pin count?
|
|
if(capturePinCount < 0 || capturePinCount > 24)
|
|
return false;
|
|
|
|
//Bad trigger?
|
|
if(triggerPinBase > 15 || triggerPinCount > 5 || triggerPinCount < 1 || triggerPinCount + triggerPinBase > 16)
|
|
return false;
|
|
|
|
//Clear capture buffer (to avoid sending bad data if the trigger happens before the presamples are filled)
|
|
memset(captureBuffer, 0, sizeof(captureBuffer));
|
|
|
|
//Store info about the capture
|
|
lastPreSize = preLength;
|
|
lastPostSize = postLength;
|
|
lastLoopCount = 0;
|
|
lastCapturePinCount = capturePinCount;
|
|
lastCaptureComplexFast = true;
|
|
lastCaptureMode = captureMode;
|
|
|
|
//Map channels to pins
|
|
for(uint8_t i = 0; i < capturePinCount; i++)
|
|
lastCapturePins[i] = pinMap[capturePins[i]];
|
|
|
|
//Store trigger info
|
|
triggerPinBase = pinMap[triggerPinBase];
|
|
lastTriggerPinBase = triggerPinBase;
|
|
|
|
//Calculate clock divider based on frequency, it generates a clock 2x faster than the capture freequency
|
|
float clockDiv = (float)clock_get_hz(clk_sys) / (float)(freq * 2);
|
|
|
|
//Store the PIO units and clear program memory
|
|
capturePIO = pio1; //Cannot clear it in PIO1 because the W uses PIO1 to transfer data
|
|
triggerPIO = pio0;
|
|
|
|
pio_clear_instruction_memory(triggerPIO);
|
|
|
|
//Configure 24 + 2 IO's to be used by the PIO (24 channels + 2 trigger pins)
|
|
pio_gpio_init(triggerPIO, COMPLEX_TRIGGER_OUT_PIN);
|
|
pio_gpio_init(capturePIO, COMPLEX_TRIGGER_IN_PIN);
|
|
|
|
for(uint8_t i = 0; i < 24; i++)
|
|
pio_gpio_init(capturePIO, pinMap[i]);
|
|
|
|
//Configure capture SM
|
|
sm_Capture = pio_claim_unused_sm(capturePIO, true);
|
|
pio_sm_clear_fifos(capturePIO, sm_Capture);
|
|
pio_sm_restart(capturePIO, sm_Capture);
|
|
captureOffset = pio_add_program(capturePIO, &FAST_CAPTURE_program);
|
|
|
|
//Modified for the W
|
|
for(int i = 0; i < 24; i++)
|
|
pio_sm_set_consecutive_pindirs(capturePIO, sm_Capture, pinMap[i], 1, false);
|
|
|
|
//Configure state machines
|
|
pio_sm_config smConfig = FAST_CAPTURE_program_get_default_config(captureOffset);
|
|
|
|
//Inputs start at pin INPUT_PIN_BASE
|
|
sm_config_set_in_pins(&smConfig, INPUT_PIN_BASE);
|
|
|
|
//Set clock to 2x required frequency
|
|
sm_config_set_clkdiv(&smConfig, clockDiv);
|
|
|
|
//Autopush per 29 bits
|
|
sm_config_set_in_shift(&smConfig, false, true, 29);
|
|
|
|
//Configure fast trigger pin (COMPLEX_TRIGGER_IN_PIN) as JMP pin.
|
|
sm_config_set_jmp_pin(&smConfig, COMPLEX_TRIGGER_IN_PIN);
|
|
|
|
//Configure interrupt 0
|
|
pio_interrupt_clear (capturePIO, 0);
|
|
irq_set_enabled(pio_get_dreq(capturePIO, sm_Capture, false), true);
|
|
|
|
//Initialize state machine
|
|
pio_sm_init(capturePIO, sm_Capture, captureOffset, &smConfig);
|
|
|
|
//Configure trigger SM
|
|
sm_Trigger = pio_claim_unused_sm(triggerPIO, true);
|
|
pio_sm_clear_fifos(triggerPIO, sm_Trigger);
|
|
pio_sm_restart(triggerPIO, sm_Trigger);
|
|
|
|
//Create trigger program
|
|
uint8_t triggerFirstInstruction = create_fast_trigger_program(triggerValue, triggerPinCount);
|
|
|
|
//Configure trigger state machine
|
|
triggerOffset = pio_add_program(triggerPIO, &FAST_TRIGGER_program);
|
|
pio_sm_set_consecutive_pindirs(triggerPIO, sm_Trigger, COMPLEX_TRIGGER_OUT_PIN, 1, true); //Pin COMPLEX_TRIGGER_OUT_PIN as output (connects to Pin COMPLEX_TRIGGER_IN_PIN, to trigger capture)
|
|
pio_sm_set_consecutive_pindirs(triggerPIO, sm_Trigger, triggerPinBase, triggerPinCount, false); //Trigger pins start at triggerPinBase
|
|
|
|
smConfig = FAST_TRIGGER_program_get_default_config(triggerOffset);
|
|
|
|
sm_config_set_in_pins(&smConfig, triggerPinBase); //Trigger input starts at pin base
|
|
sm_config_set_set_pins(&smConfig, COMPLEX_TRIGGER_OUT_PIN, 1); //Trigger output is a set pin
|
|
sm_config_set_sideset_pins(&smConfig, COMPLEX_TRIGGER_OUT_PIN); //Trigger output is a side pin
|
|
sm_config_set_clkdiv(&smConfig, 1); //Trigger always runs at max speed
|
|
|
|
//Configure DMA's
|
|
configureCaptureDMAs(captureMode);
|
|
|
|
//Enable capture state machine
|
|
pio_sm_set_enabled(capturePIO, sm_Capture, true);
|
|
|
|
//Write capture length to post program
|
|
pio_sm_put_blocking(capturePIO, sm_Capture, postLength - 1);
|
|
|
|
//Initialize trigger state machine
|
|
pio_sm_init(triggerPIO, sm_Trigger, triggerOffset, &smConfig);
|
|
|
|
//Enable trigger state machine
|
|
pio_sm_set_enabled(triggerPIO, sm_Trigger, true);
|
|
|
|
//Finally clear capture status and process flags
|
|
captureFinished = false;
|
|
captureProcessed = false;
|
|
lastCaptureType = CAPTURE_TYPE_FAST;
|
|
|
|
//We're done
|
|
return true;
|
|
}
|
|
|
|
bool startCaptureComplex(uint32_t freq, uint32_t preLength, uint32_t postLength, const uint8_t* capturePins, uint8_t capturePinCount, uint8_t triggerPinBase, uint8_t triggerPinCount, uint16_t triggerValue, CHANNEL_MODE captureMode)
|
|
{
|
|
|
|
//ABOUT THE COMPLEX TRIGGER
|
|
//
|
|
//The complex trigger is a hack to achieve the maximum speed in the capture program.
|
|
//To get to 100Msps with a 200Mhz clock each capture must be excuted in two instructions. For this the basic
|
|
//capture programs (the positive and negative ones) use the JMP PIN instruction, this redirects the program flow based in the
|
|
//state of a pin, so with an IN instruction and a JMP instruction we can create a loop that captures data until the trigger pin
|
|
//is in the correct edge and then jumps to another subroutine that captures until the post-trigger samples are met.
|
|
//
|
|
//Unfortunately there is no way to jump to a subroutine based in the status of more than one pin, you can jump based in the
|
|
//comparison of the scratch registers, but this requires more than one instruction to prepare the data.
|
|
//So, what I have implemented here is an asynchronouss trigger, a second state machine running at máximum speed checks if the trigger
|
|
//condition is met and then notifies to the first state machine. But... there is no way to notify of something between state machines
|
|
//except for interrupts, and interrupts blocks the code execution (you WAIT for the interrupt) so this is not viable, so we use a hack, we
|
|
//interconnect two pins (GPIO0 and GPIO1), one is an output from the trigger state machine and the other is the JMP PIN for the capture
|
|
//state machine. When the trigger condition is met the output pin is set to 1 so the JMP PIN pin receives this signal and we can keep
|
|
//our capture program to use two instructions.
|
|
//This carries some limitations, the trigger can only work up to 66Msps but the capture can go up to 100Msps as they are independent.
|
|
//Also, as the trigger always runs at maximum speed there may happen a glitch in the trigger signal for lower capture speeds, the
|
|
//condition may be met but for less time than a capture cycle, so the capture machine will not sample this trigger condition.
|
|
//Finally the trigger also has some cycles of delay, 3 instructions plus 2 cycles of propagation to the ISR, so a maximum of
|
|
//25ns of delay can happen.
|
|
|
|
int maxSamples;
|
|
|
|
switch(captureMode)
|
|
{
|
|
case MODE_8_CHANNEL:
|
|
maxSamples = 131072;
|
|
break;
|
|
case MODE_16_CHANNEL:
|
|
maxSamples = 65536;
|
|
break;
|
|
case MODE_24_CHANNEL:
|
|
maxSamples = 32768;
|
|
break;
|
|
}
|
|
|
|
//Too many samples requested?
|
|
if(preLength + postLength >= maxSamples)
|
|
return false;
|
|
|
|
//Frequency too high?
|
|
if(freq > 100000000)
|
|
return false;
|
|
|
|
//Incorrect pin count?
|
|
if(capturePinCount < 0 || capturePinCount > 24)
|
|
return false;
|
|
|
|
//Bad trigger?
|
|
if(triggerPinBase > 15 || triggerPinCount > 16 || triggerPinCount < 1 || triggerPinCount + triggerPinBase > 16)
|
|
return false;
|
|
|
|
//Clear capture buffer (to avoid sending bad data if the trigger happens before the presamples are filled)
|
|
memset(captureBuffer, 0, sizeof(captureBuffer));
|
|
|
|
//Store info about the capture
|
|
lastPreSize = preLength;
|
|
lastPostSize = postLength;
|
|
lastLoopCount = 0;
|
|
lastCapturePinCount = capturePinCount;
|
|
lastCaptureComplexFast = true;
|
|
lastCaptureMode = captureMode;
|
|
|
|
//Map channels to pins
|
|
for(uint8_t i = 0; i < capturePinCount; i++)
|
|
lastCapturePins[i] = pinMap[capturePins[i]];
|
|
|
|
//Store trigger info
|
|
triggerPinBase = pinMap[triggerPinBase];
|
|
lastTriggerPinBase = triggerPinBase;
|
|
|
|
//Calculate clock divider based on frequency, it generates a clock 2x faster than the capture freequency
|
|
float clockDiv = (float)clock_get_hz(clk_sys) / (float)(freq * 2);
|
|
|
|
//Store the PIO unit and clear program memory
|
|
capturePIO = pio0;
|
|
pio_clear_instruction_memory(capturePIO);
|
|
|
|
//Configure 24 + 2 IO's to be used by the PIO (24 channels + 2 trigger pins)
|
|
pio_gpio_init(capturePIO, COMPLEX_TRIGGER_OUT_PIN);
|
|
pio_gpio_init(capturePIO, COMPLEX_TRIGGER_IN_PIN);
|
|
|
|
for(uint8_t i = 0; i < 24; i++)
|
|
pio_gpio_init(capturePIO, pinMap[i]);
|
|
|
|
//Configure capture SM
|
|
sm_Capture = pio_claim_unused_sm(capturePIO, true);
|
|
pio_sm_clear_fifos(capturePIO, sm_Capture);
|
|
pio_sm_restart(capturePIO, sm_Capture);
|
|
captureOffset = pio_add_program(capturePIO, &COMPLEX_CAPTURE_program);
|
|
|
|
for(int i = 0; i < 24; i++)
|
|
pio_sm_set_consecutive_pindirs(capturePIO, sm_Capture, pinMap[i], 1, false);
|
|
|
|
//Configure state machines
|
|
pio_sm_config smConfig = COMPLEX_CAPTURE_program_get_default_config(captureOffset);
|
|
|
|
//Inputs start at pin INPUT_PIN_BASE
|
|
sm_config_set_in_pins(&smConfig, INPUT_PIN_BASE);
|
|
|
|
//Set clock to 2x required frequency
|
|
sm_config_set_clkdiv(&smConfig, clockDiv);
|
|
|
|
//Autopush per 29 bits
|
|
sm_config_set_in_shift(&smConfig, false, true, 29);
|
|
|
|
//Configure complex trigger pin (pin COMPLEX_TRIGGER_IN_PIN) as JMP pin.
|
|
sm_config_set_jmp_pin(&smConfig, COMPLEX_TRIGGER_IN_PIN);
|
|
|
|
//Configure interrupt 0
|
|
pio_interrupt_clear (capturePIO, 0);
|
|
pio_set_irq0_source_enabled(capturePIO, pis_interrupt0, true);
|
|
irq_set_exclusive_handler(PIO0_IRQ_0, complex_capture_completed);
|
|
irq_set_enabled(PIO0_IRQ_0, true);
|
|
irq_set_enabled(pio_get_dreq(capturePIO, sm_Capture, false), true);
|
|
|
|
//Initialize state machine
|
|
pio_sm_init(capturePIO, sm_Capture, captureOffset, &smConfig);
|
|
|
|
//Configure trigger SM
|
|
sm_Trigger = pio_claim_unused_sm(capturePIO, true);
|
|
pio_sm_clear_fifos(capturePIO, sm_Trigger);
|
|
pio_sm_restart(capturePIO, sm_Trigger);
|
|
|
|
//Modify trigger program to use the correct pins
|
|
COMPLEX_TRIGGER_program_instructions[5] = 0x6040 | triggerPinCount;
|
|
|
|
//Configure trigger state machine
|
|
triggerOffset = pio_add_program(capturePIO, &COMPLEX_TRIGGER_program);
|
|
pio_sm_set_consecutive_pindirs(capturePIO, sm_Trigger, COMPLEX_TRIGGER_OUT_PIN, 1, true); //Pin COMPLEX_TRIGGER_OUT_PIN as output (connects to Pin COMPLEX_TRIGGER_IN_PIN, to trigger capture)
|
|
pio_sm_set_consecutive_pindirs(capturePIO, sm_Trigger, triggerPinBase, triggerPinCount, false); //Trigger pins start at triggerPinBase
|
|
|
|
smConfig = COMPLEX_TRIGGER_program_get_default_config(triggerOffset);
|
|
sm_config_set_in_pins(&smConfig, triggerPinBase); //Trigger input starts at pin base
|
|
sm_config_set_set_pins(&smConfig, COMPLEX_TRIGGER_OUT_PIN, 1); //Trigger output is a set pin
|
|
sm_config_set_clkdiv(&smConfig, 1); //Trigger always runs at max speed
|
|
sm_config_set_in_shift(&smConfig, false, false, 0); //Trigger shifts left to right
|
|
|
|
//Initialize trigger state machine
|
|
pio_sm_init(capturePIO, sm_Trigger, triggerOffset, &smConfig); //Init trigger
|
|
|
|
//Configure DMA's
|
|
configureCaptureDMAs(captureMode);
|
|
|
|
//Enable capture state machine
|
|
pio_sm_set_enabled(capturePIO, sm_Capture, true);
|
|
|
|
//Write capture length to post program
|
|
pio_sm_put_blocking(capturePIO, sm_Capture, postLength - 1);
|
|
|
|
//Enable trigger state machine
|
|
pio_sm_set_enabled(capturePIO, sm_Trigger, true);
|
|
|
|
//Write trigger value to trigger program
|
|
pio_sm_put_blocking(capturePIO, sm_Trigger, triggerValue);
|
|
|
|
//Finally clear capture status and process flags
|
|
captureFinished = false;
|
|
captureProcessed = false;
|
|
lastCaptureType = CAPTURE_TYPE_COMPLEX;
|
|
|
|
//We're done
|
|
return true;
|
|
}
|
|
|
|
#endif
|
|
|
|
bool startCaptureSimple(uint32_t freq, uint32_t preLength, uint32_t postLength, uint8_t loopCount, const uint8_t* capturePins, uint8_t capturePinCount, uint8_t triggerPin, bool invertTrigger, CHANNEL_MODE captureMode)
|
|
{
|
|
|
|
int maxSamples;
|
|
|
|
switch(captureMode)
|
|
{
|
|
case MODE_8_CHANNEL:
|
|
maxSamples = 131072;
|
|
break;
|
|
case MODE_16_CHANNEL:
|
|
maxSamples = 65536;
|
|
break;
|
|
case MODE_24_CHANNEL:
|
|
maxSamples = 32768;
|
|
break;
|
|
}
|
|
|
|
//Too many samples requested?
|
|
if(preLength + postLength >= maxSamples)
|
|
return false;
|
|
|
|
//Frequency too high?
|
|
if(freq > 100000000)
|
|
return false;
|
|
|
|
//Incorrect pin count?
|
|
if(capturePinCount < 0 || capturePinCount > 24)
|
|
return false;
|
|
|
|
//Incorrect trigger pin?
|
|
if(triggerPin < 0 || triggerPin > 24)
|
|
return false;
|
|
|
|
//Clear capture buffer (to avoid sending bad data if the trigger happens before the presamples are filled)
|
|
memset(captureBuffer, 0, sizeof(captureBuffer));
|
|
|
|
//Store info about the capture
|
|
lastPreSize = preLength;
|
|
lastPostSize = postLength;
|
|
lastLoopCount = loopCount;
|
|
lastCapturePinCount = capturePinCount;
|
|
lastTriggerInverted = invertTrigger;
|
|
lastCaptureComplexFast = false;
|
|
lastCaptureMode = captureMode;
|
|
|
|
//Map channels to pins
|
|
for(uint8_t i = 0; i < capturePinCount; i++)
|
|
lastCapturePins[i] = pinMap[capturePins[i]];
|
|
|
|
//Store trigger info
|
|
triggerPin = pinMap[triggerPin];
|
|
lastTriggerPin = triggerPin;
|
|
|
|
//Calculate clock divider based on frequency, it generates a clock 2x faster than the capture freequency
|
|
float clockDiv = (float)clock_get_hz(clk_sys) / (float)(freq * 2);
|
|
|
|
//Store the PIO unit and clear program memory
|
|
capturePIO = pio0;
|
|
pio_clear_instruction_memory(capturePIO);
|
|
|
|
//Configure capture SM
|
|
sm_Capture = pio_claim_unused_sm(capturePIO, true);
|
|
pio_sm_clear_fifos(capturePIO, sm_Capture);
|
|
|
|
pio_sm_restart(capturePIO, sm_Capture);
|
|
|
|
//Load correct program, depending on the trigger edge
|
|
if(invertTrigger)
|
|
captureOffset = pio_add_program(capturePIO, &NEGATIVE_CAPTURE_program);
|
|
else
|
|
captureOffset = pio_add_program(capturePIO, &POSITIVE_CAPTURE_program);
|
|
|
|
//Configure capture pins
|
|
for(int i = 0; i < 24; i++)
|
|
pio_sm_set_consecutive_pindirs(capturePIO, sm_Capture, pinMap[i], 1, false);
|
|
|
|
for(uint8_t i = 0; i < 24; i++)
|
|
pio_gpio_init(capturePIO, pinMap[i]);
|
|
|
|
//Configure trigger pin
|
|
pio_sm_set_consecutive_pindirs(capturePIO, sm_Capture, triggerPin, 1, false);
|
|
pio_gpio_init(capturePIO, triggerPin);
|
|
|
|
//Configure state machines
|
|
pio_sm_config smConfig = invertTrigger?
|
|
NEGATIVE_CAPTURE_program_get_default_config(captureOffset):
|
|
POSITIVE_CAPTURE_program_get_default_config(captureOffset);
|
|
|
|
//Input starts at pin INPUT_PIN_BASE
|
|
sm_config_set_in_pins(&smConfig, INPUT_PIN_BASE);
|
|
|
|
//Set clock to 2x required frequency
|
|
sm_config_set_clkdiv(&smConfig, clockDiv);
|
|
|
|
//Autopush per dword
|
|
sm_config_set_in_shift(&smConfig, true, true, 0);
|
|
|
|
//Configure trigger pin as JMP pin.
|
|
sm_config_set_jmp_pin(&smConfig, triggerPin);
|
|
|
|
//Configure interupt 0
|
|
pio_interrupt_clear (capturePIO, 0);
|
|
pio_set_irq0_source_enabled(capturePIO, pis_interrupt0, true);
|
|
irq_set_exclusive_handler(PIO0_IRQ_0, simple_capture_completed);
|
|
irq_set_enabled(PIO0_IRQ_0, true);
|
|
irq_set_enabled(pio_get_dreq(capturePIO, sm_Capture, false), true);
|
|
|
|
//Initialize state machine
|
|
pio_sm_init(capturePIO, sm_Capture, captureOffset, &smConfig);
|
|
|
|
irq_clear(pio_get_dreq(capturePIO, sm_Capture, false));
|
|
|
|
//Configure DMA's
|
|
configureCaptureDMAs(captureMode);
|
|
|
|
//Enable state machine
|
|
pio_sm_set_enabled(capturePIO, sm_Capture, true);
|
|
|
|
//Write loop count and capture length to post program to start the capture process
|
|
pio_sm_put_blocking(capturePIO, sm_Capture, loopCount);
|
|
pio_sm_put_blocking(capturePIO, sm_Capture, postLength - 1);
|
|
|
|
|
|
//Finally clear capture status, process flags and capture type
|
|
captureFinished = false;
|
|
captureProcessed = false;
|
|
lastCaptureType = CAPTURE_TYPE_SIMPLE;
|
|
|
|
//We're done
|
|
return true;
|
|
}
|
|
|
|
bool IsCapturing()
|
|
{
|
|
//If you need an explanation of this, you're a fool. :P
|
|
return !captureFinished;
|
|
}
|
|
|
|
uint8_t* GetBuffer(uint32_t* bufferSize, uint32_t* firstSample, CHANNEL_MODE* captureMode)
|
|
{
|
|
//Compute total sample count
|
|
uint32_t totalSamples = lastPreSize + (lastPostSize * (lastLoopCount + 1));
|
|
|
|
//If we don't have processed the buffer...
|
|
if(!captureProcessed)
|
|
{
|
|
int maxSize;
|
|
|
|
switch(lastCaptureMode)
|
|
{
|
|
case MODE_8_CHANNEL:
|
|
maxSize = 131072;
|
|
break;
|
|
case MODE_16_CHANNEL:
|
|
maxSize = 65536;
|
|
break;
|
|
case MODE_24_CHANNEL:
|
|
maxSize = 32768;
|
|
break;
|
|
}
|
|
//Calculate start position
|
|
if(lastTail < totalSamples - 1)
|
|
lastStartPosition = (maxSize - totalSamples) + lastTail + 1;
|
|
else
|
|
lastStartPosition = lastTail - totalSamples + 1;
|
|
|
|
uint32_t currentPos = lastStartPosition;
|
|
|
|
switch(lastCaptureMode)
|
|
{
|
|
case MODE_24_CHANNEL:
|
|
{
|
|
uint32_t oldValue;
|
|
uint32_t newValue;
|
|
uint32_t* buffer = (uint32_t*)captureBuffer;
|
|
uint8_t lastPin = 0;
|
|
|
|
//Sort channels
|
|
//(reorder captured bits based on the channels requested)
|
|
for(int buc = 0; buc < totalSamples; buc++)
|
|
{
|
|
oldValue = buffer[currentPos]; //Store current value
|
|
newValue = 0; //New value
|
|
|
|
for(int pin = 0; pin < lastCapturePinCount; pin++) //For each captured channel...
|
|
{
|
|
lastPin = lastCapturePins[pin] - INPUT_PIN_BASE;
|
|
newValue |= (((oldValue & (1 << lastPin))) >> lastPin) << pin; //Place channel data in the correct bit
|
|
}
|
|
|
|
//Update value in the buffer
|
|
buffer[currentPos++] = newValue;
|
|
//If we reached the end of the buffer, wrap around
|
|
if(currentPos >= maxSize)
|
|
currentPos = 0;
|
|
}
|
|
}
|
|
break;
|
|
case MODE_16_CHANNEL:
|
|
{
|
|
uint16_t oldValue;
|
|
uint16_t newValue;
|
|
uint16_t* buffer = (uint16_t*)captureBuffer;
|
|
uint8_t lastPin = 0;
|
|
|
|
//Sort channels
|
|
//(reorder captured bits based on the channels requested)
|
|
for(int buc = 0; buc < totalSamples; buc++)
|
|
{
|
|
oldValue = buffer[currentPos]; //Store current value
|
|
newValue = 0; //New value
|
|
|
|
for(int pin = 0; pin < lastCapturePinCount; pin++) //For each captured channel...
|
|
{
|
|
lastPin = lastCapturePins[pin] - INPUT_PIN_BASE;
|
|
newValue |= (((oldValue & (1 << lastPin))) >> lastPin) << pin; //Place channel data in the correct bit
|
|
}
|
|
|
|
//Update value in the buffer
|
|
buffer[currentPos++] = newValue;
|
|
//If we reached the end of the buffer, wrap around
|
|
if(currentPos >= maxSize)
|
|
currentPos = 0;
|
|
}
|
|
}
|
|
break;
|
|
case MODE_8_CHANNEL:
|
|
{
|
|
uint8_t oldValue;
|
|
uint8_t newValue;
|
|
uint8_t* buffer = (uint8_t*)captureBuffer;
|
|
uint8_t lastPin = 0;
|
|
|
|
//Sort channels
|
|
//(reorder captured bits based on the channels requested)
|
|
for(int buc = 0; buc < totalSamples; buc++)
|
|
{
|
|
oldValue = buffer[currentPos]; //Store current value
|
|
newValue = 0; //New value
|
|
|
|
for(int pin = 0; pin < lastCapturePinCount; pin++) //For each captured channel...
|
|
{
|
|
lastPin = lastCapturePins[pin] - INPUT_PIN_BASE;
|
|
newValue |= (((oldValue & (1 << lastPin))) >> lastPin) << pin; //Place channel data in the correct bit
|
|
}
|
|
|
|
//Update value in the buffer
|
|
buffer[currentPos++] = newValue;
|
|
//If we reached the end of the buffer, wrap around
|
|
if(currentPos >= maxSize)
|
|
currentPos = 0;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
captureProcessed = true;
|
|
}
|
|
//Return data
|
|
*captureMode = lastCaptureMode;
|
|
*bufferSize = totalSamples;
|
|
*firstSample = lastStartPosition;
|
|
return captureBuffer;
|
|
}
|
|
|
|
%} |