# Ignition Control with AVR

#### ratlifflj

Joined Nov 4, 2008
11
Hi,
I am using an atmega128 for developing an ignition system for a 3/4 cylinder engine (needs to be usable for both).
I have things working great at a fixed rpm. Even if I change rpm all I need to do is reset and pulses for ignition fire correctly.
The problem is that I cant reset. I need this to work during transient times as well as at a fixed rpm. If it cant then it will not work on start up, etc.
I am using ICP on timer 1 to catch the "long tooth" portion of the signal from the cam sensor. I developed an external board to convert the cam signal (Hall effect sensor) to a digital pulse. The long tooth indicates cylinder #1. Once I have detected this I start timer 2 which counts the pulses from the cam sensor digital signal on the falling edge starting with the long tooth as 0. And I turn off the ICP sense switching (initially it comes in on both the rising and falling edges in order to calculate pulse width). The reason I turn off the ICP is that I was having interrupt conflicts as T2 counts on the falling edge as well. after I start T2, it counts up on falling edge and ICP catches the rising edge so we have no conflicts. But because I am doing this I have no way to calculate the pulse width and the delay time calculation for time to fire before top dead center is dependent on this. Thus, I have the issue of not being able to operate when the rpm is changing. I can provide more detail which I think will be necessary if someone thinks they can help.
Any thoughts or ideas will help immensely as I am really stuck.
Thanks

#### hgmjr

Joined Jan 28, 2005
9,029
Post your schematic and your code and we can have a look to see what can be changed to alter the behavior. Are you using Assembly or C-language coding?

hgmjr

#### hgmjr

Joined Jan 28, 2005
9,029
All we can do is guess at what lies at the heart of your problem if you are not willing to provide us with more details (i.e. code, schematic, flowchart).

If you need any assistance with how to attach a file to a post then you can refer to the FAQ Help section. You can find the link at the top of this forum page in the tool bar.

If you have questions about the attachment process that are not answered in the FAQ section then feel free to post them here.

hgmjr

#### ratlifflj

Joined Nov 4, 2008
11
I havent been at my computer until just now. so I havent had time to respond.
but as I said in the original post I am willing to provide whatever information necessary if there are suggestions. I am attaching my code and here is the board I am using:
http://www.futurlec.com/ATMEGA_Controller.shtml
the digital input from the cam sensor goes into both Timer2 as an external clock and ICP of timer 1.
excuse the code as it is a work in progress...
thanks for any help.

#### ratlifflj

Joined Nov 4, 2008
11
files. I am using C.

#### hgmjr

Joined Jan 28, 2005
9,029
Rich (BB code):
//***********************************************************************
/* **********************************************************************
*
*
* - File              : main.c
* - Compiler          : GCC
*
* - Support mail
*
* - Devices     : ATMega128
*
* - Description       : Pulse Width Demodulation to drive Ignition Spark...
*      Adapted from the AVR135 application note
*
* Revision: 09/11/2008
*****************************************************************************/
/*
* Description:
* icp.c contains functions for use of the demodulator.
* main.c contains a simple program to demonstrate the demodulator operation. It
* generates a PWM signal on OC2, then samples the demodulator output using calls
* to icp_rx() and writes the values obtained to PORTC.
* Approximately twice per second, OCR2 is incremented such that the PWM duty cycle
* steps through the entire [0:256) range.
* The intended use is on the STK500/STK501, with a 10-wire jumper connecting the
* PORTC header with the LEDs header and a single-wire jumper connecting PB7 (OC2)
* with PD4 (ICP1).
* The expected result is that the LED display cycles repeatedly from 0x00 to 0xFF.
*/
//ucontroller defintion:
#define __AVR_ATmega128__ 1
//include files:              /* sei */
#include "icp.h"
//Defines:
#define F_CPU = 8200000UL
#define SEI() sei()
#define CLI() cli()
#define SLEEP() __asm__ __volatile__ ("sleep \r\n" :: )
#define OUT_PORT        PORTF
#define OUT_DDR         DDRF

// Function prototypes
void oversampled(void);
void hb_init(void);
//void pwm_init(void);
void ig_init(void);

void timer3_init(void);
void timer3_reint(void);
void timer3_off(void);
void invert_input_init(void);
//void reset_led(void);

