Arduino Mega 2560 Timer/counter problem

Hi, friends. i am working on arduino mega.

i want to measure the count of 16 bit timer. following is steps.

  1. detects rising edge on ICP pin of arduino i am using Pin 47 of mega.
  2. Timer will start by detecting rising edge. it will counting till falling edge.
    3)as soon as pulse edge fall timer stop counting and, immediately it will store data into inside memory and then upon request it can display via serial or LCD display.

at present i am generating a single pulse from UNO and its width is varying from 5uS to 100uS. this pulse i am planning to give ICP Pin of MEGA.

i need help in coding to get such function.

kindly help, how do i move.
Thanks in advance.

I am using a similar routine to capture pulses for an rc reciever pulse ranges from 1000 to 2000 microseconds
this will capture for 1 to 65535 microseconds
PIND is for pins 0-7 on a UNO
you will have to work out how to use MEGA pins and attach an interrupt to them
the code is a start for timing the rise and fall time.

uint16_t Value ; // <<< Stores your time after pulse

void PinTimer(uint16_t cTime, uint8_t Pins , uint8_t Bit) {
  static uint16_t edgeTime;
  static uint8_t PCintLast;
 uint8_t Changed = Pins ^ PCintLast;         // doing a ^ between the current interruption and the last one indicates wich pin changed
  if (Changed  >> Bit & 1) {                         // See if the pin has changed
    if ((Pins  >> Bit & 1)) edgeTime = cTime; //Pulse went HIGH store the start time
    else {                                    // Pulse Went low calculate the duration
      uint16_t dTime = cTime - edgeTime;      // Calculate the change in time
      Value = dTime;                          // Lets Store any duration up to 65535 microseconds
    }
  }
  PCintLast = Pins;                           // we memorize the current state of all PINs in group
}


ISR(PCINT2_vect) { //this ISR pins 0-7
  static uint8_t PCintLast;
   uint16_t cTime = micros();        // micros() return a uint32_t, but it is not usefull to keep the whole bits => we keep only 16 bits
  sei();                             // re enable other interrupts at this point, the rest of this interrupt is not so time critical and can be interrupted safely
  PinTimer(cTime, PIND);             // Calculate Data
 }


// works for uno to attach an interrupt 
void RC::pciSetup(uint8_t pin, uint8_t InputType){
  pinMode(pin, InputType);// enable interrupt for pin...
  *digitalPinToPCMSK(pin) |= bit (digitalPinToPCMSKbit(pin));  // enable pin
  PCIFR  |= bit (digitalPinToPCICRbit(pin)); // clear any outstanding interrupt
  PCICR  |= bit (digitalPinToPCICRbit(pin)); // enable interrupt for the group
}

Thanks zhomeslice.
one thing i have question is that your pulse duration is about 1milli Sec to 2 milliSec. where in my case it is 5 microseconds to 100 microseconds.
Things will work better with external interrupt pin, without setting up timer in your case. but it wont work in my case because here its a too fast timing. short pulse width.

Thanks a lot…

@EJLED capturing 5 microseconds with your arduino is going to be really tough to get it to work if you don't code very close to the hardware

the micros() function has a resolution of four microseconds (i.e. the value returned is always a multiple of four - so your accuracy is not enough for what you want to achieve

Your arduino runs at 16MHz only so in 5 microseconds you can only execute 80 clock ticks.

I would wire an IRQ to detect the rising edge and in the ISR I see two options:

1/ Use a hardware timer --> Timer1 is a 16bit timer and with a Prescale of 1 you can achieve a 0.0625 uS accuracy for a max duration of 8.192 mS. You could have a look at TimerOne::start and stop in the Timer1 library (TimerOne.cpp) to get an idea on how to use the timer.

2/ You have enough cycle to manually code in assembly language - push the used registers and save CPU flags to stack beforehand - ~10 cycles - increments a 16 bit counter (using registers r24 and r25) - ~10 cycles - check your pin for falling edge and loop - ~10 cycles (read the port, mask for right bit, compare and loop if still HIGH)

As you know exactly the number of loop you executed with the counter and the time it takes for one loop to execute then you can deduct the exact number of microseconds and store that into a global variable

You fully control timing and what's going on but accuracy is probably not as good as with the timer1 though

Thank you J-M-L, do you have any sample code.

can u suggest other core except avr? i choose avr because its faster than 8051 and PIC.

i worked on 8051 and i measure 1 microsend pulse using assembly code.at 12Mhz clock frequesncy.

but it was not useful as it has no more i/o ports.

anyway i will try to work on same line, meanwhile if u have any code where i can test this. iwill be highly thankful to you.

Thanks a lot.

I'm in a train right now so don't have access to former projects - have a look at this example

the point the poster makes about trusting the Compiler is good - that's an option you have. just look at what is getting generated and calculate timing from there

From a hardware perspective, if you need to go faster, you could consider the new Genuine ZERO with a 32-bit ARM Cortex M0+ core running at 48 MHz. it has 20 I/O pins - not as many as the Mega but that's already pretty good.

Hi, Thanks J-M-L.

i will go through the link and try to implement on basis of the same.

i have arduino DUE too, its a cortex M3 , running on approx 80 Mhz. you might be knowing it.

then how do i do with that too.

my e-mail address is : ej.leds116@gmail.com if u find diffculties here you can send mail too.

Thanks a lot for great help.

You could bridge two ICP pins and use one input capture to read the rising edge, and the other to read the falling edge.

Thanks aarg, can u give me sample code for the same. i do not know how to setup timer/counter in mega.

it may work , we have to try.

thnaks

EJLED: Thanks aarg, can u give me sample code for the same. i do not know how to setup timer/counter in mega.

it may work , we have to try.

thnaks

What is your previous experience in coding for microprocessors?

Aarg, i did coding for 8051 architecture, i am new to avr. i have some blured concepts not clear visible idea for implimentation.

i do not know, thats why i am here. otherwise what is need and use of this forum.

Thanks

Okay, well what I would do is start reading the datasheet for the processor. Have you done that?

It's just that there won't be a readymade solution for your problem, because it's relatively specialized.

Aarg i know its a specialized. i wont get ready made solution i know.

i have read datasheet timers and counter but i am not able to understood completely. i have also seen many videos. now thing is only i have to start from the scratch. i just need guideline and some kind of code format. if anyone has kindly support.

Thanks.

http://www.gammon.com.au/interrupts

See also http://www.gammon.com.au/timers which has some examples of using the input capture interrupt. The key point is that to capture a pulse length is that you need to change the edge select with the initial trigger.

Using the ICP pin for input will make your code more complex with a possibly small performance increase over external or pin change interrupts. Nick Gammon describes it

Since the hardware captures the timer value in a separate register, this eliminates the delay caused by entering the interrupt routine (itself around 2 µs).

Using a 16MHz processor to measure in the 5 micro second range using interrupts is pushing the performance.