CDI tester project

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.

#include 
#include 
#include  // 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? :confused:

Let me know if this appears to be headed in the right direction.

//V1.0 set RPM potentiometer/configuration swtiches/hd44780 lcd/revised pin numbers

#include 
#include 
#include  // 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;
}

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?

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
    }

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

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.

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

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

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.

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.

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

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

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

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.

Yes, 184's code with 20 x 4 lcd. I will explore the settings and display in morning. Thanks, Tom

I've got a 20x4 on order, and should be able to work in your format when it arrives.

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

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.

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

//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.

/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.

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

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

//V1.0 set RPM potentiometer/configuration swtiches/hd44780 lcd/revised pin numbers

#include 
#include 
#include  // 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;
}

Nice progress getting the code back to the 20x4 display.

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().

if (millis() - lastAnalogRead >= analogReadInterval)
  {
      //all the pot/switch reading to change settings and display them code
   }

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.

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.

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.

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?

'Add the function setupSwitchPresets() into this section of loop(). The pinMode() calls in the function should be moved into setup().

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

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]

'Add the function setupSwitchPresets() into this section of loop(). The pinMode() calls in the function should be moved into setup().

This I do not really understand..??

//V1.0 set RPM potentiometer/configuration swtiches/hd44780 lcd/revised pin numbers

#include 
#include 
#include  // 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;
}

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?