Getting values from ADC in the Timer interrupt

Started by dvd_video, June 11, 2013, 02:15:56 PM

Previous topic - Next topic

dvd_video

Hi guys,

I am trying to detect voltage from the  ADC and write it to an array of u16-s where
every record should be done in 100 microseconds (100 us between every sample).

void TIM2_IRQHandler(void)
{   // All the time ...
   if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
   {
   // If reached 100 us
   // Clear interrupt flag
      TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
      if(TrendIndex < TREND_BUFFER_SIZE)
      {
         Trend[TrendIndex++] = GetADC();
         TrendReady = 0x00;
      }else{
         TrendIndex = 0x00;
         TrendReady = 0xff;
      }
   }
}

My timer init is:

void InitTimer()
{
   NVIC_InitTypeDef        NVIC_InitStructure;
   TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
   /* Enable the TIM2 global Interrupt */
   NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
   NVIC_Init(&NVIC_InitStructure);

   /* TIM2 clock enable */
   RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
   /* Time base configuration */
   TIM_TimeBaseStructure.TIM_Period = 100 - 1; // 1 MHz down to 1 KHz
   TIM_TimeBaseStructure.TIM_Prescaler = 42 - 1; // 24 MHz Clock down to 1 MHz
   TIM_TimeBaseStructure.TIM_ClockDivision = 0;
   TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
   TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
   /* TIM IT enable */
   TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
   /* TIM2 enable counter */
   TIM_Cmd(TIM2, ENABLE);
}

My ADC control is:

void InitADC(void)
{
    ADC_InitTypeDef ADC_Init_structure; //Structure for ADC configuration
    GPIO_InitTypeDef GPIO_InitStructre; //Structure for analog input pin
    //Clock configuration
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC3,ENABLE);//The ADC3 is connected the APB2 peripheral bus thus we will use its clock source
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF,ENABLE);//Clock for the ADC port!!
    //Analog pin configuration
    GPIO_InitStructre.GPIO_Pin = GPIO_Pin_6;//The channel 4 is connected to PF6
    GPIO_InitStructre.GPIO_Mode = GPIO_Mode_AN; //The PF6 pin is configured in analog mode
    GPIO_InitStructre.GPIO_PuPd = GPIO_PuPd_NOPULL; //We don't need any pull up or pull down
    GPIO_Init(GPIOF,&GPIO_InitStructre);//Affecting the port with the initialization structure configuration
    //ADC structure configuration
    ADC_DeInit();
    ADC_Init_structure.ADC_DataAlign = ADC_DataAlign_Right;//data converted will be shifted to right
    ADC_Init_structure.ADC_Resolution = ADC_Resolution_12b;//Input voltage is converted into a 12bit number giving a maximum value of 4096
    ADC_Init_structure.ADC_ContinuousConvMode = ENABLE; //the conversion is continuous, the input data is converted more than once
    ADC_Init_structure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;// conversion is synchronous with TIM1 and CC1 (actually I'm not sure about this one :/)
    ADC_Init_structure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;//no trigger for conversion
    ADC_Init_structure.ADC_NbrOfConversion = 1;//I think this one is clear :p
    ADC_Init_structure.ADC_ScanConvMode = DISABLE;//The scan is configured in one channel
    ADC_Init(ADC3,&ADC_Init_structure);//Initialize ADC with the previous configuration
    //Enable ADC conversion
    ADC_Cmd(ADC3,ENABLE);
    //Select the channel to be read from
    ADC_RegularChannelConfig(ADC3,ADC_Channel_4,1,ADC_SampleTime_144Cycles);
    return;
}

s32 GetADC(void)
{
    ADC_SoftwareStartConv(ADC3);//Start the conversion
    while(!ADC_GetFlagStatus(ADC3, ADC_FLAG_EOC));//Processing the conversion
    return ADC_GetConversionValue(ADC3); //Return the converted data
}

After transmitting "Trend" to RS i get

595
3873
3874
3922
3871
3861
3873
3887
3866
3850
3871
3885
3882
3880
3850
3871
3877
3877
3875
3870
3863
3888

So i thing my timer interrupt is putting the values waaaay more slow than i thought ..
Is there any way for ADC to convert faster ?
I am an automation engineer graduated from TU-Sofia, Bulgaria. My passion is Programming, hardware martial arts and cycling.

abrarmi

#1
Hi,

I am working on a project where I need to use the timer-1 interrupt of Olinuxino A13. I have successfully initialized the timer also enabled the timer-1 interrupt.

Can someone help me with writing the Interrupt Service Routine (ISR) for the timer-1 interrupt.

This is my C code so far,


/////////////////////////////////////////////////////////////
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <time.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/select.h>
#include <pthread.h>
#include <unistd.h>
#include <sched.h>

#define GPIO_BASE    0x01c20800
#define PWM_BASE     0x01c20C00

#define PortGConf1Offset    0xDC
#define PortGDataOffset    0xE8
#define PortBConf0Offset    0x24    
#define PWMCtrlOffset       0x200
#define PWMPeriodOffset    0x204

#define TimerIRQEnOffset   0x00
#define   TimerStatusOffset   0x04
#define   Timer0ControlOffset   0x10
#define   Timer0IntervalOffset   0x14
#define Timer0CurrentOffset   0x18
#define   Timer1ControlOffset   0x20
#define   Timer1IntervalOffset   0x24
#define Timer1CurrentOffset   0x28

