Go Down

### Topic: CDI tester project (Read 14331 times)previous topic - next topic

#### cattledog

#270
##### 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.

#### tom_bauer

#271
##### May 01, 2019, 04:37 amLast Edit: May 01, 2019, 04:54 am by tom_bauer
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

#### cattledog

#272
##### 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?

#### tom_bauer

#273
##### 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

#### cattledog

#274
##### 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.

#### tom_bauer

#275
##### 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

#### cattledog

#276
##### 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.

#### tom_bauer

#277
##### 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

#### tom_bauer

#278
##### 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

#### cattledog

#279
##### 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.

#### tom_bauer

#280
##### 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 headerhd44780_I2Cexp lcd; // declare lcd object: auto locate & config display for hd44780 chipint pot1 = A1; // select the input pin for the pot for rpmint pot2 = A2; // select the input pin for the pot for pickup location in degreesint potValue = 0; // variable to store the value coming from the sensorint pickupValue = 0; // position of pickup in degreesint timerTopValue = 12500; // changed from timerTopValue = 0int outputPin = 4; // select the pin for the output for trigger pulse, changed from 8int output2Pin = 5; int chargePin = 7; // select the pin for the output for charge pulsesvolatile 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 displayint RPM;int pickup;int pulseWidth;volatile boolean interruptFlag;unsigned long analogReadInterval = 500; // read pots and mapunsigned long lastAnalogRead;const byte setChargePulseSwitch = 6;boolean chargePulse = false ;  // default dc powered modevolatile byte timeSliceCount = 0; // TDC 0 degreesvoid 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;  }}`

#### cattledog

#281
##### May 11, 2019, 01:33 amLast Edit: May 11, 2019, 01:34 am by cattledog
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 headerhd44780_I2Cexp lcd; // declare lcd object: auto locate & config display for hd44780 chipint pot1 = A1; // select the input pin for the pot for rpmint pot2 = A2; // select the input pin for the pot for pickup location in degreesint potValue = 0; // variable to store the value coming from the sensorint pickupValue = 0; // position of pickup in degreesint timerTopValue = 12500; // changed from timerTopValue = 0int outputPin = 4; // select the pin for the output for trigger pulse, changed from 8int output2Pin = 5; int chargePin = 7; // select the pin for the output for charge pulsesvolatile 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 displayint RPM;int pickup;int pulseWidth;volatile boolean interruptFlag;unsigned long analogReadInterval = 500; // read pots and mapunsigned long lastAnalogRead;const byte setChargePulseSwitch = 6;boolean chargePulse = false ;  // default dc powered modevolatile byte timeSliceCount = 0; // TDC 0 degreesvoid 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;  }}`

#### tom_bauer

#282
##### 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

#### cattledog

#283
##### 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?

#### tom_bauer

#284
##### 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

Go Up