Beispiel #1
0
/** Special function for processing falling edge,
 * must be called from ISR
 * \param tmr Timer value at the moment of falling edge
 */
INLINE
void ProcessFallingEdge(uint16_t tmr)
{
 //save period value if it is correct. We need to do it forst of all to have fresh stroke_period value
 if (CHECKBIT(flags, F_VHTPER))
 {
  //calculate stroke period
  hall.stroke_period = tmr - hall.measure_start_value;
  WRITEBIT(flags, F_SPSIGN, tmr < hall.measure_start_value); //save sign
  hall.t1oc_s = hall.t1oc, hall.t1oc = 0; //save value and reset counter
 }
 SETBIT(flags, F_VHTPER);
 SETBIT(flags, F_STROKE); //set the stroke-synchronization event (устанавливаем событие тактовой синхронизации)
 hall.measure_start_value = tmr;

 if (!CHECKBIT(flags2, F_SHUTTER_S))
 {
  uint16_t delay;
#ifdef STROBOSCOPE
  hall.strobe = 1; //strobe!
#endif

  //-----------------------------------------------------
  //Software PWM is very sensitive even to small delays. So, we need to allow OCF2 and TOV2
  //interrupts occur during processing of this handler.
#ifdef COOLINGFAN_PWM
  _ENABLE_INTERRUPT();
#endif
  //-----------------------------------------------------

  //start timer for counting out of advance angle (spark)
  delay = (((uint32_t)hall.advance_angle * hall.stroke_period) / hall.degrees_per_stroke);
#ifdef COOLINGFAN_PWM
  _DISABLE_INTERRUPT();
#endif

  OCR1A = tmr + ((delay < 15) ? 15 : delay) - CALIBRATION_DELAY; //set compare channel, additionally prevent spark missing when advance angle is near to 60°
  TIFR1 = _BV(OCF1A);
  TIMSK1|= _BV(OCIE1A);

  //start timer for countiong out of knock window opening
  if (CHECKBIT(flags, F_USEKNK))
  {
#ifdef COOLINGFAN_PWM
   _ENABLE_INTERRUPT();
#endif
   delay = ((uint32_t)hall.knock_wnd_begin * hall.stroke_period) / hall.degrees_per_stroke;
#ifdef COOLINGFAN_PWM
   _DISABLE_INTERRUPT();
#endif
   set_timer0(delay);
   hall.knkwnd_mode = 0;
  }

  knock_start_settings_latching();//start the process of downloading the settings into the HIP9011 (запускаем процесс загрузки настроек в HIP)
  adc_begin_measure(_AB(hall.stroke_period, 1) < 4);//start the process of measuring analog input values (запуск процесса измерения значений аналоговых входов)
 }
}
Beispiel #2
0
void gdstpmot_run(uint16_t steps)
{
 if (steps)
 {
  _DISABLE_INTERRUPT();
  gdsm_steps_cnt = 0;
  _ENABLE_INTERRUPT();
 }
 _DISABLE_INTERRUPT();
  gdsm_steps = steps;
  gdsm_latch = 1;
 _ENABLE_INTERRUPT();
}
Beispiel #3
0
void stpmot_run(uint16_t steps)
{
 _DISABLE_INTERRUPT();
  sm_steps = steps;
  sm_latch = 1;
 _ENABLE_INTERRUPT();
}
Beispiel #4
0
uint16_t gdstpmot_stpcnt(void)
{
 uint16_t count;
 _DISABLE_INTERRUPT();
 count = gdsm_steps_cnt;
 _ENABLE_INTERRUPT();
 return count;
}
Beispiel #5
0
uint8_t eeprom_take_completed_opcode(void)
{
 uint8_t result;
 _DISABLE_INTERRUPT();
 result = eewd.completed_opcode;
 eewd.completed_opcode = 0;
 _ENABLE_INTERRUPT();
 return result;
}
Beispiel #6
0
uint8_t stpmot_is_busy(void)
{
 uint16_t current;
 uint8_t latching;
 _DISABLE_INTERRUPT();
 current = sm_steps_b;
 latching = sm_latch;
 _ENABLE_INTERRUPT();
 return (current > 0 || latching); //busy?
}
Beispiel #7
0
void ckps_set_cyl_number(uint8_t i_cyl_number)
{
 uint16_t degrees_per_stroke;
 uint8_t _t;
 _t = _SAVE_INTERRUPT();
 _DISABLE_INTERRUPT();
 hall.chan_number = i_cyl_number; //set new value
 _RESTORE_INTERRUPT(_t);

 hall.frq_calc_dividend = FRQ_CALC_DIVIDEND(i_cyl_number);

 //precalculate value of degrees per 1 engine stroke (value * ANGLE_MULTIPLIER)
 degrees_per_stroke = (720 * ANGLE_MULTIPLIER) / i_cyl_number;

 _t = _SAVE_INTERRUPT();
 _DISABLE_INTERRUPT();
 hall.io_callback = IOCFG_CB(IOP_IGN_OUT1); //use single output
 hall.degrees_per_stroke = degrees_per_stroke;
 _RESTORE_INTERRUPT(_t);
}
Beispiel #8
0
void bc_indication_mode(struct ecudata_t *d)
{
 uint8_t i = 5;
 if (!IOCFG_CHECK(IOP_BC_INPUT))
  return; //normal program execution

 //Check 5 times
 do
 {
  if (IOCFG_GET(IOP_BC_INPUT))
   return; //normal program execution
 }while(--i);

 //We are entered to the blink codes indication mode
 _DISABLE_INTERRUPT();
 ce_set_state(CE_STATE_OFF);

 vent_turnoff(d);                //turn off ventilator
 starter_set_blocking_state(1);  //block starter
 IOCFG_INIT(IOP_FL_PUMP, 0);     //turn off fuel pump
 IOCFG_INIT(IOP_IE, 0);          //turn off IE valve solenoid
 IOCFG_INIT(IOP_FE, 0);          //turn off power valve solenoid

 wdt_reset_timer();

 //delay 2 sec.
 delay_hom(20);

 //main loop
 for(;;)
 {
  uint16_t errors = 0;
  disp_start();

  delay_hom(7);

  //read errors
  eeprom_read(&errors, EEPROM_ECUERRORS_START, sizeof(uint16_t));

  for(i = 0; i < 16; ++i)
  {
   if (0 == PGM_GET_BYTE(&blink_codes[i]))
    continue;
   if (errors & (1 << i))
   {
    disp_code(PGM_GET_BYTE(&blink_codes[i]));
    delay_hom(20);
   }
  }

  delay_hom(20);
  wdt_reset_timer();
 }
}
Beispiel #9
0
//Instantaneous frequency calculation of crankshaft rotation from the measured period between the engine strokes
//(for example for 4-cylinder, 4-stroke it is 180°)
//Period measured in the discretes of timer (one discrete = 4us), one minute = 60 seconds, one second has 1,000,000 us.
//Высчитывание мгновенной частоты вращения коленвала по измеренному периоду между тактами двигателя
//(например для 4-цилиндрового, 4-х тактного это 180 градусов)
//Период в дискретах таймера (одна дискрета = 4мкс), в одной минуте 60 сек, в одной секунде 1000000 мкс.
uint16_t ckps_calculate_instant_freq(void)
{
 uint16_t period; uint8_t ovfcnt, sign;
 //ensure atomic acces to variable (обеспечиваем атомарный доступ к переменной)
 _DISABLE_INTERRUPT();
 period = hall.stroke_period;        //stroke period
 ovfcnt = hall.t1oc_s;               //number of timer overflows
 sign = CHECKBIT(flags, F_SPSIGN);   //sign of stroke period
 _ENABLE_INTERRUPT();

 //We know period and number of timer overflows, so we can calculate correct value of RPM even if RPM is very low
 if (sign && ovfcnt > 0)
  return hall.frq_calc_dividend / ((((int32_t)ovfcnt) * 65536) - (65536-period));
 else
  return hall.frq_calc_dividend / ((((int32_t)ovfcnt) * 65536) + period);
}
Beispiel #10
0
void eeprom_read(void* sram_dest, uint16_t eeaddr, uint16_t size)
{
 uint8_t _t;
 uint8_t *dest = (uint8_t*)sram_dest;
 do
 {
  _t=_SAVE_INTERRUPT();
  _DISABLE_INTERRUPT();
  __EEGET(*dest,eeaddr);
  _RESTORE_INTERRUPT(_t);

  eeaddr++;
  dest++;
 }while(--size);

 EEAR=0x000; //this will help to prevent corruption of EEPROM
}
Beispiel #11
0
uint8_t knock_module_initialize(void)
{
 uint8_t i, response;
 uint8_t init_data[2] = {KSP_SET_PRESCALER | KSP_PRESCALER_VALUE | KSP_SO_TERMINAL_ACTIVE,
                         KSP_SET_CHANNEL | KSP_CHANNEL_0};
 uint8_t _t;

 _t=_SAVE_INTERRUPT();
 _DISABLE_INTERRUPT();

 //Setting HOLD mode for integrator and "Run" mode for chip at all.
 SET_KSP_TEST(1);
 SET_KSP_INTHOLD(KNOCK_INTMODE_HOLD);
 SET_KSP_CS(1);

 spi_master_init();
 ksp.ksp_interrupt_state = 0; //init state machine
 ksp.ksp_error = 0;

 //set prescaler first
 SET_KSP_CS(0);
 spi_master_transmit(init_data[0]);
 SET_KSP_CS(1);

 //Setting SO terminal active and perform initialization. For each parameter perform
 //checking for response and correcntess of received data.
 for(i = 0; i < 2; ++i)
 {
  SET_KSP_CS(0);
  spi_master_transmit(init_data[i]);
  SET_KSP_CS(1);
  response = SPDR;
  if (response!=init_data[i])
  {
   _RESTORE_INTERRUPT(_t);
   return 0; //error - chip doesn't respond!
  }
 }

 _RESTORE_INTERRUPT(_t);
 //Initialization completed successfully
 return 1;
}
Beispiel #12
0
void eeprom_write(const void* sram_src, uint16_t eeaddr, uint16_t size)
{
 uint8_t _t;
 uint8_t *src = (uint8_t*)sram_src;
 do
 {
  _t=_SAVE_INTERRUPT();
  _DISABLE_INTERRUPT();
  __EEPUT(eeaddr, *src);
  _RESTORE_INTERRUPT(_t);

  wdt_reset_timer();

  eeaddr++;
  src++;
 }while(--size);

 EEAR=0x000; //this will help to prevent corruption of EEPROM
}
Beispiel #13
0
void eeprom_write_P(void _PGM *pgm_src, uint16_t eeaddr, uint16_t size)
{
 uint8_t _t;
 uint8_t _PGM *src = (uint8_t _PGM*)pgm_src;
 do
 {
  uint8_t byte = PGM_GET_BYTE(src);
  _t=_SAVE_INTERRUPT();
  _DISABLE_INTERRUPT();
  __EEPUT(eeaddr, byte);
  _RESTORE_INTERRUPT(_t);

  wdt_reset_timer();

  eeaddr++;
  src++;
 }while(--size);

 EEAR=0x000; //this will help to prevent corruption of EEPROM
}
Beispiel #14
0
/**Main function of firmware - entry point */
MAIN()
{
 int16_t calc_adv_ang = 0; 
 uint8_t turnout_low_priority_errors_counter = 255;
 int16_t advance_angle_inhibitor_state = 0;
 retard_state_t retard_state;

 //подготовка структуры данных переменных состояния системы
 init_ecu_data(&edat);
 knklogic_init(&retard_state);

 //конфигурируем порты ввода/вывода
 ckps_init_ports();
 vent_init_ports();
 fuelecon_init_ports();
 idlecon_init_ports();
 starter_init_ports();
 ce_init_ports();
 knock_init_ports();
 jumper_init_ports();

 //если код программы испорчен - зажигаем СЕ
 if (crc16f(0, CODE_SIZE)!=PGM_GET_WORD(&fw_data.code_crc))
  ce_set_error(ECUERROR_PROGRAM_CODE_BROKEN);

 //читаем параметры
 load_eeprom_params(&edat);

#ifdef REALTIME_TABLES
 //load currently selected tables into RAM
 load_selected_tables_into_ram(&edat);
#endif

 //предварительная инициализация параметров сигнального процессора детонации
 knock_set_band_pass(edat.param.knock_bpf_frequency);
 knock_set_gain(PGM_GET_BYTE(&fw_data.exdata.attenuator_table[0]));
 knock_set_int_time_constant(edat.param.knock_int_time_const);

 if (edat.param.knock_use_knock_channel)
  if (!knock_module_initialize())
  {//чип сигнального процессора детонации неисправен - зажигаем СЕ
   ce_set_error(ECUERROR_KSP_CHIP_FAILED);
  }
 edat.use_knock_channel_prev = edat.param.knock_use_knock_channel;

 adc_init();

 //проводим несколько циклов измерения датчиков для инициализации данных
 meas_initial_measure(&edat);

 //снимаем блокировку стартера
 starter_set_blocking_state(0);

 //инициализируем UART
 uart_init(edat.param.uart_divisor);

 //инициализируем модуль ДПКВ
 ckps_init_state();
 ckps_set_cyl_number(edat.param.ckps_engine_cyl);
 ckps_set_edge_type(edat.param.ckps_edge_type);
 ckps_set_cogs_btdc(edat.param.ckps_cogs_btdc); //<--only partial initialization
#ifndef COIL_REGULATION
 ckps_set_ignition_cogs(edat.param.ckps_ignit_cogs);
#endif
 ckps_set_knock_window(edat.param.knock_k_wnd_begin_angle,edat.param.knock_k_wnd_end_angle);
 ckps_use_knock_channel(edat.param.knock_use_knock_channel);
 ckps_set_cogs_btdc(edat.param.ckps_cogs_btdc); //<--now valid initialization
 ckps_set_merge_outs(edat.param.merge_ign_outs);

 s_timer_init();
 vent_init_state();

 //разрешаем глобально прерывания
 _ENABLE_INTERRUPT();

 sop_init_operations();
 //------------------------------------------------------------------------
 while(1)
 {
  if (ckps_is_cog_changed())
   s_timer_set(engine_rotation_timeout_counter,ENGINE_ROTATION_TIMEOUT_VALUE);

  if (s_timer_is_action(engine_rotation_timeout_counter))
  { //двигатель остановился (его обороты ниже критических)
#ifdef COIL_REGULATION
   ckps_init_ports();           //чтобы IGBT не зависли в открытом состоянии
   //TODO: Сделать мягкую отсечку для избавления от нежелательной искры. Как?
#endif
   ckps_init_state_variables();
   edat.engine_mode = EM_START; //режим пуска

   if (edat.param.knock_use_knock_channel)
    knock_start_settings_latching();

   edat.curr_angle = calc_adv_ang;
   meas_update_values_buffers(&edat, 1);  //<-- update RPM only
  }

  //запускаем измерения АЦП, через равные промежутки времени. При обнаружении каждого рабочего
  //цикла этот таймер переинициализируется. Таким образом, когда частота вращения двигателя превысит
  //определенную величину, это условие выполнятся перестанет.
  if (s_timer_is_action(force_measure_timeout_counter))
  {
   if (!edat.param.knock_use_knock_channel)
   {
    _DISABLE_INTERRUPT();
    adc_begin_measure();
    _ENABLE_INTERRUPT();
   }
   else
   {
    //если сейчас происходит загрузка настроек в HIP, то нужно дождаться ее завершения.
    while(!knock_is_latching_idle());
    _DISABLE_INTERRUPT();
    //включаем режим интегрирования и ждем около 20мкс, пока интегратор начнет интегрировать (напряжение
    //на его выходе упадет до минимума). В данном случае нет ничего страшного в том, что мы держим прерывания
    //запрещенными 20-25мкс, так как это проискодит на очень маленьких оборотах.
    knock_set_integration_mode(KNOCK_INTMODE_INT);
    _DELAY_CYCLES(350);
    knock_set_integration_mode(KNOCK_INTMODE_HOLD);
    adc_begin_measure_all(); //измеряем сигнал с ДД тоже
    _ENABLE_INTERRUPT();
   }

   s_timer_set(force_measure_timeout_counter, FORCE_MEASURE_TIMEOUT_VALUE);
   meas_update_values_buffers(&edat, 0);
  }

  //----------непрерывное выполнение-----------------------------------------
  //выполнение отложенных операций
  sop_execute_operations(&edat);
  //управление фиксированием и индицированием возникающих ошибок
  ce_check_engine(&edat, &ce_control_time_counter);
  //обработка приходящих/уходящих данных последовательного порта
  process_uart_interface(&edat);
  //управление сохранением настроек
  save_param_if_need(&edat);
  //расчет мгновенной частоты вращения коленвала
  edat.sens.inst_frq = ckps_calculate_instant_freq();
  //усреднение физических величин хранящихся в кольцевых буферах
  meas_average_measured_values(&edat);
  //cчитываем дискретные входы системы и переключаем тип топлива
  meas_take_discrete_inputs(&edat);
  //управление периферией
  control_engine_units(&edat);
  //КА состояний системы (диспетчер режимов - сердце основного цикла)
  calc_adv_ang = advance_angle_state_machine(&edat);
  //добавляем к УОЗ октан-коррекцию
  calc_adv_ang+=edat.param.angle_corr;
  //ограничиваем получившийся УОЗ установленными пределами
  restrict_value_to(&calc_adv_ang, edat.param.min_angle, edat.param.max_angle);
  //Если стоит режим нулевого УОЗ, то 0
  if (edat.param.zero_adv_ang)
   calc_adv_ang = 0;

#ifdef COIL_REGULATION
  //calculate and update coil regulation time
  ckps_set_acc_time(accumulation_time(&edat));
#endif
  //Если разрешено, то делаем отсечку зажигания при превышении определенных оборотов
  if (edat.param.ign_cutoff)
   ckps_enable_ignition(edat.sens.inst_frq < edat.param.ign_cutoff_thrd);
  else
   ckps_enable_ignition(1);  
  //------------------------------------------------------------------------

  //выполняем операции которые необходимо выполнять строго для каждого рабочего цикла.
  if (ckps_is_cycle_cutover_r())
  {
   meas_update_values_buffers(&edat, 0);
   s_timer_set(force_measure_timeout_counter, FORCE_MEASURE_TIMEOUT_VALUE);

   //Ограничиваем быстрые изменения УОЗ, он не может изменится больше чем на определенную величину
   //за один рабочий цикл. В режиме пуска фильтр УОЗ отключен.
   if (EM_START == edat.engine_mode)
    edat.curr_angle = advance_angle_inhibitor_state = calc_adv_ang;
   else
    edat.curr_angle = advance_angle_inhibitor(calc_adv_ang, &advance_angle_inhibitor_state, edat.param.angle_inc_spead, edat.param.angle_dec_spead);

   //----------------------------------------------
   if (edat.param.knock_use_knock_channel)
   {
    knklogic_detect(&edat, &retard_state);
    knklogic_retard(&edat, &retard_state);
   }
   else
    edat.knock_retard = 0;
   //----------------------------------------------

   //сохраняем УОЗ для реализации в ближайшем по времени цикле зажигания
   ckps_set_advance_angle(edat.curr_angle);

   //управляем усилением аттенюатора в зависимости от оборотов
   if (edat.param.knock_use_knock_channel)
    knock_set_gain(knock_attenuator_function(&edat));

   // индицирование этих ошибок прекращаем при начале вращения двигателя
   //(при прошествии N-го количества циклов)
   if (turnout_low_priority_errors_counter == 1)
   {
    ce_clear_error(ECUERROR_EEPROM_PARAM_BROKEN);
    ce_clear_error(ECUERROR_PROGRAM_CODE_BROKEN);
   }
   if (turnout_low_priority_errors_counter > 0)
    turnout_low_priority_errors_counter--;
  }

 }//main loop
 //------------------------------------------------------------------------
}