Go Down

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

tombauer

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.

cattledog

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

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?

tombauer

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.

tombauer

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.

cattledog

#124
Oct 21, 2016, 12:47 am Last Edit: Oct 21, 2016, 12:54 am by cattledog
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.

tombauer

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.

tombauer

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.

cattledog

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/


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.

tombauer

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.

cattledog

#129
Oct 21, 2016, 05:21 am Last Edit: Oct 21, 2016, 05:26 am by cattledog
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.

tombauer

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

tombauer

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

cattledog

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;
}



tombauer

Well the code looks good to me but will not compile?? says error compiling for board arduino pro or pro mini

cattledog

#134
Oct 22, 2016, 02:17 am Last Edit: Oct 22, 2016, 02:21 am by cattledog
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?

Go Up