2 stroke ignition on atmega328

Hi all,
i successfully implemented the code posted by Nick Gammon of the electronic engine ignition.
I’m looking for commanding the output pin PB1 directly with the COM1A1 and COM1A0 config and without using the digitalwrite command.

this is the original code of Nick

// Timer with an ISR example
// Author: Nick Gammon
// Date: 13th January 2012
// Modified: 19 October 2014

#include <digitalWriteFast.h>

const byte FIRE_SENSOR = 2;  // note this is interrupt 0
const byte SPARKPLUG = 9;

volatile unsigned int sparkDelayTime = 500;   // microseconds
volatile unsigned int sparkOnTime = 2000;     // microseconds

// allow for time taken to enter ISR (determine empirically)
const unsigned int isrDelayFactor = 4;        // microseconds

// is spark currently on?
volatile boolean sparkOn;

void activateInterrupt0 ()
  {
  EICRA &= ~(bit(ISC00) | bit (ISC01));  // clear existing flags
  EICRA |=  bit (ISC01);    // set wanted flags (falling level interrupt)
  EIFR   =  bit (INTF0);    // clear flag for interrupt 0
  EIMSK |=  bit (INT0);     // enable it
  }  // end of activateInterrupt0

void deactivateInterrupt0 ()
  {
  EIMSK &= ~bit (INT0);     // disable it
  }  // end of deactivateInterrupt0

// interrupt for when time to turn spark on then off again
ISR (TIMER1_COMPA_vect)
  {

  // if currently on, turn off
  if (sparkOn)
    {
    digitalWriteFast (SPARKPLUG, LOW);  // spark off
    TCCR1B = 0;                         // stop timer
    TIMSK1 = 0;                         // cancel timer interrupt
    activateInterrupt0 ();              // re-instate interrupts for firing time
    }
  else
    // hold-off time must be up
    {
    digitalWriteFast (SPARKPLUG, HIGH); // spark on
    TCCR1B = 0;                         // stop timer
    TCNT1 = 0;                          // count back to zero
    TCCR1B = bit(WGM12) | bit(CS11);    // CTC, scale to clock / 8
    // time before timer fires (zero relative)
    // multiply by two because we are on a prescaler of 8
    OCR1A = (sparkOnTime * 2) - (isrDelayFactor * 2) - 1;     
    }
    
  sparkOn = !sparkOn;                  // toggle

  }  // end of TIMER1_COMPA_vect

// ISR for when to fire
ISR (INT0_vect)
  {
  sparkOn = false;                  // make sure flag off just in case

  // set up Timer 1
  TCCR1A = 0;                       // normal mode
  TCNT1 = 0;                        // count back to zero
  TCCR1B = bit(WGM12) | bit(CS11);  // CTC, scale to clock / 8
  // time before timer fires - zero relative
  // multiply by two because we are on a prescaler of 8
  OCR1A = (sparkDelayTime * 2) - (isrDelayFactor * 2) - 1; 
  TIMSK1 = bit (OCIE1A);            // interrupt on Compare A Match

  deactivateInterrupt0 ();          // no more interrupts yet
  } // end of ISR (INT0_vect)

void setup() 
  {
  TCCR1A = 0;  // normal mode
  TCCR1B = 0;  // stop timer
  TIMSK1 = 0;  // cancel timer interrupt

  pinMode (SPARKPLUG, OUTPUT);
  pinMode (FIRE_SENSOR, INPUT_PULLUP);
  
  activateInterrupt0 ();
  }  // end of setup

void loop() 
  { 
  // read sensors, compute time to fire spark
  
  if (false)  // if we need to change the time, insert condition here ...
    {
    noInterrupts ();        // atomic change of the time amount
    sparkDelayTime = 500;   // delay before spark in microseconds
    sparkOnTime = 2000;     // spark on time in microseconds
    interrupts ();
    }
  }  // end of loop

I tried differend ways but with no complete success and i don’t want to post my code because i would like to understand your solution and because i don’t want to waste time as i did in other forums where i gave ultra-explained details of my code and i haven’t got any solution.

Thanks
:slight_smile:

I don't think there is much substitute for learning how, in this case, timer1 works, and looking at the data sheet for the ATMEGA328P. The pin you want to control, PB1, is referred to in the Timer1 documentation as OC1A. The relevant control register is TCCR1A.

Hi, i know how the timer works, i'm not a newbie; but setting the COM1Ax registers gave me strange results.

I just wanna let the timer controls the oc1a pin.

OK. Here is an example (untested) which I found / hacked. If you want any specific help, you’ll have to post your code:

You may still have to set OC1A as an output - pinMode(9, OUTPUT)

// Arduino timer CTC toggle pin example
// www.engblaze.com
 
 
// toggle OC1A on compare/match 
 
void setup()
{
    // initialize Timer1
    cli();          // disable global interrupts
    TCCR1A = 0;     // set entire TCCR1A register to 0
    TCCR1B = 0;     // same for TCCR1B
 
    // set compare match register to desired timer count:
    OCR1A = 15624;

    // turn on CTC mode:
    TCCR1B |= (1 << WGM12);

    // Toggle OC1A on Compare Match
    TCCR1A |= (1 << COM1A0);


    // Set CS10 and CS12 bits for 1024 prescaler:
    TCCR1B |= (1 << CS10);
    TCCR1B |= (1 << CS12);

    // enable global interrupts:
    sei();
}
 
void loop()
{
    
}

Where was the original thread? The digitalWriteFast function is very fast - only a couple of machine cycles.

i gave ultra-explained details of my code and i haven't got any solution.

What problem are you trying to solve exactly?

Hi, i want the control of the pin 9 (PB1) is done directly by the timer1 and not using digitalWrite or something like that.

Thanks

Hi, i want the control of the pin 9 (PB1) is done directly by the timer1 and not using digitalWrite or something like that.

Permission granted. Proceed.

Was there something you needed help with?