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);
}
}