From 15a478c9aa2ea6c87197cf5d2d6ae2bc07440922 Mon Sep 17 00:00:00 2001 From: Killorin Date: Thu, 24 Apr 2025 10:40:44 -0400 Subject: [PATCH] Switched to DMA 84% load with 1Msps no DMA 2.4% load with 2Msps with DMA --- main.c | 8 ++-- rtos.cfg | 6 ++- sampling.c | 106 ++++++++++++++++++++++++++++++++++++++++++++++------- sampling.h | 2 + 4 files changed, 103 insertions(+), 19 deletions(-) diff --git a/main.c b/main.c index 33b38c7..9e2f023 100644 --- a/main.c +++ b/main.c @@ -188,7 +188,7 @@ void capture_waveform(UArg arg1, UArg arg2) int32_t i; if (options.fft) { - adc_current_index = gADCBufferIndex; + adc_current_index = getADCBufferIndex(); int32_t j = 0; for(i=adc_current_index-FFT_BUF_LEN; i x_stop; x--) { if (rising) { @@ -383,6 +383,6 @@ int Trigger(bool rising) // search for edge trigger } } 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; } diff --git a/rtos.cfg b/rtos.cfg index 4486db5..69aae67 100644 --- a/rtos.cfg +++ b/rtos.cfg @@ -36,6 +36,7 @@ var Clock = xdc.useModule('ti.sysbios.knl.Clock'); var Mailbox = xdc.useModule('ti.sysbios.knl.Mailbox'); 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 * support a minimum period of 10000 us and multiples of 10000 us. @@ -538,7 +539,7 @@ Clock.timerId = 0; TimestampProvider.useClockTimer = true; var m3Hwi0Params = new m3Hwi.Params(); m3Hwi0Params.instance.name = "m3Hwi0"; -m3Hwi0Params.priority = 0; +m3Hwi0Params.priority = 64; Program.global.m3Hwi0 = m3Hwi.create(62, "&ADC_ISR", m3Hwi0Params); var task1Params = new Task.Params(); task1Params.instance.name = "waveform"; @@ -593,3 +594,6 @@ var semaphore4Params = new Semaphore.Params(); semaphore4Params.instance.name = "options_sem"; semaphore4Params.mode = Semaphore.Mode_BINARY; Program.global.options_sem = Semaphore.create(1, semaphore4Params); +var gateHwi0Params = new GateHwi.Params(); +gateHwi0Params.instance.name = "gateHwiDMA"; +Program.global.gateHwi0 = GateHwi.create(gateHwi0Params); diff --git a/sampling.c b/sampling.c index 3407ada..51fca2c 100644 --- a/sampling.c +++ b/sampling.c @@ -7,37 +7,111 @@ #include "driverlib/sysctl.h" #include "driverlib/interrupt.h" #include "driverlib/timer.h" +#include "driverlib/udma.h" #include "sysctl_pll.h" #include "inc/hw_types.h" #include "inc/hw_memmap.h" #include #include "buttons.h" #include "sampling.h" +#include +#include +#include +#include + + +#define DMA + +#ifdef DMA +#pragma DATA_ALIGN(gDMAControlTable, 1024) +tDMAControlTable gDMAControlTable[64]; // uDMA control table +#endif extern uint32_t gSystemClock; // [Hz] system clock frequency -// latest sample index -void ADC_ISR(void) +// is DMA occurring in the primary channel? +volatile bool gDMAPrimary = true; +void ADC_ISR(void) // DMA { - // clear ADC1 sequence0 interrupt flag in the ADCISC register - //HWREGBITW(ADC1_ISC_R, 1) = 1; - ADC1_ISC_R |= 1; - - // check for ADC FIFO overflow - if(ADC1_OSTAT_R & ADC_OSTAT_OV0) { - gADCErrors++; // count errors - ADC1_OSTAT_R = ADC_OSTAT_OV0; // clear overflow condition + ADCIntClearEx(ADC1_BASE, ADC_INT_DMA_SS0); // clear the ADC1 sequence 0 DMA interrupt flag + // Check the primary DMA channel for end of transfer, and + // restart if needed. + if (uDMAChannelModeGet(UDMA_SEC_CHANNEL_ADC10 | UDMA_PRI_SELECT) == + UDMA_MODE_STOP) { + // restart the primary channel (same as setup) + uDMAChannelTransferSet(UDMA_SEC_CHANNEL_ADC10 | UDMA_PRI_SELECT, + 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() { gADCBufferIndex = ADC_BUFFER_SIZE - 1; 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); GPIOPinTypeADC(GPIO_PORTE_BASE, 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); // enable the sequence. it is now sampling ADCSequenceEnable(ADC1_BASE, 0); + // 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) { diff --git a/sampling.h b/sampling.h index 9cb9b8d..cb96dfd 100644 --- a/sampling.h +++ b/sampling.h @@ -17,4 +17,6 @@ void start_sampler(void); void set_frequency(uint64_t microseconds); +int32_t getADCBufferIndex(void); + #endif /* SAMPLING_H_ */