Other Parts Discussed in Thread: TEST2
Dear support,
I've made several aquisitions to measure the wave applied to a BLDC motor (back EMF). I'm using a voltage divider with a RC filter and also reading the values with an oscilloscope.
The problem is, in some velocities of the motor, it seems to have a lot of noise. Here I present the ADC Input measured in 64 kHz.
My pwmInput varies between 7500 and 12500 arbitrary units, which are, in practical terms, varying the input duty cycle from 1 to 2 ms. In the chart below, before the 16000th sample, the wave I'm measuring has a frequency of 1,68 kHz, and above it has 2,04 kHz. I've also performed a Medium Average Filter (MAF), with 3 and 10 samples, as shown in the chart below:
1,68 kHz wave:
2,04 kHz wave:
Some possibilities I've discarted:
- Sampling problem: The max frequency of the wave I'm measuring is 2 kHz, so 64 kHz should be good enough. I've tried also with 16 and 100 kHz, the aquisition remains the same;
- ADC distance: Some people recommended me to short the distance between the ADC and the aquisition point. I've made a shield, which is attached below the launchpad;
- Voltage divider: I've read in a document that, for impedance matching purposes, the resistor of the measured point should be 1 kOhm. I was using 10 kOhm, changed to 1 kOhm, it doesn't show so many differences in the ADC reading.
I'm run out of ideas, so, I'd really appreciate some help with this issues.
Here's the .xlsx with the graph. I've also made a drive with different aquisitons and with the original .csv files:
Code used (although is pretty similar to the one from the related question):
//***************************************************************************** // Libraries //***************************************************************************** #include <stdint.h> #include <stdbool.h> #include "driverlib/adc.h" #include "driverlib/gpio.h" #include "driverlib/interrupt.h" #include "driverlib/pin_map.h" #include "driverlib/pwm.h" #include "driverlib/rom.h" #include "driverlib/rom_map.h" #include "driverlib/sysctl.h" #include "driverlib/systick.h" #include "driverlib/timer.h" #include "driverlib/uart.h" #include "drivers/pinout.h" #include "inc/hw_gpio.h" #include "inc/hw_ints.h" // Added for the Timer #include "inc/hw_memmap.h" #include "inc/hw_types.h" #include "inc/hw_adc.h" #include "inc/hw_timer.h" #include "inc/hw_nvic.h" #include "inc/hw_sysctl.h" #include "utils/uartstdio.h" //***************************************************************************** // Info //***************************************************************************** // uint32_t - unsigned integer of 32 bits - range from 0 to 2^32 - 1 //***************************************************************************** // Variable Declaration //***************************************************************************** // ADC uint32_t ui32adcValues[4]; // Variable for storing values from ADC volatile bool bDataReady = false; // Flag to indicate the ADC is ready // ADC Filter uint32_t adcSumFilterCounter = 1; // Variable used for counter uint32_t ADC_SUM_FILTER_SAMPLES_NUMBER = 1; // Size of the sum filter uint32_t analogValue_ADC3 = 0; // Variable for storing values // System uint32_t g_ui32SysClock; // System clock rate in Hz. uint32_t SYSTEM_CLOCK = 60000000; // 64 MHz // PWM float analogValue = 0, analogAvg = 0, pwmMaxFloat = 6000; float adcToPwmRatio = 0; // Ratio between used pwm values and ADC resolution float pwmMin = 7500; // Minimum value of the pwm, motor at zero speed float pwmMax = 14500; // Maximum value of the pwm, motor at full speed float analogValueFloat_ADC3; // Value from ADC after filter to acquire uint32_t sumCounter = 0, iSamples = 1000, pwmValue = 0; volatile uint32_t pwmInput = 1; uint32_t pwmDutyCycle = 15000; // 500 Hz // Timer volatile unsigned long g_ui32TimerIntCount = 0; volatile unsigned long g_ui32SecondsOnTime = 0; #define APP_TICKS_PER_SEC 100; bool bTimerDone = false; uint32_t SampleFreq = 0; // Measuring time needed for acquisition uint8_t measureCounter = 0; // Measuring, StateMachine volatile enum { IDLE, INITIAL_MEASUREMENTS, INITIAL_CALCULATION, WAIT_FOR_POS_CYCLE, WAIT_FOR_HALF_CYCLE, WAIT_FOR_FULL_CYCLE, UPDATE_MEASUREMENTS } MeasState; // Speed cycling State Machine volatile enum { SPEED1, SPEED2, SPEED3, SPEED4, SPEED5, SPEED6, STOP } CyclicState; uint32_t iSpeedStateDelay = 0; uint32_t pwmMeas = 0; #define HYSTH_MIN_ADC 250 // Minimum value for the ADC recognize the motor is in motion #define INITIAL_MEAS_NUMBER 50 // Initial measurement numbers uint32_t sumADC3 = 0; // Stores the cummulative sum of ADC3 uint32_t iADCSum3 = 0; // Initial Counter for the number of measurements done by ADC3 uint32_t nCycle3 = 0; // Steady counter for the number of measurements done by ADC3 uint32_t avgADC3 = 0; // Average value of ADC3 uint32_t currentFreq3 = 0; // Current Frequency of ADC3 long inv_deltaT = 16000000; // Frequency of ADC sampling - 16 kHz bool bStartRunning = 0; //***************************************************************************** // The error routine that is called if the driver library encounters an error. //***************************************************************************** #ifdef DEBUG void __error__(char *pcFilename, uint32_t ui32Line) { } #endif //***************************************************************************** // ADC0 Sequence ISR - 19.01.2021 //***************************************************************************** void ADC0Sequence0ISR(void) { if (measureCounter == 1) { GPIOPinWrite(GPIO_PORTL_BASE, GPIO_PIN_3, 0); measureCounter = 2; } if (measureCounter == 0) { GPIOPinWrite(GPIO_PORTL_BASE, GPIO_PIN_3, GPIO_PIN_3); measureCounter = 1; } if (measureCounter == 2) { measureCounter = 0; } ADCIntClear(ADC0_BASE, 0); ADCSequenceDataGet(ADC0_BASE, 0, ui32adcValues); if (!bDataReady) { bDataReady = true; } } //***************************************************************************** // ADC Initialization - 19.01.2021 //***************************************************************************** void ConfigureADC(void) { SysCtlPeripheralReset(SYSCTL_PERIPH_GPIOE); SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE); SysCtlPeripheralReset(SYSCTL_PERIPH_ADC0); SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0); SysCtlDelay(10); GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_3 | GPIO_PIN_2 | GPIO_PIN_1 | GPIO_PIN_0 ); // // Configure the ADC to use PLL at SYSTEM_CLOCK (96 MHz) divided by 3 to get an ADC // clock of 32 MHz, sampling at FULL rate. // ADCClockConfigSet(ADC0_BASE, ADC_CLOCK_SRC_PLL | ADC_CLOCK_RATE_FULL, 50); // // Wait for the clock configuration to set. // SysCtlDelay(10); // Choose Sequencer 2 and set it at the highest Priority. ADCSequenceConfigure(ADC0_BASE, 0, ADC_TRIGGER_TIMER, 0); //ADCSequenceConfigure(ADC0_BASE, 0, ADC_TRIGGER_ALWAYS, 0); 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 | ADC_CTL_IE | ADC_CTL_END); ADCSequenceEnable(ADC0_BASE, 0); ADCIntClear(ADC0_BASE, 0); ADCIntEnable(ADC0_BASE, 0); IntEnable(INT_ADC0SS0); } //***************************************************************************** // PWM Initialization - 13.09.2020 //***************************************************************************** void Init_PWM(){ // 1. SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF); // Enable Port F while(!SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOF)); // 2. SysCtlPeripheralDisable(SYSCTL_PERIPH_PWM0); SysCtlPeripheralReset(SYSCTL_PERIPH_PWM0); SysCtlPeripheralEnable(SYSCTL_PERIPH_PWM0); while(!(SysCtlPeripheralReady(SYSCTL_PERIPH_PWM0))); // PWM0_BASE: 0 -> 0 from M_0_PWM1 // PWM_OUT_1 and PWM_OUT_1_BIT: 1 from M0PWM_1 // PWM_GEN_0: GEN_0 for PWM0 and PWM1, GEN_1 for PWM2 and PWM3... PWMClockSet(PWM0_BASE, PWM_SYSCLK_DIV_8); // SYSTEM_CLOCK / 32 = 3 MHz GPIOPinTypePWM(GPIO_PORTF_BASE, GPIO_PIN_1); // Pin 1 from PortF - PF1 GPIOPinConfigure(GPIO_PF1_M0PWM1); PWMGenConfigure(PWM0_BASE, PWM_GEN_0, PWM_GEN_MODE_DOWN | PWM_GEN_MODE_NO_SYNC); PWMGenPeriodSet(PWM0_BASE, PWM_GEN_0, pwmDutyCycle); // 120 MHz / pwmMax = pwmFreq PWMPulseWidthSet(PWM0_BASE, PWM_OUT_1, 1); PWMGenEnable(PWM0_BASE, PWM_GEN_0); PWMOutputState(PWM0_BASE, PWM_OUT_1_BIT, true); PWMIntEnable(PWM0_BASE, PWM_INT_GEN_0); PWMGenIntTrigEnable(PWM0_BASE, PWM_GEN_0, PWM_TR_CNT_ZERO); IntEnable(INT_PWM0_0); } //***************************************************************************** // UART Initialization - 19.01.21 //***************************************************************************** void InitConsole(void){ SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA); // Enable GPIO port A which is used for UART0 pins. // // Configure the pin muxing for UART0 functions on port A0 and A1. // This step is not necessary if your part does not support pin muxing. // GPIOPinConfigure(GPIO_PA0_U0RX); GPIOPinConfigure(GPIO_PA1_U0TX); SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0); // Enable UART0 so that we can configure the clock. UARTClockSourceSet(UART0_BASE, UART_CLOCK_PIOSC); // Use the internal 16MHz oscillator as the UART clock source. // // Select the alternate (UART) function for these pins. // GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1); UARTStdioConfig(0, 115200, 16000000); // Initialize the UART for console I/O. } //***************************************************************************** // Timer Initialization - 26.01.2021 //***************************************************************************** void ConfigureTimer(void) { // // Enable the peripherals used by this example. // SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0); // // Configure a 16-bit periodic timer. // TimerConfigure(TIMER0_BASE, TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_PERIODIC); // // Set ADC sampling frequency to be 16KHz i.e. every 62.5uS. // TimerLoadSet(TIMER0_BASE, TIMER_A, (g_ui32SysClock/64000) - 1); // // Enable the ADC trigger output for Timer A. // TimerControlTrigger(TIMER0_BASE, TIMER_A, true); // // Enable processor interrupts. // IntMasterEnable(); // // Enable Timer 0 which will start the whole application process. // TimerEnable(TIMER0_BASE, TIMER_A); } int main(void){ g_ui32SysClock = MAP_SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ | SYSCTL_OSC_MAIN | SYSCTL_USE_PLL | SYSCTL_CFG_VCO_480), SYSTEM_CLOCK); // Run from the PLL at SYSTEM_CLOCK MHz InitConsole(); // Set up the serial console to use for displaying messages ConfigureTimer(); // Set up the Timer ConfigureADC(); // Set up the ADC Init_PWM(); // Set up the PWM SysCtlPeripheralEnable(SYSCTL_PERIPH_GPION); // Enable Port N while(!SysCtlPeripheralReady(SYSCTL_PERIPH_GPION)); GPIOPinTypeGPIOOutput(GPIO_PORTN_BASE, GPIO_PIN_1); // Enable the GPIO pins for the LED D1 (PN1). SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOL); // Enable Port L while(!SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOL)); GPIOPinTypeGPIOOutput(GPIO_PORTL_BASE, GPIO_PIN_3); // Enable the GPIO pins for the PL3 IntMasterEnable(); // Conversion relative to max and min pwm used and ADC reading adcToPwmRatio = (pwmMax - pwmMin)/4095.0; // 4095 = 2^12 bits pwmInput = pwmMin; // Start on pwmMin value UARTprintf("pwmValue,"); UARTprintf("AIN0,"); // \r to replace, \n to new line //UARTprintf("AIN1,"); //UARTprintf("AIN2,"); UARTprintf("AIN3\n"); //UARTprintf("avgADC3"); //UARTprintf("currentFreq3"); // Initiate MeasState in IDLE MeasState = IDLE; // Infinite loop while(1) { if (bDataReady) { UARTprintf("%3d,", pwmInput); UARTprintf("%4d,", ui32adcValues[0]); // \r to replace, \n to new line //UARTprintf("%4d,", ui32adcValues[1]); //UARTprintf("%4d,", ui32adcValues[2]); UARTprintf("%4d\n", ui32adcValues[3]); //UARTprintf("%4d,", avgADC3); //UARTprintf("%8d\n", currentFreq3); bDataReady = false; } if (iSpeedStateDelay < 191000){ iSpeedStateDelay = iSpeedStateDelay + 1; } if (iSpeedStateDelay == 20000){ pwmInput = 7500; } if (iSpeedStateDelay == 40000){ pwmInput = 8500; } if (iSpeedStateDelay == 60000){ pwmInput = 9500; } if (iSpeedStateDelay == 80000){ pwmInput = 10500; } if (iSpeedStateDelay == 100000){ pwmInput = 11500; } if (iSpeedStateDelay == 120000){ pwmInput = 12500; } if (iSpeedStateDelay == 140000){ pwmInput = 12000; } if (iSpeedStateDelay == 160000){ pwmInput = 10000; } if (iSpeedStateDelay == 170000){ pwmInput = 8200; } if (iSpeedStateDelay == 180000){ pwmInput = 7750; } if (iSpeedStateDelay == 190000){ pwmInput = 7500; } } }
Best regards,
Gustavo Wegher