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.

ADC with DMA for TM4C123GH6

What I am trying to do is sample with the ADC at 1 MSPS in 8 of the analog channels, while oversampling them. After sampling the eight analog pin of the sequence I would like to create an interrupt and use the uDMA to transfer the values to a global variable. I pieced together a code from some examples and would like to ask several questions. If I am trying to use uDMAChannelTransferSet to point to the address where the values are to be stored ( the global variable) what address this would be? Also what would be the correct size of my ADC ui32TransferSize. Finally, am I missing some important initialization? 

Thank you very much,

Michelle

#include <stdbool.h>
#include <stdint.h>

#include "inc/hw_ints.h"
#include "inc/hw_memmap.h"
#include "inc/hw_adc.h"
#include "inc/hw_types.h"
#include "inc/hw_udma.h""
#include "driverlib/debug.h"
#include "driverlib/gpio.h"
#include "driverlib/interrupt.h"
#include "driverlib/pin_map.h"
#include "driverlib/sysctl.h"
#include "driverlib/adc.h"
#include "driverlib/udma.h"
#define TARGET_IS_BLIZZARD_RB1
#include "driverlib/rom.h"

uint32_t udmaCtrlTable[1024/sizeof(uint32_t)]__attribute__((aligned(1024)));


int main(void)
{

	ROM_SysCtlClockSet(SYSCTL_SYSDIV_5|SYSCTL_USE_PLL|SYSCTL_OSC_MAIN|SYSCTL_XTAL_16MHZ);

	SysCtlDelay(10);

        GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_0);
        GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_1);
        GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_2);
        GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_3);
        GPIOPinTypeADC(GPIO_PORTD_BASE, GPIO_PIN_0);
        GPIOPinTypeADC(GPIO_PORTD_BASE, GPIO_PIN_1);
        GPIOPinTypeADC(GPIO_PORTD_BASE, GPIO_PIN_2);
        GPIOPinTypeADC(GPIO_PORTD_BASE, GPIO_PIN_3);

	init_ADC();
        

		while(1)
		{

		}
}


