Square Wave manipulation

Been around arduino for a while and made some handy "state" controls for various things... so not quite new, but not familiar with all the possibilities and limits.

My current "problem": I'm involved in a racecar. The ignition is controlled by a "high tech" ignition controller anno 1985 :roll_eyes:. Due the racecar competes in a classic class it it not permitted OR wanted to change the original ignition controller. To change the timing, the engine have to be taken out of the car and a couple of hours later you are running again. The ignition controller uses a hall-sensor mounted on the crankshaft. The wheel have 4 tooth's giving a 30% duty-cycle signal.

My wish: to be able to move the trigger-point back and forth to change the ignition advance. I my dreams by using 2 pots, one for rough and one for fine tuning the signal.

I would appreciate would comment on my following thoughts:

Max rpm is 10500, and I want a signal that is precise within max 0.5 degree. Is that possible with the arduino? I have no intention in learning assembler for this project.

The math for this(?): 10500 rpm/60 secs = 175 rev/sec 1 sec / 175 rev / 360 degrees / 2 (to have a ½ degree) = 0.0000079 sec. to calculate, count time and set the output pin on the arduino.

Next when the micros resets, I can't have it to fire at the wrong time, is it possible to make it skip the one output when that happens?

Finally, did I miss something obvious, that is much easier or that makes this a bad idea?

Thanks in advance, Jesper

0.0000079 seconds = 0.0079 milliseconds = 7.9 microseconds. The arduino executes 16 instruction cycles per microsecond so that's 126 clock cycles for each 1/2 degree of timing at max RPM. The Arduino is capable of generating pulses to that degree of accuracy. It's just a small matter of programming. :)

Max rpm is 10500, and I want a signal that is precise within max 0.5 degree. Is that possible with the arduino? I have no intention in learning assembler for this project.

The math for this(?):
10500 rpm/60 secs = 175 rev/sec
1 sec / 175 rev / 360 degrees / 2 (to have a ½ degree) = 0.0000079 sec. to calculate, count time and set the output pin on the arduino.

That’s 8us approx, which should be achievable. Using interrupts would give you pretty good resolution (1us or so?), but just polling an input ought to be good enough (there will be some jitter from the timer0 interrupts, could be an issue).

You need to keep recalculating the delay as it is a function of the current RPM - there should be enough time between pulses as you have over 5ms.

Next when the micros resets, I can’t have it to fire at the wrong time, is it possible to make it skip the one output when that happens?

So long as you use the correct test roll-over is invisible - you do something like:

volatile long trigger_timepoint ;
volatile long last_timepoint ;
volatile long current_period ;

void loop ()
{
  while (micros() - trigger_timepoint < 0)
  {} // wait till trigger time

  output_pulse () ;

  while (micros () - trigger_timepoint >= 0)
  {}  // wait till trigger changes
}

void  int_handler ()
{
  this_timepoint = micros () ;
  current_period = this_timepoint - last_timepoint ;
  // current_angle is fixed-point 16.16 representation of the fraction of whole-revolution.
  trigger_timepoint = this_timepoint + (current_angle * current_period) >> 16 ;
  last_timepoint = this_timepoint ;
}

The important point is to subtract one time from another and then look at the sign, don’t directly compare them.

I’ve given a suggestion as to how an interrupt driven variable delay could work - attach the int_handler to the relevant pin, and the main loop polls for changes in the trigger time, waits for that time and sends a pulse.

In practical terms, your controller can only delay the timing, it can't advance it. Or, put another way, if you need to advance the timing then the only way to achieve it is by timing it from the preceding ignition event based on your extrapolated RPM. This means that if you need to advance the ignition you're going to be vulnerable to crank speed variation, especially at low speed and when starting. You might want to have a 'direct' mode when the speed is below some threshold, where the output timing exactly matches the input timing. (Unless there are any tricks you want to play with the timing to make starting easier.)

Your other option is to advance the base (mechanical) timing and then retard it electronically so that you can achieve advance and retard overall. However, if you're using a dizzy based ignition you need to ensure that the total range of possible timing always stays within the fixed physical timing range of the rotor arm, otherwise you risk misfiring and cross firing problems.