/* * injection.c * * Created on: Aug 4, 2025 * Author: herli */ #include #include "injection.h" #include "main.h" #include "toothed_wheel.h" #include "tein_detection.h" #include "fuel_map.h" #include "temperature.h" #include "timeouts.h" #include "timing_manager.h" #if HAS_PREINJECTION #include "pre_injection.h" #endif static inline void TIM1_OC4_SetSafe(uint16_t ccr4_new); float INJ_UPDATE_TARGET_EOI(); float PHI_AD = 1.875; uint8_t angleMode = 0; volatile uint8_t isInjecting; volatile uint8_t hasInjected = 0; volatile uint8_t hasInjectionEnded = 1; volatile uint8_t hasInjectionEndedFlag = 0; uint8_t inj_mode = 0; uint8_t InjectionPrescaler = 16; float dFi = 0; uint8_t INJ_EOI_COMPENSATION = 0; uint32_t T_on = 0; //Time on in microseconds uint16_t T_peak = 600; uint32_t T_delayFI = 150; uint32_t T_delay = 0; uint32_t T_hold = 0; uint32_t T_injecting = 0; float target_eoi = 0; float boostmult = 0; uint8_t triggerTeeth; uint8_t blankInj = 0; uint8_t cilCount; uint8_t retardteeth = 1; float current_Alpha = 0; //Alpha is the angle corresponding to time-on float current_Beta = 0.0; //Beta is the angle corresponding to FI delay float corrected_Beta = 0.0; float forceTemp = 35.6; extern float next_MT_RPM; int missed = 0; void INJ_MT_TASK(){ INJ_END(); if(!hasInjected && !blankInj){ missed++; } hasInjected = 0; hasInjectionEnded = 0; hasInjectionEndedFlag = 0; triggerTeeth = 0; #if HAS_PREINJECTION PI_EVAL(RPM, ME, MEPI); #endif } extern float nominal_bip_angle; float lastEOI = 0; extern float last_accel; uint8_t awaitingInj = 0; float INJ_GET_NOMINAL_EOI(); void INJ_UPDATE_ALPHA(){ /*float rp_sum = MT_RPM + last_MT_RPM; float dt = (PHI1 + dFi) / 90 * (1.0f / CYLINDERS) * (120.0f / rp_sum); // B) Predict the RPM at that firing time, if you need it float rpm_at_phiad = MT_RPM + last_accel*dt;*/ //FM_GET_PHIAD(MT_RPM, ME, forceTemp); //correction_eoi_accel = TM_GET_ACCEL_CORRECTION(last_MT_RPM, MT_RPM, TEETH_RPM); FM_GET_PHIAD(MT_RPM, ME, forceTemp); float target = INJ_UPDATE_TARGET_EOI() + correction_eoi; //current_Alpha = PHI_AD + nominal_bip_angle - corrected_Beta; current_Alpha = target - (PHI1 + dFi ); //+ correction_beta //current_Alpha = GetAlpha(RPM, ME, T_ein, forceTemp); //PHIAD map if (INJ_CLOSING_MARGIN){ current_Alpha += TIMETODEG(INJ_CLOSING_MARGIN, TEETH_RPM); } current_Alpha = current_Alpha < 0.1 ? 0 : current_Alpha; boostmult = BoostMultiplier(inj_mode, RPM, ME); current_Alpha *= boostmult; } void INJ_EVAL_EOI_COMPENSATION(){ /*if(!isInjecting){ compensatingEOI = (current_Alpha > 3 ) ? 1 : 0; //antes estaba con ton, pero si el me va bajando poco a poco, de el anterior pulso tiene ton, }*/ //esto la verdad no se muy bien para que esta.... } uint8_t margin_curr_us = 70; float margin_deg = 0.3; void INJ_UPDATE_BOI_MARGIN(float rpm){ margin_deg = rpm * (T_delay + margin_curr_us)* USTODEG; // margin_deg = fclamp(margin_deg, 0.0001, 10); } void INJ_PREPARE_ONCE(){ if(RPM < 800){ InjectionPrescaler = 1; TIM1->PSC = 160-1; }else{ InjectionPrescaler = 8; TIM1->PSC = 20-1; } INJ_PREPARE_BIP(0); INJ_UPDATE_ALPHA(); INJ_UPDATE_TYPE(); } extern float correction_boi_accel_2; extern float s_boi_corr_deg; void INJ_PREPARE_BIP(uint8_t teeth){ if(teeth < triggerTeeth || !triggerTeeth) { INJ_UPDATE_BOI_TRIGGER(); INJ_UPDATE_ALPHA(); } //correction_boi_accel_2 = TM_UPDATE_ACCEL_CORRECTION_BIP(last_MT_RPM, MT_RPM, TEETH_RPM); //correction_beta = s_boi_corr_deg + correction_boi_accel_2; INJ_UPDATE_T_Delay_phi(); //THIS should be updated more times if it is using predictive rpm //TM_GET_ACCEL_CORRECTION(last_MT_RPM, MT_RPM, TEETH_RPM); } void INJ_UPDATE_T_Delay_phi(){ //float time = TM_INTEGRATE_TIME_BIP(PHI1 + dFi + correction_beta, triggerTeeth) + 0.5f; //float time = TM_INTEGRATE_TIME_BIP(PHI1 + dFi + correction_beta, triggerTeeth) + 0.5f; float time = (PHI1 + dFi + correction_beta - triggerTeeth * TW_TOOTH_ALPHA)/(USTODEG * TEETH_RPM)+ 0.5f; T_delayFI = time - T_ein + TEIN_READING_OFFSET; } uint16_t t1, t2, t3, t4; extern float last_INJECTING_RPM; float eq_rpm; void INJ_UPDATE_TYPE(){ if(eq_rpm < 20){ eq_rpm = TEETH_RPM;}///1.8; //if(eq_rpm < ) T_injecting = DEGTOTIME(current_Alpha, eq_rpm*0.6); blankInj = T_injecting ? 0 : 1; T_peak = ((T_ein > 800 && CompensateTein) ? T_ein - 200 : PH_PEAK_DEF); T_hold = T_injecting ? T_ein + T_injecting - T_peak : 0; //T_hold = (ME > 0.04 && T_hold < 340)? 340 : T_hold; //a ver si T_ein_filtered = (T_hold < 260 || !CompensateTein) ? 800 : T_ein_filtered; compensatingEOI = T_hold < 260 ? 0 : 1; //wtf compensatingEOI if(!T_hold){ T_peak = 174; }else if(T_hold < 260){ T_peak = 600; T_hold = 270; } t1 = (T_delayFI - T_delay) * InjectionPrescaler; // t2 = t1 + T_peak * InjectionPrescaler; t3 = t1 + AcquisitionTime * InjectionPrescaler; t4 = blankInj ? t2 + 1 : t2 + (T_hold + INJ_CLOSING_MARGIN) * InjectionPrescaler; } uint8_t accel_calc=0; void EvaluateInjection(){ //AJUSTADO PARA 40mV histeresis de comparador, mayor histeresis mayor retraso de la inyeccion. if(currentTooth == triggerTeeth && !safetySHUTOFF){ INJ_UPDATE_T_Delay_phi(); //THIS should be updated more times if it is using predictive rpm t1 = (T_delayFI - T_delay) * InjectionPrescaler; // t2 = t1 + T_peak * InjectionPrescaler; t3 = t1 + AcquisitionTime * InjectionPrescaler; t4 = blankInj ? t2 + 1 : t2 + (T_hold + INJ_CLOSING_MARGIN) * InjectionPrescaler; if(t1 && t2 && t4){ if(t1 < t2 && t2 <= t4){ TIM1->CCR1 = t1; TIM1->CCR2 = t2; TIM1->CCR3 = t3; // End time (sampling end) TIM1->CCR4 = t4; } } TIM1->CNT = 0; TIM1->EGR = TIM_EGR_UG; TIM1->CR1 = TIM_CR1_OPM | TIM_CR1_CEN; cilCount++; cilCount%=CYLINDERS; hasInjected = 1; awaitingInj = 1; accel_calc = 0; eq_rpm = TEETH_RPM; } } void INJ_UPDATE_BOI_TRIGGER(){ //current_Beta = GetBeta(TEETH_RPM, T_ein) + dFi; /*current_Beta = PHI1 + dFi - T_ein*USTODEG*TEETH_RPM; current_Beta = fclamp(current_Beta, 0, 90); corrected_Beta = current_Beta + correction_beta;*/ //triggerTeeth = (corrected_Beta - margin_deg) / TW_TOOTH_ALPHA; //margen a ver si mejora uint8_t id = TM_GET_TRIGGER_TEETH_FROM_REFERENCE_AND_TIME(PHI1 + dFi + correction_beta, T_ein + T_delay + margin_curr_us); if(id){ uint8_t idd = id-retardteeth; if(RPM < 1000){ idd--; } triggerTeeth = idd > TW_PERCYL_TEETH ? TW_PERCYL_TEETH : idd; triggerTeeth = idd < 0 ? 0 : idd; } //triggerTeeth = retardteeth; } int mode; float dalpha_teinstatus = 0; extern float correction_eoi_accel; extern float actual_phi1; extern uint8_t real_bip_updated; uint8_t using_real_phi1 = 0; float dPHIAD_Tein=0; float min_dPHIAD_Tein=-21; float min_alpha=0.3; //1 float lpf_target = 1; uint8_t closingTooth = 0; float margin_eoi_tooth = 3; float INJ_UPDATE_TARGET_EOI(){ //INJ_UPDATE_ALPHA(); //FM_GET_PHIAD(MT_RPM, ME, forceTemp); dPHIAD_Tein = fclamp(TM_GET_PHIAD_dTEIN(PHI1 + dFi + PHI_AD, MT_RPM), min_dPHIAD_Tein, 0); //+ dPHIAD_Tein + correction_beta //+ correction_beta TM_GET_ACCEL_CORRECTION(last_MT_RPM, MT_RPM, TEETH_RPM, triggerTeeth); //float new_target_eoi = PHI1 + dFi + dPHIAD_Tein + PHI_AD + correction_eoi_accel;//(using_real_phi1 ? actual_phi1 : PHI1 + dFi + correction_beta) float new_target_eoi = PHI1 + dFi + correction_eoi_accel;//PHI_AD > 1 ? if(ME > 0.04){ new_target_eoi += fclamp(dPHIAD_Tein + PHI_AD, RPM < 2100 ? min_alpha : 5.5, 90); }else{ new_target_eoi += dPHIAD_Tein + PHI_AD; } //target_eoi = PHI1 + dFi + correction_beta + dPHIAD_Tein + PHI_AD + correction_eoi_accel;//(using_real_phi1 ? actual_phi1 : PHI1 + dFi + correction_beta) /*if(!T_ein_status){ float d_tein_angle = target_eoi - TM_INTEGRATE_ANGLE_FROM_NEAREST_TOOTH(IC_EOI + 16*PH_PEAK_DEF,1); new_target_eoi += d_tein_angle ; }*/ target_eoi += lpf_target*(new_target_eoi-target_eoi); //target_eoi = new_target_eoi; //target_eoi = new_target_eoi; closingTooth = (uint8_t)((target_eoi - margin_eoi_tooth)/TW_TOOTH_ALPHA); return target_eoi; } float INJ_GET_TARGET_EOI(){ return target_eoi; } float INJ_GET_NOMINAL_EOI(){ return PHI1 + dFi + PHI_AD + dPHIAD_Tein; } uint32_t T_integrated; extern float real_eoi; float lpf_fastamount = 1; float min = -100; float max = 100; float K_rpm = .1; float max_slow = 0.8; float min_slow = 0.0; float fastAmount = 0.0; float fastAmount_lpf = 0.0; float new_fastAmount = 1.0; float fA_m = 0.5; float fA_n = 0; float margineq = 6; float lastTooth = 0.0; void INJ_EVAL_END(){ if(isInjecting && compensatingEOI){ //esto solo lo hace en el ultimo diente, vamos a probar updatearlo en cada diente uint16_t now = TIM1->CNT; //float target = INJ_GET_TARGET_EOI() + correction_eoi; /*if(0){ FM_GET_PHIAD(MT_RPM, ME, forceTemp); }*/ float target = INJ_UPDATE_TARGET_EOI() + correction_eoi; //float b_a = target +using_real_phi1*(actual_phi1 -PHI1 - dFi)- TW_TOOTH_ALPHA*currentTooth; //remaining angle + correction_eoi float b_a = target - TW_TOOTH_ALPHA*currentTooth; //remaining angle + correction_eoi if(real_bip_updated){ float dif = (actual_phi1 - PHI1 - dFi); b_a += dif*fA_m; } //eq_rpm = fclamp(TEETH_RPM, edgeBuf[triggerTeeth].rpm *fA_m ,edgeBuf[triggerTeeth].rpm); //if(TIM1->CNT > TIM1->CCR1 + (T_ein + 200) * InjectionPrescaler){ //if(b_a < margineq ){//b_a < 6margin_eoi_tooth if(currentTooth >= closingTooth ){//b_a < 6margin_eoi_tooth T_injecting = DEGTOTIME(b_a, TEETH_RPM); //eq_rpm //T_integrated = T_injecting; //uint32_t t4 = (T_integrated - TM_GET_T_DELAY_END()) * InjectionPrescaler; //los 25 es por el cambio de topologia, para que cierre al mismo tiempo TIM1_OC4_SetSafe((uint16_t)(now +(T_injecting - TM_GET_T_DELAY_END()) * InjectionPrescaler)); lastTooth = currentTooth; compensatingEOI = 0; return; //to not compensate nothing more }else{ T_injecting = DEGTOTIME(b_a, TEETH_RPM*0.9); //retard ass line TIM1_OC4_SetSafe((uint16_t)(now +(T_injecting - TM_GET_T_DELAY_END()) * InjectionPrescaler)); return; } //uint32_t T_current = TIM1->CCR4 - TIM1->CNT; //float T_remaining_nom = 1.0f * T_current / InjectionPrescaler; //float T_remaining_comp = T_remaining_nom - lpf_eoi*(T_remaining_nom - b_a/(TEETH_RPM)/USTODEG); //if(!T_integrated){ T_integrated = T_current;} //T_integrated = TM_INTEGRATE_TIME_FROM_REFERENCE_Forward(target, currentTooth, PHI1 + dFi) + 0.5f; T_integrated = TM_INTEGRATE_TIME_TO_EOI(target, currentTooth) + 0.5f ;// - TEIN_NOMINAL //-!T_ein_status*PH_PEAK_DEF //T_integrated -= 0.5*(1.0f * T_current - b_a/(TEETH_RPM)/USTODEG); //T_integrated = T_remaining_comp; /*if(b_a > 4.5){ //schedule for next teeth + 50% T_integrated = DEGTOTIME(b_a*1.5, TEETH_RPM); }else{ T_integrated = TM_INTEGRATE_TIME_FROM_REFERENCE_Forward(target, currentTooth, PHI1 + dFi); lastEOI = target; }*/ uint32_t t4 = (T_integrated - TM_GET_T_DELAY_END()) * InjectionPrescaler; //los 25 es por el cambio de topologia, para que cierre al mismo tiempo TIM1_OC4_SetSafe((uint16_t)(now + t4)); } } void INJ_SET_DAC(uint8_t isPeak) { if(!awaitingInj) return; if(isPeak){ isInjecting = 1; uint16_t dato_dac = (uint16_t)(((isPeak - 1)? V_PEAK : V_HOLD )*4095/3.30); //4095 in 12 bit, 255 in 8 bit HAL_DAC_SetValue(&hdac1, DAC_CHANNEL_1, DAC_ALIGN_12B_R, dato_dac); //channel 2 es el que usamos if(isPeak - 1){ HAL_GPIO_WritePin(HOLD_CONTROL_GPIO_Port, HOLD_CONTROL_Pin, GPIO_PIN_SET); } }else{ HAL_DAC_SetValue(&hdac1, DAC_CHANNEL_1, DAC_ALIGN_12B_R, 0); //channel 2 es el que usamos isInjecting = 0; HAL_GPIO_WritePin(HOLD_CONTROL_GPIO_Port, HOLD_CONTROL_Pin, GPIO_PIN_RESET); } } void INJ_END(){ if(isInjecting){ INJ_SET_DAC(0); HAL_GPIO_WritePin(HOLD_CONTROL_GPIO_Port, HOLD_CONTROL_Pin, GPIO_PIN_RESET); TW_DEFER_EOI_EVAL(TIM2->CNT); hasInjectionEndedFlag = 1; } //TW_DEFER_TEIN_VAL(); //freaky aah angle USELESS I THINK } void FORCE_INJ_END(){ /*HAL_DAC_SetValue(&hdac1, DAC_CHANNEL_1, DAC_ALIGN_12B_R, 0); //channel 2 es el que usamos HAL_GPIO_WritePin(HOLD_CONTROL_GPIO_Port, HOLD_CONTROL_Pin, GPIO_PIN_RESET); TW_DEFER_EOI_EVAL(TIM2->CNT); hasInjectionEnded = 1;*/ //TW_DEFER_TEIN_VAL(); //freaky aah angle USELESS I THINK } float DEGTOTIME(float DEG, float revs){ float TIME = 1000000 / (revs * 6) * DEG; //IN MICROSECONDS return TIME; } float TIMETODEG(float TIME, float revs){ float DEG = (revs * 6) * TIME / 1000000 ; //IN MICROSECONDS return DEG; } static inline void TIM1_OC4_SetSafe(uint16_t ccr4_new) { //uint16_t cnt = TIM1->CNT; if(ccr4_new > TIM1->CCR2){ TIM1->CCR4 = ccr4_new; } __DSB(); // ensure the write hits the peripheral before we test // If the compare time is already due or effectively "now", kill the pulse now. // Keep the threshold at 0 or 1 tick depending on your clock/propagation. if (ccr4_new < TIM1->CNT) { /*// Force OC4 inactive (OC4M = 100) uint32_t ccmr2 = TIM1->CCMR2; ccmr2 &= ~TIM_CCMR2_OC4M; ccmr2 |= (4U << TIM_CCMR2_OC4M_Pos); // Forced inactive TIM1->CCMR2 = ccmr2; __DSB(); // Restore back to PWM/OC mode (e.g., PWM1 = 110) ccmr2 &= ~TIM_CCMR2_OC4M; ccmr2 |= (6U << TIM_CCMR2_OC4M_Pos); TIM1->CCMR2 = ccmr2; __DSB();*/ INJ_END(); } } extern uint8_t startupiscar; void SEND1_Handler( const struct CanMessageDef *msg, const uint8_t in_data[8], CanTxFn tx ) { #if defined(T06301) startupiscar = 1; #endif if(!isInjecting && !hasInjectionEnded){ INJ_UPDATE_ALPHA(); } }