// Global variables
double  accumulator       = 0;  //!< Accumulated 10-bit samples
double  Vin               = 0;  //!< 16-bit float number result
short   temp              = 0;  //!< Temporary variable
short   samples           = 0;  //!< Number of conversions
int  count = 0;
//static uint8_t ledon = 0;
unsigned char hb_count;               /* counts [0:4] to make the test visible */
int repetitions = 0, f = 0;
//int fire_coil_1 = 0, fire_coil_2=0;
int flag = 0;
int bin_flag1 =1;
int timer_flag =1;
int m,c_index=4;
int coil[3];
int ind=0;
int r = 0;
int d = 0;
int s_delta[6];
int run_1_done = 0;
int bin_flag = 1;
int norm_op = 1;
int t_index[3];
int d_old = 0, d_older=0,d_oldest=0,d_older_still=0;
int d_current = 0;
//int coil_t3 = 5;
int second_run =0;
int icp_init_flag = 0;
icp_timer_t c_btdc=0,c_d=0, cnt1=0;
int flagg=0;
int j = 0, k = 0;
int distance = 0;
int delay_time;
int delta_right = 0;
int init_flag_delta = 0;
//Initialize and Define External Variables (psuedo-global):
extern int k, tooth_index, delay_time, t_i;
extern icp_timer_t glob_delay;
extern int pre_t_ind, t_count, delta_left;
extern int store_period[6], store_delta[6], tooth_pre_index;
extern long sec_deg, sum_period;
//-----------------------------------------------------------------------------

// main()
int main(void)
{
DDRF = 0x00;
PORTF = 0x00;
DDRE = 0xFF;
// PORTC for LED debug
//LED_DEBUG_PORT = 0x00;              /* initially off */
LED_DEBUG_DDR = 0xFF;              /* all output */
PORTA = 0xFF;                /* display port A is set to initially off*/
DDRA = 0xFF;                /* all output */
OUT_DDR       = 0xFF;              /* all output */
OUT_PORT = 0x00;               /*initially off*/
SEI();
MCUCR |= (1 << SE);               /* enable (idle mode) sleep */
// Init subsystems                 /* main.c */
icp_init();                 /* icp.c */                 /* main.c */
// invert_input_init();
//    cam_count_init();
// delta_timer3_init();
//set up array with coil output addresses
m = 4;
coil[0]=4;
coil[1]=5;
coil[2]=6;
t_index[0]=0;
t_index[1]=2;
t_index[2]=4;

//begin infinite loop
for (;;)                 /* Loop Forever */
{                 /* Fetch the latest reading and display it on the LEDs. */
//if(icp_init_flag == 0){
// if(TCNT2 == 1){
//  icp_init();
//  icp_init_flag = 1;
// }
//}
// start of ADC conversion for degrees BTDC
//  sbi(ADCSRA,ADSC);             //Start a conversion by writing 1 to the ADSC bit (6)
//  while (ADCSRA & 0b01000000);           //wait for conversion to complete
//  ADC_count = ((ADCL)| ((ADCH)<<8));         //10 bit conversion for channel 0 (PF0)
//  display_7seg(glob_delta);        /*Display values for testing, not needed for actual operation */
SLEEP();
}

return(0);
}
//--------------------------------------------------------------------------------------
//Subroutines:
void delta_timer3_init(void){
TCCR3B = (1<<CS30)|(0<<CS31)|(1<<CS32);
TCNT3 = 0;
}
void cam_count_init(void){
TCCR2 = (1<<CS22)| (1<<CS21) | (0<<CS20)|(0<<WGM21); //makes external clock on T2, ie counts up
// on CS20= 0 is falling edge of cam in
// CS20 = 1 is rising edge
OCR2 = 5;
TIMSK |= (1<<OCIE2);
TCCR3B = (1<<CS30)|(0<<CS31)|(1<<CS32);
TCNT3 = 0;
// delta_timer3_init();
}
SIGNAL(SIG_OUTPUT_COMPARE2){      //when OCR2 reaches 5 and interrupt is generated and comes here

j = ind*2;
if (j == 0){
d=4;
}
else if( j == 1){
d = 5;
}
else{
d=j-2;
}
if (j == 0){
k=5;
}
else{
k=j-1;
}
if(tooth_index==5){
m=0;
}
else{
m=tooth_index+1;
}
delta_right = TCNT3;
// TCCR3B = (1<<CS30)|(0<<CS31)|(1<<CS32);
TCNT3 = 0;
d_older_still=d_oldest;
d_oldest=d_older;
d_older = d_old;
d_old = d_current;
d_current = delta_right-delta_left;
s_delta[r] = delta_right-delta_left;
r++;
if (r == 6){
init_flag_delta = 1;
r = 0;
}
// if(init_flag_delta == 0){
distance = store_period[k]-store_delta[tooth_index]+store_period[j]-(store_period[j]-store_delta[m])/2;
// }
// else{
// distance = store_period[k]-s_delta[k]+store_period[j]-(store_period[j]-s_delta[j])/2;
// distance = store_period[k]-d_older+store_period[j]-(store_period[j]-d_current)/2;
// }
// delay_time = d_current;
delay_time = (distance - (sec_deg+14400))/128;
// delay_time = 2;
// delay_time=s_delta[5]/4;
timer0_init();
// if(flagg==0){
//  sbi(LED_DEBUG_PORT,4);
//  }
// if(flagg==1){
//  cbi(LED_DEBUG_PORT,4);
//  }
// flagg^=1;
OCR2= 1;
TCNT2 = 0;
ind++;
if ( ind == 3 ) ind = 0;

}
void timer0_reint(void){
TCCR0=(1<<CS00)|(1<<CS01)|(1<<CS02)|(0<<COM00)|(0<<COM01);    //1024 prescale
TCNT0=0;
OCR0 = 112;               // conducting duration
TIMSK |= (1<<OCIE0);
}
void timer0_off(void){
TCCR0=(0<<CS00)|(0<<CS01)|(0<<CS02)|(0<<COM00)|(0<<COM01);
TCNT0=0;
OCR0 = 0;
TIMSK |= (0<<OCIE0);
}
void timer0_init(void){
TCCR0=(1<<CS00)|(1<<CS01)|(1<<CS02)|(0<<COM00)|(0<<COM01);      //1024 prescale
OCR0 = delay_time;
// OCR0 = 25;
// sbi(LED_DEBUG_PORT,c_index);
TIMSK |= (1<<OCIE0);
}
SIGNAL(SIG_OUTPUT_COMPARE0){
if(bin_flag == 0){
cbi(LED_DEBUG_PORT,c_index);
timer0_off();
TCCR0=(0<<CS00)|(0<<CS01)|(0<<CS02)|(0<<COM00)|(0<<COM01);
TIMSK |= (0<<OCIE0);
c_index++;
if (c_index==7) c_index =4;
}
if (bin_flag == 1){
sbi(LED_DEBUG_PORT,c_index);
timer0_reint();
}

bin_flag ^= 1;
}

