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.

TM4C123GH6PM: ADC crosstalk between CH2 and CH3 on pins PE0 and PE1

Part Number: TM4C123GH6PM
Other Parts Discussed in Thread: DRV8801

Hello,

My custom TM4C123GH6PM board was having some (very little) problematic readings so I made a simple program to isolate the issue that would run on the tiva-c tm4c123 evaluation board.

1. There was an unexplainable bias in one of the channels

2. There was little crosstalk between channels, one affecting the other.

The issue remains and observable. What happens is if I leave one channel floating and apply 3v3 to the other channel,  one channel reads 3v3 and the other (floating) reads 2v9, and vice versa. On the real board, no adc pin is left floating, there is a 33nf cap to ground, and the voltage is coming tru a 10K resistor. (VPROPI pin of a DRV8801)

It is almost as if stale data stays in the adc fifo, or the sample/hold of the adc. Can there be a workaround for this? This has been talked in the forums previously, but not under same settings.

Maybe I can use single sequence that will sample one from ch2 one from ch3? Maybe I can assign one pin to adc0 and the other to adc1? Before I went into trial and error, I wanted to ask on this forum.

Additional Findings: a. The faster the ADC speed, the more cross coupling. b. using adc0 and adc1 seperately does not cancel cross coupling c. we are sampling both channels at the practically the same time, it will be one interrupt after another, one with priority 1 and the other priority 2 - we can maybe introduce a phase shift on the adc channels.

Best Regards,

C.

Here is my full code:

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


#include "inc/hw_gpio.h"
#include "inc/hw_ints.h"
#include "inc/hw_memmap.h"

#include "driverlib/fpu.h"
#include "driverlib/timer.h"
#include "driverlib/gpio.h"
#include "driverlib/interrupt.h"
#include "driverlib/pin_map.h"
#include "driverlib/rom_map.h"
#include "driverlib/sysctl.h"
#include "driverlib/uart.h"
#include "driverlib/adc.h"

#include "utils/uartstdio.h"
#include "utils/ustdlib.h"

#define RED_LED GPIO_PIN_1   // PF1
#define GREEN_LED GPIO_PIN_3 // PF3

#define EMA_ALPHA 15.0f
#define EMA_DIV 16.0

#define ADC_MULTIPLIER 0.000805664;

uint32_t ui32SysClkFreq;
char loginfo_buffer[128];

uint32_t adc_fifo_left_load[4];
uint32_t adc_fifo_right_load[4];
volatile uint32_t adc_ch1;
volatile uint32_t adc_ch2;

volatile float ch1 = 0.0f;
volatile float ch2 = 0.0f;

volatile float avg_ch1 = 0.0f;
volatile float avg_ch2 = 0.0f;

void ADC0SS1IntHandler(void) {
    MAP_ADCIntClear(ADC0_BASE, 1);
    MAP_ADCSequenceDataGet(ADC0_BASE, 1, adc_fifo_right_load);
    adc_ch2 = ( adc_fifo_right_load[0] + adc_fifo_right_load[1] + adc_fifo_right_load[2] + adc_fifo_right_load[3] ) / 4;
    ch2 = adc_ch2 * ADC_MULTIPLIER;
    avg_ch2 = ( (EMA_ALPHA * avg_ch2) + ch2 ) / EMA_DIV;
}

void ADC0SS2IntHandler(void) {
    MAP_ADCIntClear(ADC0_BASE, 2);
    MAP_ADCSequenceDataGet(ADC0_BASE, 2, adc_fifo_left_load);
    adc_ch1 = ( adc_fifo_left_load[0] + adc_fifo_left_load[1] + adc_fifo_left_load[2] + adc_fifo_left_load[3] ) / 4;
    ch1 = adc_ch1 * ADC_MULTIPLIER;
    avg_ch1 = ( (EMA_ALPHA * avg_ch1) + ch1 ) / EMA_DIV;
}

void init_serial(void) {
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    MAP_GPIOPinConfigure(GPIO_PA0_U0RX);
    MAP_GPIOPinConfigure(GPIO_PA1_U0TX);
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
    MAP_UARTClockSourceSet(UART0_BASE, UART_CLOCK_PIOSC);
    MAP_GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
    UARTStdioConfig(0, 115200, 16000000);
}

void init_gpio(void) {

    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOC);
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);

    MAP_GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, RED_LED);
    MAP_GPIOPadConfigSet(GPIO_PORTF_BASE, RED_LED, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD);

    MAP_GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GREEN_LED);
    MAP_GPIOPadConfigSet(GPIO_PORTF_BASE, GREEN_LED, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD);

}

