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.

T4MC1294NCPDT - ADC Global Synchronization

Other Parts Discussed in Thread: TM4C1294NCPDT

Why hello there fellows. I hope you can help me with this problem since it's been causing me headaches for days now.

First of all, i'm working on the Evaluation Kit TM4C1294XL with the TM4C1294NCPDT being the heart of it. I'm trying to get some signal processing running on it but failed on the synchronization of the ADC modules.

What i'm basically trying is, i want to use the SYNCWAIT and GSYNC Bits of the PSSI-Register to synchronize both ADC Modules to acquire data from two different channels (alas, two simple analogue Inputs). The configuration and setup went all fine, the ADCs fired and gave me Interrupts, even working with the DMA like a charm now. Unsynched, but they're working.

But here's the bug.

As soon as i try to prepare them for synchronized action (Setting the SYNCWAIT and the SSx Bit for the correct Sequencer) and set the GSYNC Bit of either Module as stated in the datasheet of the Controller under the PSSI-Register, both Modules just stupidly reset all their Bits in the PSSI-Register and remain dull. Not doing anything. My DMA remaining sad as it's unfed.

 

void vInitADC(){
	//	Initializing of the ADC Modules needed to poll the excitation frequency
	//	And the data sincos data signals
	
	SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);
	SysCtlDelay(10);
	SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC1);
	SysCtlDelay(10);
	SysCtlPeripheralEnable(SYSCTL_PERIPH_COMP0);
	
	SysCtlDelay(10);
	
	/*
	// ******************************************************************************
	// Initialization of ADC1 Module for Acquisition of the excitation Signal on PK3
	// 		Settings:
	//		1 Msps ^= 16MHz ADC clock
	//											
	// Set up the Clock at | (VCO/15)/2 = (480/15)/2 = 16MHz | which equals 1Msp/s

	ADCClockConfigSet(ADC1_BASE, ADC_CLOCK_SRC_PLL | ADC_CLOCK_RATE_HALF, 15);
	SysCtlDelay(10);
	ADCClockConfigSet(ADC0_BASE, ADC_CLOCK_SRC_PLL | ADC_CLOCK_RATE_HALF, 15);
		
	// Choose Sequencer 2 and set it at the highest Priority.
	ADCSequenceConfigure(ADC0_BASE, 2, ADC_TRIGGER_ALWAYS, 0);
	ADCSequenceConfigure(ADC1_BASE, 2, ADC_TRIGGER_ALWAYS, 0);
		
	// Choose Step 0 in Sequencer 2 as Data Buffer, set it as last Step and enable Interrupts
	ADCSequenceStepConfigure(ADC0_BASE,2,0, ADC_CTL_CH16 | ADC_CTL_END);
	ADCSequenceStepConfigure(ADC1_BASE,2,0, ADC_CTL_CH17 | ADC_CTL_END);
		
	// Enable the Sequencers SS1 and SS2 + their respective DMA-Channels.
	ADCSequenceDMAEnable(ADC1_BASE, 2);
	ADCSequenceDMAEnable(ADC0_BASE, 2);
	
	ADCIntEnableEx(ADC0_BASE, ADC_INT_DMA_SS2);
	ADCIntEnableEx(ADC1_BASE, ADC_INT_DMA_SS2);
		
	ADCIntRegister(ADC0_BASE, 2, ADC0SS2_Handler);
	ADCIntRegister(ADC1_BASE, 2, ADC1SS2_Handler);
		
	// Set both ADC- Modules to wait (Set SYNCWAIT-Bit + Sequence Enable) and..
	ADC0_PSSI_R |= 0x8000004;
	ADC1_PSSI_R |= 0x8000004;
	
// Commented since we don't want to start the modules asynchronuosly.
// If uncommented, the ADC Modules will start sampling right away. //ADCSequenceEnable(ADC0_BASE, 2); //ADCSequenceEnable(ADC1_BASE, 2); // Fire away! (Starting concurrent measures by setting GSYNC) // Be aware that it doesn't matter which GSYNC Bit is set. // Setting the GSYNC Bit of any ADC-Module will start all Modules waiting // (Whereby 'waiting' is defined by having the SYNCWAIT Bit set. ADC0_PSSI_R |= 0x80000000; }

 

I am aware that the Errata states that the Global Synchronization does not work on Silicon Revision 1 Controllers. But i have double-checked every single Evaluation Kit i have here and the printed name says "XM4C1294NCPDTI2" where the "I2" part should state a Silicon Revision 2.

Could it be that the global synch does not work due to the Controllers being pre-production? (Due to the X in front). Silicon Revision has been double-checked with the DID0 Register stating that it indeed is a Revision 2

DID0_MIN = 0x01

DID1_MAJ = 0x00

 

I would be VERY happy if someone could acknowledge he/she got the global synchronization of the ADC modules to work and would share some code for me to analyze.

 

Thanks in Advance

  • Hello Michel,

    The errata is clear that the the issue was on Rev-1 of the device. So if the device is Rev-2 then it has been fixed (irrespective of X marking).

    What you have not done as per the register specification"

    "Once the final ADC module is configured, its ADCPSSI register should be written with the appropriate SS bits set along with the GSYNC bit. All of the ADC modules then begin concurrent sampling according to their configuration"

    Regards

    Amit

  • Hello Amit,

    thank you for the reply. I did read that part of the register specification and found it indeed quite hard to interprete right. From what i gathered, i already set the appropriate SS-Bits with the following:

    // Set both ADC- Modules to wait (Set SYNCWAIT-Bit + Sequence Enable) and..
    ADC0_PSSI_R |= 0x8000004;
    ADC1_PSSI_R |= 0x8000004;

    And even if i do not pass the according SS-bits into the last write to the GSYNC, shouldn't the sampling start nonetheless? What if i don't want any Sequencers activated on the last module, so there are no SS-Bits to set? I sadly lack the technologic understanding of the underlying mechanics to further discuss this, but i tested it with the following, corrected code and they still would not start sampling.

    // Fire away! (Starting concurrent measures by setting GSYNC)
    // Be aware that it doesn't matter which GSYNC Bit is set.
    // Setting the GSYNC Bit of any ADC-Module will start all Modules waiting
    // (Whereby 'waiting' is defined by having the SYNCWAIT Bit set.
    ADC0_PSSI_R |= 0x80000004;

    This should, from what you told me, solve the problem, right? The SS-Bit of the 2nd Sequencer was written along with the GSYNC-Bit. I multi-checked the hex-code for the correct Bits. It sadly did not change anything about the symptom. However, i found another thing quite puzzling which might be the source of my problem:

    In the PSSI-Register Specification it states among the SS-Bits:

    "1: Begin sampling on Sample Sequencer x, if the sequencer is enabled in the ADCACTSS register"

    Admittingly, i have not set that ACTSS-Bit in the initialization routine because it would and still will fire off the ADC Modules before i wanted them to. As soon as i set that bit, in fact, they start sampling even though their SYNCWAIT Bit is set. My theory was, that this Bit in the ACTSS-Register might be set by a routine after GSYNC is written correctly. A full, comprehensible list of things to do to get the ADC-modules to start simultaneously might do the magic and help me, because the details in this behemoth of a datasheet honestly start to puzzle me.

     

    Thank you in advance,

     

    Sincerely,

     

    Michel

  • Hello Michel,

    Can you send the uDMA configuration code as well. it may be possible that the issue is with the uDMA initialization with ADC working fine. Usually before going to the uDMA it is always preferred to run the code with "plain old" interrupt mechanism first.

    Regards

    Amit

  • Hello Amit,

    i've decoupled the uDMA completely from the ADC logic and i still have the same symptoms. I'm able to catch the ADC red-handed sampling (alas, going into Interrupt) even with its according SYNCWAIT-Bit set in the Sequencer. From what i read and understood from the datasheet, this should not happen in any case.

    Quote: "SYNCWAIT: 1: This bit allows the sample sequences to be initiated, but delays sampling until the GSYNC bit is set"

    Vice versa, the ADC will not start sampling at all when NOT setting the Sequence Enable Bit in ACTSS and instead trying to synchronuosly firing both ADC with GSYNC and SYNCWAIT.

    So basically, either it starts off prematurely or not at all. Nonetheless, here is the uDMA Code using PingPong Mode:

    //************************************************************************
    //	This routine is called to initialize the µDMA Module of the 
    //  Microprocessor. This module is essential to help the processor
    //  gather the data to process. Without this, the additional load
    //  of handling the Interrupts and Data Movement might be too much.
    //		Settings:
    //				Control Table 		= 'pui8DMAControlTable'
    //				Channel Selection =  Mostly using Ping-Pong Mode.
    //					-> This allows to gather 100 samples, then switch
    //					memory location and keep sampling.
    //************************************************************************
    void vInitDMA(void){
    	// Enable the master peripherals (clock gating and the module itself)
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_UDMA);
    	SysCtlDelay(10);
    	uDMAEnable();
    	SysCtlDelay(5);
    	
    	// Assign the channels used to the respective DMA inputs
    	// New ones can be added here. Look up datasheet for details.
    	uDMAChannelAssign(UDMA_CH25_ADC1_1);
    	uDMAChannelAssign(UDMA_CH26_ADC1_2);
    	
    	// Assign the control table to the DMA for it to allow the
    	// data transfer and reading/saving the configuration of the channels.
    	uDMAControlBaseSet(&pui8DMAControlTable[0]);
    	
    	
    	//**********************************************************
    	// Setting up the channels to work with the ADC1 Module.
    	// This allows to parallel conversion so far but allows tests
    	// for the speed of the DMA.
    	//**********************************************************
    	uDMAChannelControlSet(UDMA_CH16_ADC0_2 | UDMA_PRI_SELECT, 
    						UDMA_SIZE_32 | UDMA_SRC_INC_NONE |
    						UDMA_DST_INC_32 | UDMA_ARB_1);
    	uDMAChannelControlSet(UDMA_CH16_ADC0_2 | UDMA_ALT_SELECT, 
    						UDMA_SIZE_32 | UDMA_SRC_INC_NONE |
    						UDMA_DST_INC_32 | UDMA_ARB_1);
    	SysCtlDelay(5);
    	uDMAChannelControlSet(UDMA_CH26_ADC1_2 | UDMA_PRI_SELECT, 
    						UDMA_SIZE_32 | UDMA_SRC_INC_NONE |
    						UDMA_DST_INC_32 | UDMA_ARB_1);
    	uDMAChannelControlSet(UDMA_CH26_ADC1_2 | UDMA_ALT_SELECT, 
    						UDMA_SIZE_32 | UDMA_SRC_INC_NONE |
    						UDMA_DST_INC_32 | UDMA_ARB_1);
    	
    	//**********************************************************
    	// Setting up the Transfers for Pingpong mode. These
    	// will copy the ADC Data directly to the appointed buffers
    	//**********************************************************
    	// Address Clarification
    	// 0x4003 -> ADC Module
    	//		8 -> ADC0
    	//		9 -> ADC1
    	//		 048 -> FIFO0
    	//		 068 -> FIFO1
    	//		 088 -> FIFO2
    	//		 0A0 -> FIFO3
    	//**********************************************************
    	uDMAChannelTransferSet(UDMA_CH16_ADC0_2 | UDMA_PRI_SELECT, 
    UDMA_MODE_PINGPONG, (void*)(0x40038088),
    &f32ADCSinResultPri[0], 100); uDMAChannelTransferSet(UDMA_CH16_ADC0_2 | UDMA_ALT_SELECT,
    UDMA_MODE_PINGPONG, (void*)(0x40038088),
    &f32ADCSinResultAlt[0], 100); SysCtlDelay(5); // Short delay to accept the changes. uDMAChannelTransferSet(UDMA_CH26_ADC1_2 | UDMA_PRI_SELECT,
    UDMA_MODE_PINGPONG, (void*)(0x40039088),
    &f32ADCCosResultPri[0], 100); uDMAChannelTransferSet(UDMA_CH26_ADC1_2 | UDMA_ALT_SELECT,
    UDMA_MODE_PINGPONG, (void*)(0x40039088),
    &f32ADCCosResultAlt[0], 100); // Enable the DMA Channels after all. Ensure everything goes // right with a little delay of 5 ticks. uDMAChannelEnable(UDMA_CH16_ADC0_2); SysCtlDelay(5); uDMAChannelEnable(UDMA_CH26_ADC1_2); }

    I still can't believe noone else tried to get the ADCs to run synchronuosly. I'll try my luck with debugging a little more today, see what i can find out about the starting and initialization behaviour of the ADC in general. Or i'll have to live with the delay between the samples, with 1Msps it's not really that much after all.

    Thanks in advance for the help,

     

    Sincerely,

     

    Michel

  • Hello Michel,

    There were quite some issues for the Interrupt to work. So I made some modifications to the project file. Attached is a working copy of the same with the GSYNC and Interrupt that you may use as a template.

    4338.TM4C129_ADC0_ADC1_GSync.c
    //*****************************************************************************
    //
    // TM4C129_ADC0_ADC1_GSync.c - ADC0 and ADC1 Global Sync Example
    //
    // Copyright (c) 2013-2014 Texas Instruments Incorporated.  All rights reserved.
    // Software License Agreement
    //
    // Texas Instruments (TI) is supplying this software for use solely and
    // exclusively on TI's microcontroller products. The software is owned by
    // TI and/or its suppliers, and is protected under applicable copyright
    // laws. You may not combine this software with "viral" open-source
    // software in order to form a larger program.
    //
    // THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
    // NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
    // NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    // A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
    // CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
    // DAMAGES, FOR ANY REASON WHATSOEVER.
    //
    // This is part of revision 2.1.0.12573 of the DK-TM4C129X Firmware Package.
    //
    //*****************************************************************************
    
    #include <stdbool.h>
    #include <stdint.h>
    #include "inc/hw_ints.h"
    #include "inc/hw_memmap.h"
    #include "inc/hw_types.h"
    #include "inc/hw_adc.h"
    #include "driverlib/debug.h"
    #include "driverlib/adc.h"
    #include "driverlib/pin_map.h"
    #include "driverlib/interrupt.h"
    #include "driverlib/rom.h"
    #include "driverlib/rom_map.h"
    #include "driverlib/sysctl.h"
    #include "driverlib/uart.h"
    #include "driverlib/udma.h"
    #include "driverlib/gpio.h"
    #include "utils/uartstdio.h"
    
    volatile bool bADC0Interrupt;
    volatile bool bADC1Interrupt;
    
    void
    ADC0SS2IntHandler(void)
    {
    	ADCIntClear(ADC0_BASE, 2);
    	bADC0Interrupt = true;
    }
    
    void
    ADC1SS2IntHandler(void)
    {
    	ADCIntClear(ADC1_BASE, 2);
    	bADC1Interrupt = true;
    }
    
    void
    vInitADC(void)
    {
    	//	Initializing of the ADC Modules needed to poll the excitation frequency
    	//	And the data sincos data signals
    
    	SysCtlPeripheralReset(SYSCTL_PERIPH_ADC0);
    	SysCtlPeripheralReset(SYSCTL_PERIPH_ADC1);
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC1);
    	SysCtlDelay(10);
    
    	/*
    	// ******************************************************************************
    	// Initialization of ADC1 Module for Acquisition of the excitation Signal on PK3
    	// 		Settings:
    	//		1 Msps ^= 16MHz ADC clock
    	//
    	// Set up the Clock at | (VCO/15)/2 = (480/30) = 16MHz | which equals 1Msp/s
    	*/
    
    	ADCClockConfigSet(ADC1_BASE, ADC_CLOCK_SRC_PLL | ADC_CLOCK_RATE_FULL, 30);
    	ADCClockConfigSet(ADC0_BASE, ADC_CLOCK_SRC_PLL | ADC_CLOCK_RATE_FULL, 30);
    
    	// Choose Sequencer 2 and set it at the highest Priority.
    	ADCSequenceConfigure(ADC0_BASE, 2, ADC_TRIGGER_ALWAYS, 0);
    	ADCSequenceConfigure(ADC1_BASE, 2, ADC_TRIGGER_ALWAYS, 0);
    
    	// Choose Step 0 in Sequencer 2 as Data Buffer, set it as last Step and enable Interrupts
    	ADCSequenceStepConfigure(ADC0_BASE,2,0, ADC_CTL_CH16 | ADC_CTL_IE | ADC_CTL_END);
    	ADCSequenceStepConfigure(ADC1_BASE,2,0, ADC_CTL_CH17 | ADC_CTL_IE | ADC_CTL_END);
    
    	// Enable the Sequencers SS1 and SS2 + their respective DMA-Channels.
    	ADCSequenceDMAEnable(ADC1_BASE, 2);
    	ADCSequenceDMAEnable(ADC0_BASE, 2);
    
    	ADCIntEnableEx(ADC0_BASE, ADC_INT_SS2);
    	ADCIntEnableEx(ADC1_BASE, ADC_INT_SS2);
    
    	IntEnable(INT_ADC0SS2);
    	IntEnable(INT_ADC1SS2);
    
    	ADCSequenceEnable(ADC1_BASE, 2);
    	ADCSequenceEnable(ADC0_BASE, 2);
    
    	// Set both ADC- Modules to wait (Set SYNCWAIT-Bit + Sequence Enable) and..
    	HWREG(ADC0_BASE+ADC_O_PSSI) |= 0x8000004;
    	HWREG(ADC1_BASE+ADC_O_PSSI) |= 0x8000004;
    
    	// Commented since we don't want to start the modules asynchronuosly.
    	// If uncommented, the ADC Modules will start sampling right away.
    	//ADCSequenceEnable(ADC0_BASE, 2);
    	//ADCSequenceEnable(ADC1_BASE, 2);
    
    	// Fire away! (Starting concurrent measures by setting GSYNC)
    	// Be aware that it doesn't matter which GSYNC Bit is set.
    	// Setting the GSYNC Bit of any ADC-Module will start all Modules waiting
    	// (Whereby 'waiting' is defined by having the SYNCWAIT Bit set.
    	HWREG(ADC0_BASE+ADC_O_PSSI) |= 0x80000000;
    
    }
    
    //*****************************************************************************
    //
    // Configure the UART and its pins.  This must be called before UARTprintf().
    //
    //*****************************************************************************
    void
    ConfigureUART(void)
    {
        //
        // Enable GPIOA
        //
        ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    
        //
        // Enable UART0
        //
        ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
    
        GPIOPinConfigure(GPIO_PA0_U0RX);
        GPIOPinConfigure(GPIO_PA1_U0TX);
        GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
    
        //
        // Use the internal 16MHz oscillator as the UART clock source.
        //
        ROM_UARTClockSourceSet(UART0_BASE, UART_CLOCK_PIOSC);
    
        //
        // Initialize the UART for console I/O.
        //
        UARTStdioConfig(0, 115200, 16000000);
    }
    
    //*****************************************************************************
    //
    // Configure the ADC0 and ADC1
    //
    //*****************************************************************************
    int
    main(void)
    {
        uint32_t ui32SysClock;
    
        //
        // Run from the PLL at 120 MHz.
        //
        ui32SysClock = SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ | SYSCTL_OSC_MAIN | SYSCTL_USE_PLL | SYSCTL_CFG_VCO_480),
        		120000000);
    
        ConfigureUART();
    
        bADC0Interrupt = false;
        bADC1Interrupt = false;
    
        //
        // Enable the (non-GPIO) peripherals used by this example.  PinoutSet()
        // already enabled GPIO Port A. ??????
        //
        vInitADC();
        UARTprintf("Configured ADC peripheral.\n");
    
        while((bADC0Interrupt == false) | (bADC1Interrupt == false ));
    
        UARTprintf("Int Done...\n");
        while(1);
    }
    

    Regards

    Amit

  • Hello Amit,

    first of all thank you lots for your effort that i've been putting you through and thank you for the example code, it does work. However, i'm still wondering about things. When i comment the line out where you set the GSYNC-Bit, the ADC-Module would still start sampling.

    This leads me to the suspicion that they are not really running concurrently, but run as soon as you enable the Sequencers (alas "ADCSequenceEnable()"). What i would expect is, that both ADC-Modules wait for their sampling when their SYNCWAIT-Bit is set until one GSYNC-Bit is set and then start. I mean, that's the definition of 'waiting' after all, isn't it. Supporting my suspicion i raise that the Fifo, the Overrun-Bit and the BUSY-Bit of either ADC-Module is being filled as soon as the Sequencer has been enabled.

    Is there any way to have an insight into the underlying mechanics of that GSYNC-Bit and how they're connected with the ADC? Or is this classified information?

    Sincerely,

     

    Michel

     

  • Hello Michel,

    I agree, but please note that the code is setting the Trigger Always Mode. The Main utility of the GSYNC is to synchronize the Phase Shifted sampling of the channel. It was not meant for an always trigger mode but more for a processor triggered mode.

    Also what you are observing is correct w.r.t FIFO, OR and BUSY bit being set.

    Regards

    Amit

  • Hello Amit,

    ah well, this is disappointing.. So you are saying that it is not possible to perfectly synchronize the startup of the ADC-Module in Always Trigger Mode, right? I guess i will have to go for a real DSP-Microcontroller like the C2000-Series if i want according features like real synchronuos sampling then.

    I would also really love if TI could state such clear facts about the features like the GSYNC-Bit in the datasheet, if it already is a behemoth of 1700+ pages :P

    Alas, i would really like to thank you for your thorough help, Amit. Seems like you're the only poor soul of TI willing to help in every single Thread here in the Forums. I appreciate it a lot.

    Sincerely,

     

    Michel

  • Hello Michel,

    No it is not possible in the Always Trigger Mode. But the other way of getting a periodic trigger and in Sync would be to use the Timer to generate a trigger to the ADC. The advantage would be not having requirement to do the GSYNC but a timer resource would be used.

    Regards

    Amit

  • Hello Amit,

    yes, i came up with that yesterday as i had to search for alternatives and i think it's a quite viable option since the Timers can trigger the ADC Modules directly and synchronuosly. I was just quite afraid that i would get a deviation of sampling time with the timers, but it's being quite accurate until now.

    Thanks again for the help and take care,

    Sincerely,

     

    Michel

  • Hello Everyone,

    Here's a little update concerning the ADCs and the synchronization done with the Timers. I experienced phase jitter when triggering the ADCs synchronuosly with the Timer.

    This jitter didn't only appear between the ADC-Modules but seemed to be unstable in between measurements themselves. This however made it impossible to acquire stable data over time intervals since the jitter would shift the measurements and therefore made ANOTHER synchronization mandatory.

    I was able to reproduce and measure this jitter in between measure by triggering a pin in the interrupt routines after 100 measurements, the interrupt being fired by the µDMA Module. This signal was then measured with an oscilloscope.

    Note: The very same program showed no jitter at all when running the ADCs in ALWAYS-Mode. There were no other Interrupts involved.

    I found peace in using the "ALWAYS" Mode under the following circumstances and unsecurities:

    • It is not possible to perfectly synchronize these measurements to each other. There is a delay to each other due to the fact you have to start the modules by writing registers. The delay to each other is therefore at least the difference between writing each register.
    • The ADC-Modules themselves therefore measure exactly at the given frequency. The signal data maintains its integrity and there is no need for further synchronization.

    I personally found it hard to believe there is no possiblity to synchronize the ADC-Modules with their GSYNC Registers in this particular "ALWAYS" Measurement Mode. I also would appreciate if this would explicitly stated in the datasheet.

     

    Sincerely,

     

    Michel

     

  • Hi,

    I did not followed all postings in this thread, so I would like to ask a simple question: where do you need such super-perfect synchronization and what is the accuracy needed for your measurement? Did you compared the accuracy loss due to jitter with the accuracy loss if you use two ADC signals on the same sequencer? O coarse this depends on signal shape/type (unspecified here).

    Please do not misunderstand me - it is OK to ask such thing, but I ask if it really matters instead of a simple, predictible approach.

    Petrei

  • Hey Petrei,

    my aim is to demodulate a magnitude-modulated sinus-cosinus-signal. In order to achieve this, one way is to demodulate by sampling on the sinus frequency. If i have a jitter on this sampling, it is a continuing error and my signal "drifts" away on my samples.

    This can be corrected by a synchronization as i stated in my post, but of course an exact sampling frequency, which is given by the processor driving the ADC with its own clock directly, can solve this problem just as well.

    It should be stated that i need to reduce the Interrupt routines to a necessary bit, since my modulated signal has a frequency of 10kHz. All the time saved by using self-sufficient systems like DMA or the self-triggered ADCs is providing processing time for my DSP-routine, where i take what i can get.

    And no, i didn't yet compare the jitter of the sequencers since i am not using them. I am using both ADC-Modules as synchronized as i can. Considering my understanding of the Sequencers, it'd be 1µs delay between two samples with 1Msps settings, right? This would, with a sine signal of 10kHz and therefore tau = 100µs, end up in an inaccuracy of the sample of 1%(3.6°) if i didn't miss something.

    Since my accuracy is given by the relation of both the sine and cosine signals, a time jitter here would end up faulting my end result which is why i wanted to synchronize the ADC-modules to begin with.

    Hope that cleared things up a little.

     

    Sincerely,

     

    Michel

  • Hi,

    I fully understand now - the main problem is the high frequency 10 KHz, for lower would be much easier.

    Regards,

    Petrei

  • Hello Michel,

    Forgive me for inserting a reply in the middle of this discussion, but the project I am on has experienced a similar problem.  We desire high sample rate (1Megsample per sec), I and Q concurrent sampling.  I tied both input channels together and supplied a 50KHz sin wave input, and observed phase errors which corresponded to 1/16th or 1/8th of a microsecond.

    The project uses Tiva-129 running at 120 MHz, uDma from both I and Q channels.  We have tested with the ADC clocked at both 16 and 32 MHz.  The PLL is 480 MHz.


    We found that using the following code to enable the sequencers eliminates the skew between ADCs (or at least makes the probability of having a skew much smaller).  The idea is to enable the two sequencers in close proximity (timewise).  This code, when compiled under gnu with modest optimization settings, results in two back-to-back stores to the ADC control registers.  For the sake of testing we've not prettied up the constants, but they enable the DMA and sequencer operations for sequencer 0 only:

       ROM_IntMasterDisable ();
       *((volatile unsigned long *)(ADC0_BASE + ADC_O_ACTSS)) = 0x101 << 0;
       *((volatile unsigned long *)(ADC1_BASE + ADC_O_ACTSS)) = 0x101 << 0;
       ROM_IntMasterEnable();

    The int disable/enable calls prevent the processor from being diverted between the two enables.  These statements replace the code:

        // enable sequencers
        ROM_ADCSequenceEnable(ADC0_BASE, 0);
        ROM_ADCSequenceEnable(ADC1_BASE, 0);

    (The DMA enable bit was set prior to these calls, and the ROM function call OR's in the seq enable bit, whereas our statements set both the DMA enable and seq enable bits at the same write).

    We've also set up a timer to trigger the DMA channels (after placing the channels in DMA trigger mode) and have not seen any excessive jitter or problems;  our ADC and our timers are both driven from the master oscillator, and our trigger rate is 1 megasample/second.  I was curious about your discussion thread; you indicated you had tried this and had difficulties;  I would like a better understanding of how you configured the timer so that we can determine if we are doing anything unwise with our configuration.

    Thank you and regards,

    Tim

  • Greets Tim,

    as sadistic as it sounds, happy someone else stumbled over quite the same problem as myself. Was starting to feel a little alone here.

    To give you a better understanding of my currently working system:

    I am using 2 input channels like you are and i have my DMA set up to Trigger an Interrupt (The only one in the whole system) whenever it sampled 25 values from the ADC ( Ping Pong Mode ). I also used this interrupt as measurement point to give a HI-Voltage on a pin to check on the synchronization on the oscilloscope.

    However, if i used a timer to synchronuosly trigger both ADC-modules instead of them running in ALWAYS-Mode, my signal 'drifts' away. This must be because of a jitter in between the measurements and would need another synchronization method. I also just verified this outcome again.

    In ALWAYS mode though, the signal on the oscilloscope is standing still perfectly. The HI-signal comes exactly every 25 values which is an exact time of 100µs.

    I cannot point out what i've done wrong with my Timers, but i can share the initiation routine which is honestly not much. I simply put up the Timer at 1:1 Clock Rate with a 120MHz/80MHz PLL Clock running and the according Timer counts for 100µs.

    What differs between our systems though would be the fact that you said you "[...] set up a timer to trigger the DMA channels". In my system, the DMA gathers Data from the ADC whenever it's available and the ADCs are self-sufficient modules running at a pre-set clock rate. Either i did not quite understand what you meant with the DMA-Channels or you are using a different mode.

    What are you triggering with your Timers? Are the ADCs running in ALWAYS mode or timer-triggered?

    Sincerely,

     

    Michel

  • Hello Michel,

    Thanks for the response.

    I apologize for my description error.  I've used both sample-always mode, and also used a timer to trigger the ADC channels.  The timer triggers both ADC0 and ADC1 at a 1 MHz rate.  I tie the I&Q to the same physical input: a function generator at 50KHz sine wave, and capture about 2K to 8K samples, and look at the I and Q under matlab. The input signal is about 25% of the full scale dynamic range of the ADC.

    DMAs run always, in ping pong mode.

    I look at the mean deviation between I and Q:  mean (abs(I - Q)), which, in a perfect world, would be 0 since the inputs are tied together:  occasional differences in samples of an LSB or two are acceptable since there are two separate ADCs but the mean should be very close to 0. A nonzero mean (typically 13 or more when it happens) indicates the channels are not sampling at the same time;  when that happens plots of I&Q show that one lags the other by a fraction of a sample.  A zero mean deviation indicates good concurrency but does not indicate jitter (both channels may be subject to jittering concurrently);  I examine the FFT to get a sense of that.


    I can readily introduce a delay between I and Q by calling the ROM functions to start the sequencers.  When I start them closer in time (back to back using the writes to the registers instead of calling the ROM functions) I observe no delay.  I am not sure, though, whether this is still a "roll of the dice" in the sense that there may still be a low probability that the system shows a skew based on when I start the sequencers (in relation to the phase of the ADC clock or other internal states):  I suspect the methods I have tried reduce but to not eliminate the possibility of timing differences between I and Q channels.

    Regards,

    Tim

    .

  • Hello Tim,

    i do believe that it is simply not possible to start both ADC-modules at an exact same time base. It is exactly what i wrote in my discussion with Amit and i guessed i had to live with it. Even though it is quite frustrating, since the datasheet offered an oppurtunity with the GSYNC and SYNCWAIT Bits with which it would seem to be possible.

    My error however was a different one than yours. And the following sentence puzzles me:

    "I've used both sample-always mode, and also used a timer to trigger the ADC channels"

    To clarify: Sample Always mode bases itself on the clock you deliver to the ADC modules. And whenever a measurement is done, the next one will be started. It has nothing to do with Timer-Triggered Mode in my understanding.

    Nonetheless, whenever i tried to timer-trigger my ADC-modules i would always not only get a skew between the samples, but also instead of sampling at a perfect rate of 1Msps, the samples would 'drift away'. I sadly cannot tell you why the timers introduced such errors but i had no means to eliminate this and honestly also lack the time to investigate any further.

    My final solution looked something around yours as well though. Just write the registers as fast as possible together and hope for the best. In a sense of digital signal processing, this sadly is a poor solution but i haven't seen any major errors or deviation on my end signals therefore. I guess if you want more specialized power and better options, you'd have to go for a C2000 Series Controller. That's what i wrote down for myself.

    Sincerely,

     

    Michel Raabe