unsigned int *portGConfig;
unsigned int *portGData;
unsigned int *portBConfig;   
unsigned int *PWMCtrl;   
unsigned int *PWMPeriod;
unsigned int *TimerIRQEn;
unsigned int *TimerStatus;
unsigned int *Timer0Control;
unsigned int *Timer0Interval;
unsigned int *Timer0Current;
unsigned int *Timer1Control;
unsigned int *Timer1Interval;
unsigned int *Timer1Current;   

static unsigned int GPIO_MMAP = 0;
static unsigned int PWM_MMAP = 0;
static unsigned int TIMER_MMAP = 0;


int main(void)
{

/////////////////////////////////////////////////////////////

   int fd;
   unsigned int addr_start, addr_offset, pwm_offset;
   unsigned int PageSize, PageMask;
   void *pc;

   fd = open("/dev/mem", O_RDWR);
      if(fd < 0) { perror("Unable to open /dev/mem"); }

   PageSize = sysconf(_SC_PAGESIZE);
   PageMask = (~(PageSize-1));
     
   addr_start  = GPIO_BASE &  PageMask;
   addr_offset = GPIO_BASE & ~PageMask;
   pwm_offset = PWM_BASE & ~PageMask;
     
   pc = (void *)mmap(0, PageSize*2, PROT_READ|PROT_WRITE, MAP_SHARED, fd, addr_start);
      if(pc == MAP_FAILED) { perror("Unable to mmap file"); }
         
   GPIO_MMAP = (unsigned int)pc;
   GPIO_MMAP += addr_offset;   

   PWM_MMAP = (unsigned int)pc;
   PWM_MMAP += pwm_offset;
   
   TIMER_MMAP = PWM_MMAP;
 
   close(fd);
      //if(fd == -1) { perror("Unable to close file"); }

/////////////////////////////////////////////////////////////

   portGConfig =     (unsigned int *)(GPIO_MMAP + PortGConf1Offset);
   portGData =     (unsigned int *)(GPIO_MMAP + PortGDataOffset);
   portBConfig =     (unsigned int *)(GPIO_MMAP + PortBConf0Offset);   
   PWMCtrl =     (unsigned int *)(PWM_MMAP + PWMCtrlOffset);   
   PWMPeriod =     (unsigned int *)(PWM_MMAP + PWMPeriodOffset);

   *portGConfig = 0x1110;      //configure port G pin 9 to output

   //*portGData = 0x0000;      // *portGData&= ~(0x0200);

   *portBConfig = 0x200;      //Configure Port B pin 2 to PWM

   *PWMCtrl = 0x00;      //printf("PWM cleared\n");
   *PWMCtrl |= 0x00000020;    //printf("PWM High Level\n");
   *PWMCtrl |= 0x00000002;    //printf("PWM 24MHz/240 = 100kHz\n");
   *PWMCtrl |= 0x00000040;    //printf("PWM Gating = pass\n");
   *PWMCtrl |= 0x00000010;    //printf("PWM Enabled\n");

   *PWMPeriod = 0x01F30064;   //printf("PWM period 0x01F30064\n");

/////////////////////////////////////////////////////////////

   TimerIRQEn =     (unsigned int *)(TIMER_MMAP + TimerIRQEnOffset);
   TimerStatus =     (unsigned int *)(TIMER_MMAP + TimerStatusOffset);
   Timer0Control =  (unsigned int *)(TIMER_MMAP + Timer0ControlOffset);
   Timer0Interval = (unsigned int *)(TIMER_MMAP + Timer0IntervalOffset);
   Timer0Current =  (unsigned int *)(TIMER_MMAP + Timer0CurrentOffset);
   Timer1Control =  (unsigned int *)(TIMER_MMAP + Timer1ControlOffset);
   Timer1Interval = (unsigned int *)(TIMER_MMAP + Timer1IntervalOffset);
   Timer1Current =  (unsigned int *)(TIMER_MMAP + Timer1CurrentOffset);

   *TimerIRQEn |= 0x02;      //printf("*TimerIRQEn = 0x%x\n", *TimerIRQEn);
   *Timer1Control = 0x04;      //printf("*Timer1Control = 0x%x\n", *Timer1Control);
   *TimerStatus = 0x02;      //printf("*TimerStatus = 0x%x\n", *TimerStatus);
   *Timer1Interval = 0x16E3600;   //printf("*Timer1Interval = 0x%x\n", *Timer1Interval);
   *Timer1Current = 0x16E3600;   //printf("*Timer1Current = 0x%x\n", *Timer1Current);

   *Timer1Control = 0x05;      //printf("*Timer1Control = 0x%x\n", *Timer1Control);

   for (;;)
   {
      while (*TimerStatus != 0x02);
      
      *TimerStatus = 0x02;
         
      if (*portGData == 0x6)   {*portGData = 0x200;}
         else      {*portGData = 0x000;}
   }

/////////////////////////////////////////////////////////////

}


In my code the timer-1 successfully works. Now I need to write a code to run when the timer-1 interrupt occurs.

I am new in interrupt code writing. I have once written an ISR for 8051. I am not sure how to write the code for Olinuxino A13 using the GCC compiler.

In other words, how do I link the timer-1 vector address, which is 0x005C, with the code I want to run.

say for example I want to Turn On and Off the on board LED (GPIO-2 Pin-9) when the timer-1 interrupt occurs.


\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
if (*portGData == 0x6)   {*portGData = 0x200;}
   else      {*portGData = 0x000;}
\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\


Please help.

JohnS