#include "globals.h" #include "i2c.h" #include "device-functions.h" #include "lcd.h" #include "monitor.h" #include "error_utils.h" #include "dummy_functions.h" #include "menus.h" #include #include long monitor_last_forced_trig[max_channels]; void I2C_Setup_Monitor(); void I2C_Setup_Monitor() { int i; float new_os; float average_os; float integrated_error; int channel; int total; total=0; average_os = 0.0; for (channel=0; channel<(globals.Flash.ChanKey_Curr_Mon_value?globals.Flash.channels:1); ++channel) if (globals.Flash.monitor_enabled[channel]) { ++total; LCD_clear(); LCD_write(0,0,"Nulling Current Monitor ...."); /* quiescent */ I2C_Write(PCF8574A+Curr_Mon_MSB+channel*4,0xff); I2C_Write(PCF8574A+Curr_Mon_LSB+channel*4,0xff); /* remove chip-select */ I2C_Write(PCF8574A+Curr_Mon_MSB+channel*4,0xbf); /* pulse CAL line low */ I2C_Write(PCF8574A+Curr_Mon_MSB+channel*4,0x9f); I2C_Write(PCF8574A+Curr_Mon_MSB+channel*4,0xbf); for(i=0; i<50; i++); /* quiescent */ I2C_Write(PCF8574A+Curr_Mon_MSB+channel*4,0xff); /* wait for monitor output to become stable */ g_usleep(1e6); do { globals.ChannelState[channel].Curr_Mon_offset=0; integrated_error=0; /* repeat until stable for 50 iterations */ int j=0; while (j<50) { g_usleep(1e4); /* pulse S/H line low for initial sample of monitor */ I2C_Write(PCF8574A+Curr_Mon_MSB+channel*4,0x7f); for (i=0; i<100; ++i) { ; } /* quiescent */ I2C_Write(PCF8574A+Curr_Mon_MSB+channel*4,0xff); /* inactive, weak pull-up mode */ I2C_Read(PCF8574A+Curr_Mon_MSB+channel*4); new_os = 1.0 * I2C_Get_Monitor_Word(channel); average_os = (average_os*j+new_os) / (j+1.0); integrated_error += (average_os-new_os); if ( fabs(new_os-average_os) < 300.0) { ++j; } else { j=0; } } } while (fabs(integrated_error) > 25.0); globals.ChannelState[channel].Curr_Mon_offset=(int) average_os; LCD_write(0,0,"Current Monitor is now ready."); } if (total) { I2C_Check_Monitors(); } return; } void force_monitor_cal(int channel, int do_calibration); void force_monitor_cal(int channel, int do_calibration) { if (do_calibration) { /* quiescent */ I2C_Write(PCF8574A+Curr_Mon_MSB+channel*4,0xff); I2C_Write(PCF8574A+Curr_Mon_LSB+channel*4,0xff); /* remove chip-select */ I2C_Write(PCF8574A+Curr_Mon_MSB+channel*4,0xbf); /* pulse CAL line low */ I2C_Write(PCF8574A+Curr_Mon_MSB+channel*4,0x9f); I2C_Write(PCF8574A+Curr_Mon_MSB+channel*4,0xbf); g_usleep(2e3); } /* pulse trigger line low and remove chip-select to force an A/D conversion */ I2C_Write(PCF8574A+Curr_Mon_MSB+channel*4,0x3f); /* quiescent */ I2C_Write(PCF8574A+Curr_Mon_MSB+channel*4,0xff); } int I2C_Get_Monitor_Word(int channel); int I2C_Get_Monitor_Word(int channel) { int monitor_word; /* remove chip-select, so that the value doesn't change while read */ I2C_Write(PCF8574A+Curr_Mon_MSB+channel*4,0xbf); monitor_word=((I2C_Read(PCF8574A+Curr_Mon_MSB+channel*4) & 0x1f)<<8) + I2C_Read(PCF8574A+Curr_Mon_LSB+channel*4); /* restore chip-select */ I2C_Write(PCF8574A+Curr_Mon_MSB+channel*4,0xff); /* PCB 116B and earlier had 13-bit ADC, PCB 116C has 12 bit. */ if (globals.Flash.pcb116c_mon == 1) { monitor_word = (monitor_word & 0x0fff) << 1; } /* deal with sign bit */ if (monitor_word & 0x1000) { monitor_word=-( ((~monitor_word)+1) & 0x0fff); } monitor_word*=-1; monitor_word-=globals.ChannelState[channel].Curr_Mon_offset; return monitor_word; } int I2C_Check_Monitors(void); int I2C_Check_Monitors(void) { int monitor_word; float step_size; int channel; int ampl_range,point_found,UseNegData,entry,word_out; int update_display; int use_neg_data; int actual_pol; int i; int error_num; long timer_check; long seconds_since_last; update_display=0; for (channel=0; channel<(globals.Flash.ChanKey_Curr_Mon_value?globals.Flash.channels:1); ++channel) { timer_check = sec_timer(); seconds_since_last = timer_check - monitor_last_forced_trig[channel]; if (seconds_since_last > 0) { if ( (globals.ChannelState[channel].func_mode==dc_mode_on) || (globals.ChannelState[channel].output_state==output_off)) { /* force monitor measurement every second in DC mode (because no TTL trigger is present) and output-off mode */ force_monitor_cal(channel,NO); } monitor_last_forced_trig[channel]=timer_check; } if (globals.Flash.sep_posneg_mon_ratio[channel] && globals.ChannelState[channel].amplitude<0.0) { use_neg_data=1; } else { use_neg_data=0; } monitor_word=I2C_Get_Monitor_Word(channel); /* determine current ampl_range */ Set_VI_Control(pwl_ampl_values,channel,globals.ChannelState[channel].amplitude,&point_found, &l_range,&UseNegData,&entry,&word_out,&actual_pol); /* 5.0V is the full-scale voltage of the 12bit ADC */ globals.ChannelState[channel].Curr_Mon_value=((((float) monitor_word)/4095.0) * 5.0) / globals.Flash.mon_vi_ratio[channel][ampl_range][use_neg_data]; /* convert to even step size */ step_size=globals.Flash.monitor_step[channel]; globals.ChannelState[channel].Curr_Mon_value= ((float) ((long) (globals.ChannelState[channel].Curr_Mon_value/step_size)) ) * step_size; /* AVO-8D2: check for duty cycle problems, as a function of measured amplitude */ if ( globals.Flash.hard_current_limit_enabled[channel] && (globals.ChannelState[channel].output_state == output_on)) { for (i=0; i globals.ChannelState[channel].soft_current_limit)) { Set_Output_State(channel,output_off); queue_and_broadcast_sensor_alarm(Soft_Limit_Exceeded); } else if (globals.MenuStatus.Type_Of_Menu==Main_Menu_On && !globals.MenuStatus.Error_Screen && !globals.MenuStatus.Nonstd_Display && globals.ChannelState[channel].Curr_Mon_value!=globals.ChannelState[channel].displayed_mon_val && (seconds_since_last > 0)) /* only update display once a second */ { ++update_display; } } if (update_display) { Menu_Update_Display(); } return OK; }