void init_ADC()
{
	SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);    
	SysCtlDelay(10); 

	ADCClockConfigSet(ADC0_BASE, ADC_CLOCK_SRC_PIOSC | ADC_CLOCK_RATE_FULL, 1);
	// ADCClockConfigSet(uint32_t ui32Base, uint32_t ui32Config, uint32_t ui32ClockDiv)

	ADCHardwareOversampleConfigure(ADC0_BASE, 4);
	

	SysCtlDelay(10); // Time for the clock configuration to set

	ADCSequenceDisable(ADC0_BASE,0);
	// With sequence disabled, it is now safe to load the new configuration parameters

	ADCSequenceConfigure(ADC0_BASE, 0, ADC_TRIGGER_ALWAYS, 0);
	// ADCSequenceConfigure(uint32_t ui32Base, uint32_t ui32SequenceNum, uint32_t ui32Trigger,
	//     uint32_t ui32Priority)
	

	ADCSequenceStepConfigure(ADC0_BASE,0,0,ADC_CTL_CH0); 
	ADCSequenceStepConfigure(ADC0_BASE,0,1,ADC_CTL_CH1); 
	ADCSequenceStepConfigure(ADC0_BASE,0,2,ADC_CTL_CH2); 
	ADCSequenceStepConfigure(ADC0_BASE,0,3,ADC_CTL_CH3); 
	ADCSequenceStepConfigure(ADC0_BASE,0,4,ADC_CTL_CH4); 
	ADCSequenceStepConfigure(ADC0_BASE,0,5,ADC_CTL_CH5); 
	ADCSequenceStepConfigure(ADC0_BASE,0,6,ADC_CTL_CH6); 
	ADCSequenceStepConfigure(ADC0_BASE,0,7,ADC_CTL_CH7 | ADC_CTL_END | ADC_CTL_IE); 
	// ADCSequenceStepConfigure(uint32_t ui32Base, uint32_t ui32SequenceNum, uint32_t ui32Step, uint32_t ui32Config)

	ADCSequenceEnable(ADC0_BASE,0); //Once configuration is set, re-enable the sequencer

	uDMAEnable(); // Enables uDMA
	uDMAControlBaseSet(udmaCtrlTable);
	// Configures the base address of the channel control table. Table resides in system memory and holds control
	//     information for each uDMA channel. Table must be aligned on a 1024-byte boundary. Base address must be
	//     configured before any of the channel functions can be used

	ADCSequenceDMAEnable(ADC0_BASE,0);
	// Allows DMA requests to be generated based on the FIFO level of the sample sequencer (SS0)

	uDMAChannelAttributeDisable(UDMA_CHANNEL_ADC0, UDMA_ATTR_ALTSELECT | UDMA_ATTR_HIGH_PRIORITY | UDMA_ATTR_REQMASK);
	// Start with Ping-pong PRI side, low priority, unmask

	uDMAChannelAttributeEnable(UDMA_CHANNEL_ADC0, UDMA_ATTR_USEBURST);
	// Only allow burst transfers

	uDMAChannelControlSet(UDMA_CHANNEL_ADC0 | UDMA_PRI_SELECT, UDMA_SIZE_16 | UDMA_SRC_INC_NONE | UDMA_DST_INC_16 | UDMA_ARB_128);
	uDMAChannelControlSet(UDMA_CHANNEL_ADC0 | UDMA_ALT_SELECT, UDMA_SIZE_16 | UDMA_SRC_INC_NONE | UDMA_DST_INC_16 | UDMA_ARB_128);
	// uDMAChannelControlSet(uint32_t ui32ChannelStructIndex, uint32_t ui32Control)

	uDMAChannelTransferSet(UDMA_CHANNEL_ADC0 | UDMA_PRI_SELECT, UDMA_MODE_PINGPONG, (void *)(ADC0_BASE + ADC_O_SSFIFO0), ?, ?);
	uDMAChannelTransferSet(UDMA_CHANNEL_ADC0 | UDMA_ALT_SELECT, UDMA_MODE_PINGPONG, (void *)(ADC0_BASE + ADC_O_SSFIFO0), ?, ?);
	// uDMAChannelTransferSet(uint32_t ui32ChannelStructIndex, uint32_t ui32Mode, void *pvSrcAddr, void *pvDstAddr, uint32_t ui32TransferSize)
	// pvSrcAddr is the source address for the transfer in this case from hw_adc.h ADC_O_SSFIFO0 is the result of the FIFO 0 register
	// pvDstAddr is the destination address for the transfer
	// ui32TransferSize is the number of data items to transfer

	IntEnable(INT_ADC0SS0);
	ADCIntEnableEx(ADC0_BASE, ADC_INT_DMA_SS0); // Enables ADC interrupt source due to DMA on ADC sample sequence 0
	uDMAChannelEnable(UDMA_CHANNEL_ADC0); // Enables DMA channel so it can perform transfers
}

  • Hello Michelle

    The address of the global variable is assigned at link time based on the buffer allocation. The transfer size is the size of the buffer at max. So if you have a buffer declared as g_ui32ADCPingBuffer[1024], then the transfer size will be 1024 to fill the buffer and move to the next buffer in Ping-Pong

    Regards
    Amit
  • Hi Michelle,

    " If I am trying to use uDMAChannelTransferSet to point to the address where the values are to be stored ( the global variable) what address this would be?"
    You are asking the destination address? That should be the variable address of course! Usually you want to use a array if you need to store multiple values. The DMA can increment the destination address (as well the source address if needed).

    " Also what would be the correct size of my ADC ui32TransferSize. " It should be how many items you want to transfer. Imagine you want 100 samples before analyzing them. You set the transfer size to 100, an array of 100 members and set the destination address increment to 1 variable size (16 if you use a array with 16bit variables, its possible to use 8 or 32 address increments.). This way every time the DMA transfer is triggered the sample will go to the array. It will of course fill the entire array from 0 to 99. At the end the DMA can trigger a DMA done interrupt and the transfer will stop, you need to set it up again to restart the transfers.
    Note that there is also the arbitration value. That's how many items per trigger it should transfer. In this case you want just 1 every trigger, but for a UART FIFO for example it would be normal to have a arbitration value of 4 or 8. Read also up on single transfer requests and burst transfer requests.

    One more note. DMA done interrupts are triggered by the DMA and the interrupt flags are on the DMA registers. Even though all that is true the DMA will use the ISR of the peripheral associated with the channel.

    I hope it helps :)
    The DMA can be a real pain but greatly improve the performance.
  • I tried to add the changes you suggested. I declared and array and pointed to the address of it in the UDMAChannelTransferSet. Now when I build and go to the debugger, it goes to FaultISR but I can't find why. Am I still missing something in the declarations?

    Thank you for all the help!

    #include <stdbool.h>
    #include <stdint.h>
    
    #include "inc/hw_ints.h"
    #include "inc/hw_memmap.h"
    #include "inc/hw_adc.h"
    #include "inc/hw_types.h"
    #include "inc/hw_udma.h"
    #include "inc/hw_emac.h"
    #include "driverlib/debug.h"
    #include "driverlib/gpio.h"
    #include "driverlib/interrupt.h"
    #include "driverlib/pin_map.h"
    #include "driverlib/sysctl.h"
    #include "driverlib/uart.h"
    #include "driverlib/adc.h"
    #include "driverlib/udma.h"
    #include "driverlib/emac.h"
    #define TARGET_IS_BLIZZARD_RB1
    #include "driverlib/rom.h"
    #define ADC_SAMPLE_BUF_SIZE (128)
    
    uint32_t udmaCtrlTable[1024/sizeof(uint32_t)]__attribute__((aligned(1024)));
    uint16_t ADC_OUT[8];
    
    
    void init_ADC();
    
    int main(void)
    {
    
    	ROM_SysCtlClockSet(SYSCTL_SYSDIV_5|SYSCTL_USE_PLL|SYSCTL_OSC_MAIN|SYSCTL_XTAL_16MHZ);
    
    	SysCtlDelay(10);
    
    	GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_0);
    	GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_1);
    	GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_2);
    	GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_3);
    	GPIOPinTypeADC(GPIO_PORTD_BASE, GPIO_PIN_0);
    	GPIOPinTypeADC(GPIO_PORTD_BASE, GPIO_PIN_1);
    	GPIOPinTypeADC(GPIO_PORTD_BASE, GPIO_PIN_2);
    	GPIOPinTypeADC(GPIO_PORTD_BASE, GPIO_PIN_3);
    
    	init_ADC();
    
    		while(1)
    		{
    
    		}
    }
    
    
    void init_ADC()
    {
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);    //Enable the clock to ADC module
    	SysCtlDelay(10); // Time for the peripheral enable to set
    
    	ADCClockConfigSet(ADC0_BASE, ADC_CLOCK_SRC_PIOSC | ADC_CLOCK_RATE_FULL, 1);
    	// ADCClockConfigSet(uint32_t ui32Base, uint32_t ui32Config, uint32_t ui32ClockDiv)
    
    	ADCHardwareOversampleConfigure(ADC0_BASE, 2);
    
    	ADCSequenceDisable(ADC0_BASE,0);
    	// With sequence disabled, it is now safe to load the new configuration parameters
    
    	ADCSequenceConfigure(ADC0_BASE, 0, ADC_TRIGGER_ALWAYS, 0);
    	// ADCSequenceConfigure(uint32_t ui32Base, uint32_t ui32SequenceNum, uint32_t ui32Trigger,
    
    	ADCSequenceStepConfigure(ADC0_BASE,0,0,ADC_CTL_CH0); 
    	ADCSequenceStepConfigure(ADC0_BASE,0,1,ADC_CTL_CH1); 
    	ADCSequenceStepConfigure(ADC0_BASE,0,2,ADC_CTL_CH2); 
    	ADCSequenceStepConfigure(ADC0_BASE,0,3,ADC_CTL_CH3); 
    	ADCSequenceStepConfigure(ADC0_BASE,0,4,ADC_CTL_CH4);
    	ADCSequenceStepConfigure(ADC0_BASE,0,5,ADC_CTL_CH5); 
    	ADCSequenceStepConfigure(ADC0_BASE,0,6,ADC_CTL_CH6); 
    	ADCSequenceStepConfigure(ADC0_BASE,0,7,ADC_CTL_CH7 | ADC_CTL_END | ADC_CTL_IE); 
    	// ADCSequenceStepConfigure(uint32_t ui32Base, uint32_t ui32SequenceNum, uint32_t ui32Step, uint32_t ui32Config)
    
    	ADCSequenceEnable(ADC0_BASE,0); //Once configuration is set, re-enable the sequencer
    
    	uDMAEnable(); // Enables uDMA
    	uDMAControlBaseSet(udmaCtrlTable);
    	// Configures the base address of the channel control table. Table resides in system memory and holds control
    	//     information for each uDMA channel. Table must be aligned on a 1024-byte boundary. Base address must be
    	//     configured before any of the channel functions can be used
    
    	ADCSequenceDMAEnable(ADC0_BASE,0);
    	// Allows DMA requests to be generated based on the FIFO level of the sample sequencer (SS0)
    
    	uDMAChannelAttributeDisable(UDMA_CHANNEL_ADC0, UDMA_ATTR_ALTSELECT | UDMA_ATTR_HIGH_PRIORITY | UDMA_ATTR_REQMASK);
    	// Start with Ping-pong PRI side, low priority, unmask
    
    	uDMAChannelAttributeEnable(UDMA_CHANNEL_ADC0, UDMA_ATTR_USEBURST);
    	// Only allow burst transfers
    
    	uDMAChannelControlSet(UDMA_CHANNEL_ADC0 | UDMA_PRI_SELECT, UDMA_SIZE_16 | UDMA_SRC_INC_NONE | UDMA_DST_INC_16 | UDMA_ARB_128);
    	uDMAChannelControlSet(UDMA_CHANNEL_ADC0 | UDMA_ALT_SELECT, UDMA_SIZE_16 | UDMA_SRC_INC_NONE | UDMA_DST_INC_16 | UDMA_ARB_128);
    	// uDMAChannelControlSet(uint32_t ui32ChannelStructIndex, uint32_t ui32Control)
    	// ui32Control is the logical OR of five values: the data size, the source address incremen, the destination address
    	//     increment, the arbitration size and the burst flag
    
    	uDMAChannelTransferSet(UDMA_CHANNEL_ADC0 | UDMA_PRI_SELECT, UDMA_MODE_PINGPONG, (void *)(ADC0_BASE + ADC_O_SSFIFO0), &ADC_OUT, ADC_SAMPLE_BUF_SIZE);
    	uDMAChannelTransferSet(UDMA_CHANNEL_ADC0 | UDMA_ALT_SELECT, UDMA_MODE_PINGPONG, (void *)(ADC0_BASE + ADC_O_SSFIFO0), &ADC_OUT, ADC_SAMPLE_BUF_SIZE);
    	// uDMAChannelTransferSet(uint32_t ui32ChannelStructIndex, uint32_t ui32Mode, void *pvSrcAddr, void *pvDstAddr, uint32_t ui32TransferSize)
    	// pvSrcAddr is the source address for the transfer in this case from hw_adc.h ADC_O_SSFIFO0 is the result of the FIFO 0 register
    	// pvDstAddr is the destination address for the transfer
    	// ui32TransferSize is the number of data items to transfer
    
    	IntEnable(INT_ADC0SS0);
    	ADCIntEnableEx(ADC0_BASE, ADC_INT_DMA_SS0); // Enables ADC interrupt source due to DMA on ADC sample sequence 0
    	uDMAChannelEnable(UDMA_CHANNEL_ADC0); // Enables DMA channel so it can perform transfers

  • Hello Michelle,

    The SysCtlPeripheralEnable for the GPIO Ports is missing. For more details look at Issue #2 and Issue #6 on how to program and debug fault

    e2e.ti.com/.../374640

    Regards
    Amit
  • Try using the breakpoints, step by step execution, going into functions until you find the source of the problem, that would be my suggestion ;)
    See if you can see after what the faultISR occurs.
  • @Amit god dam it XD
    In this thread you always answer while I am writing :p

    I have to get faster at writing in English
  • May we note that (sometimes) Amit has (likely) made a similar (although more "PC") comment!    (aimed @ you, Robert, Veikko, even moi...)

  • Amit and Luis thank you so much for your help. You were right I missed PeripheralEnable for both the GPIOs and the UDMA. Now that the issue is corrected, the code runs complete until getting into the infinite while loop on main, then it goes to IntDefaultHandler. By commenting my interrupt enables, I observed that this does not happen when only uDMAChannelEnable(UDMA_CHANNEL_ADC0) is commented. If uDMA is enabled, why would the processor not be expecting the interrupt?

    Thank you again for the help,

    Michelle

    #include <stdbool.h>
    #include <stdint.h>
    
    #include "inc/hw_ints.h"
    #include "inc/hw_memmap.h"
    #include "inc/hw_adc.h"
    #include "inc/hw_types.h"
    #include "inc/hw_udma.h"
    #include "inc/hw_emac.h"
    #include "driverlib/debug.h"
    #include "driverlib/gpio.h"
    #include "driverlib/interrupt.h"
    #include "driverlib/pin_map.h"
    #include "driverlib/sysctl.h"
    #include "driverlib/uart.h"
    #include "driverlib/adc.h"
    #include "driverlib/udma.h"
    #include "driverlib/emac.h"
    #define TARGET_IS_BLIZZARD_RB1
    #include "driverlib/rom.h"
    #define ADC_SAMPLE_BUF_SIZE (128)
    
    uint32_t udmaCtrlTable[1024/sizeof(uint32_t)]__attribute__((aligned(1024)));
    uint16_t ADC_OUT[8];
    
    
    void init_ADC();
    
    int main(void)
    {
    
    	ROM_SysCtlClockSet(SYSCTL_SYSDIV_5|SYSCTL_USE_PLL|SYSCTL_OSC_MAIN|SYSCTL_XTAL_16MHZ);
    
    	SysCtlDelay(20);
    
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);    //Enable the clock to ADC module
    	SysCtlDelay(10); // Time for the peripheral enable to set
    
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_UDMA);
    	SysCtlDelay(10);
    
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);
    	SysCtlDelay(30);
    
    	GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_0);
    	GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_1);
    	GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_2);
    	GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_3);
    	GPIOPinTypeADC(GPIO_PORTD_BASE, GPIO_PIN_0);
    	GPIOPinTypeADC(GPIO_PORTD_BASE, GPIO_PIN_1);
    	GPIOPinTypeADC(GPIO_PORTD_BASE, GPIO_PIN_2);
    	GPIOPinTypeADC(GPIO_PORTD_BASE, GPIO_PIN_3);
    	SysCtlDelay(80);
    
    	IntMasterEnable();
    
    	init_ADC();
    
    		while(1)
    		{
    
    		}
    }
    
    
    void init_ADC()
    {
    
    	ADCClockConfigSet(ADC0_BASE, ADC_CLOCK_SRC_PIOSC | ADC_CLOCK_RATE_FULL, 1);
    	// ADCClockConfigSet(uint32_t ui32Base, uint32_t ui32Config, uint32_t ui32ClockDiv)
    	// ui32Base is the base address of the ADC configure and must always be ADC0_BASE
    	// ui32Config is the value used to configure the ADC clock input. For TM4C123 device
    	//     ADC_CLOCK_SRC_PIOSC is PLL/25 always thus 400MHz/25 = 16 MHz
    	// ui32ClockDiv is the input clock divider which is in the range of 1 to 64
    
    	ADCHardwareOversampleConfigure(ADC0_BASE, 2);
    	// Oversampling average multiple samples from same analog input. Rates suported are
    	//     2x, 4x, 8x, 16x, 32x, 64x. If set to 0 hardware oversampling is disabled
    	SysCtlDelay(10); // Time for the clock configuration to set
    
    	ADCSequenceDisable(ADC0_BASE,0);
    	// With sequence disabled, it is now safe to load the new configuration parameters
    
    	ADCSequenceConfigure(ADC0_BASE, 0, ADC_TRIGGER_ALWAYS, 0);
    	// ADCSequenceConfigure(uint32_t ui32Base, uint32_t ui32SequenceNum, uint32_t ui32Trigger,
    	//     uint32_t ui32Priority)
    	// ui32Base is the base address of the ADC configure and must always be ADC0_BASE
    	// ui32SequenceNum is the sample sequence number (depends on sequencer used)
    	// ui32Trigger is the trigger source that innitiates the sampling sequence, in this case
    	//     the ADC is always running
    	// ui32Priority is the relative priority with respect to other sample sequences 0 being
    	//     the highest priority and 3 being the lowest
    
    	ADCSequenceStepConfigure(ADC0_BASE,0,0,ADC_CTL_CH0); 
    	ADCSequenceStepConfigure(ADC0_BASE,0,1,ADC_CTL_CH1); 
    	ADCSequenceStepConfigure(ADC0_BASE,0,2,ADC_CTL_CH2); 
    	ADCSequenceStepConfigure(ADC0_BASE,0,3,ADC_CTL_CH3); 
    	ADCSequenceStepConfigure(ADC0_BASE,0,4,ADC_CTL_CH4); 
    	ADCSequenceStepConfigure(ADC0_BASE,0,5,ADC_CTL_CH5); 
    	ADCSequenceStepConfigure(ADC0_BASE,0,6,ADC_CTL_CH6); 
    	ADCSequenceStepConfigure(ADC0_BASE,0,7,ADC_CTL_CH7 | ADC_CTL_END | ADC_CTL_IE); // SC Voltage Sense
    	// ADCSequenceStepConfigure(uint32_t ui32Base, uint32_t ui32SequenceNum, uint32_t ui32Step, uint32_t ui32Config)
    	// ui32Base is the base address of the ADC configure and must always be ADC0_BASE
    	// ui32SequenceNum is the sample sequence number (depends on sequencer used)
    	// ui32Step is the step to be configured
    	// ui32Config is the configuration of this step. Routs it to an analog input. Also defines the last in the
    	//     sequence with ADC_CTL_END and also fires an interrupt every 8 samples with ADC_CTL_IE
    
    	ADCSequenceEnable(ADC0_BASE,0); //Once configuration is set, re-enable the sequencer
    
    	uDMAEnable(); // Enables uDMA
    	uDMAControlBaseSet(udmaCtrlTable);
    	// Configures the base address of the channel control table. Table resides in system memory and holds control
    	//     information for each uDMA channel. Table must be aligned on a 1024-byte boundary. Base address must be
    	//     configured before any of the channel functions can be used
    
    	ADCSequenceDMAEnable(ADC0_BASE,0);
    	// Allows DMA requests to be generated based on the FIFO level of the sample sequencer (SS0)
    
    	uDMAChannelAttributeDisable(UDMA_CHANNEL_ADC0, UDMA_ATTR_ALTSELECT | UDMA_ATTR_HIGH_PRIORITY | UDMA_ATTR_REQMASK);
    	// Start with Ping-pong PRI side, low priority, unmask
    
    	uDMAChannelAttributeEnable(UDMA_CHANNEL_ADC0, UDMA_ATTR_USEBURST);
    	// Only allow burst transfers
    
    	uDMAChannelControlSet(UDMA_CHANNEL_ADC0 | UDMA_PRI_SELECT, UDMA_SIZE_16 | UDMA_SRC_INC_NONE | UDMA_DST_INC_16 | UDMA_ARB_128);
    	uDMAChannelControlSet(UDMA_CHANNEL_ADC0 | UDMA_ALT_SELECT, UDMA_SIZE_16 | UDMA_SRC_INC_NONE | UDMA_DST_INC_16 | UDMA_ARB_128);
    	// uDMAChannelControlSet(uint32_t ui32ChannelStructIndex, uint32_t ui32Control)
    	// ui32Control is the logical OR of five values: the data size, the source address incremen, the destination address
    	//     increment, the arbitration size and the burst flag
    
    	uDMAChannelTransferSet(UDMA_CHANNEL_ADC0 | UDMA_PRI_SELECT, UDMA_MODE_PINGPONG, (void *)(ADC0_BASE + ADC_O_SSFIFO0), &ADC_OUT, ADC_SAMPLE_BUF_SIZE);
    	uDMAChannelTransferSet(UDMA_CHANNEL_ADC0 | UDMA_ALT_SELECT, UDMA_MODE_PINGPONG, (void *)(ADC0_BASE + ADC_O_SSFIFO0), &ADC_OUT, ADC_SAMPLE_BUF_SIZE);
    	// uDMAChannelTransferSet(uint32_t ui32ChannelStructIndex, uint32_t ui32Mode, void *pvSrcAddr, void *pvDstAddr, uint32_t ui32TransferSize)
    	// pvSrcAddr is the source address for the transfer in this case from hw_adc.h ADC_O_SSFIFO0 is the result of the FIFO 0 register
    	// pvDstAddr is the destination address for the transfer
    	// ui32TransferSize is the number of data items to transfer
    
    	IntEnable(INT_ADC0SS0);
    	ADCIntEnableEx(ADC0_BASE, ADC_INT_DMA_SS0); // Enables ADC interrupt source due to DMA on ADC sample sequence 0
    	uDMAChannelEnable(UDMA_CHANNEL_ADC0); // Enables DMA channel so it can perform transfers
    }
    

  • Hi Michelle,

    I don't quite get the question.
    Could you please be more clearwith what happens when each function commented/remove? IntEnable(INT_ADC0SS0) and uDMAChannelEnable(UDMA_CHANNEL_ADC0), right?
  • Hello Michelle

    On the TM4C123 the interrupt line is used by the DMA for trigger action. As a result the Interrupt gets masked. This is mentioned in the TM4C123 uDMA chapter.

    Regards
    Amit
  • Hi Luis,

    When IntEnable(INT_ADC0SS0) is commented, the code runs and ADC_OUT array takes values only once but never updates them. When uDMAChannelEnable(UDMA_CHANNEL_ADC0) is commented the code runs but all the values in ADC_OUT are 0 (which makes sense because there is no transfer to the global variable). Finally when nothing is commented, ADC_OUT takes a value but then the program gets stuck in IntDefaultHandler.

    Michelle
  • Hi Amit,

    Wouldn't uDMAChannelAttributeDisable(UDMA_CHANNEL_ADC0, UDMA_ATTR_ALTSELECT | UDMA_ATTR_HIGH_PRIORITY | UDMA_ATTR_REQMASK); unmask it?

    Thank you,
    Michelle
  • Hello Michelle,

    Note that the completion of the UDMA is also on the same interrupt vector as the requesting peripheral. In the interrupt handler of the ADC you would need to reinitialize the uDMA.

    Regards
    Amit
  • Hi Amit,

    I am a little lost, how should I reinitialize uDMA in the handler of the ADC? This is the code I have for the ADC handler

    void ADCprocess(uint32_t ch)
    {
        if ((((tDMAControlTable *) udmaCtrlTable)[ch].ui32Control & UDMA_CHCTL_XFERMODE_M) != UDMA_MODE_STOP) return;
        uDMAChannelTransferSet(ch, UDMA_MODE_PINGPONG, (void *)(ADC0_BASE + ADC_O_SSFIFO0), &ADC_OUT, ADC_SAMPLE_BUF_SIZE);
    }
    
    void ADCseq0Handler()
    {
    	*(uint32_t *) (ADC0_BASE + ADC_O_ISC) = ADC_INT_DMA_SS0;
    	ADCprocess(UDMA_CHANNEL_ADC0 | UDMA_PRI_SELECT);
    	ADCprocess(UDMA_CHANNEL_ADC0 | UDMA_ALT_SELECT);
    }

    Thank you again for all the help,

    Michelle

  • Hello Michelle,

    First of all on TM4C123 the define ADC_INT_DMA_SS0 does not occur. Also when you mentioned that the code gets stuck in IntDefaultHandler did you mean ADCseqHandler?

    Regards
    Amit
  • Hi Amit,

    Then ADCIntEnableEx(ADC0_BASE, ADC_INT_DMA_SS0); doesn't do anything? And I was stuck in IntDefaultHandler because I forgot to update the handler on the vector table of the startup file. Now that I have updated it the code runs up to the ADCprocess function and then it gets trapped on the FaultISR loop.

    Thank you for the help,
    Michelle
  • Hello Michelle

    Not on the TM4C123. You can check the data sheet for the device and this bit is not marked in the corresponding register.

    On how to diagnose the cause of Bus fault...

    e2e.ti.com/.../374640

    Regards
    Amit
  • Hi Amit,

    I went through the steps in the document. NVIC_FAULT_STAT is 0x00000100 which is NVIC_FAULT_STAT_IBUS or Instruction Bus Error. Is this because I have not re initialize uDMA? Also if ADC_INT_DMA_SS0 does't exist, how could I clear the interrupt status register?

    Thank you,
    Michelle
  • Hi Amit,

    I changed the ADC_SAMPLE_BUF_SIZE to 8 and that made it stop going into FAULT_ISR. Nevertheless, the values of the ADC are not updating, they only load once at the beginning. Sometimes they refresh if I pause the debugger and start again but it is random. I am still not sure what to change ADC_INT_DMA_SS0 for and if that would solve the problem. From what I can gather with the break points is that it goes through the ADC handler twice and then it just stays in the infinite while loop of main.

    Thanks,
    Michelle

  • Hello Michelle,

    When it goes for the first time to the ADC Interrupt Handler, then it is because the primary structure is over. The ADCprocess is supposed to initialize the Primary Control Structure. Does that happen? Same for the Alternate structure.

    Note that in Ping Pong it may happen that when both buffers are in STOP condition and that you are using the debugger to step through the code, the UDMA channel is getting disabled.

    Regards
    Amit
  • Hi Amit,

    Yes it goes into the ADCProcess twice. The first time both PRI and ALT pass through the If statement and the second time they get rejected by it and the program then stays in the main loop. Even with no break points, the ADC values do not update. I am really lost now since I don't know how to tune the ADC handler to work in this application. I am sure the initialization work since the values that the ADC records once are correct.

    Thanks for all the help, it is the first time I attempt DMA with the Tiva launchpad
    Michelle
  • Hello Michelle,

    Instead of using the Always Trigger I would suggest using Processor Trigger, in the main code. The way to do it would be to implement in a while 1 loop, a check for ADC Busy Bit. If the bit is set then wait till it does not become 0 and then do a processor trigger. This will give a lot of control on the program during debug mode to see what is happening between ADC and uDMA. Do note that do not open a debugger memory window or ADC register window as it may cause an unwanted read of the ADC data.

    something like the following
    while(1)
    {
    while(ADCBusy);
    ADCProcessorTrigger;
    SysCtlDelay(10);
    }

    Regards
    Amit
  • Hello Amit,

    I was missing one ADC initialization which was making the ADC interrupt handle to only happen twice and then stop completely. Now that the initialization is there, the code runs perfectly and ADC_OUT updates with no problem. Now the problem that I have is that I need to switch to ADC1 instead of ADC0 because I have to implement another complex function that is already writen with ADC0. I tried changing all the declarations that have ADC0 to ADC1 but that does not work. The code runs, the ADC interrupt works too but the ADC_OUT values are always 0 regarless if how many times I go into the interrupt. My question would be, from the code below, what changes should I make to make it work with ADC1 instead of ADC0.

    Thank you,

    Michelle

    #include <stdbool.h>
    #include <stdint.h>
    
    #include "inc/hw_ints.h"
    #include "inc/hw_memmap.h"
    #include "inc/hw_adc.h"
    #include "inc/hw_types.h"
    #include "inc/hw_udma.h"
    #include "inc/hw_emac.h"
    #include "driverlib/debug.h"
    #include "driverlib/gpio.h"
    #include "driverlib/interrupt.h"
    #include "driverlib/pin_map.h"
    #include "driverlib/sysctl.h"
    #include "driverlib/uart.h"
    #include "driverlib/adc.h"
    #include "driverlib/udma.h"
    #include "driverlib/emac.h"
    #define TARGET_IS_BLIZZARD_RB1
    #include "driverlib/rom.h"
    #define ADC_SAMPLE_BUF_SIZE (8)
    
    uint32_t udmaCtrlTable[1024/sizeof(uint32_t)]__attribute__((aligned(1024)));
    uint16_t ADC_OUT[8];
    uint32_t n=0;
    
    void init_ADC();
    static uint32_t g_ui32DMAErrCount = 0;
    
    void uDMAErrorHandler(void)
    {
     uint32_t ui32Status;
     ui32Status = ROM_uDMAErrorStatusGet();
     if(ui32Status)
     {
     ROM_uDMAErrorStatusClear();
     g_ui32DMAErrCount++;
     }
    }
    
    void ADCprocess(uint32_t ch)
    {
        if ((((tDMAControlTable *) udmaCtrlTable)[ch].ui32Control & UDMA_CHCTL_XFERMODE_M) != UDMA_MODE_STOP) return;
        uDMAChannelTransferSet(ch, UDMA_MODE_PINGPONG, (void *)(ADC0_BASE + ADC_O_SSFIFO0), &ADC_OUT, ADC_SAMPLE_BUF_SIZE);
        uDMAChannelEnable(UDMA_CHANNEL_ADC0);
    }
    
    void ADCseq0Handler()
    {
    	ADCIntClear(ADC0_BASE, 0);
            n++;
    	ADCprocess(UDMA_CHANNEL_ADC0 | UDMA_PRI_SELECT);
    	ADCprocess(UDMA_CHANNEL_ADC0 | UDMA_ALT_SELECT);
    }
    
    int main(void)
    {
    
    	SysCtlClockSet(SYSCTL_SYSDIV_5|SYSCTL_USE_PLL|SYSCTL_OSC_MAIN|SYSCTL_XTAL_16MHZ);
    
    	SysCtlDelay(20);
    
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);    //Enable the clock to ADC module
    	SysCtlDelay(10); // Time for the peripheral enable to set
    
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_UDMA);
    	SysCtlDelay(10);
    
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);
    	SysCtlDelay(30);
    
    	GPIOPinTypeADC(GPIO_PORTB_BASE, GPIO_PIN_5);
    	GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_0);
    	GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_1);
    	GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_2);
    	GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_3);
    	GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_4);
    	GPIOPinTypeADC(GPIO_PORTD_BASE, GPIO_PIN_1);
    	GPIOPinTypeADC(GPIO_PORTD_BASE, GPIO_PIN_2);
    
    	SysCtlDelay(80);
    
    	IntMasterEnable();
    
    	init_ADC();
    
    		while(1)
    		{
    
    		}
    }
    
    void init_ADC()
    {
    
    	ADCClockConfigSet(ADC0_BASE, ADC_CLOCK_SRC_PIOSC | ADC_CLOCK_RATE_FULL, 1);
    	// ADCClockConfigSet(uint32_t ui32Base, uint32_t ui32Config, uint32_t ui32ClockDiv)
    	// ui32Base is the base address of the ADC configure
    	// ui32Config is the value used to configure the ADC clock input. For TM4C123 device
    	//     ADC_CLOCK_SRC_PIOSC is PLL/25 always thus 400MHz/25 = 16 MHz
    	// ui32ClockDiv is the input clock divider which is in the range of 1 to 64
    
    	ADCHardwareOversampleConfigure(ADC0_BASE, 64);
    	// Oversampling average multiple samples from same analog input. Rates suported are
    	//     2x, 4x, 8x, 16x, 32x, 64x. If set to 0 hardware oversampling is disabled
    	SysCtlDelay(10); // Time for the clock configuration to set
    
    	IntDisable(INT_ADC0SS0);
    	ADCIntDisable(ADC0_BASE, 0);
    	ADCSequenceDisable(ADC0_BASE,0);
    	// With sequence disabled, it is now safe to load the new configuration parameters
    
    	ADCSequenceConfigure(ADC0_BASE, 0, ADC_TRIGGER_ALWAYS, 0);
    	// ADCSequenceConfigure(uint32_t ui32Base, uint32_t ui32SequenceNum, uint32_t ui32Trigger,
    	//     uint32_t ui32Priority)
    	// ui32Base is the base address of the ADC configure and must always be ADC0_BASE
    	// ui32SequenceNum is the sample sequence number (depends on sequencer used)
    	// ui32Trigger is the trigger source that innitiates the sampling sequence, in this case
    	//     the ADC is always running
    	// ui32Priority is the relative priority with respect to other sample sequences 0 being
    	//     the highest priority and 3 being the lowest
    
    	ADCSequenceStepConfigure(ADC0_BASE,0,0,ADC_CTL_CH0); 
    	ADCSequenceStepConfigure(ADC0_BASE,0,1,ADC_CTL_CH1); 
    	ADCSequenceStepConfigure(ADC0_BASE,0,2,ADC_CTL_CH2); 
    	ADCSequenceStepConfigure(ADC0_BASE,0,3,ADC_CTL_CH3); 
    	ADCSequenceStepConfigure(ADC0_BASE,0,4,ADC_CTL_CH4); 
    	ADCSequenceStepConfigure(ADC0_BASE,0,5,ADC_CTL_CH5); 
    	ADCSequenceStepConfigure(ADC0_BASE,0,6,ADC_CTL_CH9); 
    	ADCSequenceStepConfigure(ADC0_BASE,0,7,ADC_CTL_CH11 | ADC_CTL_END | ADC_CTL_IE); 
    	// ADCSequenceStepConfigure(uint32_t ui32Base, uint32_t ui32SequenceNum, uint32_t ui32Step, uint32_t ui32Config)
    	// ui32Base is the base address of the ADC configure and must always be ADC0_BASE
    	// ui32SequenceNum is the sample sequence number (depends on sequencer used)
    	// ui32Step is the step to be configured
    	// ui32Config is the configuration of this step. Routs it to an analog input. Also defines the last in the
    	//     sequence with ADC_CTL_END and also fires an interrupt every 8 samples with ADC_CTL_IE
    
    	ADCSequenceEnable(ADC0_BASE,0); //Once configuration is set, re-enable the sequencer
    	ADCIntClear(ADC0_BASE,0);
    	uDMAEnable(); // Enables uDMA
    	uDMAControlBaseSet(udmaCtrlTable);
    	// Configures the base address of the channel control table. Table resides in system memory and holds control
    	//     information for each uDMA channel. Table must be aligned on a 1024-byte boundary. Base address must be
    	//     configured before any of the channel functions can be used
    
    	ADCSequenceDMAEnable(ADC0_BASE,0);
    	// Allows DMA requests to be generated based on the FIFO level of the sample sequencer (SS0)
    
    	uDMAChannelAttributeDisable(UDMA_CHANNEL_ADC0, UDMA_ATTR_ALTSELECT | UDMA_ATTR_HIGH_PRIORITY | UDMA_ATTR_REQMASK);
    	// Start with Ping-pong PRI side, low priority, unmask
    
    	uDMAChannelAttributeEnable(UDMA_CHANNEL_ADC0, UDMA_ATTR_USEBURST);
    	// Only allow burst transfers
    
    	uDMAChannelControlSet(UDMA_CHANNEL_ADC0 | UDMA_PRI_SELECT, UDMA_SIZE_16 | UDMA_SRC_INC_NONE | UDMA_DST_INC_16 | UDMA_ARB_128);
    	uDMAChannelControlSet(UDMA_CHANNEL_ADC0 | UDMA_ALT_SELECT, UDMA_SIZE_16 | UDMA_SRC_INC_NONE | UDMA_DST_INC_16 | UDMA_ARB_128);
    	// uDMAChannelControlSet(uint32_t ui32ChannelStructIndex, uint32_t ui32Control)
    	// ui32Control is the logical OR of five values: the data size, the source address incremen, the destination address
    	//     increment, the arbitration size and the burst flag
    
    	uDMAChannelTransferSet(UDMA_CHANNEL_ADC0 | UDMA_PRI_SELECT, UDMA_MODE_PINGPONG, (void *)(ADC0_BASE + ADC_O_SSFIFO0), &ADC_OUT, ADC_SAMPLE_BUF_SIZE);
    	uDMAChannelTransferSet(UDMA_CHANNEL_ADC0 | UDMA_ALT_SELECT, UDMA_MODE_PINGPONG, (void *)(ADC0_BASE + ADC_O_SSFIFO0), &ADC_OUT, ADC_SAMPLE_BUF_SIZE);
    	// uDMAChannelTransferSet(uint32_t ui32ChannelStructIndex, uint32_t ui32Mode, void *pvSrcAddr, void *pvDstAddr, uint32_t ui32TransferSize)
    	// pvSrcAddr is the source address for the transfer in this case from hw_adc.h ADC_O_SSFIFO0 is the result of the FIFO 0 register
    	// pvDstAddr is the destination address for the transfer
    	// ui32TransferSize is the number of data items to transfer
    	ADCIntEnable(ADC0_BASE,0);
    	IntEnable(INT_ADC0SS0);
    	//ADCIntEnableEx(ADC0_BASE, ADC_INT_DMA_SS0); // Enables ADC interrupt source due to DMA on ADC sample sequence 0
    	uDMAChannelEnable(UDMA_CHANNEL_ADC0); // Enables DMA channel so it can perform transfers
    }
    

     

  • Hello Michelle,

    Let me commend you on your persistence (marked by my like to your last post).

    There are the follwoing changes that need to be made

    1. ADC1 Clock Enable function and configuration.
    2. ADC0 Base to be moved to ADC1 base
    3. ADC1 Interrupt Handler to be in the correct position in startup file
    4. DMA channel mapping change to map ADC1 instead of ADC0

    Regards
    Amit
  • Hi Amit,

    Thank you for the like. I really need to get this working that is why I have devoted my time on it nonstop. I made the changes you suggested including the Handler change in the startup file. Interrupt counter n shows that the interrupt handler is being executed but still all the values of ADC_OUT are 0 all the time. Any other ideas? Attached the code.

    Thanks for the help,

    Michelle

    #include <stdbool.h>
    #include <stdint.h>
    
    #include "inc/hw_ints.h"
    #include "inc/hw_memmap.h"
    #include "inc/hw_adc.h"
    #include "inc/hw_types.h"
    #include "inc/hw_udma.h"
    #include "inc/hw_emac.h"
    #include "driverlib/debug.h"
    #include "driverlib/gpio.h"
    #include "driverlib/interrupt.h"
    #include "driverlib/pin_map.h"
    #include "driverlib/sysctl.h"
    #include "driverlib/uart.h"
    #include "driverlib/adc.h"
    #include "driverlib/udma.h"
    #include "driverlib/emac.h"
    #define TARGET_IS_BLIZZARD_RB1
    #include "driverlib/rom.h"
    #define ADC_SAMPLE_BUF_SIZE (8)
    
    uint32_t udmaCtrlTable[1024/sizeof(uint32_t)]__attribute__((aligned(1024)));
    uint16_t ADC_OUT[8];
    uint32_t n=0;
    
    void init_ADC();
    static uint32_t g_ui32DMAErrCount = 0;
    
    void uDMAErrorHandler(void)
    {
     uint32_t ui32Status;
     ui32Status = ROM_uDMAErrorStatusGet();
     if(ui32Status)
     {
     ROM_uDMAErrorStatusClear();
     g_ui32DMAErrCount++;
     }
    }
    
    void ADCprocess(uint32_t ch)
    {
        if ((((tDMAControlTable *) udmaCtrlTable)[ch].ui32Control & UDMA_CHCTL_XFERMODE_M) != UDMA_MODE_STOP) return;
        uDMAChannelTransferSet(ch, UDMA_MODE_PINGPONG, (void *)(ADC1_BASE + ADC_O_SSFIFO0), &ADC_OUT, ADC_SAMPLE_BUF_SIZE);
        uDMAChannelEnable(UDMA_CHANNEL_ADC1);
    }
    
    void ADCseq0Handler()
    {
    	ADCIntClear(ADC1_BASE, 0);
        n++;
    	ADCprocess(UDMA_CHANNEL_ADC1 | UDMA_PRI_SELECT);
    	ADCprocess(UDMA_CHANNEL_ADC1 | UDMA_ALT_SELECT);
    }
    
    int main(void)
    {
    
    	SysCtlClockSet(SYSCTL_SYSDIV_5|SYSCTL_USE_PLL|SYSCTL_OSC_MAIN|SYSCTL_XTAL_16MHZ);
    
    	SysCtlDelay(20);
    
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC1);    //Enable the clock to ADC module
    	SysCtlDelay(10); // Time for the peripheral enable to set
    
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_UDMA);
    	SysCtlDelay(10);
    
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);
    	SysCtlDelay(30);
    
    	GPIOPinTypeADC(GPIO_PORTB_BASE, GPIO_PIN_5);
    	GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_0);
    	GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_1);
    	GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_2);
    	GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_3);
    	GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_4);
    	GPIOPinTypeADC(GPIO_PORTD_BASE, GPIO_PIN_1);
    	GPIOPinTypeADC(GPIO_PORTD_BASE, GPIO_PIN_2);
    
    	SysCtlDelay(80);
    
    	IntMasterEnable();
    
    	init_ADC();
    
    		while(1)
    		{
    
    		}
    }
    
    void init_ADC()
    {
    
    	ADCClockConfigSet(ADC1_BASE, ADC_CLOCK_SRC_PIOSC | ADC_CLOCK_RATE_FULL, 1);
    	// ADCClockConfigSet(uint32_t ui32Base, uint32_t ui32Config, uint32_t ui32ClockDiv)
    	// ui32Base is the base address of the ADC configure and must always be ADC0_BASE
    	// ui32Config is the value used to configure the ADC clock input. For TM4C123 device
    	//     ADC_CLOCK_SRC_PIOSC is PLL/25 always thus 400MHz/25 = 16 MHz
    	// ui32ClockDiv is the input clock divider which is in the range of 1 to 64
    
    	ADCHardwareOversampleConfigure(ADC1_BASE, 64);
    	// Oversampling average multiple samples from same analog input. Rates suported are
    	//     2x, 4x, 8x, 16x, 32x, 64x. If set to 0 hardware oversampling is disabled
    	SysCtlDelay(10); // Time for the clock configuration to set
    
    	IntDisable(INT_ADC1SS0);
    	ADCIntDisable(ADC1_BASE, 0);
    	ADCSequenceDisable(ADC1_BASE,0);
    	// With sequence disabled, it is now safe to load the new configuration parameters
    
    	ADCSequenceConfigure(ADC1_BASE, 0, ADC_TRIGGER_ALWAYS, 0);
    	// ADCSequenceConfigure(uint32_t ui32Base, uint32_t ui32SequenceNum, uint32_t ui32Trigger,
    	//     uint32_t ui32Priority)
    	// ui32Base is the base address of the ADC configure and must always be ADC0_BASE
    	// ui32SequenceNum is the sample sequence number (depends on sequencer used)
    	// ui32Trigger is the trigger source that innitiates the sampling sequence, in this case
    	//     the ADC is always running
    	// ui32Priority is the relative priority with respect to other sample sequences 0 being
    	//     the highest priority and 3 being the lowest
    
    	ADCSequenceStepConfigure(ADC1_BASE,0,0,ADC_CTL_CH0); 
    	ADCSequenceStepConfigure(ADC1_BASE,0,1,ADC_CTL_CH1); 
    	ADCSequenceStepConfigure(ADC1_BASE,0,2,ADC_CTL_CH2); 
    	ADCSequenceStepConfigure(ADC1_BASE,0,3,ADC_CTL_CH3); 
    	ADCSequenceStepConfigure(ADC1_BASE,0,4,ADC_CTL_CH4); 
    	ADCSequenceStepConfigure(ADC1_BASE,0,5,ADC_CTL_CH5); 
    	ADCSequenceStepConfigure(ADC1_BASE,0,6,ADC_CTL_CH9); 
    	ADCSequenceStepConfigure(ADC1_BASE,0,7,ADC_CTL_CH11 | ADC_CTL_END | ADC_CTL_IE); 
    	// ADCSequenceStepConfigure(uint32_t ui32Base, uint32_t ui32SequenceNum, uint32_t ui32Step, uint32_t ui32Config)
    	// ui32Base is the base address of the ADC configure and must always be ADC0_BASE
    	// ui32SequenceNum is the sample sequence number (depends on sequencer used)
    	// ui32Step is the step to be configured
    	// ui32Config is the configuration of this step. Routs it to an analog input. Also defines the last in the
    	//     sequence with ADC_CTL_END and also fires an interrupt every 8 samples with ADC_CTL_IE
    
    	ADCSequenceEnable(ADC1_BASE,0); //Once configuration is set, re-enable the sequencer
    	ADCIntClear(ADC1_BASE,0);
    	uDMAEnable(); // Enables uDMA
    	uDMAControlBaseSet(udmaCtrlTable);
    	// Configures the base address of the channel control table. Table resides in system memory and holds control
    	//     information for each uDMA channel. Table must be aligned on a 1024-byte boundary. Base address must be
    	//     configured before any of the channel functions can be used
    
    	ADCSequenceDMAEnable(ADC1_BASE,0);
    	// Allows DMA requests to be generated based on the FIFO level of the sample sequencer (SS0)
    
    	uDMAChannelAttributeDisable(UDMA_CHANNEL_ADC1, UDMA_ATTR_ALTSELECT | UDMA_ATTR_HIGH_PRIORITY | UDMA_ATTR_REQMASK);
    	// Start with Ping-pong PRI side, low priority, unmask
    
    	uDMAChannelAttributeEnable(UDMA_CHANNEL_ADC1, UDMA_ATTR_USEBURST);
    	// Only allow burst transfers
    
    	uDMAChannelControlSet(UDMA_CHANNEL_ADC1 | UDMA_PRI_SELECT, UDMA_SIZE_16 | UDMA_SRC_INC_NONE | UDMA_DST_INC_16 | UDMA_ARB_128);
    	uDMAChannelControlSet(UDMA_CHANNEL_ADC1 | UDMA_ALT_SELECT, UDMA_SIZE_16 | UDMA_SRC_INC_NONE | UDMA_DST_INC_16 | UDMA_ARB_128);
    	// uDMAChannelControlSet(uint32_t ui32ChannelStructIndex, uint32_t ui32Control)
    	// ui32Control is the logical OR of five values: the data size, the source address incremen, the destination address
    	//     increment, the arbitration size and the burst flag
    
    	uDMAChannelTransferSet(UDMA_CHANNEL_ADC1 | UDMA_PRI_SELECT, UDMA_MODE_PINGPONG, (void *)(ADC1_BASE + ADC_O_SSFIFO0), &ADC_OUT, ADC_SAMPLE_BUF_SIZE);
    	uDMAChannelTransferSet(UDMA_CHANNEL_ADC1 | UDMA_ALT_SELECT, UDMA_MODE_PINGPONG, (void *)(ADC1_BASE + ADC_O_SSFIFO0), &ADC_OUT, ADC_SAMPLE_BUF_SIZE);
    	// uDMAChannelTransferSet(uint32_t ui32ChannelStructIndex, uint32_t ui32Mode, void *pvSrcAddr, void *pvDstAddr, uint32_t ui32TransferSize)
    	// pvSrcAddr is the source address for the transfer in this case from hw_adc.h ADC_O_SSFIFO0 is the result of the FIFO 0 register
    	// pvDstAddr is the destination address for the transfer
    	// ui32TransferSize is the number of data items to transfer
    	ADCIntEnable(ADC1_BASE,0);
    	IntEnable(INT_ADC1SS0);
    	uDMAChannelEnable(UDMA_CHANNEL_ADC1); // Enables DMA channel so it can perform transfers
    }
    

  • Hello Michelle,

    Unlike ADC0 the ADC1 uDMA channels are not mapped on Mux line 0. It is on Mux line 1. You would have to use the uDMAChannelAssign API with the parameter as follows based on the sequencer.

    UDMA_CH24_ADC1_0
    UDMA_CH25_ADC1_1
    UDMA_CH26_ADC1_2
    UDMA_CH27_ADC1_3

    Regards
    Amit
  • Hi Amit,

    I put uDMAChannelAssign(UDMA_CH24_ADC1_0) on line 150 but still same problem. Do I need to put it outside of init_ADC?

    Thank you,
    Michelle

  • Hello Michelle,

    Unfortunately, I do not see a line 150 in the code base!!! It was not marked. Suggest that you attach your code(s).

    Regards
    Amit
  • Hi Amit,

    Here is the code, I arranged it a little. Thank you for the help.

    #include <stdbool.h>
    #include <stdint.h>
    #include "inc/hw_ints.h"
    #include "inc/hw_memmap.h"
    #include "inc/hw_adc.h"
    #include "inc/hw_types.h"
    #include "inc/hw_udma.h"
    #include "driverlib/debug.h"
    #include "driverlib/gpio.h"
    #include "driverlib/interrupt.h"
    #include "driverlib/pin_map.h"
    #include "driverlib/sysctl.h"
    #include "driverlib/adc.h"
    #include "driverlib/udma.h"
    #include "driverlib/rom.h"
    
    //----------------------------------------------------------------
    // DEFINITIONS
    extern const uint8_t g_pui8Image[];
    #define TARGET_IS_BLIZZARD_RB1
    #define ADC_SAMPLE_BUF_SIZE (8)
    uint32_t udmaCtrlTable[1024/sizeof(uint32_t)]__attribute__((aligned(1024)));
    uint16_t ADC_OUT[8];
    uint32_t n=0;
    static uint32_t g_ui32DMAErrCount = 0;
    //----------------------------------------------------------------
    
    //----------------------------------------------------------------
    // INTERRUPT HANDLERS
    void uDMAErrorHandler(void)
    {
     uint32_t ui32Status;
     ui32Status = ROM_uDMAErrorStatusGet();
     if(ui32Status)
     {
     ROM_uDMAErrorStatusClear();
     g_ui32DMAErrCount++;
     }
    }
    
    void ADCprocess(uint32_t ch)
    {
        if ((((tDMAControlTable *) udmaCtrlTable)[ch].ui32Control & UDMA_CHCTL_XFERMODE_M) != UDMA_MODE_STOP) return;
        uDMAChannelTransferSet(ch, UDMA_MODE_PINGPONG, (void *)(ADC1_BASE + ADC_O_SSFIFO0), &ADC_OUT, ADC_SAMPLE_BUF_SIZE);
        uDMAChannelEnable(UDMA_CHANNEL_ADC1);
    }
    
    void ADCseq0Handler()
    {
    	ADCIntClear(ADC1_BASE, 0);
        n++;
    	ADCprocess(UDMA_CHANNEL_ADC1 | UDMA_PRI_SELECT);
    	ADCprocess(UDMA_CHANNEL_ADC1 | UDMA_ALT_SELECT);
    }
    //----------------------------------------------------------------
    
    //----------------------------------------------------------------
    // ADC INITIALIZATION
    void init_ADC()
    {
    
    	ADCClockConfigSet(ADC1_BASE, ADC_CLOCK_SRC_PIOSC | ADC_CLOCK_RATE_FULL, 1);
    	// ADCClockConfigSet(uint32_t ui32Base, uint32_t ui32Config, uint32_t ui32ClockDiv)
    	// ui32Base is the base address of the ADC configure and must always be ADC0_BASE
    	// ui32Config is the value used to configure the ADC clock input. For TM4C123 device
    	//     ADC_CLOCK_SRC_PIOSC is PLL/25 always thus 400MHz/25 = 16 MHz
    	// ui32ClockDiv is the input clock divider which is in the range of 1 to 64
    
    	ADCHardwareOversampleConfigure(ADC1_BASE, 64);
    	// Oversampling average multiple samples from same analog input. Rates suported are
    	//     2x, 4x, 8x, 16x, 32x, 64x. If set to 0 hardware oversampling is disabled
    	SysCtlDelay(10); // Time for the clock configuration to set
    
    	IntDisable(INT_ADC1SS0);
    	ADCIntDisable(ADC1_BASE, 0);
    	ADCSequenceDisable(ADC1_BASE,0);
    	// With sequence disabled, it is now safe to load the new configuration parameters
    
    	ADCSequenceConfigure(ADC1_BASE, 0, ADC_TRIGGER_ALWAYS, 0);
    	// ADCSequenceConfigure(uint32_t ui32Base, uint32_t ui32SequenceNum, uint32_t ui32Trigger,
    	//     uint32_t ui32Priority)
    	// ui32Base is the base address of the ADC configure and must always be ADC0_BASE
    	// ui32SequenceNum is the sample sequence number (depends on sequencer used)
    	// ui32Trigger is the trigger source that innitiates the sampling sequence, in this case
    	//     the ADC is always running
    	// ui32Priority is the relative priority with respect to other sample sequences 0 being
    	//     the highest priority and 3 being the lowest
    
    	ADCSequenceStepConfigure(ADC1_BASE,0,0,ADC_CTL_CH0); 
    	ADCSequenceStepConfigure(ADC1_BASE,0,1,ADC_CTL_CH1); 
    	ADCSequenceStepConfigure(ADC1_BASE,0,2,ADC_CTL_CH2); 
    	ADCSequenceStepConfigure(ADC1_BASE,0,3,ADC_CTL_CH3); 
    	ADCSequenceStepConfigure(ADC1_BASE,0,4,ADC_CTL_CH4); 
    	ADCSequenceStepConfigure(ADC1_BASE,0,5,ADC_CTL_CH5); 
    	ADCSequenceStepConfigure(ADC1_BASE,0,6,ADC_CTL_CH9); 
    	ADCSequenceStepConfigure(ADC1_BASE,0,7,ADC_CTL_CH11 | ADC_CTL_END | ADC_CTL_IE); 
    	// ADCSequenceStepConfigure(uint32_t ui32Base, uint32_t ui32SequenceNum, uint32_t ui32Step, uint32_t ui32Config)
    	// ui32Base is the base address of the ADC configure and must always be ADC0_BASE
    	// ui32SequenceNum is the sample sequence number (depends on sequencer used)
    	// ui32Step is the step to be configured
    	// ui32Config is the configuration of this step. Routs it to an analog input. Also defines the last in the
    	//     sequence with ADC_CTL_END and also fires an interrupt every 8 samples with ADC_CTL_IE
    
    	ADCSequenceEnable(ADC1_BASE,0); //Once configuration is set, re-enable the sequencer
    	ADCIntClear(ADC1_BASE,0);
    	uDMAEnable(); // Enables uDMA
    	uDMAControlBaseSet(udmaCtrlTable);
    	// Configures the base address of the channel control table. Table resides in system memory and holds control
    	//     information for each uDMA channel. Table must be aligned on a 1024-byte boundary. Base address must be
    	//     configured before any of the channel functions can be used
    
    	ADCSequenceDMAEnable(ADC1_BASE,0);
    	// Allows DMA requests to be generated based on the FIFO level of the sample sequencer (SS0)
    	uDMAChannelAssign(UDMA_CH24_ADC1_0);
    	uDMAChannelAttributeDisable(UDMA_CHANNEL_ADC1, UDMA_ATTR_ALTSELECT | UDMA_ATTR_HIGH_PRIORITY | UDMA_ATTR_REQMASK);
    	// Start with Ping-pong PRI side, low priority, unmask
    
    	uDMAChannelAttributeEnable(UDMA_CHANNEL_ADC1, UDMA_ATTR_USEBURST);
    	// Only allow burst transfers
    
    	uDMAChannelControlSet(UDMA_CHANNEL_ADC1 | UDMA_PRI_SELECT, UDMA_SIZE_16 | UDMA_SRC_INC_NONE | UDMA_DST_INC_16 | UDMA_ARB_128);
    	uDMAChannelControlSet(UDMA_CHANNEL_ADC1 | UDMA_ALT_SELECT, UDMA_SIZE_16 | UDMA_SRC_INC_NONE | UDMA_DST_INC_16 | UDMA_ARB_128);
    	// uDMAChannelControlSet(uint32_t ui32ChannelStructIndex, uint32_t ui32Control)
    	// ui32Control is the logical OR of five values: the data size, the source address incremen, the destination address
    	//     increment, the arbitration size and the burst flag
    
    	uDMAChannelTransferSet(UDMA_CHANNEL_ADC1 | UDMA_PRI_SELECT, UDMA_MODE_PINGPONG, (void *)(ADC1_BASE + ADC_O_SSFIFO0), &ADC_OUT, ADC_SAMPLE_BUF_SIZE);
    	uDMAChannelTransferSet(UDMA_CHANNEL_ADC1 | UDMA_ALT_SELECT, UDMA_MODE_PINGPONG, (void *)(ADC1_BASE + ADC_O_SSFIFO0), &ADC_OUT, ADC_SAMPLE_BUF_SIZE);
    	// uDMAChannelTransferSet(uint32_t ui32ChannelStructIndex, uint32_t ui32Mode, void *pvSrcAddr, void *pvDstAddr, uint32_t ui32TransferSize)
    	// pvSrcAddr is the source address for the transfer in this case from hw_adc.h ADC_O_SSFIFO0 is the result of the FIFO 0 register
    	// pvDstAddr is the destination address for the transfer
    	// ui32TransferSize is the number of data items to transfer
    
    
    	ADCIntEnable(ADC1_BASE,0);
    	uDMAChannelEnable(UDMA_CHANNEL_ADC1); // Enables DMA channel so it can perform transfers
    	SysCtlDelay(10);
    	IntEnable(INT_ADC1SS0);
    
    
    }
    //----------------------------------------------------------------
    
    int main(void)
    {
    	//-------------------------------------------------------------------------------
    	// Initializations
    	SysCtlClockSet(SYSCTL_SYSDIV_5|SYSCTL_USE_PLL|SYSCTL_OSC_MAIN|SYSCTL_XTAL_16MHZ);
    
    	SysCtlDelay(20);
    
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC1);    //Enable the clock to ADC module
    	SysCtlDelay(10); // Time for the peripheral enable to set
    
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_UDMA);
    	SysCtlDelay(10);
    
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);
    	SysCtlDelay(30);
    
    	GPIOPinTypeADC(GPIO_PORTB_BASE, GPIO_PIN_5);
    	GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_0);
    	GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_1);
    	GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_2);
    	GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_3);
    	GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_4);
    	GPIOPinTypeADC(GPIO_PORTD_BASE, GPIO_PIN_1);
    	GPIOPinTypeADC(GPIO_PORTD_BASE, GPIO_PIN_2);
    
    	SysCtlDelay(80);
    
    	IntMasterEnable();
    
    	init_ADC();
    	//------------------------------------------------------------------------------
    
    	
    		while(1)
    		{
    
    		}
    }
    
    

  • Hello Michelle,

    The issue is that UDMA_CHANNEL_ADC1 is pointing to channel 15 while UDMA_CH24_ADC1_0 is pointing to channel 24. You need to use the latter at all the places where UDMA_CHANNEL_ADC1 has been used.

    Regards
    Amit
  • Hi Amit,

    It's getting closer! Now I have values on ADC_OUT, it goes into the ADC interrupt handler after initialization, then goes into ADCprocess function but when it hits if ((((tDMAControlTable *) udmaCtrlTable)[ch].ui32Control & UDMA_CHCTL_XFERMODE_M) != UDMA_MODE_STOP) return; then it goes into FaultISR. Why would this be if that line worked back when I had everything for ADC0?

    Thank you,
    Michelle
  • Hello Michelle,

    This is the disadvantage of not using APIs. In the [ch] you are now parsing the entire define but now the define is not the channel index but also the MUX value on the DMA mapping table. Just use the channel number instead of the full mapping or better still switch to the UDMAChannelTransferGet API Call.

    Regards
    Amit
  • Hi Amit,

    It looks like it finally works, thank you very much for all the help!!!!!!!!!!

    Michelle
  • Hi Michelle,

    Can I request a short summary and maybe a working code for the future? So I can come here if needed, or another user can find it or maybe Amit could redirect other users here
  • May I commend both poster & especially Amit for this great, ongoing, and highly/uniquely detailed effort?

    And - poster Luis raises a great, valuable point - should not poster code be made available to others - as it involved so much "back-forth effort?"

    One last point - poster's desired "switch" from ADC0 to ADC1 seems (extremely) ill advised.    As soon as the added complexity was noted (and it was confirmed that, "All was well via ADC0") would it not have been so much simpler - to switch the (clearly) past (non-DMA) existing code from ADC0 to ADC1 - instead?