This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TM4C123 ADC0 with uDMA

Other Parts Discussed in Thread: TM4C123GH6PZ

Hello,

There are quite a few posts already pertaining to using the uDMA with the ADC on the TM4C123GH6PZ. I have gone through and pulled a lot of code from other examples to try and get a working piece of code (specifically here).

I call ADC0Init() from my main and the ADC and uDMA initialize. ADC0IntHandler() is set as the interrupt handler for ADC0. I periodically call GetCPUTemp(). With a breakpoint in that function, I notice that my ADC_OUT values are always 4095. ADC0IntHandler() is called, switching off between the two returning if statements. Is my arbitration size correct (16 * 8 = 128)? Am I missing a configuration setting? Is this the proper way to read the data transferred by the uDMA from the ADC?

I've attached the relevant code and an image containing my uDMA configuration table.

Regards,

Cam

#include "stdint.h"
#include "stdbool.h"
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "inc/hw_adc.h"
#include "inc/hw_ints.h"
#include "driverlib/debug.h"
#include "driverlib/gpio.h"
#include "driverlib/pwm.h"
#ifdef _NOT_PROFILING_
	#include "driverlib/rom.h"
#endif	
#include "driverlib/rom_map.h" 
#include "driverlib/sysctl.h"
#include "driverlib/adc.h"
#include "driverlib/udma.h"
#include "driverlib/interrupt.h"
#include "driverlib/sysctl.h"
#include "driverlib/timer.h"
#include "ADC.h"

#define VMON24_CH				ADC_CTL_CH11
#define VMON24_ADC				GPIO_PB5
#define VMON24_ADC_PORT			GPIO_PORTB_BASE
#define VMON24_ADC_PIN			GPIO_PIN_5

#define IMON24_CH				ADC_CTL_CH10
#define IMON24_ADC				GPIO_PB4
#define IMON24_ADC_PORT			GPIO_PORTB_BASE
#define IMON24_ADC_PIN			GPIO_PIN_4

#define VMON12_CH				ADC_CTL_CH2
#define VMON12_ADC				GPIO_PE1
#define VMON12_ADC_PORT			GPIO_PORTE_BASE
#define VMON12_ADC_PIN			GPIO_PIN_1

#define IMON12_CH				ADC_CTL_CH3
#define IMON12_ADC				GPIO_PE0
#define IMON12_ADC_PORT			GPIO_PORTE_BASE
#define IMON12_ADC_PIN			GPIO_PIN_0

#define VMON5_CH				ADC_CTL_CH0
#define VMON5_ADC				GPIO_PE3
#define VMON5_ADC_PORT			GPIO_PORTE_BASE
#define VMON5_ADC_PIN			GPIO_PIN_3

#define IMON5_CH				ADC_CTL_CH1
#define IMON5_ADC				GPIO_PE2
#define IMON5_ADC_PORT			GPIO_PORTE_BASE
#define IMON5_ADC_PIN			GPIO_PIN_2
#define ADC_SAMPLE_BUF_SIZE (8)

#pragma DATA_ALIGN(udmaCtrlTable, 1024)
uint8_t udmaCtrlTable[1024];

volatile uint16_t ADC_OUT[8];

static uint32 CPUTempCount;
static uint32 CPUTemp;

uint32 GetCPUTemp(void)
{
	CPUTempCount = ADC_OUT[6];
	CPUTempCount = ADC_OUT[7];

	CPUTemp = ((295 / 2) - (225 * CPUTempCount / 4096));
	return CPUTemp;
}


void uDMAErrorHandler(void)
{
	uint32_t ui32Status;
	ui32Status = uDMAErrorStatusGet();
	if(ui32Status)
	{
		uDMAErrorStatusClear();
	}
}

void ADC0IntHandler()
{
	ADCIntClear(ADC0_BASE, 0);

	if (uDMAChannelModeGet(UDMA_CH14_ADC0_0 | UDMA_PRI_SELECT) == UDMA_MODE_STOP)
	{
		// found the full buffer
		// re-set up a DMA transfer to the buffer
		uDMAChannelTransferSet((UDMA_CH14_ADC0_0  | UDMA_PRI_SELECT), UDMA_MODE_PINGPONG, (void *)(ADC0_BASE + ADC_O_SSFIFO0), &ADC_OUT, ADC_SAMPLE_BUF_SIZE);
		uDMAChannelEnable(UDMA_CH14_ADC0_0 ); // Enables DMA channel so it can perform transfers

		return;
	}

	if (uDMAChannelModeGet(UDMA_CH14_ADC0_0 | UDMA_ALT_SELECT) == UDMA_MODE_STOP)
	{
		// found the full buffer
		// re-set up a DMA transfer to the buffer
		uDMAChannelTransferSet((UDMA_CH14_ADC0_0  | UDMA_ALT_SELECT), UDMA_MODE_PINGPONG, (void *)(ADC0_BASE + ADC_O_SSFIFO0), &ADC_OUT, ADC_SAMPLE_BUF_SIZE);
		uDMAChannelEnable(UDMA_CH14_ADC0_0 ); // Enables DMA channel so it can perform transfers

		return;
	}
}

