Got to take a quick look today, transistor for pulse out had failed and was passing the inverted signal from its driver. It is a 4403 and is rated for 600 ma continuous collector current so I don't know why it failed. Still expecting some Honda CDI with retard in soon so can have real time info on delay reading.
Tom
Hi, I have progressed to a new set of testing where it needs a simple form of a sine wave. A DAC will suffice but I need simple control from the Arduino to do this such as D1=1 D2=0 => zero volt,
D1=1 D2=1 => +12volt, D1=0 D2=0 => -12volt. So I need to use 2 output pins rather than 1. The width of the output should stay the same.
// last change 7/22/18
// 8/17 added code for pulse out width
// 7/14/2017 added correct math and setting for position of pickup
// 10 10/28/2016 adds charging pulse with Timer 2
// lowest RPM = 615 with charge pulse to keep OCR2A <= 255
// CDI Tester Pulse Generator Serial Output Arduino Code
int pot1 = A3; // select the input pin for the pot for rpm
int pot2 = A4; // select the input pin for the pot for pickup location in degrees
int pot3 = A5; // select the input pin for the pot for width of bar on flywheel in degrees
int potValue = 0; // variable to store the value coming from the sensor
int pickupValue = 0; // position of pickup in degrees
int potWidth = 0; // variable to set width of bar on flywheel
int timerTopValue = 12500; // changed from timerTopValue = 0
int outputPin = 4; // select the pin for the output for trigger pulse, changed from 8
int chargePin = 7; // select the pin for the output for charge pulses
volatile boolean trigger = false;
volatile unsigned long delayPeriod;
unsigned long copy_delayPeriod;
volatile unsigned long delayPeriodStart;
float delayDegrees; // changed from int to float for decimal place display
int RPM;
int pickup;
int barWidth;
int pulseWidth;
volatile boolean interruptFlag;
unsigned long analogReadInterval = 250; //read pots and map
unsigned long lastAnalogRead;
const byte setFallingSwitch = 5;
char risefall = 'R'; //default rising mode
const byte setChargePulseSwitch = 6;
boolean chargePulse = false ; //default dc powered mode
volatile byte timeSliceCount = 0; //TDC 0 degrees
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
// set the LCD address to 0x3f for a 20 chars 4 line display
// Set the pins on the I2C chip used for LCD connections:
// addr, en,rw,rs,d4,d5,d6,d7,bl,blpol
LiquidCrystal_I2C lcd(0x3f, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); // Set the LCD I2C address
void setup() {
//Serial.begin(115200);
//Serial.println("starting...");
lcd.begin(20, 4); // initialize the lcd for 20 chars 4 lines, turn on backlight
lcd.setCursor(1, 0); // lcd display setup of unchanging headings
lcd.print("RPM:"); // print fixed characters
lcd.setCursor(12, 0);
lcd.print("Mode:"); //to display code choice R or F
lcd.setCursor(1, 1);
lcd.print("Pos:");
lcd.setCursor(9, 1);
lcd.print("Width:");
lcd.setCursor(1, 2);
lcd.print("Us Delay:");
lcd.setCursor(1, 3);
lcd.print("Deg Advance:");
pinMode(outputPin, OUTPUT); // declare the outputPin as an OUTPUT
pinMode(chargePin, OUTPUT); // declare the chargePin as an OUTPUT
pinMode (setFallingSwitch, INPUT_PULLUP); //check for a LOW input to indicate switch is closed to ground
pinMode(setChargePulseSwitch, INPUT_PULLUP);
if (digitalRead(setChargePulseSwitch) == LOW)
chargePulse = true; //AC CDI
//Timer1 default set up .5ms trigger pulse every 50 ms
TCCR1A = 0;
TCCR1B = (1 << WGM12); //CTC mode to OCR1A
OCR1A = timerTopValue;
TIMSK1 |= (1 << OCIE1A); //interrupt enable compareA
TIMSK1 |= (1 << OCIE1B); //interrupt enable compareB
OCR1B = 125; //sets trigger pulse width, 500 = 2Ms, 250 = 1Ms, 125 = .5Ms, set to 1250 for 5013 cdi ***************
TCCR1B |= (1 << CS11) | (1 << CS10); //prescaler 64 4us/tick
//Timer2 default setup charge pulse 12 periods 30 degrees each; only 5 get turned on
//charge pulse timing interval = Timer1 trigger period/12 = timerTopValue/96
TCCR2A = 0;
TCCR2B = 0;
TCCR2A = 1 << WGM20; //lsb of mode 7 pwm to OCR2A
TCCR2B = 1 << WGM22; //msb of mode 7 pwm to OCR2A;
OCR2A = timerTopValue / 96; //96 = 12*4*2 (#periods, prescaler difference, up/down timer mode )
TIMSK2 = 0;
TIMSK2 = 1 << TOIE2; //enable overflow interrupt
// actually start timer in ISR(TIMER1_COMPA_vect
// to prevent out of sync charge pulse, no prescaler set here
attachInterrupt(digitalPinToInterrupt(3), delayPeriodTiming, FALLING);
}
void loop()
{
if (millis() - lastAnalogRead >= analogReadInterval)
{
lastAnalogRead += analogReadInterval;
potValue = analogRead(pot1); //rpm
pickupValue = analogRead(pot2); // pickup position
barWidth = analogRead(pot3);
//Timer2 OCR2A requires max value 255 => 615 lowest RPM
if (chargePulse)
{
RPM = map(potValue, 0, 1023, 615, 10000); //this section needs 2 pots added to set pickup and pulseWidth **************************
pickup = 74; //map(pickupValue, 0, 1023, 0, 65); so advance will read based on delay,52 for yamaha 350 2 pu, 74 for 1 pu, 72 for tw200, 25 for 5013
pulseWidth = (60000000/RPM)/360; //time for 1° in uS
barWidth = 60; //barWidth = pulseWidth + 1000; //10 for yamaha 350 2 pu, 60 for 1 pu, 60 for tw200
//RPM = 615; //for my serial test purposes 615-3800
}
else
{
RPM = map(potValue, 0, 1023, 500, 3800);
pickup = 25; //map(pickupValue, 0, 1023, 0, 50); //to set position of pickup so advance will read
pulseWidth = map(potWidth, 0, 1023, 271, 44); //add Width to non charging case
// RPM = 500;//for my serial test purposes 500-3800
}
timerTopValue = 15000000UL / RPM;
OCR1B = pulseWidth;
if (digitalRead(setFallingSwitch) == LOW) //set Falling
{
risefall = 'F';
}
else
{
risefall = 'R';
}
lcd.setCursor(6, 0);
lcd.print(" "); // print blank spaces to clear old data
lcd.setCursor(6, 0);
lcd.print(RPM);
lcd.setCursor(18, 0);
lcd.print(" ");
lcd.setCursor(18, 0);
lcd.print(risefall); //print R or F at upper right side
lcd.setCursor(6, 1);
lcd.print(" ");
lcd.setCursor(6, 1);
lcd.print(pickup);
lcd.setCursor(16, 1);
lcd.print(" ");
lcd.setCursor(16, 1);
lcd.print(pulseWidth);
lcd.setCursor(11, 2);
lcd.print(" ");
lcd.setCursor(11, 2);
lcd.print(copy_delayPeriod);
lcd.setCursor(14, 3);
lcd.print(" ");
lcd.setCursor(14, 3);
lcd.print(delayDegrees, 1); //delayDegrees, 1);
}
if (trigger == true && interruptFlag == true )
{
trigger = false;
interruptFlag = false;
noInterrupts();
copy_delayPeriod = delayPeriod;
interrupts();
delayDegrees = pickup - (360.0 * (copy_delayPeriod) / (timerTopValue * 4.0)); //for decimal place in deg display.
}
}
ISR(TIMER1_COMPA_vect) {
OCR1A = (timerTopValue); // value to set delay between pulses to trigger cdi
digitalWrite(chargePin, LOW); //guarantee off charge pin at trigger
digitalWrite(outputPin, HIGH); //turn on pin trigger
if (risefall == 'R') //switch not set; default Rising trigger
{
delayPeriodStart = micros(); //start looking for response as pulse rises
trigger = true;
}
//start Timer 2 for charge pulses
if (chargePulse)
{
timeSliceCount = 0;
TCNT2 = 0;
OCR2A = timerTopValue/96; //set 12 periods
TCCR2B |= 1 << CS22 | 1 << CS21; //prescaleer 256 16us/tick
}
}
ISR(TIMER1_COMPB_vect) {
digitalWrite(outputPin, LOW);
if (risefall == 'F') //switch set for Falling trigger
{
delayPeriodStart = micros(); //start looking for response as pulse falls
trigger = true;
}
}
void delayPeriodTiming()
{
delayPeriod = micros() - delayPeriodStart;
interruptFlag = true;
}
ISR(TIMER2_OVF_vect)
//5 pulses of 30 degrees starting at 60 degrees
//ON at 60,120,180,240,300 = 2,4,6,8,10
//OFF at 90,150,210,270,330 = 3,5,7,9,11
{
if (timeSliceCount != 0 && timeSliceCount % 2 == 0)
{
digitalWrite (chargePin, HIGH);
}
else //if (timeSliceCount == 0 || timeSliceCount % 2 == 1)
{
digitalWrite(chargePin, LOW);
}
timeSliceCount++;
if (timeSliceCount == 12)
{
timeSliceCount = 0;
//stop Timer2 by clearing prescaler bits
TCCR2B &= ~1<< CS22;
TCCR2B &= ~1<< CS21;
}
}
Hi Tom.
It's nice to hear that you are still in business with the CDI tester. I need to take a day to reacquaint myself with the project. While I'm doing that, can you explain a bit more about what you are doing with the AC output. Is this related to the ignition pulse, the charging pulse, or is a a new third output?
Any wiring diagrams and more information about what you are trying to do will be of help. How will you be working the DAC?
Are you needing to add two switches which will be read to determine the output? Like the mode switch and charging switch set a program path take?
Any wiring diagrams and more information about what you are trying to do will be of help.
I think to use 2 output pins on Arduino, call them D1 and D2. DAC will have 12+ and 12- supply voltage. This is only for the ignition pulse. The pulse width should change with rpm, I think I remember it does that now, and the time between the 2 pulses should change in relation to barWidth.
when all input pins of DAC get a 1 (+5v) the DAC output +12v (if powered by +12)
when all input pins of DAC get a 0 (gnd) the DAC output -12v (if powered by -12)
when pin5 of DAC get a 1 and others got a 0 the DAC output 0v
Then 2 pins of arduino are enough to get pos and neg square pulses and zero volt.
Say you connect D1 to pin 5 and D2 to pins 6,7,8,9,10,11,12 together
Thanks, Tom
I think I understand.
You want a new ignition pulse, on two pins to replace the current single output on pin 4.
It looks like we now get an output pulse on pin 4 of some length and some repeating frequency determined by the RPM setting. It sound like you want to change this to an output on two pins.
The pulse width should change with rpm, I think I remember it does that now, and the time between the 2 pulses should change in relation to barWidth.
when all input pins of DAC get a 1 (+5v) the DAC output +12v (if powered by +12)
when all input pins of DAC get a 0 (gnd) the DAC output -12v (if powered by -12)
when pin5 of DAC get a 1 and others got a 0 the DAC output 0v
What I'm unclear of is how the two outputs to the DAC are timed. Is a +/- varying signal sent from the DAC to the module each cycle. Can you draw a timing diagram of how the 11 00 10 output states are sent to the DAC? Are they all sent in sequence during one output timing cycle?
It would help me if you could draw a timing diagram of the desired output pulses.
Can you explain about "barWidth". This variable does not appear in the previous code we worked on. What is it, and how does it relate to the timing of the 2 pulses.
In this new mode of output to the DAC, will the the return pulse from the module and the reading on the pin 2 interrupt be unchanged?
Will the charge pulse code be unchanged?
It's been awhile
cattledog:
I think I understand.You want a new ignition pulse, on two pins to replace the current single output on pin 4.
Yes
It looks like we now get an output pulse on pin 4 of some length and some repeating frequency determined by the RPM setting. It sound like you want to change this to an output on two pins.
The length of the existing pulse is determined by barWidth I think. So the 2 new pulse array must replace >that in such a way that it tells the DAC to output a pos pulse and then after a time determined by barWidth >output a neg pulse, then no pulse until it repeats. i have to determine what the pulse width should be.
What I'm unclear of is how the two outputs to the DAC are timed. Is a +/- varying signal sent from the DAC to the module each cycle. Can you draw a timing diagram of how the 11 00 10 output states are sent to the DAC? Are they all sent in sequence during one output timing cycle?
In this simplest control of the DAC it has 3 states of output, 0 volt, pos volt, neg volt.
It would help me if you could draw a timing diagram of the desired output pulses.
attached is something that may help. MSB is DAC pin 5 and all others are 6 thru 12 tied together.
Can you explain about "barWidth". This variable does not appear in the previous code we worked on. What is it, and how does it relate to the timing of the 2 pulses.
It is the width of the bar that passes past the pickup coil. Some engines it is just a short bar and only >serves to make a short pulse where they are only interested in the positive component of the signal. These >generally have two pickup coils and two short bars. In this case I am only interested in one of the positive >pulses so I set the barWidth to small value. Other times the bar can be 60° long and the negative pulse is >at the beginning and then the positive is at the end of bar which has just one pickup coil. For this I set the >barWidth to a higher value, usually the bar length in degrees plus the base timing so 74 is a normal setting.
In this new mode of output to the DAC, will the the return pulse from the module and the reading on the pin 2 interrupt be unchanged?
I think the answer is yes.
Will the charge pulse code be unchanged?
Yes
It's been awhile
Yes for me also, I tend to forget a lot of what I have learned doing this!!
Maybe this also helps, I ask a friend with a similar interest and he said.
How wide should the on time of each pulse I send to the DAC be?
The answer is: "it depend !"
For having Zero volt , DAC need 10 (MSB pin at 1 , others at 0)
Leave MSB pin at 1 , others at 0 as long as you want a 0volt, about 350degres (so most of the time)
The time MSB is 1 and other are 1 too to produce a +12v is up to you.
If you want a 1ms pickup, then those 2 pins must not move during 1ms
Personally , I decided that ONE pulse last 10degree so the code is :
-
send 10 to produce 0volt
-
for positive pickup: send 11 to produce +12v
-
wait (PERIOD/360) * 10 (PERIOD is in ms)
-
send 10 to produce 0volt
-wait 'barWidth' millisecond you want
-send 00 to produce -12v
-wait (PERIOD/360) * 10 (PERIOD is in ms)
- send 10 to produce 0volt
That's it , then wait for the next rotation
Do I use 'barWidth' for beginning of pulse to end of the other, or between the 2 pulses.
between the 2 pulses
OK, I think I have it. I'll express things in degrees, and the event timing will be changed by RPM.
First, you will need a switch to set the AC trigger mode. This will be similar to the RISE/FALL switch and the CHARGEPULSE mode switch. Do you have this switch installed already?
Personally , I decided that ONE pulse last 10degree
In the AC Trigger mode you want the + and - pulses each to be 10 degrees long, separated by 60 degrees. We can make those values adjustable by a pot, but these sound like default starting values. I think you already have a pot 3 for bar width.
Other times the bar can be 60° long and the negative pulse is >at the beginning and then the positive is at the end of bar
You have also described and drawn the pulse train as starting with a positive 12 volts. i.e. +12v for 10 degrees, 0v for bar width(60) degrees, -12v for 10 degrees, 0v for remainder of the timing cycle.
What pulse do you want to lead with?
You will need to determine where you want the return pulse delay measurement to start. At present the RISE/FALL switch controls whether delay timing starts with the rise of the trigger or the fall of the trigger. With the AC trigger and the bar width, you will need to establish the the start of timing for the return.
I'm pretty sure you have a scope to measure output pulses. I think I will try to write a simple piece of test code at 1200 rpm (50 ms cycle timing). 50/360 = .139 milliseconds/degree or 140 microseconds/degree to use a nice round number. Let me know if you want to lead with 00 (-12v) or 11(+12v) and I will try to write some code which outputs the pulse train.
Do you have arduino pin numbers you want me to use for D1 and D2?
Hi, I can easily install a switch for AC trigger but I am not clear on it's purpose.
The pulse length can be hard coded as long as I can change it in the code easily, I assume I would be able to. Once set it would likely never be changed. The pot to change barWidth is all that is needed here and I have that along with the readout on display.
It would be nice to have the polarity of the output switchable and I think I can do that by swapping pins 2 & 4 on the DAC. So just + first should be OK.
To answer the last question I need to understand what you refer to as AC trigger.
Thanks, Tom
Hi, I can easily install a switch for AC trigger but I am not clear on it's purpose.
How will the program know to run the dual trigger pulse instead of the standard single pulse trigger for the cdi module?
To answer the last question I need to understand what you refer to as AC trigger.
I am referring to the two +/- voltage pulses as an AC trigger for the cdi module. If you have other terminology like "bipolar trigger" or anything else you like, let me know. I focus on the word trigger, because the pulses are used to trigger the delayed response from the module and we have used the word trigger in the existing code to refer to the outgoing pulse from the arduino.
Oh OK, I see what you think. No this as you say AC trigger, completely replaces the old single trigger.
Before I had the single trigger go to a very small transformer so as the trigger turns on it energizes the transformer and makes a output pulse, then it stays on for period of time and when it turns off the collapse of field in transformer also makes a opposite pulse. Crude but it works, now I just wanted to improve the system. Also I can code the Arduino to drive more bits of the DAC to make a better sine wave.
By the way I have a Hantek DSO5072P. I love it. Before I had a Tektronic 585A, 50 years old now and still works.
Tom
The output pins can be 4 and 5. I see that it may be necessary to have a switch to tell Arduino to do - or + first, no electronic way to easily swap them.
Tom
Here's some code to test to see if we have the output pulses correct. Please check that I have the correct output to the DAC pins for the +/- 12 and 0 voltage. I have tried to keep nomenclature similar to the original code. To get the two pulses, I have changed the timer mode from what we had, and broke the 360 degree cycle into two unequal pieces, each containing one pulse. Output compare interrupt B always turns off the pulses. I tested with an led indicator and a slower rpm and timer prescaler, but have left these adaptations commented in the code. Throw a scope on this and tell me what you get. Ask any questions for clarification.
//You can use pots to set RPM, pulseWidthDegrees, and barWidth
unsigned int RPM = 1200;
//unsigned int RPM = 400;
unsigned int pulseWidthDegrees = 10;
unsigned int barWidthDegrees = 60;
unsigned long pulseWidthTime;
unsigned long timerTopValue;//sets 360 degree cycleTime
unsigned int timerTicksPerDegree;
const byte pinA = 4; //to DAC pins tied together
const byte pinB = 5; //to pin5 DAC
void setup() {
pinMode(13, OUTPUT); //telltale led
pinMode(pinA, OUTPUT);
pinMode(pinB, OUTPUT);
//initialize timer
TCCR1A = 0;
TCCR1B = 0;
//set Timer1 mode Fast PWM to ICR1
TCCR1B |= (1 << WGM13) | (1 << WGM12);
TCCR1A |= (1 << WGM11);
timerTopValue = 15000000UL / RPM;
//15000000 timerTicksperMinute at 4 us per tick with prescaler 64
//timerTopValue = 12500 at 1200 RPM 50ms per revolution
timerTicksPerDegree = timerTopValue/360;
ICR1 = timerTopValue;//initial placeholder
pulseWidthTime = pulseWidthDegrees*timerTicksPerDegree;
OCR1B = pulseWidthTime;
//start Timer apply prescaler
//TCCR1B |= (1 << CS12) | (1 << CS10); //1024 for led test
TCCR1B |= (1<<CS11) | (1<<CS10);//64 for .5 us tick
//enable B OutputCompare and Overflow interrupts
TIMSK1 |= (1 << OCIE1B) | (1 << TOIE1);
}
void loop() {
}
ISR(TIMER1_COMPB_vect) {
digitalWrite(13, LOW); //turn off pulse
digitalWrite(pinA, LOW); //tied pins LOW
digitalWrite(pinB, HIGH); //DAC5 HIGH
}
ISR(TIMER1_OVF_vect) {
//alternate ICR1 values to generate two outputs
//360 degree cycle time broken into two pieces
static byte count = 0;
if (count == 0)
{
ICR1 = timerTicksPerDegree*(pulseWidthDegrees+barWidthDegrees); //first pulse and bar width
digitalWrite(13, HIGH);
//positive pulse
digitalWrite(pinA, HIGH);
digitalWrite(pinB, HIGH);
}
if (count == 1)
{
ICR1 = timerTicksPerDegree*(360-(pulseWidthDegrees+barWidthDegrees));//second pulse and dead band
digitalWrite(13, HIGH);
//negative pulse
digitalWrite(pinA, LOW);
digitalWrite(pinB, LOW);
}
count++;
if (count == 2)
count = 0;
}
OK, I have some parts on order and need to wire it up so it may be a few days. Thanks, I will keep in touch.
Tom
Can you scope the output from the Arduino and confirm that it is what you want before connecting to all the other hardware down stream? I'd like to try and separate any software issues from subsequent hardware issues.
OK I will look at it soon but I am tied up with other work til mid week
Tom
I think that's what we wanted.
Before I had the single trigger go to a very small transformer so as the trigger turns on it energizes the transformer and makes a output pulse, then it stays on for period of time and when it turns off the collapse of field in transformer also makes a opposite pulse.
Where to want to start timing the return pulse. How have you been using the R and F settings?
I think there are 4 places we can time from Start and Finish of the tied pins(yellow trace/PinA) going High and back to Low, or the Start and Finish of the single pin to DAC5(blue trace/PinB) going Low and then back to High.
I hope I have the pin and color designations correct. I think we should change the nomenclature from pinA and pinB to something else. dacTiedPins and dacPin5 works to clarify things for me. Do you ahve something else to call then which makes better sense to you?
const byte dacTiedPins = 4; //to DAC pins tied together
const byte dacPin5 = 5; //to pin5 DAC