Switched to DMA

84% load with 1Msps no DMA

2.4% load with 2Msps with DMA
This commit is contained in:
Killorin 2025-04-24 10:40:44 -04:00
parent bd79be6eac
commit 15a478c9aa
4 changed files with 103 additions and 19 deletions

8
main.c
View file

@ -188,7 +188,7 @@ void capture_waveform(UArg arg1, UArg arg2)
int32_t i; int32_t i;
if (options.fft) { if (options.fft) {
adc_current_index = gADCBufferIndex; adc_current_index = getADCBufferIndex();
int32_t j = 0; int32_t j = 0;
for(i=adc_current_index-FFT_BUF_LEN; i<adc_current_index; i++) { for(i=adc_current_index-FFT_BUF_LEN; i<adc_current_index; i++) {
adc_buffer_fft_sample[j++] = gADCBuffer[ADC_BUFFER_WRAP(adc_current_index + i)]; adc_buffer_fft_sample[j++] = gADCBuffer[ADC_BUFFER_WRAP(adc_current_index + i)];
@ -199,7 +199,7 @@ void capture_waveform(UArg arg1, UArg arg2)
int trigger; int trigger;
if (trigger_mode == 2) { if (trigger_mode == 2) {
trigger = gADCBufferIndex - (WIDTH / 2); // show latest if trigger disabled trigger = getADCBufferIndex() - (WIDTH / 2); // show latest if trigger disabled
} else { } else {
trigger = Trigger(trigger_mode); trigger = Trigger(trigger_mode);
} }
@ -367,7 +367,7 @@ void display_waveform(UArg arg1, UArg arg2)
int Trigger(bool rising) // search for edge trigger int Trigger(bool rising) // search for edge trigger
{ {
int x = gADCBufferIndex - (WIDTH / 2); // half screen width int x = getADCBufferIndex() - (WIDTH / 2); // half screen width
int x_stop = x - ADC_BUFFER_SIZE/2; int x_stop = x - ADC_BUFFER_SIZE/2;
for (; x > x_stop; x--) { for (; x > x_stop; x--) {
if (rising) { if (rising) {
@ -383,6 +383,6 @@ int Trigger(bool rising) // search for edge trigger
} }
} }
if (x == x_stop) // for loop ran to the end if (x == x_stop) // for loop ran to the end
x = gADCBufferIndex - (WIDTH / 2); // reset x back to how it was initialized x = getADCBufferIndex() - (WIDTH / 2); // reset x back to how it was initialized
return x; return x;
} }

View file

@ -36,6 +36,7 @@
var Clock = xdc.useModule('ti.sysbios.knl.Clock'); var Clock = xdc.useModule('ti.sysbios.knl.Clock');
var Mailbox = xdc.useModule('ti.sysbios.knl.Mailbox'); var Mailbox = xdc.useModule('ti.sysbios.knl.Mailbox');
var TimestampProvider = xdc.useModule('ti.sysbios.family.arm.lm4.TimestampProvider'); var TimestampProvider = xdc.useModule('ti.sysbios.family.arm.lm4.TimestampProvider');
var GateHwi = xdc.useModule('ti.sysbios.gates.GateHwi');
/* /*
* Default value is family dependent. For example, Linux systems often only * Default value is family dependent. For example, Linux systems often only
* support a minimum period of 10000 us and multiples of 10000 us. * support a minimum period of 10000 us and multiples of 10000 us.
@ -538,7 +539,7 @@ Clock.timerId = 0;
TimestampProvider.useClockTimer = true; TimestampProvider.useClockTimer = true;
var m3Hwi0Params = new m3Hwi.Params(); var m3Hwi0Params = new m3Hwi.Params();
m3Hwi0Params.instance.name = "m3Hwi0"; m3Hwi0Params.instance.name = "m3Hwi0";
m3Hwi0Params.priority = 0; m3Hwi0Params.priority = 64;
Program.global.m3Hwi0 = m3Hwi.create(62, "&ADC_ISR", m3Hwi0Params); Program.global.m3Hwi0 = m3Hwi.create(62, "&ADC_ISR", m3Hwi0Params);
var task1Params = new Task.Params(); var task1Params = new Task.Params();
task1Params.instance.name = "waveform"; task1Params.instance.name = "waveform";
@ -593,3 +594,6 @@ var semaphore4Params = new Semaphore.Params();
semaphore4Params.instance.name = "options_sem"; semaphore4Params.instance.name = "options_sem";
semaphore4Params.mode = Semaphore.Mode_BINARY; semaphore4Params.mode = Semaphore.Mode_BINARY;
Program.global.options_sem = Semaphore.create(1, semaphore4Params); Program.global.options_sem = Semaphore.create(1, semaphore4Params);
var gateHwi0Params = new GateHwi.Params();
gateHwi0Params.instance.name = "gateHwiDMA";
Program.global.gateHwi0 = GateHwi.create(gateHwi0Params);

View file

@ -7,37 +7,111 @@
#include "driverlib/sysctl.h" #include "driverlib/sysctl.h"
#include "driverlib/interrupt.h" #include "driverlib/interrupt.h"
#include "driverlib/timer.h" #include "driverlib/timer.h"
#include "driverlib/udma.h"
#include "sysctl_pll.h" #include "sysctl_pll.h"
#include "inc/hw_types.h" #include "inc/hw_types.h"
#include "inc/hw_memmap.h" #include "inc/hw_memmap.h"
#include <math.h> #include <math.h>
#include "buttons.h" #include "buttons.h"
#include "sampling.h" #include "sampling.h"
#include <xdc/std.h>
#include <xdc/runtime/System.h>
#include <xdc/cfg/global.h>
#include <ti/sysbios/gates/GateHwi.h>
#define DMA
#ifdef DMA
#pragma DATA_ALIGN(gDMAControlTable, 1024)
tDMAControlTable gDMAControlTable[64]; // uDMA control table
#endif
extern uint32_t gSystemClock; // [Hz] system clock frequency extern uint32_t gSystemClock; // [Hz] system clock frequency
// latest sample index // is DMA occurring in the primary channel?
void ADC_ISR(void) volatile bool gDMAPrimary = true;
void ADC_ISR(void) // DMA
{ {
// clear ADC1 sequence0 interrupt flag in the ADCISC register ADCIntClearEx(ADC1_BASE, ADC_INT_DMA_SS0); // clear the ADC1 sequence 0 DMA interrupt flag
//HWREGBITW(ADC1_ISC_R, 1) = 1; // Check the primary DMA channel for end of transfer, and
ADC1_ISC_R |= 1; // restart if needed.
if (uDMAChannelModeGet(UDMA_SEC_CHANNEL_ADC10 | UDMA_PRI_SELECT) ==
// check for ADC FIFO overflow UDMA_MODE_STOP) {
if(ADC1_OSTAT_R & ADC_OSTAT_OV0) { // restart the primary channel (same as setup)
gADCErrors++; // count errors uDMAChannelTransferSet(UDMA_SEC_CHANNEL_ADC10 | UDMA_PRI_SELECT,
ADC1_OSTAT_R = ADC_OSTAT_OV0; // clear overflow condition UDMA_MODE_PINGPONG, (void*)&ADC1_SSFIFO0_R,
(void*)&gADCBuffer[0], ADC_BUFFER_SIZE/2);
// DMA is currently occurring in the alternate buffer
gDMAPrimary = false;
}
// Check the alternate DMA channel for end of transfer, and
// restart if needed.
// Also set the gDMAPrimary global.
if (uDMAChannelModeGet(UDMA_SEC_CHANNEL_ADC10 | UDMA_ALT_SELECT) ==
UDMA_MODE_STOP) {
// restart the primary channel (same as setup)
uDMAChannelTransferSet(UDMA_SEC_CHANNEL_ADC10 | UDMA_ALT_SELECT,
UDMA_MODE_PINGPONG, (void*)&ADC1_SSFIFO0_R,
(void*)&gADCBuffer[ADC_BUFFER_SIZE/2],
ADC_BUFFER_SIZE/2);
// DMA is currently occurring in the primary buffer
gDMAPrimary = true;
}
// The DMA channel may be disabled if the CPU is paused by the debugger
if (!uDMAChannelIsEnabled(UDMA_SEC_CHANNEL_ADC10)) {
// re-enable the DMA channel
uDMAChannelEnable(UDMA_SEC_CHANNEL_ADC10);
} }
gADCBufferIndex = ADC_BUFFER_WRAP(gADCBufferIndex + 1);
// read sample from the ADC1 sequence 0 FIFO
gADCBuffer[gADCBufferIndex] = (ADC1_SSFIFO0_R & ADC_SSFIFO0_DATA_M);
} }
int32_t getADCBufferIndex(void)
{
int32_t index;
uint32_t key = GateHwi_enter(gateHwi0);
if (gDMAPrimary) { // DMA is currently in the primary channel
index = ADC_BUFFER_SIZE/2 - 1 -
uDMAChannelSizeGet(UDMA_SEC_CHANNEL_ADC10 |
UDMA_PRI_SELECT);
} else { // DMA is currently in the alternate channel
index = ADC_BUFFER_SIZE - 1 -
uDMAChannelSizeGet(UDMA_SEC_CHANNEL_ADC10 |
UDMA_ALT_SELECT);
}
GateHwi_leave(gateHwi0, key);
return index;
}
void start_sampler() { void start_sampler() {
gADCBufferIndex = ADC_BUFFER_SIZE - 1; gADCBufferIndex = ADC_BUFFER_SIZE - 1;
gADCErrors = 0; gADCErrors = 0;
// init DMA
SysCtlPeripheralEnable(SYSCTL_PERIPH_UDMA);
uDMAEnable();
uDMAControlBaseSet(gDMAControlTable);
// assign DMA channel 24 to ADC1 sequence 0
uDMAChannelAssign(UDMA_CH24_ADC1_0);
uDMAChannelAttributeDisable(UDMA_SEC_CHANNEL_ADC10, UDMA_ATTR_ALL);
// primary DMA channel = first half of the ADC buffer
uDMAChannelControlSet(UDMA_SEC_CHANNEL_ADC10 | UDMA_PRI_SELECT,
UDMA_SIZE_16 | UDMA_SRC_INC_NONE | UDMA_DST_INC_16 |
UDMA_ARB_4);
uDMAChannelTransferSet(UDMA_SEC_CHANNEL_ADC10 | UDMA_PRI_SELECT,
UDMA_MODE_PINGPONG, (void*)&ADC1_SSFIFO0_R,
(void*)&gADCBuffer[0], ADC_BUFFER_SIZE/2);
// alternate DMA channel = second half of the ADC buffer
uDMAChannelControlSet(UDMA_SEC_CHANNEL_ADC10 | UDMA_ALT_SELECT,
UDMA_SIZE_16 | UDMA_SRC_INC_NONE | UDMA_DST_INC_16 |
UDMA_ARB_4);
uDMAChannelTransferSet(UDMA_SEC_CHANNEL_ADC10 | UDMA_ALT_SELECT,
UDMA_MODE_PINGPONG, (void*)&ADC1_SSFIFO0_R,
(void*)&gADCBuffer[ADC_BUFFER_SIZE/2],
ADC_BUFFER_SIZE/2);
uDMAChannelEnable(UDMA_SEC_CHANNEL_ADC10);
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE); SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);
GPIOPinTypeADC(GPIO_PORTE_BASE, GPIOPinTypeADC(GPIO_PORTE_BASE,
GPIO_PIN_0); // GPIO setup for analog input AIN3 GPIO_PIN_0); // GPIO setup for analog input AIN3
@ -64,8 +138,12 @@ void start_sampler() {
ADCSequenceStepConfigure(ADC1_BASE, 0, 0, ADC_CTL_CH3 | ADC_CTL_END | ADC_CTL_IE); ADCSequenceStepConfigure(ADC1_BASE, 0, 0, ADC_CTL_CH3 | ADC_CTL_END | ADC_CTL_IE);
// enable the sequence. it is now sampling // enable the sequence. it is now sampling
ADCSequenceEnable(ADC1_BASE, 0); ADCSequenceEnable(ADC1_BASE, 0);
// enable sequence 0 interrupt in the ADC1 peripheral // enable sequence 0 interrupt in the ADC1 peripheral
ADCIntEnable(ADC1_BASE, 0); // INT_ADC1SS0 //ADCIntEnable(ADC1_BASE, 0); // INT_ADC1SS0
ADCSequenceDMAEnable(ADC1_BASE, 0); // enable DMA for ADC1 sequence 0
ADCIntEnableEx(ADC1_BASE, ADC_INT_DMA_SS0); // enable ADC1 sequence 0 DMA interrupt
} }
void set_frequency(uint64_t microseconds) { void set_frequency(uint64_t microseconds) {

View file

@ -17,4 +17,6 @@ void start_sampler(void);
void set_frequency(uint64_t microseconds); void set_frequency(uint64_t microseconds);
int32_t getADCBufferIndex(void);
#endif /* SAMPLING_H_ */ #endif /* SAMPLING_H_ */