AnsweredAssumed Answered

STM32F4, ADC multichannel getting wrong values

Question asked by pablo on Jan 9, 2014
Latest reply on Jan 10, 2014 by pablo
Hello all and thanks for your help.
I made some research on how to make an adc conversion using 2 channels (for 2 different sensors). I wrote down my program but there are some strange behaviors.
In my idea this program should sample the data from 2 different sensor according to a Timer. Once there is TIM4_IRQHandler a function, send_Data_USART(), that sends the data via USART is called. 
I'm focus in particular on what happen in send_Data_USART().
First of all, in debug mode, I can see when I'm reading the values uint16_t adc1_ch1 = ADCConvertedValues[0] and     uint16_t adc1_ch2 = ADCConvertedValues[1] I have the next behavior:
- the value zero (nothing on the pins) is not zero, there is a bias of some mV that give me numbers different than zero.
- when I put a signal in one pin I can read a value (correct one) but also the other pin get a proportional value (lower) and viceversa. How this is possible? one is associated to ADCConvertedValues[0] and the other ADCConvertedValues[1] but I got this.
I also try to use different channels but still is the same story, at this point I wondering if there is a mistake in my code.


Here is my code, hope is clear and thanks for your help.
Pablo.


p.s. here is my reference: https://my.st.com/public/STe2ecommunities/mcu/Lists/STM32Discovery/Flat.aspx?RootFolder=%2Fpublic%2FSTe2ecommunities%2Fmcu%2FLists%2FSTM32Discovery%2FMulti%20Channel%20ADC%20reading&FolderCTID=0x01200200770978C69A1141439FE559EB459D75800084C20D8867EAD444A5987D47BE638E0F&currentviews=422

main.c
#include "utility.h"
  
int main(void)
{
    USART_Config();
    NVICConfig();
    TIM_Config();
    PWM_Config();
    PWM_SetDutyCycle(50);
    GPIO_Configuration();
    ADC1_Configuration();
  
    while(1)
    {
  
    }
}
 
events.c
#include "utility.h"
  
void TIM4_IRQHandler(void)
{
    send_Data_USART();
    TIM_ClearFlag( TIM4, TIM_FLAG_Update );
}
 
utility.h
/*
* All the header for the stm board.
*/
#include <stm32f4xx_gpio.h>
#include <stm32f4xx_rcc.h>
#include <stm32f4xx_tim.h>
#include <stm32f4xx_exti.h>
#include <stm32f4xx_syscfg.h>
#include <stm32f4xx_usart.h>
#include <stm32f4xx_adc.h>
#include <stm32f4xx_dma.h>
#include <misc.h>
  
/*
 * variables
 */
volatile uint16_t ADCConvertedValues[2];
  
/*
 * functions
 */
void GPIO_Configuration(void);
void ADC1_Configuration(void);
void TIM_Config(void);
void PWM_Config(void);
void PWM_SetDutyCycle(uint16_t dutycycle);
void USART_Config(void);
void NVICConfig(void);
  
void send_Data_USART(void);
 
utility.c
#include "utility.h"
  
GPIO_Configuration(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
    /* Configure ADC1 Channel3 & 5 pins as analog input ******************************/
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
}
  
void ADC1_Configuration(void)
{
    ADC_InitTypeDef       ADC_InitStructure;
    ADC_CommonInitTypeDef ADC_CommonInitStructure;
    DMA_InitTypeDef       DMA_InitStructure;
  
    /* Enable peripheral clocks *************************************************/
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
  
    /* DMA2_Stream0 channel0 configuration **************************************/
    DMA_DeInit(DMA2_Stream0);
    DMA_InitStructure.DMA_Channel = DMA_Channel_0;
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;
    DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADCConvertedValues[0];
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
    DMA_InitStructure.DMA_BufferSize = 2;
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;
    DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
    DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
    DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
    DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
    DMA_Init(DMA2_Stream0, &DMA_InitStructure);
    /* DMA2_Stream0 enable */
    DMA_Cmd(DMA2_Stream0, ENABLE);
  
    /* ADC Common Init **********************************************************/
    ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
    ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;
    ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
    ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
    ADC_CommonInit(&ADC_CommonInitStructure);
  
    /* ADC1 Init ****************************************************************/
    ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
    ADC_InitStructure.ADC_ScanConvMode = ENABLE;
    ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
    ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T4_CC4;
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
    ADC_InitStructure.ADC_NbrOfConversion = 2;
    ADC_Init(ADC1, &ADC_InitStructure);
  
    /* ADC1 regular channel configuration ******************************/
    ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_480Cycles); // PA1
    ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 2, ADC_SampleTime_480Cycles); // PA2
  
    /* Enable DMA request after last transfer (Single-ADC mode) */
    ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);
  
    /* Enable ADC1 DMA */
    ADC_DMACmd(ADC1, ENABLE);
  
    /* Enable ADC1 **************************************************************/
    ADC_Cmd(ADC1, ENABLE);
  
    /* Start ADC1 Software Conversion */
    ADC_SoftwareStartConv(ADC1);
}
  
