This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

LPC1768 Timer Interupt

Hello,

Please help confirm if my logic is right regarding timer interupt using NVIC based on the below code.
1) I can only receive or display on LCD 1 value each 3124 counts and the rest of idstring[94] values are blank.
2) Do ADC clock and Timer need to synch?

**Current result from the LCD shows as follow:
1) sometime it displays couple of values at a time (ie.idstring[1]=1, idstring[2]=23, etc.) and hung. If this happened, I need to reset phically.
2) sometime it shows couple of values at a time (ie.idstring[1]=1, idstring[2]=23, etc.) and passed and went back to main()loop.
3) the speed of the LCD display depends on the LPC_TIM0->MR0. If I changed this value higher than 3124, the LCD speeds faster. Why?

#include "lpc17xx.h"
#include "LCD.h"
int idstring[96];                 // data stored here
int j=0;

int main (void){
        int i;

        LCD_Hardware_Initial();
        LCD_initial();
        Signal_Detect_Initial();
        Timer_Hardware_Initial();
        ADC_Hardware_Initial();

  while (1){
   if ((LPC_GPIO0->FIOPIN & (1<<24))==0){     //signal input trigger
     Signal_Detect();
     for (i=1; i<96;i++){                     //display value on LCD
        LCD_send_command(0x01);                 //Clear screen
        LCD_display_int(i);
        LCD_display_string(": ");
        LCD_display_int(idstring[i]);
        delay_mS(50);
     }
   }

/******************subroutines******************************/
void Signal_Detect(void){
        NVIC_EnableIRQ(TIMER0_IRQn);
        LPC_TIM0->TCR = 1;         // Start timer: (1<<0) = bit 0 selected

}

void Timer_Hardware_Initial(void){
        LPC_SC->PCONP         |= (1<<1);       // Enable power to Timer/ Counter 0
        LPC_SC->PCLKSEL0 |= (1<<2);            // Select peripheral clock for Timer/ Counter 0
        LPC_TIM0->TCR          = 0x02;               // reset timer
        LPC_TIM0->PR           = 0x00;               // set prescaler to zero
        LPC_TIM0->MR0          = 3124;            // 1/(8000Hz) = 125 uS = 3125-1 counts @ 40nS/tick
        LPC_TIM0->MCR          = 3;          // Interupt and Reset on MR0: (1<<0) | (1<<1)
}

void TIMER0_IRQHandler (void){
        int val;

        LPC_ADC->ADCR |=  (1<<24);                             // start conversion
         while (!(LPC_ADC->ADGDR & (1UL<<31)));            // Wait for conversion end
         val = ((LPC_ADC->ADGDR >> 4) & 0xFFF);            // read converted value
         LPC_ADC->ADCR &= ~(7<<24);                                // stop conversion

        idstring[j]=val;
         j++;

        LPC_TIM0 ->IR =1;
}

void ADC_Hardware_Initial(void){
  LPC_PINCON->PINSEL1 &= ~(1UL<<14);                       // Reset P0.23 = GPIO
  LPC_PINCON->PINSEL1 |=  (1UL<<14);                   // Config P0.23 is AD0.0
  LPC_SC->PCONP       |=  (1UL<<12);                   // Enable power to ADC block
  LPC_ADC->ADCR        =  (1UL<< 0) |                  // select AD0.0 pin
                          (1UL<< 8) |                  // ADC clock is 18MHz/2
                          (1UL<<21);                   // enable ADC
}


Thanks in advance

  • Your timer tick has a big issue - it continues to read 8000 samples/second. But your array only have room for 96 entries.

    After 12 ms you run out of array space - where do you think your interrupt will write data then?

    Next thing - you like to have a global variable named "j"? Is it even possible to find a more non-descriptive name of a variable?

    LPC_TIM0->MR0          = 3124;            // 1/(8000Hz) = 125 uS = 3125-1 counts @ 40nS/tick
    


    Why did you manually compute the value 3124? 40ns (note small "s" for second - large "S" for Siemens) means 25 MHz peripherial clock. Why not write something like:

    enum {
        PCLK_TIMER0 = 25000000,  // Supply 25 MHz peripherial clock to timer 0.
        TIMER0_FREQ = 8000,      // Want 8 kHz to start ADC conversion.
    };
    ...
    LPC_TIM0->MR0 = (PCLK_TIMER0/TIMER0_FREQ)-1;
    

    Yes - more text. But wouldn't it be more readable? And easier to modify the code in case you want to change PCLK or the sampling rate for the ADC?

    Another thing - why not let the timer interrupt start the conversion and then use an ADC interrupt when conversion is done? Then you don't lock up the processor inside an interrupt. Interrupts should always try to be as fast as possible. Especially if you don't allow nested interrupts.

  • Hi Per,

    Thank you for your valuable suggestion about

     enum{}..
    

    I was monkey sees monkey does from on the sample code.

    Still fuzzy a little about timer interupt:
    Does the interupt interupt continuely through the program? In this case, it interupts each 125us per sample forever?
    How could I stop an interupt at certain time? Let's say a signal transfers data in 3 seconds.

    Thanks in advance.

  • You can disable the interrupt when you don't more interrupts.

    But note that you talk about measuring for 3 seconds. That is 3*8000 = 24000 samples. Your array is 96 elements long.

    You insert at 8kHz, i.e. every 125us.
    You consume at 20Hz, every 50ms.

    Either you need a longer array, or start to eat at a higher pace, or slow down the data collection when the consumer gets too far behind.