Arduino Forum

Using Arduino => Project Guidance => Topic started by: tombauer on Sep 23, 2016, 04:07 am

Title: CDI tester project
Post by: tombauer on Sep 23, 2016, 04:07 am
Hi all, I have a project I would like some help with. The code I have so far is attached and works great. It is on a pro mini 16Mhz clone. I repair CDI modules for mowers and other small engines and for a couple years I have had a 555 timer that I have used for testing. It is lacking in several ways. Now I have started this project that will have:

1) a LCD to display rpm from 500 to 3000
2) generate a pulse at intervals from 120Ms to 20Ms to trigger the CDI (one pulse / revolution)
3) generate pulses at 50Hz to 300Hz to simulate the charging coils. Here may be the tricky
part, as there are 6 pulses per revolution, but skip every 6th pulse and have that time interval
align with the above triggering pulse. (you don't want a triggering pulse at the same time the
charging coil has output because the part that the charging coil charges is shorted at that
moment)
4) input the trigger pulse and also input a signal from the coil and display the time interval as ° timing, as at low rpm there is a delay varying from 100us to 0us approx. The delay at low rpm is taken away at higher rpm to produce advance.

What I have so far is the LCD which works well and displays the rpm. Also for now I had it display the Ms between pulses just to be sure it was changing correctly. The pulse out I made 1Ms and used 2 transistors to switch 12 vdc to the input of the CDI, works well. I added the pin 7 output as the future high pulse rate simulating charging coils. I will feed this also with 2 transistors through a transformer to obtain approx 200 vac.
Thanks, hope it is not to ambitious!
(edited errors)

Code: [Select]


//Pulse Generator Arduino Code  
#include "U8glib.h"
U8GLIB_ST7920_128X64_1X u8g(13, 11, 10);  // SPI Com: SCK = en = 15, MOSI = rw = 16, CS = di = 17
int pot1 = A5;          // select the input pin for the pot
int potValue = 0;       // variable to store the value coming from the sensor
int pulseValue = 0;    // 2 variables from one pot
int delayValue = 0;
int outputPin = 8;      // select the pin for the output for trigger pulse
int chargePin = 7;      // select the pin for the output for charge pulses

void draw() {
  // graphic commands to redraw the complete screen should be placed here  
  
  u8g.setPrintPos(0, 15);        // call procedure from base class, http://arduino.cc/en/Serial/Print
  u8g.print("RPM =");
  u8g.setPrintPos(50, 15);
  u8g.print(potValue);
  u8g.setPrintPos(8, 30);
  u8g.print("Ms =");
  u8g.setPrintPos(50, 30);
  u8g.print(pulseValue);
  u8g.setPrintPos(0, 45);
  u8g.print("Advance =");
  u8g.setPrintPos(80, 45);
  u8g.print("10");                               // for use in future code

}

void setup() {
  Serial.begin(115200);                       // serial com speed for display
  // flip screen, if required
  // u8g.setRot180();  
 pinMode(outputPin, OUTPUT);            // declare the outputPin as an OUTPUT
 pinMode(chargePin, OUTPUT);            // declare the chargePin as an OUTPUT
 u8g.firstPage();
 u8g.setFont(u8g_font_unifont);
 delay (2000);

 //Timer1 set up 2ms pulse every 50 ms
  TCCR1A = 0;
  TCCR1B = (1 << WGM12);//CTC mode to OCR1A
  OCR1A = 12500; //50 ms to top value
  TIMSK1 |= (1 << OCIE1A);//interrupt enable compareA
  TIMSK1 |= (1 << OCIE1B);//interrupt enable compareB
  OCR1B = 250; //1 ms pulse width
  TCCR1B |= (1 << CS11) |(1<<CS10); //prescaler 64  4us/tick
 
}
  
void loop() {
  // picture loop
  u8g.firstPage();
  do {
    draw();
} while( u8g.nextPage() );

  potValue = analogRead(pot1);                                          // read the value from the pot for rpm
  pulseValue = analogRead(pot1);                                        // read the value from the pot for pulse
  delayValue = analogRead(pot1);                                        // read the value from the pot for pulse delay
  potValue = map(potValue, 0, 1023, 500, 3000);                         // map pot for 500 - 3000 for rpm display
  pulseValue = map(pulseValue, 0, 1023, 120, 20);                       // map pot for pulse delay 20 to 120 Ms
  delayValue = map(delayValue, 0, 1023, 30000, 5000);                   // map pot for actual pulse delay
  delay (10);
}

ISR(TIMER1_COMPA_vect) {
  OCR1A = (delayValue);                                                 // value to set delay between pulses
  digitalWrite(outputPin,HIGH); //turn on pin 8
  digitalWrite(chargePin,HIGH); //turn on pin 7
}

ISR(TIMER1_COMPB_vect) {
 digitalWrite(outputPin,LOW); //turn off pin 8
 digitalWrite(chargePin,LOW); //turn off pin 7
 
}

Title: Re: CDI tester project
Post by: cattledog on Sep 23, 2016, 06:01 am
Tom--

Let me see if I have this correct. I understand 1,2, and 3 as follows.

You have a 1 ms CDI trigger pulse at 0 degrees. The period between trigger pulses is 20 to 120 ms. In the CDI system is this the trigger for the discharge of the capacitor to the coil?

Then, within that period you then want to output a ? ms pulse at 60°, another at 120°, another at 180°, another at 240° and one at 300°. That's five pulses spaced 360/6 with a gap at 0.  This part seems straight forward. In the CDI system, are these pulses charging the capacitor?
 
I'm not certain about point 4

Quote
4) input the trigger pulse and also input a signal from the coil and display the time interval as ° timing, as at low rpm there is a delay varying from 100us to 0us approx. The delay at low rpm is taken away at higher rpm to produce advance.
The trigger fires. The capacitor discharges into the coil. Please explain more about the "signal from the coil". If you can get this into a 5v signal for input into the Arduino it should be possible to calculate the time from the trigger pulse. I'm not sure if this is better done with a pin change (or external interrupt) or a timer input capture.

For development, you can certainly simulate this pulse with one generated by the Arduino or from possibly a second one. Do you have a second pro mini to possibly use as a coil output signal generator?

I'm not sure if your project will require the millis() and micros() timer. You may need three timers --one to generate the trigger, one to generate the 5 pulses, and one to time the ignition delay. It's possible that this project could benefit from additional hardware timers. Are you bound to the pro mini, or is there the possibility of using a Mega with the additional timers.

I would recommend developing this system without the TFT display. Use a 4x20 lcd or serial to a laptop. Your program will be complicated enough without having to work around the blocking characteristics of the display draw while you are working through other issues.
Title: Re: CDI tester project
Post by: 6v6gt on Sep 23, 2016, 08:24 am
I tried get the OP's description onto a time line to make it easier to visualise. I hope I've understood it correctly.

(http://forum.arduino.cc/index.php?action=dlattach;topic=425551.0;attach=181346)
Title: Re: CDI tester project
Post by: allanhurst on Sep 23, 2016, 08:48 am
I take it you mean 18,000rpm, not 18,000 Hz - that would be a pretty quick engine!

regards

Allan.

ps I've looked at these gadgets - the ones I've seen are potted in epoxy or similar, and I've always thought them unrepairable. How do you get them apart?
Title: Re: CDI tester project
Post by: tombauer on Sep 23, 2016, 04:42 pm
Tom--

Let me see if I have this correct. I understand 1,2, and 3 as follows.

You have a 1 ms CDI trigger pulse at 0 degrees. The period between trigger pulses is 20 to 120 ms. In the CDI system is this the trigger for the discharge of the capacitor to the coil?
   >>>>Yes this simulates the pusle coil and tells the CDI to fire.

Then, within that period you then want to output a ? ms pulse at 60°, another at 120°, another at 180°, another at 240° and one at 300°. That's five pulses spaced 360/6 with a gap at 0.  This part seems straight forward. In the CDI system, are these pulses charging the capacitor?
  >>>>Yes that is the a/c from the charging coil under flywheel that outputs around 200vac
 
I'm not certain about point 4

The trigger fires. The capacitor discharges into the coil. Please explain more about the "signal from the coil". If you can get this into a 5v signal for input into the Arduino it should be possible to calculate the time from the trigger pulse. I'm not sure if this is better done with a pin change (or external interrupt) or a timer input capture.
  >>>>I can use a induction coil or a voltage divider to pick up a signal from the coil.

For development, you can certainly simulate this pulse with one generated by the Arduino or from possibly a second one. Do you have a second pro mini to possibly use as a coil output signal generator?

I'm not sure if your project will require the millis() and micros() timer. You may need three timers --one to generate the trigger, one to generate the 5 pulses, and one to time the ignition delay. It's possible that this project could benefit from additional hardware timers. Are you bound to the pro mini, or is there the possibility of using a Mega with the additional timers.
  >>>>No I can use any other board as needed, the generation of the 5 pulses for charging is just a luxury,
         I  can use a high impedance transformer like I have now.

I would recommend developing this system without the TFT display. Use a 4x20 lcd or serial to a laptop. Your program will be complicated enough without having to work around the blocking characteristics of the display draw while you are working through other issues.
Title: Re: CDI tester project
Post by: tombauer on Sep 23, 2016, 04:49 pm
I take it you mean 18,000rpm, not 18,000 Hz - that would be a pretty quick engine!

regards

Allan.

ps I've looked at these gadgets - the ones I've seen are potted in epoxy or similar, and I've always thought them unrepairable. How do you get them apart?
Ok, 6 charging coils with magnet turning at 3000 rpm would be 300Hz signal so output needs
to be 50 - 300Hz.

I find the cheaper ones are epoxy but MANY others are in something softer.
Title: Re: CDI tester project
Post by: 6v6gt on Sep 23, 2016, 04:55 pm
6 charging coils with magnet turning at 3000 rpm would be 18000Hz signal would it not? . . .
Exactly, if your minute is only only one second in duration.
Title: Re: CDI tester project
Post by: cattledog on Sep 23, 2016, 05:08 pm
Quote
the generation of the 5 pulses for charging is just a luxury,
If you use the five pulses, what duration should they be?

If you use only one pulse, what duration should it be, and how should it be timed to the trigger?

Quote
Top line would only have 1 pulse at the time where the second line does   
not.
The top line represents a system clock and the overall timing. There are no output pulses, but the other pulses are timed in relationship to the clock.
Title: Re: CDI tester project
Post by: tombauer on Sep 23, 2016, 05:34 pm
If you use the five pulses, what duration should they be?
  >>>These pulses would be fed to a small transformer so they can just be square wave.

If you use only one pulse, what duration should it be, and how should it be timed to the trigger?
  >>>.If I don't even have these pulses it is not that bad for a tester, I can just use a transformer off the line with isolation. Right now I have 2 12v to 120v transformers back to back so I also get my 12 vdc from them.

The top line represents a system clock and the overall timing. There are no output pulses, but the other pulses are timed in relationship to the clock.
  >>>>Ok, I did not understand, so it is correct.
Title: Re: CDI tester project
Post by: cattledog on Sep 23, 2016, 09:45 pm
Here is a some test code with the advance (coil pulse delay) measurement in microseconds patched into a serial version of your code.

I have simulated a delay pulse with a signal on pin 4 generated by a software timer which sends a pulse 5 milliseconds after the main trigger. From my testing, most of the timing error is due to the analogRead() going on. Putting the advance measurement on a timer input capture interrupt, instead of an external interrupt might be more accurate.

How accurate does the advance measurement need to be? What is the range of advance measurements?

Code: [Select]
//Pulse Generator Serial Output Arduino Code

int pot1 = A5;          // select the input pin for the pot
int potValue = 0;       // variable to store the value coming from the sensor
int pulseValue = 0;    // 2 variables from one pot
int delayValue = 0;
int outputPin = 8;      // select the pin for the output for trigger pulse
int chargePin = 7;      // select the pin for the output for charge pulses

volatile boolean trigger = false;
volatile unsigned long delayPeriod;
unsigned long copy_delayPeriod;
volatile unsigned long delayPeriodStart;


void setup() {
  Serial.begin(115200);                       // serial com speed for display
  pinMode(outputPin, OUTPUT);            // declare the outputPin as an OUTPUT
  pinMode(chargePin, OUTPUT);            // declare the chargePin as an OUTPUT
  delay (2000);

  pinMode(4, OUTPUT); //signal out for delay test

  //Timer1 set up 1ms pulse every 50 ms
  TCCR1A = 0;
  TCCR1B = (1 << WGM12);//CTC mode to OCR1A
  OCR1A = 12500; //50 ms to top value
  TIMSK1 |= (1 << OCIE1A);//interrupt enable compareA
  TIMSK1 |= (1 << OCIE1B);//interrupt enable compareB
  OCR1B = 250; //1 ms pulse width
  TCCR1B |= (1 << CS11) | (1 << CS10); //prescaler 64  4us/tick

  attachInterrupt(digitalPinToInterrupt(3), delayPeriodTiming, RISING);
}

void loop() {

  potValue = analogRead(pot1);                                          // read the value from the pot for rpm
  pulseValue = analogRead(pot1);                                        // read the value from the pot for pulse
  delayValue = analogRead(pot1);                                        // read the value from the pot for pulse delay
  potValue = map(potValue, 0, 1023, 500, 3000);                         // map pot for 500 - 3000 for rpm display
  pulseValue = map(pulseValue, 0, 1023, 120, 20);                       // map pot for pulse delay 20 to 120 Ms
  delayValue = map(delayValue, 0, 1023, 30000, 5000);

  //my test for trigger pulse delay response)
  if (trigger == true)
  {
    if (micros() - delayPeriodStart >= 5000) //5 ms delay
    {
      trigger = false;
      digitalWrite(4, HIGH);//simulate pulse
      digitalWrite(4, LOW);
      noInterrupts();
      copy_delayPeriod = delayPeriod;
      interrupts();

      Serial.print("RPM =");
      Serial.println(potValue);
      Serial.print("Ms =");
      Serial.println(pulseValue);
      Serial.print("AdvanceMicroseconds =");
      Serial.println(copy_delayPeriod);                               // for use in future code

    }
  }
}

ISR(TIMER1_COMPA_vect) {
  OCR1A = (delayValue);                                                 // value to set delay between pulses
  digitalWrite(outputPin, HIGH); //turn on pin 8
  digitalWrite(chargePin, HIGH); //turn on pin 7
}

ISR(TIMER1_COMPB_vect)
{
  digitalWrite(outputPin, LOW); //turn off pin 8
  digitalWrite(chargePin, LOW); //turn off pin 7
  delayPeriodStart = micros();//start looking for response
  trigger = true;
}

void delayPeriodTiming()
{
 delayPeriod = micros() - delayPeriodStart;
}

Title: Re: CDI tester project
Post by: tombauer on Sep 23, 2016, 10:35 pm
I am repairing just one such CDI right now and will get (hopefully) some measurements from it regarding pulse delay. I anticipate that 5 Ms delay will give 18° advance when it is taken away. I would think a range of 20° would be more than adequate. Also +/- .5° if obtainable would be fine, these are not race car engines!   
Title: Re: CDI tester project
Post by: tombauer on Sep 23, 2016, 11:26 pm
So far unable to measure and delay! I have one OEM CDI and a cheap Chinese one that should have delay, I am looking at the pulse and the primary of the ign coil with dual trace scope (Tektronix 585A) at any speed pulses are at same time!
Title: Re: CDI tester project
Post by: tombauer on Sep 24, 2016, 04:34 am
I loaded the above code and it compiled and loaded but apparently locks up, the small led flashes once and goes out, no response after that??
Title: Re: CDI tester project
Post by: cattledog on Sep 24, 2016, 05:44 am
Quote
I loaded the above code and it compiled and loaded but apparently locks up, the small led flashes once and goes out, no response after that??
I'm running it now on a Uno. Did you jumper pin 4 to pin 3? Did you set the Serial monitor to 115200 baud? I am also running a jumper from 3.3v to A5 for the analog read. Ms =56  RPM = 2110 delay = 5400 us.

Code: [Select]
RPM =2137
Ms =56
AdvanceMicroseconds =5052
RPM =2137
Ms =56
AdvanceMicroseconds =5052
RPM =2137
Ms =56
AdvanceMicroseconds =5060
RPM =2127
Ms =56
AdvanceMicroseconds =5232
RPM =2117
Ms =56
AdvanceMicroseconds =5224
RPM =2130
Ms =56
AdvanceMicroseconds =5504
Title: Re: CDI tester project
Post by: tombauer on Sep 24, 2016, 04:15 pm
I still have the 12864B display and it is a serial setup. I would like to understand "I would recommend developing this system without the TFT display. Use a 4x20 lcd or serial to a laptop. Your program will be complicated enough without having to work around the blocking characteristics of the display draw while you are working through other issues."
Yes 3 and 4 are jumped,
Thanks, Tom
Title: Re: CDI tester project
Post by: cattledog on Sep 24, 2016, 04:46 pm
In a previous thread it was apparent that there are blocking characteristics with how you are writing to that display. http://forum.arduino.cc/index.php?topic=424874.msg2927434#msg2927434 (http://forum.arduino.cc/index.php?topic=424874.msg2927434#msg2927434)

The CDI aspects of your program require critical timing. We already placed one aspect of your program on a hardware timer (the trigger pulse) to work around the display. In my opinion it is more important to get the core functionality of your program working first. If you need to use millis() timers (i.e. software timers instead of hardware) don't tie your hands. It may be possible to work around the display as now written, but I don't have the hardware to help you do that.

There are other possible displays to use, or the entire 12864B display program can be re-crafted to draw a tiny bit of the display image and then return to the program.
Title: Re: CDI tester project
Post by: tombauer on Sep 24, 2016, 05:38 pm
OK, I understand that now. Would a hd44780 lcd with i2c adapter be suitable? If so it displays enough to just be permanent. Or a 2004 with i2c?
Title: Re: CDI tester project
Post by: tombauer on Sep 24, 2016, 09:47 pm
I now have a serial monitor, silly me, it is built in. Will get a more suitable one soon. The pot I have for rpm, potValue, now does nothing and there is no output from pin 7 or 8. Values on monitor do not change, but ms jumps around a lot from low values to really high.
Title: Re: CDI tester project
Post by: tombauer on Sep 25, 2016, 05:23 pm
cattledog,
Success! I had a power supply problem and the board was not getting enough voltage. Now it all works, display on pc shows values and pot1 is consistent and linear. (before it was really flaky) Now to turn pulse delay into ° advance? I have 2 cdi that should have advance built in, they use ic MB4213 for delay but neither of them have any delay. Maybe they are bad and this is exactly why I need this tester!
Best, Tom
Title: Re: CDI tester project
Post by: cattledog on Sep 25, 2016, 08:14 pm
I'm glad that you are finding success with your project. In my testing I found that much of the variation in delay timing was coming from the continual analorRead dof the pots in loop. Because the changing of this pot is manual input I thought it would be OK to put the readings at one second intervals. There is far greater stability of the delay values. If the precision of the tester is not adequate with this modification, we can use a running average of several delay values to smooth it more.

I think that 360 * delay/puseValue *1000  should give you degrees of delay. I've calculated as an int, but you may want to use a float for fractional degrees.


Code: [Select]
//Pulse Generator Serial Output Arduino Code

int pot1 = A5;          // select the input pin for the pot
int potValue = 0;       // variable to store the value coming from the sensor
int pulseValue = 0;    // 2 variables from one pot
int delayValue = 0;
int outputPin = 8;      // select the pin for the output for trigger pulse
int chargePin = 7;      // select the pin for the output for charge pulses

volatile boolean trigger = false;
volatile unsigned long delayPeriod;
unsigned long copy_delayPeriod;
volatile unsigned long delayPeriodStart;
int delayDegrees;

unsigned long analogReadInterval = 1000;//read pots and map
unsigned long lastAnalogRead;

void setup() {
  Serial.begin(115200);                       // serial com speed for display
  pinMode(outputPin, OUTPUT);            // declare the outputPin as an OUTPUT
  pinMode(chargePin, OUTPUT);            // declare the chargePin as an OUTPUT
  delay (2000);

  pinMode(4, OUTPUT); //signal out for delay test

  //Timer1 set up 1ms pulse every 50 ms
  TCCR1A = 0;;
  TCCR1B = (1 << WGM12);//CTC mode to OCR1A
  OCR1A = 12500; //50 ms to top value
  TIMSK1 |= (1 << OCIE1A);//interrupt enable compareA
  TIMSK1 |= (1 << OCIE1B);//interrupt enable compareB
  OCR1B = 250; //1 ms pulse width
  TCCR1B |= (1 << CS11) | (1 << CS10); //prescaler 64  4us/tick

  attachInterrupt(digitalPinToInterrupt(3), delayPeriodTiming, RISING);
}

void loop() {

  if (millis() - lastAnalogRead >= analogReadInterval)
  {
    lastAnalogRead += analogReadInterval;
    potValue = analogRead(pot1);                                         
    pulseValue = analogRead(pot1);                                     
    delayValue = analogRead(pot1);
    potValue = map(potValue, 0, 1023, 500, 3000);                         
    pulseValue = map(pulseValue, 0, 1023, 120, 20);                       
    delayValue = map(delayValue, 0, 1023, 30000, 5000);
  }
  //my test for trigger pulse delay response)
  if (trigger == true)
  {
    if (micros() - delayPeriodStart >= 5000) //5 ms delay
    {
      trigger = false;
      digitalWrite(4, HIGH);//simulate pulse
      digitalWrite(4, LOW);
      noInterrupts();
      copy_delayPeriod = delayPeriod;
      interrupts();

      delayDegrees = 360*(copy_delayPeriod)/(pulseValue*1000UL);
     
      Serial.print("RPM =");
      Serial.println(potValue);
      Serial.print("Ms =");
      Serial.println(pulseValue);
      Serial.print("Delay Microseconds =");
      Serial.println(copy_delayPeriod);                               // for use in future code
      Serial.print("Delay Degrees = ");
      Serial.println(delayDegrees);

    }
  }
}

ISR(TIMER1_COMPA_vect) {
  OCR1A = (delayValue);                                                 // value to set delay between pulses
  digitalWrite(outputPin, HIGH); //turn on pin 8
  digitalWrite(chargePin, HIGH); //turn on pin 7
}

ISR(TIMER1_COMPB_vect)
{
  digitalWrite(outputPin, LOW); //turn off pin 8
  digitalWrite(chargePin, LOW); //turn off pin 7
  delayPeriodStart = micros();//start looking for response
  trigger = true;
}

void delayPeriodTiming()
{
  delayPeriod = micros() - delayPeriodStart;
}
Title: Re: CDI tester project
Post by: tombauer on Sep 25, 2016, 08:31 pm
Thanks, before I implement this I want to say that I made a voltage divider across the coil primary, tied pin 3 to ground through a 1k resistor and used 2 zeners back to back to pull any signal down to 5v. It shows a fairly consistent delay but then locks uo the FTDI TTL-232 There are surely better ways to get the secondary pulse but I am running out of time before I leave for a week.
Best, Tom
Title: Re: CDI tester project
Post by: cattledog on Sep 25, 2016, 08:48 pm
Can you please post the code you are using to read actual delays from the system, and a drawing of your wiring arrangement.
 
If the delay interrupts are triggering very frequently, it can lock up the Serial output, but this should not happen if the measurement is timed to the trigger and the input is not floating. Have you looked at the signal from the coil and see a clean edge?
Title: Re: CDI tester project
Post by: tombauer on Sep 25, 2016, 10:14 pm
I am using your code as last update. Scope shows clean 5v spike at pin 3.
With out the coil attached it does not lock and the display shows 'delayMicroseconds' as 5012 at 500 rpm and 5016 at 3000. It shows 'DegreesAdvance' as 15 at 500 rpm and 82 at 3000. This is the crude way I attached coil pulse to the board.
Title: Re: CDI tester project
Post by: cattledog on Sep 25, 2016, 10:52 pm
Quote
It shows 'DegreesAdvance' as 15 at 500 rpm and 82 at 3000.
It should report 90 at 3000 since 5000 us/20msx1000 = 90.

Quote
This is the crude way I attached coil pulse to the board.
Quote
Scope shows clean 5v spike at pin 3.
I don't know enough about hardware to evaluate the coil circuit. Are you getting a clean 5v pulse at pin three from the coil circuit as well as from the simulation test code? If you actually can get a clean pulse from the coil, then I think the code should work and not lock up.

Please post the code which is taking the actual pulse from the coil. I'm not clear on how you modified it.

Here's one possibility (untested)
 EDIT: I tested this with a second UNO set up to deliver a delayed response to the trigger. The code measured the delay as expected. There is the question of whether the CDI unit delays the coil pulse based on the leading or falling edge of the 1 ms trigger pulse. It may be a significant period for shorter delays.  The code is currently written to read the delay from the falling edge.

Code: [Select]
//Pulse Generator Serial Output Arduino Code

int pot1 = A5;          // select the input pin for the pot
int potValue = 0;       // variable to store the value coming from the sensor
int pulseValue = 0;    // 2 variables from one pot
int delayValue = 0;
int outputPin = 8;      // select the pin for the output for trigger pulse
int chargePin = 7;      // select the pin for the output for charge pulses

volatile boolean trigger = false;
volatile unsigned long delayPeriod;
unsigned long copy_delayPeriod;
volatile unsigned long delayPeriodStart;
int delayDegrees;

volatile boolean interruptFlag;

unsigned long analogReadInterval = 1000;//read pots and map
unsigned long lastAnalogRead;

void setup() {
  Serial.begin(115200);                       // serial com speed for display
  pinMode(outputPin, OUTPUT);            // declare the outputPin as an OUTPUT
  pinMode(chargePin, OUTPUT);            // declare the chargePin as an OUTPUT
  delay (2000);

  pinMode(4, OUTPUT); //signal out for delay test

  //Timer1 set up 1ms pulse every 50 ms
  TCCR1A = 0;;
  TCCR1B = (1 << WGM12);//CTC mode to OCR1A
  OCR1A = 12500; //50 ms to top value
  TIMSK1 |= (1 << OCIE1A);//interrupt enable compareA
  TIMSK1 |= (1 << OCIE1B);//interrupt enable compareB
  OCR1B = 250; //1 ms pulse width
  TCCR1B |= (1 << CS11) | (1 << CS10); //prescaler 64  4us/tick

  attachInterrupt(digitalPinToInterrupt(3), delayPeriodTiming, RISING);
}

void loop() {

  if (millis() - lastAnalogRead >= analogReadInterval)
  {
    lastAnalogRead += analogReadInterval;
    potValue = analogRead(pot1);                                         
    pulseValue = analogRead(pot1);                                     
    delayValue = analogRead(pot1);
    potValue = map(potValue, 0, 1023, 500, 3000);                         
    pulseValue = map(pulseValue, 0, 1023, 120, 20);                       
    delayValue = map(delayValue, 0, 1023, 30000, 5000);
  }
 
  if (trigger == true && interruptFlag == true )
  {
      trigger = false;
      interruptFlag = false;
      noInterrupts();
      copy_delayPeriod = delayPeriod;
      interrupts();

      delayDegrees = 360*(copy_delayPeriod)/(pulseValue*1000UL);
     
      Serial.print("RPM =");
      Serial.println(potValue);
      Serial.print("Ms =");
      Serial.println(pulseValue);
      Serial.print("Delay Microseconds =");
      Serial.println(copy_delayPeriod);                               // for use in future code
      Serial.print("Delay Degrees = ");
      Serial.println(delayDegrees);

    }
  }


ISR(TIMER1_COMPA_vect) {
  OCR1A = (delayValue);                                                 // value to set delay between pulses
  digitalWrite(outputPin, HIGH); //turn on pin 8
  digitalWrite(chargePin, HIGH); //turn on pin 7
}

ISR(TIMER1_COMPB_vect)
{
  digitalWrite(outputPin, LOW); //turn off pin 8
  digitalWrite(chargePin, LOW); //turn off pin 7
  delayPeriodStart = micros();//start looking for response
  trigger = true;
}

void delayPeriodTiming()
{
  delayPeriod = micros() - delayPeriodStart;
  interruptFlag = true;
}
Title: Re: CDI tester project
Post by: tombauer on Sep 25, 2016, 11:52 pm
OH, well I am way behind the curve here. Only been looking at and reading code for almost 2 weeks and am a slow learner! I did not modify the code at all, just put a pulse on pin 3 to see if it would do 'anything' at all. Sadly I don't seem to have a CDI that is willing to exhibit a delay. I have some MB4213 chips so it will be easy to put one together to see if that works. The advance and rpm curve can be adjusted in a very basic way. Yes the clean pulse was from the coil through my limiting circuit.

The 15 and 82 degrees it reports was I think with the 3 and 4 jumped. It never does report 3000 rpm just close.

I will be back 9/30 so after that I can devote some more time to it. I will get some screen shots of scope and display, I ordered some displays so will be over that hurdle also.
Thanks again for your help, hope you have a great week, Tom
Title: Re: CDI tester project
Post by: tombauer on Oct 02, 2016, 05:28 pm
cattledog,
Hi, I got back and modified the code for a lcd and proved that it worked. Then I modified that code with your last update and it will not compile. It says that 'delayPeriodTiming' was not declared in this scope. I have done lots of reading and don't see the problem.
Tom


Code: [Select]


// CDI Tester Pulse Generator Serial Output Arduino Code

int pot1 = A3;          // select the input pin for the pot (changed for this version because of lcd)
int potValue = 0;       // variable to store the value coming from the sensor
int pulseValue = 0;    // 2 variables from one pot
int delayValue = 0;
int outputPin = 8;      // select the pin for the output for trigger pulse
int chargePin = 7;      // select the pin for the output for charge pulses

volatile boolean trigger = false;
volatile unsigned long delayPeriod;
unsigned long copy_delayPeriod;
volatile unsigned long delayPeriodStart;
int delayDegrees;

volatile boolean interruptFlag;

unsigned long analogReadInterval = 1000;//read pots and map
unsigned long lastAnalogRead;

#include <LiquidCrystal_I2C.h>
// set the LCD address to 0x27 for a 20 chars 4 line display
// Set the pins on the I2C chip used for LCD connections:
//                    addr, en,rw,rs,d4,d5,d6,d7,bl,blpol
LiquidCrystal_I2C lcd(0x3f, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address

void setup() {
  Serial.begin(9600);  // Used to type in characters
  lcd.begin(20,4);         // initialize the lcd for 20 chars 4 lines, turn on backlight
  //lcd.backlight();                       // backlight on 
  pinMode(outputPin, OUTPUT);            // declare the outputPin as an OUTPUT
  pinMode(chargePin, OUTPUT);            // declare the chargePin as an OUTPUT
  delay (2000);

  //pinMode(4, OUTPUT); //signal out for delay test

  //Timer1 set up 1ms pulse every 50 ms
  TCCR1A = 0;;
  TCCR1B = (1 << WGM12);//CTC mode to OCR1A
  OCR1A = 12500; //50 ms to top value
  TIMSK1 |= (1 << OCIE1A);//interrupt enable compareA
  TIMSK1 |= (1 << OCIE1B);//interrupt enable compareB
  OCR1B = 250; //1 ms pulse width
  TCCR1B |= (1 << CS11) | (1 << CS10); //prescaler 64  4us/tick

  attachInterrupt(digitalPinToInterrupt(3), delayPeriodTiming, RISING);
 
}

void loop() {
{
   
    if (Serial.available()) {                          // when characters arrive over the serial port...   
      delay(100);                                      // wait a bit for the entire message to arrive
      lcd.clear();                                     // clear the screen
      while (Serial.available() > 0) {                 // read all the available characters
      lcd.write(Serial.read());                        // display each character to the LCD
      }
    }
  }
  if (millis() - lastAnalogRead >= analogReadInterval)
  {
    lastAnalogRead += analogReadInterval;
    potValue = analogRead(pot1);                                         
    pulseValue = analogRead(pot1);                                     
    delayValue = analogRead(pot1);
    potValue = map(potValue, 0, 1023, 500, 3000);                         
    pulseValue = map(pulseValue, 0, 1023, 120, 20);                       
    delayValue = map(delayValue, 0, 1023, 30000, 5000);
  }
   
  if (trigger == true && interruptFlag == true )
  {
    //if (micros() - delayPeriodStart >= 5000) //5 ms delay
    //{
      trigger = false;
      interruptflag = false;
      //digitalWrite(4, HIGH);//simulate pulse
      //digitalWrite(4, LOW);
      noInterrupts();
      copy_delayPeriod = delayPeriod;
      interrupts();

      delayDegrees = 360*(copy_delayPeriod)/(pulseValue*1000UL);

      lcd.setCursor(3,0);
      lcd.print("RPM:");
      lcd.setCursor(8,0);
      lcd.print(potValue);
      lcd.setCursor(3,1);
      lcd.print("Ms:");
      lcd.setCursor(7,1);
      lcd.print(pulseValue);
      lcd.setCursor(3,2);
      lcd.print("Ms Delay:");
      lcd.setCursor(13,2);
      lcd.print(copy_delayPeriod);
      lcd.setCursor(3,3);
      lcd.print("Deg Advance:");
      lcd.setCursor(16,3);
      lcd.print(delayDegrees);
     
    }
  }
}

ISR(TIMER1_COMPA_vect) {
  OCR1A = (delayValue);                                                 // value to set delay between pulses to trigger cdi
  digitalWrite(outputPin, HIGH); //turn on pin 8
  digitalWrite(chargePin, HIGH); //turn on pin 7
}

ISR(TIMER1_COMPB_vect)
{
  digitalWrite(outputPin, LOW); //turn off pin 8
  digitalWrite(chargePin, LOW); //turn off pin 7
  delayPeriodStart = micros();//start looking for response
  trigger = true;
}

void delayPeriodTiming()
{
  delayPeriod = micros() - delayPeriodStart;
  interruptflag = true;
}

Title: Re: CDI tester project
Post by: cattledog on Oct 02, 2016, 07:01 pm
Welcome back. Good job on getting the display going. Many people have difficulty with the i2c displays up and running.

There are extra and misplaced brackets in your code. There is also a capitalization error with interruptflag != interruptFlag.

The code below compiles. Once again I encourage you to use auto format and check every bracket for its match.

How do you plan to use the serial input?

While you were away I wrote some code for the charging pulses. When you get the delay measurement working we can add that.

All the displayed headings which do not change, like "RPM " or "Deg Advance" only need to be written once on the lcd in setup. There is an internal memory which stores the characters and their positions.  It helps speed up the program to not re-write unchanging characters. You may also want to place the display of the pot values and their derivatives in the section where they are read, rather than in the code section determining the delay

Code: [Select]


// CDI Tester Pulse Generator Serial Output Arduino Code

int pot1 = A3;          // select the input pin for the pot (changed for this version because of lcd)
int potValue = 0;       // variable to store the value coming from the sensor
int pulseValue = 0;    // 2 variables from one pot
int delayValue = 0;
int outputPin = 8;      // select the pin for the output for trigger pulse
int chargePin = 7;      // select the pin for the output for charge pulses

volatile boolean trigger = false;
volatile unsigned long delayPeriod;
unsigned long copy_delayPeriod;
volatile unsigned long delayPeriodStart;
int delayDegrees;

volatile boolean interruptFlag;

unsigned long analogReadInterval = 1000;//read pots and map
unsigned long lastAnalogRead;

#include <LiquidCrystal_I2C.h>
// set the LCD address to 0x27 for a 20 chars 4 line display
// Set the pins on the I2C chip used for LCD connections:
//                    addr, en,rw,rs,d4,d5,d6,d7,bl,blpol
LiquidCrystal_I2C lcd(0x3f, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address

void setup() {
  Serial.begin(9600);  // Used to type in characters
  lcd.begin(20, 4);        // initialize the lcd for 20 chars 4 lines, turn on backlight
  //lcd.backlight();                       // backlight on
  pinMode(outputPin, OUTPUT);            // declare the outputPin as an OUTPUT
  pinMode(chargePin, OUTPUT);            // declare the chargePin as an OUTPUT
  delay (2000);

  //pinMode(4, OUTPUT); //signal out for delay test

  //Timer1 set up 1ms pulse every 50 ms
  TCCR1A = 0;;
  TCCR1B = (1 << WGM12);//CTC mode to OCR1A
  OCR1A = 12500; //50 ms to top value
  TIMSK1 |= (1 << OCIE1A);//interrupt enable compareA
  TIMSK1 |= (1 << OCIE1B);//interrupt enable compareB
  OCR1B = 250; //1 ms pulse width
  TCCR1B |= (1 << CS11) | (1 << CS10); //prescaler 64  4us/tick

  attachInterrupt(digitalPinToInterrupt(3), delayPeriodTiming, RISING);

}

void loop()
{
  // {

  if (Serial.available()) {                          // when characters arrive over the serial port...
    delay(100);                                      // wait a bit for the entire message to arrive
    lcd.clear();                                     // clear the screen
    while (Serial.available() > 0) {                 // read all the available characters
      lcd.write(Serial.read());                        // display each character to the LCD
    }
  }
  // }
 
  if (millis() - lastAnalogRead >= analogReadInterval)
  {
    lastAnalogRead += analogReadInterval;
    potValue = analogRead(pot1);
    pulseValue = analogRead(pot1);
    delayValue = analogRead(pot1);
    potValue = map(potValue, 0, 1023, 500, 3000);
    pulseValue = map(pulseValue, 0, 1023, 120, 20);
    delayValue = map(delayValue, 0, 1023, 30000, 5000);
  }

  if (trigger == true && interruptFlag == true )
  {
    //if (micros() - delayPeriodStart >= 5000) //5 ms delay
    //{
    trigger = false;
    interruptFlag = false;//capitalize F in Flag
    //digitalWrite(4, HIGH);//simulate pulse
    //digitalWrite(4, LOW);
    noInterrupts();
    copy_delayPeriod = delayPeriod;
    interrupts();

    delayDegrees = 360 * (copy_delayPeriod) / (pulseValue * 1000UL);

    lcd.setCursor(3, 0);
    lcd.print("RPM:");
    lcd.setCursor(8, 0);
    lcd.print(potValue);
    lcd.setCursor(3, 1);
    lcd.print("Ms:");
    lcd.setCursor(7, 1);
    lcd.print(pulseValue);
    lcd.setCursor(3, 2);
    lcd.print("Ms Delay:");
    lcd.setCursor(13, 2);
    lcd.print(copy_delayPeriod);
    lcd.setCursor(3, 3);
    lcd.print("Deg Advance:");
    lcd.setCursor(16, 3);
    lcd.print(delayDegrees);

  }
}
//}

ISR(TIMER1_COMPA_vect) {
  OCR1A = (delayValue);                                                 // value to set delay between pulses to trigger cdi
  digitalWrite(outputPin, HIGH); //turn on pin 8
  digitalWrite(chargePin, HIGH); //turn on pin 7
}

ISR(TIMER1_COMPB_vect)
{
  digitalWrite(outputPin, LOW); //turn off pin 8
  digitalWrite(chargePin, LOW); //turn off pin 7
  delayPeriodStart = micros();//start looking for response
  trigger = true;
}

void delayPeriodTiming()
{
  delayPeriod = micros() - delayPeriodStart;
  interruptFlag = true; //capitalize F in Flag
}
Title: Re: CDI tester project
Post by: tombauer on Oct 02, 2016, 08:05 pm
cattledog,
Yes the lcd was tricky but I went to the site where I got it and there was a link to https://arduino-info.wikispaces.com/LCD-Blue-I2C where  I found a code to determine the address to use. Not an address that was expected or in the chart either, even with all 3 jumpers open it was not 0x27.

Wow I sure missed a lot! I read over it several times looking for cap issues.

If you are asking how I am going to use  Serial.begin(9600);, the lcd will not work without it.??

OK, it compiles, but several unexpected issues.

1: with no input to pin 3 there is no display.
2: this was this way before but the ms delay is fixed, i.e. does not change. this is left over from
    the testing? This can be done away with in the end but may be good to have it show now for
    confirmation that it is accurate and has expected value.
3: a problem I had with the display from the start with this lcd is that it does not clear the trailing
    digits, i.e. if it shows 1987 rpm, when it goes to say, 623 it shows 6237. the Ms also has this
    issue.
4: I am not sure the deg advance is showing actual correct info. It shows from 0 to 3, in 4 places, it
    could perhaps only show the first 2 places, that would be plenty of resolution.

Again many thanks, as I said I am really out of my element here, but am reading about every mistake and understanding a little more all the time. My real element is repairing electronics and mechanical things.
Title: Re: CDI tester project
Post by: tombauer on Oct 02, 2016, 09:28 pm
cattledog,
 Yes, I see the code you asked about. It was left over from the lcd learning code I read and I didn't realize at the time what it was for. Now removed.

Code: [Select]

if (Serial.available()) {                          // when characters arrive over the serial port...
    delay(100);                                      // wait a bit for the entire message to arrive
    lcd.clear();                                     // clear the screen
    while (Serial.available() > 0) {                 // read all the available characters
      lcd.write(Serial.read());                        // display each character to the LCD
    }
  }
Title: Re: CDI tester project
Post by: cattledog on Oct 02, 2016, 09:33 pm
Quote
If you are asking how I am going to use  Serial.begin(9600);, the lcd will not work without it.??
No, I was referring to this section which takes input from the serial monitor and displays it on the lcd.

Code: [Select]
if (Serial.available()) {                          // when characters arrive over the serial port...
    delay(100);                                      // wait a bit for the entire message to arrive
    lcd.clear();                                     // clear the screen
    while (Serial.available() > 0) {                 // read all the available characters
      lcd.write(Serial.read());                        // display each character to the LCD
    }


Quote
1: with no input to pin 3 there is no display.
The display is embedded in the code section which determines the delay, and follows an interrupt on pin3.
That's why I suggested that you move all of the display code except for the update of the delay and the delay degrees, into the section with the analogRead() where the information comes from.

Quote
2: this was this way before but the ms delay is fixed, i.e. does not change. this is left over from
    the testing? This can be done away with in the end but may be good to have it show now for
    confirmation that it is accurate and has expected value.
I don't understand this. The delay should be changing if the actual signal delay is. If the degrees are changing than the delay should be changing.
Can you please clarify?

Quote
3: a problem I had with the display from the start with this lcd is that it does not clear the trailing
    digits, i.e. if it shows 1987 rpm, when it goes to say, 623 it shows 6237. the Ms also has this
    issue.
You will have to manage the display to write blanks to clear old data. For example if you have a maximum 4 digit rpm field you could do some thing like this to not have trailing data after a three digit number. There is a learning curve for lcd display and cursor management, so this stuff is to be expected.
Code: [Select]
lcd.setCursor(3, 0);
    lcd.print("RPM:");
    lcd.setCursor(8, 0);
    lcd.print("    ");//print 4 blank spaces to clear old data
    lcd.setCursor(8, 0);
    lcd.print(potValue);


Quote
4: I am not sure the deg advance is showing actual correct info. It shows from 0 to 3, in 4 places, it
    could perhaps only show the first 2 places, that would be plenty of resolution.
I don't really understand. delayDegrees is typed as an integer, and should have no decimal places. Are you sure this isn't more of the extra digits problem from a field which is shorter than the previous one?
Can you provide an example of the problem?

Quote
Again many thanks, as I said I am really out of my element here, but am reading about every mistake and understanding a little more all the time. My real element is repairing electronics and mechanical things.
You're doing fine. Have you found a unit with delay, and can read it with the code?
Title: Re: CDI tester project
Post by: tombauer on Oct 02, 2016, 10:03 pm
OK, fixed the serial input code, left over from lesson.

Moved the display code to proper place.

RPM and Ms I can fix as you suggest.

Ms Delay always shows from 119224 to 224220 with excursions to a little lower and much higher numbers regardless of pot position. Well it does affect it just a little but it stays in that range.

Deg Advance shows mostly 0 at 500 rpm and mostly 3 at 3000 but at 500 rpm it cycles randomly from 0 to 3. yes I think the last digits are left over. Can it be set to display in 1's ans 10's such as 1.3 and 2.5 etc, with a decimal place?

I have 4 cdi's here now, they all show the same advance but it is so short I have not been able to confirm it with my scope. only 3 deg max. That's not much and not as much as I would have thought.
Title: Re: CDI tester project
Post by: cattledog on Oct 02, 2016, 10:22 pm
Quote
Ms Delay always shows from 119224 to 224220 with excursions to a little lower and much higher numbers regardless of pot position. Well it does affect it just a little but it stays in that range.
Something is very wrong here. The value should be in the range of thousands--that is a few milli seconds.

The base pulse output is 1ms every 120 to 20 ms. The delayed response to the output pulse can not be 120 ms. I tested the code with another Arduino as a signal generator and got reliable readings in the millisecond range for delays I was using.

The degree Advance is derived from the delay, so it can't be correct either.

I think you will need to get a scope on this to see what is happening.

Do you have a second Arduino you can set up to provide a delayed pulse when it receives the output pulse?
I can give you the test code to generate the delayed response to be read on the interrupt pin.
Title: Re: CDI tester project
Post by: tombauer on Oct 02, 2016, 10:41 pm
the pro mini has 2 pins marked gnd. are they the same or is the one by rx and tx just a signal ground??
Title: Re: CDI tester project
Post by: cattledog on Oct 02, 2016, 10:48 pm
Quote
the pro mini has 2 pins marked gnd. are they the same or is the one by rx and tx just a signal ground??
All pins marked GND are tied together.
Title: Re: CDI tester project
Post by: tombauer on Oct 02, 2016, 10:51 pm
here is my revised code. gotta go do some "stuff" I'll get more done soon. Sure please send me the pulse generator code, I have some spares and we need to prove that my board and setup works before we go chasing ghosts!! Thanks.

Code: [Select]

// CDI Tester Pulse Generator Serial Output Arduino Code

int pot1 = A3;          // select the input pin for the pot (changed for this version because of lcd)
int potValue = 0;       // variable to store the value coming from the sensor
int pulseValue = 0;    // 2 variables from one pot
int delayValue = 0;
int outputPin = 8;      // select the pin for the output for trigger pulse
int chargePin = 7;      // select the pin for the output for charge pulses

volatile boolean trigger = false;
volatile unsigned long delayPeriod;
unsigned long copy_delayPeriod;
volatile unsigned long delayPeriodStart;
int delayDegrees;
volatile boolean interruptFlag;
unsigned long analogReadInterval = 1000;//read pots and map
unsigned long lastAnalogRead;

#include <LiquidCrystal_I2C.h>
// set the LCD address to 0x3f for a 20 chars 4 line display
// Set the pins on the I2C chip used for LCD connections:
//                    addr, en,rw,rs,d4,d5,d6,d7,bl,blpol
LiquidCrystal_I2C lcd(0x3f, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address

void setup() {
  Serial.begin(9600);
  lcd.begin(20, 4);        // initialize the lcd for 20 chars 4 lines, turn on backlight
  pinMode(outputPin, OUTPUT);            // declare the outputPin as an OUTPUT
  pinMode(chargePin, OUTPUT);            // declare the chargePin as an OUTPUT
  delay (2000);

  //Timer1 set up 1ms pulse every 50 ms
  TCCR1A = 0;;
  TCCR1B = (1 << WGM12);//CTC mode to OCR1A
  OCR1A = 12500; //50 ms to top value
  TIMSK1 |= (1 << OCIE1A);//interrupt enable compareA
  TIMSK1 |= (1 << OCIE1B);//interrupt enable compareB
  OCR1B = 250; //1 ms pulse width
  TCCR1B |= (1 << CS11) | (1 << CS10); //prescaler 64  4us/tick

  attachInterrupt(digitalPinToInterrupt(3), delayPeriodTiming, RISING);

}

void loop()
{
  if (millis() - lastAnalogRead >= analogReadInterval)
  {
    lastAnalogRead += analogReadInterval;
    potValue = analogRead(pot1);
    pulseValue = analogRead(pot1);
    delayValue = analogRead(pot1);
    potValue = map(potValue, 0, 1023, 500, 3000);
    pulseValue = map(pulseValue, 0, 1023, 120, 20);
    delayValue = map(delayValue, 0, 1023, 30000, 5000);

    //lcd.clear();
    lcd.setCursor(3, 0);
    lcd.print("RPM:");
    lcd.setCursor(8, 0);
    lcd.print("    ");//print 4 blank spaces to clear old data
    lcd.setCursor(8, 0);
    lcd.print(potValue);
    
    lcd.setCursor(3, 1);
    lcd.print("Ms:");
    lcd.setCursor(7, 1);
    lcd.print("    ");
    lcd.setCursor(7, 1);
    lcd.print(pulseValue);
    
    lcd.setCursor(3, 2);
    lcd.print("Ms Delay:");
    lcd.setCursor(13, 2);
    lcd.print("      ");
    lcd.setCursor(13, 2);
    lcd.print(copy_delayPeriod);
    
    lcd.setCursor(3, 3);
    lcd.print("Deg Advance:");
    lcd.setCursor(16, 3);
    lcd.print("    ");
    lcd.setCursor(16, 3);
    lcd.print(delayDegrees);
  }

  if (trigger == true && interruptFlag == true )
  {
    trigger = false;
    interruptFlag = false;      
    noInterrupts();
    copy_delayPeriod = delayPeriod;
    interrupts();

    delayDegrees = 360 * (copy_delayPeriod) / (pulseValue * 1000UL);
   }
}

ISR(TIMER1_COMPA_vect) {
  OCR1A = (delayValue);                                                 // value to set delay between pulses to trigger cdi
  digitalWrite(outputPin, HIGH); //turn on pin 8
  digitalWrite(chargePin, HIGH); //turn on pin 7
}

ISR(TIMER1_COMPB_vect)
{
  digitalWrite(outputPin, LOW);      //turn off pin 8
  digitalWrite(chargePin, LOW);      //turn off pin 7
  delayPeriodStart = micros();       //start looking for response
  trigger = true;
}

void delayPeriodTiming()
{
  delayPeriod = micros() - delayPeriodStart;
  interruptFlag = true; //capitalize F in Flag
}

Title: Re: CDI tester project
Post by: cattledog on Oct 02, 2016, 11:20 pm
Here is the code with the static elements of the display moved into setup.

With the update active portion of the display in the analogRead() section the MS Delay and the Deg Advance will only be every second, but that is OK for now. If they need to be changing with every reading, then they can be moved into the code section where delayDegrees is computed but the update may be too frequent in that section and could produce flicker.

I've attached some test code below. Jumper the output pin 8 from the main Arduino to pin 3 (interrupt 1) of the signal generating Arduino, and then jumper pin 4 of the signal generator back to pin 3 of the main Arduino. Changing the delayMicroseconds() will change the delay.

EDIT: Also connect the grounds of the two Aruinos.

Code: [Select]

// CDI Tester Pulse Generator Serial Output Arduino Code

int pot1 = A3;          // select the input pin for the pot (changed for this version because of lcd)
int potValue = 0;       // variable to store the value coming from the sensor
int pulseValue = 0;    // 2 variables from one pot
int delayValue = 0;
int outputPin = 8;      // select the pin for the output for trigger pulse
int chargePin = 7;      // select the pin for the output for charge pulses

volatile boolean trigger = false;
volatile unsigned long delayPeriod;
unsigned long copy_delayPeriod;
volatile unsigned long delayPeriodStart;
int delayDegrees;
volatile boolean interruptFlag;
unsigned long analogReadInterval = 1000;//read pots and map
unsigned long lastAnalogRead;

#include <LiquidCrystal_I2C.h>
// set the LCD address to 0x3f for a 20 chars 4 line display
// Set the pins on the I2C chip used for LCD connections:
//                    addr, en,rw,rs,d4,d5,d6,d7,bl,blpol
LiquidCrystal_I2C lcd(0x3f, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address

void setup() {
  Serial.begin(9600);
  lcd.begin(20, 4);        // initialize the lcd for 20 chars 4 lines, turn on backlight
  //lcd display setup of unchanging headings
  lcd.setCursor(3, 0);
  lcd.print("RPM:");
  lcd.setCursor(3, 1);
  lcd.print("Ms:");
  lcd.setCursor(3, 2);
  lcd.print("Ms Delay:");
  lcd.setCursor(3, 3);
  lcd.print("Deg Advance:");

  pinMode(outputPin, OUTPUT);            // declare the outputPin as an OUTPUT
  pinMode(chargePin, OUTPUT);            // declare the chargePin as an OUTPUT
  delay (2000);

  //Timer1 set up 1ms pulse every 50 ms
  TCCR1A = 0;;
  TCCR1B = (1 << WGM12);//CTC mode to OCR1A
  OCR1A = 12500; //50 ms to top value
  TIMSK1 |= (1 << OCIE1A);//interrupt enable compareA
  TIMSK1 |= (1 << OCIE1B);//interrupt enable compareB
  OCR1B = 250; //1 ms pulse width
  TCCR1B |= (1 << CS11) | (1 << CS10); //prescaler 64  4us/tick

  attachInterrupt(digitalPinToInterrupt(3), delayPeriodTiming, RISING);

}

void loop()
{
  if (millis() - lastAnalogRead >= analogReadInterval)
  {
    lastAnalogRead += analogReadInterval;
    potValue = analogRead(pot1);
    pulseValue = analogRead(pot1);
    delayValue = analogRead(pot1);
    potValue = map(potValue, 0, 1023, 500, 3000);
    pulseValue = map(pulseValue, 0, 1023, 120, 20);
    delayValue = map(delayValue, 0, 1023, 30000, 5000);

    //lcd.clear();
    //lcd.setCursor(3, 0);
    //lcd.print("RPM:");
    lcd.setCursor(8, 0);
    lcd.print("    ");//print 4 blank spaces to clear old data
    lcd.setCursor(8, 0);
    lcd.print(potValue);

    // lcd.setCursor(3, 1);
    // lcd.print("Ms:");
    lcd.setCursor(7, 1);
    lcd.print("    ");
    lcd.setCursor(7, 1);
    lcd.print(pulseValue);

    //lcd.setCursor(3, 2);
    //lcd.print("Ms Delay:");
    lcd.setCursor(13, 2);
    lcd.print("      ");
    lcd.setCursor(13, 2);
    lcd.print(copy_delayPeriod);

    //lcd.setCursor(3, 3);
    //lcd.print("Deg Advance:");
    lcd.setCursor(16, 3);
    lcd.print("    ");
    lcd.setCursor(16, 3);
    lcd.print(delayDegrees);
  }

  if (trigger == true && interruptFlag == true )
  {
    trigger = false;
    interruptFlag = false;
    noInterrupts();
    copy_delayPeriod = delayPeriod;
    interrupts();

    delayDegrees = 360 * (copy_delayPeriod) / (pulseValue * 1000UL);
  }
}

ISR(TIMER1_COMPA_vect) {
  OCR1A = (delayValue);                                                 // value to set delay between pulses to trigger cdi
  digitalWrite(outputPin, HIGH); //turn on pin 8
  digitalWrite(chargePin, HIGH); //turn on pin 7
}

ISR(TIMER1_COMPB_vect)
{
  digitalWrite(outputPin, LOW);      //turn off pin 8
  digitalWrite(chargePin, LOW);      //turn off pin 7
  delayPeriodStart = micros();       //start looking for response
  trigger = true;
}

void delayPeriodTiming()
{
  delayPeriod = micros() - delayPeriodStart;
  interruptFlag = true; //capitalize F in Flag
}


Delayed Pulse Generator code

Code: [Select]
void setup() {
 pinMode(4,OUTPUT);
 attachInterrupt(1,pulse,FALLING);
}

void loop() {
  // put your main code here, to run repeatedly:

}

void pulse()
{
  delayMicroseconds(1000);
  digitalWrite(4,HIGH);
  digitalWrite(4,LOW);
}
Title: Re: CDI tester project
Post by: tombauer on Oct 02, 2016, 11:51 pm
OK, I see what you did. Makes sense now. I also might as well just put a 4213 on a board with support components, it is not much. That way the delay would correspond with the rpm as it should. I will do that later as there must be something wrong with the way I am feeding the delayed pulse. I am also waiting on a 5v supply dedicated to the pro mini, pot and lcd. that way I will have 12v for my pulse controlling transistor and eventually for the larger charge coil transistor.
Title: Re: CDI tester project
Post by: tombauer on Oct 03, 2016, 01:11 am
To recap the way these CDIs work, the pulser coil on the crankshaft is at a position so that if it fired the CDI directly the timing would be advanced. So the CDI gets the pulse and based on rpm it delays it the same amount that the pulser coil is advanced on the shaft. (At low RPM) This gives no advance. As rpm increases the delay is taken away giving more advance. I hope this is what you understood and that the math figures it this way as it opposed to conventional thinking.
Best, Tom
Title: Re: CDI tester project
Post by: cattledog on Oct 03, 2016, 02:37 am
Quote
I hope this is what you understood and that the math figures it this way as it opposed to conventional thinking.
I think so. In the code, the main output pulse is referenced 0 degrees, but in the actual engine, the main pulse is set to be triggered before 0, and then there is a delay until the coil is actually fired. As that delay goes away, the actual firing will be advanced to before TDC.

The code measures the delay between the main trigger pulse and the coil fire pulse. The actual relationship of that pair to the real engine is not a factor for the code. That is why I have always tried to call what we are measuring delay instead of advance.

I hope I have it correct?
Title: Re: CDI tester project
Post by: tombauer on Oct 03, 2016, 01:22 pm
With the delay test code, set at 1000us (1Ms) the display shows 500 RPM, 120Ms between pulses, Ms Delay of 1004, Deg Advance 3. At 3000 RPM, 20Ms between pulses, Ms Delay 1004, Deg Advance 18.
My original math told me that the degrees per Ms would be just that, a range from 3 to 18 with RPM from 500 to 3000.

The part of the math and code that I cannot quite wrap my mind around is that the longer the delay, the less advance (at low RPM) and vice versa. I am thinking for instance, that at 500 RPM, and if the total advance would be 18 degrees then the delay at 500 would be 1Ms and that the delay would shorten until at some preset point the delay would be gone and timing advance would look like 18 degrees. It seems that the display should then be reversed? If the delay goes away completely then the display should show a larger number but it shows smaller.
Am I making any sense? Sometimes I wonder!

OK, anyway the board and code work, so now to see why it does not work in real time. I did confirm that I had a clean pulse of just over 5v from my feedback 'network'. Could the pulse be to short? I will get some shots of the scope display later.
Best, Tom
Title: Re: CDI tester project
Post by: cattledog on Oct 03, 2016, 05:33 pm
Quote
The part of the math and code that I cannot quite wrap my mind around is that the longer the delay, the less advance (at low RPM) and vice versa. I am thinking for instance, that at 500 RPM, and if the total advance would be 18 degrees then the delay at 500 would be 1Ms and that the delay would shorten until at some preset point the delay would be gone and timing advance would look like 18 degrees. It seems that the display should then be reversed? If the delay goes away completely then the display should show a larger number but it shows smaller.
Am I making any sense? Sometimes I wonder!
Both my head and the crankshaft are spinning. I think we are seeing the mathematical result of using a fixed delay at increasing speeds. This is why I have tried to never use the term advance, but just refer to the frame of the timing, and call what occurs between the two pulses as delay.

I would like to wait until you see some actual delay times out of a CDI unit. If the delay goes from 1ms to .5ms (or maybe from 5 ms to .05ms) as the speed increases, then we can figure out how to best present the data.  How are the specs for the cdi units written? Do they specify a delay period at certain rpm, or do they refer to degrees of advance. We can certainly normalize the data to present an"'advance" from low speed timing.

Quote
Could the pulse be to short?
I doubt it? The test code is written to provide a delayed response pulse which is only the length of a digitalWrite() which is about 4 microseconds. The interrupt which is looking for that pulse is much faster than that. I would think that the actual spark fire pulse going to the coil would be longer than that, but your scope will tell us.
Title: Re: CDI tester project
Post by: allanhurst on Oct 03, 2016, 08:01 pm
I can see how you obtain the automatic advance in hardware....


the voltage of the pulse generated will be proportional to rpm. So if one had a fixed trigger threshold, the rising voltage at higher rpm would reach this threshold earlier and so give you advance....

regards

Allan.
Title: Re: CDI tester project
Post by: tombauer on Oct 03, 2016, 08:32 pm
cattledog,
I did not mean to spin your head too! I just wanted to be sure that you had a correct view of how this works, and you do. I am good calling it delay, which it is, just wanted to clarify.

I had a CDI apart repairing it and connected to the input and the output of the delay IC. Whatever I try I get 6 digit numbers for the Ms Delay. With the test code it is clean and correct. Any other way it just does not make sense. I do understand not to even think about the degrees line until the delay if displaying correctly.

What I notice is that if I leave pin 3 open, the display shows 6 digits starting with a 1 and continuing with numbers in the 100000 range. If I tie pin 3 to ground with a 1k resistor it stays at 0. Even while pin 3 is tied directly to ground, if I power the CDI on the display foe Ms Delay starts showing 6 digit numbers always starting with 1.

Confused I am, Tom
Title: Re: CDI tester project
Post by: cattledog on Oct 03, 2016, 10:07 pm
It sounds like the ground of the Arduino, and the ground of the delay IC are not tied.

I like the idea of the external pull down on pin3. Perhaps try something weaker like 10K which will draw less current from the IC.

You might all try to explicitly set the pinMode on pin 3, although I think that attachInterrupt() does that.
Code: [Select]
pinMode(3,INPUT);
 attachInterrupt(digitalPinToInterrupt(3), delayPeriodTiming, RISING);


What is the output of the delay IC. Is it an active pulse, or is it perhaps open collector and needs a pull up.

Previously, I thought you were getting a delayed 5v pulse from a discharge circuit activated by the IC. Is the IC itself putting out a 5v signal?
Title: Re: CDI tester project
Post by: tombauer on Oct 03, 2016, 11:03 pm
This happens with no connection to the CDI output. All I have to do is turn on power supply to CDI the only part of the board that is connected is the output on pin 8 and that is thru 2 transistors.


'What I notice is that if I leave pin 3 open, the display shows 6 digits starting with a 1 and continuing with numbers in the 100000 range. If I tie pin 3 to ground with a 1k resistor it stays at 0. Even while pin 3 is tied directly to ground, if I power the CDI on, the display for Ms Delay starts showing 6 digit numbers always starting with 1.'
Title: Re: CDI tester project
Post by: tombauer on Oct 04, 2016, 04:28 am
cattledog,
What must be happening is that the arduino is picking up electrical noise from the world around it. What is odd is that once it displays it it will not stop until it is reset even when I take the noise away.
I am not sure that it is pin 3 that is picking up the 'noise', has this problem happened before? Can the other pins be picking up noise if they are floating at high impedance? Is there code to pull they down? Maybe the whole thing needs to be in a Faraday cage?
Title: Re: CDI tester project
Post by: cattledog on Oct 04, 2016, 07:50 am
It sounds like you are fighting a very electronically noisy environment.

Are you certain it is not the display, but the Arduino itself? You might want to see what you get with a serial monitor version of the sketch. LCD displays can be sensitive to noise around relays, motors, etc., but usually the symptom is a garbled display with nonsense characters.

What happens when the wire from pin 8 is disconnected? Is the noise entering the Arduino on that line? Or, is it radiated emi and gives the strange behaviour with no wires connected.

What happens if you run the test delay program with the second Arduino, but have all the other electronics running nearby? It might help to sort out if it is proximity or actual connection.

Quote
Can the other pins be picking up noise if they are floating at high impedance? Is there code to pull they down?
The digital pins default to inputs and are indeed floating. You can try setting all unused pins to INPUT_PULLUP, or try setting them as outputs written low.

You said that having an external pull down on pin 3 kept the displayed value at 0 with nothing connected. Is that still true? If you can get a signal from the delay line strong enough to pull that up to 5v it should work.

I'm afraid that with more hardware, and less software problems, the less help I can be. At some point you may have to draw a good schematic and take this to the General Electronics section of the forum.
Title: Re: CDI tester project
Post by: tombauer on Oct 04, 2016, 05:33 pm
cattledog,
I applied better electrical practices to the board construction, i.e. keeping all leads as short as possible and very short path to ground etc. I found that with pin 3 open and unconnected there was no problem, but even a 2" wire touched to it was enough to pick up the RFI. Now it seems to work but I don't understand that the top 2 lines clear all trailing characters every second, while the last 2 lines do not.
The Ms Delay shows from 119 to 24, sort of as expected, but 2 or 3 places after that confuses the ability to read it. At the same time the Deg Advance line shows from 3 to 55 but also with extra 1 or 2 characters. I am using a CDI that I expected to have LOTS of 'advance' since it is for a very high rpm engine so readings are probably correct. I increased the max RPM to 3800 per service manual for the engine I most test.
Best, Tom
Title: Re: CDI tester project
Post by: cattledog on Oct 04, 2016, 05:49 pm
Quote
Now it seems to work but I don't understand that the top 2 lines clear all trailing characters every second, while the last 2 lines do not.
If the lcd commands for all 4 lines to print blank spaces, and then the data, are all within the analogRead() once per second block then they should all clear every second?

Are you printing enough spaces to clear all the data?

Please post your latest code.
Title: Re: CDI tester project
Post by: Oldsnake00 on Oct 04, 2016, 06:45 pm
See http://transmic.net/index.php/2016/07/23/pickup-simulator/
Title: Re: CDI tester project
Post by: tombauer on Oct 04, 2016, 09:48 pm
See http://transmic.net/index.php/2016/07/23/pickup-simulator/
Yes, I know Thierry, but his setup does not do what I need. This will be different and more universal.
Title: Re: CDI tester project
Post by: tombauer on Oct 04, 2016, 10:21 pm
cattledog,

Yes the first 2 lines are within  the analogRead() once per second block, but is that because they are  potValue = analogRead(pot1); and pulseValue = analogRead(pot1); and those 2 variables are called in the lcd.print() while the last 2 lines are not? I added more spaces but it makes no change. When there is an input to pin 3, there is data changing every second, when I remove input the display just remembers what it showed last. I think I am actually learning something!!
I put some comments in the code for you.


Code: [Select]




// CDI Tester Pulse Generator Serial Output Arduino Code
// Advance is 12° at idle and 29° at over xxxx RPM

int pot1 = A3;          // select the input pin for the pot (changed for this version because of lcd)
int potValue = 0;       // variable to store the value coming from the sensor
int pulseValue = 0;    // 2 variables from one pot
int delayValue = 0;    // ""
int outputPin = 8;      // select the pin for the output for trigger pulse
int chargePin = 7;      // select the pin for the output for charge pulses

volatile boolean trigger = false;
volatile unsigned long delayPeriod;
unsigned long copy_delayPeriod;
volatile unsigned long delayPeriodStart;
int delayDegrees;
volatile boolean interruptFlag;
unsigned long analogReadInterval = 1000;//read pots and map
unsigned long lastAnalogRead;

#include <LiquidCrystal_I2C.h>
// set the LCD address to 0x3f for a 20 chars 4 line display
// Set the pins on the I2C chip used for LCD connections:
//                    addr, en,rw,rs,d4,d5,d6,d7,bl,blpol
LiquidCrystal_I2C lcd(0x3f, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address

void setup() {
  Serial.begin(9600);
  lcd.begin(20, 4);         // initialize the lcd for 20 chars 4 lines, turn on backlight
  lcd.setCursor(3, 0);      // lcd display setup of unchanging headings
  lcd.print("RPM:");        // print fixed characters
  lcd.setCursor(3, 1);
  lcd.print("Ms:");
  lcd.setCursor(3, 2);
  lcd.print("Ms Delay:");        // should this be micro seconds? or should it have a decimal point?
  lcd.setCursor(3, 3);
  lcd.print("Deg Advance:");

  pinMode(outputPin, OUTPUT);            // declare the outputPin as an OUTPUT
  pinMode(chargePin, OUTPUT);            // declare the chargePin as an OUTPUT
  delay (2000);

  //Timer1 set up 1ms pulse every 50 ms
  TCCR1A = 0;;
  TCCR1B = (1 << WGM12);//CTC mode to OCR1A
  OCR1A = 12500;                           //50 ms to top value            // this should change since top value is now 63.333?
  TIMSK1 |= (1 << OCIE1A);//interrupt enable compareA
  TIMSK1 |= (1 << OCIE1B);//interrupt enable compareB
  OCR1B = 250; //1 ms pulse width
  TCCR1B |= (1 << CS11) | (1 << CS10); //prescaler 64  4us/tick

  attachInterrupt(digitalPinToInterrupt(3), delayPeriodTiming, RISING);

}

void loop()
{
  if (millis() - lastAnalogRead >= analogReadInterval)
  {
    lastAnalogRead += analogReadInterval;
    potValue = analogRead(pot1);
    pulseValue = analogRead(pot1);
    delayValue = analogRead(pot1);
    potValue = map(potValue, 0, 1023, 500, 3800);                            // changed for max rpm of 3800
    pulseValue = map(pulseValue, 0, 1023, 120, 16);                          // which makes delay times wider apart
    delayValue = map(delayValue, 0, 1023, 30000, 6333);

    //lcd.setCursor(3, 0);
    //lcd.print("RPM:");
    lcd.setCursor(8, 0);
    lcd.print("    ");               //print blank spaces to clear old data
    lcd.setCursor(8, 0);
    lcd.print(potValue);

    // lcd.setCursor(3, 1);
    // lcd.print("Ms:");
    lcd.setCursor(7, 1);
    lcd.print("    ");
    lcd.setCursor(7, 1);
    lcd.print(pulseValue);

    //lcd.setCursor(3, 2);
    //lcd.print("Ms Delay:");
    lcd.setCursor(13, 2);
    lcd.print("       ");        // should clear 7 spaces but does not
    lcd.setCursor(13, 2);
    lcd.print(copy_delayPeriod);

    //lcd.setCursor(3, 3);
    //lcd.print("Deg Advance:");
    lcd.setCursor(16, 3);
    lcd.print("    ");           // should clear 4 spaces but not sure it does
    lcd.setCursor(16, 3);
    lcd.print(delayDegrees);
  }

  if (trigger == true && interruptFlag == true )
  {
    trigger = false;
    interruptFlag = false;
    noInterrupts();
    copy_delayPeriod = delayPeriod;
    interrupts();

    delayDegrees = 360 * (copy_delayPeriod) / (pulseValue * 1000UL);
  }
}

ISR(TIMER1_COMPA_vect) {
  OCR1A = (delayValue);                                                 // value to set delay between pulses to trigger cdi
  digitalWrite(outputPin, HIGH); //turn on pin 8
  digitalWrite(chargePin, HIGH); //turn on pin 7
}

ISR(TIMER1_COMPB_vect)
{
  digitalWrite(outputPin, LOW);      //turn off pin 8
  digitalWrite(chargePin, LOW);      //turn off pin 7
  delayPeriodStart = micros();       //start looking for response
  trigger = true;
}

void delayPeriodTiming()
{
  delayPeriod = micros() - delayPeriodStart;
  interruptFlag = true;
}


Title: Re: CDI tester project
Post by: cattledog on Oct 04, 2016, 11:31 pm
Quote
When there is an input to pin 3, there is data changing every second, when I remove input the display just remembers what it showed last.
I think you are saying that that you want the display to show "no data" if there is no trigger going out or delayed pulse coming back.

One way to do that is with a "new data" flag set in the section which gets the delay data from the interrupt and
calculates the delay degrees. The flag will be cleared after the display. I've modified the code below.

There is some work for you to clean this up, in that "no data" is seven characters(six letters plus a space)
and you need to make room for it in the "Deg Advance" printout. I would use "Deg Adv" as the heading, and reposition the cursor for the data or "no data" printing and make sure you clear 7 spaces.

Let me know when this project is stable enough for you to attempt to add the coil charging.


Code: [Select]

// CDI Tester Pulse Generator Serial Output Arduino Code
// Advance is 12° at idle and 29° at over xxxx RPM

int pot1 = A3;          // select the input pin for the pot (changed for this version because of lcd)
int potValue = 0;       // variable to store the value coming from the sensor
int pulseValue = 0;    // 2 variables from one pot
int delayValue = 0;    // ""
int outputPin = 8;      // select the pin for the output for trigger pulse
int chargePin = 7;      // select the pin for the output for charge pulses

volatile boolean trigger = false;
volatile unsigned long delayPeriod;
unsigned long copy_delayPeriod;
volatile unsigned long delayPeriodStart;
int delayDegrees;
volatile boolean interruptFlag;
unsigned long analogReadInterval = 1000;//read pots and map
unsigned long lastAnalogRead;

boolean newData = false;

#include <LiquidCrystal_I2C.h>
// set the LCD address to 0x3f for a 20 chars 4 line display
// Set the pins on the I2C chip used for LCD connections:
//                    addr, en,rw,rs,d4,d5,d6,d7,bl,blpol
LiquidCrystal_I2C lcd(0x3f, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address

void setup() {
  Serial.begin(9600);
  lcd.begin(20, 4);         // initialize the lcd for 20 chars 4 lines, turn on backlight
  lcd.setCursor(3, 0);      // lcd display setup of unchanging headings
  lcd.print("RPM:");        // print fixed characters
  lcd.setCursor(3, 1);
  lcd.print("Ms:");
  lcd.setCursor(3, 2);
  lcd.print("Ms Delay:");        // should this be micro seconds? or should it have a decimal point?
  lcd.setCursor(3, 3);
  lcd.print("Deg Advance:");

  pinMode(outputPin, OUTPUT);            // declare the outputPin as an OUTPUT
  pinMode(chargePin, OUTPUT);            // declare the chargePin as an OUTPUT
  delay (2000);

  //Timer1 set up 1ms pulse every 50 ms
  TCCR1A = 0;;
  TCCR1B = (1 << WGM12);//CTC mode to OCR1A
  OCR1A = 12500;                           //50 ms to top value            // this should change since top value is now 63.333?
  TIMSK1 |= (1 << OCIE1A);//interrupt enable compareA
  TIMSK1 |= (1 << OCIE1B);//interrupt enable compareB
  OCR1B = 250; //1 ms pulse width
  TCCR1B |= (1 << CS11) | (1 << CS10); //prescaler 64  4us/tick

  attachInterrupt(digitalPinToInterrupt(3), delayPeriodTiming, RISING);

}

void loop()
{
  if (millis() - lastAnalogRead >= analogReadInterval)
  {
    lastAnalogRead += analogReadInterval;
    potValue = analogRead(pot1);
    pulseValue = analogRead(pot1);
    delayValue = analogRead(pot1);
    potValue = map(potValue, 0, 1023, 500, 3800);                            // changed for max rpm of 3800
    pulseValue = map(pulseValue, 0, 1023, 120, 16);                          // which makes delay times wider apart
    delayValue = map(delayValue, 0, 1023, 30000, 6333);

    
    lcd.setCursor(8, 0);
    lcd.print("    ");               //print blank spaces to clear old data
    lcd.setCursor(8, 0);
    lcd.print(potValue);

  
    lcd.setCursor(7, 1);
    lcd.print("    ");
    lcd.setCursor(7, 1);
    lcd.print(pulseValue);

    
    lcd.setCursor(13, 2);
    lcd.print("       ");        // should clear 7 spaces
    lcd.setCursor(13, 2);
    if (newData == true)
    {
      lcd.print(copy_delayPeriod);
    }
    else
      lcd.print("no data"); // 7 characters

   //You will need to reposition the cursor and clear 7 spaces in this section

    lcd.setCursor(16, 3);
    lcd.print("    ");           // should clear 4 spaces
    lcd.setCursor(16, 3);
    if (newData == true)
    {
      newData = false; //clear flag at this point
      lcd.print(delayDegrees);
    }
    else
      lcd.print("no data");
  }

  if (trigger == true && interruptFlag == true )
  {
    trigger = false;
    interruptFlag = false;
    newData = true;
    noInterrupts();
    copy_delayPeriod = delayPeriod;
    interrupts();

    delayDegrees = 360 * (copy_delayPeriod) / (pulseValue * 1000UL);
  }
}

ISR(TIMER1_COMPA_vect) {
  OCR1A = (delayValue);                                                 // value to set delay between pulses to trigger cdi
  digitalWrite(outputPin, HIGH); //turn on pin 8
  digitalWrite(chargePin, HIGH); //turn on pin 7
}

ISR(TIMER1_COMPB_vect)
{
  digitalWrite(outputPin, LOW);      //turn off pin 8
  digitalWrite(chargePin, LOW);      //turn off pin 7
  delayPeriodStart = micros();       //start looking for response
  trigger = true;
}

void delayPeriodTiming()
{
  delayPeriod = micros() - delayPeriodStart;
  interruptFlag = true;
}

Title: Re: CDI tester project
Post by: tombauer on Oct 05, 2016, 12:56 am
cattledog,

I was just being sure I gave you as much info about how it acted as I could, you know, clues. In reality it does not really ever need to say 'no data', I just would like to understand how to refresh the entire character set in the last 2 lines with each new read. The first 2 lines refresh and remove trailing characters when they are not needed, but for some reason I have yet to find the last 2 do not. So what happens is that the trailing spaces stay full of what ever was printed there last.  Just makes it hard to read at a glance.

In Dbase, I could limit how many characters would print, and the same would work here as Ms Delay never needs to print more than 3 characters from 0 to 999 with leading char being a 0 when needed. Same with Advance since it will always be from 0 to 99. Just a thought, I don't want to go off in another direction, just remove un needed info from display
Title: Re: CDI tester project
Post by: cattledog on Oct 05, 2016, 02:15 am
Quote
The first 2 lines refresh and remove trailing characters when they are not needed, but for some reason I have yet to find the last 2 do not
I do not understand this either. I would go back to some testing with the LCD. Write every position in the 20X4 with "X" and then see if you can remove them with spaces. Are you aware that the locations in the row of twenty is indexed 0 to 19.

Maybe add a snippet like this to setup and see what prints and what clears

Code: [Select]
lcd.setCursor(0,0);
 lcd.print("XXXXXXXXXXXXXXXXXXXX");// twenty X's
delay(5000);
 lcd.setCursor(0,1);
 lcd.print("XXXXXXXXXXXXXXXXXXXX");// twenty X's
delay(5000);
 lcd.setCursor(0,2);
 lcd.print("XXXXXXXXXXXXXXXXXXXX");// twenty X's
delay(5000);
 lcd.setCursor(0,3);
 lcd.print("XXXXXXXXXXXXXXXXXXXX");// twenty X's
 delay(5000);
 
lcd.setCursor(13,0);
lcd.print("       "); //seven spaces be sure to count when typing in
delay(5000);
lcd.setCursor(13,1);
lcd.print("       "); //seven spaces be sure to count when typing in
delay(5000);
lcd.setCursor(13,2);
lcd.print("       "); //seven spaces be sure to count when typing in
delay(5000);
lcd.setCursor(13,3);
lcd.print("       "); //seven spaces be sure to count when typing in;
delay(10000);
Title: Re: CDI tester project
Post by: tombauer on Oct 05, 2016, 03:33 am
cattledog,

Tested lcd with your idea, it works as expected. Writes all Xs and then removes last 7.

This is what I think is happening to the Ms Delay line. It is printing 6 characters, so when we only want to know first 3 such as 119 at 500 RPM, it prints 119352. Then at higher RPM when it should print smaller number like 74, that number is really 074 but it strips away leading 0 and then prints 74496.

This is why printing spaces does nothing. It is printing spaces and then putting the longer number right back up.

To prove that, I put this code and it printed '0XXXXXXX' with no input since with no input the display does not start. Then with input it printed '119453X', and at higher RPM printed '52596XX'

So the problem is that copy_delayPeriod is a 6 digit number and delayDegrees is a 4 digit number.

Code: [Select]


//lcd.setCursor(3, 2);
    //lcd.print("Ms Delay:");
    lcd.setCursor(12, 2);
    lcd.print("XXXXXXX");       
    lcd.setCursor(12, 2);
    lcd.print(copy_delayPeriod);

Title: Re: CDI tester project
Post by: cattledog on Oct 05, 2016, 06:13 am
Yes, I see what is happening. The delayPeriod is calculated in microseconds and was typed as an unsigned long because it is related to time values. I never paid much attention to the heading "Ms Delay" but it looks like you wanted it in milliseconds which will be a three digit number, since the overall period is 20 to 120 milliseconds. I was also unclear if the delay period would make it into the final version or if you wanted it in degrees which  factors in the rpm.

I think that you can simply divide copy_delayPeriod by 1000. I would do that division after you calculate the degrees of delay using the full six digits of the microseconds,

Code: [Select]
delayDegrees = 360 * (copy_delayPeriod) / (pulseValue * 1000UL);
copy_delayPeriod = copy_delayPeriod/1000; //value for display


If you want delayDegrees to one decimal, change the initial declaration of delayDegrees from int to float, and then calculate as follows.

Code: [Select]
delayDegrees = 360.0 * (copy_delayPeriod) / (pulseValue * 1000.0);

and then when printed
Code: [Select]
lcd.print(delayDegrees,1);
Title: Re: CDI tester project
Post by: tombauer on Oct 05, 2016, 05:17 pm
cattledog,

It's ironic, I had the same thought last night as I went to bed, that the number needed to be divided by 1000. So now that is working and soon I will actually measure the delay and compare it with the readout. That may take a couple days as I need to catch up on other work. I did want to leave the Ms Delay in place just to fine tune the process of getting the degree display correct. I did find that the main CDI I repair has 17° advance, so I can calculate the delay at various rpms and see how it looks.
Best, Tom
Title: Re: CDI tester project
Post by: tombauer on Oct 06, 2016, 08:00 pm
cattledog,
 
I am about to admit defeat. I just cannot get this to work. Using your test code to generate the delay from pin 8 output to pin 3 input I cannot get any results anymore that make any sense. Well just one actually, if I set the delay to 0 then I get 0 which would be correct. If I set it to 1000 I get 119 for us delay and from 3** to 5** for degrees. Remember that with us delay at 0 the degrees should display whatever the full advance is (in my case 17) and with us delay at about 2.882 Ms the advance should say 0.
Lost I am, Tom
Title: Re: CDI tester project
Post by: cattledog on Oct 06, 2016, 08:20 pm
Please post the two programs you are using, and describe how the two Arduino's are connected.

On October 3, your post indicated that you were using the simulated response from a second Arduino and were seeing the correct 1000 us delay. Then you had problems attaching to the real world circuit and fine tuning the display.

Can you think of what has changed?
Title: Re: CDI tester project
Post by: tombauer on Oct 06, 2016, 10:23 pm
I changed the rpm range to go to 3800 and have a question about if I should change the ORC1A value?

Code: [Select]


 //Timer1 set up 1ms pulse every 50 ms
  TCCR1A = 0;;
  TCCR1B = (1 << WGM12);//CTC mode to OCR1A
  OCR1A = 12500;                           //50 ms to top value            // this should change since top value is now 63.333? was 12500 at 50 ms should it be 15832?



Added second line to refine display

Code: [Select]


 delayDegrees = 360 * (copy_delayPeriod) / (pulseValue * 1000UL);
    copy_delayPeriod = copy_delayPeriod/1000;                           //value for display



Must have had a solder bridge, couldn't see it, on pin 3 so no input to main board. Also had my 'network' attached and I am using a 1k resistor to pull that pin down to prevent RFI. Yes I know that is much lower than normal, but the circuit driving the input can easily support that. Had to remove the network, it was also puling down the test board.

I have not been able to show delay on scope, so I wanted to just prove that the code would display delay correctly and to be honest thinking about the delay shortening while RPM goes up and trying to understand how that interacts just is over my head.

Now with the test delay this is what I get.
Test code set at 1000us gives reading of 1 and deg advance range of 3 to 22 (500 to 3800 rpm)
Set at 2000us gives reading of 2 and deg advance range of 6 to 45

I expect a delay of .002822 at low RPM, how would I have the test code produce that?
Many thanks, Tom
Title: Re: CDI tester project
Post by: tombauer on Oct 07, 2016, 12:59 am
cattledog,

When I leave this line out, the us line shows the delay that the test board is set to. Remember we put that in to correct the display? Now with the test it does not seem to need it. Maybe it will again in real world, unknown right now.

Code: [Select]


copy_delayPeriod = copy_delayPeriod/1000;




When I increase the delay value in test, also the degrees rise on both ends of the range. More delay should lower the low rpm end and I still don't really comprehend how the increasing rpm affects the degree display. I mean I see the math but it doesn't work out like I expect it to??

Tom
Title: Re: CDI tester project
Post by: cattledog on Oct 07, 2016, 01:33 am
Quote
Must have had a solder bridge, couldn't see it, on pin 3 so no input to main board. Also had my 'network' attached and I am using a 1k resistor to pull that pin down to prevent RFI. Yes I know that is much lower than normal, but the circuit driving the input can easily support that. Had to remove the network, it was also puling down the test board.
Glad to hear that you figured out your hardware problems.

Quote
I changed the rpm range to go to 3800 and have a question about if I should change the ORC1A value?
The OCR1A value used in setup (12500) is just a starting point, and it is quickly overwritten with the value mapped from the pot.

You haven't quite worked the math right for the 3800 rpm value. 3800/60 = 63.3333 pulses per second.  1/63.3333 = 15.79 milliseconds per pulse. You have rounded to 16 ms which is the period for 3750 rpm, so lets work with that.

If you want the timer to send a pulse every 16 ms, and the basic "tick" has been set to 4 microseconds, then it needs to count to 4000. (16/.004). That is the value you want to pass to OCR1A for 3750 rpm.

Code: [Select]

 potValue = map(potValue, 0, 1023, 500, 3750);       // changed for max rpm of 3750
 pulseValue = map(pulseValue, 0, 1023, 120, 16);          
 delayValue = map(delayValue, 0, 1023, 30000, 4000);


I advise that you clean up this section. There's nothing really critical and you can do what you understand and feels comfortable. Fundamentally, three separate readings of the same pot mapped into three variables all derived from each other feels awkward to me and you can make mistakes when you want to change values.

First, I would change the term "delayValue" to something like "timerTopValue" so its not confused with the delayed signal produced. Second, "potValue" should be called RPM as that's what it being mapped.  Third "pulseValue" should probably go away as it is not really used either by the human who looks at RPM or the timer which uses "timerTopValue".

EDIT: I see that the millisecond pulseValue is used a a convenience in the calculation of the delay degrees so its probably OK to have it.

Quote
I expect a delay of .002822 at low RPM, how would I have the test code produce that?
It's easy enough to have the test code put out that delay with
Code: [Select]
delayMicroseconds(2822);

The problem is that with the division of copy_delayValue by 1000 it's going to truncate to 2. It sounds like the delay values are going to be in the range of 2822 to 0 so you can probably not perform the division which was being used when you had large, incorrect values.

One point that I raised earlier and which might have been overlooked is that the delayValue is measured from the start of the 1 millisecond pulse delivered by pin 8. It now appears that we are dealing with delay values in that low range, and you need to understand the CDI IC and whether or not the delay is from the start or end of that pulse. Your code can easily handle which ever way is correct.


Title: Re: CDI tester project
Post by: cattledog on Oct 07, 2016, 01:49 am
Quote
When I increase the delay value in test, also the degrees rise on both ends of the range. More delay should lower the low rpm end and I still don't really comprehend how the increasing rpm affects the degree display. I mean I see the math but it doesn't work out like I expect it to??
I think you are getting confused by what happens when you test a fixed delay at the different rpm. If the delay goes down faster than the period, the degrees of delay will get smaller.

Example:

3000 microseconds of signal delay at 500 rpm = 9 degrees of delay.

300 microseconds of signal delay at 3000 rpm = 5.4 degrees of delay
Title: Re: CDI tester project
Post by: tombauer on Oct 07, 2016, 02:35 am
'I think you are getting confused by what happens when you test a fixed delay at the different rpm. If the delay goes down faster than the period, the degrees of delay will get smaller.'
Yes, I had just thought of that, the fact that I had a fixed delay being fed in to a variable RPM.

I did finally realize that I could just put 2822 into the test code. Didn't work when I first tried it but I had other issues then as well, all resolved.

Can I place a decimal value into the 'pulseValue = map(pulseValue, 0, 1023, 120, 16);' line such as 15.79 instead of the 16? I see that rounding is not good in this situation!

It looks like I may need to have the ability to "0" the advance degrees reading at 500 RPM so that it can more accurately compute the advance at high RPM. Does that make sense? Now it shows some advance at 500 when it is probably 0 in reality. A push button to reset it to 0??
Thanks, Tom
Title: Re: CDI tester project
Post by: cattledog on Oct 07, 2016, 05:31 am
Quote
Can I place a decimal value into the 'pulseValue = map(pulseValue, 0, 1023, 120, 16);' line such as 15.79 instead of the 16? I see that rounding is not good in this situation!
Here's the opportunity to do away with the unneeded map function. The OCR1A value defines a period equal to one revolution and is better calculated directly. The math is simple.

First convert revolutions per minute to revolutions per microsecond and take the inverse to obtain microseconds per revolution = 60000000/RPM. The timer has been set up for a 4 microsecond "tick" so the timer counts per revolution are 15000000/RPM.

For example, numerically 3800 RPM = 15000000/3800 = 3947 timer counts. The numbers will be integers and the decimal places don't matter.  Using some of your original values and dividing 15000000 by them you see that 3000 RPM  = 5000 timer counts  500 RPM = 30000 timer counts.

At the top of the program, rename delayValue to timerTopValue. You will also need a new unsigned int variable RPM. I would then have the potentiometer setting section looks like this

Code: [Select]
 
    potValue = analogRead(pot1);
   // pulseValue = analogRead(pot1);
   // delayValue = analogRead(pot1);
    RPM = map(potValue, 0, 1023, 500, 3800);                           
   // pulseValue = map(pulseValue, 0, 1023, 120, 16);                         
    timerTopValue = 15000000UL/RPM;


Remember to change the name of the variables where they are printed to the lcd.

Remember to change the variable name in the assignment to OCR1A
Code: [Select]

ISR(TIMER1_COMPA_vect) {
  OCR1A = (timerTopValue);   // value to set timing of pulses to trigger cdi
  digitalWrite(outputPin, HIGH); //turn on pin 8
  digitalWrite(chargePin, HIGH); //turn on pin 7
}



If you want delayDegrees to one decimal place, change the initial declaration of delayDegrees from int to float, and then calculate as follows.

Code: [Select]
delayDegrees = 360.0 * (copy_delayPeriod) / (timerTopValue * 4.0);


and then when printed
Code: [Select]

lcd.print(delayDegrees,1);
Title: Re: CDI tester project
Post by: tombauer on Oct 07, 2016, 05:30 pm
cattledog,

I had to add wire.h to the sketch. ??
All done, but have a question. If pulseValue is commented out, the second line (Ms) displays 0. I understand why but I still want to hold on to that for now, just until I get the final system closer to reporting correct degrees, so I left that in for now.

And back To a previous question, 'It looks like I may need to have the ability to "0" the advance degrees reading at 500 RPM so that it can more accurately compute the advance at high RPM. Does that make sense? Now it shows some advance at 500 when it is probably 0 in reality. A push button to reset it to 0??' each other CDI I test will have the same sort of scheme for advance but at low end of RPM they all in effect should show 0 advance to easily read the total advance at high RPM but they will have different amounts of delay.

I think this is proven by changing the test delay and leaving the RPM set at 500, the longer the delay, the larger the degree value becomes, but the range increases. In reality the advance curve is not linear, it may start advancing at 1800 and be all done by 2500. Will that be a problem for the math that is there now?
Thanks, Tom
Title: Re: CDI tester project
Post by: cattledog on Oct 07, 2016, 06:28 pm
Quote
If pulseValue is commented out, the second line (Ms) displays 0. I understand why but I still want to hold on to that for now, just until I get the final system closer to reporting correct degrees, so I left that in for now.
pulseValue is now timerTopValue*4 but its in microseconds and not milliseconds.

Quote
I had to add wire.h to the sketch. ??
Wire.h is the library which handles the i2c protocols for the lcd display. Some liquid crystal libraries will add it by themselves, and others require you to add it to the sketch.  What liquid crystal library are you using? Did you change it? If the library you use requires you to include it in the sketch I'm surprised it worked without it.

Quote
I may need to have the ability to "0" the advance degrees reading at 500 RPM so that it can more accurately compute the advance at high RPM. Does that make sense?
Not really.  Foremost, I get confused when we switch to the term "advance".

All you measure is a delay from the trigger pulse. At 500 rpm you measure some delay. At 3800 rpm you measure another delay. That time delay becomes shorter as the rpm increase, and all that is controlled by the ic in the ignition unit. You can certainly set up the program to report the change in delay from 500 to 3800 rpm or the change in degrees delay. It would be easy to develop a measurement routine where you set 500 rpm, press a button and remember the delay value, set 3800 rpm and take another value. I'm not sure if the change is linear or if you need to take intermediate points as well to plot a delay curve. Before we start I'd really like to see several sets or number from actual cdi units.

I've asked before how are the cdi units specified? You want to test them as they are spec'd. I don't understand how can they specify "advance" when the location of the trigger position on the crank/flywheel for any lawnmower may be different across brands, but you are the expert here.

There is one thing you can do which may increase the discrimination between high rpm and low rpm measurement of delay, and that is to measure the delay from the start of the trigger pulse or to make the trigger pulse shorter. Why is the trigger pulse set at 1 ms? On the lawnmower if the trigger pulse is derived from a hall sensor the pulse length should vary with rpm.   Do you know what the actual CDI units do.

I think it may have been an error when I measured the delay from the end of the trigger pulse instead of the start. To measure the delay from the start of the trigger pulse instead of from the end, move this code from the TIMER1_COMPB_vect to the TIMER1_COMPA_vect
Code: [Select]
delayPeriodStart = micros();//start looking for response
  trigger = true;


What does this change do when working with a CDI.

Please post your complete current code in your next posting. Thanks
Title: Re: CDI tester project
Post by: tombauer on Oct 07, 2016, 07:30 pm
cattledog,

'What liquid crystal library are you using?'
I am using 'Newliquidcrystal' from https://bitbucket.org/fmalpartida/new-liquidcrystal/downloads/NewliquidCrystal_1.3.4.zip I had it before without the wire.h and it worked. No problem, I figured out the messase I got when I tried to compile.

'Not really.  Foremost, I get confused when we switch to the term "advance". '
Yes, I know, sorry my mind is wired the other way, but all CDI with delay work mostly the same way and most use the same IC MB4213. So the designer of any particular engine specs when they want the spark and at what RPM. Then they position the pickup, usually a small coil with a magnetic core, at the point they want the spark to occur at high RPM (with no delay). They then design the CDI to give enough delay so that the spark occurs at the correct point at low RPM. But this is not a linear curve, the delay may be a high value (3 or 4 Ms) until maybe 1800 RPM and then the delay starts going away and at maybe 2800 RPM it is gone so no more delay. With no more delay the timing stays at that setting for the rest of the RPM range.

Here may lie the main issue, the display will show the delay and as RPM goes up, if the delay stays the same the degree line should not change (it does now) then as the delay goes away the degree line must start from 0 and calculate with info from RPM and delay to show correct info. When the delay has hit 0, the degree line should not show any higher number even as the RPM goes up. (it does now)

I now find that with the delay tester code if I set it at 1000 I get a reading of 1508 and if I set it at 0 I get reading of 512
Title: Re: CDI tester project
Post by: cattledog on Oct 08, 2016, 01:48 am
Quote
I now find that with the delay tester code if I set it at 1000 I get a reading of 1508 and if I set it at 0 I get reading of 512
What do you see with the delay measured from the start of the trigger pulse rather than the end? That was a change which I suggested in the previous post.

I'm a little surprised at the latency of approximately 500 microseconds with the delayMicroseconds(0) in the test code.  It should be more like the 1 millisecond (1000 microseconds) that the trigger pulse lasts.

EDIT: I may be wrong about this. I just checked the simulation program again, and the interrupt response is set to FALLING, so the reply signal is triggered by the same edge which starts the measurement. I think that the main program should still be changed to start looking for the response at the start of the output pulse on pin 8, and the simulated delay sketch should have the interrupt trigger as RISING. The latency of 508 microseconds still does not seem correct. I'll do some testing at this end.

EDIT #2 I can not confirm your additional 500ms delay mystery. When I test, it does not matter whether I trigger from the rising edge or the falling edge of the pulse if the response simulator is set to match. I see a delay of 1008 for a setting of 1000 and a delay of 8 for a setting of 0. This is what I saw some time ago, and now confirm those results. It's definitely in the range expected.

Please post the actual code you are running when you see the 508 microsecond delay for a setting of 0. I will test it.
 
Title: Re: CDI tester project
Post by: cattledog on Oct 08, 2016, 04:49 am
Here are the two pieces of code I am running which give 1008 and 8 microseconds of delay for the measurement of the the return pulse delay when the simulator is set for 1000 and 0.

Code: [Select]

int pot1 = A5;          // select the input pin for the pot
int potValue = 0;       // variable to store the value coming from the sensor
//int pulseValue = 0;    // 2 variables from one pot
//int delayValue = 0;
unsigned int timerTopValue  = 0;
int RPM = 0;
int outputPin = 8;      // select the pin for the output for trigger pulse
int chargePin = 7;      // select the pin for the output for charge pulses

volatile boolean trigger = false;
volatile unsigned long delayPeriod;
unsigned long copy_delayPeriod;
volatile unsigned long delayPeriodStart;
float delayDegrees;

volatile boolean interruptFlag;

unsigned long analogReadInterval = 1000;//read pots and map
unsigned long lastAnalogRead;

void setup() {
  Serial.begin(115200);                       // serial com speed for display
  pinMode(outputPin, OUTPUT);            // declare the outputPin as an OUTPUT
  pinMode(chargePin, OUTPUT);            // declare the chargePin as an OUTPUT
  delay (2000);

  //Timer1 set up 1ms pulse every 50 ms
  TCCR1A = 0;;
  TCCR1B = (1 << WGM12);//CTC mode to OCR1A
  OCR1A = 12500; //50 ms to top value
  TIMSK1 |= (1 << OCIE1A);//interrupt enable compareA
  TIMSK1 |= (1 << OCIE1B);//interrupt enable compareB
  OCR1B = 250; //1 ms pulse width
  TCCR1B |= (1 << CS11) | (1 << CS10); //prescaler 64  4us/tick

  attachInterrupt(digitalPinToInterrupt(3), delayPeriodTiming, RISING);
}

void loop() {

  if (millis() - lastAnalogRead >= analogReadInterval)
  {
    lastAnalogRead += analogReadInterval;
    potValue = analogRead(pot1);
    // pulseValue = analogRead(pot1);
    // delayValue = analogRead(pot1);
    RPM = map(potValue, 0, 1023, 500, 3800);
    // pulseValue = map(pulseValue, 0, 1023, 120, 20);
    // delayValue = map(delayValue, 0, 1023, 30000, 5000);
    timerTopValue = 15000000UL / RPM;
  }

  if (trigger == true && interruptFlag == true )
  {
    trigger = false;
    interruptFlag = false;
    noInterrupts();
    copy_delayPeriod = delayPeriod;
    interrupts();

    //delayDegrees = 360*(copy_delayPeriod)/(pulseValue*1000UL);
    delayDegrees = 360.0 * (copy_delayPeriod) / (timerTopValue * 4.0);

    Serial.print("RPM =");
    //Serial.println(potValue);
    Serial.println(RPM);
    Serial.print("Period Microseconds =");
    // Serial.println(pulseValue);
    Serial.println(timerTopValue * 4UL);
    Serial.print("Delay Microseconds =");
    Serial.println(copy_delayPeriod);                               // for use in future code
    Serial.print("Delay Degrees = ");
    Serial.println(delayDegrees,1);

  }
}

ISR(TIMER1_COMPA_vect) {
  //OCR1A = (delayValue);  // value to set delay between pulses
  OCR1A = timerTopValue;
  digitalWrite(outputPin, HIGH); //turn on pin 8
  digitalWrite(chargePin, HIGH); //turn on pin 7
  delayPeriodStart = micros();//start looking for response
  trigger = true;
}

ISR(TIMER1_COMPB_vect)
{
  digitalWrite(outputPin, LOW); //turn off pin 8
  digitalWrite(chargePin, LOW); //turn off pin 7
  //delayPeriodStart = micros();//start looking for response
  // trigger = true;
}

void delayPeriodTiming()
{
  delayPeriod = micros() - delayPeriodStart;
  interruptFlag = true;
}


Code: [Select]
void setup() {
 pinMode(4,OUTPUT);
 attachInterrupt(1,pulse,RISING);//interrupt on pin3
}

void loop() {}

void pulse()
{
  delayMicroseconds(1000);
  //delayMicroseconds(0);
  digitalWrite(4,HIGH);
  digitalWrite(4,LOW);
}


Sample output
Code: [Select]
RPM =3800
Period Microseconds =15788
Delay Microseconds =8
Delay Degrees = 0.2


Title: Re: CDI tester project
Post by: tombauer on Oct 08, 2016, 04:55 pm
cattledog,

I copied and pasted your code so as not to have errors. Had to change A5 to A3 for pot, that was the only change I made. Changed the test code to RISING, again only change, and with pot set to max I get:

RPM =3777
Period Microseconds =15884
Delay Microseconds =10892
Delay Degrees = 246.9
Title: Re: CDI tester project
Post by: cattledog on Oct 08, 2016, 04:59 pm
Ae there only two Arduino's involved, or is there some sort of circuitry between them to model the actual test circuit? Is there a low pass filter, from  your noise suppression work, on either the pin 8 line going out or the pin 4 line coming back? If there are more than the two Ardjino's involved, please post the circuit.

Did you run the sample code with Serial monitor output or with the lcd?

EDIT:
Quote
Delay Microseconds =10892
What was the delay setting in the response piece of code?
Title: Re: CDI tester project
Post by: tombauer on Oct 08, 2016, 05:14 pm
cattledog,

Yes just the 2 arduinos, but again I seem to have an issue with the main one. Remember before I got no reading because I thought I had a solder bridge on pin 3? But it didn't look like it so I just redid it and it worked. Now I can change the test code to any delay and get the same results. I never could find any real reason before so now I wonder if the main board has gone whacky?
Title: Re: CDI tester project
Post by: tombauer on Oct 08, 2016, 05:57 pm
cattledog,

test code arduino must have a issue, put in a new one and results at 1000 are

RPM =500
Period Microseconds =120000
Delay Microseconds =1012
Delay Degrees = 3

RPM =3793
Period Microseconds =15816
Delay Microseconds =1012
Delay Degrees = 23.0

with delay at 0

RPM =500
Period Microseconds =120000
Delay Microseconds =from 8 to 12
Delay Degrees = 3

RPM =3764
Period Microseconds =15992
Delay Microseconds =8 to 12
Delay Degrees = 0.2 to 0.3

Tried the test code again with the last revision  and it reports the correct microsec delay, actually about 6 us over but that is probably ok. I think I now need to work on my interface network to get it fine tuned for different CDI. I have some more coming for repair and if they all report the same values that would be a good sign.

working code is now:

Code: [Select]



// revision 6
// CDI Tester Pulse Generator Serial Output Arduino Code
// Advance is 12° at idle and 29° at over xxxx RPM
#include <Wire.h>
int pot1 = A3;            // select the input pin for the pot (changed for this version because of lcd)
int potValue = 0;         // variable to store the value coming from the sensor
int pulseValue = 0;       // 2 variables from one pot
int timerTopValue = 0;    // changed from timerTopValue
int outputPin = 8;        // select the pin for the output for trigger pulse
int chargePin = 7;        // select the pin for the output for charge pulses

volatile boolean trigger = false;
volatile unsigned long delayPeriod;
unsigned long copy_delayPeriod;
volatile unsigned long delayPeriodStart;
float delayDegrees;        // changed from int for decimal place display
int RPM;                   //new
volatile boolean interruptFlag;
unsigned long analogReadInterval = 1000;//read pots and map
unsigned long lastAnalogRead;

#include <LiquidCrystal_I2C.h>
// set the LCD address to 0x3f for a 20 chars 4 line display
// Set the pins on the I2C chip used for LCD connections:
//                    addr, en,rw,rs,d4,d5,d6,d7,bl,blpol
LiquidCrystal_I2C lcd(0x3f, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address

void setup() {
  Serial.begin(9600);
  lcd.begin(20, 4);         // initialize the lcd for 20 chars 4 lines, turn on backlight
  lcd.setCursor(3, 0);      // lcd display setup of unchanging headings
  lcd.print("RPM:");        // print fixed characters
  lcd.setCursor(3, 1);
  lcd.print("Ms:");
  lcd.setCursor(3, 2);
  lcd.print("Us Delay:");       
  lcd.setCursor(3, 3);
  lcd.print("Deg Advance:");

  pinMode(outputPin, OUTPUT);            // declare the outputPin as an OUTPUT
  pinMode(chargePin, OUTPUT);            // declare the chargePin as an OUTPUT
  delay (2000);

  //Timer1 set up 1ms pulse every 50 ms
  TCCR1A = 0;;
  TCCR1B = (1 << WGM12);//CTC mode to OCR1A
  OCR1A = 12500;                                                           //50 ms to top value           
  TIMSK1 |= (1 << OCIE1A);//interrupt enable compareA
  TIMSK1 |= (1 << OCIE1B);//interrupt enable compareB
  OCR1B = 62.5;                                                             //1 ms pulse width was 250, 125 = .5ms
  TCCR1B |= (1 << CS11) | (1 << CS10); //prescaler 64  4us/tick

  attachInterrupt(digitalPinToInterrupt(3), delayPeriodTiming, RISING);

}

void loop()
{
  if (millis() - lastAnalogRead >= analogReadInterval)
  {
    lastAnalogRead += analogReadInterval;
    potValue = analogRead(pot1);
    pulseValue = analogRead(pot1);
    //delayValue = analogRead(pot1);
    RPM = map(potValue, 0, 1023, 500, 3800);
    //potValue = map(potValue, 0, 1023, 500, 3800);                            // to show rpm
    pulseValue = map(pulseValue, 0, 1023, 120, 16);                          // to show ms between pulse out on lcd
    timerTopValue = 15000000UL/RPM;
    //delayValue = map(timerTopValue, 0, 1023, 30000, 6333);                   // used to set delap between pulses out

 
    //lcd.setCursor(3, 0);
    //lcd.print("RPM:");
    lcd.setCursor(8, 0);
    lcd.print("    ");               // print blank spaces to clear old data
    lcd.setCursor(8, 0);
    lcd.print(RPM);                  // changed

    // lcd.setCursor(3, 1);
    // lcd.print("Ms:");
    lcd.setCursor(7, 1);
    lcd.print("    ");
    lcd.setCursor(7, 1);
    lcd.print(pulseValue);

    //lcd.setCursor(3, 2);
    //lcd.print("Us Delay:");
    lcd.setCursor(13, 2);
    lcd.print("       ");       
    lcd.setCursor(13, 2);
    lcd.print(copy_delayPeriod);
   

    //lcd.setCursor(3, 3);
    //lcd.print("Deg Advance:");
    lcd.setCursor(16, 3);
    lcd.print("    ");           
    lcd.setCursor(16, 3);
    lcd.print(delayDegrees,1);
  }

  if (trigger == true && interruptFlag == true )
  {
    trigger = false;
    interruptFlag = false;
    noInterrupts();
    copy_delayPeriod = delayPeriod;
    interrupts();

    //delayDegrees = 360 * (copy_delayPeriod) / (pulseValue * 1000UL);
    delayDegrees = 360.0 * (copy_delayPeriod) / (timerTopValue * 4.0);    // for decimal place in deg display
    //copy_delayPeriod = copy_delayPeriod/1000;                           //value for display to 3 places in us
  }
}

ISR(TIMER1_COMPA_vect) {
  OCR1A = (timerTopValue);                                                 // value to set delay between pulses to trigger cdi
  digitalWrite(outputPin, HIGH); //turn on pin 8
  digitalWrite(chargePin, HIGH); //turn on pin 7
  delayPeriodStart = micros();       //start looking for response
  trigger = true;
}

ISR(TIMER1_COMPB_vect)
{
  digitalWrite(outputPin, LOW);      //turn off pin 8
  digitalWrite(chargePin, LOW);      //turn off pin 7
 
}

void delayPeriodTiming()
{
  delayPeriod = micros() - delayPeriodStart;
  interruptFlag = true;
}




Best, Tom
Title: Re: CDI tester project
Post by: cattledog on Oct 08, 2016, 07:00 pm
Tom--

Quote
Tried the test code again with the last revision  and it reports the correct microsec delay, actually about 6 us over but that is probably ok. I think I now need to work on my interface network to get it fine tuned for different CDI. I have some more coming for repair and if they all report the same values that would be a good sign.
It feels like you are making progress and it will be good to see some data from real cdi units. It will be interesting to see if the same 6 to 12 microseconds at 0 delays are reported at high rpm with the 4213 IC providing the response instead of the Arduino.

The micros() function is limited to +/- 4 microsecond resolution, and it takes a couple of microseconds to enter the interrupts. As you previously said, we are dealing with lawnmowers, and not race cars, so I have opted for the simplicity of micros() and external interrupts, rather than the higher accuracy/precision which could have been achieved with timer input capture to time the delay.



Title: Re: CDI tester project
Post by: tombauer on Oct 08, 2016, 10:55 pm
cattledog,

Hi, I refined my network and except for the 'ring' from the coil primary I have a 5v pulse at pin 3. This does require a good spark so the supply voltage to the CDI has to be either 12v or with the cheap one below, 220vac.

Now with a CDI that does not have delay I get 1 to 2 consistently in the us delay line. However with a cheap Chinese racing CDI that "implies" that it has delay I get 0 across the range. I am not really surprised, they probably just lied about it.

I ordered another one that says it has adjustable delay built in with a internal pot. We will see.
Plus should have some more real Honda ones soon.

 Hope you are having a great weekend, Tom
Title: Re: CDI tester project
Post by: cattledog on Oct 08, 2016, 11:10 pm
Quote
Now with a CDI that does not have delay I get 1 to 2 consistently in the us delay line.
I don't want to rain on your parade, but this makes me a little suspicious. On 16 MHz Arduino boards the micros() function has a resolution of four microseconds (i.e. the value returned is always a multiple of four). The math, since we are subtracting two micros() values form each other, would lead to a value of 0,4,8,12 for measured values of delay if it is near zero.

I'm uncertain if the Chinese cdi really is defective and has no delay or if there is something wrong with your circuit.

The lack of quantization of delay value by four is bothering me.
Title: Re: CDI tester project
Post by: tombauer on Oct 09, 2016, 03:28 am
Yes, I see, I will reconfirm that the module alone it reading correctly now. I added 2 pin connectors that I can jump so I don't need to unsolder things to break sections apart for testing.
I did change this line: unsigned long analogReadInterval = 1000;//read pots and map, to 250 for a more stable read and the delay reading does not jump around as much now. Also changed OCR1B = 62.5; from 250 to make output pulse narrower, seems to be fine with that. My goal today was to get the Arduino to the point where I trusted it to be correct and then work on the interface. Maybe tomorrow I will write some code for the test board to add a display and have a variable delay for testing. Does that sound worthwhile? I was hoping the post would bring some units today but no luck.
Title: Re: CDI tester project
Post by: tombauer on Oct 10, 2016, 12:09 am
cattledog,

Today I put this together just to see.

Code: [Select]


// variable delay output for testing
int pot1 = A3;          // select the input pin for the pot (changed for this version because of lcd)
int delayValue = 0;       // variable to store the value coming from the sensor
unsigned long analogReadInterval = 1000;//read pot and map
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
// set the LCD address to 0x3f for a 20 chars 4 line display
// Set the pins on the I2C chip used for LCD connections:
//                    addr, en,rw,rs,d4,d5,d6,d7,bl,blpol
LiquidCrystal_I2C lcd(0x3f, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address

void setup() {
  Serial.begin(9600);
  lcd.begin(20, 4);         // initialize the lcd for 20 chars 4 lines, turn on backlight
  lcd.setCursor(3, 0);      // lcd display setup of unchanging headings
  lcd.print("Delay:");      // print fixed characters
 
{
   attachInterrupt(1,pulseIn,RISING);
   pinMode(4,OUTPUT);
   
}

}

void loop()
  {
    delayValue = analogRead(delayValue);
    delayValue = map(delayValue, 0, 1023, 0, 3000);                           

    lcd.setCursor(10, 0);
    lcd.print("    ");               //print blank spaces to clear old data
    lcd.setCursor(10, 0);
    lcd.print(delayValue);
    delay (500);
  }

void pulse()
{
  delayMicroseconds(delayValue);
  digitalWrite(4,HIGH);
  digitalWrite(4,LOW);
}




What happens is that the test display shows 'Delay:' and nothing else. If I send the same code to the main arduino, it shows the value from 0 to 3000. I swapped the displays, same result. Then I sent the main code to the test arduino and it shows all data correctly.
Confused, Tom
Title: Re: CDI tester project
Post by: cattledog on Oct 10, 2016, 12:23 am
Code: [Select]
int pot1 = A3;          // select the input pin for the pot (changed for this version because of lcd)
int delayValue = 0;       // variable to store the value coming from the sensor
//delayValue = analogRead(delayValue);
 delayVaue = analogRead(pot1);


You need to read the potentiometer on A3. The code was reading A0.

Title: Re: CDI tester project
Post by: tombauer on Oct 10, 2016, 12:45 am
cattledog,

Well that would make sense to me, but it worked with the main arduino. Still same with test arduino, just says Delay: no data is shown.

I sent the code to the main arduino and it works fine, as does the test board if I sent the CDI program to it.

Code: [Select]


// variable delay output for testing
int pot1 = A3;          // select the input pin for the pot (changed for this version because of lcd)
int delayValue = 0;       // variable to store the value coming from the sensor
unsigned long analogReadInterval = 1000;//read pot and map
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
// set the LCD address to 0x3f for a 20 chars 4 line display
// Set the pins on the I2C chip used for LCD connections:
//                    addr, en,rw,rs,d4,d5,d6,d7,bl,blpol
LiquidCrystal_I2C lcd(0x3f, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address

void setup() {
  Serial.begin(9600);
  lcd.begin(20, 4);         // initialize the lcd for 20 chars 4 lines, turn on backlight
  lcd.setCursor(3, 0);      // lcd display setup of unchanging headings
  lcd.print("Delay:");      // print fixed characters
 
{
   attachInterrupt(1,pulseIn,RISING);
   pinMode(4,OUTPUT);
   
}

}

void loop()
  {
    delayValue = analogRead(pot1);
    delayValue = map(delayValue, 0, 1023, 0, 3000);                           

    lcd.setCursor(10, 0);
    lcd.print("    ");               //print blank spaces to clear old data
    lcd.setCursor(10, 0);
    lcd.print(delayValue);
    delay (500);
  }

void pulse()
{
  delayMicroseconds(delayValue);
  digitalWrite(4,HIGH);
  digitalWrite(4,LOW);
}

Title: Re: CDI tester project
Post by: cattledog on Oct 10, 2016, 01:36 am
The code you posted did not compile due to a misnamed function in attach interrupt. There are also some unnecessary brackets but they were not critical.
This code works fine with Serial. It's a mystery to me how you got it to run
Code: [Select]


// variable delay output for testing
int pot1 = A3;          // select the input pin for the pot (changed for this version because of lcd)
int delayValue = 0;       // variable to store the value coming from the sensor
unsigned long analogReadInterval = 1000;//read pot and map
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
// set the LCD address to 0x3f for a 20 chars 4 line display
// Set the pins on the I2C chip used for LCD connections:
//                    addr, en,rw,rs,d4,d5,d6,d7,bl,blpol
LiquidCrystal_I2C lcd(0x3f, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address

void setup() {
  Serial.begin(9600);
  lcd.begin(20, 4);         // initialize the lcd for 20 chars 4 lines, turn on backlight
  lcd.setCursor(3, 0);      // lcd display setup of unchanging headings
  lcd.print("Delay:");      // print fixed characters

  //{ stray bracket
  //attachInterrupt(1,pulseIn,RISING);//wrong name for isr function
  attachInterrupt(1,pulse,RISING);
  pinMode(4, OUTPUT);
  //} stray bracket
}

void loop()
{
  delayValue = analogRead(pot1);
  delayValue = map(delayValue, 0, 1023, 0, 3000);

  lcd.setCursor(10, 0);
  lcd.print("    ");               //print blank spaces to clear old data
  lcd.setCursor(10, 0);
  lcd.print(delayValue);
  Serial.println(delayValue);
  delay (500);
}

void pulse()
{
  delayMicroseconds(delayValue);
  digitalWrite(4, HIGH);
  digitalWrite(4, LOW);
}
Title: Re: CDI tester project
Post by: tombauer on Oct 10, 2016, 02:46 am
cattledog,

That is indeed a mystery! I had used "attachInterrupt(1,pulse,RISING);" and it would not compile, complaining about that line, so I read about 'pulse' and the only thing I could find was pulseIn, so I tried that and it did compile! But then it would only run on the one arduino and not the other. As far as from a hardwire point of view they are both wired exactly the same.
Well, that's often the kind of day I have! Thanks.
Title: Re: CDI tester project
Post by: tombauer on Oct 12, 2016, 04:44 pm
cattledog,

My test code arduino must have failed. It will load code and the display works but no pulse out. Tried other pin puts, nothing. Waiting for some replacements and refining the feedback interface network.
Tom
Title: Re: CDI tester project
Post by: cattledog on Oct 12, 2016, 05:34 pm
Quote
My test code arduino must have failed. It will load code and the display works but no pulse out. Tried other pin puts, nothing.
Sounds unusual. Are you sure there is not something overloading the output and dragging it down.

Without connecting to your circuit, try some thing like this to see if the pins are responding.

Code: [Select]
void setup() {
Serial.begin(9600);
pinMode(4,OUTPUT);
digitalWrite(4,HIGH);
delay(5);
Serial.println(digitalRead(4));
digitalWrite(4,LOW);
delay(5);
Serial.println(digitalRead(4));
}
void loop() {}


With the circuit not connected, can you read any output with a multimeter?

I sounds like the i2c display and the is pot working so the analog pins may not be damaged if there is indeed something wrong. The analog pins are just the same as digital pins but with additional analogRead() functionality. You could try the output pulse on one of them.
Title: Re: CDI tester project
Post by: tombauer on Oct 12, 2016, 06:12 pm
cattledog,

Looking at the test arduino with a scope there is just no output, I tried different pin out and nothing.
Working with the main board I have a clean 5v pulse at pin 3 and the RPM and Ms display but the Us delay now shows 0 all the time while the degree line does show from a low number to a higher number.I have been remarking the coding changes as revisions and this is rev 6

Code: [Select]

// revision 6
// CDI Tester Pulse Generator Serial Output Arduino Code
// Advance is 12° at idle and 29° at over xxxx RPM
#include <Wire.h>
int pot1 = A3;            // select the input pin for the pot (changed for this version because of lcd)
int potValue = 0;         // variable to store the value coming from the sensor
int pulseValue = 0;       // 2 variables from one pot
int timerTopValue = 0;    // changed from timerTopValue
int outputPin = 8;        // select the pin for the output for trigger pulse
int chargePin = 7;        // select the pin for the output for charge pulses

volatile boolean trigger = false;
volatile unsigned long delayPeriod;
unsigned long copy_delayPeriod;
volatile unsigned long delayPeriodStart;
float delayDegrees;        // changed from int for decimal place display
int RPM;                   //new
volatile boolean interruptFlag;
unsigned long analogReadInterval = 250;//read pots and map
unsigned long lastAnalogRead;

#include <LiquidCrystal_I2C.h>
// set the LCD address to 0x3f for a 20 chars 4 line display
// Set the pins on the I2C chip used for LCD connections:
//                    addr, en,rw,rs,d4,d5,d6,d7,bl,blpol
LiquidCrystal_I2C lcd(0x3f, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address

void setup() {
  Serial.begin(9600);
  lcd.begin(20, 4);         // initialize the lcd for 20 chars 4 lines, turn on backlight
  lcd.setCursor(1, 0);      // lcd display setup of unchanging headings
  lcd.print("RPM:");        // print fixed characters
  lcd.setCursor(1, 1);
  lcd.print("Ms:");
  lcd.setCursor(1, 2);
  lcd.print("Us Delay:");       
  lcd.setCursor(1, 3);
  lcd.print("Deg Advance:");

  pinMode(outputPin, OUTPUT);            // declare the outputPin as an OUTPUT
  pinMode(chargePin, OUTPUT);            // declare the chargePin as an OUTPUT
  delay (2000);

  //Timer1 set up 1ms pulse every 50 ms
  TCCR1A = 0;;
  TCCR1B = (1 << WGM12);//CTC mode to OCR1A
  OCR1A = 12500;                                                           //50 ms to top value           
  TIMSK1 |= (1 << OCIE1A);//interrupt enable compareA
  TIMSK1 |= (1 << OCIE1B);//interrupt enable compareB
  OCR1B = 62.5;                                                             //1 ms pulse width was 250, 125 = .5ms
  TCCR1B |= (1 << CS11) | (1 << CS10); //prescaler 64  4us/tick

  attachInterrupt(digitalPinToInterrupt(3), delayPeriodTiming, RISING);

}

void loop()
{
  if (millis() - lastAnalogRead >= analogReadInterval)
  {
    lastAnalogRead += analogReadInterval;
    potValue = analogRead(pot1);
    pulseValue = analogRead(pot1);
    //delayValue = analogRead(pot1);
    RPM = map(potValue, 0, 1023, 500, 3800);
    //potValue = map(potValue, 0, 1023, 500, 3800);                            // to show rpm
    pulseValue = map(pulseValue, 0, 1023, 120, 16);                          // to show ms between pulse out on lcd
    timerTopValue = 15000000UL/RPM;
    //delayValue = map(timerTopValue, 0, 1023, 30000, 6333);                   // used to set delap between pulses out

 
    //lcd.setCursor(3, 0);
    //lcd.print("RPM:");
    lcd.setCursor(6, 0);
    lcd.print("    ");               // print blank spaces to clear old data
    lcd.setCursor(6, 0);
    lcd.print(RPM);                  // changed

    // lcd.setCursor(3, 1);
    // lcd.print("Ms:");
    lcd.setCursor(5, 1);
    lcd.print("    ");
    lcd.setCursor(5, 1);
    lcd.print(pulseValue);

    //lcd.setCursor(3, 2);
    //lcd.print("Us Delay:");
    lcd.setCursor(11, 2);
    lcd.print("       ");       
    lcd.setCursor(11, 2);
    lcd.print(copy_delayPeriod);
   

    //lcd.setCursor(3, 3);
    //lcd.print("Deg Advance:");
    lcd.setCursor(14, 3);
    lcd.print("      ");           
    lcd.setCursor(14, 3);
    lcd.print(delayDegrees,1);
  }

  if (trigger == true && interruptFlag == true )
  {
    trigger = false;
    interruptFlag = false;
    noInterrupts();
    copy_delayPeriod = delayPeriod;
    interrupts();

    //delayDegrees = 360 * (copy_delayPeriod) / (pulseValue * 1000UL);
    delayDegrees = 360.0 * (copy_delayPeriod) / (timerTopValue * 4.0);    // for decimal place in deg display
    copy_delayPeriod = copy_delayPeriod/1000;                           //value for display to 3 places in us
  }
}

ISR(TIMER1_COMPA_vect) {
  OCR1A = (timerTopValue);                                                 // value to set delay between pulses to trigger cdi
  digitalWrite(outputPin, HIGH); //turn on pin 8
  digitalWrite(chargePin, HIGH); //turn on pin 7
  delayPeriodStart = micros();       //start looking for response
  trigger = true;
}

ISR(TIMER1_COMPB_vect)
{
  digitalWrite(outputPin, LOW);      //turn off pin 8
  digitalWrite(chargePin, LOW);      //turn off pin 7
 
}

void delayPeriodTiming()
{
  delayPeriod = micros() - delayPeriodStart;
  interruptFlag = true;
}
Title: Re: CDI tester project
Post by: tombauer on Oct 12, 2016, 09:02 pm
cattledog,

I tried your test with nothing at all connected to the main arduino. It responds 1 then 0 once and nothing more unless I push reset then I get 1 and 0 and stops. I then tried it on pin 3 and got 0  0.
Tried it on pin 5 and got 1  0
Title: Re: CDI tester project
Post by: cattledog on Oct 12, 2016, 09:20 pm
Quote
Looking at the test arduino with a scope there is just no output, I tried different pin out and nothing.
Quote
I tried your test with nothing at all connected to the main arduino. It responds 1 then 0 once and nothing more unless I push reset then I get 1 and 0 and stops. I then tried it on pin 3 and got 0  0.
Tried it on pin 5 and got 1  0
I don't know about the scope, but it would appear that you are indeed getting output. I don't understand why pin 3 won't respond.

The test was in set up so it would only run once.

I'm not sure why the test arduino is not putting out a signal that the main arduino can read, but I would not be so certain it is broken.
Title: Re: CDI tester project
Post by: tombauer on Oct 12, 2016, 10:10 pm
Test arduino just does not put out pulse. It did before, it must have gone bad. Main arduino has 9k ohms from each pin to ground but has 50 ohms in each direction from pin 3 to ground so it must also be bad. It will not accept pulse input on any other pin as well. At $4 each I guess I cannot expect to much. New ones in a couple of days.
Tom
Title: Re: CDI tester project
Post by: cattledog on Oct 13, 2016, 12:35 am
Quote
It will not accept pulse input on any other pin as well
The two external interrupt pins are 2 and 3. Try pin 2 with
Code: [Select]
attachInterrupt(digitalPinToInterrupt(2), delayPeriodTiming, RISING);


Title: Re: CDI tester project
Post by: tombauer on Oct 13, 2016, 06:58 pm
cattledog,

I tried several things,  first I moved the input to pin 2. Then I moved the output on test board to pin 7 since 8 does not work anymore. So now sometimes the display does show what the test board is set at and sometimes it just shows 0 or random numbers. When I change the delay setting on the test board with its pot, should the main arduino display follow?? I have to reset the board with every change of the test unit.
Title: Re: CDI tester project
Post by: cattledog on Oct 13, 2016, 07:25 pm
Quote
I tried several things,  first I moved the input to pin 2. Then I moved the output on test board to pin 7 since 8 does not work anymore
First, I am confused about which board (arduino) is the "test board". Is the "test board" the board simulating the delay of a CDI, and is the "main" board the one measuring the delay from a CDI unit or from the "test" board?

Both boards use an interrupt on pin 2 or pin 3 so I'm not clear which one was moved.

As I understand it, the "main" board outputs a trigger pulse on pin 8 to the "test" board input on pin 2 or 3. The "test" board originally had an output on pin 4 back to the interrupt input pin of the "main" board. Is that pin 4 output on the "test" board broken and it was switched to pin 7?

Quote
When I change the delay setting on the test board with its pot, should the main arduino display follow??
Yes

Quote
I have to reset the board with every change of the test unit.
I don't understand this. The two programs and two arduinos should be independent of each other.

Can you please provide a sketch of how you have the two boards connected, and the two pieces of code.
Title: Re: CDI tester project
Post by: tombauer on Oct 13, 2016, 07:53 pm
First, I am confused about which board (arduino) is the "test board". Is the "test board" the board simulating the delay of a CDI, and is the "main" board the one measuring the delay from a CDI unit or from the "test" board?

Yes

Both boards use an interrupt on pin 2 or pin 3 so I'm not clear which one was moved.

Both, as they had some failure test board is input on 3 and output on 7 now, main is input on 2 and output on 8.

As I understand it, the "main" board outputs a trigger pulse on pin 8 to the "test" board input on pin 2. The "test" board originally had an output on pin 4 back to the interrupt input pin of the "main" board. Is that pin 4 output on the "test" board broken and it was switched to pin 7?

Yes

I don't understand this. The two programs and two arduinos should be independent of each other.

I feel they simply had some static related failure. I will have new ones maybe later today.

Can you please provide a sketch of how you have the two boards connected, and the two pieces of code.
Code: [Select]

// revision 6 draft, some small changes from 6
// CDI Tester Pulse Generator Serial Output Arduino Code
// Advance is 12° at idle and 29° at over xxxx RPM

int pot1 = A3;            // select the input pin for the pot (changed for this version because of lcd)
int potValue = 0;         // variable to store the value coming from the sensor
int pulseValue = 0;       // 2 variables from one pot
int timerTopValue = 0;    // changed from timerTopValue
int outputPin = 8;        // select the pin for the output for trigger pulse
int chargePin = 7;        // select the pin for the output for charge pulses

volatile boolean trigger = false;
volatile unsigned long delayPeriod;
unsigned long copy_delayPeriod;
volatile unsigned long delayPeriodStart;
float delayDegrees;                           // changed from int for decimal place display
int RPM;                                      //new
volatile boolean interruptFlag;
unsigned long analogReadInterval = 250;       //read pots and map
unsigned long lastAnalogRead;
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
// set the LCD address to 0x3f for a 20 chars 4 line display
// Set the pins on the I2C chip used for LCD connections:
//                    addr, en,rw,rs,d4,d5,d6,d7,bl,blpol
LiquidCrystal_I2C lcd(0x3f, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address

void setup() {
  Serial.begin(9600);
  lcd.begin(20, 4);         // initialize the lcd for 20 chars 4 lines, turn on backlight
  lcd.setCursor(1, 0);      // lcd display setup of unchanging headings
  lcd.print("RPM:");        // print fixed characters
  lcd.setCursor(1, 1);
  lcd.print("Ms:");
  lcd.setCursor(1, 2);
  lcd.print("Us Delay:");
  lcd.setCursor(1, 3);
  lcd.print("Deg Advance:");

  pinMode(outputPin, OUTPUT);            // declare the outputPin as an OUTPUT
  pinMode(chargePin, OUTPUT);            // declare the chargePin as an OUTPUT
  delay (2000);

  //Timer1 set up 1ms pulse every 50 ms
  TCCR1A = 0;;
  TCCR1B = (1 << WGM12);//CTC mode to OCR1A
  OCR1A = 12500;                                                           //50 ms to top value           
  TIMSK1 |= (1 << OCIE1A);//interrupt enable compareA
  TIMSK1 |= (1 << OCIE1B);//interrupt enable compareB
  OCR1B = 125;                                                             //1 ms pulse width was 250, 125 = .5ms
  TCCR1B |= (1 << CS11) | (1 << CS10); //prescaler 64  4us/tick

  attachInterrupt(digitalPinToInterrupt(2), delayPeriodTiming, RISING);

}

void loop()
{
  if (millis() - lastAnalogRead >= analogReadInterval)
  {
    lastAnalogRead += analogReadInterval;
    potValue = analogRead(pot1);
    pulseValue = analogRead(pot1);
    RPM = map(potValue, 0, 1023, 500, 3800);
    pulseValue = map(pulseValue, 0, 1023, 120, 16);                          // to show ms between pulse out on lcd
    timerTopValue = 15000000UL/RPM;

    lcd.setCursor(6, 0);
    lcd.print("    ");               // print blank spaces to clear old data
    lcd.setCursor(6, 0);
    lcd.print(RPM);

    lcd.setCursor(5, 1);
    lcd.print("    ");
    lcd.setCursor(5, 1);
    lcd.print(pulseValue);

    lcd.setCursor(11, 2);
    lcd.print("       ");
    lcd.setCursor(11, 2);
    lcd.print(copy_delayPeriod);

    lcd.setCursor(14, 3);
    lcd.print("    ");
    lcd.setCursor(14, 3);
    lcd.print(delayDegrees,1);
  }

  if (trigger == true && interruptFlag == true )
  {
    trigger = false;
    interruptFlag = false;
    noInterrupts();
    copy_delayPeriod = delayPeriod;
    interrupts();

    delayDegrees = 360.0 * (copy_delayPeriod) / (timerTopValue * 4.0);  // for decimal place in deg display
    //copy_delayPeriod = copy_delayPeriod/1000;                           //value for display to 3 places in us
  }
}

ISR(TIMER1_COMPA_vect) {
  OCR1A = (timerTopValue);                                              // value to set delay between pulses to trigger cdi
  digitalWrite(outputPin, HIGH); //turn on pin 8
  digitalWrite(chargePin, HIGH); //turn on pin 7
  delayPeriodStart = micros();                                          //start looking for response
  trigger = true;
}

ISR(TIMER1_COMPB_vect)
{
  digitalWrite(outputPin, LOW);      //turn off pin 8
  digitalWrite(chargePin, LOW);      //turn off pin 7

}

void delayPeriodTiming()
{
  delayPeriod = micros() - delayPeriodStart;
  interruptFlag = true;
}


Code: [Select]


// variable delay output for testing
// with display
int pot1 = A3;          // select the input pin for the pot (changed for this version because of lcd)
int delayValue = 0;       // variable to store the value coming from the sensor
unsigned long analogReadInterval = 1000;//read pot and map
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
// set the LCD address to 0x3f for a 20 chars 4 line display
// Set the pins on the I2C chip used for LCD connections:
//                    addr, en,rw,rs,d4,d5,d6,d7,bl,blpol
LiquidCrystal_I2C lcd(0x3f, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address

void setup() {
  Serial.begin(9600);
  lcd.begin(20, 4);         // initialize the lcd for 20 chars 4 lines, turn on backlight
  lcd.setCursor(3, 0);      // lcd display setup of unchanging headings
  lcd.print("Delay:");      // print fixed characters
 
   attachInterrupt(1,pulse,RISING);
   pinMode(7,OUTPUT);
   
}

void loop()
  {
    delayValue = analogRead(pot1);
    delayValue = map(delayValue, 0, 1023, 0, 3000);                           

    lcd.setCursor(10, 0);
    lcd.print("    ");               //print blank spaces to clear old data
    lcd.setCursor(10, 0);
    lcd.print(delayValue);
    delay (500);
  }

void pulse()
{
  delayMicroseconds(delayValue);
  digitalWrite(7,HIGH);
  digitalWrite(7,LOW);
}

Title: Re: CDI tester project
Post by: tombauer on Oct 13, 2016, 11:37 pm
cattledog,

Hi, I want  to be sure I understand this correctly. On the test board digitalWrite(7,HIGH); and
  digitalWrite(7,LOW); cause the pin to be tied to 5v or be then tied to gnd? The reason I want to be sure is that the digital pin that is watching this on the main board is high impedance above ground and picks up any noise (RFI). So if I am correct, the pin 7 out on the test board may be giving a pulse of 5v but then is just open instead of gnd. That would explain why now I get a good reading at times but mostly just noise (to many digits that mean nothing). I swapped out the main board but did not have time to change the test board. I assume that when I do it will start working.
Best, Tom
Title: Re: CDI tester project
Post by: cattledog on Oct 14, 2016, 12:42 am
Quote
On the test board digitalWrite(7,HIGH); and
  digitalWrite(7,LOW); cause the pin to be tied to 5v or be then tied to gnd?
Yes, that is correct. The pin is not floating when LOW. It is connected to ground.
Title: Re: CDI tester project
Post by: tombauer on Oct 14, 2016, 07:44 pm
Hello my friend,
 Well there is something strange going on that I just don't see. I got some new arduinos, this time they are 168p 5v 16mhz pro mini, and I run this code.

Code: [Select]

void setup() {
Serial.begin(9600);
pinMode(7,OUTPUT);
digitalWrite(7,HIGH);
delay(5);
Serial.println(digitalRead(7));
digitalWrite(7,LOW);
delay(5);
Serial.println(digitalRead(7));
}
void loop() {}


 I get a return of 1,0 so it can output ok. Then i run code of

Code: [Select]
void setup() {
 pinMode(7,OUTPUT);
 attachInterrupt(1,pulse,RISING);
}

void loop() {
  // put your main code here, to run repeatedly:

}

void pulse()
{
  delayMicroseconds(1822);
  digitalWrite(7,HIGH);
  digitalWrite(7,LOW);
}


And nothing on output pin 7 with a good 5v pulse on pin 3.
What am I missing?
Tom
Title: Re: CDI tester project
Post by: tombauer on Oct 14, 2016, 09:07 pm
What I think I see here is that both arduinos are ignoring or doing something else with the line :
attachInterrupt(1,pulse,RISING);
on both I am using pin 3 for input.
Title: Re: CDI tester project
Post by: tombauer on Oct 14, 2016, 09:51 pm
On test board I changed the code

Code: [Select]

//attachInterrupt(1,pulse,RISING);
   attachInterrupt(digitalPinToInterrupt(3),pulse, RISING);


This made the board have pulse out on pin7, it is 5v but is so fast it barely shows up on scope.
This is in the code
// variable delay output for testing
// with display

The main board registers it most of the time but I have to reset board each time to see changes??
Title: Re: CDI tester project
Post by: tombauer on Oct 14, 2016, 10:22 pm
cattledog,

Major progress but I don't understand why it was needed (the code changes)
Please see the 2 lines with the ** at the end. The main board now shows Ms Delay at very close to what the test board display says. Also for some strange reason now able to see delay on scope! I want to understand why this code works when the seemingly same code written differently would not??
Now to further refine the feedback network for reading the actual delay from CDI. I hope.

Code: [Select]


// variable delay output for testing
// with display
int pot1 = A3;            // select the input pin for the pot (changed for this version because of lcd)
int delayValue = 0;       // variable to store the value coming from the sensor
unsigned long analogReadInterval = 1000;//read pot and map
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
// set the LCD address to 0x3f for a 20 chars 4 line display
// Set the pins on the I2C chip used for LCD connections:
//                    addr, en,rw,rs,d4,d5,d6,d7,bl,blpol
LiquidCrystal_I2C lcd(0x3f, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address

void setup() {
  Serial.begin(9600);
  lcd.begin(20, 4);         // initialize the lcd for 20 chars 4 lines, turn on backlight
  lcd.setCursor(3, 0);      // lcd display setup of unchanging headings
  lcd.print("Delay:");      // print fixed characters
 
   //attachInterrupt(1,pulse,RISING);                                       //remove this line and
   attachInterrupt(digitalPinToInterrupt(3),pulse, RISING);                 //added this line to have any pulse out**********
   pinMode(7,OUTPUT);
   
}

void loop()
  {
    delayValue = analogRead(pot1);
    delayValue = map(delayValue, 0, 1023, 0, 3000);                           

    lcd.setCursor(10, 0);
    lcd.print("    ");               //print blank spaces to clear old data
    lcd.setCursor(10, 0);
    lcd.print(delayValue);
    delay (500);
  }

void pulse()
{
  delayMicroseconds(delayValue);
  digitalWrite(7,HIGH);
  delay(1);                                                                 //added so pulse would register on main board**********
  digitalWrite(7,LOW);
}

Title: Re: CDI tester project
Post by: cattledog on Oct 15, 2016, 12:54 am

Quote
Major progress but I don't understand why it was needed (the code changes)
Please see the 2 lines with the ** at the end
Code: [Select]
//attachInterrupt(1,pulse,RISING);  //remove this line and
   attachInterrupt(digitalPinToInterrupt(3),pulse, RISING); //added this line to have any pulse out


These two lines would appear equivalent, but possibly when the IDE was changed to support the digitalPinTo Interrupt() syntax there was a change I don't understand. You could try the attachInterrupt(1, pulse, RISING) with an explicit pinMode(3,INPUT) to see if that clears the mystery. If it doesn't, just use the new syntax and be thankful you fixed the problem.

Code: [Select]
digitalWrite(7,HIGH);
delay(1);  //added so pulse would register on main board**********
digitalWrite(7,LOW);


I could understand that you needed a longer pulse than the two microseconds of the digitalWrite() HIGH/LOW pair to see it on the scope. The interrupt on the main board should have seen it. It certainly did in all my testing on paired Arduinos.  Is there some sort of low pass filter or noise suppression on the input which is conditioning the pulse?

Do you know how long a pulse you will see out of an actual CDI? The main board interrupt is looking for a rising edge, and should be very fast. You could try changing the test board pulse width by using delayMicroseconds() and determining where the interrupt stops responding.

Code: [Select]
digitalWrite(7,HIGH);
delayMicroseconds(100);  // modify the pulse length to see what is sensed by main board*******
digitalWrite(7,LOW);
Title: Re: CDI tester project
Post by: tombauer on Oct 15, 2016, 04:10 am
cattledog,

No, there is nothing between the 2 boards, main pin 8 out and pin 3 in, and test pin 7 out and pin 3 in.
I had to set delay(2) to get main board to read reliably. So I have to wonder if there is a code problem with main board? I agree it should read without the delay on test board but it does not. Also on the scope the pulse out from test looks longer and certainly far more jittery that the pulse out from main. Also I have 2 Chinese CDI which say they have delay and obviously do not. No big surprise a lot of the Chinese stuff is fake and misrepresented.
Title: Re: CDI tester project
Post by: cattledog on Oct 15, 2016, 06:23 am
Quote
I had to set delay(2) to get main board to read reliably. So I have to wonder if there is a code problem with main board?
Code: [Select]
unsigned long analogReadInterval = 250;

On thing I would like to see you try is to that the analogRead() period of the main board pot back to one second. When I was testing earlier, the analogRead() every pass through loop() was creating problems. It is a blocking function and takes around 100 microseconds to execute. You still do two reads, even thought they are duplicates.

That is the major thing I see presently wrong with the main board code, and is not how I tested.

One other area to explore is the lcd display in the main board code. All my testing has been with Serial output. If you can set up without the lcd you might see if it is creating any problems. Actually. what would be best is if you have two additional arduinos you can remove from your real world testing apparatus and just test separately without noise and using Serial output, you can sort out any issues of code from the environment. I have tested the code fairly intensively and don't understand many of the problems you have encountered over the course of this thread.

You can also see what happens if you cut down the lcd display and only print the RPM and the copy_delayPeriod. Does the main board look any more responsive?


Quote
Also on the scope the pulse out from test looks longer and certainly far more jittery that the pulse out from main.
The pulse out from the main board is .5ms and the pulse from the test board is 1 or maybe 2 ms, so longer is to be expected. "Jittery"  ??

I really do not understand the necessity for a 2 ms pulse width for the main board to respond. The code is interrupt based and edge detect driven. Pulse width should not be a factor. It really should not matter to the main board what follows the leading edge. If there is noise on the lead edge of the pulse and the interrupt triggers several times, it can only make the calculation of delayPeriod slightly longer as micros() increases. 

You need to ensure that there is very good ground connection between the two boards.
Title: Re: CDI tester project
Post by: tombauer on Oct 15, 2016, 03:40 pm
cattledog,

OK, I took your advise and set read time back to 1 sec, made test code to 100us. The test pulse out was changing width, that is what I meant by jittery. With 100us it is good now, must have been some timing issue.

Since we are working on pulse issues, please explain how the pulse width out on the main board is controlled? It is 1.5 millisec wide at present and that may be just fine since it is now working, I just want to fully understand the code.

I will now work on getting a real CDI to input correctly.

Tom
Title: Re: CDI tester project
Post by: cattledog on Oct 15, 2016, 05:01 pm
Good progress Tom.

Quote
please explain how the pulse width out on the main board is controlled? It is 1.5 millisec wide at present and that may be just fine since it is now working, I just want to fully understand the code.
The pulse out on the main board is generated from Timer1. I explained this a time ago,  in the original thread about the cdi testor and problems with the tft display.
http://forum.arduino.cc/index.php?topic=424874.msg2927434#msg2927434 (http://forum.arduino.cc/index.php?topic=424874.msg2927434#msg2927434)

Code: [Select]

  //Timer1 set up pulse every 50 ms
  TCCR1A = 0;;
  TCCR1B = (1 << WGM12);//CTC mode to OCR1A
  OCR1A = 12500;                                                           //50 ms to top value           
  TIMSK1 |= (1 << OCIE1A);//interrupt enable compareA
  TIMSK1 |= (1 << OCIE1B);//interrupt enable compareB
  OCR1B = 125;                                                             //1 ms pulse width was 250, 125 = .5ms
  TCCR1B |= (1 << CS11) | (1 << CS10); //prescaler 64  4us/tick


Code: [Select]
ISR(TIMER1_COMPA_vect) {
  OCR1A = (timerTopValue);                                              // value to set delay between pulses to trigger cdi
  digitalWrite(outputPin, HIGH); //turn on pin 8
  digitalWrite(chargePin, HIGH); //turn on pin 7
  delayPeriodStart = micros();                                          //start looking for response
  trigger = true;
}

ISR(TIMER1_COMPB_vect)
{
  digitalWrite(outputPin, LOW);      //turn off pin 8
  digitalWrite(chargePin, LOW);      //turn off pin 7

}


If OCR1B is still set at 125, then the pulse width will be .5ms and not 1.5.  Throughout this thread, I have learned to not trust your scope  ;)
Title: Re: CDI tester project
Post by: tombauer on Oct 15, 2016, 07:15 pm
cattledog,

Thanks for bearing with me. This is a huge learning experience  with some relearning! My scope is 50 years old, but as you may know Tektronix equipment lasts forever. About all I ever used it for was signal tracing and setting the eye pattern on early CD players. I had some problems with measuring the delay on the scope and now I don't really know why. It is now showing exactly what would be expected. I set the OCR1B to 500 and it shows pulse width of exactly 2Ms and I can now see and confirm the timing shift in real time. Thanks for all the help, I am going to segue over to using a CDI instead of the test board and see the results.
Tom
Title: Re: CDI tester project
Post by: tombauer on Oct 16, 2016, 07:27 pm
cattledog,

As I narrow down on problems, it looks like in the real world the CDI sends the output pulse to the coil on the falling edge of the pulse from pin 8 on main board. To confirm that I set OCR1B = 250; and scope still shows it coming out of CDI on falling edge. Set it to 80 and falling edge. With it set to 250 the Us delay reads 1184 or 1188. With it set to 80 the Us line reads 652 to 656. The readings are not very stable at low rpm but very good at higher settings. So how do I make the code read from falling edge of pulse on pin 3?? Way to make readings more stable?
Tom
Title: Re: CDI tester project
Post by: cattledog on Oct 16, 2016, 08:35 pm
Quote
So how do I make the code read from falling edge of pulse on pin 3??
Interesting. This the way we used to have the code.

To measure the delay from the end of the trigger pulse instead of from the start, move this code from the TIMER1_COMPA_vect  back to the TIMER1_COMPB_vect. You can see that one of these routines is writing the output pin trigger pulse HIGH and the other one writes it LOW. Start the delay time from which ever one you want.

Code: [Select]
delayPeriodStart = micros();//start looking for response
  trigger = true;


Code: [Select]
ISR(TIMER1_COMPA_vect) {
  OCR1A = timerTopValue;
  digitalWrite(outputPin, HIGH); //turn on pin 8
  digitalWrite(chargePin, HIGH); //turn on pin 7
  //delayPeriodStart = micros();//start looking for response
 // trigger = true;
}

ISR(TIMER1_COMPB_vect)
{
  digitalWrite(outputPin, LOW); //turn off pin 8
  digitalWrite(chargePin, LOW); //turn off pin 7
  delayPeriodStart = micros();//start looking for response
  trigger = true;
}


When you change this, you should also change the code of the test board program so that its interrupt responds to the FALLING to match the real CDI.
Code: [Select]
attachInterrupt(digitalPinToInterrupt(3),pulse, FALLING);

To be clear, only change this on the test board program. The main board program wants to read the RISING edge of the delayed return pulse.


Quote
The readings are not very stable at low rpm but very good at higher settings.
Way to make readings more stable?
You will have to explain more about what you are seeing.

Are you seeing issues relating to the microseconds values having a minimum resolution of 4 and variations of 4,8,12 units between readings, or is there something of a larger magnitude that's the problem? Can you post some actual data?


Title: Re: CDI tester project
Post by: tombauer on Oct 16, 2016, 08:55 pm
cattledog,

"To be clear, only change this on the test board program. The main board program wants to read the RISING edge of the delayed return pulse."

OK yes I understand, but I don't think there is need to change it on test board as the display from it matched main board.

This 'issue' must be because the actual CDI triggers off the falling edge to fire coil so the main board looking at coil pulse must take that into account. Make sense?

I just realized that some of the CDI I have been using have rev limited so they cancel spark above certain RPM and in an unknown way so this must play hell with the counting!! I will change that code and find a CDI with no limiter and reassess the problem, it may not be real. At 2000 RPM the value returned is 1184, 1188, and 1192 with occasional jumps to 1048.

Thanks, Tom
Title: Re: CDI tester project
Post by: cattledog on Oct 16, 2016, 09:11 pm
Quote
This 'issue' must be because the actual CDI triggers off the falling edge to fire coil so the main board looking at coil pulse must take that into account. Make sense?
Yes this make sense. But your other statement does not.

Quote
but I don't think there is need to change it on test board as the display from it matched main board.
If the actual CDI unit fires from the falling edge of the trigger, then the simulator should fire from the falling edge as well, or else the measured delay times at the main board (once you change it to start timing from the end of the trigger pulse) will all be longer by the length of the trigger pulse when using the test board instead of a real CDI.
Title: Re: CDI tester project
Post by: tombauer on Oct 16, 2016, 09:20 pm
OK, I agree with that, and the test board should be as accurate as possible. I changed the main board code and at 1000 RPM the delay reads 88Us and at 2000 it reads 96Us at 2800 reads 100Us. I will change test code and recheck.
Tom
Title: Re: CDI tester project
Post by: tombauer on Oct 16, 2016, 10:00 pm
cattledog,

With test code changed to falling, 0 on test gives 8 or 12 on main, mostly 8. atest at 3000 gives 3004 to 3008 on main.

All the testing so far has been using mains supply, isolated, for high voltage to CDI. This means there are times when the SRC is firing and the AC cycle is at a peak. I really have no idea what this may have been doing to the stability of readings. I am still waiting on some 5v supplies to power the main board and then use an adjustable supply to power the output pulse since technically it is weak compared to real life.

Tom
Title: Re: CDI tester project
Post by: tombauer on Oct 18, 2016, 10:37 pm
cattledog,

The read for the Us delay line happens every second, right? I see that analog inputs can have many reads per time unit and averaging. That may not be the best as the erroneous displays are very large compared to the correct info. Can data that is way off just be thrown out? Or is there a way to make that read and display more stable? It seems to be accurate but there are little snippets of noise that must be at just the right place at just the right time to cause an error every so many reads. (maybe 1 out of 6 to 8)

Tom
Title: Re: CDI tester project
Post by: cattledog on Oct 19, 2016, 08:42 am
Quote
It seems to be accurate but there are little snippets of noise that must be at just the right place at just the right time to cause an error every so many read.
How big are these errors?  

I know that the analogRead() can introduce an error up to 100us in the delay timing, because all the time stamps for delay timing are within ISR's and they won't be created until analogRead() returns a value if it is off taking one. That is why I want the potentiometer readings kept to a minimum.  I am working on a version of the code which uses a non-blocking variation of analogRead() but I don't have it completed or tested.

If the errors are much larger than that, then it is probably noise or a real error for some reason.

The delay values should be created every trigger cycle, which is at least 10x faster than the display cycle. The last value is what is currently displayed, so we can definitely work in some averaging but, as you say, averaging an erroneous value is not good.

Here's a version of the code which requires a delay reading to be "close" to the average of the previous four to be accepted. Otherwise it is replaced by the average.  If this happens three times in a row, there is an error reported and printed on the lcd. You may see some errors when you change the rpm and the delay actually changes.

I have modified the last posted code(rev6 draft) adding the previous revisions to the Timer Compare Match interrupts, and the analogRead() at 1 second. I'm not sure if the interrupt and output pin assignments are correct, so you may have to clean this up a little.  Try this code and see if it does what you want with the erratic data?

Code: [Select]

// revision 6 draft, some small changes from 6
// CDI Tester Pulse Generator Serial Output Arduino Code
// Advance is 12° at idle and 29° at over xxxx RPM

int pot1 = A3;            // select the input pin for the pot (changed for this version because of lcd)
int potValue = 0;         // variable to store the value coming from the sensor
int pulseValue = 0;       // 2 variables from one pot
int timerTopValue = 0;    // changed from timerTopValue
int outputPin = 8;        // select the pin for the output for trigger pulse
int chargePin = 7;        // select the pin for the output for charge pulses

volatile boolean trigger = false;
volatile unsigned long delayPeriod;
unsigned long copy_delayPeriod;
volatile unsigned long delayPeriodStart;
float delayDegrees;                           // changed from int for decimal place display
int RPM;                                      //new
volatile boolean interruptFlag;
unsigned long analogReadInterval = 1000;       //read pots and map
unsigned long lastAnalogRead;

//additional variables for error checking and smoothing
byte errorValue = 50;
byte errorCount = 0;
boolean errorFlag = false;
byte readingCount = 0;
boolean averageReady = false;
unsigned long average_delayPeriod;

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
// set the LCD address to 0x3f for a 20 chars 4 line display
// Set the pins on the I2C chip used for LCD connections:
//                    addr, en,rw,rs,d4,d5,d6,d7,bl,blpol
LiquidCrystal_I2C lcd(0x3f, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address

void setup() {
  //Serial.begin(115200);
  lcd.begin(20, 4);         // initialize the lcd for 20 chars 4 lines, turn on backlight
  lcd.setCursor(1, 0);      // lcd display setup of unchanging headings
  lcd.print("RPM:");        // print fixed characters
  lcd.setCursor(1, 1);
  lcd.print("Ms:");
  lcd.setCursor(1, 2);
  lcd.print("Us Delay:");
  lcd.setCursor(1, 3);
  lcd.print("Deg Advance:");

  pinMode(outputPin, OUTPUT);            // declare the outputPin as an OUTPUT
  pinMode(chargePin, OUTPUT);            // declare the chargePin as an OUTPUT
  delay (2000);

  //Timer1 set up 1ms pulse every 50 ms
  TCCR1A = 0;;
  TCCR1B = (1 << WGM12);//CTC mode to OCR1A
  OCR1A = 12500;                                                           //50 ms to top value
  TIMSK1 |= (1 << OCIE1A);//interrupt enable compareA
  TIMSK1 |= (1 << OCIE1B);//interrupt enable compareB
  OCR1B = 125;                                                             //1 ms pulse width was 250, 125 = .5ms
  TCCR1B |= (1 << CS11) | (1 << CS10); //prescaler 64  4us/tick

  attachInterrupt(digitalPinToInterrupt(2), delayPeriodTiming, RISING);

}

void loop()
{
  if (millis() - lastAnalogRead >= analogReadInterval)
  {
    lastAnalogRead += analogReadInterval;
    potValue = analogRead(pot1);
    pulseValue = analogRead(pot1);
    RPM = map(potValue, 0, 1023, 500, 3800);
    pulseValue = map(pulseValue, 0, 1023, 120, 16);                          // to show ms between pulse out on lcd
    timerTopValue = 15000000UL / RPM;

    if (averageReady)
    {
      lcd.setCursor(6, 0);
      lcd.print("    ");               // print blank spaces to clear old data
      lcd.setCursor(6, 0);
      lcd.print(RPM);

      lcd.setCursor(5, 1);
      lcd.print("    ");
      lcd.setCursor(5, 1);
      lcd.print(pulseValue);

      lcd.setCursor(11, 2);
      lcd.print("       ");
      lcd.setCursor(11, 2);
      if (errorFlag)
      {
        lcd.print ("error");
      }
      else
      {
        lcd.print(average_delayPeriod);
      }

      lcd.setCursor(14, 3);
      lcd.print("    ");
      lcd.setCursor(14, 3);
      if (errorFlag)
      {
        lcd.print ("error");
      }
      else
      {
        lcd.print(delayDegrees,  1);
      }
    }
  }

  if (trigger == true && interruptFlag == true )
  {
    trigger = false;
    interruptFlag = false;
    noInterrupts();
    copy_delayPeriod = delayPeriod;
    interrupts();

    // build initial average
    if (averageReady == false)
    {
      readingCount++;
      average_delayPeriod += copy_delayPeriod;
      if (readingCount == 4)
      {
        averageReady = true;
        average_delayPeriod = average_delayPeriod / 4;
      }
    }

    // add new code for error check and smoothing

    if (averageReady == true)
    {
      int val = copy_delayPeriod - average_delayPeriod;
      if (abs(val) >= errorValue)
      {
        copy_delayPeriod = average_delayPeriod;
        errorCount++;
        if (errorCount >= 3)
          errorFlag = true;
      }
      else
      {
        errorFlag = false;
        errorCount = 0;
      }
      //simple smoothing; not circular buffer dropping oldest value
      average_delayPeriod = (average_delayPeriod * 3 + copy_delayPeriod) / 4;
      delayDegrees = 360.0 * (average_delayPeriod) / (timerTopValue * 4.0);  // for decimal place in deg display
    }
  }
}

ISR(TIMER1_COMPA_vect) {
  OCR1A = (timerTopValue);          // value to set delay between pulses to trigger cdi
  digitalWrite(outputPin, HIGH); //turn on pin 8
  digitalWrite(chargePin, HIGH); //turn on pin 7
}

ISR(TIMER1_COMPB_vect)
{
  digitalWrite(outputPin, LOW);      //turn off pin 8
  digitalWrite(chargePin, LOW);      //turn off pin 7
  delayPeriodStart = micros();        //start looking for response
  trigger = true;

}

void delayPeriodTiming()
{
  delayPeriod = micros() - delayPeriodStart;
  interruptFlag = true;
}
Title: Re: CDI tester project
Post by: tombauer on Oct 19, 2016, 08:32 pm
Yes, that seems to work much better. Now it does get rare error but recovers quickly. I was also able to take the delay out of the test board code.
Code: [Select]
delayMicroseconds(delayValue);
  digitalWrite(7,HIGH);
  //delayMicroseconds(125);                                                  // modify the pulse length to see what is sensed by main board*******
  digitalWrite(7,LOW);

However with the test board it shows error almost each time the delay value is changed and main must be reset to continue. It will not recover on its own.

This may be a good time to work on the display of degrees. When the Us delay value is highest will be at low rpm and vice versa. With the CDI I repair the most, it would be a delay of .005100 at idle and no delay above 1800 rpm. This would correspond to 0° at idle and 17° at 1800 and above. Now in reality I don't have to even have the degree line, it is just bells and whistles. As long as I can see the delay value I will know it is working. I see that the degrees per Us time unit is tied to the rpm, for each time the rpm doubles the time unit between degrees in cut in half. The complication I don't quite know how to do is that there will be 2 ranges of rpm where there will be no change. Maybe it is better to not have this feature!!
Tom
Title: Re: CDI tester project
Post by: cattledog on Oct 20, 2016, 12:19 am
Quote
However with the test board it shows error almost each time the delay value is changed and main must be reset to continue. It will not recover on its own.
I believe that you mentioned this before. That would mean this behavior occurred before the recent changes and addition of the error checking and averaging.

Is it the same problem as before or is it something new?  Does this occur with a CDI unit, or only the test board? If you open the error value from 50 to 100, does it recover?  Is there any relationship between the rpm setting on the main board and the delay value from the test board which creates the need to reset the main?

If you post the two latest versions (test and main) I will do some testing. I have probably only tested with static delays or slow sweeps from the test board. From the quote below, it sounds like you need create a test delay of between 0 and 5100 microseconds.

Quote
This may be a good time to work on the display of degrees. With the CDI I repair the most, it would be a delay of .005100 at idle and no delay above 1800 rpm. [snip] As long as I can see the delay value I will know it is working.
You know what you want to test and how, and I would agree that the degree calculation is derived from other values and is perhaps confusing in that it gets you thinking of "advance". Degrees can not befundamental to how the CDI chip is specified. The chip designer can only provide a delay from a received pulse, and that delay varies with the frequency of that pulse. I would think that a graph of delay plotted against rpm(i.e. pulse frequency) would tell you all you need to know about the cdi chip.
Title: Re: CDI tester project
Post by: tombauer on Oct 20, 2016, 04:15 am
cattledog

I had an epiphany this afternoon! I have thought for this whole process that the noise and dirty signal from the coil feeding back to the main board pin 3 is the real problem. Suddenly it dawned on me that many people have done just what I am trying to do, but for different purpose. They want to build tachometer using Arduino! So they must have had same problem and some must have overcome it.

Thinking this I did some searches and find they mostly used an optical coupler and then a Schmitt trigger to make a clean pulse into the board. Do you agree?  Attached is version 7 which is mostly what you used for your latest code, but I now don't see where that code is needed. Also my version of the test code, and yes I had already set it to 0 to 5100. With these 2 boards, main and test running it is very stable and accurate. In the test code I made the pulse wider so that it is easy to see and measure on scope. The main board has no problem with no delay in test pulses now.

Code: [Select]

// revision 7 10/19/2016
// CDI Tester Pulse Generator Serial Output Arduino Code
// Advance is 12° at idle and 29° at over xxxx RPM

int pot1 = A3;            // select the input pin for the pot (changed for this version because of lcd)
int potValue = 0;         // variable to store the value coming from the sensor
int pulseValue = 0;       // 2 variables from one pot
int timerTopValue = 0;    // changed from timerTopValue
int outputPin = 8;        // select the pin for the output for trigger pulse
int chargePin = 7;        // select the pin for the output for charge pulses

volatile boolean trigger = false;
volatile unsigned long delayPeriod;
unsigned long copy_delayPeriod;
volatile unsigned long delayPeriodStart;
float delayDegrees;                           // changed from int for decimal place display
int RPM;                                      //new
volatile boolean interruptFlag;
unsigned long analogReadInterval = 1000;       //read pots and map
unsigned long lastAnalogRead;
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
// set the LCD address to 0x3f for a 20 chars 4 line display
// Set the pins on the I2C chip used for LCD connections:
//                    addr, en,rw,rs,d4,d5,d6,d7,bl,blpol
LiquidCrystal_I2C lcd(0x3f, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address

void setup() {
  Serial.begin(9600);
  lcd.begin(20, 4);         // initialize the lcd for 20 chars 4 lines, turn on backlight
  lcd.setCursor(1, 0);      // lcd display setup of unchanging headings
  lcd.print("RPM:");        // print fixed characters
  lcd.setCursor(1, 1);
  lcd.print("Ms:");
  lcd.setCursor(1, 2);
  lcd.print("Us Delay:");
  lcd.setCursor(1, 3);
  lcd.print("Deg Advance:");

  pinMode(outputPin, OUTPUT);            // declare the outputPin as an OUTPUT
  pinMode(chargePin, OUTPUT);            // declare the chargePin as an OUTPUT
  delay (2000);

  //Timer1 set up 1ms pulse every 50 ms
  TCCR1A = 0;;
  TCCR1B = (1 << WGM12);//CTC mode to OCR1A
  OCR1A = 12500;                                                           //50 ms to top value           
  TIMSK1 |= (1 << OCIE1A);//interrupt enable compareA
  TIMSK1 |= (1 << OCIE1B);//interrupt enable compareB
  OCR1B = 250;                                                             //sets pulse out width, 500 = 2Ms, 250 = 1Ms
  TCCR1B |= (1 << CS11) | (1 << CS10); //prescaler 64  4us/tick

  attachInterrupt(digitalPinToInterrupt(3), delayPeriodTiming, RISING);

}

void loop()
{
  if (millis() - lastAnalogRead >= analogReadInterval)
  {
    lastAnalogRead += analogReadInterval;
    potValue = analogRead(pot1);
    pulseValue = analogRead(pot1);
    RPM = map(potValue, 0, 1023, 500, 3800);
    pulseValue = map(pulseValue, 0, 1023, 120, 16);                          // to show ms between pulse out on lcd
    timerTopValue = 15000000UL/RPM;

    lcd.setCursor(6, 0);
    lcd.print("    ");               // print blank spaces to clear old data
    lcd.setCursor(6, 0);
    lcd.print(RPM);

    lcd.setCursor(5, 1);
    lcd.print("    ");
    lcd.setCursor(5, 1);
    lcd.print(pulseValue);

    lcd.setCursor(11, 2);
    lcd.print("       ");
    lcd.setCursor(11, 2);
    lcd.print(copy_delayPeriod);
     
    lcd.setCursor(14, 3);
    lcd.print("      ");
    lcd.setCursor(14, 3);
    lcd.print(delayDegrees,1);
  }

  if (trigger == true && interruptFlag == true )
  {
    trigger = false;
    interruptFlag = false;
    noInterrupts();
    copy_delayPeriod = delayPeriod;
    interrupts();

    delayDegrees = 360.0 * (copy_delayPeriod) / (timerTopValue * 4.0);  // for decimal place in deg display
    //copy_delayPeriod = copy_delayPeriod/100;                           //value for display to 3 places in us
  }
}

ISR(TIMER1_COMPA_vect) {
  OCR1A = (timerTopValue);                                              // value to set delay between pulses to trigger cdi
  digitalWrite(outputPin, HIGH); //turn on pin 8
  digitalWrite(chargePin, HIGH); //turn on pin 7
 
}

ISR(TIMER1_COMPB_vect)
{
  digitalWrite(outputPin, LOW);      //turn off pin 8
  digitalWrite(chargePin, LOW);      //turn off pin 7
  delayPeriodStart = micros();                                          //start looking for response as pulse falls
  trigger = true;
 
}

void delayPeriodTiming()
{
  delayPeriod = micros() - delayPeriodStart;
  interruptFlag = true;
}


Code: [Select]


// variable delay output for testing main board Us Delay line
// with display
int pot1 = A3;            // select the input pin for the pot (changed for this version because of lcd)
int delayValue = 0;       // variable to store the value coming from the sensor
unsigned long analogReadInterval = 1000;//read pot and map
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
// set the LCD address to 0x3f for a 20 chars 4 line display
// Set the pins on the I2C chip used for LCD connections:
//                    addr, en,rw,rs,d4,d5,d6,d7,bl,blpol
LiquidCrystal_I2C lcd(0x3f, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);             // Set the LCD I2C address

void setup() {
  Serial.begin(9600);
  lcd.begin(20, 4);                                                        // initialize the lcd for 20 chars 4 lines, turn on backlight
  lcd.setCursor(2, 0);                                                     // lcd display setup of unchanging headings
  lcd.print("Us Delay:");                                                  // print fixed characters
 
   attachInterrupt(digitalPinToInterrupt(3),pulse, FALLING);               //added this line to have any pulse out**********
   pinMode(7,OUTPUT);
   
}

void loop()
  {
    delayValue = analogRead(pot1);
    delayValue = map(delayValue, 0, 1023, 0, 5100);                           

    lcd.setCursor(12, 0);
    lcd.print("       ");                                                  //print blank spaces to clear old data
    lcd.setCursor(12, 0);
    lcd.print(delayValue);
    delay (500);
  }

void pulse()
{
  delayMicroseconds(delayValue);
  digitalWrite(7,HIGH);
  delayMicroseconds(200);                                                  // modify the pulse length to see what is sensed by main board*******
  digitalWrite(7,LOW);
}



Best, Tom
Title: Re: CDI tester project
Post by: cattledog on Oct 20, 2016, 06:03 am
Quote
an optical coupler and then a Schmitt trigger to make a clean pulse into the board. Do you agree?
I'm not a hardware guy, but anything you do to get a clean signal to the interrupt pin is good. The automotive environment is very challenging. When you run the lawnmower I'm sure there is static on the neighbor's radio. :)

Quote
With these 2 boards, main and test running it is very stable and accurate.
It's great to see you having success. Stable and accurate functioning of the code has been my experience with two Arduinos on my desk. Your hardware and enviromental issues have been another story.

Have you actually changed the hardware to use the optoisolator and the Schmitt trigger?

Does the main board still require a reset when you change the delay on the test board? If not, I won't work on it. If yes, I will.

Do the CDI modules and the main board act like the test and main board?

And now for the big question--Are you still interested in the charge pulses, and are you ready to work on adding them to the code now?
Title: Re: CDI tester project
Post by: tombauer on Oct 20, 2016, 06:15 am
or maybe this is an idea to incorporate?

http://forum.arduino.cc/index.php?topic=125297.0
Title: Re: CDI tester project
Post by: cattledog on Oct 20, 2016, 07:16 am
I would strongly recommend that you focus on hardware solutions to get a clean interrupt signal.

You might even try a simple capacitor on the input. The Schmitt trigger is useful for turning a slow rise time signal into a sharp digital input, but I don't think that is your issue. In fact, slowing and smoothing the pulse with a low pass filter might be more appropriate.

I think that way in which the code requires the trigger flag and interrupt flag to take a delayValue reading, ensures the delayValue is immune to extensive bounce at the lead edge of a pulse. The trigger flag gets cleared on the first transition and no further values will be saved until the output pulse cycles again. I think that the worst a ragged front edge can do is extend the delay value by a few microseconds which is likely lost in the +/- 4 us resolution of the function.

When you were observing erratic values, were they longer or shorter than normal, or random each way. You have never answered my question as to the magnitude of the errors.

I can see noise significantly shortening the delay values if the interrupt is executed due to noise rather than a true returning pulse. The errorValue filter and the 4 reading averaging would be useful in this case to trim out the outliers.

Again, first focus on hardware solutions. Optoisolation, shielding, ferrite chokes, capacitors, low pass filters, etc.
Title: Re: CDI tester project
Post by: tombauer on Oct 20, 2016, 05:06 pm
cattledog,

Hi, I tried to send a reply last night but something must have failed.

I have not changed any hardware yet, yes I already have a low pass filter in that input.

With just the test board directly connected there is never the need for a reset.

When various CDI are connected the delay display line goes crazy. Some CDI it shows 84 which seems to be the base value, then jumps to 4000 area. Others it constantly shows 6 digits in the 30000 range. Confirmed they have no delay.

I will try one more low pass filter design I found last night.
Title: Re: CDI tester project
Post by: cattledog on Oct 20, 2016, 06:32 pm
Tom

It is pretty clear to me that the software is solid, and you are fighting hardware/noise issues.

I think that earlier in the thread there was a circuit diagram(http://forum.arduino.cc/index.php?action=dlattach;topic=425551.0;attach=181615)

I would encourage you to bring it up to date, and make it as accurate and complete as possible. I think that at some point you will take it to the general electronics section of this forum.

Is there any way to pick the cdi unit's delayed trigger signal going to the scr and not from the discharge circuitry?

At one point you talked about a separate 5V power supply for promini and lcd have you done that?
Title: Re: CDI tester project
Post by: tombauer on Oct 20, 2016, 10:03 pm
cattledog.

Yes the software seems to be great and I do get consistent good accurate readings with the test board.
Today I striped off all the signal conditioning hardware and built just an opto coupling path. It goes directly from the coil to pin 3. It puts out a very clean looking pulse that according to the scope has no delay across the rpm range. As soon as I ran it I got 6 digit numbers for microsecond delay, but there was a very stable pattern i.e. they did not change for a set rpm. I cannot help but think there is something else going on when the RPM pot is changing while the delay is being measured, but I did not get this with the test board. It really seems like it is computing a value based on something I am missing.

These are the readings:
RPM        Micro delay
500         1191
1000        590
1500        390
2000        290
2500        231
3000        190
3500        162

I put the line " copy_delayPeriod = copy_delayPeriod/100; " back in and changed the 1000 to 100 but that only trimmed the length of the readings.
Title: Re: CDI tester project
Post by: tombauer on Oct 21, 2016, 12:23 am
This is basically the circuit I used to connect to the coil, different opto and set to give a positive pulse, but same front end.
Title: Re: CDI tester project
Post by: cattledog on Oct 21, 2016, 12:47 am
Quote
It puts out a very clean looking pulse that according to the scope has no delay across the rpm range.
I'm not sure I understand the "no delay" statement. Does this mean the cdi unit is known to have no delay from the trigger pulse or is this some reference to electronic issues you were having in measurement of the pulses?

Are you saying that the scope reads correctly 0 delay, but the main program is reading significant delay with the same signal?

Quote
I put the line " copy_delayPeriod = copy_delayPeriod/100; " back in and changed the 1000 to 100 but that only trimmed the length of the readings.
Quote
These are the readings:
RPM        Micro delay
500         1191
1000        590
1500        390
2000        290
2500        231
3000        190
3500        162
I think I understand that  you are calling Micro delay is actually delayValue/100. That is, microseconds/100.

It interesting, but when I consider the reported numbers as millisecondsx10 the reported Micro delay numbers look very much like the trigger periods. 500 rpm = 120 ms trigger period 2000rpm = 300 ms trigger period and 3000 rpm  = 20 ms trigger period.

EDIT: It even looks like it is the pulse period with a missing 1 ms due to the pulse width. ]

It looks to me like you are reading the delay between trigger pulses. Since this doesn't happen with the test board, it's very confusing. Do you have any ideas?

You mentioned before that you could put a bare 4213 ic on the board. I think this would be useful in that you could determine if the 5v 1ms trigger pulse actually gets it to fire, and you can look at the output to the scr instead of the high voltage pulse to confirm that the delay operation is what we think it is.
Title: Re: CDI tester project
Post by: tombauer on Oct 21, 2016, 02:38 am
I'm not sure I understand the "no delay" statement. Does this mean the cdi unit is known to have no delay from the trigger pulse or is this some reference to electronic issues you were having in measurement of the pulses?

Right, it is a CDI I bought for testing and was supposed to have delay, but is a fake product and I have confirmed with scope that it has NO delay across RPM range.

Are you saying that the scope reads correctly 0 delay, but the main program is reading significant delay with the same signal?

Yes that is what it does.

I think I understand that  you are calling Micro delay is actually delayValue/100. That is, microseconds/100.

Yes that is what it is.

It interesting, but when I consider the reported numbers as millisecondsx10 the reported Micro delay numbers look very much like the trigger periods. 500 rpm = 120 ms trigger period 2000rpm = 30 ms trigger period and 3000 rpm  = 20 ms trigger period.

Yes, 120,60,40,30,24,20. But why??
EDIT: It even looks like it is the pulse period with a missing 1 ms due to the pulse width. ]

It looks to me like you are reading the delay between trigger pulses. Since this doesn't happen with the test board, it's very confusing. Do you have any ideas?

If you are puzzled by this, imagine how I feel.

Yes it does look like that now that you mention it. So if I take that /100 line out it is displaying 500 = 119160 and 1500 = 39040, 2500 = 23136 Ideas? Yes I think it is possessed!!

This is with a DC powered CDI so there is no issue with the AC power.
On the plus side, the displayed values are stable and predictable. I don't see what the problem is, but it has to be software?? Wish I was more help, I will look at it for a while.

You mentioned before that you could put a bare 4213 ic on the board. I think this would be useful in that you could determine if the 5v 1ms trigger pulse actually gets it to fire, and you can look at the output to the scr instead of the high voltage pulse to confirm that the delay operation is what we think it is.
Yes I have several but don't have all the support parts. I was hoping to have one that uses it come in and I could tap into it while it is open. I see them all the time, except now!! The main reason I don't want to do it that way all the time is so that I can analyze a unit without taking it apart.
Title: Re: CDI tester project
Post by: tombauer on Oct 21, 2016, 02:49 am
Just to make sure I am reading this correctly, we are measuring from " digitalWrite(outputPin, LOW); "
to " attachInterrupt(digitalPinToInterrupt(3), delayPeriodTiming, RISING) "

Maybe outputPin is not defined right? Remember I had to change
" attachInterrupt(digitalPinToInterrupt(3), delayPeriodTiming, RISING); " to get it to read that pin?

It must be something simply in syntax? I'm just guessing here, I don't see why it is measuring what it is.
Title: Re: CDI tester project
Post by: cattledog on Oct 21, 2016, 03:10 am
Quote
Just to make sure I am reading this correctly, we are measuring from " digitalWrite(outputPin, LOW); "
to " attachInterrupt(digitalPinToInterrupt(3), delayPeriodTiming, RISING) "
Yes, we are timing from the end of the trigger pulse to the arrival of the return delayed pulse., The last code showed the trigger output on pin 8 and the return pulse input on pin 3 for the interrupt.

Here's an idea I had about the actual cdi trigger pulse, pre-conditioning circuitry, and ic behaviour.
I understand that the real trigger pulse will be a high and low pulse as the flywheel passes the magnetic sensor/
(http://i397.photobucket.com/albums/pp60/LynnEdwards_photo/CDITriggerPulseWaveformcranking.jpg)

I'm not sure how this signal is conditioned and what the input to the 4213 ic actually looks like, and what edge the ic responds to. Perhaps in the real application the ic is responding to something which looks like the next trigger pulse. This would explain a delay which looks like the trigger time - the trigger pulse width.

One thing you could test, is to lengthen the trigger pulse width to 5 ms or even 10ms, and see if the delays are reduced by 4 or 9 ms from what you see with the trigger length at 1 ms. I think you know how to control the trigger pulse length with OCR1B as you have played around with it before.

I'd still like to get a bare 4213 in your circuit, but changing the pulse width might give us a clue.
Title: Re: CDI tester project
Post by: tombauer on Oct 21, 2016, 04:37 am
Solved. I changed this code back to the way it was.

Code: [Select]
ISR(TIMER1_COMPA_vect) {
  OCR1A = (timerTopValue);                                              // value to set delay between pulses to trigger cdi
  digitalWrite(outputPin, HIGH); //turn on pin 8
  digitalWrite(chargePin, HIGH); //turn on pin 7
  delayPeriodStart = micros();                                          //start looking for response as pulse falls
  trigger = true;
 
}

ISR(TIMER1_COMPB_vect)
{
  digitalWrite(outputPin, LOW);      //turn off pin 8
  digitalWrite(chargePin, LOW);      //turn off pin 7
 
 
}

void delayPeriodTiming()
{
  delayPeriod = micros() - delayPeriodStart;
  interruptFlag = true;
}


Remember we changed that code when it looked like the CDI was triggering on rising edge of pulse.
So the main board started looking for a pulse when it falls and the next pulse pin 3 sees is actually the NEXT pulse so it counts all that time.
Some CDI do trigger on rising edge of pulse and some on falling. A software switch to select and add rise/fall to display??

I just tried it with an AC CDI and this CDI triggers on rising edge of pulse. It also sometimes triggers on the falling edge so there is a double pulse sometimes and this affects the reading. Here is where a Schmitt trigger may help, I only have the opti coupler which would be needed for the Schmitt anyway.
Title: Re: CDI tester project
Post by: cattledog on Oct 21, 2016, 05:21 am
Nice job of figuring out what was going on.

Quote
Remember we changed that code when it looked like the CDI was triggering on rising edge of pulse
No, we changed it when it looked like the CDI module was responding to the falling edge. We've probably had it each way at least twice as you chased this around. :)

Code: [Select]
//start looking for response as pulse falls Change the comment to reflect what you are actually doing. When you look at the code a year from now you will confuse yourself.

Quote
Some CDI do trigger on rising edge of pulse and some on falling. A software switch to select and add rise/fall to display??
How will you know which is which?

Quote
It also sometimes triggers on the falling edge so there is a double pulse sometimes and this affects the reading.
I do not understand the cdi triggering on both edges of the trigger pulse. The trigger pulse from the Arduino is very clean and there should be no ringing which can confuse the CDI.

You might try to reduce the width of the trigger pulse from 1 ms to the shortest time which triggers the cdi. When the delay time is shorter than the pulse width it can lead to the confusion we just saw.

The way I understand the Schmitt trigger is that it converts a slowly rising signal to a cleaner binary digital pulse. It has nothing to do with what appears to be producing strange results.

I would consider putting back the software outlier control and perhaps the smoothing. There are 10 to 20 delayValues observed for each one reported for display. You might as well take advantage of the additional information available.
Title: Re: CDI tester project
Post by: tombauer on Oct 21, 2016, 05:53 am
Hi, well I forgot the reason in the meantime.....But we had noise and that on top of CDI that triggered to rising or falling. It has been a learning experience to be sure.

I won't know which is which, but I have one here now of each type and with the wrong code it is apparent. With the right code choice delay is just around 100. It would be advantageous to be able to switch between them easily.

I looked again at that particular CDI and the second feedback pulse cycles around, sometimes it is at the falling edge and then it floats back to same position as leading edge pulse. Perhaps this is an effect of this being an AC CDI and being on line frequency.

Obviously there are several circuits for CDI, some are better and some are worse, but all work in their intended environment

I did try your last code with the smoothing and get error most of the time. I have not looked at it in detail.
Thanks again, Tom
Title: Re: CDI tester project
Post by: tombauer on Oct 21, 2016, 11:00 pm
cattledog,

Well I thought I would add 2 switches to toggle the code for rising or falling pulse timing. Cannot get it to compile, Thoughts please??

Code: [Select]


// revision 7 10/19/2016 ttesty for code choice bu button push
// CDI Tester Pulse Generator Serial Output Arduino Code
// Advance is 12° at idle and 29° at over xxxx RPM

int pot1 = A3;            // select the input pin for the pot (changed for this version because of lcd)
int potValue = 0;         // variable to store the value coming from the sensor
int pulseValue = 0;       // 2 variables from one pot
int timerTopValue = 0;    // changed from timerTopValue
int outputPin = 8;        // select the pin for the output for trigger pulse
int chargePin = 7;        // select the pin for the output for charge pulses

volatile boolean trigger = false;
volatile unsigned long delayPeriod;
unsigned long copy_delayPeriod;
volatile unsigned long delayPeriodStart;
float delayDegrees;                           // changed from int for decimal place display
int RPM;                                      //new
char risefall;                                                                    //assign char name to be used for display of code choice********
volatile boolean interruptFlag;
unsigned long analogReadInterval = 1000;       //read pots and map
unsigned long lastAnalogRead;
byte setupAswitch = 5;// define pins to be used                                   //input pins for code choice************
byte setupBswitch = 6;
byte mode; // 0 = waiting to start, 1 = setupA, 2 = setupB


#include <Wire.h>
#include <LiquidCrystal_I2C.h>
// set the LCD address to 0x3f for a 20 chars 4 line display
// Set the pins on the I2C chip used for LCD connections:
//                    addr, en,rw,rs,d4,d5,d6,d7,bl,blpol
LiquidCrystal_I2C lcd(0x3f, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address

void setup() {
  Serial.begin(9600);
  lcd.begin(20, 4);         // initialize the lcd for 20 chars 4 lines, turn on backlight
  lcd.setCursor(1, 0);      // lcd display setup of unchanging headings
  lcd.print("RPM:");        // print fixed characters
  lcd.setCursor(11, 0);
  lcd.print("Mode:");         //to display code choice R or F
  lcd.setCursor(1, 1);
  lcd.print("Ms:");
  lcd.setCursor(1, 2);
  lcd.print("Us Delay:");
  lcd.setCursor(1, 3);
  lcd.print("Deg Advance:");

  pinMode(outputPin, OUTPUT);            // declare the outputPin as an OUTPUT
  pinMode(chargePin, OUTPUT);            // declare the chargePin as an OUTPUT
  delay (2000);
  pinMode (setupAswitch, INPUT);
  digitalWrite (setupAswitch, HIGH); // turn on internl pullup - check for a LOW input to indicate switch is closed to ground
  pinMode (setupBswitch, INPUT);
  digitalWrite (setupBswitch, HIGH);

 

  //Timer1 set up 1ms pulse every 50 ms
  TCCR1A = 0;;
  TCCR1B = (1 << WGM12);//CTC mode to OCR1A
  OCR1A = 12500;                                                           //50 ms to top value           
  TIMSK1 |= (1 << OCIE1A);//interrupt enable compareA
  TIMSK1 |= (1 << OCIE1B);//interrupt enable compareB
  OCR1B = 125;                                                             //sets pulse out width, 500 = 2Ms, 250 = 1Ms, 125 = .5Ms
  TCCR1B |= (1 << CS11) | (1 << CS10); //prescaler 64  4us/tick

  attachInterrupt(digitalPinToInterrupt(3), delayPeriodTiming, RISING);

}

void loop()
  {
  {
  if (millis() - lastAnalogRead >= analogReadInterval)
  {
    lastAnalogRead += analogReadInterval;
    potValue = analogRead(pot1);
    pulseValue = analogRead(pot1);
    RPM = map(potValue, 0, 1023, 500, 3800);
    pulseValue = map(pulseValue, 0, 1023, 120, 16);                          // to show ms between pulse out on lcd
    timerTopValue = 15000000UL/RPM;

    if (mode == 0 && digitalRead(setupAswitch) == LOW){ mode = 1;}            //read if switchs pushed*************
    if (mode == 0 && digitalRead(setupBswitch) == LOW){ mode = 2;}
    switch (mode)
    case 0:
    // do nothing
    break;

   

    lcd.setCursor(6, 0);
    lcd.print("    ");               // print blank spaces to clear old data
    lcd.setCursor(6, 0);
    lcd.print(RPM);

    lcd.setCursor(17, 0);
    lcd.print("  ");
    lcd.setCursor(17, 0);
    //lcd.print(risefall);              //print R or F at upper right side

    lcd.setCursor(5, 1);
    lcd.print("    ");
    lcd.setCursor(5, 1);
    lcd.print(pulseValue);

    lcd.setCursor(11, 2);
    lcd.print("       ");
    lcd.setCursor(11, 2);
    lcd.print(copy_delayPeriod);
     
    lcd.setCursor(14, 3);
    lcd.print("      ");
    lcd.setCursor(14, 3);
    lcd.print(delayDegrees,1);
  }

  if (trigger == true && interruptFlag == true )
  {
    trigger = false;
    interruptFlag = false;
    noInterrupts();
    copy_delayPeriod = delayPeriod;
    interrupts();

    delayDegrees = 360.0 * (copy_delayPeriod) / (timerTopValue * 4.0);  // for decimal place in deg display
    //copy_delayPeriod = copy_delayPeriod/1000;                           //value for display to 3 places in us
  }
}

ISR(TIMER1_COMPA_vect) {
  OCR1A = (timerTopValue);                                              // value to set delay between pulses to trigger cdi
  digitalWrite(outputPin, HIGH); //turn on pin 8
  digitalWrite(chargePin, HIGH); //turn on pin 7
  switch (mode) {                                                        // choose code************
  case 1:
  // A setup code
  delayPeriodStart = micros();                                          //start looking for response as pulse rises
  trigger = true;
  //risefall = R
  mode = 0;
  break;
  } 
}

ISR(TIMER1_COMPB_vect) {
  digitalWrite(outputPin, LOW);      //turn off pin 8
  digitalWrite(chargePin, LOW);      //turn off pin 7
  switch (mode) {                                                       //or choose this code*************
  case 2:
  // B setup code
  delayPeriodStart = micros();                                          //start looking for response as pulse falls
  trigger = true;
  //risefall = F
  mode = 0;
  break;
  }
}   
  }

void delayPeriodTiming()
{
  delayPeriod = micros() - delayPeriodStart;
  interruptFlag = true;
}



Tom
Title: Re: CDI tester project
Post by: cattledog on Oct 22, 2016, 01:11 am
The reason it would not compile was bracket abuse, but i'm not sure if it would have worked if it did compile as there were significant errors with the switch case syntax.

I'm not sure if you were trying to design this around a tactile button, momentary switch, or a physical toggle switch. I like the idea of the toggle switch (open/closed) and recommend that.

I think things can be made much more simple, if there is a default delay timing mode (I've chosen Rising edge of trigger) and one switch to change it to the Falling edge.

If you find there are issues with bounce when the switch is changed, we can fix that. I like your idea of displaying the timing mode, so I put that back in. I can help you make this anyway you want, but take a look at this and see if it does what you want.
Code: [Select]


// revision 7 10/21/2016 test for code choice switch
// CDI Tester Pulse Generator Serial Output Arduino Code
// Advance is 12° at idle and 29° at over xxxx RPM

int pot1 = A3;            // select the input pin for the pot (changed for this version because of lcd)
int potValue = 0;         // variable to store the value coming from the sensor
int pulseValue = 0;       // 2 variables from one pot
int timerTopValue = 0;    // changed from timerTopValue
int outputPin = 8;        // select the pin for the output for trigger pulse
int chargePin = 7;        // select the pin for the output for charge pulses

volatile boolean trigger = false;
volatile unsigned long delayPeriod;
unsigned long copy_delayPeriod;
volatile unsigned long delayPeriodStart;
float delayDegrees;                           // changed from int for decimal place display
int RPM;                                      //new                                                                   //assign char name to be used for display of code choice********
volatile boolean interruptFlag;
unsigned long analogReadInterval = 1000;       //read pots and map
unsigned long lastAnalogRead;

const byte setFallingSwitch = 5;
char risefall = 'R';//default rising mode

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
// set the LCD address to 0x3f for a 20 chars 4 line display
// Set the pins on the I2C chip used for LCD connections:
//                    addr, en,rw,rs,d4,d5,d6,d7,bl,blpol
LiquidCrystal_I2C lcd(0x3f, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address

void setup() {
  Serial.begin(9600);
  lcd.begin(20, 4);         // initialize the lcd for 20 chars 4 lines, turn on backlight
  lcd.setCursor(1, 0);      // lcd display setup of unchanging headings
  lcd.print("RPM:");        // print fixed characters
  lcd.setCursor(11, 0);
  lcd.print("Mode:");         //to display code choice R or F
  lcd.setCursor(1, 1);
  lcd.print("Ms:");
  lcd.setCursor(1, 2);
  lcd.print("Us Delay:");
  lcd.setCursor(1, 3);
  lcd.print("Deg Advance:");

  pinMode(outputPin, OUTPUT);            // declare the outputPin as an OUTPUT
  pinMode(chargePin, OUTPUT);            // declare the chargePin as an OUTPUT
  pinMode (setFallingSwitch, INPUT_PULLUP);//check for a LOW input to indicate switch is closed to ground

  //Timer1 set up 1ms pulse every 50 ms
  TCCR1A = 0;;
  TCCR1B = (1 << WGM12);//CTC mode to OCR1A
  OCR1A = 12500;                                                           //50 ms to top value
  TIMSK1 |= (1 << OCIE1A);//interrupt enable compareA
  TIMSK1 |= (1 << OCIE1B);//interrupt enable compareB
  OCR1B = 125;                                                             //sets pulse out width, 500 = 2Ms, 250 = 1Ms, 125 = .5Ms
  TCCR1B |= (1 << CS11) | (1 << CS10); //prescaler 64  4us/tick

  attachInterrupt(digitalPinToInterrupt(3), delayPeriodTiming, RISING);

}

void loop()
{
  if (millis() - lastAnalogRead >= analogReadInterval)
  {
    lastAnalogRead += analogReadInterval;
    potValue = analogRead(pot1);
    pulseValue = analogRead(pot1);
    RPM = map(potValue, 0, 1023, 500, 3800);
    pulseValue = map(pulseValue, 0, 1023, 120, 16);                          // to show ms between pulse out on lcd
    timerTopValue = 15000000UL / RPM;

    if (digitalRead(setFallingSwitch) == LOW) //set Falling
    {
      risefall = 'F';
    }
    else
    {
      risefall = 'R';
    }

    lcd.setCursor(6, 0);
    lcd.print("    ");               // print blank spaces to clear old data
    lcd.setCursor(6, 0);
    lcd.print(RPM);

    lcd.setCursor(17, 0);
    lcd.print("  ");
    lcd.setCursor(17, 0);
    lcd.print(risefall);              //print R or F at upper right side

    lcd.setCursor(5, 1);
    lcd.print("    ");
    lcd.setCursor(5, 1);
    lcd.print(pulseValue);

    lcd.setCursor(11, 2);
    lcd.print("       ");
    lcd.setCursor(11, 2);
    lcd.print(copy_delayPeriod);

    lcd.setCursor(14, 3);
    lcd.print("      ");
    lcd.setCursor(14, 3);
    lcd.print(delayDegrees, 1);
  }

  if (trigger == true && interruptFlag == true )
  {
    trigger = false;
    interruptFlag = false;
    noInterrupts();
    copy_delayPeriod = delayPeriod;
    interrupts();

    delayDegrees = 360.0 * (copy_delayPeriod) / (timerTopValue * 4.0);  // for decimal place in deg display
    //copy_delayPeriod = copy_delayPeriod/1000;                           //value for display to 3 places in us
  }
}

ISR(TIMER1_COMPA_vect) {
  OCR1A = (timerTopValue);                                              // value to set delay between pulses to trigger cdi
  digitalWrite(outputPin, HIGH); //turn on pin 8
  digitalWrite(chargePin, HIGH); //turn on pin 7

  if (risefall == 'R') //switch not set; default Rising trigger
  {
    delayPeriodStart = micros();                                          //start looking for response as pulse rises
    trigger = true;
  }
}

ISR(TIMER1_COMPB_vect) {
  digitalWrite(outputPin, LOW);      //turn off pin 8
  digitalWrite(chargePin, LOW);      //turn off pin 7

  if (risefall == 'F') //switch set for Falling trigger
  {
    delayPeriodStart = micros();                                          //start looking for response as pulse falls
    trigger = true;
  }
}

void delayPeriodTiming()
{
  delayPeriod = micros() - delayPeriodStart;
  interruptFlag = true;
}


Title: Re: CDI tester project
Post by: tombauer on Oct 22, 2016, 02:14 am
Well the code looks good to me but will not compile?? says error compiling for board arduino pro or pro mini
Title: Re: CDI tester project
Post by: cattledog on Oct 22, 2016, 02:17 am
It compiles for me with pro or pro mini selected as board. Did you cut and past from the forum correctly?
Memory usage should fit an AT 168.

What is the exact error message?
Title: Re: CDI tester project
Post by: tombauer on Oct 22, 2016, 04:58 am
Hi, well I am running this on Win XP Pro and wonder if that is wise since there are no updates for Java available and Arduino says "The environment is written in Java and based on Processing and other open-source software." I think it may not be able to install the latest version as well, it installed 1.6.10 and acted like that was the latest but my Win 7 machine says otherwise.
I think I have a issue with the IDE finding the libraries so I am going to work on that. The install said that I could chose my install directory which I did, but they suggest keeping the default one. Maybe that was for a reason.
Any way the code looked good to me and I am sure when I get past the library issues it will be fine. I will let you know how it goes.
Thanks again, Tom
Title: Re: CDI tester project
Post by: tombauer on Oct 22, 2016, 06:57 am
Got things sorted and it compiles but nothing. No data, just the headings on LCD, no pulse out.
Title: Re: CDI tester project
Post by: cattledog on Oct 22, 2016, 09:06 am
I don't understand it, but there was a delay in setup before the timer setup which I dropped. I put it back and the code is as expected. I'm busy tomorrow, but I'll work to figure this out.
Code: [Select]
pinMode(outputPin, OUTPUT);            // declare the outputPin as an OUTPUT
  pinMode(chargePin, OUTPUT);            // declare the chargePin as an OUTPUT 
  pinMode (setFallingSwitch, INPUT_PULLUP);//check for a LOW input to indicate switch is closed to ground
  delay(2000);
Title: Re: CDI tester project
Post by: tombauer on Oct 22, 2016, 04:45 pm
cattledog,

Good morning! I put the "delay(2000);" in and all works as expected. I think now I am ready to add the pulse out on pin 7 to power the inverter for the AC type CDIs.

Best, Tom
Title: Re: CDI tester project
Post by: tombauer on Oct 23, 2016, 12:59 am
Hi, I am working on formula to display degrees, don't really need it but I may learn something.
I am attaching the schematic, not finished but enough there to see what I have.
Title: Re: CDI tester project
Post by: cattledog on Oct 23, 2016, 07:57 am
Here is the bug in the program which required delay(2000) in setup.
Code: [Select]
int timerTopValue =  0;

When the first TIMER1_COMPA_vector  interrupt was triggered, and OCR1A was set to timerTopValue, it was being set to 0 because this interrupt occurred before the first read of the pot to set the period. Because of this 0 value, the subsequent interrupts were occurring so fast that I think the millis() function was blocked from advancing and the code did not enter the section where the pot was read. I'm not quite sure why the delay in setup fixed this.

There are two solutions, simple one is to initialize the timerTopValue with the 12500 count used in the initial setup. You can also change the line in the timer set up to reflect the non zero initial assignment.

Code: [Select]
//int timerTopValue =  0;
int timerTopValue = 12500; //50 ms with 64 prescaler   // changed from timerTopValue = 0


Code: [Select]
// OCR1A = 12500;  //50 ms to top value
  OCR1A = timerTopValue; 


The other would be to call an analogRead() in set up and assign the mapped value to RPM and calculate an intitial timerTopValue at that time. With either of these changes, the sketch does not require the delay in set up.
Title: Re: CDI tester project
Post by: tombauer on Oct 23, 2016, 08:47 pm
cattledog,

Other issue solved as you said.

I think I have math that will give me the correct degree answer but I do not know how to write it in code.

delayDegrees = copy_delayPeriod / ((pulseValue / 360) / (1000));

This will not compile so is there another way to write it?

Where pulseValue must be divided by 360 first, and then that answer must be divided by 1000.
Then that answer must be divided into copy_delayPeriod

Tom
Title: Re: CDI tester project
Post by: cattledog on Oct 23, 2016, 09:32 pm
Quote
I think I have math that will give me the correct degree answer but I do not know how to write it in code.

delayDegrees = copy_delayPeriod / ((pulseValue / 360) / (1000));
I don't understand what was the problem with the existing code. What values is it giving you that appear to be incorrect? Can you give some numerical examples?

Code: [Select]
  delayDegrees = 360.0 * (copy_delayPeriod) / (timerTopValue * 4.0);  // for decimal place in deg display

timerTopValue*4 is the pulseValue (i.e. the repeating trigger period ~16-120 ms) expressed in microseconds instead of timer ticks. copy_delayPeriod is also in microseconds.  The ratio of the delay to the total period gets converted to degrees by multiplying by 360.

Suppose the RPM = 500 and therefore the trigger period will be 120 ms = 120000us

If the delay is 3000us then   360*(3000/120000) = 9 degrees.

Title: Re: CDI tester project
Post by: tombauer on Oct 23, 2016, 09:48 pm
I may be confused, but when delay says 92, degree says 0.3 and when delay says 596, degree says 1.8.
Both taken at 500 rpm. With more delay, degree should be less. Unless we should not call that line Deg Advance, and should call it Degree retarded. I have no problem either way but what it says now, taken literally is not correct even though it may be right.
Title: Re: CDI tester project
Post by: cattledog on Oct 23, 2016, 10:04 pm
Quote
With more delay, degree should be less.
Not really.  Think of a one armed clock with the arm sweeping around. If the trigger goes off when the hand is at 12 and the signal comes back when the hand is at 1, then the delay of the response is 1/12 = 30 degrees. If the pulse comes back when the hand is at 2 then the delay of the response is 2/12  = 60 degrees. If the pulse comes back when the hand is at 3 then the delay of the response is 3/12 = 90 degrees.

If you understand degrees retarded better than degrees delayed it seems like an ok term to use.
 
Title: Re: CDI tester project
Post by: tombauer on Oct 23, 2016, 10:41 pm
Hi, Yes you are right, but in the beginning I was, and still do think of it as advance. That is because I come from the world of engines and mechanical things as well as electronics. It has to do with the way "advance" is arrived at, using delay from a predetermined spot which is the most advanced that the spark will ever occur at high rpm. So I will think of it as degrees retarded, no problem, it makes it simple and then there is not the issue of calibrating for each different cdi.

With the test board, the degrees seem to make sense now, being approx what I expect, I need to install the switch for mode. I still don't really understand why with a cdi of no delay, the measurement of delay is from 96 to 136.

With test board set to 0 main shows 16 in the F mode, and with test set to 5100 main shows 5116.
With cdi of no delay, main shows 96 to 136, ideally this would be 0. Ideas? It is not important unless it is an easy fix, it may be that for some reason it really does take that long from pulse in to spark out.

Tom
Title: Re: CDI tester project
Post by: cattledog on Oct 25, 2016, 08:07 am
Here is some code for the CDI modules which require the charge pulse. It's pretty will commented but here's a summary.

There is mode switch(pin6) for the charge pulses similar to the switch for trigger edge, but unlike the switch for the trigger edge, it is active in set up only and is not dynamic. Default is to not use the charge pulses. Let me know if that needs changing. I thought you would know which module you were testing.

The 5 charging pulses are turned on and off by an overflow interrupt from Timer2. I use Timer2 to time out the charge pulses, because when I used a micros() software timer (like the the one which controls the display frequency) I saw problems at the higher rpm due to blocking aspects of the code. The charge pulses from Timer 2 are gated by the trigger pulse from Timer1. One issue which came up is that because of the 8 bit limit of Timer2 I could not cover the complete range of charge pulse intervals from 500 to 3800 rpm with one prescaler setting. I chose to limit the lowest rpm in the charging mode to 615 instead of 500. If that is a major problem, let me know and I will try to work out a switch between two prescaler settings for Timer2.

I don't have a scope, and tested as best I could with Serial output, but you will need to check on both the long term timing (synchronization)  of the of the charge pulses with the trigger, and the transient behavior on start up with the very first trigger pulses.  Beyond the control of timer2 by timer1, I added some additional safety by always writing the charge pulse pin low at the spark trigger, independent of the timer 2 period control.

Take a look at this and get back to me with any questions.
Code: [Select]

// revision 9 10/24/2016 adds charging pulse with Timer 2
// lowest RPM = 615 with charge pulse to keep OCR2A <= 255
// CDI Tester Pulse Generator Serial Output Arduino Code

int pot1 = A3;            // select the input pin for the pot (changed for this version because of lcd)
int potValue = 0;         // variable to store the value coming from the sensor
int pulseValue = 0;       // 2 variables from one pot
int timerTopValue = 12500;// changed from timerTopValue = 0
int outputPin = 8;        // select the pin for the output for trigger pulse
int chargePin = 7;        // select the pin for the output for charge pulses

volatile boolean trigger = false;
volatile unsigned long delayPeriod;
unsigned long copy_delayPeriod;
volatile unsigned long delayPeriodStart;
float delayDegrees;       // changed from int for decimal place display
int RPM;                                             
volatile boolean interruptFlag;
unsigned long analogReadInterval = 1000; //read pots and map
unsigned long lastAnalogRead;

const byte setFallingSwitch = 5;
char risefall = 'R';   //default rising mode

const byte setChargePulseSwitch = 6;
boolean chargePulse = false ;  //default powered mode

volatile byte timeSliceCount = 0;  //TDC 0 degrees

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
// set the LCD address to 0x3f for a 20 chars 4 line display
// Set the pins on the I2C chip used for LCD connections:
//                    addr, en,rw,rs,d4,d5,d6,d7,bl,blpol
LiquidCrystal_I2C lcd(0x3f, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address

void setup() {
  //Serial.begin(115200);
  //Serial.println("starting...");
  lcd.begin(20, 4);         // initialize the lcd for 20 chars 4 lines, turn on backlight
  lcd.setCursor(1, 0);      // lcd display setup of unchanging headings
  lcd.print("RPM:");        // print fixed characters
  lcd.setCursor(11, 0);
  lcd.print("Mode:");       //to display code choice R or F
  lcd.setCursor(1, 1);
  lcd.print("Ms:");
  lcd.setCursor(1, 2);
  lcd.print("Us Delay:");
  lcd.setCursor(1, 3);
  lcd.print("Deg Advance:");

  pinMode(outputPin, OUTPUT);            // declare the outputPin as an OUTPUT
  pinMode(chargePin, OUTPUT);            // declare the chargePin as an OUTPUT
  pinMode (setFallingSwitch, INPUT_PULLUP);//check for a LOW input to indicate switch is closed to ground
  pinMode(setChargePulseSwitch, INPUT_PULLUP);

  if (digitalRead(setChargePulseSwitch) == LOW)
    chargePulse = true; //AC CDI

  //Timer1 default set up .5ms trigger pulse every 50 ms
  TCCR1A = 0;
  TCCR1B = (1 << WGM12);//CTC mode to OCR1A
  OCR1A = timerTopValue;
  TIMSK1 |= (1 << OCIE1A);//interrupt enable compareA
  TIMSK1 |= (1 << OCIE1B);//interrupt enable compareB
  OCR1B = 125; // .5ms trigger pulse width  //sets pulse out width, 500 = 2Ms, 250 = 1Ms, 125 = .5Ms
  TCCR1B |= (1 << CS11) | (1 << CS10); //prescaler 64 4us/tick

  //Timer2 default setup charge pulse 12 periods 30 degrees each; only 5 get turned on
  //charge pulse timing interval = Timer1 trigger period/12 = timerTopValue/96
  TCCR2A = 0;
  TCCR2B = 0;
  TCCR2A = 1 << WGM20; //lsb of mode 7 pwm to OCR2A
  TCCR2B = 1 << WGM22; //msb of mode 7 pwm to OCR2A;
  OCR2A = timerTopValue / 96; //96 = 12*4*2 (#periods, prescaler difference, up/down timer mode )
  TIMSK2 = 0;
  TIMSK2 = 1 << TOIE2; //enable overflow interrupt
  // actually start timer in ISR(TIMER1_COMPA_vect
  //prevent out of sync charge pulse, no prescaler set here

  attachInterrupt(digitalPinToInterrupt(3), delayPeriodTiming, RISING);

}

void loop()
{
  if (millis() - lastAnalogRead >= analogReadInterval)
  {
    lastAnalogRead += analogReadInterval;
    potValue = analogRead(pot1);
    pulseValue = analogRead(pot1);
   
    //Timer2 OCR2A requires max value 255 => 615 lowest RPM
    if (chargePulse)
    {
      RPM = map(potValue, 0, 1023, 615, 3800);
      pulseValue = map(pulseValue, 0, 1023, 97, 16);// to show ms between pulse out on lcd
      //RPM = 615;//for my serial test purposes 615-3800
    }
    else
    {
      RPM = map(potValue, 0, 1023, 500, 3800);
      pulseValue = map(pulseValue, 0, 1023, 120, 16);// to show ms between pulse out on lcd
     // RPM = 500;//for my serial test purposes 500-3800
    }

    timerTopValue = 15000000UL / RPM;

    if (digitalRead(setFallingSwitch) == LOW) //set Falling
    {
      risefall = 'F';
    }
    else
    {
      risefall = 'R';
    }

    lcd.setCursor(6, 0);
    lcd.print("    ");    // print blank spaces to clear old data
    lcd.setCursor(6, 0);
    lcd.print(RPM);

    lcd.setCursor(17, 0);
    lcd.print("  ");
    lcd.setCursor(17, 0);
    lcd.print(risefall);    //print R or F at upper right side

    lcd.setCursor(5, 1);
    lcd.print("    ");
    lcd.setCursor(5, 1);
    lcd.print(pulseValue);

    lcd.setCursor(11, 2);
    lcd.print("       ");
    lcd.setCursor(11, 2);
    lcd.print(copy_delayPeriod);
   
    lcd.setCursor(14, 3);
    lcd.print("      ");
    lcd.setCursor(14, 3);
    lcd.print(delayDegrees, 1);
  }
 
  if (trigger == true && interruptFlag == true )
  {
    trigger = false;
    interruptFlag = false;
    noInterrupts();
    copy_delayPeriod = delayPeriod;
    interrupts();

    delayDegrees = 360.0 * (copy_delayPeriod) / (timerTopValue * 4.0);  // for decimal place in degree display                         //value for display to 3 places in us
  }
}

ISR(TIMER1_COMPA_vect) {
  OCR1A = (timerTopValue);// value to set delay between pulses to trigger cdi
  digitalWrite(chargePin, LOW); //guarantee off charge pin at trigger
  digitalWrite(outputPin, HIGH); //turn on pin 8 trigger

  if (risefall == 'R') //switch not set; default Rising trigger
  {
    delayPeriodStart = micros();                                          //start looking for response as pulse rises
    trigger = true;
  }
  //start Timer 2 for charge pulses
  if (chargePulse)
  {
    timeSliceCount = 0;
    TCNT2 = 0;
    OCR2A = timerTopValue/96; //set 12 periods
    TCCR2B |=  1 << CS22 | 1 << CS21; //prescaleer 256 16us/tick
  }
}

ISR(TIMER1_COMPB_vect) {
  digitalWrite(outputPin, LOW);      //turn off pin 8

  if (risefall == 'F') //switch set for Falling trigger
  {
    delayPeriodStart = micros();                                          //start looking for response as pulse falls
    trigger = true;
  }
}

void delayPeriodTiming()
{
  delayPeriod = micros() - delayPeriodStart;
  interruptFlag = true;
}

ISR(TIMER2_OVF_vect)
//5 pulses of 30 degrees starting at 60 degrees
//ON at 60,120,180,240,300 = 2,4,6,8,10
//OFF at 90,150,210,270,330 = 3,5,7,9,11
{
  if (timeSliceCount != 0 && timeSliceCount % 2 == 0)
  {
    digitalWrite (chargePin, HIGH);
  }
  else //if (timeSliceCount == 0 || timeSliceCount % 2 == 1)
  {
    digitalWrite(chargePin, LOW);
  }
  timeSliceCount++;

  if (timeSliceCount == 12)
  {
    timeSliceCount = 0;
    //stop Timer2 by clearing prescaler bits
    TCCR2B &= ~1<< CS22;
    TCCR2B &= ~1<< CS21;
  }
}

Title: Re: CDI tester project
Post by: tombauer on Oct 25, 2016, 10:53 pm
cattledog,

Hi, I looked it over, will try it soon. One question came up yesterday when I tested a CDI that fires from falling edge. It gave long Us delay times like I had before when it was measuring from leading edge. So many CDIs do the same thing in function but with slightly different characteristics!

So I put this 100Us delay in and it fixed it, but any less than 100 did not correct it and more than 100 had no more effect. Just wanted to understand. With the 100Us delay, the Us Delay reads 8 or 12, mostly 12.

Code: [Select]

ISR(TIMER1_COMPB_vect) {
  digitalWrite(outputPin, LOW);                                          //turn off pin 8
  digitalWrite(chargePin, LOW);                                          //turn off pin 7

  if (risefall == 'F')                                                   //switch set for Falling edge of pulse for trigger
  {
    delayMicroseconds(100);                                             // delay for 4518 cdi
    delayPeriodStart = micros();                                        //start looking for response as pulse falls
    trigger = true;
  }
}

void delayPeriodTiming()
{
  delayPeriod = micros() - delayPeriodStart;
  interruptFlag = true;
}
Title: Re: CDI tester project
Post by: cattledog on Oct 26, 2016, 07:29 am
Quote
One question came up yesterday when I tested a CDI that fires from falling edge. It gave long Us delay times like I had before when it was measuring from leading edge. So many CDIs do the same thing in function but with slightly different characteristics!
When we code for the trigger on the falling edge but the actual trigger is on the leading edge, we get long delay times equal to the fundamental repeating trigger period plus the actual delay. The code did not start looking for the return pulse until after it had arrived and we were catching the next one.

When we code for the trigger on the leading edge, but the actual trigger is on the falling edge, we get delay times equal to the trigger pulse length plus the actual delay. Trigger pulse length was last set at 125 Timer1 counts (each equal to 4 microseconds by prescaler 64) which is 500 microseconds.

When we code for the trigger edge which actually matches the device, we were reading the correct delay.

You are now reporting a new issue in that the code with the falling edge delay measurement start time and the module delay being falling edge triggered you see "large" numbers unless there is a 100 microsecond delay.

First, are you absolutely certain the CDI unit delay is falling edge triggered? How do you know?

If indeed this strangely behaving module were actually rising edge triggered, but measured with falling edge code, the added 100 microsecond delay could push the time at which the delayed pulse was sensed to back after the falling edge and it would measure a small delay.

I can't see any other way that added delay would turn a large measured delay into a small one unless it pushed the arrival of the delayed pulse echo to after the end of the trigger pulse.

What are the actual delay numbers you see, and at what RPM? That data last time was the key to figuring out what was going on.

Have you ever seen issues with the Rising edge triggered code? Have you ever seen issues with Falling edge triggered code and the two Arduino test setup?

Do you know how the modules sense the RPM? We have coded everything based on the premise that the module figures RPM by the time between similar edges and the delayed spark pulse is fired from that edge. But it's conceivable that there are other methods in use.

The delayMicroseconds(100) in the code can only affect the Arudino and its measurement as the trigger pulse was ended before the delay and the real delay is controlled by the module hardware. What does the scope tell us about the relationship between the trigger pulse and when the spark pulse is really being fired?

Adding the delayMicroseconds(100) into the ISR is not good practice and could have unintended consequences for other timing, so its best to figure this out.
Title: Re: CDI tester project
Post by: tombauer on Oct 27, 2016, 02:39 am
cattledog,

Ok, I had time today to look into this and was very surprised by what I found. This was on a CDI that is DC powered meaning it has its own DC to high voltage AC inverter inside. When I looked at it on the scope (like I should have done at first) The signal from the coil primary had an incredible amount of ringing or oscillation after the pulse firing the coil. This was playing havoc with the optocoupler. I put a diode across the coil and completely eliminated this problem. I will have to keep remaining myself that we have fairly established that the software is working very well and problems that arise are outside that scope!!

I really do need to thank you for the help you have provided, I do car audio repair daily so if you ever have a need perhaps I can repay you.

I had a thought about what to use for a 'box' for this all to live in and thought of a dvd duplicator or external cd drive case since they usually have small power supplies with 3.3, 5.0, and 12 volt outputs, and have the available room of 2 or 3 5.25" drives. Is there something else I might consider?

Best, Tom
Title: Re: CDI tester project
Post by: tombauer on Oct 28, 2016, 08:47 pm
cattledog,

Initial response is there is nothing on pin 7. Does this require a feedback on pin 3 to start? If so that is a catch 22 since there is no high voltage for the CDI to make a spark.

edit: I see that I need to reset the Arduino after changing the setting. Now testing.
Title: Re: CDI tester project
Post by: cattledog on Oct 28, 2016, 09:13 pm
Quote
Initial response is there is nothing on pin 7. Does this require a feedback on pin 3 to start?
No charge pulses are independent of any signal on pin 3.

The default is for no charge pulse unless pin 6 (setChargePulsePin) is grounded. Do you have a 2 position switch on pin 6? If not, you can just run a wire from 6 to ground.
Title: Re: CDI tester project
Post by: tombauer on Oct 28, 2016, 10:23 pm
OK, but what happens is if the Arduino is running when I jump pin 6 to ground the charge pulses do not start until I reset. If I remove ground from pin 6 the charge pulses do not stop until I reset. It is not a big issue and I still need to work on hardware to turn those pulses into something usable.
Tom
Title: Re: CDI tester project
Post by: tombauer on Oct 28, 2016, 10:37 pm
Just discovered that the pulse out on pin 8 has changed. What used to be the on time is now the off time and off time is on time making very long pulses with .5Ms off.
Title: Re: CDI tester project
Post by: cattledog on Oct 29, 2016, 02:01 am
Quote
Just discovered that the pulse out on pin 8 has changed. What used to be the on time is now the off time and off time is on time making very long pulses with .5Ms off.
There is nothing I see in the code I wrote which could do that.  To confirm, I just went and tested the code posted in #146 with a frequency/duty cycle analysis program I use, and the trigger pulse on pin 8 was indeed the 500us (.5ms) HIGH expected with the low period length determined by the rpm.

Are you running the exact code I posted? If not please post the code you are running.

When you run the code without the pin 6 jumper to ground and the chargePulses are disabled, do you see the pin 8 problem?

Do a "find" on the word "outputPin" and see where it is turned on and off. Is there anything in your hardware which could invert the pulse?

Go back to the version you were last running before the chargePulse modifications. Do you see the pin 8 pulse timing change or is it correct? If indeed you have two versions of code, one of which is correct on/off and the other which is reversed on the same hardware, please post both versions.

Right now, I can't confirm your findings.



Title: Re: CDI tester project
Post by: tombauer on Oct 29, 2016, 08:06 pm
Got to take a quick look today, transistor for pulse out had failed and was passing the inverted signal from its driver. It is a 4403 and is rated for 600 ma continuous collector current so I don't know why it failed. Still expecting some Honda CDI with retard in soon so can have real time info on delay reading.
Tom
Title: Re: CDI tester project
Post by: tom_bauer on Jan 17, 2019, 11:43 pm
Hi, I have progressed to a new set of testing where it needs a simple form of a sine wave. A DAC will suffice but I need simple control from the Arduino to do this such as D1=1 D2=0  => zero volt,
D1=1 D2=1  => +12volt, D1=0 D2=0  => -12volt. So I need to use 2 output pins rather than 1. The width of the output should stay the same.

Code: [Select]

// last change 7/22/18
// 8/17 added code for pulse out width
// 7/14/2017 added correct math and setting for position of pickup
// 10 10/28/2016 adds charging pulse with Timer 2
// lowest RPM = 615 with charge pulse to keep OCR2A <= 255
// CDI Tester Pulse Generator Serial Output Arduino Code


int pot1 = A3; // select the input pin for the pot for rpm
int pot2 = A4; // select the input pin for the pot for pickup location in degrees
int pot3 = A5; // select the input pin for the pot for width of bar on flywheel in degrees
int potValue = 0; // variable to store the value coming from the sensor
int pickupValue = 0; // position of pickup in degrees
int potWidth = 0; // variable to set width of bar on flywheel
int timerTopValue = 12500; // changed from timerTopValue = 0
int outputPin = 4; // select the pin for the output for trigger pulse, changed from 8
int chargePin = 7; // select the pin for the output for charge pulses

volatile boolean trigger = false;
volatile unsigned long delayPeriod;
unsigned long copy_delayPeriod;
volatile unsigned long delayPeriodStart;
float delayDegrees; // changed from int to float for decimal place display
int RPM;
int pickup;
int barWidth;
int pulseWidth;                                           
volatile boolean interruptFlag;
unsigned long analogReadInterval = 250; //read pots and map
unsigned long lastAnalogRead;

const byte setFallingSwitch = 5;
char risefall = 'R'; //default rising mode

const byte setChargePulseSwitch = 6;
boolean chargePulse = false ;  //default dc powered mode

volatile byte timeSliceCount = 0; //TDC 0 degrees

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
// set the LCD address to 0x3f for a 20 chars 4 line display
// Set the pins on the I2C chip used for LCD connections:
//                    addr, en,rw,rs,d4,d5,d6,d7,bl,blpol
LiquidCrystal_I2C lcd(0x3f, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address

void setup() {
  //Serial.begin(115200);
  //Serial.println("starting...");
  lcd.begin(20, 4); // initialize the lcd for 20 chars 4 lines, turn on backlight
  lcd.setCursor(1, 0); // lcd display setup of unchanging headings
  lcd.print("RPM:"); // print fixed characters
  lcd.setCursor(12, 0);
  lcd.print("Mode:"); //to display code choice R or F
  lcd.setCursor(1, 1);
  lcd.print("Pos:");
  lcd.setCursor(9, 1);
  lcd.print("Width:");
  lcd.setCursor(1, 2);
  lcd.print("Us Delay:");
  lcd.setCursor(1, 3);
  lcd.print("Deg Advance:");

  pinMode(outputPin, OUTPUT); // declare the outputPin as an OUTPUT
  pinMode(chargePin, OUTPUT); // declare the chargePin as an OUTPUT
  pinMode (setFallingSwitch, INPUT_PULLUP); //check for a LOW input to indicate switch is closed to ground
  pinMode(setChargePulseSwitch, INPUT_PULLUP);

  if (digitalRead(setChargePulseSwitch) == LOW)
    chargePulse = true; //AC CDI

  //Timer1 default set up .5ms trigger pulse every 50 ms
  TCCR1A = 0;
  TCCR1B = (1 << WGM12); //CTC mode to OCR1A
  OCR1A = timerTopValue;
  TIMSK1 |= (1 << OCIE1A); //interrupt enable compareA
  TIMSK1 |= (1 << OCIE1B); //interrupt enable compareB
  OCR1B = 125; //sets trigger pulse width, 500 = 2Ms, 250 = 1Ms, 125 = .5Ms, set to 1250 for 5013 cdi ***************
  TCCR1B |= (1 << CS11) | (1 << CS10); //prescaler 64 4us/tick

  //Timer2 default setup charge pulse 12 periods 30 degrees each; only 5 get turned on
  //charge pulse timing interval = Timer1 trigger period/12 = timerTopValue/96
  TCCR2A = 0;
  TCCR2B = 0;
  TCCR2A = 1 << WGM20; //lsb of mode 7 pwm to OCR2A
  TCCR2B = 1 << WGM22; //msb of mode 7 pwm to OCR2A;
  OCR2A = timerTopValue / 96; //96 = 12*4*2 (#periods, prescaler difference, up/down timer mode )
  TIMSK2 = 0;
  TIMSK2 = 1 << TOIE2; //enable overflow interrupt
  // actually start timer in ISR(TIMER1_COMPA_vect
  // to prevent out of sync charge pulse, no prescaler set here

  attachInterrupt(digitalPinToInterrupt(3), delayPeriodTiming, FALLING);

}

void loop()
{
  if (millis() - lastAnalogRead >= analogReadInterval)
  {
    lastAnalogRead += analogReadInterval;
    potValue = analogRead(pot1); //rpm
    pickupValue = analogRead(pot2); // pickup position
    barWidth = analogRead(pot3); 
 
    //Timer2 OCR2A requires max value 255 => 615 lowest RPM
    if (chargePulse)
    {
      RPM = map(potValue, 0, 1023, 615, 10000);  //this section needs 2 pots added to set pickup and pulseWidth **************************
      pickup = 74; //map(pickupValue, 0, 1023, 0, 65); so advance will read based on delay,52 for yamaha 350 2 pu, 74 for 1 pu, 72 for tw200, 25 for 5013
      pulseWidth = (60000000/RPM)/360; //time for 1° in uS
      barWidth = 60; //barWidth = pulseWidth + 1000;  //10 for yamaha 350 2 pu, 60 for 1 pu, 60 for tw200
      //RPM = 615; //for my serial test purposes 615-3800
    }
    else
    {
      RPM = map(potValue, 0, 1023, 500, 3800);
      pickup = 25; //map(pickupValue, 0, 1023, 0, 50); //to set position of pickup so advance will read
      pulseWidth = map(potWidth, 0, 1023, 271, 44); //add Width to non charging case
     // RPM = 500;//for my serial test purposes 500-3800
    }

    timerTopValue = 15000000UL / RPM;
    OCR1B = pulseWidth;

    if (digitalRead(setFallingSwitch) == LOW) //set Falling
    {
      risefall = 'F';
    }
    else
    {
      risefall = 'R';
    }

    lcd.setCursor(6, 0);
    lcd.print("     "); // print blank spaces to clear old data
    lcd.setCursor(6, 0);
    lcd.print(RPM);

    lcd.setCursor(18, 0);
    lcd.print("  ");
    lcd.setCursor(18, 0);
    lcd.print(risefall); //print R or F at upper right side

    lcd.setCursor(6, 1);
    lcd.print("   ");
    lcd.setCursor(6, 1);
    lcd.print(pickup);

    lcd.setCursor(16, 1);
    lcd.print("   ");
    lcd.setCursor(16, 1);
    lcd.print(pulseWidth);

    lcd.setCursor(11, 2);
    lcd.print("       ");
    lcd.setCursor(11, 2);
    lcd.print(copy_delayPeriod);
   
    lcd.setCursor(14, 3);
    lcd.print("      ");
    lcd.setCursor(14, 3);
    lcd.print(delayDegrees, 1);   //delayDegrees, 1);
  }
 
  if (trigger == true && interruptFlag == true )
  {
    trigger = false;
    interruptFlag = false;
    noInterrupts();
    copy_delayPeriod = delayPeriod;
    interrupts();

    delayDegrees = pickup - (360.0 * (copy_delayPeriod) / (timerTopValue * 4.0)); //for decimal place in deg display.
    }
}

ISR(TIMER1_COMPA_vect) {
  OCR1A = (timerTopValue); // value to set delay between pulses to trigger cdi
  digitalWrite(chargePin, LOW); //guarantee off charge pin at trigger
  digitalWrite(outputPin, HIGH); //turn on pin  trigger

  if (risefall == 'R') //switch not set; default Rising trigger
  {
    delayPeriodStart = micros(); //start looking for response as pulse rises
    trigger = true;
  }
  //start Timer 2 for charge pulses
  if (chargePulse)
  {
    timeSliceCount = 0;
    TCNT2 = 0;
    OCR2A = timerTopValue/96; //set 12 periods
    TCCR2B |=  1 << CS22 | 1 << CS21; //prescaleer 256 16us/tick
  }
}

ISR(TIMER1_COMPB_vect) {
  digitalWrite(outputPin, LOW);

  if (risefall == 'F') //switch set for Falling trigger
  {
    delayPeriodStart = micros(); //start looking for response as pulse falls
    trigger = true;
  }
}

void delayPeriodTiming()
{
  delayPeriod = micros() - delayPeriodStart;
  interruptFlag = true;
}

ISR(TIMER2_OVF_vect)
//5 pulses of 30 degrees starting at 60 degrees
//ON at 60,120,180,240,300 = 2,4,6,8,10
//OFF at 90,150,210,270,330 = 3,5,7,9,11
{
  if (timeSliceCount != 0 && timeSliceCount % 2 == 0)
  {
    digitalWrite (chargePin, HIGH);
  }
  else //if (timeSliceCount == 0 || timeSliceCount % 2 == 1)
  {
    digitalWrite(chargePin, LOW);
  }
  timeSliceCount++;

  if (timeSliceCount == 12)
  {
    timeSliceCount = 0;
    //stop Timer2 by clearing prescaler bits
    TCCR2B &= ~1<< CS22;
    TCCR2B &= ~1<< CS21;
  }
}

Title: Re: CDI tester project
Post by: cattledog on Jan 18, 2019, 05:42 am
Hi Tom.

It's nice to hear that you are still in business with the CDI tester. I need to take a day to reacquaint myself with the project. While I'm doing that, can you explain a bit more about what you are doing with the AC output. Is this related to the ignition pulse, the charging pulse, or is a a new third output?

Any wiring diagrams and more information about what you are trying to do will be of help. How will you be working the DAC?

Are you needing to add two switches which will be read to determine the output? Like the mode switch and charging switch set a program path take?

Any wiring diagrams and more information about what you are trying to do will be of help.

Title: Re: CDI tester project
Post by: tom_bauer on Jan 18, 2019, 12:50 pm
I think to use 2 output pins on Arduino, call them D1 and D2. DAC will have 12+ and 12- supply voltage. This is only for the ignition pulse. The pulse width should change with rpm, I think I remember it does that now, and the time between the 2 pulses should change in relation to barWidth.

when all input pins of DAC get a 1 (+5v) the DAC output  +12v (if powered by +12)
when all input pins of DAC get a 0 (gnd) the DAC output  -12v (if powered by -12)
when pin5 of DAC get a 1 and others got a 0 the DAC output  0v

Then 2 pins of arduino are enough to get pos and neg square pulses and zero volt.
Say you connect D1 to pin 5 and D2 to pins 6,7,8,9,10,11,12 together

 Thanks, Tom
Title: Re: CDI tester project
Post by: cattledog on Jan 19, 2019, 08:33 am
I think I understand.

You want a new ignition pulse, on two pins to replace the current single output on pin 4.

It looks like we now get an output pulse on pin 4 of some length and some repeating frequency determined by the RPM setting. It sound like you want to change this to an output on two pins.

Quote
The pulse width should change with rpm, I think I remember it does that now, and the time between the 2 pulses should change in relation to barWidth.
when all input pins of DAC get a 1 (+5v) the DAC output  +12v (if powered by +12)
when all input pins of DAC get a 0 (gnd) the DAC output  -12v (if powered by -12)
when pin5 of DAC get a 1 and others got a 0 the DAC output  0v
What I'm unclear of is how the two outputs to the DAC are timed. Is a +/- varying signal sent from the DAC to the module each cycle. Can you draw a timing diagram of how the 11 00 10 output states are sent to the DAC? Are they all sent in sequence during one output timing cycle? 

It would help me if you could draw a timing diagram of the desired output pulses.

Can you explain about "barWidth". This variable does not appear in the previous code we worked on. What is it, and how does it relate to the timing of the 2 pulses.

In this new mode of output to the DAC, will the the return pulse from the module and the reading on the pin 2 interrupt be unchanged?

Will the charge pulse code be unchanged?

It's been awhile  :smiley-confuse:
Title: Re: CDI tester project
Post by: tom_bauer on Jan 19, 2019, 10:00 pm
I think I understand.

You want a new ignition pulse, on two pins to replace the current single output on pin 4.

>Yes

It looks like we now get an output pulse on pin 4 of some length and some repeating frequency determined by the RPM setting. It sound like you want to change this to an output on two pins.

>The length of the existing pulse is determined by barWidth I think. So the 2 new pulse array must replace >that in such a way that it tells the DAC to output a pos pulse and then after a time determined by barWidth >output a neg pulse, then no pulse until it repeats. i have to determine what the pulse width should be.

What I'm unclear of is how the two outputs to the DAC are timed. Is a +/- varying signal sent from the DAC to the module each cycle. Can you draw a timing diagram of how the 11 00 10 output states are sent to the DAC? Are they all sent in sequence during one output timing cycle?

>In this simplest control of the DAC it has 3 states of output, 0 volt, pos volt, neg volt. 

It would help me if you could draw a timing diagram of the desired output pulses.

> attached is something that may help. MSB is DAC pin 5 and all others are 6 thru 12 tied together.

Can you explain about "barWidth". This variable does not appear in the previous code we worked on. What is it, and how does it relate to the timing of the 2 pulses.

> It is the width of the bar that passes past the pickup coil. Some engines it is just a short bar and only >serves to make a short pulse where they are only interested in the positive component of the signal. These >generally have two pickup coils and two short bars. In this case I am only interested in one of the positive >pulses so I set the barWidth to small value. Other times the bar can be 60° long and the negative pulse is >at the beginning and then the positive is at the end of bar which has just one pickup coil. For this I set the >barWidth to a higher value, usually the bar length in degrees plus the base timing so 74 is a normal setting.

In this new mode of output to the DAC, will the the return pulse from the module and the reading on the pin 2 interrupt be unchanged?

>I think the answer is yes.

Will the charge pulse code be unchanged?

>Yes

It's been awhile  :smiley-confuse:

> Yes for me also, I tend to forget a lot of what I have learned doing this!!
Title: Re: CDI tester project
Post by: tom_bauer on Jan 19, 2019, 10:25 pm
here is a representation of the DAC control.
Title: Re: CDI tester project
Post by: tom_bauer on Jan 19, 2019, 10:46 pm
Maybe this also helps, I ask a friend with a similar interest and he said.

>How wide should the on time of each pulse I send to the DAC be?

The answer is: "it depend !"

For having Zero volt , DAC need 10 (MSB pin at 1 , others at 0)
Leave MSB pin at 1 , others at 0 as long as you want a 0volt, about 350degres (so most of the time)

The time MSB is 1 and other are 1 too  to produce a +12v is up to you.
If you want a 1ms pickup, then those 2 pins must not move during 1ms

Personally , I decided that ONE pulse last 10degree so the code is :
- send 10 to produce 0volt
- for positive pickup: send 11 to produce +12v
- wait (PERIOD/360) * 10           (PERIOD is in ms)

- send 10 to produce 0volt
-wait 'barWidth' millisecond you want

-send 00 to produce -12v
-wait (PERIOD/360) * 10           (PERIOD is in ms)
- send 10 to produce 0volt

That's it , then wait for the next rotation



>Do I use 'barWidth' for beginning of pulse to end of the other, or between the 2 pulses.

between the 2 pulses

Title: Re: CDI tester project
Post by: cattledog on Jan 20, 2019, 08:00 am
OK, I think I have it. I'll express things in degrees, and the event timing will be changed by RPM.

First, you will need a switch to set the AC trigger mode. This will be similar to the RISE/FALL switch and the CHARGEPULSE mode switch. Do you have this switch installed already?

Quote
Personally , I decided that ONE pulse last 10degree
In the AC Trigger mode you want the + and - pulses each to be 10 degrees long, separated by 60 degrees. We can make those values adjustable by a pot, but these sound like default starting values. I think you already have a pot 3 for bar width.

Quote
Other times the bar can be 60° long and the negative pulse is >at the beginning and then the positive is at the end of bar
You have also described and drawn the pulse train as starting with a positive 12 volts. i.e. +12v for 10 degrees, 0v for bar width(60) degrees, -12v for 10 degrees, 0v for remainder of the timing cycle.

What pulse do you want to lead with?

You will need to determine where you want the return pulse delay measurement to start. At present the RISE/FALL switch controls whether delay timing starts with the rise of the trigger or the fall of the trigger. With the AC trigger and the bar width, you will need to establish the the start of timing for the return.

I'm pretty sure you have a scope to measure output pulses. I think I will try to write a simple piece of test code at 1200 rpm (50 ms cycle timing). 50/360 = .139 milliseconds/degree or 140 microseconds/degree to use a nice round number. Let me know if you want to lead with 00 (-12v) or 11(+12v) and I will try to write some code which outputs the pulse train.

Do you have arduino pin numbers you want me to use for D1 and D2?

Title: Re: CDI tester project
Post by: tom_bauer on Jan 20, 2019, 04:27 pm
Hi, I can easily install a switch for AC trigger but I am not clear on it's purpose.

The pulse length can be hard coded as long as I can change it in the code easily, I assume I would be able to. Once set it would likely never be changed. The pot to change barWidth is all that is needed here and I have that along with the readout on display.

It would be nice to have the polarity of the output switchable and I think I can do that by swapping pins 2 & 4 on the DAC. So just + first should be OK.

To answer the last question I need to understand what you refer to as AC trigger.
Thanks, Tom

Title: Re: CDI tester project
Post by: cattledog on Jan 20, 2019, 05:29 pm
Quote
Hi, I can easily install a switch for AC trigger but I am not clear on it's purpose.
How will the program know to run the dual trigger pulse instead of the standard single pulse trigger for the cdi module?

Quote
To answer the last question I need to understand what you refer to as AC trigger.
I am referring to the two +/- voltage pulses as an AC trigger for the cdi module. If you have other terminology like "bipolar trigger" or anything else you like, let me know. I focus on the word trigger, because the pulses are used to trigger the delayed response from the module and we have used the word trigger in the existing code to refer to the outgoing pulse from the arduino.
Title: Re: CDI tester project
Post by: tom_bauer on Jan 20, 2019, 07:03 pm
Oh OK, I see what you think. No this as you say AC trigger, completely replaces the old single trigger.

Before I had the single trigger go to a very small transformer so as the trigger turns on it energizes the transformer and makes a output pulse, then it stays on for period of time and when it turns off the collapse of field in transformer also makes a opposite pulse. Crude but it works, now I just wanted to improve the system. Also I can code the Arduino to drive more bits of the DAC to make a better sine wave.

By the way I have a Hantek DSO5072P. I love it. Before I had a Tektronic 585A, 50 years old now and still works.
Tom
Title: Re: CDI tester project
Post by: tom_bauer on Jan 20, 2019, 07:42 pm
The output pins can be 4 and 5. I see that it may be necessary to have a switch to tell Arduino to do - or + first, no electronic way to easily swap them.
Tom
Title: Re: CDI tester project
Post by: cattledog on Jan 21, 2019, 12:27 am
Here's some code to test to see if we have the output pulses correct. Please check that I have the correct output to the DAC pins for the +/- 12 and 0 voltage.  I have tried to keep nomenclature similar to the original code. To get the two pulses, I have changed the timer mode from what we had, and broke the 360 degree cycle into two unequal pieces, each containing one pulse. Output compare interrupt B always turns off the pulses. I tested with an led indicator and a slower rpm and timer prescaler, but have left these adaptations commented in the code.  Throw a scope on this and tell me what you get. Ask any questions for clarification.

Code: [Select]
//You can use pots to set RPM, pulseWidthDegrees, and barWidth
unsigned int RPM = 1200;
//unsigned int RPM = 400;
unsigned int pulseWidthDegrees = 10;
unsigned int barWidthDegrees = 60;
unsigned long pulseWidthTime;
unsigned long timerTopValue;//sets 360 degree cycleTime
unsigned int timerTicksPerDegree;
const byte pinA = 4; //to DAC pins tied together
const byte pinB = 5; //to pin5 DAC

void setup() {
  pinMode(13, OUTPUT); //telltale led
  pinMode(pinA, OUTPUT);
  pinMode(pinB, OUTPUT);
  //initialize timer
  TCCR1A = 0;
  TCCR1B = 0;
  //set Timer1 mode Fast PWM to ICR1
  TCCR1B |= (1 << WGM13) | (1 << WGM12);
  TCCR1A |= (1 << WGM11);
 
  timerTopValue = 15000000UL / RPM;
  //15000000 timerTicksperMinute at 4 us per tick with prescaler 64
  //timerTopValue = 12500 at 1200 RPM 50ms per revolution
  timerTicksPerDegree = timerTopValue/360;
  ICR1 = timerTopValue;//initial placeholder
  pulseWidthTime = pulseWidthDegrees*timerTicksPerDegree;
  OCR1B = pulseWidthTime;

  //start Timer apply prescaler
  //TCCR1B |= (1 << CS12) | (1 << CS10); //1024 for led test
  TCCR1B |= (1<<CS11) | (1<<CS10);//64 for .5 us tick

  //enable B OutputCompare and Overflow interrupts
  TIMSK1 |= (1 << OCIE1B) | (1 << TOIE1);
}

void loop() {
}

ISR(TIMER1_COMPB_vect) {
  digitalWrite(13, LOW); //turn off pulse
  digitalWrite(pinA, LOW); //tied pins LOW
  digitalWrite(pinB, HIGH); //DAC5 HIGH
}

ISR(TIMER1_OVF_vect) {
  //alternate ICR1 values to generate two outputs
  //360 degree cycle time broken into two pieces
  static byte count = 0;
  if (count == 0)
  {
    ICR1 = timerTicksPerDegree*(pulseWidthDegrees+barWidthDegrees); //first pulse and bar width
    digitalWrite(13, HIGH);
    //positive pulse
    digitalWrite(pinA, HIGH);
    digitalWrite(pinB, HIGH);
  }
  if (count == 1)
  {
   ICR1 = timerTicksPerDegree*(360-(pulseWidthDegrees+barWidthDegrees));//second pulse and dead band
    digitalWrite(13, HIGH);
    //negative pulse
    digitalWrite(pinA, LOW);
    digitalWrite(pinB, LOW);
  }
  count++;
  if (count == 2)
    count = 0;
}

Title: Re: CDI tester project
Post by: tom_bauer on Jan 21, 2019, 03:00 am
OK, I have some parts on order and need to wire it up so it may be a few days. Thanks, I will keep in touch.
Tom
Title: Re: CDI tester project
Post by: cattledog on Jan 21, 2019, 03:11 am
Can you scope the output from the Arduino and confirm that it is what you want before connecting to all the other hardware down stream? I'd like to try and separate any software issues from subsequent hardware issues.
Title: Re: CDI tester project
Post by: tom_bauer on Jan 21, 2019, 04:26 am
OK I will look at it soon but I am tied up with other work til mid week
Tom
Title: Re: CDI tester project
Post by: tom_bauer on Jan 23, 2019, 12:56 am
OK pin 4 = yellow, 5 = blue
Title: Re: CDI tester project
Post by: cattledog on Jan 23, 2019, 02:41 am
I think that's what we wanted.
(http://forum.arduino.cc/index.php?action=dlattach;topic=425551.0;attach=291376)

Quote
Before I had the single trigger go to a very small transformer so as the trigger turns on it energizes the transformer and makes a output pulse, then it stays on for period of time and when it turns off the collapse of field in transformer also makes a opposite pulse.
Where to want to start timing the return pulse. How have you been using the R and F settings?

I think there are 4 places we can time from Start and Finish of the tied pins(yellow trace/PinA) going High and back to Low, or the Start and Finish of the single pin to DAC5(blue trace/PinB) going Low and then back to High.

I hope I have the pin and color designations correct. I think we should change the nomenclature from pinA and pinB to something else. dacTiedPins and dacPin5 works to clarify things for me. Do you ahve something else to call then which makes better sense to you?

Code: [Select]
const byte dacTiedPins = 4; //to DAC pins tied together
const byte dacPin5 = 5; //to pin5 DAC
Title: Re: CDI tester project
Post by: tom_bauer on Jan 23, 2019, 03:03 am
Hi, OK maybe this helps? I have to think about the R and F, to see if I only really use one.
Title: Re: CDI tester project
Post by: cattledog on Jan 23, 2019, 04:43 am
(http://forum.arduino.cc/index.php?action=dlattach;topic=425551.0;attach=291384)

Some comments on your understanding of what line in the code does what.

I recommend that you consider the cycle to start with the +12v pulse and that it is done with the code at lines 54-61. This + pulse (and the - pulse as well) are taken back to 0v with the code at line 44. The code triggering the -12v is at lines 62-69.

There are two interrupts which turn the pulses on and off.

Turn Off code, is in the Compare B interrupt which always occurs after 10 degrees of pulse length.

Turn On code, with either +12 or -12, is in the Overflow interrupt, and the time to overflow, or overall cycle length, is set by the rpm.

You could consider the alternating pulses as a switch case, or state machine, situation where the two alternating cases are 1)give a positive pulse and wait at 0v for the bar length time and 2)give a negative pulse and wait at 0v for the remainder of the cycle time.


Title: Re: CDI tester project
Post by: tom_bauer on Jan 24, 2019, 01:30 am
here is a little easier to see pattern, but yes it looks to do what is needed.
pin 4 = yellow
pin 5 = blue
Title: Re: CDI tester project
Post by: tom_bauer on Jan 24, 2019, 05:00 am
OK I have changed the comments a little to help me, so I hope you also think it is good description.
Also to consider, I leave the Rise / Fall switch at Rise all the time so it could be done just in code, no need for a switch anymore.
The other thing is that there should be a switch to choose Pos first or Neg first for this trigger pulse.

Code: [Select]


//You can use pots to set RPM, pulseWidthDegrees, and barWidth
unsigned int RPM = 1200;
//unsigned int RPM = 400;
unsigned int pulseWidthDegrees = 10;
unsigned int barWidthDegrees = 60;
unsigned long pulseWidthTime;
unsigned long timerTopValue;//sets 360 degree cycleTime
unsigned int timerTicksPerDegree;
const byte pinA = 4; //to DAC pin 6 - 12, called 6
const byte pinB = 5; //to DAC pin 5

void setup() {
  pinMode(13, OUTPUT); //telltale led
  pinMode(pinA, OUTPUT);
  pinMode(pinB, OUTPUT);
  //initialize timer
  TCCR1A = 0;
  TCCR1B = 0;
  //set Timer1 mode Fast PWM to ICR1
  TCCR1B |= (1 << WGM13) | (1 << WGM12);
  TCCR1A |= (1 << WGM11);
 
  timerTopValue = 15000000UL / RPM;
  //15000000 timerTicksperMinute at 4 us per tick with prescaler 64
  //timerTopValue = 12500 at 1200 RPM 50ms per revolution
  timerTicksPerDegree = timerTopValue/360;
  ICR1 = timerTopValue;//initial placeholder
  pulseWidthTime = pulseWidthDegrees*timerTicksPerDegree;
  OCR1B = pulseWidthTime;

  //start Timer apply prescaler
  //TCCR1B |= (1 << CS12) | (1 << CS10); //1024 for led test
  TCCR1B |= (1<<CS11) | (1<<CS10);//64 for .5 us tick

  //enable B OutputCompare and Overflow interrupts
  TIMSK1 |= (1 << OCIE1B) | (1 << TOIE1);
}

void loop() {
}

ISR(TIMER1_COMPB_vect) {
  digitalWrite(13, LOW);    //turn off pulse for 0 volt
  digitalWrite(pinA, LOW);  //DAC 6 LOW
  digitalWrite(pinB, HIGH); //DAC 5 HIGH
}

ISR(TIMER1_OVF_vect) {
  //alternate ICR1 values to generate two outputs
  //360 degree cycle time broken into two pieces
  static byte count = 0;
  if (count == 0)
  {
    ICR1 = timerTicksPerDegree*(pulseWidthDegrees+barWidthDegrees); //first pulse and bar width
    digitalWrite(13, HIGH);    //turn on pulse for +12v
    digitalWrite(pinA, HIGH);  //DAC 6 HIGH
    digitalWrite(pinB, HIGH);  //DAC 5 HIGH
  }
  if (count == 1)
  {
   ICR1 = timerTicksPerDegree*(360-(pulseWidthDegrees+barWidthDegrees));//second pulse and dead band
    digitalWrite(13, HIGH);   //turn on pulse for -12v
    digitalWrite(pinA, LOW);  //DAC 6 LOW
    digitalWrite(pinB, LOW);  //DAC 5 LOW
  }
  count++;
  if (count == 2)
    count = 0;
}



Title: Re: CDI tester project
Post by: cattledog on Jan 24, 2019, 08:34 am
Quote
OK I have changed the comments a little to help me, so I hope you also think it is good description.
Looks good to me.

Quote
The other thing is that there should be a switch to choose Pos first or Neg first for this trigger pulse.
I patched in the code for the first pulse polarity. You'll need to set up a toggle switch for this. I think you can use the R/F switch but in the current code it is on pin5 which is becoming an output.

Code: [Select]

//You can use pots to set RPM, pulseWidthDegrees, and barWidth
unsigned int RPM = 1200;
//unsigned int RPM = 400;
unsigned int pulseWidthDegrees = 10;
unsigned int barWidthDegrees = 60;
unsigned long pulseWidthTime;
unsigned long timerTopValue;//sets 360 degree cycleTime
unsigned int timerTicksPerDegree;
const byte pinA = 4; //to DAC pin 6 - 12, called 6
const byte pinB = 5; //to DAC pin 5
//set first pulse state with toggle switch like R/F or charging switch
//const byte setfirstPulseSwitch = ??;
//boolean firstPulsePos = true;
boolean firstPulsePos = false;

void setup() {
  pinMode(13, OUTPUT); //telltale led
  pinMode(pinA, OUTPUT);
  pinMode(pinB, OUTPUT);
  /*
    pinMode(setFirstPulseSwitch, INPUT_PULLUP);
    if (digitalRead(setFirstPulseSwitch) == HIGH)
     firstPulsePos = true;
    else
     firstPulsePos = false; //first pulse negative
  */

  //initialize timer
  TCCR1A = 0;
  TCCR1B = 0;
  //set Timer1 mode Fast PWM to ICR1
  TCCR1B |= (1 << WGM13) | (1 << WGM12);
  TCCR1A |= (1 << WGM11);

  timerTopValue = 15000000UL / RPM;
  //15000000 timerTicksperMinute at 4 us per tick with prescaler 64
  //timerTopValue = 12500 at 1200 RPM 50ms per revolution
  timerTicksPerDegree = timerTopValue / 360;
  ICR1 = timerTopValue;//initial placeholder
  pulseWidthTime = pulseWidthDegrees * timerTicksPerDegree;
  OCR1B = pulseWidthTime;

  //start Timer apply prescaler
  //TCCR1B |= (1 << CS12) | (1 << CS10); //1024 for led test 8us tick
  TCCR1B |= (1<<CS11) | (1<<CS10);//64 for .5 us tick

  //enable B OutputCompare and Overflow interrupts
  TIMSK1 |= (1 << OCIE1B) | (1 << TOIE1);
}

void loop() {
}

ISR(TIMER1_COMPB_vect) {
  digitalWrite(13, LOW);    //turn off pulse for 0 volt
  digitalWrite(pinA, LOW);  //DAC 6 LOW
  digitalWrite(pinB, HIGH); //DAC 5 HIGH
}

ISR(TIMER1_OVF_vect) {
  //alternate ICR1 values to generate two outputs
  //360 degree cycle time broken into two pieces
  static byte count = 0;
  if (count == 0) //first pulse
  {
    ICR1 = timerTicksPerDegree * (pulseWidthDegrees + barWidthDegrees); //first pulse and bar width
    digitalWrite(13, HIGH);
    if (firstPulsePos == true)
      setPulsePos();
    else
      setPulseNeg();//first pulse neg if firstPulsePos == false
  }
 
  if (count == 1)//second pulse
  {
    ICR1 = timerTicksPerDegree * (360 - (pulseWidthDegrees + barWidthDegrees)); //second pulse and dead band
    digitalWrite(13, HIGH);
    if (firstPulsePos)
      setPulseNeg();
    else
      setPulsePos();//first pulse was negative
  }
  count++;
  if (count == 2)
    count = 0;
}

void setPulsePos()
{
  digitalWrite(pinA, HIGH);  //DAC 6 HIGH
  digitalWrite(pinB, HIGH);  //DAC 5 HIGH
}

void setPulseNeg()
{
  digitalWrite(pinA, LOW );  //DAC 6 LOW
  digitalWrite(pinB, LOW);  //DAC 5 LOW
}
Title: Re: CDI tester project
Post by: tom_bauer on Jan 24, 2019, 05:10 pm
Hi, OK it works changing the polarity. I have assigned different pins, here is my choice,
D3 - timing signal from clamp on probe.
D4 - polarity switch
D5 - rise / fall
D6 - controls AC - DC output
D7 - output for charge pulses
D8 - to DAC 5
D9 - to DAC 6 - 12

This is the schematic of the whole tester.
Thanks, Tom
Title: Re: CDI tester project
Post by: cattledog on Jan 24, 2019, 07:34 pm
OK.
Quote
D4 - polarity switch
D5 - rise / fall
D6 - controls AC - DC output
Can you explain more to me about the three switches. I understand the polarity switch which will control which comes first +12 or -12.

Is D6 to use the current unipolar output or the new bipolar mode?  Previously you said that the bipolar output would replace the current mode. If we are keeping it, what pin is the output on?
EDIT: Is pin6 the switch which currently sets the charge pulses active? 

Do you still want to keep the rise/fall return timing start option? In the bipolar mode, Do you know which of the two pulses(+12v, -12v), and which edge do you want to start timing from?

Title: Re: CDI tester project
Post by: tom_bauer on Jan 25, 2019, 04:10 am
Hi,
OK, here is a more detailed view. D7 is the charge pulse out, D6 controls if it is active or not. Some CDI use DC to power them so when it is not active, 12v DC is output to the power connector J1/J2. Some CDI are AC powered so when it is active it makes the AC power with Q3, Q4 and TR3. So D6 can stay the way it is now.

Can we keep the rise fall switch as is until I confirm how the DAC is going to act? I think I need it to be set at rise but time will tell.

Is all this OK or are we near the capacity of the Arduino?
Best, Tom
Title: Re: CDI tester project
Post by: cattledog on Jan 25, 2019, 05:28 am
Thanks for the clarifications. 

Quote
Can we keep the rise fall switch as is until I confirm how the DAC is going to act? I think I need it to be set at rise but time will tell.
I think that given how the existing system is working with the negative pulse on the collapse of the first pulse field, it makes sense to keep the timing from the first pulse. When the first pulse is positive going, the rise/fall to begin on either the lead edge or trail edge of the pulse makes sense.

What do we want to do when the first pulse is negative going? Unless you think differently, I will leave R to mean the lead edge, and F to mean the trailing edge of the lead pulse, whatever the direction, + or -.

I will start integrating the the new pulse and switches into the existing code. If you need anything more, (beyond what we have which demonstrates the pulses) to use as simple test code when developing the hardware, let me know.

Quote
Is all this OK or are we near the capacity of the Arduino?
We are not close at all. The additions are not very code intensive, and this is from the existing code you posted.
Quote
Sketch uses 6860 bytes (21%) of program storage space. Maximum is 32256 bytes.
Global variables use 329 bytes (16%) of dynamic memory, leaving 1719 bytes for local variables. Maximum is 2048 bytes.
Title: Re: CDI tester project
Post by: tom_bauer on Jan 25, 2019, 02:29 pm
OK, what I am not sure of is how the pulse timing will work which is why I thought finally to leave rise/fall as is, well sort of anyway. Before, it only makes the one output and the transformer makes the pos and neg, with the DAC I think it still needs to time from the first edge of the output. But that output will be different than before. Hope you understand, I think you have it sorted!
Best, Tom
Title: Re: CDI tester project
Post by: cattledog on Jan 29, 2019, 05:00 am
Hi Tom--

Here's what I have so far. I hope it is enough to use to get your hardware set up.
I've put some of the code into functions, used the new pin numbers, coded for the toggled switch presets. I have not coded anything with the charge pulses, Timer2, and how the charge pulses coordinate with the bipolar pulses.

I am using a much improved library for the i2c lcd. It's called hd44780 and is available through the library manager for download. It is auto configuring for the i2c address and the configuration of the driver pins. It is faster, and lets you change out display without having to figure out if it's any different from the previous one. Use these magic words at the head of the sketch.
Code: [Select]
#include <Wire.h>
#include <hd44780.h>
#include <hd44780ioClass/hd44780_I2Cexp.h> // include i/o class header
hd44780_I2Cexp lcd; // declare lcd object: auto locate & config display for hd44780 chip


I've used a 16x2 with lcd.begin(16,2) in setup and you will need lcd.begin(20,4), and can adjust the the display code for what you want to show.

As before, I'm uncertain about how you want to present the time delay from the trigger pulse to the delayed response from the module. Delay/ Advance?  :smiley-confuse:

Let me know if this appears to be headed in the right direction.

Code: [Select]
//V1.0 set RPM potentiometer/configuration swtiches/hd44780 lcd/revised pin numbers

#include <Wire.h>
#include <hd44780.h>
#include <hd44780ioClass/hd44780_I2Cexp.h> // include i/o class header
hd44780_I2Cexp lcd; // declare lcd object: auto locate & config display for hd44780 chip

//utility definitions
#define positive HIGH
#define negative LOW
#define firstPulse 0
#define secondPulse 1

//You can use pots to set RPM, pulseWidthDegrees, and barWidth
unsigned int RPM = 1200;//adjusted with potementiometer
unsigned int pulseWidthDegrees = 10;
unsigned int barWidthDegrees = 60;
int pickupPositionOffset = 0; //timing offset from TDC

unsigned long pulseWidthTime;//degrees converted to time
unsigned long timerTopValue;//sets 360 degree cycleTime
unsigned int timerTicksPerDegree;

//output pins
const byte chargePin = 7; //charge pulses
const byte pinB = 8; //to DAC pin 5
const byte pinA = 9; //to DAC pin 6 - 12, called 6

//configuration switch setup
const byte polaritySwitch = 4;
boolean firstPulsePos = positive; //first pulse polarity
const byte setFallingSwitch = 5;
char risefall = 'R'; //default rising mode start timing from rising edge
const byte setChargePulseSwitch = 6;
boolean chargePulse = false ;  //AC CDI default is DC

const byte pot1 = A3; //input pin for pot which sets rpm

//return pulse interrupt variables
volatile boolean trigger = false;
volatile boolean interruptFlag;
volatile unsigned long delayPeriod;
unsigned long copy_delayPeriod;
volatile unsigned long delayPeriodStart;
float delayDegrees; // changed from int to float for decimal place display

void setup()
{
  Serial.begin(115200);
  //set outputs for 0v
  pinMode(13, OUTPUT); //telltale led
  digitalWrite(13, LOW);
  pinMode(pinA, OUTPUT);
  digitalWrite(pinA, LOW);  //DAC 6 LOW
  pinMode(pinB, OUTPUT);
  digitalWrite(pinB, HIGH); //DAC 5 HIGH
  pinMode(3, INPUT_PULLUP); //interrupt pin, return pulse drives low
  pinMode(chargePin, OUTPUT); // declare the chargePin as an OUTPUT

  // initialize LCD with number of columns and rows:
  lcd.begin(16, 2);
  lcd.setCursor(0, 0); // lcd display setup of unchanging headings
  lcd.print("RPM:"); // print fixed characters
  lcd.setCursor(9, 0);
  lcd.print("Mode:");
  lcd.setCursor(0, 1);
  lcd.print("1stPulse:"); //first pulse + or -
  lcd.setCursor(11, 1);
  lcd.print("CP:"); //charge pulse AC CDI Y or N

  setupTimer1();
  setupSwitchPresets();

  //15000000 timerTicksperMinute at 4 us per tick with prescaler 64
  //timerTopValue = 12500 at 1200 RPM 50ms per revolution
  timerTopValue = 15000000UL / RPM;
  timerTicksPerDegree = timerTopValue / 360;
  pulseWidthTime = pulseWidthDegrees * timerTicksPerDegree;
  TCNT1 = 0;
  OCR1B = pulseWidthTime;//timer ticks
  attachInterrupt(digitalPinToInterrupt(3), delayPeriodTiming, FALLING);
  delay(5000);//display setup parameters
  lcd.setCursor(0, 1);
  lcd.print("DelayDeg:");
}

void loop()
{
  const unsigned long analogReadInterval = 250;//250; //read pots and map
  static unsigned long lastAnalogRead = 0;
  if (millis() - lastAnalogRead >= analogReadInterval)
  {
    //add other potentiometer adjustments here
    lastAnalogRead += analogReadInterval;
    RPM = map(analogRead(pot1), 0, 1023, 500, 4000);
    //adjust timer values for RPM
    timerTopValue = 15000000UL / RPM;
    timerTicksPerDegree = timerTopValue / 360;
    pulseWidthTime = pulseWidthDegrees * timerTicksPerDegree;
    OCR1B = pulseWidthTime;

    lcd.setCursor(4, 0);
    lcd.print("           "); // print blank spaces to clear old data
    lcd.setCursor(5, 0);
    lcd.print(RPM);
    lcd.setCursor(9, 1);
    lcd.print("       ");
    lcd.setCursor(10, 1);
    lcd.print(delayDegrees);
  }

  if (trigger == true && interruptFlag == true )
  {
    trigger = false;
    interruptFlag = false;
    noInterrupts();
    copy_delayPeriod = delayPeriod;//microseconds
    interrupts();
    //Serial.print(copy_delayPeriod);
    //Serial.print('\t');
    //divide by 4 to convert microseconds to timer ticks
    delayDegrees = (copy_delayPeriod / 4) / timerTicksPerDegree;
    //Serial.println(delayDegrees);
    //delayDegrees = pickup - (360.0 * (copy_delayPeriod) / (timerTopValue * 4.0)); //for decimal place in deg display.
  }
}

void setupTimer1()
{
  TCCR1A = 0;
  TCCR1B = 0;
  TCNT1 = 0;
  //set Timer1 mode Fast PWM to ICR1
  TCCR1B |= (1 << WGM13) | (1 << WGM12);
  TCCR1A |= (1 << WGM11);
  //start Timer apply prescaler
  // TCCR1B |= (1 << CS12) | (1 << CS10); //1024 for led test 8us tick
  TCCR1B |= (1 << CS11) | (1 << CS10); //64 for .5 us tick
  //enable B OutputCompare and Overflow interrupts
  TIMSK1 |= (1 << OCIE1B) | (1 << TOIE1);
}

ISR(TIMER1_OVF_vect)
{
  //alternate ICR1 values to generate two outputs over 360 degrees
  //360 degree cycle time broken into two pieces
  //timerTopValue adjusted with RPM pot
  //timerTicksPerDegree = timerTopValue / 360; //gets new value to update ICR1
  static byte pulse = firstPulse;
  if (pulse == firstPulse)
  {
    ICR1 = timerTicksPerDegree * (pulseWidthDegrees + barWidthDegrees); //first pulse and bar width
    digitalWrite(13, HIGH);
    if (firstPulsePos == true)
      setPulse(positive);
    else
      setPulse(negative);
    //set timing start at lead edge of first pulse
    if (risefall == 'R')
    {
      delayPeriodStart = micros();                                          //start looking for response as pulse rises
      trigger = true;
    }
    else //risefall == 'F' set timing at trailing edge of first pulse
    {
      //convert pulseWidthTime in timer ticks to microseconds
      //prescaler 8 = 4us/timer tick
      delayPeriodStart = micros() + pulseWidthTime * 4;                                        //start looking for response as pulse rises
      trigger = true;
    }
    pulse = secondPulse; //next pulse
  }
  else //second pulse
  {
    ICR1 = timerTicksPerDegree * (360 - (pulseWidthDegrees + barWidthDegrees)); //second pulse and dead band
    digitalWrite(13, HIGH);
    if (firstPulsePos)
      setPulse(negative);
    else
      setPulse(positive);
    pulse = firstPulse; //next pulse
  }
}

ISR(TIMER1_COMPB_vect) {
  digitalWrite(13, LOW);    //turn off pulse for 0 volt
  digitalWrite(pinA, LOW);  //DAC 6 LOW
  digitalWrite(pinB, HIGH); //DAC 5 HIGH
}

void setPulse(byte state)    //state negative = LOW state positive = HIGH
{
  digitalWrite(pinA, state );  //DAC 6 state
  digitalWrite(pinB, state);  //DAC 5 state
}

void setupSwitchPresets()
{
  pinMode(setChargePulseSwitch, INPUT_PULLUP);
  if (digitalRead(setChargePulseSwitch) == LOW)
    chargePulse = true; //AC CDI
  else
    chargePulse = false;
  lcd.setCursor(14, 1);
  if (chargePulse)
    lcd.print("Y");
  else
    lcd.print("N");

  pinMode(polaritySwitch, INPUT_PULLUP);
  if (digitalRead(polaritySwitch) == HIGH)
    firstPulsePos = true; //first pulse positive
  else
    firstPulsePos = false; //first pulse negative
  lcd.setCursor(9, 1);
  if (firstPulsePos)
    lcd.print("+");
  else
    lcd.print("-");

  pinMode (setFallingSwitch, INPUT_PULLUP); //check for a LOW input to indicate switch is closed to ground
  if (digitalRead(setFallingSwitch) == LOW) //set Falling
  {
    risefall = 'F';
  }
  else
  {
    risefall = 'R';
  }
  lcd.setCursor(14, 0);
  lcd.print(risefall);
}

void delayPeriodTiming()
{
  delayPeriod = micros() - delayPeriodStart;
  interruptFlag = true;
}



Title: Re: CDI tester project
Post by: cattledog on Jan 29, 2019, 05:01 am
Can you explain to me why you have the difference in the rpm mapping in this section of your code when charge pulses are active?
Code: [Select]
if (chargePulse)
    {
      RPM = map(potValue, 0, 1023, 615, 10000);  //this section needs 2 pots added to set pickup and pulseWidth **************************
      pickup = 74; //map(pickupValue, 0, 1023, 0, 65); so advance will read based on delay,52 for yamaha 350 2 pu, 74 for 1 pu, 72 for tw200, 25 for 5013
      pulseWidth = (60000000/RPM)/360; //time for 1° in uS
      barWidth = 60; //barWidth = pulseWidth + 1000;  //10 for yamaha 350 2 pu, 60 for 1 pu, 60 for tw200
      //RPM = 615; //for my serial test purposes 615-3800
    }
    else
    {
      RPM = map(potValue, 0, 1023, 500, 3800);
      pickup = 25; //map(pickupValue, 0, 1023, 0, 50); //to set position of pickup so advance will read
      pulseWidth = map(potWidth, 0, 1023, 271, 44); //add Width to non charging case
     // RPM = 500;//for my serial test purposes 500-3800
    }
Title: Re: CDI tester project
Post by: tom_bauer on Jan 29, 2019, 05:13 pm
Hi and thanks!

When you say 'As before, I'm uncertain about how you want to present the time delay from the trigger pulse to the delayed response from the module. Delay/ Advance? ' I am not completely sure what you are asking.

When you ask 'Can you explain to me why you have the difference in the rpm mapping in this section of your code when charge pulses are active?'  The if section is for charge pulse output mode and the else section is when it is off and just DC out to CDI.

I tell you, it has been so long I have forgot some of this!
Tom
Title: Re: CDI tester project
Post by: cattledog on Jan 29, 2019, 06:57 pm
Quote
I tell you, it has been so long I have forgot some of this!
Me too! Start experimenting with the code I provided, and maybe your questions will get us both back to speed.
Title: Re: CDI tester project
Post by: tom_bauer on Jan 29, 2019, 07:26 pm
OK I will start this weekend if I can get caught up!! I also make power steering kits for military trucks,  and just got a big order.
Tom
Title: Re: CDI tester project
Post by: tom_bauer on Jan 30, 2019, 07:13 pm
Hi, also had a question about the pots. This is way ahead of itself but I saw this yesterday. The one for rpm can easily be a pot as it is not critical and I just sweep it the range I want. The bar width and length are a small range and should stay set at an exact number. You may remember I inquired about using an encoder in the past and now I see a 4131-103 digital pot. I wonder if it would be an easy way to do what I want or is there another way to input the numbers for those settings. To be honest I have just been writing to the code each time I need to change it!!
Tom
Title: Re: CDI tester project
Post by: cattledog on Jan 30, 2019, 07:49 pm
The digital pot does not seem much of an advantage over an analog pot(perhaps a 10 turn) with ranges to give values for +/- 1 from a known starting point. The digital pots may use more pins than an analog one.

For a small range, a rotary encoder is not a bad solution for user input, but again they use more pins than the analog pot.

User input for any program is always a tricky issue. Simple Bluetooth2.0 and a phone might be another solution.

Quote
To be honest I have just been writing to the code each time I need to change it!!
If this is not a significant problem, then its probably best to continue making adjustments this way until we get farther down the road with the new operating pulses.

 

Title: Re: CDI tester project
Post by: tom_bauer on Jan 30, 2019, 08:10 pm
Oh yes, I agree, it was just an academic question. I ordered a breadboard, have never used one! In the end I will have a printed circuit board made for  the final version.
Thanks, Tom
Title: Re: CDI tester project
Post by: tom_bauer on Jan 30, 2019, 10:57 pm
Hello, OK I have installed the library for LCD and it works bot does not display any values, not even rpm which I see is fixed for now. What functions should I test / work on first?
Tom
Title: Re: CDI tester project
Post by: cattledog on Jan 31, 2019, 01:39 am
Quote
Hello, OK I have installed the library for LCD and it works bot does not display any values, not even rpm which I see is fixed for now. What functions should I test / work on first?
I assume you are running the code posted in #184. Are you using a 20x4 lcd or 16x2?

Do you see the screen from setup which shows RPM with no number following and then the values of the three toggle switch settings, which if there are no switches will default to the Mode:R  1stPulse + and CP N?

The RPM is not fixed, but is set by a pot on A3
Code: [Select]
RPM = map(analogRead(pot1), 0, 1023, 500, 4000);
If you tie A3 to 3.3v you should see RPM near 2800.

I would work first to get a pot on A3, or otherwise, change the line with the RPM mapping to a fixed RPM.

The second line with DelayDegree should show 0.00 until there is a return pulse on the interrupt pin 3.

Title: Re: CDI tester project
Post by: tom_bauer on Jan 31, 2019, 02:29 am
Yes, 184's code with 20 x 4 lcd.
I will explore the settings and display in morning.
Thanks, Tom
Title: Re: CDI tester project
Post by: cattledog on Jan 31, 2019, 02:40 am
I've got a 20x4 on order, and should be able to work in your format when it arrives.
Title: Re: CDI tester project
Post by: tom_bauer on Jan 31, 2019, 06:03 pm
Hi, on lines 61 to 69 and then 102 to 109 there is lcd info that seems to conflict in a way I don't understand.
Tom
Title: Re: CDI tester project
Post by: cattledog on Jan 31, 2019, 06:25 pm
Because I was working with a 16x2 display, I didn't have the real estate for your current display parameters, so I tried to use a set up screen and then an operating screen.  I will have a 20x4 in a few days and can go back to your original approach with one screen.

Quote
that seems to conflict in a way I don't understand.
Can you explain more.

These lines are for a setup screen, and the values are filled in with the print statement in the setupSwitchPresets() function

Code: [Select]
//61-69
lcd.begin(16, 2);
lcd.setCursor(0, 0); // lcd display setup of unchanging headings
lcd.print("RPM:"); // print fixed characters
lcd.setCursor(9, 0);
lcd.print("Mode:");
lcd.setCursor(0, 1);
lcd.print("1stPulse:"); //first pulse + or -
lcd.setCursor(11, 1);


These lines are for the operating screen and show the current RPM from the pot setting, and the delay of the return pulse from the module from the point in time when the R or F edge of trigger pulse was sent.

Code: [Select]
/102-109
lcd.setCursor(4, 0);
lcd.print("           "); // print blank spaces to clear old data
lcd.setCursor(5, 0);
lcd.print(RPM);
lcd.setCursor(9, 1);
lcd.print("       ");
lcd.setCursor(10, 1);
lcd.print(delayDegrees, 1);


We should get bact to the 20x4, and display what ever data makes sense to you.
Title: Re: CDI tester project
Post by: tom_bauer on Jan 31, 2019, 07:43 pm
Hi, OK I think I see. Yes I would like to go to the display I had, it shows everything I want to know. No need for the firstPulse info, I will see if the toggle switch is up for + or down for -. Also I prefer the Degrees Advanced, I had a calculation in the last code that did that quite well.
Tom
Title: Re: CDI tester project
Post by: tom_bauer on Feb 01, 2019, 09:06 pm
Hi, I have done some testing and here is my revision of the code. Pins 6, 5, 4 do not update, require a reboot, how to have them reset parameters when they are changed?

No charge pulses on pin 7.

LCD would not work until I moved the code from line 248 to 129 and from 259 to 123

Tom



Code: [Select]
//V1.0 set RPM potentiometer/configuration swtiches/hd44780 lcd/revised pin numbers

#include <Wire.h>
#include <hd44780.h>
#include <hd44780ioClass/hd44780_I2Cexp.h> // include i/o class header
hd44780_I2Cexp lcd; // declare lcd object: auto locate & config display for hd44780 chip

//utility definitions
#define positive HIGH
#define negative LOW
#define firstPulse 0
#define secondPulse 1

//You can use pots to set RPM, pulseWidthDegrees, and barWidth
//unsigned int RPM = 1200;//adjusted with potementiometer
unsigned int pulseWidthDegrees = 10;
unsigned int barWidthDegrees = 60;
int pickupPositionOffset = 0; //timing offset from TDC

unsigned long pulseWidthTime;//degrees converted to time
unsigned long timerTopValue;//sets 360 degree cycleTime
unsigned int timerTicksPerDegree;

//output pins
const byte chargePin = 7; //charge pulses
const byte pinB = 8;      //to DAC pin 5
const byte pinA = 9;      //to DAC pin 6 - 12, called 6

//configuration switch setup
const byte polaritySwitch = 4;
boolean firstPulsePos = positive; //first pulse polarity
const byte setFallingSwitch = 5;
char risefall = 'R'; //default rising mode start timing from rising edge
const byte setChargePulseSwitch = 6;
boolean chargePulse = false ;  //AC CDI default is DC

int pot1 = A3; //input pin for pot which sets rpm

//return pulse interrupt variables
volatile boolean trigger = false;
volatile boolean interruptFlag;
volatile unsigned long delayPeriod;
unsigned long copy_delayPeriod;
volatile unsigned long delayPeriodStart;
float delayDegrees; // changed from int to float for decimal place display


int RPM;
int pickup;
int barWidth;
int pulseWidth;


void setup()
{
  Serial.begin(115200);
  //set outputs for 0v
  pinMode(13, OUTPUT); //telltale led
  digitalWrite(13, LOW);
  pinMode(pinA, OUTPUT);
  digitalWrite(pinA, LOW);  //DAC 6 LOW
  pinMode(pinB, OUTPUT);
  digitalWrite(pinB, HIGH); //DAC 5 HIGH
  pinMode(3, INPUT_PULLUP); //interrupt pin, return pulse drives low
  pinMode(chargePin, OUTPUT); // declare the chargePin as an OUTPUT

  // initialize LCD with number of columns and rows:
  lcd.begin(20, 4); // initialize the lcd for 20 chars 4 lines, turn on backlight
  lcd.setCursor(0, 0); // lcd display setup of unchanging headings
  lcd.print("RPM:"); // print fixed characters
  lcd.setCursor(9, 0);
  lcd.print("Mode:"); //to display code choice R or F
  lcd.setCursor(1, 1);
  lcd.print("Pos:");
  lcd.setCursor(9, 1);
  lcd.print("Width:");
  lcd.setCursor(1, 2);
  lcd.print("Us Delay:");
  lcd.setCursor(1, 3);
  lcd.print("Deg Advance:");

  setupTimer1();
  setupSwitchPresets();

  //15000000 timerTicksperMinute at 4 us per tick with prescaler 64
  //timerTopValue = 12500 at 1200 RPM 50ms per revolution
  timerTopValue = 15000000UL / RPM;
  timerTicksPerDegree = timerTopValue / 360;
  pulseWidthTime = pulseWidthDegrees * timerTicksPerDegree;
  TCNT1 = 0;
  OCR1B = pulseWidthTime;//timer ticks
  attachInterrupt(digitalPinToInterrupt(3), delayPeriodTiming, FALLING);
  delay(5000);//display setup parameters
  //lcd.setCursor(0, 1);
 //lcd.print("DelayDeg:");
}

void loop()
{
  const unsigned long analogReadInterval = 250;//250; //read pots and map
  static unsigned long lastAnalogRead = 0;
  if (millis() - lastAnalogRead >= analogReadInterval)
  {
    //add other potentiometer adjustments here
    lastAnalogRead += analogReadInterval;
    RPM = map(analogRead(pot1), 0, 1023, 500, 4000);
    //adjust timer values for RPM
    timerTopValue = 15000000UL / RPM;
    timerTicksPerDegree = timerTopValue / 360;
    pulseWidthTime = pulseWidthDegrees * timerTicksPerDegree;
    OCR1B = pulseWidthTime;

    lcd.setCursor(4, 0);
    lcd.print("     "); // print blank spaces to clear old data
    lcd.setCursor(4, 0);
    lcd.print(RPM);

    lcd.setCursor(14, 0);
    lcd.print("  ");
    lcd.setCursor(14, 0);
    lcd.print(risefall); //print R or F at upper right side

    lcd.setCursor(16, 0);
  if (firstPulsePos)
    lcd.print("+");
  else
    lcd.print("-");

    lcd.setCursor(18, 0);   
  if (chargePulse)
    lcd.print("AC");
  else
    lcd.print("DC");

    lcd.setCursor(6, 1);
    lcd.print("   ");
    lcd.setCursor(6, 1);
    lcd.print(pickup);

    lcd.setCursor(16, 1);
    lcd.print("   ");
    lcd.setCursor(16, 1);
    lcd.print(pulseWidth);

    lcd.setCursor(11, 2);
    lcd.print("       ");
    lcd.setCursor(11, 2);
    lcd.print(copy_delayPeriod);
   
    lcd.setCursor(14, 3);
    lcd.print("      ");
    lcd.setCursor(14, 3);
    lcd.print(delayDegrees, 1);   //delayDegrees, 1);
  }

  if (trigger == true && interruptFlag == true )
  {
    trigger = false;
    interruptFlag = false;
    noInterrupts();
    copy_delayPeriod = delayPeriod;//microseconds
    interrupts();
    //Serial.print(copy_delayPeriod);
    //Serial.print('\t');
    //divide by 4 to convert microseconds to timer ticks
    delayDegrees = (copy_delayPeriod / 4) / timerTicksPerDegree;
    //Serial.println(delayDegrees);
    //delayDegrees = pickup - (360.0 * (copy_delayPeriod) / (timerTopValue * 4.0)); //for decimal place in deg display.
  }
}

void setupTimer1()
{
  TCCR1A = 0;
  TCCR1B = 0;
  TCNT1 = 0;
  //set Timer1 mode Fast PWM to ICR1
  TCCR1B |= (1 << WGM13) | (1 << WGM12);
  TCCR1A |= (1 << WGM11);
  //start Timer apply prescaler
  // TCCR1B |= (1 << CS12) | (1 << CS10); //1024 for led test 8us tick
  TCCR1B |= (1 << CS11) | (1 << CS10); //64 for .5 us tick
  //enable B OutputCompare and Overflow interrupts
  TIMSK1 |= (1 << OCIE1B) | (1 << TOIE1);
}

ISR(TIMER1_OVF_vect)
{
  //alternate ICR1 values to generate two outputs over 360 degrees
  //360 degree cycle time broken into two pieces
  //timerTopValue adjusted with RPM pot
  //timerTicksPerDegree = timerTopValue / 360; //gets new value to update ICR1
  static byte pulse = firstPulse;
  if (pulse == firstPulse)
  {
    ICR1 = timerTicksPerDegree * (pulseWidthDegrees + barWidthDegrees); //first pulse and bar width
    digitalWrite(13, HIGH);
    if (firstPulsePos == true)
      setPulse(positive);
    else
      setPulse(negative);
    //set timing start at lead edge of first pulse
    if (risefall == 'R')
    {
      delayPeriodStart = micros();                                          //start looking for response as pulse rises
      trigger = true;
    }
    else //risefall == 'F' set timing at trailing edge of first pulse
    {
      //convert pulseWidthTime in timer ticks to microseconds
      //prescaler 8 = 4us/timer tick
      delayPeriodStart = micros() + pulseWidthTime * 4;                    //start looking for response as pulse rises
      trigger = true;
    }
    pulse = secondPulse; //next pulse
  }
  else //second pulse
  {
    ICR1 = timerTicksPerDegree * (360 - (pulseWidthDegrees + barWidthDegrees)); //second pulse and dead band
    digitalWrite(13, HIGH);
    if (firstPulsePos)
      setPulse(negative);
    else
      setPulse(positive);
    pulse = firstPulse; //next pulse
  }
}

ISR(TIMER1_COMPB_vect) {
  digitalWrite(13, LOW);    //turn off pulse for 0 volt
  digitalWrite(pinA, LOW);  //DAC 6 LOW
  digitalWrite(pinB, HIGH); //DAC 5 HIGH
}

void setPulse(byte state)    //state negative = LOW state positive = HIGH
{
  digitalWrite(pinA, state );  //DAC 6 state
  digitalWrite(pinB, state);  //DAC 5 state
}

void setupSwitchPresets()
{
  pinMode(setChargePulseSwitch, INPUT_PULLUP);
  if (digitalRead(setChargePulseSwitch) == LOW)
    chargePulse = true; //AC CDI
  else
    chargePulse = false;
  //lcd.setCursor(19, 0);   //moved to line 129
  //if (chargePulse)
    //lcd.print("Y");
  //else
    //lcd.print("N");

  pinMode(polaritySwitch, INPUT_PULLUP);
  if (digitalRead(polaritySwitch) == HIGH)
    firstPulsePos = true; //first pulse positive
  else
    firstPulsePos = false; //first pulse negative
  //lcd.setCursor(17, 0);   // moved to line 123
  //if (firstPulsePos)
    //lcd.print("+");
  //else
    //lcd.print("-");

  pinMode (setFallingSwitch, INPUT_PULLUP); //check for a LOW input to indicate switch is closed to ground
  if (digitalRead(setFallingSwitch) == LOW) //set Falling
  {
    risefall = 'F';
  }
  else
  {
    risefall = 'R';
  }
  //lcd.setCursor(14, 0);
  //lcd.print(risefall);
}

void delayPeriodTiming()
{
  delayPeriod = micros() - delayPeriodStart;
  interruptFlag = true;
}

Title: Re: CDI tester project
Post by: cattledog on Feb 02, 2019, 12:30 am
Nice progress getting the code back to the 20x4 display.

Quote
Pins 6, 5, 4 do not update, require a reboot, how to have them reset parameters when they are changed?
Add the function setupSwitchPresets() into this section of loop(). The pinMode() calls in the function should  be moved into setup().

Code: [Select]
if (millis() - lastAnalogRead >= analogReadInterval)
  {
      //all the pot/switch reading to change settings and display them code
   }


Quote
No charge pulses on pin 7.
Correct. I am working on the timer2 and charge pulse code now. With the dual pulses I think there may be some changes about how the charge pulses are coordinated and synced to the trigger pulse.

Quote
LCD would not work until I moved the code from line 248 to 129 and from 259 to 123
This does not make sense to me, but when I get the 20x4 on line I can revisit this. It does not make any difference it you are going to change the toggle switch settings while the code is running.

Quote
Also I prefer the Degrees Advanced, I had a calculation in the last code that did that quite well.
First, declare a new global variable called degreesAdvance and call it when/where you want to display it on the lcd.

Then add a new line to the code after the line of code which calculates the delayDegrees from the interrupt timing of the delayPeriod.

Code: [Select]
delayDegrees = (copy_delayPeriod / 4) / timerTicksPerDegree;
degreesAdvance = pickup - delayDegrees;


This will be the degrees before TDC of  the return pulse.

When do you think you will have the hardware set up to test the dual pulses? Can you do that without the charge pulses?




Title: Re: CDI tester project
Post by: tom_bauer on Feb 02, 2019, 12:59 am
'Add the function setupSwitchPresets() into this section of loop(). The pinMode() calls in the function should  be moved into setup().

Code: [Select]
if (millis() - lastAnalogRead >= analogReadInterval)
  {
      //all the pot/switch reading to change settings and display them code
   }
'
This I do not really understand..??

OK re the charge pulses, actually now it may be good to have twice as many pulses for the charge output to drive the transformer that makes the AC.

'This does not make sense to me, but when I get the 20x4 on line I can revisit this. It does not make any difference it you are going to change the toggle switch settings while the code is running.'
The way it was the Arduino would not even start until I commented out those lines.

'First, declare a new global variable called degreesAdvance and call it when/where you want to display it on the lcd.
Then add a new line to the code
Code: [Select]
delayDegrees = (copy_delayPeriod / 4) / timerTicksPerDegree;
degreesAdvance = pickup - delayDegrees;

This will be the degrees before TDC of  the return pulse.'

OK I will work on this after I get the hardware set up.

'When do you think you will have the hardware set up to test the dual pulses? Can you do that without the charge pulses?'

Yes I can, but the pulses look correct on the scope so I have little doubt it will work correctly when wired up. Bread board should be here tomorrow.
Tom





[/quote]
Title: Re: CDI tester project
Post by: cattledog on Feb 02, 2019, 01:14 am
Quote
'Add the function setupSwitchPresets() into this section of loop(). The pinMode() calls in the function should  be moved into setup().
Quote
This I do not really understand..??
Code: [Select]
//V1.0 set RPM potentiometer/configuration swtiches/hd44780 lcd/revised pin numbers

#include <Wire.h>
#include <hd44780.h>
#include <hd44780ioClass/hd44780_I2Cexp.h> // include i/o class header
hd44780_I2Cexp lcd; // declare lcd object: auto locate & config display for hd44780 chip

//utility definitions
#define positive HIGH
#define negative LOW
#define firstPulse 0
#define secondPulse 1

//You can use pots to set RPM, pulseWidthDegrees, and barWidth
//unsigned int RPM = 1200;//adjusted with potementiometer
unsigned int pulseWidthDegrees = 10;
unsigned int barWidthDegrees = 60;
int pickupPositionOffset = 0; //timing offset from TDC

unsigned long pulseWidthTime;//degrees converted to time
unsigned long timerTopValue;//sets 360 degree cycleTime
unsigned int timerTicksPerDegree;

//output pins
const byte chargePin = 7; //charge pulses
const byte pinB = 8;      //to DAC pin 5
const byte pinA = 9;      //to DAC pin 6 - 12, called 6

//configuration switch setup
const byte polaritySwitch = 4;
boolean firstPulsePos = positive; //first pulse polarity
const byte setFallingSwitch = 5;
char risefall = 'R'; //default rising mode start timing from rising edge
const byte setChargePulseSwitch = 6;
boolean chargePulse = false ;  //AC CDI default is DC

int pot1 = A3; //input pin for pot which sets rpm

//return pulse interrupt variables
volatile boolean trigger = false;
volatile boolean interruptFlag;
volatile unsigned long delayPeriod;
unsigned long copy_delayPeriod;
volatile unsigned long delayPeriodStart;
float delayDegrees; // changed from int to float for decimal place display


int RPM;
int pickup;
int barWidth;
int pulseWidth;


void setup()
{
  Serial.begin(115200);
  //set outputs for 0v
  pinMode(13, OUTPUT); //telltale led
  digitalWrite(13, LOW);
  pinMode(pinA, OUTPUT);
  digitalWrite(pinA, LOW);  //DAC 6 LOW
  pinMode(pinB, OUTPUT);
  digitalWrite(pinB, HIGH); //DAC 5 HIGH
  pinMode(3, INPUT_PULLUP); //interrupt pin, return pulse drives low
  pinMode(chargePin, OUTPUT); // declare the chargePin as an OUTPUT
  //add toggle switch pinMode
  pinMode(setFallingSwitch, INPUT_PULLUP);
  pinMode(polaritySwitch, INPUT_PULLUP);
  pinMode(setChargePulseSwitch, INPUT_PULLUP);

  // initialize LCD with number of columns and rows:
  lcd.begin(20, 4); // initialize the lcd for 20 chars 4 lines, turn on backlight
  lcd.setCursor(0, 0); // lcd display setup of unchanging headings
  lcd.print("RPM:"); // print fixed characters
  lcd.setCursor(9, 0);
  lcd.print("Mode:"); //to display code choice R or F
  lcd.setCursor(1, 1);
  lcd.print("Pos:");
  lcd.setCursor(9, 1);
  lcd.print("Width:");
  lcd.setCursor(1, 2);
  lcd.print("Us Delay:");
  lcd.setCursor(1, 3);
  lcd.print("Deg Advance:");

  setupTimer1();
  setupSwitchPresets();

  //15000000 timerTicksperMinute at 4 us per tick with prescaler 64
  //timerTopValue = 12500 at 1200 RPM 50ms per revolution
  timerTopValue = 15000000UL / RPM;
  timerTicksPerDegree = timerTopValue / 360;
  pulseWidthTime = pulseWidthDegrees * timerTicksPerDegree;
  TCNT1 = 0;
  OCR1B = pulseWidthTime;//timer ticks
  attachInterrupt(digitalPinToInterrupt(3), delayPeriodTiming, FALLING);
  delay(5000);//display setup parameters
  //lcd.setCursor(0, 1);
  //lcd.print("DelayDeg:");
}

void loop()
{
  const unsigned long analogReadInterval = 250;//250; //read pots and map
  static unsigned long lastAnalogRead = 0;
  if (millis() - lastAnalogRead >= analogReadInterval)
  {
    //add other potentiometer adjustments here
    lastAnalogRead += analogReadInterval;
    RPM = map(analogRead(pot1), 0, 1023, 500, 4000);
    //adjust timer values for RPM
    timerTopValue = 15000000UL / RPM;
    timerTicksPerDegree = timerTopValue / 360;
    pulseWidthTime = pulseWidthDegrees * timerTicksPerDegree;
    OCR1B = pulseWidthTime;

    setupSwitchPresets();

    lcd.setCursor(4, 0);
    lcd.print("     "); // print blank spaces to clear old data
    lcd.setCursor(4, 0);
    lcd.print(RPM);

    lcd.setCursor(14, 0);
    lcd.print("  ");
    lcd.setCursor(14, 0);
    lcd.print(risefall); //print R or F at upper right side

    lcd.setCursor(16, 0);
    if (firstPulsePos)
      lcd.print("+");
    else
      lcd.print("-");

    lcd.setCursor(18, 0);
    if (chargePulse)
      lcd.print("AC");
    else
      lcd.print("DC");

    lcd.setCursor(6, 1);
    lcd.print("   ");
    lcd.setCursor(6, 1);
    lcd.print(pickup);

    lcd.setCursor(16, 1);
    lcd.print("   ");
    lcd.setCursor(16, 1);
    lcd.print(pulseWidth);

    lcd.setCursor(11, 2);
    lcd.print("       ");
    lcd.setCursor(11, 2);
    lcd.print(copy_delayPeriod);

    lcd.setCursor(14, 3);
    lcd.print("      ");
    lcd.setCursor(14, 3);
    lcd.print(delayDegrees, 1);   //delayDegrees, 1);
  }

  if (trigger == true && interruptFlag == true )
  {
    trigger = false;
    interruptFlag = false;
    noInterrupts();
    copy_delayPeriod = delayPeriod;//microseconds
    interrupts();
    //Serial.print(copy_delayPeriod);
    //Serial.print('\t');
    //divide by 4 to convert microseconds to timer ticks
    delayDegrees = (copy_delayPeriod / 4) / timerTicksPerDegree;
    //Serial.println(delayDegrees);
    //delayDegrees = pickup - (360.0 * (copy_delayPeriod) / (timerTopValue * 4.0)); //for decimal place in deg display.
  }
}

void setupTimer1()
{
  TCCR1A = 0;
  TCCR1B = 0;
  TCNT1 = 0;
  //set Timer1 mode Fast PWM to ICR1
  TCCR1B |= (1 << WGM13) | (1 << WGM12);
  TCCR1A |= (1 << WGM11);
  //start Timer apply prescaler
  // TCCR1B |= (1 << CS12) | (1 << CS10); //1024 for led test 8us tick
  TCCR1B |= (1 << CS11) | (1 << CS10); //64 for .5 us tick
  //enable B OutputCompare and Overflow interrupts
  TIMSK1 |= (1 << OCIE1B) | (1 << TOIE1);
}

ISR(TIMER1_OVF_vect)
{
  //alternate ICR1 values to generate two outputs over 360 degrees
  //360 degree cycle time broken into two pieces
  //timerTopValue adjusted with RPM pot
  //timerTicksPerDegree = timerTopValue / 360; //gets new value to update ICR1
  static byte pulse = firstPulse;
  if (pulse == firstPulse)
  {
    ICR1 = timerTicksPerDegree * (pulseWidthDegrees + barWidthDegrees); //first pulse and bar width
    digitalWrite(13, HIGH);
    if (firstPulsePos == true)
      setPulse(positive);
    else
      setPulse(negative);
    //set timing start at lead edge of first pulse
    if (risefall == 'R')
    {
      delayPeriodStart = micros();                                          //start looking for response as pulse rises
      trigger = true;
    }
    else //risefall == 'F' set timing at trailing edge of first pulse
    {
      //convert pulseWidthTime in timer ticks to microseconds
      //prescaler 8 = 4us/timer tick
      delayPeriodStart = micros() + pulseWidthTime * 4;                    //start looking for response as pulse rises
      trigger = true;
    }
    pulse = secondPulse; //next pulse
  }
  else //second pulse
  {
    ICR1 = timerTicksPerDegree * (360 - (pulseWidthDegrees + barWidthDegrees)); //second pulse and dead band
    digitalWrite(13, HIGH);
    if (firstPulsePos)
      setPulse(negative);
    else
      setPulse(positive);
    pulse = firstPulse; //next pulse
  }
}

ISR(TIMER1_COMPB_vect) {
  digitalWrite(13, LOW);    //turn off pulse for 0 volt
  digitalWrite(pinA, LOW);  //DAC 6 LOW
  digitalWrite(pinB, HIGH); //DAC 5 HIGH
}

void setPulse(byte state)    //state negative = LOW state positive = HIGH
{
  digitalWrite(pinA, state );  //DAC 6 state
  digitalWrite(pinB, state);  //DAC 5 state
}

void setupSwitchPresets()
{
  //pinMode(setChargePulseSwitch, INPUT_PULLUP);
  if (digitalRead(setChargePulseSwitch) == LOW)
    chargePulse = true; //AC CDI
  else
    chargePulse = false;
  //lcd.setCursor(19, 0);   //moved to line 129
  //if (chargePulse)
  //lcd.print("Y");
  //else
  //lcd.print("N");

  //pinMode(polaritySwitch, INPUT_PULLUP);
  if (digitalRead(polaritySwitch) == HIGH)
    firstPulsePos = true; //first pulse positive
  else
    firstPulsePos = false; //first pulse negative
  //lcd.setCursor(17, 0);   // moved to line 123
  //if (firstPulsePos)
  //lcd.print("+");
  //else
  //lcd.print("-");

  //pinMode (setFallingSwitch, INPUT_PULLUP); //check for a LOW input to indicate switch is closed to ground
  if (digitalRead(setFallingSwitch) == LOW) //set Falling
  {
    risefall = 'F';
  }
  else
  {
    risefall = 'R';
  }
  //lcd.setCursor(14, 0);
  //lcd.print(risefall);
}

void delayPeriodTiming()
{
  delayPeriod = micros() - delayPeriodStart;
  interruptFlag = true;
}
Title: Re: CDI tester project
Post by: cattledog on Feb 02, 2019, 05:55 am
Quote
OK re the charge pulses, actually now it may be good to have twice as many pulses for the charge output to drive the transformer that makes the AC.
In the existing program, there are 5 pulses of 30 degrees starting at 60 degrees
ON at 60,120,180,240,300 = 2,4,6,8,10
OFF at 90,150,210,270,330 = 3,5,7,9,11[/quote]

Do you want say 10 pulses of 15 degrees over the same 240 degrees? Do you want something different than equal duty cycle on/off to cover more of the 360 with pulses. Can we be closer to TDC with the pulses. Now, there is 120 degrees around 0 with no pulses?
Title: Re: CDI tester project
Post by: tom_bauer on Feb 02, 2019, 06:26 am
Hi, No, never mind me, I was thinking wrong. Pulses are fine as is.
Tom
Title: Re: CDI tester project
Post by: tom_bauer on Feb 02, 2019, 05:53 pm
Hi, OK, all tested, all working. Later today I may get to do final test of pulses for DAC just to confirm that they match rpm but I assume they do/will.
Tom
Title: Re: CDI tester project
Post by: cattledog on Feb 02, 2019, 08:28 pm
Here is the code attached with the charge pulses back in. I have cleaned up some variables and nomenclature. The current code only displays one "width" and I wasn't sure if it was barWidthDegrees or pulseWidthDegrees. You may want to change the display to show both.




Title: Re: CDI tester project
Post by: tom_bauer on Feb 08, 2019, 05:13 pm
Hi, I was adding the pots and changed a couple variable names and now it won't compile!! I must have done something dumb!
Tom
Title: Re: CDI tester project
Post by: cattledog on Feb 08, 2019, 07:34 pm
Ok, Here's your version which now compiles. Tere was a misplaced bracket and an undefined variable.
I now have my 20x4 online so I can follow your work more closely,

I see a couple of problems with the code as provided.

You are mapping two values from the same pot. Is that correct?
Code: [Select]
pickupValue = map(analogRead(pot2), 0, 1023, 10, 90);
    barWidth = map(analogRead(pot2), 0, 1023, 20, 80);


I think this should be pickupValue if you want the pot controlled variable and not the fixed one I had.
Code: [Select]
lcd.print(pickup);

I leave you to make these changes to the code if I'm correct.

Have you had the charge pulses on the scope? If so, do they look correct in relationship to the trigger pulse?



Title: Re: CDI tester project
Post by: cattledog on Feb 08, 2019, 07:45 pm
I just noted another error in the analogRead() pot mapping section. The placement of the new readings had broken the if/else construction of the rpm mapping with and without the charge pulses. That section should look like this.

Code: [Select]
if (millis() - lastAnalogRead >= analogReadInterval)
  {
    //add other potentiometer adjustments here
    lastAnalogRead += analogReadInterval;
    if (chargePulse)//lowest rpm with charge pulse is 615
      RPM = map(analogRead(pot1), 0, 1023, 615, 4000);
    else
      RPM = map(analogRead(pot1), 0, 1023, 500, 4000);
    pickupValue = map(analogRead(pot2), 0, 1023, 10, 90);//two variables on same pot
    barWidth = map(analogRead(pot2), 0, 1023, 20, 80);//two variables on same pot

  }


EDIT:

With the new adjustable variable pickupValue the code for degreesAdvance should change.

Code: [Select]
//degreesAdvance = pickup - delayDegrees;
    degreesAdvance = pickupValue - delayDegrees;
Title: Re: CDI tester project
Post by: tom_bauer on Feb 08, 2019, 09:14 pm
Hi, OK I will work with this for a while. Yes there are 3 pots so should be 1 is rpm, 2 is pickup, 3 is bar width.
Many thanks, Tom
Title: Re: CDI tester project
Post by: tom_bauer on Feb 09, 2019, 03:42 pm
Hi, OK with just the rpm pot it works. With the installation of either of the other 2 it crashes.
Tom
Title: Re: CDI tester project
Post by: cattledog on Feb 09, 2019, 07:26 pm
You can not use A4 and A5 for the new adjustment pots. They are common with the SDA and SCL pins for the i2c lcd.
I have changed them to A2 and A1 and the code does not crash. One other correction is that pulseWidth needs a non zero value, and I have set it to 10 degrees. There was also an incorrect arrangement of the if/else on the rpm mapping with the charge pulses which I have corrected.

Title: Re: CDI tester project
Post by: tom_bauer on Feb 09, 2019, 08:16 pm
OK, thanks. I will do some more testing and see it the DAC will work! But waiting on the dc-dc converter from China.
Tom
Title: Re: CDI tester project
Post by: tom_bauer on Feb 10, 2019, 09:04 pm
Hi, on line 98 it says FALLING. I have a tester with the code here to check the time from output trigger on pin 9 to the signal back on pin 3. I think I may be ahead of myself here but it is off by 600 uS. When delay is 0 it reports 600. Probably this is fine tuning and must wait for DAC to be working. Also I need confirmation this code would be accurate?
Here is shot of the charge pulses and the pin 6 - 12 of DAC.
Thanks, Tom

Code: [Select]


// variable delay output for testing main board Us Delay line
// with display
int pot1 = A3;            // select the input pin for the pot (changed for this version because of lcd)
int delayValue = 0;       // variable to store the value coming from the sensor
unsigned long analogReadInterval = 1000;//read pot and map
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
// set the LCD address to 0x3f for a 20 chars 4 line display
// Set the pins on the I2C chip used for LCD connections:
//                    addr, en,rw,rs,d4,d5,d6,d7,bl,blpol
LiquidCrystal_I2C lcd(0x3f, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);             // Set the LCD I2C address

void setup() {
  Serial.begin(9600);
  lcd.begin(20, 4);                                                        // initialize the lcd for 20 chars 4 lines, turn on backlight
  lcd.setCursor(2, 0);                                                     // lcd display setup of unchanging headings
  lcd.print("Us Delay:");                                                  // print fixed characters
  
   attachInterrupt(digitalPinToInterrupt(3),pulse, FALLING);               //added this line to have any pulse out**********
   pinMode(7,OUTPUT);
  
}

void loop()
  {
    delayValue = analogRead(pot1);
    delayValue = map(delayValue, 0, 1023, 0, 5100);                          

    lcd.setCursor(12, 0);
    lcd.print("       ");                                                  //print blank spaces to clear old data
    lcd.setCursor(12, 0);
    lcd.print(delayValue);
    delay (500);
  }

void pulse()
{
  delayMicroseconds(delayValue);
  digitalWrite(7,HIGH);
  delayMicroseconds(200);                                                  // modify the pulse length to see what is sensed by main board*******
  digitalWrite(7,LOW);
}

Title: Re: CDI tester project
Post by: cattledog on Feb 10, 2019, 10:31 pm
Quote
I think I may be ahead of myself here but it is off by 600 uS. When delay is 0 it reports 600.
My simulated response sketch is different, and has always used a rising interrupt edge and a 10us pulse width for the response pulse.

Code: [Select]
//pin 3 interrupt as as input
//pin 4 as pulse output
void setup() {
 pinMode(4,OUTPUT);
 attachInterrupt(digitalPinToInterrupt(3),pulse,RISING);//interrupt on pin3
}

void loop() {}

void pulse()
{
  delayMicroseconds(1000);
  //delayMicroseconds(0);
  digitalWrite(4,HIGH);
  delayMicroseconds(10);
  digitalWrite(4,LOW);
}


With delayMicroseconds(1000) I read 1008, and with delayMicroseconds(0) I see 8 or 16.

We have to figure out where the 600us in your sketch is coming from. Are the grounds connected? Try my sketch as the module response simulator and see what you get. I'm not sure why your comments say couldn't get a response with a RISING interrupt.

We can get better precision than delayMicroseconds(), but that's not the main issue at this point.

I'm a little unclear about whether the interrupt on the main sketch should be set for RISING or FALLING. As you say its currently at FALLING because the input pin is set for INPUT_PULLUP to keep if from floating. I believe that this may be a change from the original code of several years ago. I don't remember if the response from the cdi module is open collector with switch to ground or if its an active signal. We should fine tune this when we have the new hardware and an actual module.

Title: Re: CDI tester project
Post by: tom_bauer on Feb 16, 2019, 07:12 pm
Hi, OK got the DAC running and everything works, well mostly! First issue is that if I start it up wile set in Falling mode, the display has 2 areas that  display wrong info, confused. If I start it up in Rising it is OK.

There are a couple other things that I am unsure of like the timing and computation of Advance display, it will likely be always from the end of the first sine until D3 sees a signal. The thing I don't understand right now is that the barWidth setting influences this and I don't think it should.

Also attached is the DAC output set to barWidth of 80
Tom
Title: Re: CDI tester project
Post by: cattledog on Feb 16, 2019, 07:35 pm
Quote
I start it up wile set in Falling mode, the display has 2 areas that  display wrong info, confused. If I start it up in Rising it is OK.
What are the two incorrect display values/positions in the Falling mode?
Title: Re: CDI tester project
Post by: tom_bauer on Feb 16, 2019, 07:36 pm
DAC output at bar = 80
Title: Re: CDI tester project
Post by: tom_bauer on Feb 16, 2019, 07:44 pm
The word RPM changes to something else, the us: gets changed to a bunch of numbers.
Tom
Title: Re: CDI tester project
Post by: tom_bauer on Feb 16, 2019, 08:45 pm
After consulting and thinking about this new system of triggering the CDI I realize that it will likely be timed from the rising edge of the first sine even if that sine is negative or positive first, still first edge.
The bar length should have no effect on the readings, it is just there to trigger the CDI in another way that has no real relation to the tester.

With those settings everything seems to work, but the delay is shown as about 864 when I am giving no delay. That generates the error in the degree advance that I see.
Thanks, Tom
Title: Re: CDI tester project
Post by: cattledog on Feb 16, 2019, 10:47 pm
Quote
The word RPM changes to something else, the us: gets changed to a bunch of numbers.
Tom
Tom I can not confirm the Falling mode startup screen issue. I do not see this
(http://forum.arduino.cc/index.php?action=dlattach;topic=425551.0;attach=295168)

but rather this
(http://forum.arduino.cc/index.php?action=dlattach;topic=425551.0;attach=295185)

If you still have this problem, please post the code you are using. We may have gotten out of synch.
Title: Re: CDI tester project
Post by: cattledog on Feb 16, 2019, 11:22 pm
Quote
DAC output at bar = 80
(http://forum.arduino.cc/index.php?action=dlattach;topic=425551.0;attach=295172)

Excellent. Looks to be positioned at 80/360.  I think we have got the trigger pulses and the charge pulses looking good. Do these pulses go into/through some high voltage section, or do they go directly to the module under test?

Quote
After consulting and thinking about this new system of triggering the CDI I realize that it will likely be timed from the rising edge of the first sine even if that sine is negative or positive first, still first edge.
OK. I think the current code already does that. It always uses the first pulse. Rising is from the lead edge whether its positive or negative. The difference between R and F is that it just adds in the 10 degree pulse width into the timing when it is set to Falling. The start of timing is independent of the first pulse positive or first pulse negative settings.

Code: [Select]
//set timing start at lead edge of first pulse
    if (risefall == 'R')
    {
      delayPeriodStart = micros();//start looking for response as pulse rises
      trigger = true;
    }
    else //risefall == 'F' set timing at trailing edge of first pulse
    {
      //convert pulseWidthTime in timer ticks to microseconds
      //prescaler 8 = 4us/timer tick
      delayPeriodStart = micros() + pulseWidthTime * 4;//start looking for response as pulse falls
      trigger = true;
    }


Quote
The bar length should have no effect on the readings, it is just there to trigger the CDI in another way that has no real relation to the tester.
Correct, bar length does not figure into any of the calculations other than to set the timing between the first and second pulse.

Quote
With those settings everything seems to work, but the delay is shown as about 864 when I am giving no delay. That generates the error in the degree advance that I see.
I think we are back to where we were a few posts ago with the simulated response. Did you ever try the test routine I supplied and saw very small delay values?
Title: Re: CDI tester project
Post by: tom_bauer on Feb 17, 2019, 12:03 am
The gremlins in the display went away mysteriously.

The trigger pulses go right to the input of a CDI, the charge pulses will be used for the primary of a HV transformer to make around 150 vac. I will send you a capture of the charge pulses with the trigger pulses, at max bar length there is some overlap. The idea was to not have a HV charge pulse when the SCR was firing as this was in effect a short but the HV source is high impedance so it may not matter.

>The difference between R and F is that it just adds in the 10 degree pulse width into the timing when it is set to Falling.< If I set the pulseWidth from 10 to 5 will this be read correctly?

I am having a problem programming a arduino I have to run your code, have forgotten what model it is!! I will get it done tomorrow.
Thanks, Tom
Title: Re: CDI tester project
Post by: cattledog on Feb 17, 2019, 12:28 am
Quote
The idea was to not have a HV charge pulse when the SCR was firing as this was in effect a short but the HV source is high impedance so it may not matter.
Yes, I remember this from the initial project. If its important, we can make the barwidth a factor in the timing of the charge pulses and delay the first one. There seems to be plenty of room.
Code: [Select]
//5 pulses of 30 degrees starting at 60 degrees
//ON at 60,120,180,240,300 = 2,4,6,8,10
//OFF at 90,150,210,270,330 = 3,5,7,9,11


Quote
If I set the pulseWidth from 10 to 5 will this be read correctly?
Yes. The pulse width in degrees gets converted to timerTicks and then to an actual time based on rpm.

 
Code: [Select]
timerTopValue = 15000000UL / RPM;
  timerTicksPerDegree = timerTopValue / 360;
  pulseWidthTime = pulseWidth * timerTicksPerDegree;


  //convert pulseWidthTime in timer ticks to microseconds
  //prescaler 8 = 4us/timer tick
  delayPeriodStart = micros() + pulseWidthTime * 4;


Quote
I am having a problem programming a arduino I have to run your code, have forgotten what model it is!!
I sometimes don't know what day it is, so don't feel bad. ;-)
Title: Re: CDI tester project
Post by: tom_bauer on Feb 17, 2019, 04:04 pm
Hi, well after an hour of trying, I give up. I have a Pro Mini and a FTDI. The com port is right, it just won't upload anything. I was going to try your test code but no go. Very frustrated!
Tom
Title: Re: CDI tester project
Post by: cattledog on Feb 17, 2019, 05:40 pm
Sorry to hear about the balky mini. Do you have the correct board and port selected. Do you have the FTDI driver on your computer? I remember several years ago that there was a problem with counterfeit FTDI chips being bricked by the manufacturer, but I think the last project when it worked was after that time.

What error message do you see?

To keep moving forward before you get a replacement, I have two thoughts. If you have a UNO with a removable DIP processor, you can remove it and use the board as a ust to ttl converter to program the mini.

Alternatively, can you read the outgoing pulse and the return from the cdi on your scope to confirm the 800+ microsecond delay is real. If so, can you think of anything on the cdi side which could create the delay. I'm pretty confident in the code.
Title: Re: CDI tester project
Post by: tom_bauer on Feb 17, 2019, 05:51 pm
OK, to keep moving, I just set up a PIC that I use for new CDIs and I can just compare the readings with what I know is right. What I would like to do now is set the refresh rate slower as it is hard to read.
Especially the delay display scrolls all the time.
Tom
Title: Re: CDI tester project
Post by: cattledog on Feb 17, 2019, 06:09 pm
Quote
What I would like to do now is set the refresh rate slower as it is hard to read.
I'm not sure where the change happened, but the display update was pulled out of the analogRead timer section and is updates every pass.

The first thing to try is to place the display update in the analog read timer section. There is one bracket which has to be commented out, and another which needs to be added. If this does not fix the issue, we can create a separate timer for the display. The analogRead() timer can be increased from the 250 ms is well.

If this simple change does not work, I'll separate the display from the adjutments.

Quote
Especially the delay display scrolls all the time.
What do you mean by this '"scrolling". Vertically or horizontally?

Code: [Select]
  if (millis() - lastAnalogRead >= analogReadInterval)
  {
    //add other potentiometer adjustments here
    lastAnalogRead += analogReadInterval;
    if (chargePulse) //lowest rpm with charge pulse is 615
      RPM = map(analogRead(pot1), 0, 1023, 615, 4000);
    else
      RPM = map(analogRead(pot1), 0, 1023, 500, 4000);
     
    pickupValue = map(analogRead(pot2), 0, 1023, 10, 90);
    barWidth = map(analogRead(pot3), 0, 1023, 20, 80);
   
    //RPM = 1200;
   
 // }//remove this bracket to add display to analogRead() timer
 
  //adjust timer values for RPM
  timerTopValue = 15000000UL / RPM;
  timerTicksPerDegree = timerTopValue / 360;
  pulseWidthTime = pulseWidth * timerTicksPerDegree;
  OCR1B = pulseWidthTime;

  setupSwitchPresets();//enable toggle switch adjustments in loop

  lcd.setCursor(4, 0);
  lcd.print("     "); // print blank spaces to clear old data
  lcd.setCursor(4, 0);
  lcd.print(RPM);

  lcd.setCursor(14, 0);
  lcd.print("  ");
  lcd.setCursor(14, 0);
  lcd.print(risefall); //print R or F at upper right side

  lcd.setCursor(16, 0);
  if (firstPulsePos)
    lcd.print("+");
  else
    lcd.print("-");

  lcd.setCursor(18, 0);
  if (chargePulse)
    lcd.print("AC");
  else
    lcd.print("DC");

  lcd.setCursor(6, 1);
  lcd.print("   ");
  lcd.setCursor(6, 1);
  lcd.print(pickupValue);//should this be pickupValue??

  lcd.setCursor(16, 1);
  lcd.print("   ");
  lcd.setCursor(16, 1);
  lcd.print(barWidth); //maybe pulse width??

  lcd.setCursor(11, 2);
  lcd.print("       ");
  lcd.setCursor(11, 2);
  lcd.print(copy_delayPeriod);

  lcd.setCursor(14, 3);
  lcd.print("      ");
  lcd.setCursor(14, 3);
  lcd.print(degreesAdvance, 1);

}//add bracket to put display within analogRead() timer
 


Title: Re: CDI tester project
Post by: tom_bauer on Feb 17, 2019, 08:22 pm
Hi, apparently my computer had decided to add something else to com3 that I was using creating a conflict. Now resolved I hope.
OK I made read interval 500 and included display in the interval so it is much better to read now. I had meant refreshing when I said scrolling. I will try the Uno again for checking delay.
Tom
Title: Re: CDI tester project
Post by: tom_bauer on Feb 18, 2019, 11:01 pm
Hi, I have tested as far as I can without creating some more circuits and for that I want to have a few boards made. I have a error or about 40us which gives an error of +-2° at higher rpms. I think that may go away with the final circuit. I have my old tester to compare to and actual engines with timing light for final check of my PIC programming. The simulated sine out works well so that is an accomplishment!
So, I will say Thank you many times and I will go work on learning KiCad! I just use Eagle now but it is the small version.
Very Best, Tom
Title: Re: CDI tester project
Post by: cattledog on Feb 18, 2019, 11:51 pm
Great progress. :-)

I learned a few things from playing around with the simulated response the other day.

1) Depending on the output from the CDI the return pulse interrupt on the tester will need to be either RISING or FALLING. Currently he interrupt pin is set as INPUT_PULLUP and the interrupt FALLING so the pin will respond to a grounding signal from the module. If the module puts out a high pulse, I think the interrupt will need to be changed. The interrupt pin might need an external pull down resistor.

2). When using FALLING mode for the trigger pulse, the time delay of the response pulse needs to be longer the trigger pulse width or else you see strange results as you are getting a negative value from the subtraction of start time from end time.

3).When using first pulse negative, the delayed response simulator needs to see a pulse from pin 8 and not pin 9. 

4) When the charge pulses are active, I see some additional delay (approx 30us) at 0 delay which I don't understand. The charge pulses should not be interactive with the trigger pulse or the return pulse interrupt but I see something. At longer delays, the effect seems reduced. I would keep my eye on the AC mode.

Good luck going forward. Please report back with how this project turns out.


Title: Re: CDI tester project
Post by: tom_bauer on Feb 19, 2019, 03:04 am
OK
re #1, the spark generated by the CDI will always produce a grounding signal to the tester. I use a small SCR to do this and that is triggered by an inductive pickup. This keeps annoying rfi from getting back to the Arduino, they hate that stuff!

re #2, it is VERY likely that I will always use the rising edge of the first sine and will call that point rising whether that first sine is pos or neg. That is where the CDI starts its timing to create a pulse to trigger the SCR for the spark.

re #3, this may not apply? I am using the output after the op-amp that is driven by the DAC.

re #4, I have long been looking for a good way to simulate the HV from the magneto and the 5 pulses per rev seemed to be a workable solution. I have some small transformers with powdered iron pole pieces so frequency response should be much better that the lines transformer I had been using. I needed a transformer with a fairly low primary resistance and now have a few to try. I also have a DC - DC converter that is adjustable and can output 100 to 300 vdc. It may be a viable choice and that would allow the charge pulses to be completely removed. This is after all just for testing and measurement and not long term operation.

Best, Tom
Title: Re: CDI tester project
Post by: cattledog on Feb 19, 2019, 04:32 am
Quote
Also I can code the Arduino to drive more bits of the DAC to make a better sine wave.
The simulated sine out works well so that is an accomplishment!
I don't understand the hardware and how the two A/B pulses (00,11,01) to the DAC creating -12, +12, and 0 volts generate a sine wave to the cdi. Is it created by the op amp and RC after the DAC?  

Are you planning to separate some the the tied inputs on PinA to generate something different from the DAC?

Title: Re: CDI tester project
Post by: tom_bauer on Feb 19, 2019, 06:33 am
Well I call it a sine wave, it is really just the most basic of such, a pos followed by a neg, really all I need to make a CDI see for triggering purposes.
Tom
Title: Re: CDI tester project
Post by: tom_bauer on Mar 29, 2019, 07:57 pm
Cattledog,
Hi, I am now making circuit board as I think I have everything else worked out. Have adjustable HV output switchable to 2 levels so once I get everything on one board I can see how the timing and such works. Seems to be good.
Again many thanks for your help, Tom
Title: Re: CDI tester project
Post by: tom_bauer on Apr 13, 2019, 08:01 pm
Cattledog, Hi, I find that I need to be able to have just the pos or just the neg pulse from the DAC and I don't understand where in the code that control is done. Ideally there would be 2 digital pins that one or the other pulled low would control this.
Thanks, Tom

Title: Re: CDI tester project
Post by: cattledog on Apr 13, 2019, 11:17 pm
Welcome back.

Quote
I find that I need to be able to have just the pos or just the neg pulse from the DAC
Do you need to have two modes--one where the two pulses pos/neg follow each other, and another with just one pulse or do you want the program to now only have the single pulse mode?

The selection of polarity switch will continue to control whether or not the single pulse is pos or neg, and we can treat the single pulse as the first pulse.

If you only want the one pulse mode, the code can be simplified to remove the bits needed to calculate the interpulse separation and the division of the timing cycle into two piece.

For now, here is quick revision which leaves the code pretty much intact, maintains the two pulse structure,  but removes the second pulse. See if this gives the one pulse you want.

Code: [Select]
ISR(TIMER1_OVF_vect)
{
  //alternate ICR1 values to generate two outputs over 360 degrees
  //360 degree cycle time broken into two pieces
  //timerTopValue adjusted with RPM pot
  //timerTicksPerDegree = timerTopValue / 360; //gets new value to update ICR1
  static byte pulse = firstPulse;
  if (pulse == firstPulse)
  {
    ICR1 = timerTicksPerDegree * (pulseWidth + barWidth); //first pulse and bar width
    digitalWrite(13, HIGH);
    digitalWrite(chargePin, LOW); //guarantee charge pin off at trigger
    if (firstPulsePos == true)
      setPulse(positive);
    else
      setPulse(negative);
    //set timing start at lead edge of first pulse
    if (risefall == 'R')
    {
      delayPeriodStart = micros();//start looking for response as pulse rises
      trigger = true;
    }
    else //risefall == 'F' set timing at trailing edge of first pulse
    {
      //convert pulseWidthTime in timer ticks to microseconds
      //prescaler 8 = 4us/timer tick
      delayPeriodStart = micros() + pulseWidthTime * 4;//start looking for response as pulse falls
      trigger = true;
    }
    //start Timer 2 for charge pulses
    if (chargePulse)
    {
      timeSliceCount = 0;
      TCNT2 = 0;
      OCR2A = timerTopValue / 96; //set 12 periods
      //start timer running
      TCCR2B |=  1 << CS22 | 1 << CS21; //prescaleer 256 16us/tick
    }

    pulse = secondPulse; //next pulse
  }
  else //second pulse
  {
    ICR1 = timerTicksPerDegree * (360 - (pulseWidth + barWidth)); //second pulse and dead band
    digitalWrite(13, HIGH);

    //block the second pulse
    //if (firstPulsePos)
      //setPulse(negative);
    //else
      //setPulse(positive);

    pulse = firstPulse; //next pulse
  }
}
Title: Re: CDI tester project
Post by: tom_bauer on Apr 14, 2019, 04:09 pm
OK, thanks, at first I thought it did not work but it is fine! I have an issue with the neg pulse triggering the CDI and have not found it yet. This is my first time using a DAC for this so I don't know if the pulse is to short. More later!
Best, Tom
Title: Re: CDI tester project
Post by: tom_bauer on Apr 17, 2019, 10:31 pm
Cattledog,
Hi my friend, well sometimes the best laid plans just are not the best! I had thought that using a DAC was a good way to have neg pulse from Arduino. It is for some uses perhaps but the CDI input circuit draws much more current that can be supplied.
So a change of plans is sadly in order. I find that I just need 1 pulse for the trigger plus the 5 pulses for the HV supply. The circuit can just sample from the Rise of the trigger pulse by default and the bar width and position can remain with the rpm pot. Also the D6 to turn on the output at D7 can stay.
Much like the one you did a couple of years ago but I am going to finally add the pots and make a proper circuit board. I feel like it was a good idea and was suggested to me by a EE friend. But it works better to keep it simple!
Again, many thanks, Tom
Title: Re: CDI tester project
Post by: tom_bauer on Apr 20, 2019, 10:11 pm
Cattledog,
I have worked with the code and with the hardware to get a pretty nice result I think. It is mostly a rework of the old version. What I am stumbling on is the DC output. I just want to turn off the HV pulse generator and keep everything else running. When I remove pin 6 from ground the output on pin 5 gets strange, going in cycles. I also want to keeo the reporting of degrees advance in the DC mode.
Thanks, Tom

Code: [Select]
// replaced on 7/22/18 mod on 4/18/2019 changed to go simple transformer control of pos / neg trigger
// update 7/14/2017 added correct math and setting for position of pickup
// revision 10 10/28/2016 adds charging pulse with Timer 2
// lowest RPM = 615 with charge pulse to keep OCR2A <= 255
// CDI Tester Pulse Generator Serial Output Arduino Code
// 8/17 added code for pulse out width

int pot1 = A1; // select the input pin for the pot for rpm
int pot2 = A2; // select the input pin for the pot for pickup location in degrees
// int pot3 = A3; // select the input pin for the pot for length of bar on flywheel in degrees
int potValue = 0; // variable to store the value coming from the sensor
int pickupValue = 0; // position of pickup in degrees
int potWidth = 0; // variable to set length of bar on flywheel
int timerTopValue = 12500; // changed from timerTopValue = 0
int outputPin = 4; // select the pin for the output for trigger pulse, changed from 8
int chargePin = 7; // select the pin for the output for charge pulses

volatile boolean trigger = false;
volatile unsigned long delayPeriod;
unsigned long copy_delayPeriod;
volatile unsigned long delayPeriodStart;
float delayDegrees; // changed from int to float for decimal place display
int RPM;
int pickup;
// int barLength;
int pulseWidth;                                           
volatile boolean interruptFlag;
unsigned long analogReadInterval = 500; // read pots and map
unsigned long lastAnalogRead;

// const byte setFallingSwitch = 5;
// char risefall = 'R'; // default rising mode

const byte setChargePulseSwitch = 6;
boolean chargePulse = false ;  // default dc powered mode

volatile byte timeSliceCount = 0; // TDC 0 degrees

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
// set the LCD address to 0x3f for a 20 chars 4 line display
// Set the pins on the I2C chip used for LCD connections:
//                    addr, en,rw,rs,d4,d5,d6,d7,bl,blpol
LiquidCrystal_I2C lcd(0x3f, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address

void setup() {
// Serial.begin(115200);
// Serial.println("starting...");
  lcd.begin(20, 4); // initialize the lcd for 20 chars 4 lines, turn on backlight
  lcd.setCursor(1, 0); // lcd display setup of unchanging headings
  lcd.print("RPM:"); // print fixed characters
  lcd.setCursor(12, 0);
  lcd.print("Deg");
  lcd.setCursor(1, 1);
  lcd.print("Pos:");
//  lcd.setCursor(12, 1);
//  lcd.print("Bar:");
  lcd.setCursor(1, 2);
  lcd.print("Us Delay:");
  lcd.setCursor(1, 3);
  lcd.print("Deg Advance:");

  pinMode(outputPin, OUTPUT); // declare the outputPin as an OUTPUT
  pinMode(chargePin, OUTPUT); // declare the chargePin as an OUTPUT
// pinMode (setFallingSwitch, INPUT_PULLUP); // check for a LOW input to indicate switch is closed to ground
  pinMode(setChargePulseSwitch, INPUT_PULLUP);

  if (digitalRead(setChargePulseSwitch) == LOW)
    chargePulse = true; // AC CDI

 // Timer1 default set up .5ms trigger pulse every 50 ms
  TCCR1A = 0;
  TCCR1B = (1 << WGM12); // CTC mode to OCR1A
  OCR1A = timerTopValue;
  TIMSK1 |= (1 << OCIE1A); // interrupt enable compareA
  TIMSK1 |= (1 << OCIE1B); // interrupt enable compareB
  OCR1B = 500; // sets trigger pulse width, 500 = 2Ms, 250 = 1Ms, 125 = .5Ms, set to 1250 for 5013 *********************************************
  TCCR1B |= (1 << CS11) | (1 << CS10); // prescaler 64 4us/tick

// Timer2 default setup charge pulse 12 periods 30 degrees each; only 5 get turned on
// charge pulse timing interval = Timer1 trigger period/12 = timerTopValue/96
  TCCR2A = 0;
  TCCR2B = 0;
  TCCR2A = 1 << WGM20; // lsb of mode 7 pwm to OCR2A
  TCCR2B = 1 << WGM22; // msb of mode 7 pwm to OCR2A;
  OCR2A = timerTopValue / 96; // 96 = 12*4*2 (#periods, prescaler difference, up/down timer mode )
  TIMSK2 = 0;
  TIMSK2 = 1 << TOIE2; // enable overflow interrupt
// actually start timer in ISR(TIMER1_COMPA_vect
// to prevent out of sync charge pulse, no prescaler set here

  attachInterrupt(digitalPinToInterrupt(3), delayPeriodTiming, FALLING);

}

void loop()
{
  if (millis() - lastAnalogRead >= analogReadInterval)
  {
    lastAnalogRead += analogReadInterval;
    potValue = analogRead(pot1); // rpm
    pickupValue = analogRead(pot2); // pickup position
//  barLength = analogRead(pot3); // length of bar for pickup
 
// Timer2 OCR2A requires max value 255 => 615 lowest RPM
    if (chargePulse)
    {
      RPM = map(potValue, 0, 1023, 615, 10000);
      pickup = map(pickupValue, 0, 1023, 10, 75); // so advance will read based on delay, 57 for yamaha 350 2 pu, 74 for 1 pu, 72 for tw200, 25 for 5013
      pulseWidth = (60000000/RPM)/360; // time for 1° in uS
//    barSize = map(barLength, 0, 1023, 10, 60);  // 10 for yamaha 350 2 pu, 60 for 1 pu, 60 for tw200
// RPM = 615; // for my serial test purposes 615-3800
    }
    else
    {
      RPM = map(potValue, 0, 1023, 500, 3800);
      pickupValue = map(pickupValue, 0, 1023, 0, 50); // to set position of pickup so advance will read
//    pulseWidth = map(barLength, 0, 1023, 71, 44); // add Width to non charging case
// RPM = 500; // for my serial test purposes 500-3800
    }

    timerTopValue = 15000000UL / RPM;
    OCR1B = pulseWidth;

// if (digitalRead(setFallingSwitch) == LOW) // set Falling
// {
// risefall = 'F';
// }
// else
// {
// risefall = 'R';
// }

    lcd.setCursor(6, 0);
    lcd.print("     "); // print blank spaces to clear old data
    lcd.setCursor(6, 0);
    lcd.print(RPM);  // print rpm

    lcd.setCursor(16, 0);
    lcd.print("  ");
    lcd.setCursor(16, 0);
    lcd.print(pulseWidth, 1); // print us per degree
   
    lcd.setCursor(6, 1);
    lcd.print("   ");
    lcd.setCursor(6, 1);
    lcd.print(pickup); // print pickup coil position

//    lcd.setCursor(16, 1);
//    lcd.print("   ");
//    lcd.setCursor(16, 1);
//    lcd.print(barLength); // length of bar

    lcd.setCursor(11, 2);
    lcd.print("       ");
    lcd.setCursor(11, 2);
    lcd.print(copy_delayPeriod);
   
    lcd.setCursor(14, 3);
    lcd.print("      ");
    lcd.setCursor(14, 3);
    lcd.print(delayDegrees, 1);   // delayDegrees, 1);
  }
 
  if (trigger == true && interruptFlag == true )
  {
    trigger = false;
    interruptFlag = false;
    noInterrupts();
    copy_delayPeriod = delayPeriod;
    interrupts();

    delayDegrees = pickup - (360.0 * (copy_delayPeriod) / (timerTopValue * 4.0)); // for decimal place in deg display.
    }
}

ISR(TIMER1_COMPA_vect) {
  OCR1A = (timerTopValue); // value to set delay between pulses to trigger cdi
  digitalWrite(chargePin, LOW); // guarantee off charge pin at trigger
  digitalWrite(outputPin, HIGH); // turn on pin  trigger

// if (risefall == 'R') // switch not set; default Rising trigger
  {
    delayPeriodStart = micros(); // start looking for response as pulse rises
    trigger = true;
  }
// start Timer 2 for charge pulses
  if (chargePulse)
  {
    timeSliceCount = 0;
    TCNT2 = 0;
    OCR2A = timerTopValue/96; // set 12 periods
    TCCR2B |=  1 << CS22 | 1 << CS21; //prescaleer 256 16us/tick
  }
}

ISR(TIMER1_COMPB_vect) {
  digitalWrite(outputPin, LOW);

// if (risefall == 'F') // switch set for Falling trigger
  {
    delayPeriodStart = micros(); // start looking for response as pulse falls
    trigger = true;
  }
}

void delayPeriodTiming()
{
  delayPeriod = micros() - delayPeriodStart;
  interruptFlag = true;
}

ISR(TIMER2_OVF_vect)
// 5 pulses of 30 degrees starting at 60 degrees
// ON at 60,120,180,240,300 = 2,4,6,8,10
// OFF at 90,150,210,270,330 = 3,5,7,9,11
{
  if (timeSliceCount != 0 && timeSliceCount % 2 == 0)
  {
    digitalWrite (chargePin, HIGH);
  }
  else // if (timeSliceCount == 0 || timeSliceCount % 2 == 1)
  {
    digitalWrite(chargePin, LOW);
  }
  timeSliceCount++;

  if (timeSliceCount == 12)
  {
    timeSliceCount = 0;
// stop Timer2 by clearing prescaler bits
    TCCR2B &= ~1<< CS22;
    TCCR2B &= ~1<< CS21;
  }
}
Title: Re: CDI tester project
Post by: cattledog on Apr 21, 2019, 05:53 pm
Quote
What I am stumbling on is the DC output. I just want to turn off the HV pulse generator and keep everything else running. When I remove pin 6 from ground the output on pin 5 gets strange, going in cycles.
Code: [Select]

// const byte setFallingSwitch = 5;
// char risefall = 'R'; // default rising mode
//pinMode (setFallingSwitch, INPUT_PULLUP);


You have removed the pinMode for pin5 and it will be floating. I'm somewhat unclear about what you are trying to do with the R/F setting, and you have a conflict here as you are setting the start time for both R and F modes.
Code: [Select]

ISR(TIMER1_COMPA_vect) {
  OCR1A = (timerTopValue); // value to set delay between pulses to trigger cdi
  digitalWrite(chargePin, LOW); // guarantee off charge pin at trigger
  digitalWrite(outputPin, HIGH); // turn on pin  trigger

// if (risefall == 'R') // switch not set; default Rising trigger
  {
    delayPeriodStart = micros(); // start looking for response as pulse rises
    trigger = true;
  }
// start Timer 2 for charge pulses
  if (chargePulse)
  {
    timeSliceCount = 0;
    TCNT2 = 0;
    OCR2A = timerTopValue/96; // set 12 periods
    TCCR2B |=  1 << CS22 | 1 << CS21; //prescaleer 256 16us/tick
  }
}

ISR(TIMER1_COMPB_vect) {
  digitalWrite(outputPin, LOW);

// if (risefall == 'F') // switch set for Falling trigger
  {
    delayPeriodStart = micros(); // start looking for response as pulse falls
    trigger = true;
  }
}


Quote
I also want to keep the reporting of degrees advance in the DC mode.
I see in the last bi-polar pulse code we had
Code: [Select]
degreesAdvance = pickupValue - delayDegrees;

I think you can just add it here, and display it as you do in the bipolar sketch.
Code: [Select]
delayDegrees = pickup - (360.0 * (copy_delayPeriod) / (timerTopValue * 4.0)); // for decimal place in deg display.
degreesAdvance = pickupValue - delayDegrees;


Title: Re: CDI tester project
Post by: tom_bauer on Apr 21, 2019, 07:03 pm
Hi, I see I misspoke in last message. It should say "What I am stumbling on is the DC output. I just want to turn off the HV pulse generator and keep everything else running. When I remove pin 6 from ground the output on pin 4 gets strange, going in cycles."

OK let me clarify as it may make a difference. I don't think I need a switch to choose between Rise and Fall for the start of the timing operation. It will always be from the Rising edge so I wanted to remove that part of the code and have it operate in that mode only.
Also if it simplifies things there is no need for the code to know when the charge pulses are being used, just a way to turn them on or off by switch. The same switch will turn on the DC when it turns off the charge pulses.
I have had a hardware problem for a long time and did not realize it which is why I thought the DAC may be the answer, but once I found that problem it all became much simpler.

I should also note I am using the pins of the old system, A1 is rpm, A2 is pickup position, D3 is input from sensor for spark, D4 is pulse trigger out, D6 is charge pulse on, D7 is charge pulse out.
Tom
Title: Re: CDI tester project
Post by: cattledog on Apr 21, 2019, 08:22 pm
Quote
I should also note I am using the pins of the old system, A1 is rpm, A2 is pickup position, D3 is input from sensor for spark, D4 is pulse trigger out, D6 is charge pulse on, D7 is charge pulse out.
Quote
When I remove pin 6 from ground the output on pin 4 gets strange, going in cycles."
I can't see any software interaction between the pulse trigger and the charge pulses or charge pulse selector switch . Can you show the pulse trigger output on a scope? Are you looking at the Arduino output of pin 4, or the HV trigger?

Quote
D6 is charge pulse on, D7 is charge pulse out
Since you moved the switch to D6, are you certain of the wiring, and can confirm that the INPUT_PULLUP is active. Use a simple test with digitalRead() to check the output of the switch.

Once I'm more clear about what is going on, I can simplify the sketch to remove stuff that isn't needed.

I would also recommend that you go back to using the hd44780 library. It really is superior and will make life easy if you have to change a display.
Title: Re: CDI tester project
Post by: tom_bauer on Apr 21, 2019, 08:55 pm
When I open the switch for D6, it goes to 5v, I have to reset, then output on D7 stops. After reset, the output on D4 runs for several pulses then stops with just a very tiny noise pulse occasionally. I have to reset each time I change D6.
Tom
Title: Re: CDI tester project
Post by: cattledog on Apr 21, 2019, 09:06 pm
Quote
I have to reset each time I change D6.
That can be fixed with the changes we made in the Bipolar Pulse Code where the switch checking was moved out of setup and into loop(). It can be added in loop where you do the analogRead() every 500ms or els try and adopt the setSwichPresets function in the last Bipolar code.

Quote
After reset, the output on D4 runs for several pulses then stops with just a very tiny noise pulse occasionally.
I am really confused. After reset with D6 changed, it should just look like a fresh start with D6 set for DC. Do you see normal trigger pulses on D4 in DC mode at all?
Title: Re: CDI tester project
Post by: tom_bauer on Apr 21, 2019, 10:03 pm
Just to be sure I didn't post a wrong sketch, But what happens is that I get 4 or 5 pulses from D4 when D6 is high. This happens when I reset or do a cold start and looking with scope.

Code: [Select]

// replaced on 7/22/18 mod on 4/18/2019 changed to go simple transformer control of pos / neg trigger
// update 7/14/2017 added correct math and setting for position of pickup
// revision 10 10/28/2016 adds charging pulse with Timer 2
// lowest RPM = 615 with charge pulse to keep OCR2A <= 255
// CDI Tester Pulse Generator Serial Output Arduino Code
// 8/17 added code for pulse out width

#include <Wire.h>
#include <hd44780.h>
#include <hd44780ioClass/hd44780_I2Cexp.h> // include i/o class header
hd44780_I2Cexp lcd; // declare lcd object: auto locate & config display for hd44780 chip

int pot1 = A1; // select the input pin for the pot for rpm
int pot2 = A2; // select the input pin for the pot for pickup location in degrees
// int pot3 = A3; // select the input pin for the pot for length of bar on flywheel in degrees
int potValue = 0; // variable to store the value coming from the sensor
int pickupValue = 0; // position of pickup in degrees
int potWidth = 0; // variable to set length of bar on flywheel
int timerTopValue = 12500; // changed from timerTopValue = 0
int outputPin = 4; // select the pin for the output for trigger pulse, changed from 8
int chargePin = 7; // select the pin for the output for charge pulses

volatile boolean trigger = false;
volatile unsigned long delayPeriod;
unsigned long copy_delayPeriod;
volatile unsigned long delayPeriodStart;
float delayDegrees; // changed from int to float for decimal place display
int RPM;
int pickup;
// int barLength;
int pulseWidth;                                           
volatile boolean interruptFlag;
unsigned long analogReadInterval = 500; // read pots and map
unsigned long lastAnalogRead;

// const byte setFallingSwitch = 5;
// char risefall = 'R'; // default rising mode

const byte setChargePulseSwitch = 6;
boolean chargePulse = false ;  // default dc powered mode

volatile byte timeSliceCount = 0; // TDC 0 degrees

void setup() {
// Serial.begin(115200);
// Serial.println("starting...");
  lcd.begin(20, 4); // initialize the lcd for 20 chars 4 lines, turn on backlight
  lcd.setCursor(1, 0); // lcd display setup of unchanging headings
  lcd.print("RPM:"); // print fixed characters
  lcd.setCursor(12, 0);
  lcd.print("Deg");
  lcd.setCursor(1, 1);
  lcd.print("Pos:");
//  lcd.setCursor(12, 1);
//  lcd.print("Bar:");
  lcd.setCursor(1, 2);
  lcd.print("Us Delay:");
  lcd.setCursor(1, 3);
  lcd.print("Deg Advance:");

  pinMode(outputPin, OUTPUT); // declare the outputPin as an OUTPUT
  pinMode(chargePin, OUTPUT); // declare the chargePin as an OUTPUT
// pinMode (setFallingSwitch, INPUT_PULLUP); // check for a LOW input to indicate switch is closed to ground
  pinMode(setChargePulseSwitch, INPUT_PULLUP);

  if (digitalRead(setChargePulseSwitch) == LOW)
    chargePulse = true; // AC CDI

 // Timer1 default set up .5ms trigger pulse every 50 ms
  TCCR1A = 0;
  TCCR1B = (1 << WGM12); // CTC mode to OCR1A
  OCR1A = timerTopValue;
  TIMSK1 |= (1 << OCIE1A); // interrupt enable compareA
  TIMSK1 |= (1 << OCIE1B); // interrupt enable compareB
  OCR1B = 500; // sets trigger pulse width, 500 = 2Ms, 250 = 1Ms, 125 = .5Ms, set to 1250 for 5013 *********************************************
  TCCR1B |= (1 << CS11) | (1 << CS10); // prescaler 64 4us/tick

// Timer2 default setup charge pulse 12 periods 30 degrees each; only 5 get turned on
// charge pulse timing interval = Timer1 trigger period/12 = timerTopValue/96
  TCCR2A = 0;
  TCCR2B = 0;
  TCCR2A = 1 << WGM20; // lsb of mode 7 pwm to OCR2A
  TCCR2B = 1 << WGM22; // msb of mode 7 pwm to OCR2A;
  OCR2A = timerTopValue / 96; // 96 = 12*4*2 (#periods, prescaler difference, up/down timer mode )
  TIMSK2 = 0;
  TIMSK2 = 1 << TOIE2; // enable overflow interrupt
// actually start timer in ISR(TIMER1_COMPA_vect
// to prevent out of sync charge pulse, no prescaler set here

  attachInterrupt(digitalPinToInterrupt(3), delayPeriodTiming, FALLING);

}

void loop()
{
  if (millis() - lastAnalogRead >= analogReadInterval)
  {
    lastAnalogRead += analogReadInterval;
    potValue = analogRead(pot1); // rpm
    pickupValue = analogRead(pot2); // pickup position
   
//  barLength = analogRead(pot3); // length of bar for pickup
 
// Timer2 OCR2A requires max value 255 => 615 lowest RPM
    if (chargePulse)
    {
      RPM = map(potValue, 0, 1023, 615, 10000);
      pickup = map(pickupValue, 0, 1023, 10, 75); // so advance will read based on delay, 57 for yamaha 350 2 pu, 74 for 1 pu, 72 for tw200, 25 for 5013
      pulseWidth = (60000000/RPM)/360; // time for 1° in uS
//    barSize = map(barLength, 0, 1023, 10, 60);  // 10 for yamaha 350 2 pu, 60 for 1 pu, 60 for tw200
// RPM = 615; // for my serial test purposes 615-3800
    }
    else
    {
      RPM = map(potValue, 0, 1023, 500, 3800);
      pickupValue = map(pickupValue, 0, 1023, 0, 50); // to set position of pickup so advance will read
//    pulseWidth = map(barLength, 0, 1023, 71, 44); // add Width to non charging case
// RPM = 500; // for my serial test purposes 500-3800
    }

    timerTopValue = 15000000UL / RPM;
    OCR1B = pulseWidth;

// if (digitalRead(setFallingSwitch) == LOW) // set Falling
// {
// risefall = 'F';
// }
// else
// {
// risefall = 'R';
// }

    lcd.setCursor(6, 0);
    lcd.print("     "); // print blank spaces to clear old data
    lcd.setCursor(6, 0);
    lcd.print(RPM);  // print rpm

    lcd.setCursor(16, 0);
    lcd.print("  ");
    lcd.setCursor(16, 0);
    lcd.print(pulseWidth, 1); // print us per degree
   
    lcd.setCursor(6, 1);
    lcd.print("   ");
    lcd.setCursor(6, 1);
    lcd.print(pickup); // print pickup coil position

//    lcd.setCursor(16, 1);
//    lcd.print("   ");
//    lcd.setCursor(16, 1);
//    lcd.print(barLength); // length of bar

    lcd.setCursor(11, 2);
    lcd.print("       ");
    lcd.setCursor(11, 2);
    lcd.print(copy_delayPeriod);
   
    lcd.setCursor(14, 3);
    lcd.print("      ");
    lcd.setCursor(14, 3);
    lcd.print(delayDegrees, 1);   // delayDegrees, 1);
  }
 
  if (trigger == true && interruptFlag == true )
  {
    trigger = false;
    interruptFlag = false;
    noInterrupts();
    copy_delayPeriod = delayPeriod;
    interrupts();

    delayDegrees = pickup - (360.0 * (copy_delayPeriod) / (timerTopValue * 4.0)); // for decimal place in deg display.
//    degreesAdvance = pickupValue - delayDegrees; // added
    }
}

ISR(TIMER1_COMPA_vect) {
  OCR1A = (timerTopValue); // value to set delay between pulses to trigger cdi
  digitalWrite(chargePin, LOW); // guarantee off charge pin at trigger
  digitalWrite(outputPin, HIGH); // turn on pin  trigger

// if (risefall == 'R') // switch not set; default Rising trigger
  {
    delayPeriodStart = micros(); // start looking for response as pulse rises
    trigger = true;
  }
// start Timer 2 for charge pulses
  if (chargePulse)
  {
    timeSliceCount = 0;
    TCNT2 = 0;
    OCR2A = timerTopValue/96; // set 12 periods
    TCCR2B |=  1 << CS22 | 1 << CS21; //prescaleer 256 16us/tick
  }
}

ISR(TIMER1_COMPB_vect) {
  digitalWrite(outputPin, LOW);

// if (risefall == 'F') // switch set for Falling trigger
  {
    delayPeriodStart = micros(); // start looking for response as pulse falls
    trigger = true;
  }
}

void delayPeriodTiming()
{
  delayPeriod = micros() - delayPeriodStart;
  interruptFlag = true;
}

ISR(TIMER2_OVF_vect)
// 5 pulses of 30 degrees starting at 60 degrees
// ON at 60,120,180,240,300 = 2,4,6,8,10
// OFF at 90,150,210,270,330 = 3,5,7,9,11
{
  if (timeSliceCount != 0 && timeSliceCount % 2 == 0)
  {
    digitalWrite (chargePin, HIGH);
  }
  else // if (timeSliceCount == 0 || timeSliceCount % 2 == 1)
  {
    digitalWrite(chargePin, LOW);
  }
  timeSliceCount++;

  if (timeSliceCount == 12)
  {
    timeSliceCount = 0;
// stop Timer2 by clearing prescaler bits
    TCCR2B &= ~1<< CS22;
    TCCR2B &= ~1<< CS21;
  }
}
Title: Re: CDI tester project
Post by: cattledog on Apr 21, 2019, 10:52 pm
Quote
But what happens is that I get 4 or 5 pulses from D4 when D6 is high
Just to be clear. The DC mode is not working properly and all you see are a few trigger pulses on D4 and then they go away.

In AC mode, with the charge pulses, do you see correct trigger pulse output on D4?
Was DC mode working with the original mono pulse code we started with?
Was DC mode working in the Bipolar pulse sketch?
Title: Re: CDI tester project
Post by: tom_bauer on Apr 21, 2019, 11:21 pm
Just to be clear. The DC mode is not working properly and all you see are a few trigger pulses on D4 and then they go away.
Yes that is right

In AC mode, with the charge pulses, do you see correct trigger pulse output on D4?
Yes they are fine then.

Was DC mode working with the original mono pulse code we started with?
Yes

Was DC mode working in the Bipolar pulse sketch?
Sorry, not sure and that test bed is not usable right now.

What I tried to do was go back to the older sketch with the mono pulse output.
Title: Re: CDI tester project
Post by: cattledog on Apr 22, 2019, 01:38 am
Quote
Just to be clear. The DC mode is not working properly and all you see are a few trigger pulses on D4 and then they go away.
Yes that is right
I can not confirm what you are seeing. I loaded the code that you posted in #246 and made the RPM fixed at 1500 with this line which I uncommented. The else refers to when there are no charge pulses. That is with pin6 pulled HIGH by its INPUT_PULLUP.

Code: [Select]

else
    {
      RPM = map(potValue, 0, 1023, 500, 3800);
      pickupValue = map(pickupValue, 0, 1023, 0, 50); // to set position of pickup so advance will read
//    pulseWidth = map(barLength, 0, 1023, 71, 44); // add Width to non charging case
 RPM = 1500; // for my serial test purposes 500-3800


I jumpered the output of pin 4 to a second Arduino (grounds connected) on pin 2 where I ran the following simple interrupt counting code. I saw 25 counts per second which the the 1500 rpm. Pin 4 was outputting when the charge pulses were disabled. I'm not clear about what is going on with the scope or your hardware, but see if you can see what I see with a second Arduino.

Code: [Select]
volatile unsigned long  count = 0;
unsigned long copyCount = 0;

unsigned long lastRead = 0;
unsigned long interval = 1000;//one second

void setup()
{
  Serial.begin(115200);
  Serial.println("start...");
 
  //interrupt on pin2
  pinMode(2,INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(2),isrCount,RISING);
}

void loop()
{
  if (millis() - lastRead >= interval) //read interrupt count every second
  {
    lastRead  += interval;
    // disable interrupts,make copy of count,reenable interrupts
    noInterrupts();
    copyCount = count;
    count = 0;
    interrupts();
    //use copyCount for all calulations and actions in loop
    Serial.println(copyCount);
  }
}

void isrCount()
{
  count++;
}
Title: Re: CDI tester project
Post by: tom_bauer on Apr 22, 2019, 09:33 pm
Hi, OK I must have a flaky UNO, I accidentally left it on last night and this morning it was dead, would not drive display so I let it sit disconnected for 30 min and it came back to life but I don't trust it now, more here soon.

Have worked with it anyway and this seems to be a working sketch, it goes back to the one I was using before the DAC idea. I have cleaned up the display items a little and the timing computation works when the AC is on but not when it is off. Also I cannot get it to change from AC to DC without manual reset and don't see why.
Best, Tom

Code: [Select]

#include <Wire.h>
#include <hd44780.h>
#include <hd44780ioClass/hd44780_I2Cexp.h> // include i/o class header
hd44780_I2Cexp lcd; // declare lcd object: auto locate & config display for hd44780 chip

int pot1 = A1; // select the input pin for the pot for rpm
int pot2 = A2; // select the input pin for the pot for pickup location in degrees
int pot3 = A3; // select the input pin for the pot for length of bar on flywheel in degrees
int potValue = 0; // variable to store the value coming from the sensor
int pickupValue = 0; // position of pickup in degrees
int potWidth = 0; // variable to set length of bar on flywheel
int timerTopValue = 12500; // changed from timerTopValue = 0
int outputPin = 4; // select the pin for the output for trigger pulse, changed from 8
int chargePin = 7; // select the pin for the output for charge pulses

volatile boolean trigger = false;
volatile unsigned long delayPeriod;
unsigned long copy_delayPeriod;
volatile unsigned long delayPeriodStart;
float delayDegrees; // changed from int to float for decimal place display
int RPM;
int pickup;
// int barLength;
int pulseWidth;                                            
volatile boolean interruptFlag;
// unsigned long analogReadInterval = 500; // read pots and map
unsigned long lastAnalogRead;

// const byte setFallingSwitch = 5;
// char risefall = 'R'; // default rising mode

const byte setChargePulseSwitch = 6;
boolean chargePulse = false ;  // default dc powered mode

volatile byte timeSliceCount = 0; // TDC 0 degrees

void setup() {
// Serial.begin(115200);
// Serial.println("starting...");
  lcd.begin(20, 4); // initialize the lcd for 20 chars 4 lines, turn on backlight
  lcd.setCursor(1, 0); // lcd display setup of unchanging headings
  lcd.print("RPM:"); // print fixed characters
  lcd.setCursor(12, 0);
  lcd.print("Deg");
  lcd.setCursor(1, 1);
  lcd.print("Pos:");
//  lcd.setCursor(12, 1);
//  lcd.print("Bar:");
  lcd.setCursor(1, 2);
  lcd.print("Us Delay:");
  lcd.setCursor(1, 3);
  lcd.print("Deg Advance:");

  pinMode(outputPin, OUTPUT); // declare the outputPin as an OUTPUT
  pinMode(chargePin, OUTPUT); // declare the chargePin as an OUTPUT
// pinMode (setFallingSwitch, INPUT_PULLUP); // check for a LOW input to indicate switch is closed to ground
  pinMode(setChargePulseSwitch, INPUT_PULLUP);

  if (digitalRead(setChargePulseSwitch) == LOW)
    chargePulse = true; // AC CDI

 // Timer1 default set up .5ms trigger pulse every 50 ms
  TCCR1A = 0;
  TCCR1B = (1 << WGM12); // CTC mode to OCR1A
  OCR1A = timerTopValue;
  TIMSK1 |= (1 << OCIE1A); // interrupt enable compareA
  TIMSK1 |= (1 << OCIE1B); // interrupt enable compareB
  OCR1B = 500; // sets trigger pulse width, 500 = 2Ms, 250 = 1Ms, 125 = .5Ms, set to 1250 for 5013 *********************************************
  TCCR1B |= (1 << CS11) | (1 << CS10); // prescaler 64 4us/tick

// Timer2 default setup charge pulse 12 periods 30 degrees each; only 5 get turned on
// charge pulse timing interval = Timer1 trigger period/12 = timerTopValue/96
  TCCR2A = 0;
  TCCR2B = 0;
  TCCR2A = 1 << WGM20; // lsb of mode 7 pwm to OCR2A
  TCCR2B = 1 << WGM22; // msb of mode 7 pwm to OCR2A;
  OCR2A = timerTopValue / 96; // 96 = 12*4*2 (#periods, prescaler difference, up/down timer mode )
  TIMSK2 = 0;
  TIMSK2 = 1 << TOIE2; // enable overflow interrupt
// actually start timer in ISR(TIMER1_COMPA_vect
// to prevent out of sync charge pulse, no prescaler set here

  attachInterrupt(digitalPinToInterrupt(3), delayPeriodTiming, FALLING);

}

void loop()
{
  unsigned long analogReadInterval = 500; // read pots and map
  if (millis() - lastAnalogRead >= analogReadInterval)
  {
    
    lastAnalogRead += analogReadInterval;
    potValue = analogRead(pot1); // rpm
    pickupValue = analogRead(pot2); // pickup position
    
//  barLength = analogRead(pot3); // length of bar for pickup
  
// Timer2 OCR2A requires max value 255 => 615 lowest RPM
    if (chargePulse)
    {
      RPM = map(potValue, 0, 1023, 615, 10000);
      pickup = map(pickupValue, 0, 1023, 10, 75); // so advance will read based on delay, 57 for yamaha 350 2 pu, 74 for 1 pu, 72 for tw200, 25 for 5013
      pulseWidth = (60000000/RPM)/360; // time for 1° in uS
//    barSize = map(barLength, 0, 1023, 10, 60);  // 10 for yamaha 350 2 pu, 60 for 1 pu, 60 for tw200
// RPM = 615; // for my serial test purposes 615-3800
    }
    else
    {
      RPM = map(potValue, 0, 1023, 500, 3800);
      pickupValue = map(pickupValue, 0, 1023, 0, 50); // to set position of pickup so advance will read
//    pulseWidth = map(barLength, 0, 1023, 71, 44); // add Width to non charging case
// RPM = 500; // for my serial test purposes 500-3800
    }

    timerTopValue = 15000000UL / RPM;
    OCR1B = pulseWidth;

// if (digitalRead(setFallingSwitch) == LOW) // set Falling
// {
// risefall = 'F';
// }
// else
// {
// risefall = 'R';
// }

    lcd.setCursor(6, 0);
    lcd.print("     "); // print blank spaces to clear old data
    lcd.setCursor(6, 0);
    lcd.print(RPM);  // print rpm

    lcd.setCursor(16, 0);
    lcd.print("  ");
    lcd.setCursor(16, 0);
    lcd.print(pulseWidth, 1); // print us per degree
    
    lcd.setCursor(6, 1);
    lcd.print("   ");
    lcd.setCursor(6, 1);
    lcd.print(pickup); // print pickup coil position

//    lcd.setCursor(16, 1);
//    lcd.print("   ");
//    lcd.setCursor(16, 1);
//    lcd.print(barLength); // length of bar

    lcd.setCursor(11, 2);
    lcd.print("       ");
    lcd.setCursor(11, 2);
    lcd.print(copy_delayPeriod);
  
    lcd.setCursor(14, 3);
    lcd.print("      ");
    lcd.setCursor(14, 3);
    lcd.print(delayDegrees, 1);   // delayDegrees, 1);
  }
 
  if (trigger == true && interruptFlag == true )
  {
    trigger = false;
    interruptFlag = false;
    noInterrupts();
    copy_delayPeriod = delayPeriod;
    interrupts();

    delayDegrees = pickup - (360.0 * (copy_delayPeriod) / (timerTopValue * 4.0)); // for decimal place in deg display.
//    degreesAdvance = pickupValue - delayDegrees; // added
    }
}

ISR(TIMER1_COMPA_vect) {
  OCR1A = (timerTopValue); // value to set delay between pulses to trigger cdi
  digitalWrite(chargePin, LOW); // guarantee off charge pin at trigger
  digitalWrite(outputPin, HIGH); // turn on pin  trigger

// if (risefall == 'R') // switch not set; default Rising trigger
  {
    delayPeriodStart = micros(); // start looking for response as pulse rises
    trigger = true;
  }
// start Timer 2 for charge pulses
  if (chargePulse)
  {
    timeSliceCount = 0;
    TCNT2 = 0;
    OCR2A = timerTopValue/96; // set 12 periods
    TCCR2B |=  1 << CS22 | 1 << CS21; //prescaleer 256 16us/tick
  }
}

ISR(TIMER1_COMPB_vect) {
  digitalWrite(outputPin, LOW);

// if (risefall == 'F') // switch set for Falling trigger
  {
    delayPeriodStart = micros(); // start looking for response as pulse falls
    trigger = true;
  }
}

void delayPeriodTiming()
{
  delayPeriod = micros() - delayPeriodStart;
  interruptFlag = true;
}

ISR(TIMER2_OVF_vect)
// 5 pulses of 30 degrees starting at 60 degrees
// ON at 60,120,180,240,300 = 2,4,6,8,10
// OFF at 90,150,210,270,330 = 3,5,7,9,11
{
  if (timeSliceCount != 0 && timeSliceCount % 2 == 0)
  {
    digitalWrite (chargePin, HIGH);
  }
  else // if (timeSliceCount == 0 || timeSliceCount % 2 == 1)
  {
    digitalWrite(chargePin, LOW);
  }
  timeSliceCount++;

  if (timeSliceCount == 12)
  {
    timeSliceCount = 0;
// stop Timer2 by clearing prescaler bits
    TCCR2B &= ~1<< CS22;
    TCCR2B &= ~1<< CS21;
  }
}



Title: Re: CDI tester project
Post by: cattledog on Apr 22, 2019, 10:16 pm
This code seems very similar to wht you posted in#246.
Quote
Have worked with it anyway and this seems to be a working sketch, it goes back to the one I was using before the DAC idea. I have cleaned up the display items a little and the timing computation works when the AC is on but not when it is off
Do you mean that you now see outgoing pulses on pin4 in both modes, but not the timing of the return pulses?

I see trigger output as before with my interrupt counter. I then set up my delayed return pulse sketch for 2000 us delay and I see that reported in the Us Delay: line of the lcd. All looks well with my tool set.

There is certainly clean up to be done, but first, lets work through the issue of sending trigger pulses and reading returns in DC mode.
Title: Re: CDI tester project
Post by: tom_bauer on Apr 22, 2019, 10:26 pm
This code seems very similar to wht you posted in#246.
Do you mean that you now see outgoing pulses on pin4 in both modes, but not the timing of the return pulses?
Yes, the timing computation only works when there are pulses going out on pin 7 for the charge pulse.
Pin 4 has good pulses in both situations, and the relation to the charge pluses is perfect.

I see trigger output as before with my interrupt counter. I then set up my delayed return pulse sketch for 2000 us delay and I see that reported in the Us Delay: line of the lcd. All looks well with my tool set.

There is certainly clean up to be done, but first, lets work through the issue of sending trigger pulses and reading returns in DC mode.
OK, I agree that and the reset should be working first.
Title: Re: CDI tester project
Post by: cattledog on Apr 22, 2019, 10:40 pm
Quote
Also I cannot get it to change from AC to DC without manual reset and don't see why.
You are only reading the AC/DC setting switch in setup. Leave it ins setup but add the reading to loop here
Code: [Select]

if (millis() - lastAnalogRead >= analogReadInterval)
  {   
    lastAnalogRead += analogReadInterval;
    potValue = analogRead(pot1); // rpm
    pickupValue = analogRead(pot2); // pickup position

    if (digitalRead(setChargePulseSwitch) == LOW)
    chargePulse = true; // AC CDI
.
.
.



Do you understand what was previously wrong with the pin 4 output?

Quote
Yes, the timing computation only works when there are pulses going out on pin 7 for the charge pulse.
Do you know if you are seeing return pulses coming back to pin3?
Title: Re: CDI tester project
Post by: tom_bauer on Apr 23, 2019, 12:53 am
Yes whether in DC or AC mode there are always pulses at D3, the current to the ign coil is sensed by a clamp on pickup and triggers a small SCR so as long as the coil is making a spark there is a signal at D3

I am not sure what was going on with D4 output, perhaps a conflict in timer? That is why I went back to a known good sketch to modify.
Tom
Title: Re: CDI tester project
Post by: cattledog on Apr 23, 2019, 01:27 am
Tom--
Since I can't confirm your issue, I would like you to try using a second Arduino to issue the response, and see if the calculations occur. Lets try and separate software from hardware issues.

Jumper the cdi tester output on pin 4 to the second Arduino pin 3 and the second Arduino's pin 4 back to pin 3 of the cdi tester. Do you see Us Delay reported in both AC and DC mode?

Code: [Select]


//pin 3 interrupt as as input
//pin 4 as pulse output
void setup() {
 pinMode(4,OUTPUT);
 attachInterrupt(digitalPinToInterrupt(3),pulse,RISING);//interrupt on pin3
}

void loop() {}

void pulse()
{
  delayMicroseconds(2000);
  //delayMicroseconds(0);
  digitalWrite(4,LOW);//will drive main board interrupt FALLING
  delayMicroseconds(10);
  digitalWrite(4,HIGH);
}

Title: Re: CDI tester project
Post by: tom_bauer on Apr 23, 2019, 03:09 am
Hi, I may be looking at this wrong, when in DC mode it is pot2 that does not work so it shows position as 0 and therefore degree advance shows as 0 or 0.1  I was thinking that this part of the code was just not working and it may be, just that if pickup position is not set to something real it has nothing to compute. Make sense?
Tom
Title: Re: CDI tester project
Post by: cattledog on Apr 23, 2019, 04:11 am
Quote
Make sense?
No.
The math does not require a non zero value
Code: [Select]
delayDegrees = pickup - (360.0 * (copy_delayPeriod) / (timerTopValue * 4.0)); // for decimal place in deg display.

My test code is showing POS(pickup) at 0. With a 2000 microsecond delay in the response I see Us Delay 2000 and as expected from the math, Deg Advance is negative.

For now, focus on the Us Delay. That's the microsecond value of the delayed response from the cdi unit (or the simulated test code of my previous post.). It shows if there a response read as a reply to the outgoing pulse.

Any time you have a question about values, you can always comment out the code which varies a pot, and just substitute a fixed value.
Title: Re: CDI tester project
Post by: tom_bauer on Apr 23, 2019, 05:50 am
Hi, re the math, no what I meant was that the pot2 was not being read so the code saw a 0. Once I got the pot for position to read in AC and DC then that problem went away. You will see that I striped a lot away. It seems to work very well, maybe you will see some remnants still lurking in the timer parts, I really don't understand the code for timers!
Thanks for everything.
Title: Re: CDI tester project
Post by: cattledog on Apr 24, 2019, 12:13 am
I'm pleased you got the mysteries sorted out. I can't say that I understand what what wrong, but I don't believe it was the code. Given that you have fought your way through so many  hardware issues over the long course of this project its time to give you a Karma point.

I noticed on the image of the actual charge pulse output that there are only 4 pulses, and the first one is somewhat low. The pin output is 5 pulses. Do you understand what is going on here?

Nice job cleaning up the code for version_15. There is one issue which needs to be addressed.

You start the timing cycle in two places. This goes back to when we wanted to time from either the rising or falling edge of the trigger pulse which is one degree long. The rising edge timing is in  ISR(Timer1_COMPA_vect) and the falling edge timing is in the ISR(TIMER1_COMPB_vect). Either put the R/F back, or decide which start time to use.

Code: [Select]
ISR(TIMER1_COMPA_vect) {
  OCR1A = (timerTopValue); // value to set delay between pulses to trigger cdi
  digitalWrite(chargePin, LOW); // guarantee off charge pin at trigger
  digitalWrite(outputPin, HIGH); // turn on pin  trigger

 
    delayPeriodStart = micros(); // start looking for response as pulse rises
    trigger = true;
 
  // start Timer 2 for charge pulses
  if (chargePulse)
  {
    timeSliceCount = 0;
    TCNT2 = 0;
    OCR2A = timerTopValue / 96; // set 12 periods
    TCCR2B |=  1 << CS22 | 1 << CS21; //prescaleer 256 16us/tick
  }
}

ISR(TIMER1_COMPB_vect) {
  digitalWrite(outputPin, LOW);
 
    delayPeriodStart = micros(); // start looking for response as pulse falls
    trigger = true;

}

 

Title: Re: CDI tester project
Post by: tom_bauer on Apr 24, 2019, 12:35 am
Thanks, re the actual charge pulses, they are charging up a 2.2uf 400v capacitor so the first pulse has a lot of load on it compared to the final one. As for the seemingly only 4 pulses, I think the first one is just too small to show. For this I am only powering the transformer driver circuit with 12v and the working version will likely be driven with a 25v to 35v supply. I also need to work out a pos and neg trigger combined as some Honda CDI need to see both. Most of the Yamaha that I make I need them completely seperate to do testing on the CDI. This will all be done in hardware.
Again, many thanks.

By the way I assume you have a Australian Cattle Dog ? I have a 1 1/2 year old male and he is, well a typical cattle dog but with an attitude.
Tom
Title: Re: CDI tester project
Post by: cattledog on Apr 24, 2019, 03:21 am
Quote
I also need to work out a pos and neg trigger combined as some Honda CDI need to see both. Most of the Yamaha that I make I need them completely seperate to do testing on the CDI. This will all be done in hardware.
It's too bad the DAC did not work out for this purpose. Are you certain that with what you know now, you can't get it to work. The code is ready to go :)

Quote
By the way I assume you have a Australian Cattle Dog ? I have a 1 1/2 year old male and he is, well a typical cattle dog but with an attitude.
Mine is long gone, but I think they all have attitudes. They are very tough breed to have. I never had the patience to properly train mine, and she did what she wanted to do. Totally a mind of it's own.

Mine was a terrible watch dog-- aggressive but not not alert. No alarm barking, but she'd bite when a stranger sneaked up on her.
Title: Re: CDI tester project
Post by: tom_bauer on Apr 29, 2019, 07:05 pm
Cattledog,
Hi, I had an idea I wanted to try. For this I need a second pulse on a second output pin to occur an adjustable time after the first trigger pulse on D4, the time will be 1° so I thought to use pulseWidth.
Of course this code does  not work but may give you an idea of what I wanted to do.

Code: [Select]
ISR(TIMER1_COMPB_vect) {
  digitalWrite(outputPin, LOW);
  time = pulseWidth
  wait(time)
  digitalWrite(output2Pin, HIGH); // turn on 2nd pin trigger D5
  {
    delayPeriodStart = micros(); // start looking for response as pulse rises
    trigger = true;
  }
  digitalWrite(output2Pin, LOW);
 


Tom
Title: Re: CDI tester project
Post by: cattledog on Apr 30, 2019, 12:41 am
Quote
Hi, I had an idea I wanted to try. For this I need a second pulse on a second output pin to occur an adjustable time after the first trigger pulse on D4, the time will be 1° so I thought to use pulseWidth.
Of course this code does  not work but may give you an idea of what I wanted to do.
Do you want a second pulse of 1 degree width starting 1 degree after the first pulse is terminated? Does this pulse need to be 1 degree wide, or can it be shorter. Do you want to start the return pulse timing from this second pulse? Is the delay period of 1 degree after the first pulse ends fixed or variable?

Do you still have a working version of the bipolar pulse program. If we make both the first and second pulses positive where bar width is setting the timing between them would that work? We could generate the pulses either with or without the DAC.

I'm trying to decide if we can add a second output pulse to the current unipulse program or if its better to leverage off the two pulse program but make both pulses positive (can be done without DAC).

How certain are you that you will need a two pulse program, and how much is this a quick and dirty experiment?
Title: Re: CDI tester project
Post by: tom_bauer on Apr 30, 2019, 12:58 am
Hi, well this is just an experiment but it looks likely to be as good or better than what I have now. Remember I once said I did not understand timers? Well that is certainly still true! Today I got a working version going but it has issues. So what I don't know is: where is the width or duration of the existing pulse set? The second pulse, on a different output pin, should likely start right where the first ends but it may need just a tiny amount of time in between. Lets for now assume it won't. But it needs to be as wide as the first.
Thanks, Tom
Title: Re: CDI tester project
Post by: cattledog on Apr 30, 2019, 01:18 am
Quote
where is the width or duration of the existing pulse set?
The pulse width is set a fixed one degree, by the OCR1B value. The compare match B turns the pulse off.

Quote
The second pulse, on a different output pin, should likely start right where the first ends but it may need just a tiny amount of time in between. Lets for now assume it won't. But it needs to be as wide as the first.
OK. Ill see what I can do.  Where does the return pulse delay timing start? With the first or second pulse? Can you explain the function of the second pulse?
Title: Re: CDI tester project
Post by: cattledog on Apr 30, 2019, 02:04 am
I added an output2Pin 5

I changed the timer mode to CTC to ICR1 (instead of OCR1A) to free up a second compare match (A) to turn off the  second pin.  The Overflow vector turns on the first pin at the top, similar to what the compare match A was previously doing. The B compare match turns off the first pin (turned on at the top) and turns on the second. The second pin turns off with the A compare match. pulseWidth is 1 degree for both.  It still starts timing in two places and that issue is unresolved.

See if this does what you want.


Code: [Select]
// last change 4/21/2019
// 8/17 added code for pulse out width
// 7/14/2017 added correct math and setting for position of pickup
// 10 10/28/2016 adds charging pulse with Timer 2
// lowest RPM = 615 with charge pulse to keep OCR2A <= 255
// CDI Tester Pulse Generator Serial Output Arduino Code
// replaced on 7/22/18 mod on 4/18/2019 changed to go simple transformer control of pos / neg trigger
// update 7/14/2017 added correct math and setting for position of pickup
// revision 10 10/28/2016 adds charging pulse with Timer 2
// lowest RPM = 615 with charge pulse to keep OCR2A <= 255
// CDI Tester Pulse Generator Serial Output Arduino Code
// 8/17 added code for pulse out width

#include <Wire.h>
#include <hd44780.h>
#include <hd44780ioClass/hd44780_I2Cexp.h> // include i/o class header
hd44780_I2Cexp lcd; // declare lcd object: auto locate & config display for hd44780 chip

int pot1 = A1; // select the input pin for the pot for rpm
int pot2 = A2; // select the input pin for the pot for pickup location in degrees
int potValue = 0; // variable to store the value coming from the sensor
int pickupValue = 0; // position of pickup in degrees
int timerTopValue = 12500; // changed from timerTopValue = 0
int outputPin = 4; // select the pin for the output for trigger pulse, changed from 8
int output2Pin = 5;
int chargePin = 7; // select the pin for the output for charge pulses

volatile boolean trigger = false;
volatile unsigned long delayPeriod;
unsigned long copy_delayPeriod;
volatile unsigned long delayPeriodStart;
float delayDegrees; // changed from int to float for decimal place display
int RPM;
int pickup;
int pulseWidth;                                           
volatile boolean interruptFlag;
unsigned long analogReadInterval = 500; // read pots and map
unsigned long lastAnalogRead;
const byte setChargePulseSwitch = 6;
boolean chargePulse = false ;  // default dc powered mode
volatile byte timeSliceCount = 0; // TDC 0 degrees

void setup() {
// Serial.begin(115200);
// Serial.println("starting...");
  lcd.begin(20, 4); // initialize the lcd for 20 chars 4 lines, turn on backlight
  lcd.setCursor(1, 0); // lcd display setup of unchanging headings
  lcd.print("RPM:"); // print fixed characters
  lcd.setCursor(12, 0);
  lcd.print("Deg");
  lcd.setCursor(1, 1);
  lcd.print("Pos:");
  lcd.setCursor(1, 2);
  lcd.print("Us Delay:");
  lcd.setCursor(1, 3);
  lcd.print("Deg Advance:");

  pinMode(outputPin, OUTPUT); // declare the outputPin as an OUTPUT
  pinMode(output2Pin, OUTPUT);
  pinMode(chargePin, OUTPUT); // declare the chargePin as an OUTPUT
  pinMode(setChargePulseSwitch, INPUT_PULLUP);

  if (digitalRead(setChargePulseSwitch) == LOW)
    chargePulse = true; // AC CDI

 // Timer1 default set up .5ms trigger pulse every 50 ms
  TCCR1A = 0;
   TCCR1B = 0;
  //TCCR1B = (1 << WGM12); // CTC mode to OCR1A
  TCCR1B = (1 << WGM13) | (1 << WGM12);//CTC mode to ICR1
  //OCR1A = timerTopValue;
  ICR1 = timerTopValue;
  TIMSK1 |= (1 << OCIE1A); // interrupt enable compareA
  TIMSK1 |= (1 << OCIE1B); // interrupt enable compareB
  TIMSK1 |= (1<< TOIE1);//overflow interrupt at top
  OCR1B = 500; // sets trigger pulse width, 500 = 2Ms, 250 = 1Ms, 125 = .5Ms, set to 1250 for 5013 *********************************************
  OCR1A = OCR1B +500;//add default
  TCCR1B |= (1 << CS11) | (1 << CS10); // prescaler 64 4us/tick

// Timer2 default setup charge pulse 12 periods 30 degrees each; only 5 get turned on
// charge pulse timing interval = Timer1 trigger period/12 = timerTopValue/96
  TCCR2A = 0;
  TCCR2B = 0;
  TCCR2A = 1 << WGM20; // lsb of mode 7 pwm to OCR2A
  TCCR2B = 1 << WGM22; // msb of mode 7 pwm to OCR2A;
  OCR2A = timerTopValue / 96; // 96 = 12*4*2 (#periods, prescaler difference, up/down timer mode )
  TIMSK2 = 0;
  TIMSK2 = 1 << TOIE2; // enable overflow interrupt
// actually start timer in ISR(TIMER1_COMPA_vect
// to prevent out of sync charge pulse, no prescaler set here

  attachInterrupt(digitalPinToInterrupt(3), delayPeriodTiming, FALLING);

}

void loop()
{
  unsigned long analogReadInterval = 500; // read pots and map
  if (millis() - lastAnalogRead >= analogReadInterval)
  {
    lastAnalogRead += analogReadInterval;
    potValue = analogRead(pot1); // rpm
    pickupValue = analogRead(pot2); // pickup position

    if (digitalRead(setChargePulseSwitch) == LOW)
    chargePulse = true; // AC CDI
    else chargePulse = false;
   
// Timer2 OCR2A requires max value 255 => 615 lowest RPM
// if (chargePulse)
    {
      RPM = map(potValue, 0, 1023, 615, 10000);
      pickup = map(pickupValue, 0, 1023, 10, 75); // so advance will read based on delay, 57 for yamaha 350 2 pu, 74 for 1 pu, 72 for tw200, 25 for 5013
      pulseWidth = (60000000/RPM)/360; // time for 1° in uS
    }

    timerTopValue = 15000000UL / RPM;
    OCR1B = pulseWidth;
    OCR1A = OCR1B + pulseWidth;

    lcd.setCursor(6, 0);
    lcd.print("     "); // print blank spaces to clear old data
    lcd.setCursor(6, 0);
    lcd.print(RPM);  // print rpm

    lcd.setCursor(16, 0);
    lcd.print("  ");
    lcd.setCursor(16, 0);
    lcd.print(pulseWidth, 1); // print us per degree
   
    lcd.setCursor(6, 1);
    lcd.print("   ");
    lcd.setCursor(6, 1);
    lcd.print(pickup); // print pickup coil position

    lcd.setCursor(11, 2);
    lcd.print("       ");
    lcd.setCursor(11, 2);
    lcd.print(copy_delayPeriod);
   
    lcd.setCursor(14, 3);
    lcd.print("      ");
    lcd.setCursor(14, 3);
    lcd.print(delayDegrees, 1);   // delayDegrees, 1);
  }
 
  if (trigger == true && interruptFlag == true )
  {
    trigger = false;
    interruptFlag = false;
    noInterrupts();
    copy_delayPeriod = delayPeriod;
    interrupts();

    delayDegrees = pickup - (360.0 * (copy_delayPeriod) / (timerTopValue * 4.0)); // for decimal place in deg display.
    }
}

//ISR(TIMER1_COMPA_vect) {
ISR(TIMER1_OVF_vect){
  //OCR1A = (timerTopValue); // value to set delay between pulses to trigger cdi
  ICR1 = (timerTopValue);
  digitalWrite(chargePin, LOW); // guarantee off charge pin at trigger
  digitalWrite(outputPin, HIGH); // turn on pin  trigger

  {
    delayPeriodStart = micros(); // start looking for response as pulse rises
    trigger = true;
  }
// start Timer 2 for charge pulses
  if (chargePulse)
  {
    timeSliceCount = 0;
    TCNT2 = 0;
    OCR2A = timerTopValue/96; // set 12 periods
    TCCR2B |=  1 << CS22 | 1 << CS21; //prescaleer 256 16us/tick
  }
}

ISR(TIMER1_COMPB_vect) {
  digitalWrite(outputPin, LOW);
  //could add short delayMiocroseconds here for gap
  digitalWrite(output2Pin,HIGH);

  {
    delayPeriodStart = micros(); // start looking for response as pulse falls
    trigger = true;
  }
}

ISR(TIMER1_COMPA_vect) {
  digitalWrite(output2Pin, LOW);
}

void delayPeriodTiming()
{
  delayPeriod = micros() - delayPeriodStart;
  interruptFlag = true;
}

ISR(TIMER2_OVF_vect)
// 5 pulses of 30 degrees starting at 60 degrees
// ON at 60,120,180,240,300 = 2,4,6,8,10
// OFF at 90,150,210,270,330 = 3,5,7,9,11
{
  if (timeSliceCount != 0 && timeSliceCount % 2 == 0)
  {
    digitalWrite (chargePin, HIGH);
  }
  else // if (timeSliceCount == 0 || timeSliceCount % 2 == 1)
  {
    digitalWrite(chargePin, LOW);
  }
  timeSliceCount++;

  if (timeSliceCount == 12)
  {
    timeSliceCount = 0;
// stop Timer2 by clearing prescaler bits
    TCCR2B &= ~1<< CS22;
    TCCR2B &= ~1<< CS21;
  }
}
Title: Re: CDI tester project
Post by: tom_bauer on Apr 30, 2019, 05:36 pm
Hi, well interesting result, but no sorry. No output at all from D4, output from D5 varies in width as expected but does not follow rpm change.
Tom
Title: Re: CDI tester project
Post by: cattledog on Apr 30, 2019, 10:06 pm
Hi Tom--

Sorry I didn't test what I posted last night.

It works as intended with a slightly different Timer mode. I don't think the Overflow interrupt was being triggered in CTC to ICR1 mode. Change the Timer1 setup to Fast PWM to ICR1 mode. This one line added goes in the Timer1 setup portion of the code. I see pulses on pins 4 and 5 which change with RPM, and the pulse counts are correct for the RPM.

Code: [Select]
TCCR1A = (1<< WGM11);//Fast PWM to ICR1
  TCCR1B = (1 << WGM13) | (1 << WGM12);
Title: Re: CDI tester project
Post by: tom_bauer on Apr 30, 2019, 10:36 pm
Cattledog,
Yes that works splendidly. I will finish the circuit tomorrow and see how the transformer output looks. I am going to Florida until middle of next week but will let you know results first.
I also noted  that changing the OCR1B value does not change the width of the pules and I have been unable to put any separation between them as I think I will need to do. I think that just putting milliseconds there won't be ideal as the pulse separation should be based on rpm since the faster it turns the shorter the time.
Best, Tom
Title: Re: CDI tester project
Post by: cattledog on May 01, 2019, 04:19 am
Quote
I also noted  that changing the OCR1B value does not change the width of the pulses
I just saw your edit about pulseWidth. Here is the section of code which sets it to one degree. The actual pulseWidth time varies with RPM. You can change the math for any length you want. What did you have in mind?

Code: [Select]
pulseWidth = (60000000/RPM)/360; // time for 1° in us

    timerTopValue = 15000000UL / RPM;
    OCR1B = pulseWidth;
    OCR1A = OCR1B + pulseWidth; //2*pulsewidth



Quote
I have been unable to put any separation between them as I think I will need to do. I think that just putting milliseconds there won't be ideal as the pulse separation should be based on rpm since the faster it turns the shorter the time.
How long of a gap do you want? You might be able to get away with using a gap of less than 10 microseconds by using some no operations (NOP) to create a delay in the COMP_B isr. The number of NOP's called can vary with RPM.

Longer than that, we may need to go back to the bipolar pulse code with the period divided into two parts. 

I also think that if you can put the outputs on pins 9 and 10  it might open some options as we can use the hardware pwm outputs to turn the two pins on and off with a variable gap between them.


Title: Re: CDI tester project
Post by: tom_bauer on May 01, 2019, 04:37 am
OK 9 and 10 are available. What I was thinking, not understanding timers, was a way to have the gap between the pulses be a function of degrees. If pulseWidth is 1° then how would you put 4° gap for instance. That way the gap would narrow along with the actual pulse width.

What I was asking earlier was regarding line 76:
OCR1B = 500; // sets trigger pulse width, 500 = 2Ms, 250 = 1Ms, 125 = .5Ms, set to 1250 for 5013
I used to be able to set the pulse width here but not now, was curious why.
Tom
Title: Re: CDI tester project
Post by: cattledog on May 01, 2019, 04:59 am
Quote
If pulseWidth is 1° then how would you put 4° gap for instance. That way the gap would narrow along with the actual pulse width.
This is starting to sound alot like the bipolar pulse code where the pulse separation was set by barWidth, and was based on degrees. I will look at modifying that code to make the two pin output separated by a degree value which can be variable with a pot and read in the loop along with RPM and pickup.

Can you test the hardware for the two pulses by putting a delayMicroseconds() call in the COMP_B isr where I indicated with the comment?
Title: Re: CDI tester project
Post by: tom_bauer on May 01, 2019, 05:21 am
Yes I will do that in morning. Don't put any time into it yet, I need to see what the output of the transformer looks like. It does not need to be variable with a pot, just set for the best response from transformer and The magnetic characteristics will determine most of that.
Tom
Title: Re: CDI tester project
Post by: cattledog on May 01, 2019, 06:24 am
Quote
OCR1B = 500; // sets trigger pulse width, 500 = 2Ms, 250 = 1Ms, 125 = .5Ms, set to 1250 for 5013
I used to be able to set the pulse width here but not now, was curious why.
This is just a placeholder in setup. It may have come from original development when RPM was hard coded before the value was put on a pot for adjustment, or from an earlier time when we were working with time values and not degrees.   

The setup default is overridden by the setting in loop when the RPM pot is read.
Title: Re: CDI tester project
Post by: tom_bauer on May 01, 2019, 08:01 pm
Hi, well the transformer had more magnetic ringing issues than it is worth dealing with so version 15 looks to be the one I will use. I never did figure out how to not start the second timer as you noted. Thanks for all the help, if someone wants to see the schematic for this I can upload it, it is very useful for testing.
Best, Tom
Title: Re: CDI tester project
Post by: cattledog on May 01, 2019, 08:38 pm

Quote
I never did figure out how to not start the second timer as you noted.
Remove the timing start from the COMP_B isr.

Code: [Select]
ISR(TIMER1_COMPB_vect) {
  digitalWrite(outputPin, LOW);

 // {
 //   delayPeriodStart = micros(); // start looking for response as pulse falls
 //   trigger = true;
  //}
}


This removes the delay timing start the falling edge of the trigger pulse. If you want to use it, remove the equivalent code from the COMPA ISR which starts the timing from the rising edge. The two edges are separated by 1 degree, so the timing change is not large.

If you are not sure of what you want to use, you can put the R/F edge selector code back.


Title: Re: CDI tester project
Post by: tom_bauer on May 01, 2019, 09:14 pm
Cattledog,
OK thanks, I see that now and start to understand! Well thanks for all the help, I will be putting this together in a week or so.
Best, Tom
Title: Re: CDI tester project
Post by: tom_bauer on May 10, 2019, 10:15 pm
Cattledog,
While working with several small transformers I think that the core may being saturated at higher rpm so I would like to narrow the pulse width for the charge pulses. I am not clear on how to do that.
Thanks, Tom
Title: Re: CDI tester project
Post by: cattledog on May 10, 2019, 11:32 pm
Tom--

Please post the code you are currently using, and want me to modify. Currently, the 5 charge pulses are 30 degrees wide. I can see a way to easily give you the same 5 pulses either 15 degrees wide or 10 degrees wide.

The code currently divides the 360 degree period into 12 slices of 30 degrees, but turns on and off every other slice. I can easily modify the code to make 24 slices of 15 degrees and 36 slices of 10 degrees.

I've not really looked close enough to see how to get complete flexibility. But I'd like so see what you need.
Title: Re: CDI tester project
Post by: tom_bauer on May 11, 2019, 01:06 am
Here is the code that I settled on, 15A, it does everything well. I think going to 10° charge pulse width from 30° will show me if the saturation of the core is the issue.
Tom

Code: [Select]

// last change 4/21/2019
// 8/17 added code for pulse out width
// 7/14/2017 added correct math and setting for position of pickup
// 10 10/28/2016 adds charging pulse with Timer 2
// lowest RPM = 615 with charge pulse to keep OCR2A <= 255
// CDI Tester Pulse Generator Serial Output Arduino Code
// replaced on 7/22/18 mod on 4/18/2019 changed to go simple transformer control of pos / neg trigger
// update 7/14/2017 added correct math and setting for position of pickup
// revision 10 10/28/2016 adds charging pulse with Timer 2
// lowest RPM = 615 with charge pulse to keep OCR2A <= 255
// CDI Tester Pulse Generator Serial Output Arduino Code
// 8/17 added code for pulse out width

#include <Wire.h>
#include <hd44780.h>
#include <hd44780ioClass/hd44780_I2Cexp.h> // include i/o class header
hd44780_I2Cexp lcd; // declare lcd object: auto locate & config display for hd44780 chip

int pot1 = A1; // select the input pin for the pot for rpm
int pot2 = A2; // select the input pin for the pot for pickup location in degrees
int potValue = 0; // variable to store the value coming from the sensor
int pickupValue = 0; // position of pickup in degrees
int timerTopValue = 12500; // changed from timerTopValue = 0
int outputPin = 4; // select the pin for the output for trigger pulse, changed from 8
int output2Pin = 5;
int chargePin = 7; // select the pin for the output for charge pulses

volatile boolean trigger = false;
volatile unsigned long delayPeriod;
unsigned long copy_delayPeriod;
volatile unsigned long delayPeriodStart;
float delayDegrees; // changed from int to float for decimal place display
int RPM;
int pickup;
int pulseWidth;
volatile boolean interruptFlag;
unsigned long analogReadInterval = 500; // read pots and map
unsigned long lastAnalogRead;
const byte setChargePulseSwitch = 6;
boolean chargePulse = false ;  // default dc powered mode
volatile byte timeSliceCount = 0; // TDC 0 degrees

void setup() {
// Serial.begin(115200);
// Serial.println("starting...");
  lcd.begin(20, 4); // initialize the lcd for 20 chars 4 lines, turn on backlight
  lcd.setCursor(1, 0); // lcd display setup of unchanging headings
  lcd.print("RPM:"); // print fixed characters
  lcd.setCursor(12, 0);
  lcd.print("Deg");
  lcd.setCursor(1, 1);
  lcd.print("Pos:");
  lcd.setCursor(1, 2);
  lcd.print("Us Delay:");
  lcd.setCursor(1, 3);
  lcd.print("Deg Advance:");

  pinMode(outputPin, OUTPUT); // declare the outputPin as an OUTPUT
  pinMode(output2Pin, OUTPUT);
  pinMode(chargePin, OUTPUT); // declare the chargePin as an OUTPUT
  pinMode(setChargePulseSwitch, INPUT_PULLUP);

  if (digitalRead(setChargePulseSwitch) == LOW)
    chargePulse = true; // AC CDI

 // Timer1 default set up .5ms trigger pulse every 50 ms
  TCCR1A = (1<< WGM11);//Fast PWM to ICR1
  TCCR1B = (1 << WGM13) | (1 << WGM12);
  //TCCR1B = (1 << WGM12); // CTC mode to OCR1A
  TCCR1B = (1 << WGM13) | (1 << WGM12);//CTC mode to ICR1
  //OCR1A = timerTopValue;
  ICR1 = timerTopValue;
  TIMSK1 |= (1 << OCIE1A); // interrupt enable compareA
  TIMSK1 |= (1 << OCIE1B); // interrupt enable compareB
  TIMSK1 |= (1<< TOIE1);//overflow interrupt at top
  OCR1B = 250; // sets trigger pulse width, 500 = 2Ms, 250 = 1Ms, 125 = .5Ms, set to 1250 for 5013 *********************************************
  OCR1A = OCR1B +500;//add default
  TCCR1B |= (1 << CS11) | (1 << CS10); // prescaler 64 4us/tick

// Timer2 default setup charge pulse 12 periods 30 degrees each; only 5 get turned on
// charge pulse timing interval = Timer1 trigger period/12 = timerTopValue/96
  TCCR2A = 0;
  TCCR2B = 0;
  TCCR2A = 1 << WGM20; // lsb of mode 7 pwm to OCR2A
  TCCR2B = 1 << WGM22; // msb of mode 7 pwm to OCR2A;
  OCR2A = timerTopValue / 96; // 96 = 12*4*2 (#periods, prescaler difference, up/down timer mode )
  TIMSK2 = 0;
  TIMSK2 = 1 << TOIE2; // enable overflow interrupt
// actually start timer in ISR(TIMER1_COMPA_vect
// to prevent out of sync charge pulse, no prescaler set here

  attachInterrupt(digitalPinToInterrupt(3), delayPeriodTiming, FALLING);

}

void loop()
{
  unsigned long analogReadInterval = 500; // read pots and map
  if (millis() - lastAnalogRead >= analogReadInterval)
  {
    lastAnalogRead += analogReadInterval;
    potValue = analogRead(pot1); // rpm
    pickupValue = analogRead(pot2); // pickup position

    if (digitalRead(setChargePulseSwitch) == LOW)
    chargePulse = true; // AC CDI
    else chargePulse = false;
   
// Timer2 OCR2A requires max value 255 => 615 lowest RPM
// if (chargePulse)
    {
      RPM = map(potValue, 0, 1023, 615, 10000);
      pickup = map(pickupValue, 0, 1023, 10, 75); // position so advance will read based on delay, 57 for yamaha 350 2 pu, 74 for 1 pu, 72 for tw200, 25 for 5013
      pulseWidth = (60000000/RPM)/360; // time for 1° in uS
    }

    timerTopValue = 15000000UL / RPM;
    OCR1B = pulseWidth;
    OCR1A = OCR1B + pulseWidth;

    lcd.setCursor(6, 0);
    lcd.print("     "); // print blank spaces to clear old data
    lcd.setCursor(6, 0);
    lcd.print(RPM);  // print rpm

    lcd.setCursor(16, 0);
    lcd.print("  ");
    lcd.setCursor(16, 0);
    lcd.print(pulseWidth, 1); // print us per degree
   
    lcd.setCursor(6, 1);
    lcd.print("   ");
    lcd.setCursor(6, 1);
    lcd.print(pickup); // print pickup coil position

    lcd.setCursor(11, 2);
    lcd.print("       ");
    lcd.setCursor(11, 2);
    lcd.print(copy_delayPeriod);
   
    lcd.setCursor(14, 3);
    lcd.print("      ");
    lcd.setCursor(14, 3);
    lcd.print(delayDegrees, 1);   // delayDegrees, 1);
  }
 
  if (trigger == true && interruptFlag == true )
  {
    trigger = false;
    interruptFlag = false;
    noInterrupts();
    copy_delayPeriod = delayPeriod;
    interrupts();

    delayDegrees = pickup - (360.0 * (copy_delayPeriod) / (timerTopValue * 4.0)); // for decimal place in deg display.
    }
}

//ISR(TIMER1_COMPA_vect) {
ISR(TIMER1_OVF_vect){
  //OCR1A = (timerTopValue); // value to set delay between pulses to trigger cdi
  ICR1 = (timerTopValue);
  digitalWrite(chargePin, LOW); // guarantee off charge pin at trigger
  digitalWrite(outputPin, HIGH); // turn on pin  trigger

  {
    delayPeriodStart = micros(); // start looking for response as pulse rises
    trigger = true;
  }
// start Timer 2 for charge pulses
  if (chargePulse)
  {
    timeSliceCount = 0;
    TCNT2 = 0;
    OCR2A = timerTopValue/96; // set 12 periods
    TCCR2B |=  1 << CS22 | 1 << CS21; //prescaleer 256 16us/tick
  }
}

ISR(TIMER1_COMPB_vect) {
  digitalWrite(outputPin, LOW);
  //could add short delayMiocroseconds here for gap
  digitalWrite(output2Pin,HIGH);

  //{
  //  delayPeriodStart = micros(); // start looking for response as pulse falls
  //  trigger = true;
  //}
}

ISR(TIMER1_COMPA_vect) {
  digitalWrite(output2Pin, LOW);
}

void delayPeriodTiming()
{
  delayPeriod = micros() - delayPeriodStart;
  interruptFlag = true;
}

ISR(TIMER2_OVF_vect)
// 5 pulses of 30 degrees starting at 60 degrees
// ON at 60,120,180,240,300 = 2,4,6,8,10
// OFF at 90,150,210,270,330 = 3,5,7,9,11
{
  if (timeSliceCount != 0 && timeSliceCount % 2 == 0)
  {
    digitalWrite (chargePin, HIGH);
  }
  else // if (timeSliceCount == 0 || timeSliceCount % 2 == 1)
  {
    digitalWrite(chargePin, LOW);
  }
  timeSliceCount++;

  if (timeSliceCount == 12)
  {
    timeSliceCount = 0;
// stop Timer2 by clearing prescaler bits
    TCCR2B &= ~1<< CS22;
    TCCR2B &= ~1<< CS21;
  }
}
Title: Re: CDI tester project
Post by: cattledog on May 11, 2019, 01:33 am
I think this will give 5 pulses of 10 degrees width starting at 60, 120, 180, 240, 300. Instead of creating 12 periods for a cycle I used 36, and turn on with modulo 6 (%6) instead of modulo 2(%2). Please verify with a scope as I have not done any testing. I have not looked closely if there are minimum or maximum rpm requirements. If the shorter pulse is important, we can test deeper.

Code: [Select]
//change charge pulse to 10 degrees from 30
// last change 4/21/2019
// 8/17 added code for pulse out width
// 7/14/2017 added correct math and setting for position of pickup
// 10 10/28/2016 adds charging pulse with Timer 2
// lowest RPM = 615 with charge pulse to keep OCR2A <= 255
// CDI Tester Pulse Generator Serial Output Arduino Code
// replaced on 7/22/18 mod on 4/18/2019 changed to go simple transformer control of pos / neg trigger
// update 7/14/2017 added correct math and setting for position of pickup
// revision 10 10/28/2016 adds charging pulse with Timer 2
// lowest RPM = 615 with charge pulse to keep OCR2A <= 255
// CDI Tester Pulse Generator Serial Output Arduino Code
// 8/17 added code for pulse out width

#include <Wire.h>
#include <hd44780.h>
#include <hd44780ioClass/hd44780_I2Cexp.h> // include i/o class header
hd44780_I2Cexp lcd; // declare lcd object: auto locate & config display for hd44780 chip

int pot1 = A1; // select the input pin for the pot for rpm
int pot2 = A2; // select the input pin for the pot for pickup location in degrees
int potValue = 0; // variable to store the value coming from the sensor
int pickupValue = 0; // position of pickup in degrees
int timerTopValue = 12500; // changed from timerTopValue = 0
int outputPin = 4; // select the pin for the output for trigger pulse, changed from 8
int output2Pin = 5;
int chargePin = 7; // select the pin for the output for charge pulses

volatile boolean trigger = false;
volatile unsigned long delayPeriod;
unsigned long copy_delayPeriod;
volatile unsigned long delayPeriodStart;
float delayDegrees; // changed from int to float for decimal place display
int RPM;
int pickup;
int pulseWidth;
volatile boolean interruptFlag;
unsigned long analogReadInterval = 500; // read pots and map
unsigned long lastAnalogRead;
const byte setChargePulseSwitch = 6;
boolean chargePulse = false ;  // default dc powered mode
volatile byte timeSliceCount = 0; // TDC 0 degrees

void setup() {
// Serial.begin(115200);
// Serial.println("starting...");
  lcd.begin(20, 4); // initialize the lcd for 20 chars 4 lines, turn on backlight
  lcd.setCursor(1, 0); // lcd display setup of unchanging headings
  lcd.print("RPM:"); // print fixed characters
  lcd.setCursor(12, 0);
  lcd.print("Deg");
  lcd.setCursor(1, 1);
  lcd.print("Pos:");
  lcd.setCursor(1, 2);
  lcd.print("Us Delay:");
  lcd.setCursor(1, 3);
  lcd.print("Deg Advance:");

  pinMode(outputPin, OUTPUT); // declare the outputPin as an OUTPUT
  pinMode(output2Pin, OUTPUT);
  pinMode(chargePin, OUTPUT); // declare the chargePin as an OUTPUT
  pinMode(setChargePulseSwitch, INPUT_PULLUP);

  if (digitalRead(setChargePulseSwitch) == LOW)
    chargePulse = true; // AC CDI

 // Timer1 default set up .5ms trigger pulse every 50 ms
  TCCR1A = (1<< WGM11);//Fast PWM to ICR1
  TCCR1B = (1 << WGM13) | (1 << WGM12);
  //TCCR1B = (1 << WGM12); // CTC mode to OCR1A
  TCCR1B = (1 << WGM13) | (1 << WGM12);//CTC mode to ICR1
  //OCR1A = timerTopValue;
  ICR1 = timerTopValue;
  TIMSK1 |= (1 << OCIE1A); // interrupt enable compareA
  TIMSK1 |= (1 << OCIE1B); // interrupt enable compareB
  TIMSK1 |= (1<< TOIE1);//overflow interrupt at top
  OCR1B = 250; // sets trigger pulse width, 500 = 2Ms, 250 = 1Ms, 125 = .5Ms, set to 1250 for 5013 *********************************************
  OCR1A = OCR1B +500;//add default
  TCCR1B |= (1 << CS11) | (1 << CS10); // prescaler 64 4us/tick

// Timer2 default setup charge pulse 36 periods 10 degrees each; only 5 get turned on
// charge pulse timing interval = Timer1 trigger period/12 = timerTopValue/96
  TCCR2A = 0;
  TCCR2B = 0;
  TCCR2A = 1 << WGM20; // lsb of mode 7 pwm to OCR2A
  TCCR2B = 1 << WGM22; // msb of mode 7 pwm to OCR2A;
  //OCR2A = timerTopValue / 96; // 96 = 12*4*2 (#periods, prescaler difference, up/down timer mode )
  OCR2A = timerTopValue / 288; //  = 36*4*2 (#periods, prescaler difference, up/down timer mode )
  TIMSK2 = 0;
  TIMSK2 = 1 << TOIE2; // enable overflow interrupt
// actually start timer in ISR(TIMER1_COMPA_vect
// to prevent out of sync charge pulse, no prescaler set here

  attachInterrupt(digitalPinToInterrupt(3), delayPeriodTiming, FALLING);

}

void loop()
{
  unsigned long analogReadInterval = 500; // read pots and map
  if (millis() - lastAnalogRead >= analogReadInterval)
  {
    lastAnalogRead += analogReadInterval;
    potValue = analogRead(pot1); // rpm
    pickupValue = analogRead(pot2); // pickup position

    if (digitalRead(setChargePulseSwitch) == LOW)
    chargePulse = true; // AC CDI
    else chargePulse = false;
   
// Timer2 OCR2A requires max value 255 => 615 lowest RPM
// if (chargePulse)
    {
      RPM = map(potValue, 0, 1023, 615, 10000);
      pickup = map(pickupValue, 0, 1023, 10, 75); // position so advance will read based on delay, 57 for yamaha 350 2 pu, 74 for 1 pu, 72 for tw200, 25 for 5013
      pulseWidth = (60000000/RPM)/360; // time for 1° in uS
    }

    timerTopValue = 15000000UL / RPM;
    OCR1B = pulseWidth;
    OCR1A = OCR1B + pulseWidth;

    lcd.setCursor(6, 0);
    lcd.print("     "); // print blank spaces to clear old data
    lcd.setCursor(6, 0);
    lcd.print(RPM);  // print rpm

    lcd.setCursor(16, 0);
    lcd.print("  ");
    lcd.setCursor(16, 0);
    lcd.print(pulseWidth, 1); // print us per degree
   
    lcd.setCursor(6, 1);
    lcd.print("   ");
    lcd.setCursor(6, 1);
    lcd.print(pickup); // print pickup coil position

    lcd.setCursor(11, 2);
    lcd.print("       ");
    lcd.setCursor(11, 2);
    lcd.print(copy_delayPeriod);
   
    lcd.setCursor(14, 3);
    lcd.print("      ");
    lcd.setCursor(14, 3);
    lcd.print(delayDegrees, 1);   // delayDegrees, 1);
  }
 
  if (trigger == true && interruptFlag == true )
  {
    trigger = false;
    interruptFlag = false;
    noInterrupts();
    copy_delayPeriod = delayPeriod;
    interrupts();

    delayDegrees = pickup - (360.0 * (copy_delayPeriod) / (timerTopValue * 4.0)); // for decimal place in deg display.
    }
}

//ISR(TIMER1_COMPA_vect) {
ISR(TIMER1_OVF_vect){
  //OCR1A = (timerTopValue); // value to set delay between pulses to trigger cdi
  ICR1 = (timerTopValue);
  digitalWrite(chargePin, LOW); // guarantee off charge pin at trigger
  digitalWrite(outputPin, HIGH); // turn on pin  trigger

  {
    delayPeriodStart = micros(); // start looking for response as pulse rises
    trigger = true;
  }
// start Timer 2 for charge pulses
  if (chargePulse)
  {
    timeSliceCount = 0;
    TCNT2 = 0;
    //OCR2A = timerTopValue/96; // set 12 periods
    OCR2A = timerTopValue/288;//set 36 periods
    TCCR2B |=  1 << CS22 | 1 << CS21; //prescaleer 256 16us/tick
  }
}

ISR(TIMER1_COMPB_vect) {
  digitalWrite(outputPin, LOW);
  //could add short delayMiocroseconds here for gap
  digitalWrite(output2Pin,HIGH);

  //{
  //  delayPeriodStart = micros(); // start looking for response as pulse falls
  //  trigger = true;
  //}
}

ISR(TIMER1_COMPA_vect) {
  digitalWrite(output2Pin, LOW);
}

void delayPeriodTiming()
{
  delayPeriod = micros() - delayPeriodStart;
  interruptFlag = true;
}

ISR(TIMER2_OVF_vect)
// 5 pulses of 10 degrees starting at 60 degrees
// ON at 60,120,180,240,300 = slice count 6,12,18,24,30
// OFF at 70,130,190,250,310
{
  if (timeSliceCount != 0 && timeSliceCount % 6 == 0)
  {
    digitalWrite (chargePin, HIGH);
  }
  else
  {
    digitalWrite(chargePin, LOW);
  }
  timeSliceCount++;

  if (timeSliceCount == 36)
  {
    timeSliceCount = 0;
// stop Timer2 by clearing prescaler bits
    TCCR2B &= ~1<< CS22;
    TCCR2B &= ~1<< CS21;
  }
}
Title: Re: CDI tester project
Post by: tom_bauer on May 11, 2019, 04:01 pm
Hi, OK the good news this worked fine. Bad news is the transformer responded worse to this width pulse!
So what I have is about the best that I can get.
Again many thanks, Tom
Title: Re: CDI tester project
Post by: cattledog on May 11, 2019, 05:33 pm
Quote
Hi, OK the good news this worked fine. Bad news is the transformer responded worse to this width pulse!
Too bad. This project has had many instances where the hardware does not respond well to the software.

Can you explain to me (perhaps again), what is the purpose of the two trigger pulse output?
What two things are being triggered by the outputs, and how do they combine for generate the actual trigger to the cdi module? Is this like the bar width separation between the two pulses we worked with earlier?
Title: Re: CDI tester project
Post by: tom_bauer on May 11, 2019, 07:25 pm
Hi, yes it has been a rocky road at times. At first there was just 1 pulse for 1 revolution to trigger the spark. Then an engineer friend of mine suggested the DAC to make that pulse available in pos and neg polarity, making it more like the actual real life pulse. But the circuit that the DAC controlled, the one that actually supplied the pos and neg, could not provide enough power. That is where we had the 2 trigger pulses, for the DAC. So I went back to the single pulse for the trigger pulse. This is fed to a small audio transformer so as the pulse rises it makes a magnetic field that outputs voltage from the secondary of the transformer. As the pulse stops the field collapses and makes the opposite polarity output.

What you just wrote for me is for the 5 pulses per revolution that simulates the high voltage exciter coil in a bikes magneto. These charge pulses are switched by a large transistor and apply 12 to 30 volts to another transformer which outputs 75 to 200 volts to charge the capacitor in the CDI. It must be recharged every revolution. The pulse was 30° wide and I wondered if the transformer would perform better with a narrower pulse, it was worse.
Happy to explain more if you like, thanks, Tom
Title: Re: CDI tester project
Post by: cattledog on May 11, 2019, 10:15 pm
Quote
That is where we had the 2 trigger pulses, for the DAC. So I went back to the single pulse for the trigger pulse.
Yes I understand that. What I am curious about is the two trigger outputs on the two different pins, one right after another. Not the positive and negative pulse to the DAC.

Quote
But the circuit that the DAC controlled, the one that actually supplied the pos and neg, could not provide enough power.
Is it worth redesigning that circuit to provide enough power?
Title: Re: CDI tester project
Post by: tom_bauer on May 12, 2019, 01:10 am
Hi, OK those 2 trigger outputs were an experiment to drive a transformer in both polarities. With a center tapped winding, power applied to that tap and 2 transistors alternately grounding the 2 sides of the winding to create AC on the secondary. It worked but left a large spike on the secondary after the second pulse.
In reflection, for the testing I do I only need just a neg or pos signal alone. Some of the CDIs I build and test use just 1 pickup that produces pos and neg. If I only give them one polarity, only that part of the circuit responds so it does test only that circuit. The other polarity acts the same way with another part of the CDI.
Tom