AnsweredAssumed Answered

STM32F0 Signal Sensing with ADC

Question asked by Tichenko.Anthony on Nov 8, 2016
Latest reply on Nov 9, 2016 by Tichenko.Anthony
Hello,
I'm working on a solution that attempts to implement a signal sensor as well as a switch to standby power supply. The signal is inserted into ADC and if it is below certain value, switch should be triggered to enable standby PSU.
However, there is a problem. On default, the device starts up in active mode, then goes to standby like it should, but unfortunately after that the MCU does not wake up. In fact it freezes completely and does not respond to any external triggers or anything. It appears that this freezing happens during the change of power supplies. The MCU has got plenty of decoupling on power supply and +3.3V supply is not being interrupted, so the MCU stays ON  all the time. I have checked that. 
I'm thinking that the problem may be with timings, please have a look at my code below, I will appreciate any advice.
Many Thanks,

#include "main.h"


GPIO_InitTypeDef GPIO_InitStructure;
ADC_InitTypeDef ADC_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
DMA_InitTypeDef DMA_InitStructure;


volatile uint16_t Conversions[2];


uint8_t Mode_status = 0;
uint8_t LED_status = 0;


uint16_t temperature = 0;
uint16_t signal_sense = 0;


void ADC_restart(void)
{
     DMA_Cmd(DMA1_Channel1, DISABLE); //Disable the DMA channel
     DMA_Init(DMA1_Channel1, &DMA_InitStructure); //Re-initialize channel
     DMA_Cmd(DMA1_Channel1, ENABLE); //Enable the DMA channel


     ADC_StartOfConversion(ADC1); // Start the next conversion
}


void signal_read(void)
{
     if (Mode_status == MODE_STANDBY && Mode_status != MODE_FAULT)
          {
               if (signal_sense > SENSE_LOW_TH)
                    {
                         Mode_status = MODE_ACTIVE;
                    }
          }
                                   
     if (Mode_status == MODE_ACTIVE && Mode_status != MODE_FAULT)
          {
               if (signal_sense < SENSE_LOW_TH)
                    {
                         Mode_status = MODE_STANDBY;
                    }
          }
     else{}
}


void temperature_read(void)
{
     if (temperature > TEMP_WARNING)
          {
               LED_status = LED_RED_FLASH;
                    if (temperature > TEMP_FAULT)
                         {
                              Mode_status = MODE_FAULT;
                         }
                    else{}
          }
     else{}
}


