ECE3849/sampling.c
2025-04-24 10:55:49 -04:00

145 lines
5.3 KiB
C

#include <stdint.h>
#include <stdbool.h>
#include "inc/tm4c1294ncpdt.h"
#include "driverlib/adc.h"
#include "driverlib/pin_map.h"
#include "driverlib/gpio.h"
#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 <math.h>
#include "buttons.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
// is DMA occurring in the primary channel?
volatile bool gDMAPrimary = true;
void ADC_ISR(void) // DMA
{
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);
}
}
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
// initialize ADC peripherals
SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);
SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC1);
// ADC clock
uint32_t pll_frequency = SysCtlFrequencyGet(CRYSTAL_FREQUENCY);
uint32_t pll_divisor =
(pll_frequency - 1) / (16 * ADC_SAMPLING_RATE) + 1; // round up
ADCClockConfigSet(ADC0_BASE, ADC_CLOCK_SRC_PLL | ADC_CLOCK_RATE_FULL,
pll_divisor);
ADCClockConfigSet(ADC1_BASE, ADC_CLOCK_SRC_PLL | ADC_CLOCK_RATE_FULL,
pll_divisor);
// choose ADC1 sequence 0; disable before configuring
ADCSequenceDisable(ADC1_BASE, 0);
ADCSequenceConfigure(ADC1_BASE, 0, ADC_TRIGGER_ALWAYS,
0); // specify the "Always" trigger
// in the 0th step, sample channel 3 (AIN3)
// enable interrupt, and make it the end of sequence
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
ADCSequenceDMAEnable(ADC1_BASE, 0); // enable DMA for ADC1 sequence 0
ADCIntEnableEx(ADC1_BASE, ADC_INT_DMA_SS0); // enable ADC1 sequence 0 DMA interrupt
}