#include #include #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 #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 // 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 }