How to slow down bytesend

Hi,

I am looking for interrupt or serial port experts. I am on an Arduino UNO board. I want to interface it with a ov7670+FIFO. I dont want to dump the data as fast as possible via serial port which many have done. I wanted to slowly take one byte at a time and send it via a slower 115200 bps link instead of blitzing the serial port at 1 or 2 Mbps.

I have hooked up a 1 Mhz clock to my INT0. I have also setup a Timer1 which does 1 Khz.

The INT0 clock input is the same as the clock which goes to my ov7670+FIFO module. This produces a 8 bit data byte on the rising edge of this clock at 1 Mhz.

What I thought will work is this that I will increment a counter in the hardware interrupt INT1(At 1 Mhz). Also I will increment another counter at 1 Khz using the timer interrupt.

On INT0 I have a reset which resets the counter to 0. This is my VSYNC from the camera. This resets everytime a new frame is finished.

My code looks like

volatile unsigned char sendByte ;

volatile unsigned long serialByteCounter;
volatile long pixelByteCounter = -1;


void clockSetup(void){

  ASSR &= ~(_BV(EXCLK) | _BV(AS2));
 /* Setup the 1MHz PWM clock 
  * This will be on pin 11*/
  DDRB|=(1<<3);//pin 11 output
  TCCR2A=(1<<COM2A0)|(1<<WGM21)|(1<<WGM20);
  TCCR2B=(1<<WGM22)|(1<<CS20);
  OCR2A=7;//(F_CPU)/(2*(X+1))// Running RCLK at 1 Mhz(min)

  //set timer0 interrupt at 2kHz
  TCCR0A = 0;// set entire TCCR2A register to 0
  TCCR0B = 0;// same for TCCR2B
  TCNT0  = 0;//initialize counter value to 0
  // set compare match register for 2khz increments
  OCR0A = 124;// = (16*10^6) / (2000*64) - 1 (must be <256)
  // turn on CTC mode
  TCCR0A |= (1 << WGM01);
  // Set CS01 and CS00 bits for 64 prescaler
  TCCR0B |= (1 << CS01) | (1 << CS00);   
  // enable timer compare interrupt
  TIMSK0 |= (1 << OCIE0A);

}




ISR(TIMER0_COMPA_vect){//timer0 interrupt 2kHz toggles pin 8
//generates pulse wave of frequency 2kHz/2 = 1kHz (takes two cycles for full wave- toggle high then toggle low)

 if(serialByteCounter <= 307200){
   serialByteCounter++;
 }
 else{
  serialByteCounter=0;
 }
}


void resetPixelByte(){
  pixelByteCounter = 0;
}

void increasePixelByte(){
  if(pixelByteCounter != -1){
    pixelByteCounter++;
    if(pixelByteCounter == serialByteCounter){
      sendByte++;
    }
  }

  pixelByteCounter = 0;
  serialByteCounter = 0;

  cli();
  attachInterrupt(0,resetPixelByte,RISING);
  attachInterrupt(1,increasePixelByte,RISING);
  sei();
  
}

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  clockSetup();
  pinMode(2, INPUT);
  pinMode(3, INPUT);
}


void loop() {
  // put your main code here, to run repeatedly:
  Serial.println(sendByte,HEX);
}

And it dosent work. Can you please help me ?

This question is more in general if the approach will work.

So in summary: The approach is that a faster hardware counter will be matched with a slower timer counter. When the counters match, a new byte is available to be processed slowly. I am using the camera to take still images, so repeating frames over a long time is not a problem.

Hope I am able to explain my issue sufficiently.

I am looking for interrupt or serial port experts. I am on an Arduino UNO board. I want to interface it with a ov7670+FIFO. I dont want to dump the data as fast as possible via serial port which many have done. I wanted to slowly take one byte at a time and send it via a slower 115200 bps link instead of blitzing the serial port at 1 or 2 Mbps.

That sounds like complete nonsense.

This question is more in general if the approach will work.

No, it won't work. The arduino cannot do anything useful at 1 Mhz.

