Go Down

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

cattledog

#255
Apr 23, 2019, 01:27 am Last Edit: Apr 23, 2019, 01:28 am by cattledog
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);
}


tom_bauer

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

cattledog

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.

tom_bauer

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.

cattledog

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;

}

 


tom_bauer

#260
Apr 24, 2019, 12:35 am Last Edit: Apr 24, 2019, 12:46 am by tom_bauer
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

cattledog

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.

tom_bauer

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

cattledog

#263
Apr 30, 2019, 12:41 am Last Edit: Apr 30, 2019, 12:42 am by cattledog
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?

tom_bauer

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

cattledog

#265
Apr 30, 2019, 01:18 am Last Edit: Apr 30, 2019, 01:20 am by cattledog
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?

cattledog

#266
Apr 30, 2019, 02:04 am Last Edit: Apr 30, 2019, 02:06 am by cattledog
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;
  }
}

tom_bauer

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

cattledog

#268
Apr 30, 2019, 10:06 pm Last Edit: Apr 30, 2019, 11:35 pm by cattledog
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);

tom_bauer

#269
Apr 30, 2019, 10:36 pm Last Edit: May 01, 2019, 01:54 am by tom_bauer
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

Go Up