void ADC0Init(void)
{
	TypeConversion Var;

	CPUTemp = 0;
	CPUTempCount = 0;

	/*
	 * Enable the Peripheral
	 */
	SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);
    SysCtlDelay(10);

    SysCtlPeripheralEnable(SYSCTL_PERIPH_UDMA);
    SysCtlDelay(10);
	/*
	 * Set the speed of the ADC to 16 MHz.
	 */
	ADCClockConfigSet(ADC0_BASE, ADC_CLOCK_SRC_PLL | ADC_CLOCK_RATE_FULL, 25);

    /*
     * Configure GPIO pins as ADC
     */
    GPIOPinTypeADC(VMON24_ADC_PORT, VMON24_ADC_PIN);
    GPIOPinTypeADC(IMON24_ADC_PORT, IMON24_ADC_PIN);
    GPIOPinTypeADC(VMON12_ADC_PORT, VMON12_ADC_PIN);
    GPIOPinTypeADC(IMON12_ADC_PORT, IMON12_ADC_PIN);
    GPIOPinTypeADC(VMON5_ADC_PORT, VMON5_ADC_PIN);
    GPIOPinTypeADC(IMON5_ADC_PORT, IMON5_ADC_PIN);


    /*
     * Configure the primary ADC sequence based on the default settings.
     */
    ADCReferenceSet(ADC0_BASE, ADC_REF_EXT_3V);
     /*
     * Disable the ADC sequence and interrupts for safe reconfiguration of
     * the ADC sequences.
     */
    IntDisable(INT_ADC0SS0);
    ADCIntDisable(ADC0_BASE, 0);
    ADCSequenceDisable(ADC0_BASE, 0);

    /*
     * Ensure that this sequence is the highest priority sequence
     * (in the event that other ADC sequences are being used
     * elsewhere in the system).
     */
    ADCSequenceConfigure(ADC0_BASE, 0, ADC_TRIGGER_ALWAYS, 0);

    //Program the sequence Number 0. One steps for each channel and onchip temperature sensor
    ADCSequenceStepConfigure(ADC0_BASE, 0, 0, VMON24_CH);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 1, IMON24_CH);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 2, VMON12_CH);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 3, IMON12_CH);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 4, VMON5_CH);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 5, IMON5_CH);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 6, ADC_CTL_TS);			//CPU Temperature
    ADCSequenceStepConfigure(ADC0_BASE, 0, 7, ADC_CTL_END | ADC_CTL_IE | ADC_CTL_TS);


    //Re enable the ADC sequence code.
    ADCSequenceEnable(ADC0_BASE, 0);
    ADCIntClear(ADC0_BASE,0);

    uDMAEnable();
    uDMAControlBaseSet(udmaCtrlTable);
    ADCSequenceDMAEnable(ADC0_BASE, 0);
    uDMAChannelAttributeDisable(UDMA_CH14_ADC0_0, UDMA_ATTR_ALTSELECT | UDMA_ATTR_HIGH_PRIORITY | UDMA_ATTR_REQMASK);
    uDMAChannelAttributeEnable(UDMA_CH14_ADC0_0, UDMA_ATTR_USEBURST);
    uDMAChannelControlSet(UDMA_CH14_ADC0_0 | UDMA_PRI_SELECT, UDMA_SIZE_16 | UDMA_SRC_INC_NONE | UDMA_DST_INC_16 | UDMA_ARB_128);
    uDMAChannelControlSet(UDMA_CH14_ADC0_0 | UDMA_ALT_SELECT, UDMA_SIZE_16 | UDMA_SRC_INC_NONE | UDMA_DST_INC_16 | UDMA_ARB_128);
    uDMAChannelTransferSet(UDMA_CH14_ADC0_0 | UDMA_PRI_SELECT, UDMA_MODE_PINGPONG, (void *)(ADC0_BASE + ADC_O_SSFIFO0), &ADC_OUT, ADC_SAMPLE_BUF_SIZE);
    uDMAChannelTransferSet(UDMA_CH14_ADC0_0 | UDMA_ALT_SELECT, UDMA_MODE_PINGPONG, (void *)(ADC0_BASE + ADC_O_SSFIFO0), &ADC_OUT, ADC_SAMPLE_BUF_SIZE);

    uDMAChannelEnable(UDMA_CH14_ADC0_0); // Enables DMA channel so it can perform transfers

    MAP_IntPrioritySet(INT_ADC0SS0, 0x30);
    IntEnable(INT_UDMAERR);
    ADCIntEnable(ADC0_BASE,0);
    IntEnable(INT_ADC0SS0);
}

  • Hello CamK,

    Are you trying to read the temperature from the internal temperature sensor of TM4C or from and external sensor?

    If you are reading from the internal temperature sensor, did you refer the file: "./examples/peripherals/adc/temperature_sensor.c"? This example does not use uDMA, but this be accomplished before using uDMA.

    If you are reading from an external temperature sensor, does the setup work without uDMA?

    And lastly, do you require using uDMA? For most cases the required through put could be achieved by using interrupt. It takes time and effort to set-up the uDMA correctly and could also take up effort to maintain a code that uses uDMA. So please weigh the effort vs benefits of using uDMA before you make a decision.

    Thanks,
    Sai
  • Hello Sai,

    Thanks for the reply. I am attempting to read the internal temperature sensor along with some various other analog signal levels. I took a look at the example and I use the same equation for calculating the temperature in degrees C (though it has been converted to a different form). I have completed and tested a version of the code that works using interrupts. I get back realistic values for all of my measurements. 

    I'd like to use the uDMA, but this code results in all of the ADC values returning as 4095. I don't see any glaring mistakes and was hoping someone else may see something or offer suggestions. The code is very similar to some previously posted here on the forum (modified to fit my needs).

    Regards,

    Cam

  • Hello CamK,

    Did you make any progress? If not, I can try to use uDMA to read the internal temperature of the MCU and get back.

    Thanks,
    Sai