There is a thread, dozens of pages long, concerning interfacing with this camera device, with contributions from a couple of guys who have spent years working on them.

I suggest that you read it.

Apologies if the framing didnt make sense. If have a better framing and if you think my question is a valid one, can you please edit it to make sense better ?

I have read that thread on ov7670 (many times over). I have not included the code related to ov7670 in this post as the purpose is not to ask questions about interfacing the camera. I have successfully followed those posts and wired up the camera.

The problem I am encountering is the datarate. The slowest clock speed the module of the camera with FIFO will accept is 1 Mhz (minimum refresh rate for the FIFO buffer) and it roughly has a byte of image data available at that rate or 8 mega bytes per second.

I am trying to somehow trick the controller into grabbing a few bytes from each frame at a slower frequency. So something like

Frame 1 : 307k bytes: Get first 30 bytes Frame 2: 307k bytes: Get next 30 bytes ... Frame N: 307k bytes: Get last 30 bytes

Given that in my case the camera is focused on a static object, N frames will essentially produce the same image. Using 30 bytes from each frame, I want to programatically split the image into smaller chunks of data in each cycle and discarding the rest, hence reducing the data rate I want to transmit.

I have been thinking - including moving to mega or another micro controller. But I am not yet ready to give up ...

Looks like interrupt is not the way. I reread the datasheet for 328P and it has 8 clock cycles of overhead. That leaves me only an additional 8 clock cycles for the rest of the CPU at 1 Mhz .. and maybe I can use 1 or 2 of that.

So say if I do away with interrupts, I save 8 clock cycles. All I need to do is increment a counter to count upto 307k. What is the smartest way to poll a pin at 1 Mhz and maintain a counter to count upto 300k odd at the rising edge of this pin ? Any ideas ?

You cannot copy 30 bytes in one or 2 clock cycles.

In my opinion, attempting any kind of this photography, whether moving pictures or still pictures, on the arduino, is a waste of your time. Get a raspberry pi.

Thanks for your attention to my post.

I want to limit the cost - hence moving up the capability ladder is not my choice.

30 byte was an example - I could be 1 byte as well.

If you can - can you please have a look at my question in the last sentence and if you have any ideas - share it ?

For your convenience I repeat it :

" What is the best way to poll a pin for rising edge at 1 Mhz frequency to maintain a counter that can count upto a higher number than int allows"

void increasePixelByte(){
...
  cli();
  attachInterrupt(0,resetPixelByte,RISING);
  attachInterrupt(1,increasePixelByte,RISING);
  sei();
 }

Attaching an interrupt, inside the ISR that the interrupt is going to call, seems to be an incredibly bad idea. In fact that is the only place the interrupt is attached, so it will never be called.

abbanerjee: For your convenience I repeat it :

" What is the best way to poll a pin for rising edge at 1 Mhz frequency to maintain a counter that can count upto a higher number than int allows"

You could use a hardware timer to count things. As for the interrupt, no. See: http://www.gammon.com.au/interrupts

An ISR takes around 5 µS to run. You want it to run at 1 MHz, which is every 1 µS. Can't be done on this processor.

abbanerjee: I am looking for interrupt or serial port experts. I am on an Arduino UNO board. I want to interface it with a ov7670+FIFO. I dont want to dump the data as fast as possible via serial port which many have done. I wanted to slowly take one byte at a time and send it via a slower 115200 bps link

Have you a link to the datasheet for the ov7670 ?

If I understand you, you want to read the device much more slowly than usual - without the datasheet how can we know if that is possible ?

An Uno should be able to communicate with a PC at 1,000,000 baud and a Leonardo can work even faster. Why do you need to use 115200 baud ?

...R

Hi,

Thanks for the answers @Nick Gammon. Your website is a great resource that I did not come across before. Great work !

I noticed now that I made a mistake in the code when I was putting it on the forum. I am not actually setting the attachInterrupts within the ISR. Its a copy paste error when removing other unrelated code.

I will think a bit more but I am certain now that interrupts wont work to poll a pin.