145 lines
5.3 KiB
C
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
|
|
}
|