void TIM_Config(void)
{
        GPIO_InitTypeDef GPIO_InitStructure;
  
        /* TIM3 clock enable */
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
        /* TIM4 clock enable */
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
  
        /* GPIOC clock enable */
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC , ENABLE);
        /* GPIOB clock enable */
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
  
        /* GPIOC Configuration: TIM3 CH1 (PC6) */
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
        GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
        GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP ;
        GPIO_Init(GPIOC, &GPIO_InitStructure);
  
        /* GPIOD Configuration: TIM4 CH1(PB6) */
  
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
        GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
        GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP ;
        GPIO_Init(GPIOB, &GPIO_InitStructure);
  
        /* Connect TIM3 pins to AF2, PC6 */
        GPIO_PinAFConfig(GPIOC, GPIO_PinSource6, GPIO_AF_TIM3);
        /* Connect TIM4 pins to AF2, PB6  */
        GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_TIM4);
  
}
void PWM_Config(void)
{
        TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
        TIM_OCInitTypeDef  TIM_OCInitStructure;
  
        /* TIM3 Time base configuration */
        TIM_TimeBaseStructure.TIM_Period = 1000 - 1;//period;
        TIM_TimeBaseStructure.TIM_Prescaler = 21000 - 1;//PrescalerValue;
        TIM_TimeBaseStructure.TIM_ClockDivision = 0;
        TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
  
        TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
  
        /* TIM4 Time base configuration */
  
        TIM_TimeBaseStructure.TIM_Period = 500-1;//period - 1;
        TIM_TimeBaseStructure.TIM_Prescaler = 1000-1;//PrescalerValue;
        TIM_TimeBaseStructure.TIM_ClockDivision = 0;
        TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
  
        TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);
  
        /* TIM3 PWM1 Mode configuration: Channel1 */
        TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
        TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
        TIM_OCInitStructure.TIM_Pulse = 0;
        TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
  
        TIM_OC1Init(TIM3, &TIM_OCInitStructure);
  
        TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable);
  
        TIM_ARRPreloadConfig(TIM3, ENABLE);
  
        /* TIM4 PWM1 Mode configuration: Channel1 */
  
        TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
        TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
        TIM_OCInitStructure.TIM_Pulse = 0; // OFF
        TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
  
        TIM_OC1Init(TIM4, &TIM_OCInitStructure);
        TIM_OC1PreloadConfig(TIM4, TIM_OCPreload_Enable);
  
        TIM_ARRPreloadConfig(TIM4, ENABLE);
  
        /* TIM3 &TIM4 enable counter */
        // TIM3  interrupt
        TIM_Cmd(TIM3, ENABLE);
        //TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);
  
        TIM_Cmd(TIM4, ENABLE);
        //TIM4 la parte per gli interrupt
        TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE);
  
}
  
void PWM_SetDutyCycle(uint16_t dutycycle)
{
    TIM3->CCR1 = dutycycle;
    TIM4->CCR1 = dutycycle;
}
  
void USART_Config(void)
{
        /* USARTx configured as follow:
            - BaudRate = 115200 baud
            - Word Length = 8 Bits
            - One Stop Bit
            - No parity
            - Hardware flow control disabled (RTS and CTS signals)
            - Receive and transmit enabled
        */
        GPIO_InitTypeDef GPIO_InitStructure;
        USART_InitTypeDef USART_InitStructure;
  
        /* Enable GPIO clock */
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
  
        /* Enable UART clock */
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
  
        /* Connect PXx to USARTx_Tx*/
        GPIO_PinAFConfig(GPIOB, GPIO_PinSource10, GPIO_AF_USART3);
  
        /* Connect PXx to USARTx_Rx*/
        GPIO_PinAFConfig(GPIOB, GPIO_PinSource11, GPIO_AF_USART3);
  
        /* Configure USART Tx as alternate function  */
        GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
        GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOB, &GPIO_InitStructure);
  
        /* Configure USART Rx as alternate function  */
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
        GPIO_Init(GPIOB, &GPIO_InitStructure);
  
        USART_InitStructure.USART_BaudRate = 115200;
        USART_InitStructure.USART_WordLength = USART_WordLength_8b;
        USART_InitStructure.USART_StopBits = USART_StopBits_1;
        USART_InitStructure.USART_Parity = USART_Parity_No;
        USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
        USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
  
        /* USART configuration */
        USART_Init(USART3, &USART_InitStructure);
        //USART_ClearFlag(USART3, USART_FLAG_TC);
  
        /* Enable USART */
        USART_Cmd(USART3, ENABLE);
}
  
void NVICConfig(void)
{
    NVIC_InitTypeDef NVIC_InitStructure;
  
    /* Enable the TIM4 Interrupt */
    NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn ;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
  
    /* Enable the TIM4 Interrupt */
  
    NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn ;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}
  
void send_Data_USART(void)
{
    uint16_t adc1_ch1 = ADCConvertedValues[0];
    uint16_t adc1_ch2 = ADCConvertedValues[1];
  
    //break point here
    uint8_t adc1_ch1MSB = adc1_ch1 >> 8;
    adc1_ch1MSB = adc1_ch1MSB & 0xF; //00001111
    uint8_t adc1_ch1LSB = adc1_ch1;
  
    uint8_t adc1_ch2MSB = adc1_ch2 >> 8;
    adc1_ch2MSB = adc1_ch2MSB | 0x30; //01100000
    uint8_t adc1_ch2LSB = adc1_ch2;
  
    while(USART_GetFlagStatus(USART3, USART_FLAG_TC) == RESET);
    USART_SendData(USART3,adc1_ch1MSB);
    while(USART_GetFlagStatus(USART3, USART_FLAG_TC) == RESET);
    USART_SendData(USART3,adc1_ch1LSB);
  
    while(USART_GetFlagStatus(USART3, USART_FLAG_TC) == RESET);
    USART_SendData(USART3,adc1_ch2MSB);
    while(USART_GetFlagStatus(USART3, USART_FLAG_TC) == RESET);
    USART_SendData(USART3,adc1_ch2LSB);
  
}

Outcomes