Ignition Control with AVR

Discussion in 'The Projects Forum' started by ratlifflj, Jan 30, 2009.

  1. ratlifflj

    Thread Starter Member

    Nov 4, 2008
    11
    0
    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
     
  2. hgmjr

    Moderator

    Jan 28, 2005
    9,030
    214
    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
     
  3. hgmjr

    Moderator

    Jan 28, 2005
    9,030
    214
    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
     
  4. ratlifflj

    Thread Starter Member

    Nov 4, 2008
    11
    0
    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.
     
  5. ratlifflj

    Thread Starter Member

    Nov 4, 2008
    11
    0
    files. I am using C.
     
  6. hgmjr

    Moderator

    Jan 28, 2005
    9,030
    214
    Code ( (Unknown Language)):
    1. //***********************************************************************
    2. /* **********************************************************************
    3. *
    4. *
    5. * - File              : main.c
    6. * - Compiler          : GCC
    7. *
    8. * - Support mail    
    9. *
    10. * - Devices     : ATMega128
    11. *
    12. * - Description       : Pulse Width Demodulation to drive Ignition Spark...
    13. *      Adapted from the AVR135 application note
    14. *  
    15. * Revision: 09/11/2008
    16. *****************************************************************************/
    17. /*
    18. * Description:
    19. * icp.c contains functions for use of the demodulator.
    20. * main.c contains a simple program to demonstrate the demodulator operation. It
    21. * generates a PWM signal on OC2, then samples the demodulator output using calls
    22. * to icp_rx() and writes the values obtained to PORTC.
    23. * Approximately twice per second, OCR2 is incremented such that the PWM duty cycle
    24. * steps through the entire [0:256) range.
    25. * The intended use is on the STK500/STK501, with a 10-wire jumper connecting the
    26. * PORTC header with the LEDs header and a single-wire jumper connecting PB7 (OC2)
    27. * with PD4 (ICP1).
    28. * The expected result is that the LED display cycles repeatedly from 0x00 to 0xFF.
    29. */
    30. //ucontroller defintion:  
    31. #define __AVR_ATmega128__ 1
    32. //include files:              /* sei */
    33. #include "icp.h"
    34. //Defines:
    35. #define F_CPU = 8200000UL
    36. #define SEI() sei()
    37. #define CLI() cli()
    38. #define SLEEP() __asm__ __volatile__ ("sleep \r\n" :: )
    39. #define OUT_PORT        PORTF
    40. #define OUT_DDR         DDRF
    41.  
    42.  
    43.  
    44. // Function prototypes
    45. void init_adc(void);                  
    46. void oversampled(void);
    47. void hb_init(void);
    48. //void pwm_init(void);
    49. void ig_init(void);
    50.  
    51. void timer3_init(void);
    52. void timer3_reint(void);
    53. void timer3_off(void);
    54. void invert_input_init(void);
    55. //void reset_led(void);
    56.  
    57. // Global variables
    58. double  accumulator       = 0;  //!< Accumulated 10-bit samples
    59. double  Vin               = 0;  //!< 16-bit float number result
    60. short   temp              = 0;  //!< Temporary variable
    61. short   samples           = 0;  //!< Number of conversions
    62. int  ADC_count, number;
    63. int  count = 0;
    64. //static uint8_t ledon = 0;
    65. unsigned char hb_count;               /* counts [0:4] to make the test visible */
    66. int repetitions = 0, f = 0;
    67. //int fire_coil_1 = 0, fire_coil_2=0;
    68. int flag = 0;
    69. int bin_flag1 =1;
    70. int timer_flag =1;
    71. int m,c_index=4;
    72. int coil[3];
    73. int ind=0;
    74. int r = 0;
    75. int d = 0;
    76. int s_delta[6];
    77. int run_1_done = 0;
    78. int bin_flag = 1;
    79. int norm_op = 1;
    80. int t_index[3];
    81. int d_old = 0, d_older=0,d_oldest=0,d_older_still=0;
    82. int d_current = 0;
    83. //int coil_t3 = 5;
    84. int second_run =0;
    85. int icp_init_flag = 0;
    86. icp_timer_t c_btdc=0,c_d=0, cnt1=0;
    87. int flagg=0;
    88. int j = 0, k = 0;
    89. int distance = 0;
    90. int delay_time;
    91. int delta_right = 0;
    92. int init_flag_delta = 0;
    93. //Initialize and Define External Variables (psuedo-global):
    94. extern int k, tooth_index, delay_time, t_i;
    95. extern icp_timer_t glob_delay;
    96. extern int pre_t_ind, t_count, delta_left;
    97. extern int store_period[6], store_delta[6], tooth_pre_index;
    98. extern long sec_deg, sum_period;
    99. //-----------------------------------------------------------------------------
    100.  
    101. // main()
    102. int main(void)
    103. {
    104.  DDRF = 0x00;
    105.  PORTF = 0x00;
    106.  DDRE = 0xFF;  
    107.                     // PORTC for LED debug
    108.  //LED_DEBUG_PORT = 0x00;              /* initially off */
    109.  LED_DEBUG_DDR = 0xFF;              /* all output */
    110.   PORTA = 0xFF;                /* display port A is set to initially off*/
    111.   DDRA = 0xFF;                /* all output */
    112.     OUT_DDR       = 0xFF;              /* all output */
    113.  OUT_PORT = 0x00;               /*initially off*/
    114.  SEI();
    115.  MCUCR |= (1 << SE);               /* enable (idle mode) sleep */
    116.  // Init subsystems                 /* main.c */
    117.  icp_init();                 /* icp.c */                 /* main.c */
    118. // invert_input_init();
    119. // init_adc();
    120. //    cam_count_init();
    121. // delta_timer3_init();
    122.  //set up array with coil output addresses
    123.  m = 4;
    124.  coil[0]=4;
    125.  coil[1]=5;
    126.  coil[2]=6;
    127.  t_index[0]=0;
    128.  t_index[1]=2;
    129.  t_index[2]=4;
    130.  
    131.  //begin infinite loop
    132.  for (;;)                 /* Loop Forever */
    133.  {                 /* Fetch the latest reading and display it on the LEDs. */
    134.   //if(icp_init_flag == 0){
    135.   // if(TCNT2 == 1){
    136.   //  icp_init();
    137.   //  icp_init_flag = 1;
    138.   // }
    139.   //}
    140.   // start of ADC conversion for degrees BTDC
    141. //  sbi(ADCSRA,ADSC);             //Start a conversion by writing 1 to the ADSC bit (6)
    142. //  while (ADCSRA & 0b01000000);           //wait for conversion to complete
    143. //  ADC_count = ((ADCL)| ((ADCH)<<8));         //10 bit conversion for channel 0 (PF0)
    144. //  display_7seg(glob_delta);        /*Display values for testing, not needed for actual operation */
    145.   SLEEP();              
    146.  }
    147.  
    148.  return(0);
    149. }
    150. //--------------------------------------------------------------------------------------
    151. //Subroutines:                  
    152. void delta_timer3_init(void){
    153.  TCCR3B = (1<<CS30)|(0<<CS31)|(1<<CS32);
    154.  TCNT3 = 0;
    155. }
    156. void cam_count_init(void){
    157.  TCCR2 = (1<<CS22)| (1<<CS21) | (0<<CS20)|(0<<WGM21); //makes external clock on T2, ie counts up
    158.                // on CS20= 0 is falling edge of cam in
    159.                // CS20 = 1 is rising edge
    160.  OCR2 = 5;
    161.  TIMSK |= (1<<OCIE2);
    162.  TCCR3B = (1<<CS30)|(0<<CS31)|(1<<CS32);
    163.  TCNT3 = 0;
    164. // delta_timer3_init();
    165. }
    166. SIGNAL(SIG_OUTPUT_COMPARE2){      //when OCR2 reaches 5 and interrupt is generated and comes here
    167.  
    168.  j = ind*2;
    169.  if (j == 0){
    170.   d=4;
    171.  }
    172.  else if( j == 1){
    173.   d = 5;
    174.  }
    175.  else{
    176.   d=j-2;
    177.  }
    178.  if (j == 0){
    179.   k=5;
    180.  }
    181.  else{
    182.   k=j-1;
    183.  }
    184.  if(tooth_index==5){
    185.   m=0;
    186.  }
    187.  else{
    188.   m=tooth_index+1;
    189.  }
    190.  delta_right = TCNT3;
    191. // TCCR3B = (1<<CS30)|(0<<CS31)|(1<<CS32);
    192.  TCNT3 = 0;
    193.  d_older_still=d_oldest;
    194.  d_oldest=d_older;
    195.  d_older = d_old;
    196.  d_old = d_current;
    197.  d_current = delta_right-delta_left;
    198.  s_delta[r] = delta_right-delta_left;
    199.  r++;
    200.  if (r == 6){
    201.   init_flag_delta = 1;
    202.    r = 0;
    203.  }
    204. // if(init_flag_delta == 0){
    205.   distance = store_period[k]-store_delta[tooth_index]+store_period[j]-(store_period[j]-store_delta[m])/2;
    206. // }
    207. // else{
    208.  // distance = store_period[k]-s_delta[k]+store_period[j]-(store_period[j]-s_delta[j])/2;
    209.  // distance = store_period[k]-d_older+store_period[j]-(store_period[j]-d_current)/2;
    210. // }  
    211. // delay_time = d_current;
    212.  delay_time = (distance - (sec_deg+14400))/128;
    213. // delay_time = 2;
    214. // delay_time=s_delta[5]/4;
    215.  timer0_init();
    216. // if(flagg==0){
    217. //  sbi(LED_DEBUG_PORT,4);
    218. //  }
    219. // if(flagg==1){
    220. //  cbi(LED_DEBUG_PORT,4);
    221. //  }
    222. // flagg^=1;
    223.  OCR2= 1;
    224.  TCNT2 = 0;
    225.  ind++;
    226.  if ( ind == 3 ) ind = 0;
    227.  
    228. }
    229. void timer0_reint(void){
    230.  TCCR0=(1<<CS00)|(1<<CS01)|(1<<CS02)|(0<<COM00)|(0<<COM01);    //1024 prescale
    231.  TCNT0=0;
    232.  OCR0 = 112;               // conducting duration
    233.  TIMSK |= (1<<OCIE0);
    234.  }
    235. void timer0_off(void){
    236.  TCCR0=(0<<CS00)|(0<<CS01)|(0<<CS02)|(0<<COM00)|(0<<COM01);
    237.  TCNT0=0;
    238.  OCR0 = 0;
    239.  TIMSK |= (0<<OCIE0);
    240.  }
    241. void timer0_init(void){
    242.  TCCR0=(1<<CS00)|(1<<CS01)|(1<<CS02)|(0<<COM00)|(0<<COM01);      //1024 prescale
    243.  OCR0 = delay_time;
    244. // OCR0 = 25;
    245. // sbi(LED_DEBUG_PORT,c_index);
    246.  TIMSK |= (1<<OCIE0);
    247.  }
    248. SIGNAL(SIG_OUTPUT_COMPARE0){
    249.  if(bin_flag == 0){
    250.   cbi(LED_DEBUG_PORT,c_index);
    251.   timer0_off();
    252.   TCCR0=(0<<CS00)|(0<<CS01)|(0<<CS02)|(0<<COM00)|(0<<COM01);
    253.   TIMSK |= (0<<OCIE0);
    254.   c_index++;
    255.   if (c_index==7) c_index =4;  
    256.  }
    257.  if (bin_flag == 1){
    258.   sbi(LED_DEBUG_PORT,c_index);
    259.   timer0_reint();
    260.  }
    261.  
    262.  bin_flag ^= 1;
    263. }
    264.  
    265. //adc inititialization
    266. void init_adc(void)              /*Initialize ADC*/
    267. {
    268.    ADCSRA |= (BV(ADEN));            
    269.  ADCSRA &= ~(BV(ADFR));             //single sample conversion by clearing bit 5 (ADFR)
    270.  ADCSRA = ((ADCSRA & 0b11111000)|0b00000110);       //selects div by 64 clock prescaler                      
    271.    ADMUX = ((ADMUX & 0b00111111)|0b01000000);       //selects AVCC as Vref
    272.  cbi(ADMUX,ADLAR);             //selects right adjust
    273.  ADMUX &= 0b11100000;            //selects single ended conversion of PF0                                
    274. }
    275.  
    276.  
    277.  
    278.  
    Here is your main.c routine.
     
    Last edited: Feb 3, 2009
  7. ratlifflj

    Thread Starter Member

    Nov 4, 2008
    11
    0
    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.
     
  8. ratlifflj

    Thread Starter Member

    Nov 4, 2008
    11
    0
    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.
     
  9. hgmjr

    Moderator

    Jan 28, 2005
    9,030
    214
    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
     
  10. hgmjr

    Moderator

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

    hgmjr
     
  11. ratlifflj

    Thread Starter Member

    Nov 4, 2008
    11
    0
    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.
     
  12. hgmjr

    Moderator

    Jan 28, 2005
    9,030
    214
    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
     
  13. ratlifflj

    Thread Starter Member

    Nov 4, 2008
    11
    0
    thanks for you help!
     
Loading...