Alex
Alex

Reputation: 107

ADC through PWM signal problems

I am using an STM32F100RB at the moment and I am trying to read a value from a potentiometer and to display it through the PWM signal. The problem I have is where I am connecting them I think. The PWM signal is generated through this code:

GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
uint32_t Prescaler, Period;

/* Enable GPIO clock */
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

/* Enable TIM clock */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);

/* Configure TIM1_CH1 as alternate function push-pull */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; // No point in overdriving
GPIO_Init(GPIOA, &GPIO_InitStructure);

/* Both these must ultimately fit in 16-bit, ie 1..65536 */

Prescaler = (SystemCoreClock / 20000); // System -> 20 KHz
Period = 2000; // 20 KHz -> 1 Hz

/* Extra caution required with TIM1/TIM8 full function timers, to initialize ALL fields */

/* Time base configuration */
TIM_TimeBaseStructure.TIM_Prescaler = (uint16_t)(Prescaler - 1);
TIM_TimeBaseStructure.TIM_Period = (uint16_t)(Period - 1);
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // Where do those stairs go? They go up!
TIM_TimeBaseStructure.TIM_ClockDivision = 0; // Not used
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0; // Not used

TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);

/* PWM1 Mode configuration: Channel1 */
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_Pulse = (uint16_t)(Period / ADC1ConvertedValue[0]); // 50%
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;
TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Reset;

TIM_OC1Init(TIM1, &TIM_OCInitStructure);

/* TIM1 enable counter */
TIM_Cmd(TIM1, ENABLE);

/* TIM1 Main Output Enable */
TIM_CtrlPWMOutputs(TIM1, ENABLE);

while (1)
  {
  }

The PWM output works fine, and it displays what it should display. The problem comes with the ADC, where something seems not to work as it should (the code is from the manufacturer website), and this is the full code.

#include "stm32f10x.h"
//#include "stm32f10x_conf.h"
#include "stm32f10x_usart.h"
#include "stm32f10x_rcc.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_tim.h"
#include "stm32f10x_adc.h"
#include "stm32f10x_dma.h"
#include "stm32f10x_flash.h"
#define ADC1_DR_Address    ((uint32_t)0x4001244C)
#define BufferLenght       4
ADC_InitTypeDef   ADC_InitStructure;
DMA_InitTypeDef   DMA_InitStructure;
uint16_t ADC1ConvertedValue[BufferLenght];
ErrorStatus HSEStartUpStatus;
void RCC_Configuration(void);
void GPIO_Configuration(void);
RCC_Configuration();
GPIO_Configuration();
/* DMA1 channel1 configuration ---------------------------------------------*/
DMA_DeInit(DMA1_Channel1);
DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)ADC1ConvertedValue;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_BufferSize = BufferLenght;
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_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel1, &DMA_InitStructure);

/* Enable DMA1 channel1 */
DMA_Cmd(DMA1_Channel1, ENABLE);

/* ADC1 configuration ------------------------------------------------------*/
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_InitStructure.ADC_ScanConvMode = ENABLE;
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfChannel = BufferLenght;
ADC_Init(ADC1, &ADC_InitStructure);

/* ADC1 regular channel11, channel14, channel16 and channel17 configurations */
ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 1, ADC_SampleTime_41Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_17, 2, ADC_SampleTime_239Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_16, 3, ADC_SampleTime_239Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_14, 4, ADC_SampleTime_1Cycles5);

/* Enable ADC1 DMA */
ADC_DMACmd(ADC1, ENABLE);

/* Enable ADC1 */
ADC_Cmd(ADC1, ENABLE);

/* Enable TempSensor and Vrefint channels: channel16 and Channel17 */
ADC_TempSensorVrefintCmd(ENABLE);

/* Enable ADC1 reset calibaration register */
ADC_ResetCalibration(ADC1);

/* Check the end of ADC1 reset calibration register */
while(ADC_GetResetCalibrationStatus(ADC1));

/* Start ADC1 calibaration */
ADC_StartCalibration(ADC1);

/* Check the end of ADC1 calibration */
while(ADC_GetCalibrationStatus(ADC1));

/* Start ADC1 Software Conversion */
ADC_SoftwareStartConvCmd(ADC1, ENABLE);

/* Test on Channel 1 DMA1_FLAG_TC flag */
while(!DMA_GetFlagStatus(DMA1_FLAG_TC1));

/* Clear Channel 1 DMA1_FLAG_TC flag */
DMA_ClearFlag(DMA1_FLAG_TC1);


GPIO_InitTypeDef GPIO_InitStructure;
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    TIM_OCInitTypeDef TIM_OCInitStructure;
    uint32_t Prescaler, Period;