int main(void) {

    MAP_FPUEnable();
    MAP_FPULazyStackingEnable();
    MAP_SysCtlClockSet(SYSCTL_SYSDIV_2_5 | SYSCTL_USE_PLL | SYSCTL_XTAL_20MHZ | SYSCTL_OSC_MAIN);

    ui32SysClkFreq = MAP_SysCtlClockGet();

    init_gpio();

    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);                                                 // enable ADC0
    while(!SysCtlPeripheralReady(SYSCTL_PERIPH_ADC0));

    MAP_GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_0 | GPIO_PIN_1);                                   // PE0, PE1
    MAP_ADCReferenceSet(ADC0_BASE, ADC_REF_INT);                                                    // Use internal reference VDDA = 3V3

    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER2);                                               // timer2 enable

    MAP_ADCSequenceConfigure(ADC0_BASE, 1, ADC_TRIGGER_TIMER, 1);                                   // set adc trigger for sequence 1 pri 1
    MAP_ADCSequenceConfigure(ADC0_BASE, 2, ADC_TRIGGER_TIMER, 2);                                   // set adc trigger for sequence 2 pri 2

    MAP_ADCSequenceStepConfigure(ADC0_BASE, 1, 0, ADC_CTL_CH2);                                     // sequence 1 step configuration
    MAP_ADCSequenceStepConfigure(ADC0_BASE, 1, 1, ADC_CTL_CH2);
    MAP_ADCSequenceStepConfigure(ADC0_BASE, 1, 2, ADC_CTL_CH2);
    MAP_ADCSequenceStepConfigure(ADC0_BASE, 1, 3, ADC_CTL_CH2 | ADC_CTL_IE | ADC_CTL_END);

    MAP_ADCSequenceStepConfigure(ADC0_BASE, 2, 0, ADC_CTL_CH3);                                     // sequence 2 step configuration
    MAP_ADCSequenceStepConfigure(ADC0_BASE, 2, 1, ADC_CTL_CH3);
    MAP_ADCSequenceStepConfigure(ADC0_BASE, 2, 2, ADC_CTL_CH3);
    MAP_ADCSequenceStepConfigure(ADC0_BASE, 2, 3, ADC_CTL_CH3 | ADC_CTL_IE | ADC_CTL_END);

    MAP_ADCSequenceEnable(ADC0_BASE, 1);                                                            // enable sequence 1
    MAP_ADCSequenceEnable(ADC0_BASE, 2);                                                            // enable sequence 2

    MAP_ADCIntClear(ADC0_BASE, 1);                                                                  // interrupt clear sequence 1
    MAP_ADCIntClear(ADC0_BASE, 2);                                                                  // interrupt clear sequence 2

    ADCIntRegister(ADC0_BASE, 1, ADC0SS1IntHandler);                                                // register interrupt SS1
    ADCIntRegister(ADC0_BASE, 2, ADC0SS2IntHandler);                                                // register interrupt SS2

    MAP_ADCIntEnable(ADC0_BASE, 1);                                                                 // adc interrupt int enable
    MAP_IntEnable(INT_ADC0SS1);                                                                     // enable nvic interrupt

    MAP_ADCIntEnable(ADC0_BASE, 2);                                                                 // adc interrupt int enable
    MAP_IntEnable(INT_ADC0SS2);                                                                     // enable nvic interrupt

    MAP_TimerConfigure(TIMER2_BASE, TIMER_CFG_A_PERIODIC);                                          // configure timer as periodic

    MAP_TimerLoadSet(TIMER2_BASE, TIMER_A, ui32SysClkFreq / 16000);                                 // sampling at 16khz default
    MAP_TimerControlTrigger(TIMER2_BASE, TIMER_A, true);                                            // enable the ADC trigger output for Timer A

    init_serial();

    MAP_IntMasterEnable();

    MAP_TimerEnable(TIMER2_BASE, TIMER_A);                                                          // always running, trigger is g_ADC_SAMPLING

    uint8_t len = sprintf(loginfo_buffer, "SYSINIT");
    UARTprintf(loginfo_buffer, len);

    while(true) {
        len = sprintf(loginfo_buffer, "%f %f\n", avg_ch1, avg_ch2);
        UARTprintf(loginfo_buffer, len);
        MAP_SysCtlDelay(100000);
    }

}