{
ADCSRA &= ~(BV(ADFR));             //single sample conversion by clearing bit 5 (ADFR)
ADCSRA = ((ADCSRA & 0b11111000)|0b00000110);       //selects div by 64 clock prescaler
ADMUX = ((ADMUX & 0b00111111)|0b01000000);       //selects AVCC as Vref
ADMUX &= 0b11100000;            //selects single ended conversion of PF0
}
Here is your main.c routine.

Last edited:

#### ratlifflj

Joined Nov 4, 2008
11
as you will see in my code commented out is the use of Timer 3 to calculate pulse width without the use of the ICP. When I do this on an engine stand everything works smoothly. But when I do it on an actual unit (engine running a heat pump) I have some random skipping. The signal for the ignition shifts randomly. If I reset everything returns to normal and then begins to shift again. I am running in parallel with another ignition module in order to do testing and only one of them controls actual ignition process. I am also using a VFD for controlling the blower motor. I think that this could be causing noise as well as the way the unit is grounded. My purpose of posting my code and problem is to have someone else look at the code to see if I am missing something in the code. Since you cannot see my project in detail analysis of the code would be ideal. Sometimes fresh eyes on a project helps to offer insight.

#### ratlifflj

Joined Nov 4, 2008
11
I am also trying to add in the use of an external interrupt to calculate pulse width as external interrupts can be asynchronous and this may allow me to continuously calculate the pulse width even during the transient periods.
I havent tested this but it is what I am doing now.

#### hgmjr

Joined Jan 28, 2005
9,029
Of course it will take a bit to digest the overall code to get a sense of what is what.

Let me see what I can do. Is there any urgency to complete the project that I should know about?

hgmjr

#### hgmjr

Joined Jan 28, 2005
9,029
You mentioned that you had designed an external interface board. Can you post a schematic of the board?

hgmjr

#### ratlifflj

Joined Nov 4, 2008
11
No urgency for project.
The board just uses a LM311 and a 2n3904 (logic inverter circuit) to create a digital pulse from the cam sensor signal. The pulse is 0-5V and has varying pulse width and period. it repeats every 6 pulses. I can provide a circuit if you want. I will have to prepare one. its a simple circuit. the lm311 is just is a low power comparator since the cam sensor signal cannot stand high impedance and the lm 311 just inverts the signal.

#### hgmjr

Joined Jan 28, 2005
9,029
It sounds simple enough that it need not be provided at this time. If I see any need for it I will make a request here.

hgmjr