/* Enable GPIO clock */
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

    /* Enable TIM clock */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);

    /* Configure TIM1_CH1 as alternate function push-pull */
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; // No point in overdriving
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    /* Both these must ultimately fit in 16-bit, ie 1..65536 */

    Prescaler = (SystemCoreClock / 20000); // System -> 20 KHz
    Period = 2000; // 20 KHz -> 1 Hz

    /* Extra caution required with TIM1/TIM8 full function timers, to initialize ALL fields */

    /* Time base configuration */
    TIM_TimeBaseStructure.TIM_Prescaler = (uint16_t)(Prescaler - 1);
    TIM_TimeBaseStructure.TIM_Period = (uint16_t)(Period - 1);
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // Where do those stairs go? They go up!
    TIM_TimeBaseStructure.TIM_ClockDivision = 0; // Not used
    TIM_TimeBaseStructure.TIM_RepetitionCounter = 0; // Not used

    TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);

    /* PWM1 Mode configuration: Channel1 */
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
    TIM_OCInitStructure.TIM_Pulse = (uint16_t)(Period / ADC1ConvertedValue[0]); // 50%
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
    TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;
    TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
    TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Reset;

    TIM_OC1Init(TIM1, &TIM_OCInitStructure);

    /* TIM1 enable counter */
    TIM_Cmd(TIM1, ENABLE);

    /* TIM1 Main Output Enable */
    TIM_CtrlPWMOutputs(TIM1, ENABLE);

while (1)
{
}
}

/**
* @brief    Configures the different system clocks.
* @param    None
* @retval None
*/
void RCC_Configuration(void)
{
    /* RCC system reset(for debug purpose) */
RCC_DeInit();

/* Enable HSE */
RCC_HSEConfig(RCC_HSE_ON);

/* Wait till HSE is ready */
HSEStartUpStatus = RCC_WaitForHSEStartUp();

if(HSEStartUpStatus == SUCCESS)
{
    /* Enable Prefetch Buffer */
    FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);

    /* Flash 2 wait state */
    FLASH_SetLatency(FLASH_Latency_2);

    /* HCLK = SYSCLK */
    RCC_HCLKConfig(RCC_SYSCLK_Div1);

    /* PCLK2 = HCLK */
    RCC_PCLK2Config(RCC_HCLK_Div1);

    /* PCLK1 = HCLK/2 */
    RCC_PCLK1Config(RCC_HCLK_Div2);

    /* ADCCLK = PCLK2/4 */
    RCC_ADCCLKConfig(RCC_PCLK2_Div4);

#ifndef STM32F10X_CL
    /* PLLCLK = 8MHz * 7 = 56 MHz */
    RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_7);

#else
    /* Configure PLLs *********************************************************/
    /* PLL2 configuration: PLL2CLK = (HSE / 5) * 8 = 40 MHz */
    RCC_PREDIV2Config(RCC_PREDIV2_Div5);
    RCC_PLL2Config(RCC_PLL2Mul_8);

    /* Enable PLL2 */
    RCC_PLL2Cmd(ENABLE);

    /* Wait till PLL2 is ready */
    while (RCC_GetFlagStatus(RCC_FLAG_PLL2RDY) == RESET)
    {}

    /* PLL configuration: PLLCLK = (PLL2 / 5) * 7 = 56 MHz */
    RCC_PREDIV1Config(RCC_PREDIV1_Source_PLL2, RCC_PREDIV1_Div5);
    RCC_PLLConfig(RCC_PLLSource_PREDIV1, RCC_PLLMul_7);
#endif

    /* Enable PLL */
    RCC_PLLCmd(ENABLE);

    /* Wait till PLL is ready */
    while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
    {
    }

    /* Select PLL as system clock source */
    RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);

    /* Wait till PLL is used as system clock source */
    while(RCC_GetSYSCLKSource() != 0x08)
    {
    }
}

    /* Enable DMA1 clock */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

/* Enable peripheral clocks     --------------------------------------------------*/
/* Enable ADC1 and GPIOC clock */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
}

/**
* @brief    Configures the different GPIO ports.
* @param    None
* @retval None
*/
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;