int main (void)
{     
     SystemInit();
     SystemCoreClockUpdate();
     
     RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA | RCC_AHBPeriph_GPIOB, ENABLE); // GPIOA enable
     RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); // enable ADC clock
     RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); // enable DMA clock


     GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_3 | GPIO_Pin_5 | GPIO_Pin_12; 
     GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_OUT;
     GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_Level_1;
     GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_NOPULL;
     GPIO_Init(GPIOA, &GPIO_InitStructure); // GPIOA outputs: PIN_STB, PIN_TDA_UNMUTE, PIN_UNMUTE
     
     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_4;
     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
     GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
     GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
     GPIO_Init(GPIOA, &GPIO_InitStructure); // ADC inputs: PIN_SENSE, PIN_TEMP     
     
     GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6;
     GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_OUT;
     GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_Level_1;
     GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_NOPULL;
     GPIO_Init(GPIOB, &GPIO_InitStructure); // GPIOB_outputs: LED_HF_HIGH, LED_BYP, LED_1, LED_2
     
     ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
     ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
     ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None; 
     ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
  ADC_InitStructure.ADC_ScanDirection = ADC_ScanDirection_Upward;
     ADC_Init(ADC1, &ADC_InitStructure);
     
     ADC_GetCalibrationFactor(ADC1); // calibrate the ADC
     
     ADC_Cmd(ADC1, ENABLE); // Activate the ADC
     ADC_DMACmd(ADC1, ENABLE);
     
     DMA_InitStructure.DMA_BufferSize = 1;                                                  //Two variables
     DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;                                   //ADC peripheral is the data source
     DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;                                        //Disable memory to memory mode
     DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t) &Conversions[0];               //Pointer to variables array
     DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;               //'Conversions' is 16bits large (HWord)
     DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                              //Enable memory increment
     DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;                                        //Circular DMA mode
     DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) &ADC1->DR;               //Pointer to ADC data register!
     DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;     //ADC1->DR is 16bits!
     DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;               //Disable peripheral increment
     DMA_InitStructure.DMA_Priority = DMA_Priority_Low;                                   //A low priority DMA stream, not a big deal here!
     DMA_Init(DMA1_Channel1, &DMA_InitStructure);
     DMA_Cmd(DMA1_Channel1, ENABLE);
     
     DMA_ClearITPendingBit(DMA1_IT_TC1);
     DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE);
     
     NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn;
     NVIC_InitStructure.NVIC_IRQChannelPriority = 1;
     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
     
     ADC_ChannelConfig (ADC1, ADC_Channel_1, ADC_SampleTime_239_5Cycles); // 18uS sampling time
     ADC_ChannelConfig (ADC1, ADC_Channel_4, ADC_SampleTime_239_5Cycles); // 18uS sampling time     
     
     while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_ADRDY)); // wait for the ADC to become ready
     
     ADC_StartOfConversion(ADC1); // Start the first conversion


     Mode_status = MODE_ACTIVE;
     
     while (1)
          {                    
               switch (Mode_status)
                    {
                         case MODE_ACTIVE:
                              LED_status = LED_GREEN;
                              GPIOA->ODR |= (1<<PIN_STB);
                              GPIOA->ODR |= (1<<PIN_TDA_UNMUTE);
                              GPIOA->ODR |= (1<<PIN_UNMUTE);
                              break;
                         case MODE_STANDBY:                         
                              LED_status = LED_ORANGE;
                              GPIOA->ODR &=~ (1<<PIN_UNMUTE);
                              GPIOA->ODR &=~ (1<<PIN_TDA_UNMUTE);
                              GPIOA->ODR &=~ (1<<PIN_STB);
                              break;
                         case MODE_FAULT:
                              LED_status = LED_RED;
                              GPIOA->ODR &=~ (1<<PIN_UNMUTE);
                              GPIOA->ODR &=~ (1<<PIN_TDA_UNMUTE);
                              GPIOA->ODR &=~ (1<<PIN_STB);
                              break;
                    }
                    
               switch (LED_status)
                    {
                    case LED_GREEN: 
                         GPIOB->ODR |= (1<<LED_1);
                         GPIOB->ODR &=~ (1<<LED_2);
                         break;
                    case LED_RED:
                         GPIOB->ODR |= (1<<LED_2);
                         GPIOB->ODR &=~ (1<<LED_1);
                         break;
                    case LED_ORANGE:
                         GPIOB->ODR |= ((1<<LED_1) | (1<<LED_2));
                         break;
                    case LED_GREEN_FLASH:
                         GPIOB->ODR ^= (1<<LED_1);
                         GPIOB->ODR &=~ (1<<LED_2);
                         break;
                    case LED_RED_FLASH:
                         GPIOB->ODR ^= (1<<LED_2);
                         GPIOB->ODR &=~ (1<<LED_1);
                         break;
                    case LED_ORANGE_FLASH:
                         GPIOB->ODR ^= ((1<<LED_1) | (1<<LED_2));
                         break;
                    case LED_OFF:
                         GPIOB->ODR &=~ ((1<<LED_1) | (1<<LED_2));
                         break;
                    }
                    
                    __WFI();
          }
}


void DMA1_Channel1_IRQHandler(void)
{
     if (DMA_GetITStatus(DMA1_IT_TC1) != RESET)
     {
          DMA_ClearITPendingBit(DMA1_IT_TC1);
          
          signal_sense = (uint16_t) Conversions[0];
          temperature = (uint16_t) Conversions[1];
          
          signal_read();
          temperature_read();
          
          ADC_restart();
     }
}


Outcomes