/* Configure PC.01 and PC.04 (Channel11 and Channel14) as analog input -----*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOC, &GPIO_InitStructure);
}

I am combining those two parts of code at the point where I should divide the value that TIM_Pulse is assigned: TIM_OCInitStructure.TIM_Pulse = (uint16_t)(Period / ADC1ConvertedValue[0]);

I am a newcome in the embedded programming, and I just started playing with this board and the goal I want to achieve is to set the Pulse length according to the potentiometer value. Thank you in advance, Alex.

Upvotes: 0

Views: 1357

Answers (1)

Alex
Alex

Reputation: 107

The modified code looks like this:

    #include "stm32f10x_conf.h"
    #include "stm32f10x_gpio.h"
    #include "stm32f10x_rcc.h"
    #include "stm32f10x_adc.h"
    #include "stm32f10x_tim.h"

    double x = 0;
    GPIO_InitTypeDef myGPIO;
    ADC_InitTypeDef myADC;

    void adc_config()
    {

    //ADC
    myGPIO.GPIO_Pin = GPIO_Pin_6; //setat pe pin6
    myGPIO.GPIO_Mode = GPIO_Mode_AIN; //setare ca analog
    GPIO_Init(GPIOA, &myGPIO); //set to A6

    RCC_ADCCLKConfig (RCC_PCLK2_Div6); //ceas pentru ADC (max 14MHz, 72/6=12MHz)
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); //ceas ADC

    //configurare parametrii ADC
    myADC.ADC_Mode = ADC_Mode_Independent;
    myADC.ADC_ScanConvMode = DISABLE;
    myADC.ADC_ContinuousConvMode = ENABLE;
    myADC.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
    myADC.ADC_DataAlign = ADC_DataAlign_Right;
    myADC.ADC_NbrOfChannel  = 1;
    ADC_RegularChannelConfig(ADC1, ADC_Channel_6, 1, ADC_SampleTime_55Cycles5); //PA6 as Input
    ADC_Init(ADC1, &myADC);

    //enable
    ADC_Cmd(ADC1, ENABLE);


        ADC_ResetCalibration(ADC1);
    while(ADC_GetResetCalibrationStatus(ADC1));
    ADC_StartCalibration(ADC1);
    while(ADC_GetCalibrationStatus(ADC1));


    ADC_Cmd(ADC1, ENABLE);
}


    int getPot(void)
{
    return ADC_GetConversionValue(ADC1);
}

    //configurare pini I/O
    void GPIO_config(void)
{

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
    //LED-pinC9
    GPIO_StructInit(&myGPIO);
    myGPIO.GPIO_Pin = GPIO_Pin_9;
    myGPIO.GPIO_Mode = GPIO_Mode_Out_PP;
    myGPIO.GPIO_Speed = GPIO_Speed_2MHz;
    GPIO_Init(GPIOC, &myGPIO);


}

    int main(void)
    {
    GPIO_config(); //configurare pini
        adc_config(); //configurare ADC
        GPIO_InitTypeDef GPIO_InitStructure;
          TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
          TIM_OCInitTypeDef TIM_OCInitStructure;
          uint32_t Prescaler, Period;

          /*!< At this stage the microcontroller clock setting is already configured,
               this is done through SystemInit() function which is called from startup
               file (startup_stm32f10x_xx.s) before to branch to application main.
               To reconfigure the default setting of SystemInit() function, refer to
               system_stm32f10x.c file
             */

          /* Enable GPIO clock */
            RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

          /* Enable TIM clock */
          RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);

          /* Configure TIM1_CH1 as alternate function push-pull */
          GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
          GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
          GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; // No point in overdriving
          GPIO_Init(GPIOA, &GPIO_InitStructure);

          /* Both these must ultimately fit in 16-bit, ie 1..65536 */

          Prescaler = (SystemCoreClock / 200000); // System -> 20 KHz
          Period = 2000; // 20 KHz -> 1 Hz

          /* Extra caution required with TIM1/TIM8 full function timers, to initialize ALL fields */

          /* Time base configuration */
          TIM_TimeBaseStructure.TIM_Prescaler = (uint16_t)(Prescaler - 1);
          TIM_TimeBaseStructure.TIM_Period = (uint16_t)(Period - 1);
          TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // Where do those stairs go? They go up!
          TIM_TimeBaseStructure.TIM_ClockDivision = 0; // Not used
          TIM_TimeBaseStructure.TIM_RepetitionCounter = 0; // Not used

          TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
        while(1)
        {
            x = getPot()*3.3/4096; //obtinere valoare analog si convertirea in volti, 12bit ADC
            /* PWM1 Mode configuration: Channel1 */
              TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
              TIM_OCInitStructure.TIM_Pulse = (uint16_t)(Period / x); // 50%
              TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
              TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;
              TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
              TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;
              TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
              TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Reset;

              TIM_OC1Init(TIM1, &TIM_OCInitStructure);

              /* TIM1 enable counter */
              TIM_Cmd(TIM1, ENABLE);

              /* TIM1 Main Output Enable */
              TIM_CtrlPWMOutputs(TIM1, ENABLE);

            if(x > 2)
            {
            GPIO_WriteBit(GPIOC, GPIO_Pin_9, Bit_SET);//pornire Led
            }
            else {
            GPIO_WriteBit(GPIOC, GPIO_Pin_9, Bit_RESET);//oprire Led
            }

        }

    }

Thanks to @Olaf.

Upvotes: 2

Related Questions