void get_adc_vdc_high() { int LoopCtrl; Uint32 RunTimeMsec,StartTimeMsec; double adc_Vdc_in, adc_Vdc_out; UNION32 u32data; load_sci_tx_mail_box( "Start ADC at Vdc high"); delay_msecs(10); gfRunTime=0.0; LoopCtrl = 1; gMachineState = STATE_READY; while(LoopCtrl == 1) { if( gfRunTime >= 1.0 ) LoopCtrl = 0; RunTimeMsec = ulGetTime_mSec( StartTimeMsec); if(RunTimeMsec > 1){ StartTimeMsec = ulGetNow_mSec( ); adc_Vdc_in = (double)giAdcVdc; LPF1(0.002,10.0,adc_Vdc_in, & adc_Vdc_out); } } if( gfRunTime >= 1.0 ){ code_adc_vdc_high = adc_Vdc_out; u32data.dword = code_adc_vdc_high; write_code_2_eeprom(CODE_adc_vdc_high,u32data); load_sci_tx_mail_box("OK adc_vdc_high Saved");delay_msecs(10); } }
/************************************************************************************* * This method calculates the voltage that should be output to the PWM peripheral. * It takes the reading from the light sensor, scales it appropriately, calculates * the P, I, and D values, converts it to the duty cycle value, and outputs the * value to the PWM params. **************************************************************************************/ XStatus calc_PID() { double deriv, integral, error, prev_error = 0; double volt_out; int duty_out; XStatus Status; // Xilinx return status // stabilize the PWM output (and thus the lamp intensity) at the // minimum before starting the test Status = PWM_SetParams(&PWMTimerInst, pwm_freq, dc_start); if (Status == XST_SUCCESS) { PWM_Start(&PWMTimerInst); } else { return -1; } //Wait for the LED output to settle before starting delay_msecs(1500); for (smpl_idx = 1; smpl_idx < NUM_FRQ_SAMPLES; smpl_idx++) { delay_msecs(100); // get count from light sensor and convert to voltage sample[smpl_idx] = LIGHTSENSOR_Capture(LIGHTSENSOR_BASEADDR, slope, offset, is_scaled, freq_min_cnt); volt_out = (-3.3 / 4095.0) * (sample[smpl_idx]) + 3.3; // calculate derivative; error = setpoint - volt_out; deriv = error - prev_error; // calculate integral if (error < setpoint/10) integral += error; else integral = 0; // Control offset is gotten from characterization volt_out = offset + (error * prop_gain) + (deriv * deriv_gain) + (integral * integral_gain); duty_out = (volt_out)* (MAX_DUTY+1)/VOLT_MAX; // establish bounds if (duty_out < 1) duty_out = 1; if (duty_out > 99)duty_out = 99; // activate PWM Status = PWM_SetParams(&PWMTimerInst, pwm_freq, duty_out); if (Status == XST_SUCCESS) { PWM_Start(&PWMTimerInst); } } return XST_SUCCESS; }
XStatus calc_bang() { Xfloat32 volt_out; XStatus Status; // Xilinx return status // stabilize the PWM output (and thus the lamp intensity) at the // minimum before starting the test Status = PWM_SetParams(&PWMTimerInst, pwm_freq, dc_start); if (Status == XST_SUCCESS) { PWM_Start(&PWMTimerInst); } else { return -1; } //Wait for the LED output to settle before starting delay_msecs(1500); for (smpl_idx = 1; smpl_idx < NUM_FRQ_SAMPLES; smpl_idx++) { // get count from light sensor and convert to voltage sample[smpl_idx] = LIGHTSENSOR_Capture(LIGHTSENSOR_BASEADDR, slope, offset, is_scaled, freq_min_cnt); volt_out = (-3.3 / 4095.0) * (sample[smpl_idx]) + 3.3; if (volt_out < setpoint) { Status = PWM_SetParams(&PWMTimerInst, pwm_freq, MAX_DUTY); delay_msecs(1); if (Status == XST_SUCCESS) { PWM_Start(&PWMTimerInst); } } else { Status = PWM_SetParams(&PWMTimerInst, pwm_freq, MIN_DUTY); delay_msecs(1); if (Status == XST_SUCCESS) { PWM_Start(&PWMTimerInst); } } delay_msecs(100); } return XST_SUCCESS; }
int GetKey() { int KeySave; if((KeySave= GetKeyTemp()) != BTN_NULL ) { delay_msecs(20); if( ( KeySave = GetKeyTemp()) != BTN_NULL ) { while( GetKeyTemp() != BTN_NULL); } delay_msecs(20); // off bound proc } return KeySave; }
/***** * DoTest_Track() - Perform the Tracking test * * This function uses the global "pwm_freq" and "pwm_duty" values to adjust the PWM * duty cycle and thus the intensity of the LED. The function displays * the light detector reading as it tracks changes in the * LED intensity. This test runs continuously until a different test is selected. * Returns XST_SUCCESS since this test can't fail. Returns approximate sample interval * in the global variable "frq_sample_interval" *****/ XStatus DoTest_Track(void) { static int old_pwm_freq = 0; // old pwm_frequency and duty cycle static int old_pwm_duty = 200; // these values will force the initial display volatile u16 frq_cnt; // light detector counts to display XStatus Status; // Xilinx return status unsigned tss; // starting timestamp if ((pwm_freq != old_pwm_freq) || (pwm_duty != old_pwm_duty)) { // set the new PWM parameters - PWM_SetParams stops the timer Status = PWM_SetParams(&PWMTimerInst, pwm_freq, pwm_duty); if (Status == XST_SUCCESS) { PWM_Start(&PWMTimerInst); } tss = timestamp; //ECE544 Students: //make the light sensor measurement frq_cnt = LIGHTSENSOR_Capture(LIGHTSENSOR_BASEADDR, slope, offset, is_scaled); delay_msecs(1); frq_smple_interval = timestamp - tss; // update the display and save the frequency and duty // cycle for next time update_lcd(pwm_duty, frq_cnt); old_pwm_freq = pwm_freq; old_pwm_duty = pwm_duty; } return XST_SUCCESS; }
int init_eprom_data() { UNION32 data,data2; int check; int address,cmd,loop_ctrl; int return_value; data.dword = 0.0; cmd = CMD_READ_DATA; address = return_value = 0; loop_ctrl = 1; while(loop_ctrl) { cmd = CMD_READ_DATA; check = get_code_information( address, cmd , & code_inform); if( check==0 ){ if( code_inform.type == TYPE_DOUBLE){ data.dword = code_inform.code_default.doubles; } else{ data.word.word0 = code_inform.code_default.ints; } read_eprom_data(address, & data2 ); if( data.dword != data2.dword) write_code_2_eeprom( address,data); read_eprom_data(address, & data2 ); if( data.dword != data2.dword) { loop_ctrl = 0; return_value = -1; load_sci_tx_mail_box("Trip : eeprom write" ); delay_msecs(100); break; } code_inform.code_value.doubles = data.dword; cmd = CMD_WRITE_RAM; check = get_code_information( address,cmd, & code_inform); address ++; } else if( check == -2) address = (address/100)*100 + 100; else address ++; if( address >= CODE_GROUP7_END ) { EepromSaveFlag = 0; return 0; } } EepromSaveFlag = 0; return return_value; }
void set_PID_vals(row, col) { u32 btnsw; NX3_readBtnSw(&btnsw); // Set which control measurement we're using if (btnsw & msk_BTN_NORTH) { // increment to the next selection. If we're at the last enum, set it to the 1st (proportional) if (PID_current_sel == OFFSET) PID_current_sel = PROPORTIONAL; else PID_current_sel = (Control_t)((int)(PID_current_sel+1)); //casting to allow increment // cursor control logic if (PID_current_sel == PROPORTIONAL) { row = 1; col = 2; } else if (PID_current_sel == INTEGRAL) { row = 1; col = 7; } else if (PID_current_sel == DERIVATIVE) { row = 1; col = 12; } else if (PID_current_sel == OFFSET) { row = 2; col = 13; } } delay_msecs(20); //set cursor location and turn on cursor LCD_setcursor(row,col); LCD_docmd(LCD_DISPLAYONOFF, LCD_CURSOR_ON); if (btnsw & msk_BTN_EAST) { if (PID_current_sel == PROPORTIONAL) prop_gain += GAIN_INCREMENT; else if (PID_current_sel == INTEGRAL) integral_gain += GAIN_INCREMENT; else if (PID_current_sel == DERIVATIVE) deriv_gain += GAIN_INCREMENT; else offset += GAIN_INCREMENT; } if (btnsw & msk_BTN_WEST) { if (PID_current_sel == PROPORTIONAL) prop_gain -= GAIN_INCREMENT; else if (PID_current_sel == INTEGRAL) integral_gain -= GAIN_INCREMENT; else if (PID_current_sel == DERIVATIVE) deriv_gain -= GAIN_INCREMENT; else offset -= GAIN_INCREMENT; } }
/***** * DoTest_Step() - Perform the Step test * * This function stabilizes the duty cycle at "dc_start" for * about a second and a half and then steps the duty cycle from min to max or * max to min depending on the test. NUM_FRQ_SAMPLES are collected * into the global array sample[]. An approximate sample interval * is written to the global variable "frq_smpl_interval" *****/ XStatus DoTest_Step(int dc_start) { XStatus Status; // Xilinx return status unsigned tss; // starting timestamp u16 frq_cnt; // measured counts to display // stabilize the PWM output (and thus the lamp intensity) before // starting the test Status = PWM_SetParams(&PWMTimerInst, pwm_freq, dc_start); if (Status == XST_SUCCESS) { PWM_Start(&PWMTimerInst); } else { return XST_FAILURE; } //Wait for the LED output to settle before starting delay_msecs(1500); if (dc_start > STEPDC_MAX / 2) { Status = PWM_SetParams(&PWMTimerInst, pwm_freq, STEPDC_MIN); } else { Status = PWM_SetParams(&PWMTimerInst, pwm_freq, STEPDC_MAX); } if (Status == XST_SUCCESS) { PWM_Start(&PWMTimerInst); pwm_duty = dc_start; } else { return XST_FAILURE; } // gather the samples smpl_idx = 0; tss = timestamp; while (smpl_idx < NUM_FRQ_SAMPLES) { //ECE544 Students: //make the light sensor measurement sample[smpl_idx++] = LIGHTSENSOR_Capture(LIGHTSENSOR_BASEADDR, slope, offset, is_scaled); } frq_smple_interval = (timestamp - tss) / NUM_FRQ_SAMPLES; return XST_SUCCESS; }
void get_adc_offset() { int LoopCtrl; Uint32 RunTimeMsec,StartTimeMsec; double u_offset_in, v_offset_in; double R_offset_in, S_offset_in; double u_offset_out, v_offset_out; double R_offset_out, S_offset_out; UNION32 u32data; load_sci_tx_mail_box( "\n***********************"); delay_msecs(10); load_sci_tx_mail_box( "\n Start ADC Offset Calc "); delay_msecs(10); load_sci_tx_mail_box( "\n***********************"); delay_msecs(10); gfRunTime=0.0; LoopCtrl = 1; while(LoopCtrl == 1) { if( gfRunTime >= 5.0 ) LoopCtrl = 0; RunTimeMsec = ulGetTime_mSec( StartTimeMsec); if(RunTimeMsec > 1){ StartTimeMsec = ulGetNow_mSec( ); u_offset_in = (double)giAdcUphase; v_offset_in = (double)giAdcVphase; R_offset_in = (double)giAdcRphase; S_offset_in = (double)giAdcSphase; LPF1(0.002,10.0,u_offset_in, & u_offset_out); LPF1(0.002,10.0,v_offset_in, & v_offset_out); LPF1(0.002,10.0,R_offset_in, & R_offset_out); LPF1(0.002,10.0,S_offset_in, & S_offset_out); } } if( gfRunTime >= 5.0 ){ adc_u_offset = (int)u_offset_out; adc_v_offset = (int)v_offset_out; adc_R_offset = (int)R_offset_out; adc_S_offset = (int)S_offset_out; u32data.word.word0 = adc_u_offset; write_code_2_eeprom(CODE_adc_u_offset,u32data); u32data.word.word0 = adc_v_offset; write_code_2_eeprom(CODE_adc_v_offset,u32data); u32data.word.word0 = adc_R_offset; write_code_2_eeprom(CODE_adc_R_offset,u32data); u32data.word.word0 = adc_S_offset; write_code_2_eeprom(CODE_adc_S_offset,u32data); load_sci_tx_mail_box("\n*********************");delay_msecs(10); load_sci_tx_mail_box("\n OK Adc offset Saved ");delay_msecs(10); load_sci_tx_mail_box("\n*********************");delay_msecs(10); } }
int main() { XStatus Status; u32 btnsw, old_btnsw = 0x000000FF; int rotcnt, old_rotcnt = 0x1000; bool done = false; // initialize devices and set up interrupts, etc. Status = do_init(); if (Status != XST_SUCCESS) { LCD_setcursor(1,0); LCD_wrstring("****** ERROR *******"); LCD_setcursor(2,0); LCD_wrstring("INIT FAILED- EXITING"); exit(XST_FAILURE); } // initialize the global variables timestamp = 0; pwm_freq = INITIAL_FREQUENCY; pwm_duty = INITIAL_DUTY_CYCLE; clkfit = 0; new_perduty = false; // start the PWM timer and kick of the processing by enabling the Microblaze interrupt PWM_SetParams(&PWMTimerInst, pwm_freq, pwm_duty); PWM_Start(&PWMTimerInst); microblaze_enable_interrupts(); // display the greeting LCD_setcursor(1,0); LCD_wrstring(" PWM LIB TEST R0"); LCD_setcursor(2,0); LCD_wrstring(" by Roy Kravitz "); NX3_writeleds(0x000000FF); delay_msecs(2000); NX3_writeleds(0x00000000); // write the static text to the display LCD_clrd(); LCD_setcursor(1,0); LCD_wrstring("G|FR: DCY: %"); LCD_setcursor(2,0); LCD_wrstring("Vavg: "); // main loop do { // check rotary encoder pushbutton to see if it's time to quit NX3_readBtnSw(&btnsw); if (btnsw & msk_BTN_ROT) { done = true; } else { new_perduty = false; if (btnsw != old_btnsw) { switch (btnsw & PWM_FREQ_MSK) { case 0x00: pwm_freq = PWM_FREQ_10HZ; break; case 0x01: pwm_freq = PWM_FREQ_100HZ; break; case 0x02: pwm_freq = PWM_FREQ_1KHZ; break; case 0x03: pwm_freq = PWM_FREQ_10KHZ; break; case 0x04: pwm_freq = PWM_FREQ_50KHZ; break; case 0x05: pwm_freq = PWM_FREQ_100KHZ; break; case 0x06: pwm_freq = PWM_FREQ_150KHZ; break; case 0x07: pwm_freq = PWM_FREQ_200KHZ; break; } old_btnsw = btnsw; new_perduty = true; } // read rotary count and handle duty cycle changes // limit duty cycle to 0% to 99% ROT_readRotcnt(&rotcnt); if (rotcnt != old_rotcnt) { pwm_duty = MAX(0, MIN(rotcnt, 99)); old_rotcnt = rotcnt; new_perduty = true; } // update generated frequency and duty cycle if (new_perduty) { u32 freq, dutycycle; float vavg; char s[10]; // set the new PWM parameters - PWM_SetParams stops the timer Status = PWM_SetParams(&PWMTimerInst, pwm_freq, pwm_duty); if (Status == XST_SUCCESS) { PWM_GetParams(&PWMTimerInst, &freq, &dutycycle); update_lcd(freq, dutycycle, 1); vavg = dutycycle * .01 * 3.3; voltstostrng(vavg, s); LCD_setcursor(2,5); LCD_wrstring(s); PWM_Start(&PWMTimerInst); } } } } while (!done); // wait until rotary encoder button is released do { NX3_readBtnSw(&btnsw); delay_msecs(10); } while ((btnsw & msk_BTN_ROT) == 0x80); // and say goodbye LCD_clrd(); LCD_wrstring("That's all folks"); delay_msecs(2000); LCD_clrd(); exit(XST_SUCCESS); }
// read data format "9:4:123:x.xxxe-x" // write data format "9:6:123:1.234e-3" void scib_cmd_proc( int * sci_cmd, double * sci_ref) { double data,dbtemp; int addr,check,temp; char str[30]={0}; TRIP_INFO * TripData; * sci_cmd = CMD_NULL; * sci_ref = 0.0; if( scib_rx_msg_flag == 0) return; scib_rx_msg_flag = 0; if ( scib_rx_msg_box[0] != '9') return; addr = (scib_rx_msg_box[4]- '0')* 100 +(scib_rx_msg_box[5]- '0')*10 + (scib_rx_msg_box[6]- '0'); scib_rx_msg_box[16]=0; data = atof( & scib_rx_msg_box[8]); // regist write function decoding if( scib_rx_msg_box[2] == '6'){ if( addr == 900 ){ check = (int)data; if(check == 10){ * sci_cmd = CMD_START; * sci_ref = code_btn_start_ref; load_scib_tx_mail_box("UART CMD_START"); } else if( check == 20 ){ * sci_cmd = CMD_STOP; * sci_ref = 0.0; load_scib_tx_mail_box("UART CMD_STOP"); } else if( check == 30 ){ * sci_cmd = CMD_RESET; * sci_ref = 0.0; load_scib_tx_mail_box("UART CMD_RESET"); } else if( data == 40 ){ * sci_cmd = CMD_SAVE; * sci_ref = 0.0; load_scib_tx_mail_box("UART CMD_SAVE"); } else if( data == 80 ){ * sci_cmd = CMD_NULL; * sci_ref = 0.0; get_adc_offset(); } else if( data == 90 ){ * sci_cmd = CMD_NULL; * sci_ref = 0.0; load_scib_tx_mail_box("EEPROM init Start"); check = init_eprom_data(); // 0이 아니면 address value if( check != 0) load_scib_tx_mail_box("EEPROM init Fail"); else load_scib_tx_mail_box("EEPROM init Success"); } else{ load_scib_tx_mail_box("Illegal CMD data"); } } else{ // registor_write_proc(addr,data); check = SaveDataProc(addr, data); Nop(); } } //================== // read routine //==================== else if(scib_rx_msg_box[2] == '4'){ if(addr == 901){ // monitor state check = (int)data; if(check == 0){ switch(gMachineState){ case STATE_POWER_ON: load_scib_tx_mail_box("[POWE_ON] "); break; case STATE_READY: load_scib_tx_mail_box("[READY] "); break; case STATE_RUN: load_scib_tx_mail_box("[RUN ] "); break; case STATE_TRIP: load_scib_tx_mail_box("[TRIP] "); break; case STATE_INIT_RUN: load_scib_tx_mail_box("[INIT] "); break; case STATE_GO_STOP: load_scib_tx_mail_box("[GO_STOP] "); break; case STATE_WAIT_BREAK_OFF: load_scib_tx_mail_box("STATE_WAIT_BREAK_OFF"); break; default: load_scib_tx_mail_box("Unknown State"); break; } } return; } else if(addr == 902){ // 내부 변수 read check = (int)data; switch( check ){ case 0 : temp = (int)(floor(Freq_out +0.5)); snprintf( str,10,"Fq=%3d[hz]",temp); load_scib_tx_mail_box(str); break; case 1 : temp = (int)(floor(rpm +0.5)); snprintf( str,10,"RPM =%4d ",temp); load_scib_tx_mail_box(str); break; case 2 : temp = (int)(floor(Vdc +0.5)); snprintf( str,10," VDC =%4d",temp); load_scib_tx_mail_box(str); break; case 3 : temp = (int)(floor( RMS_Ia * 10 + 0.5 ) ); snprintf( str,10,"I1 =%2d.%d ",temp/10, temp%10); load_scib_tx_mail_box(str); break; case 4 : temp = (int)(floor( RMS_Ib * 10 + 0.5 ) ); snprintf( str,10,"I2 =%2d.%d ",temp/10, temp%10); load_scib_tx_mail_box(str); break; case 5 : // Reset; gMachineState = STATE_POWER_ON; Nop(); asm (" .ref _c_int00"); // ;Branch to start of boot.asm in RTS library asm (" LB _c_int00"); // ;Branch to start of boot.asm in RTS library break; default: break; } // check 에 따른 변수를 포인터로 두어서 처리 한다. // snprintf( str,30,"\n Vdc =%10.3e \n",Vdc); load_scib_tx_mail_box(str); return; } else if(addr == 903){ // 내부 변수 read // EEPROM TRIP DATA check = (int)data; if( data == 0 ){ snprintf( str,4,"%03d:",TripInfoNow.CODE); load_scib_tx_mail_box(str); delay_msecs(180); load_scib_tx_mail_box(TripInfoNow.MSG); delay_msecs(220); load_scib_tx_mail_box(TripInfoNow.TIME); delay_msecs(180); dbtemp = TripInfoNow.HZ; temp = (int)(floor(dbtemp +0.5)); snprintf( str,10,"Fq=%3d[hz]",temp); load_scib_tx_mail_box(str); delay_msecs(180); dbtemp = TripInfoNow.VDC; temp = (int)(floor(dbtemp +0.5)); snprintf( str,10," VDC =%4d",temp); load_scib_tx_mail_box(str); delay_msecs(180); dbtemp = TripInfoNow.CURRENT; temp = (int)(floor(dbtemp +0.5)); snprintf( str,10,"I1 =%4d ",temp); load_scib_tx_mail_box(str); delay_msecs(180); dbtemp = TripInfoNow.DATA; temp = (int)(floor(dbtemp +0.5)); snprintf( str,10," DATA=%4d",temp); load_scib_tx_mail_box(str); delay_msecs(180); } else{ TripData = (TRIP_INFO*)malloc(sizeof(TRIP_INFO)); GetTripInfo(check + 1,TripData); strncpy(gStr1,TripInfoNow.MSG,20); snprintf( str,4,"%03d:",TripData->CODE); load_scib_tx_mail_box(str); delay_msecs(180); load_scib_tx_mail_box(TripData->MSG); delay_msecs(220); load_scib_tx_mail_box(TripData->TIME); delay_msecs(180); dbtemp = TripData->HZ; temp = (int)(floor(dbtemp +0.5)); snprintf( str,10,"Fq=%3d[hz]",temp); load_scib_tx_mail_box(str); delay_msecs(180); dbtemp = TripData->VDC; temp = (int)(floor(dbtemp +0.5)); snprintf( str,10," VDC =%4d",temp); load_scib_tx_mail_box(str); delay_msecs(180); dbtemp = TripData->CURRENT; temp = (int)(floor(dbtemp +0.5)); snprintf( str,10,"I1 =%4d ",temp); load_scib_tx_mail_box(str); delay_msecs(180); dbtemp = TripData->DATA; temp = (int)(floor(dbtemp +0.5)); snprintf( str,10," DATA=%4d",temp); load_scib_tx_mail_box(str); delay_msecs(180); free(TripData); } return; } else if(addr == 904){ // DATE & TIME SET check = (int)data; switch( check ){ case 0: TimeInput[0] = scib_rx_msg_box[10]; TimeInput[1] = scib_rx_msg_box[11]; TimeInput[2] = scib_rx_msg_box[12]; TimeInput[3] = scib_rx_msg_box[13]; TimeInput[4] = scib_rx_msg_box[14]; TimeInput[5] = scib_rx_msg_box[15]; break; case 1: TimeInput[6] = scib_rx_msg_box[10]; TimeInput[7] = scib_rx_msg_box[11]; TimeInput[8] = scib_rx_msg_box[12]; TimeInput[9] = scib_rx_msg_box[13]; TimeInput[10] = scib_rx_msg_box[14]; TimeInput[11] = scib_rx_msg_box[15]; delay_msecs(50); WriteTimeToDS1307(TimeInput); load_scib_tx_mail_box("Date & Time Saved"); break; case 2: // load_scib_tx_mail_box("WAIT FOR CLEAR DATA!"); // delay_msecs(180); ClearTripDataToEeprom(); break; } return; } else if(addr == 905){ // RUN & STOP check = (int)data; switch( check ){ case 0: * sci_cmd = CMD_START; * sci_ref = code_btn_start_ref; break; case 1: * sci_cmd = CMD_STOP; * sci_ref = 0.0; break; case 2: * sci_cmd = CMD_SPEED_UP; break; case 3: * sci_cmd = CMD_SPEED_DOWN; break; default: * sci_cmd = CMD_NULL; break; } return; } else if(addr == 906){ GetTimeAndDateStr(str); load_scib_tx_mail_box(str); return; } else if (( addr > 979) && ( addr < 996)){ check = addr - 980; snprintf( str,19,"adc =%4d",adc_result[check]); load_scib_tx_mail_box(str); delay_msecs(10); return; } check = get_code_information( addr, CMD_READ_DATA , & code_inform); if( check == 0 ){ check = (int)data; switch(check) { case 0: snprintf( str,19,"CODE=%4d",addr); load_scib_tx_mail_box(str); delay_msecs(10); break; case 1: load_scib_tx_mail_box(code_inform.disp);delay_msecs(10); break; case 2: if( code_inform.type == TYPE_DOUBLE ){ snprintf( str,20,"Data =%10.3e",code_inform.code_value.doubles); } else{ snprintf( str,20,"Data =%10d",code_inform.code_value.ints); } load_scib_tx_mail_box(str); delay_msecs(10); break; default: snprintf( str,19,"CODE=%4d",addr); load_scib_tx_mail_box(str);delay_msecs(10); load_scib_tx_mail_box(code_inform.disp);delay_msecs(10); if( code_inform.type == TYPE_DOUBLE ) snprintf( str,20,"Data =%10.3e",code_inform.code_value.doubles); else snprintf( str,20,"Data =%10d",code_inform.code_value.ints); load_scib_tx_mail_box(str); delay_msecs(10); break; } } else{ load_scib_tx_mail_box("Error Invalid Address");delay_msecs(10); } return; } }
void TripProc( ) { int iCommand; int LoopCtrl; int temp; double fReference; double dbtemp; char str[30]; str[29] = 0; EALLOW; GpioCtrlRegs.GPAMUX1.bit.GPIO0 = 0; // GPIO0 = PWM1A GpioCtrlRegs.GPAMUX1.bit.GPIO1 = 0; // GPIO1 = PWM1B GpioCtrlRegs.GPAMUX1.bit.GPIO2 = 0; // GPIO2 = PWM2A GpioCtrlRegs.GPAMUX1.bit.GPIO3 = 0; // GPIO3 = PWM2B GpioCtrlRegs.GPAMUX1.bit.GPIO4 = 0; // GPIO4 = PWM3A GpioCtrlRegs.GPAMUX1.bit.GPIO5 = 0; // GPIO5 = PWM3B GpioCtrlRegs.GPAMUX1.bit.GPIO6 = 0; // GPIO4A GpioCtrlRegs.GPAMUX1.bit.GPIO7 = 0; // GPIO4B GpioCtrlRegs.GPAMUX1.bit.GPIO8 = 0; // GPIO5A GpioCtrlRegs.GPAMUX1.bit.GPIO9 = 0; // GPIO5B GpioCtrlRegs.GPAMUX1.bit.GPIO10 = 0; // GPIO6A GpioCtrlRegs.GPAMUX1.bit.GPIO11 = 0; // GPIO6B GpioCtrlRegs.GPADIR.bit.GPIO0 = 1; // GPIO0 = Output GpioCtrlRegs.GPADIR.bit.GPIO1 = 1; // GPIO1 = Output GpioCtrlRegs.GPADIR.bit.GPIO2 = 1; // GPIO2 = Output GpioCtrlRegs.GPADIR.bit.GPIO3 = 1; // GPIO3 = Output GpioCtrlRegs.GPADIR.bit.GPIO4 = 1; // GPIO4 = Output GpioCtrlRegs.GPADIR.bit.GPIO5 = 1; // GPIO5 = Output GpioCtrlRegs.GPADIR.bit.GPIO6 = 1; // GPIO4A GpioCtrlRegs.GPADIR.bit.GPIO7 = 1; // GPIO4B GpioCtrlRegs.GPADIR.bit.GPIO8 = 1; // GPIO5A GpioCtrlRegs.GPADIR.bit.GPIO9 = 1; // GPIO5B GpioCtrlRegs.GPADIR.bit.GPIO10 = 1; // GPIO6A GpioCtrlRegs.GPADIR.bit.GPIO11 = 1; // GPIO6B GpioDataRegs.GPACLEAR.bit.GPIO0 = 1; // Set Output GpioDataRegs.GPACLEAR.bit.GPIO1 = 1; // Set Output GpioDataRegs.GPACLEAR.bit.GPIO2 = 1; // Set Output GpioDataRegs.GPACLEAR.bit.GPIO3 = 1; // Set Output GpioDataRegs.GPACLEAR.bit.GPIO4 = 1; // Set Output GpioDataRegs.GPACLEAR.bit.GPIO5 = 1; // Set Output GpioDataRegs.GPACLEAR.bit.GPIO6 = 1; // Set Output GpioDataRegs.GPACLEAR.bit.GPIO7 = 1; // Set Output GpioDataRegs.GPACLEAR.bit.GPIO8 = 1; // Set Output GpioDataRegs.GPACLEAR.bit.GPIO9 = 1; // Set Output GpioDataRegs.GPACLEAR.bit.GPIO10 = 1; // Set Output GpioDataRegs.GPACLEAR.bit.GPIO11 = 1; // Set Output EDIS; gMachineState = STATE_TRIP; MAIN_CHARGE_OFF; // Main Charge Relay Off init_charge_flag=0; INIT_CHARGE_CLEAR; TRIP_OUT_ON; GetTimeAndDateStr(str); strncpy( TripInfoNow.TIME,str,20); // SaveTripDataToEeprom(); debug_jsk load_sci_tx_mail_box("TRP"); delay_msecs(20); snprintf( str,4,"%03d:",TripInfoNow.CODE); load_sci_tx_mail_box(str); delay_msecs(20); load_sci_tx_mail_box(TripInfoNow.MSG); delay_msecs(20); load_sci_tx_mail_box( TripInfoNow.TIME) ; delay_msecs(20); dbtemp = TripInfoNow.HZ; temp = (int)(floor(dbtemp +0.5)); snprintf( str,10,"Fq=%3d[hz]",temp); load_sci_tx_mail_box(str); delay_msecs(20); dbtemp = TripInfoNow.VDC; temp = (int)(floor(dbtemp +0.5)); snprintf( str,10," VDC =%4d",temp); load_sci_tx_mail_box(str); delay_msecs(20); dbtemp = TripInfoNow.CURRENT; temp = (int)(floor(dbtemp +0.5)); snprintf( str,10,"I1 =%4d ",temp); load_sci_tx_mail_box(str); delay_msecs(20); dbtemp = TripInfoNow.DATA; temp = (int)(floor(dbtemp +0.5)); snprintf( str,10," DATA=%4d",temp); load_sci_tx_mail_box(str); delay_msecs(20); LoopCtrl = CMD_NULL; while( LoopCtrl != CMD_RESET) { get_command( & iCommand, & fReference); // Command를 입력 받음 if( iCommand == CMD_RESET) LoopCtrl = CMD_RESET; Nop(); } delay_msecs(50); while( LoopCtrl == CMD_RESET) { get_command( & iCommand, & fReference); // Command를 입력 받음 if( iCommand == CMD_STOP) LoopCtrl = CMD_STOP; Nop(); } for( ; ; ) // system reset { gMachineState = STATE_TRIP; Nop(); asm (" .ref _c_int00"); // ;Branch to start of boot.asm in RTS library asm (" LB _c_int00"); // ;Branch to start of boot.asm in RTS library } }
int SaveDataProc(int addr, double data) { int cmd,i,return_value; char SciBuf[30]={0}; char str[30]; UNION32 u32data,u32data2; return_value = 0; cmd = CMD_READ_DATA; i = get_code_information( addr,cmd,&code_inform); if( i != 0 ) goto _SAVE_ERROR_INVALID_ADDR; if( addr >= 800 ){ if( data < 1.22 ) goto _SAVE_ERROR_INVALID_DATA; if( data > 1.24 ) goto _SAVE_ERROR_INVALID_DATA; switch(addr) { case CODE_Data_Check: return_value = check_backup_data(); break; case CODE_Data_Backup: strncpy(str,"Wait for Data Backup",20); load_sci_tx_mail_box(str); delay_msecs(20); save_backup_data(); strncpy(str,"Wait for Error Check",20); load_sci_tx_mail_box(str); delay_msecs(20); break; case CODE_Data_Load: strncpy(str,"Wait for Data Load !",20); load_sci_tx_mail_box(str); delay_msecs(20); backup_data_load(); break; case CODE_Data_Init: strncpy(str,"Wait For Data Init !",20); load_sci_tx_mail_box(str); delay_msecs(20); init_eprom_data(); strncpy(str,"Data Init OK ! ",20); load_sci_tx_mail_box(str); delay_msecs(20); break; case CODE_get_adc_offset: get_adc_offset(); break; default: goto _SAVE_ERROR_INVALID_ADDR; } return return_value; } if( code_inform.type == TYPE_INTEGER){ if( (code_inform.code_min.ints) > (int)data ){ goto _SAVE_ERROR_DATA_UNDER; } else if( (code_inform.code_max.ints) < (int)data){ goto _SAVE_ERROR_DATA_OVER; } else { // u32data.word.word1 = 0; u32data.word.word0 = (int)data; read_eprom_data( addr, & u32data2); if( u32data.word.word0 != u32data2.word.word0 ){ write_code_2_eeprom( addr, u32data); read_eprom_data( addr, & u32data2); if( u32data.word.word0 != u32data2.word.word0 ) goto _EEPROM_WRITE_ERROR; code_inform.code_value.ints = (int)data; cmd = CMD_WRITE_RAM; get_code_information( addr,cmd, & code_inform); load_sci_tx_mail_box("OK write success") ; } else{ load_sci_tx_mail_box("Equal Data write skipped"); } return 0; } } else { // code_inform->Type == TYPE_DOUBLE if( ( code_inform.code_min.doubles) > data ){ goto _SAVE_ERROR_DATA_UNDER; } else if( ( code_inform.code_max.doubles) < data ){ goto _SAVE_ERROR_DATA_OVER; } else { u32data.dword = data; read_eprom_data( addr, & u32data2); if( u32data.dword != u32data2.dword ){ write_code_2_eeprom( addr, u32data); read_eprom_data( addr, & u32data2); if( u32data.dword != u32data2.dword ) goto _EEPROM_WRITE_ERROR; code_inform.code_value.doubles = data; cmd = CMD_WRITE_RAM; get_code_information( addr,cmd, & code_inform); // CheckSum Save u32data.dword = CheckSum(); EepromSaveFlag = 1; write_code_2_eeprom(EPROM_ADDR_CHECKSUM, u32data); EepromSaveFlag = 0; load_sci_tx_mail_box("OK write success") ; } else{ load_sci_tx_mail_box("Equal Data write skipped"); } return 0; } } _SAVE_ERROR_INVALID_ADDR: // strcpy(SciBuf, "ADDR"); strcpy(SciBuf,"Invalid Address" ); load_sci_tx_mail_box(SciBuf) ; return -1; _SAVE_ERROR_DATA_UNDER: // strcpy(SciBuf, "UNDE"); strcpy(SciBuf,"Input data under" ); load_sci_tx_mail_box(SciBuf) ; return -1; _SAVE_ERROR_DATA_OVER: // strcpy(SciBuf, "OVER"); strcpy(SciBuf,"Input data over" ); load_sci_tx_mail_box(SciBuf) ; return -1; _SAVE_ERROR_INVALID_DATA: // strcpy(SciBuf, "DATA"); strcpy(SciBuf,"Invalid data " ); load_sci_tx_mail_box(SciBuf) ; return -1; _EEPROM_WRITE_ERROR: // strcpy(SciBuf, "DATA"); strcpy(SciBuf,"Eeprom write error" ); load_sci_tx_mail_box(SciBuf) ; return -1; }
/***** * DoTest_Characterize() - Perform the Characterization test * * This function starts the duty cycle at the minimum duty cycle and * then increases it to the max duty cycle for the test. * Samples are collected into the global array sample[]. * The function toggles the TEST_RUNNING signal high for the duration * of the test as a debug aid and adjusts the global "pwm_duty" * * The test also sets the global ADC min and max counts to * help limit the ADC counts to the active range for the circuit *****/ int DoTest_Characterize(void) { XStatus Status; // Xilinx return status unsigned tss; // starting timestamp u16 adc_1, adc_2; // holds the ADC count - sampled twice and averaged u16 adc_cnt; // ADC counts to display int n; // number of samples Xuint32 freq, dutyfactor; // current frequency and duty factor // stabilize the PWM output (and thus the lamp intensity) at the // minimum before starting the test pwm_duty = PWM_STEPDC_MIN; Status = PWM_SetParams(&PWMTimerInst, pwm_freq, pwm_duty); if (Status == XST_SUCCESS) { PWM_Start(&PWMTimerInst); } else { return -1; } delay_msecs(1000); // sweep the duty cycle from STEPDC_MIN to STEPDC_MAX smpl_idx = PWM_STEPDC_MIN; n = 0; tss = timestamp; while (smpl_idx <= PWM_STEPDC_MAX) { Status = PWM_SetParams(&PWMTimerInst, pwm_freq, smpl_idx); if (Status == XST_SUCCESS) { PWM_Start(&PWMTimerInst); } else { return -1; } // sample the ADC twice and average the readings adc_1 = PmodCtlSys_readADC(&SPIInst); delay_msecs(1); adc_2 = PmodCtlSys_readADC(&SPIInst); adc_cnt = (adc_1 + adc_2) / 2; sample[smpl_idx++] = adc_cnt; n++; delay_msecs(20); } adc_smple_interval = (timestamp - tss) / smpl_idx; // initialize the ADC min and max counts from the saved data ADC_min_cnt = ADC_max_cnt = 0; for (n = PWM_STEPDC_MIN; n <= PWM_STEPDC_MAX; n++) { if (sample[n] < ADC_min_cnt) ADC_min_cnt = sample[n]; if (sample[n] > ADC_max_cnt) ADC_max_cnt = sample[n]; } ADC_max_vout = PmodCtlSys_ADCVolts(ADC_min_cnt); ADC_min_vout = PmodCtlSys_ADCVolts(ADC_max_cnt); // initialize the PWM min and max counts - these are constants so can be calculated here // count = ((pwm duty cycle * PLB clock frequency[Hz]) / pwm frequency[Hz]) - 2 PWM_GetParams(&PWMTimerInst, &freq, &dutyfactor); PWM_min_cnt = ((PWM_STEPDC_MIN * .01 * PLB_CLOCK_FREQ_HZ) / freq) - 2; PWM_max_cnt = ((PWM_STEPDC_MAX * .01 * PLB_CLOCK_FREQ_HZ) / freq) - 2; return n; }
int main() { XStatus Status; u32 btnsw = 0x00000000, old_btnsw = 0x000000FF; int rotcnt, old_rotcnt = 0x1000; Test_t test, next_test; is_scaled = false; bool lcd_initial = true; char sp[20]; u16 row = 1; u16 col = 2; bool calc_done = false; freq_min_cnt = 3000; // initialize devices and set up interrupts, etc. Status = do_init(); if (Status != XST_SUCCESS) { LCD_setcursor(1,0); LCD_wrstring("****** ERROR *******"); LCD_setcursor(2,0); LCD_wrstring("INIT FAILED- EXITING"); exit(XST_FAILURE); } // initialize the variables timestamp = 0; pwm_freq = PWM_FREQUENCY; next_test = TEST_INVALID; prop_gain = PROP_INIT_GAIN; integral_gain = INT_INIT_GAIN; deriv_gain = DERIV_INIT_GAIN; // Enable the Microblaze caches and kick off the processing by enabling the Microblaze // interrupt. This starts the FIT timer which updates the timestamp. if (USE_ICACHE == 1) { microblaze_invalidate_icache(); microblaze_enable_icache(); } if (USE_DCACHE == 1) { microblaze_invalidate_dcache(); microblaze_enable_dcache(); } microblaze_enable_interrupts(); // display the greeting LCD_setcursor(1,0); LCD_wrstring("PWM Ctrl sys"); LCD_setcursor(2,0); LCD_wrstring("Erik R, Caren Z"); NX3_writeleds(0xFF); //delay_msecs(2500); LCD_clrd(); LCD_setcursor(1,0); LCD_wrstring("Characterizing.."); //Run the LED characterization routine to establish sensor min's and max's DoTest_Characterize(); LCD_setcursor(2,0); LCD_wrstring("Done."); NX3_writeleds(0x00); delay_msecs(500); //set initial screen // main loop - there is no exit except by hardware reset while (1) { //set Vin to min or max depending on switch 3 value if (btnsw & msk_SWITCH3) { pwm_duty = MAX_DUTY; dc_start = MAX_DUTY; } else { pwm_duty = MIN_DUTY; dc_start = MIN_DUTY; } // Write values to display when in "idle" state if (lcd_initial) { LCD_clrd(); LCD_setcursor(1,0); LCD_wrstring("P: I: D: "); LCD_setcursor(1,2); LCD_setcursor(2,0); LCD_wrstring("SP:+ OFF: "); lcd_initial = false; LCD_setcursor(1,2); } no_test_LCD(); NX3_readBtnSw(&btnsw); // Set which control measurement we're using if (btnsw & msk_BTN_NORTH) { // increment to the next selection. If we're at the last enum, set it to the 1st (proportional) if (PID_current_sel == OFFSET) PID_current_sel = PROPORTIONAL; else PID_current_sel = (Control_t)((int)(PID_current_sel+1)); //casting to allow increment // cursor control logic if (PID_current_sel == PROPORTIONAL) { row = 1; col = 2; } else if (PID_current_sel == INTEGRAL) { row = 1; col = 7; } else if (PID_current_sel == DERIVATIVE) { row = 1; col = 12; } else if (PID_current_sel == OFFSET) { row = 2; col = 13; } } delay_msecs(20); //set cursor location and turn on cursor LCD_setcursor(row,col); LCD_docmd(LCD_DISPLAYONOFF, LCD_CURSOR_ON); if (btnsw & msk_BTN_EAST) { if (PID_current_sel == PROPORTIONAL) prop_gain += GAIN_INCREMENT; else if (PID_current_sel == INTEGRAL) integral_gain += GAIN_INCREMENT; else if (PID_current_sel == DERIVATIVE) deriv_gain += GAIN_INCREMENT; else offset += GAIN_INCREMENT; } if (btnsw & msk_BTN_WEST) { if (PID_current_sel == PROPORTIONAL) prop_gain -= GAIN_INCREMENT; else if (PID_current_sel == INTEGRAL) integral_gain -= GAIN_INCREMENT; else if (PID_current_sel == DERIVATIVE) deriv_gain -= GAIN_INCREMENT; else offset -= GAIN_INCREMENT; } // read sw[1:0] to get the test to perform. NX3_readBtnSw(&btnsw); test = btnsw & (msk_SWITCH1 | msk_SWITCH0); ROT_readRotcnt(&rotcnt); if (rotcnt != old_rotcnt) { //scale rotary count to setpoint values LCD_docmd(LCD_DISPLAYONOFF, LCD_CURSOR_OFF); setpoint = MAX(VOLT_MIN, MIN((rotcnt/SETPOINT_SCALE), VOLT_MAX)); voltstostrng(setpoint, sp); old_rotcnt = rotcnt; LCD_setcursor(2, 3); LCD_wrstring(sp); LCD_setcursor(2, 3); LCD_wrstring('+'); } if (test == TEST_T_CALLS) //unused { next_test = TEST_INVALID; lcd_initial = true; delay_msecs(3000); } else if ((test == TEST_BANG ) || (test == TEST_PID)) // Test 1 & 2 - control methods Bang Bang and PID { Xfloat32 v; char s[20]; // start the test on the rising edge of the Rotary Encoder button press // the test will write the light detector samples into the global "sample[]" // the samples will be sent to stdout when the Rotary Encoder button // is released // // NOTE ON DETECTING BUTTON CHANGES: // btnsw ^ old_btnsw will set the bits for all of the buttons and switches that // have changed state since the last time the buttons and switches were read // msk_BTN_ROT & btnsw will test whether the rotary encoder was one of the // buttons that changed from 0 -> 1 if ((btnsw ^ old_btnsw) && (msk_BTN_ROT & btnsw)) // do the step test and dump data { /*Running Test (rotary pushbutton pushed): Show which control algorithm is running and display instructions for running test and uploading data.*/ if (test != next_test) { if (test == TEST_BANG) { strcpy(s, "|BANG|Long Press"); } else { strcpy(s, "|PID|Long Press"); } delay_msecs(100); LCD_clrd(); LCD_setcursor(1,0); LCD_wrstring(s); LCD_setcursor(2,0); LCD_wrstring("RotBtn to start"); } NX3_writeleds(0x01); if (test == TEST_BANG) // perform bang bang calculations { calc_bang(); } else // perform PID tests { calc_PID(); } NX3_writeleds(0x00); //FEATURE: wait for user input to send data over NX3_readBtnSw(&btnsw); if ((btnsw ^ old_btnsw) && (msk_BTN_ROT & btnsw)) { // light "Transfer" LED to indicate that data is being transmitted // Show the traffic on the LCD NX3_writeleds(0x02); LCD_clrd(); LCD_setcursor(1, 0); LCD_wrstring("Sending Data...."); LCD_setcursor(2, 0); LCD_wrstring("S: DATA: "); // print the descriptive heading followed by the data if (test == TEST_BANG) { xil_printf("\n\rBang Bang! Test Data\t\tAppx. Sample Interval: %d msec\n\r", frq_smple_interval); } else { xil_printf("\n\rPID Test Data\t\tAppx. Sample Interval: %d msec\n\r", frq_smple_interval); } // trigger the serial charter program) xil_printf("===STARTPLOT===\n"); // start with the second sample. The first sample is not representative of // the data. This will pretty-up the graph a bit for (smpl_idx = 1; smpl_idx < NUM_FRQ_SAMPLES; smpl_idx++) { u16 count; count = sample[smpl_idx]; if (count > 4096) count = 4095; v = (-3.3 / 4095.0) * (count) + 3.3; voltstostrng(v, s); xil_printf("%d\t%d\t%s\n\r", smpl_idx, count, s); LCD_setcursor(2, 2); LCD_wrstring(" "); LCD_setcursor(2, 2); LCD_putnum(smpl_idx, 10); LCD_setcursor(2, 11); LCD_wrstring(" "); LCD_setcursor(2, 11); LCD_putnum(count, 10); } // stop the serial charter program xil_printf("===ENDPLOT===\n"); NX3_writeleds(0x00); old_btnsw = btnsw; next_test = TEST_INVALID; lcd_initial = true; delay_msecs(3000); } } // do the step test and dump data } else if (test == TEST_CHARACTERIZE) // Test 3 - Characterize Response { // start the test on the rising edge of the Rotary Encoder button press // the test will write the samples into the global "sample[]" // the samples will be sent to stdout when the Rotary Encoder button // is released NX3_readBtnSw(&btnsw); if ((btnsw ^ old_btnsw) && (msk_BTN_ROT & btnsw)) { LCD_docmd(LCD_DISPLAYONOFF, LCD_CURSOR_OFF); // light "Run" (rightmost) LED to show the test has begun // and do the test. The test will return when the measured samples array // has been filled. Turn off the rightmost LED after the data has been if (test != next_test) { LCD_clrd(); LCD_setcursor(1,0); LCD_wrstring("|CHAR|Long Press"); LCD_setcursor(2,0); LCD_wrstring("RotBtn to start"); } // captured to let the user know he/she can release the button NX3_readBtnSw(&btnsw); if ((msk_BTN_ROT & btnsw) && (!calc_done)) { NX3_writeleds(0x01); LCD_clrd(); LCD_setcursor(1,0); LCD_wrstring("Characterizing.."); DoTest_Characterize(); LCD_setcursor(2,0); LCD_wrstring("Done."); NX3_writeleds(0x00); delay_msecs(750); LCD_setcursor(2,8); LCD_wrstring("<OK>"); calc_done = true; next_test = test; } NX3_readBtnSw(&btnsw); if (msk_BTN_ROT & btnsw) { // light "Transfer" LED to indicate that data is being transmitted // Show the traffic on the LCD NX3_writeleds(0x02); LCD_clrd(); LCD_setcursor(1, 0); LCD_wrstring("Sending Data...."); LCD_setcursor(2, 0); LCD_wrstring("S: DATA: "); xil_printf("\n\rCharacterization Test Data\t\tAppx. Sample Interval: %d msec\n\r", frq_smple_interval); // trigger the serial charter program) xil_printf("===STARTPLOT===\n\r"); for (smpl_idx = STEPDC_MIN; smpl_idx <= STEPDC_MAX; smpl_idx++) { u16 count; Xfloat32 v; char s[10]; count = sample[smpl_idx]; if (count > 4096) count = 4095; v = (-3.3 / 4095.0) * (count) + 3.3; voltstostrng(v, s); xil_printf("%d\t%d\t%s\n\r", smpl_idx, count, s); LCD_setcursor(2, 2); LCD_wrstring(" "); LCD_setcursor(2, 2); LCD_putnum(smpl_idx, 10); LCD_setcursor(2, 11); LCD_wrstring(" "); LCD_setcursor(2, 11); LCD_putnum(count, 10); } // stop the serial charter program xil_printf("===ENDPLOT===\n\r"); NX3_writeleds(0x00); old_btnsw = btnsw; next_test = TEST_INVALID; delay_msecs(1000); lcd_initial = true; delay_msecs(3000); } } // do the step test and dump data } // Test 3 - Characterize Response else // outside the current test range - blink LED's and hang { // should never get here but just in case NX3_writeleds(0xFF); delay_msecs(2000); NX3_writeleds(0x00); } // wait a bit and start again delay_msecs(100); } // while(1) loop } // end main()
/***** * DoTest_BB() - Perform Bang-Bang control * * This function adjusts the global "pwm_duty" value to try to bring the * control system simulator closer to the ADC setpoint. The initial state of the PWM * is derived from the global "init_high" flag. NUM_ADC_SAMPLES are collected * into the global array sample[] and the count returned. The function toggles the TEST_RUNNING * signal high for the duration of the test as a debug aid. An approximate * ADC sample interval is written to the global variable "adc_smpl_interval" * * Bang-bang control is the simplest form of closed loop control. The PWM is turned either full-on * of full-off depending on whether the output is below or above the setpoint. * * NOTE: THIS ALGORIHM IS LEFT AS AN EXERCISE FOR THE PROGRAMMER *****/ int DoTest_BB(void) { XStatus Status; // Xilinx return status unsigned tss; // starting timestamp u16 adc_1, adc_2; // holds the ADC count - sampled twice and averaged u16 adc_cnt; // ADC counts to display int n; // number of samples Xfloat32 setpoint_volts, adc_reading_volts; //The initial state of the PWM is derived from the global "init_high" flag. // true if inital state of test should be full-on, false otherwise if (init_high == true) pwm_duty = PWM_STEPDC_MAX; else pwm_duty = PWM_STEPDC_MIN; //Checks Status Status = PWM_SetParams(&PWMTimerInst, pwm_freq, pwm_duty); if (Status == XST_SUCCESS) { PWM_Start(&PWMTimerInst); } else { return -1; } delay_msecs(100); smpl_idx = 0; n = 0; tss = timestamp; //Calculate in volts our setpoint setpoint_volts = PmodCtlSys_ADCVolts(setpoint); ////------------------------------- LCD_clrd(); LCD_setcursor(1, 0); LCD_wrstring("BANG BANG"); while (smpl_idx <= NUM_ADC_SAMPLES) { Status = PWM_SetParams(&PWMTimerInst, pwm_freq, pwm_duty); if (Status == XST_SUCCESS) { PWM_Start(&PWMTimerInst); } else { return -1; } //Sample the ADC and average the readings adc_1 = PmodCtlSys_readADC(&SPIInst); delay_msecs(1); adc_2 = PmodCtlSys_readADC(&SPIInst); adc_cnt = (adc_1 + adc_2) / 2; //Converting the ADC average into volts adc_reading_volts = PmodCtlSys_ADCVolts(adc_cnt); if (adc_reading_volts < setpoint_volts) pwm_duty = PWM_STEPDC_MIN; //input to 100% duty cycle else pwm_duty = PWM_STEPDC_MAX; //CHECK STATUS Status = PWM_SetParams(&PWMTimerInst, pwm_freq, pwm_duty); if (Status == XST_SUCCESS) { PWM_Start(&PWMTimerInst); } else { return -1; } //store in array sample[smpl_idx++] = adc_cnt; n++; } adc_smple_interval = (timestamp - tss) / smpl_idx; return n; }
int main() { XStatus Status; u32 btnsw = 0x00000000, old_btnsw = 0x000000FF; int rotcnt, old_rotcnt = 0x1000; Test_t test, next_test; is_scaled = false; // initialize devices and set up interrupts, etc. Status = do_init(); if (Status != XST_SUCCESS) { LCD_setcursor(1,0); LCD_wrstring("****** ERROR *******"); LCD_setcursor(2,0); LCD_wrstring("INIT FAILED- EXITING"); exit(XST_FAILURE); } // initialize the variables timestamp = 0; pwm_freq = PWM_FREQUENCY; pwm_duty = STEPDC_MIN; next_test = TEST_INVALID; // Enable the Microblaze caches and kick off the processing by enabling the Microblaze // interrupt. This starts the FIT timer which updates the timestamp. if (USE_ICACHE == 1) { microblaze_invalidate_icache(); microblaze_enable_icache(); } if (USE_DCACHE == 1) { microblaze_invalidate_dcache(); microblaze_enable_dcache(); } microblaze_enable_interrupts(); // display the greeting LCD_setcursor(1,0); LCD_wrstring("PmodCtlSys Test "); LCD_setcursor(2,0); LCD_wrstring("R3.0 by Robin M."); NX3_writeleds(0xFF); //Run the LED characterization routine to establish sensor min's and max's DoTest_Characterize(); NX3_writeleds(0x00); // main loop - there is no exit except by hardware reset while (1) { // read sw[1:0] to get the test to perform. NX3_readBtnSw(&btnsw); test = btnsw & (msk_SWITCH1 | msk_SWITCH0); if (test == TEST_TRACKING) // Test 0 = Track PWM voltage { // write the static info to display if necessary if (test != next_test) { LCD_clrd(); LCD_setcursor(1,0); LCD_wrstring("| TRK| Vi: sx.xx"); LCD_setcursor(2,0); LCD_wrstring("Vo:sx.xx C:sxxxx"); } // read rotary count and handle duty cycle changes // limit duty cycle to between STEPDC_MIN and STEPDC_MAX // PWM frequency does not change in this test ROT_readRotcnt(&rotcnt); if (rotcnt != old_rotcnt) { pwm_duty = MAX(STEPDC_MIN, MIN(rotcnt, STEPDC_MAX)); old_rotcnt = rotcnt; } DoTest_Track(); next_test = TEST_TRACKING; } // Test 0 = Track PWM voltage else if ((test == TEST_STEPHILO) || (test == TEST_STEPLOHI)) // Test 1 & 2 - Step response { Xfloat32 v; char s[20]; // write the static info to the display if necessary if (test != next_test) { if (test == TEST_STEPHILO) { strcpy(s, "|HILO|Press RBtn"); } else { strcpy(s, "|LOHI|Press RBtn"); } LCD_clrd(); LCD_setcursor(1,0); LCD_wrstring(s); LCD_setcursor(2,0); LCD_wrstring("LED OFF-Release "); } // start the test on the rising edge of the Rotary Encoder button press // the test will write the light detector samples into the global "sample[]" // the samples will be sent to stdout when the Rotary Encoder button // is released // // NOTE ON DETECTING BUTTON CHANGES: // btnsw ^ old_btnsw will set the bits for all of the buttons and switches that // have changed state since the last time the buttons and switches were read // msk_BTN_ROT & btnsw will test whether the rotary encoder was one of the // buttons that changed from 0 -> 1 if ((btnsw ^ old_btnsw) && (msk_BTN_ROT & btnsw)) // do the step test and dump data { // light "Run" (rightmost) LED to show the test has begun // and do the test. The test will return when the measured samples array // has been filled. Turn off the rightmost LED after the data has been // captured to let the user know he/she can release the button NX3_writeleds(0x01); if (test == TEST_STEPHILO) // perform High->Low step test { DoTest_Step(STEPDC_MAX); } else // perform Low->High step { DoTest_Step(STEPDC_MIN); } NX3_writeleds(0x00); // wait for the Rotary Encoder button to be released // and then send the sample data to stdout do { NX3_readBtnSw(&btnsw); delay_msecs(10); } while ((btnsw & msk_BTN_ROT) == 0x80); // light "Transfer" LED to indicate that data is being transmitted // Show the traffic on the LCD NX3_writeleds(0x02); LCD_clrd(); LCD_setcursor(1, 0); LCD_wrstring("Sending Data...."); LCD_setcursor(2, 0); LCD_wrstring("S: DATA: "); // print the descriptive heading followed by the data if (test == TEST_STEPHILO) { xil_printf("\n\rHigh->Low Test Data\t\tAppx. Sample Interval: %d msec\n\r", frq_smple_interval); } else { xil_printf("\n\rLow->High Test Data\t\tAppx. Sample Interval: %d msec\n\r", frq_smple_interval); } // trigger the serial charter program) xil_printf("===STARTPLOT===\n"); // start with the second sample. The first sample is not representative of // the data. This will pretty-up the graph a bit for (smpl_idx = 1; smpl_idx < NUM_FRQ_SAMPLES; smpl_idx++) { u16 count; count = sample[smpl_idx]; //ECE544 Students: //Convert from count to 'volts' v = LIGHTSENSOR_Count2Volts(count); voltstostrng(v, s); xil_printf("%d\t%d\t%s\n\r", smpl_idx, count, s); LCD_setcursor(2, 2); LCD_wrstring(" "); LCD_setcursor(2, 2); LCD_putnum(smpl_idx, 10); LCD_setcursor(2, 11); LCD_wrstring(" "); LCD_setcursor(2, 11); LCD_putnum(count, 10); } // stop the serial charter program xil_printf("===ENDPLOT===\n"); NX3_writeleds(0x00); old_btnsw = btnsw; next_test = TEST_INVALID; } // do the step test and dump data else { next_test = test; } } // Test 1 & 2 - Step response else if (test == TEST_CHARACTERIZE) // Test 3 - Characterize Response { if (test != next_test) { LCD_clrd(); LCD_setcursor(1,0); LCD_wrstring("|CHAR|Press RBtn"); LCD_setcursor(2,0); LCD_wrstring("LED OFF-Release "); } // start the test on the rising edge of the Rotary Encoder button press // the test will write the samples into the global "sample[]" // the samples will be sent to stdout when the Rotary Encoder button // is released if ((btnsw ^ old_btnsw) && (msk_BTN_ROT & btnsw)) // do the step test and dump data { // light "Run" (rightmost) LED to show the test has begun // and do the test. The test will return when the measured samples array // has been filled. Turn off the rightmost LED after the data has been // captured to let the user know he/she can release the button NX3_writeleds(0x01); DoTest_Characterize(); NX3_writeleds(0x00); // wait for the Rotary Encoder button to be released // and then send the sample data to stdout do { NX3_readBtnSw(&btnsw); delay_msecs(10); } while ((btnsw & msk_BTN_ROT) == 0x80); // light "Transfer" LED to indicate that data is being transmitted // Show the traffic on the LCD NX3_writeleds(0x02); LCD_clrd(); LCD_setcursor(1, 0); LCD_wrstring("Sending Data...."); LCD_setcursor(2, 0); LCD_wrstring("S: DATA: "); xil_printf("\n\rCharacterization Test Data\t\tAppx. Sample Interval: %d msec\n\r", frq_smple_interval); // trigger the serial charter program) xil_printf("===STARTPLOT===\n\r"); for (smpl_idx = STEPDC_MIN; smpl_idx <= STEPDC_MAX; smpl_idx++) { u16 count; Xfloat32 v; char s[10]; count = sample[smpl_idx]; //ECE544 Students: //Convert from count to 'volts' v = LIGHTSENSOR_Count2Volts((Xuint32)count); voltstostrng(v, s); xil_printf("%d\t%d\t%s\n\r", smpl_idx, count, s); LCD_setcursor(2, 2); LCD_wrstring(" "); LCD_setcursor(2, 2); LCD_putnum(smpl_idx, 10); LCD_setcursor(2, 11); LCD_wrstring(" "); LCD_setcursor(2, 11); LCD_putnum(count, 10); } // stop the serial charter program xil_printf("===ENDPLOT===\n\r"); NX3_writeleds(0x00); old_btnsw = btnsw; next_test = TEST_INVALID; } // do the step test and dump data else { next_test = test; } } // Test 3 - Characterize Response else // outside the current test range - blink LED's and hang { // should never get here but just in case NX3_writeleds(0xFF); delay_msecs(2000); NX3_writeleds(0x00); } // wait a bit and start again delay_msecs(100); } // while(1) loop } // end main()
int main() { XStatus status; u16 sw, oldSw =0xFFFF; // 0xFFFF is invalid --> makes sure the PWM freq is updated 1st time int rotcnt, oldRotcnt = 0x1000; bool done = false; bool hw_switch = 0; init_platform(); // initialize devices and set up interrupts, etc. status = do_init(); if (status != XST_SUCCESS) { PMDIO_LCD_setcursor(1,0); PMDIO_LCD_wrstring("****** ERROR *******"); PMDIO_LCD_setcursor(2,0); PMDIO_LCD_wrstring("INIT FAILED- EXITING"); exit(XST_FAILURE); } // initialize the global variables timestamp = 0; pwm_freq = INITIAL_FREQUENCY; pwm_duty = INITIAL_DUTY_CYCLE; clkfit = 0; new_perduty = false; // start the PWM timer and kick of the processing by enabling the Microblaze interrupt PWM_SetParams(&PWMTimerInst, pwm_freq, pwm_duty); PWM_Start(&PWMTimerInst); microblaze_enable_interrupts(); // display the greeting PMDIO_LCD_setcursor(1,0); PMDIO_LCD_wrstring("ECE544 Project 1"); PMDIO_LCD_setcursor(2,0); PMDIO_LCD_wrstring(" by Rehan Iqbal "); NX4IO_setLEDs(0x0000FFFF); delay_msecs(2000); NX4IO_setLEDs(0x00000000); // write the static text to the display PMDIO_LCD_clrd(); PMDIO_LCD_setcursor(1,0); PMDIO_LCD_wrstring("G|FR: DCY: %"); PMDIO_LCD_setcursor(2,0); PMDIO_LCD_wrstring("D|FR: DCY: %"); // turn off the LEDs and clear the seven segment display NX4IO_setLEDs(0x00000000); NX410_SSEG_setAllDigits(SSEGLO, CC_BLANK, CC_BLANK, CC_BLANK, CC_BLANK, DP_NONE); NX410_SSEG_setAllDigits(SSEGHI, CC_BLANK, CC_BLANK, CC_BLANK, CC_BLANK, DP_NONE); // main loop do { // check rotary encoder pushbutton to see if it's time to quit if (PMDIO_ROT_isBtnPressed()) { done = true; } else { new_perduty = false; // get the switches and mask out all but the switches that determine the PWM timer frequency sw &= PWM_FREQ_MSK; sw = NX4IO_getSwitches(); if (sw != oldSw) { // check the status of sw[2:0] and assign appropriate PWM output frequency switch (sw & 0x07) { case 0x00: pwm_freq = PWM_FREQ_100HZ; break; case 0x01: pwm_freq = PWM_FREQ_1KHZ; break; case 0x02: pwm_freq = PWM_FREQ_10KHZ; break; case 0x03: pwm_freq = PWM_FREQ_50KHZ; break; case 0x04: pwm_freq = PWM_FREQ_100KHZ; break; case 0x05: pwm_freq = PWM_FREQ_500KHZ; break; case 0x06: pwm_freq = PWM_FREQ_1MHZ; break; case 0x07: pwm_freq = PWM_FREQ_5MHZ; break; } // check the status of sw[3] and assign to global variable hw_switch = (sw & 0x08); // update global variable indicating there are new changes oldSw = sw; new_perduty = true; } // read rotary count and handle duty cycle changes // limit duty cycle to 0% to 99% PMDIO_ROT_readRotcnt(&rotcnt); if (rotcnt != oldRotcnt) { // show the rotary count in hex on the seven segment display NX4IO_SSEG_putU16Hex(SSEGLO, rotcnt); // change the duty cycle pwm_duty = MAX(1, MIN(rotcnt, 99)); oldRotcnt = rotcnt; new_perduty = true; } // update generated frequency and duty cycle if (new_perduty) { u32 freq, dutycycle; unsigned int detect_freq = 0x00; unsigned int detect_duty = 0x00; // set the new PWM parameters - PWM_SetParams stops the timer status = PWM_SetParams(&PWMTimerInst, pwm_freq, pwm_duty); if (status == XST_SUCCESS) { PWM_GetParams(&PWMTimerInst, &freq, &dutycycle); update_lcd(freq, dutycycle, 1); // check if sw[3] is high or low (HWDET / SWDET) // pass functions different args depending on which mode is selected if (hw_switch) { detect_freq = calc_freq(hw_high_count, hw_low_count, hw_switch); detect_duty = calc_duty(hw_high_count, hw_low_count); } else { detect_freq = calc_freq(sw_high_count, sw_low_count, hw_switch); detect_duty = calc_duty(sw_high_count, sw_low_count); } // update the LCD display with detected frequency & duty cycle update_lcd(detect_freq, detect_duty, 2); PWM_Start(&PWMTimerInst); } } } } while (!done); // wait until rotary encoder button is released do { delay_msecs(10); } while (PMDIO_ROT_isBtnPressed()); // we're done, say goodbye xil_printf("\nThat's All Folks!\n\n"); PMDIO_LCD_setcursor(1,0); PMDIO_LCD_wrstring("That's All Folks"); PMDIO_LCD_setcursor(2,0); PMDIO_LCD_wrstring(" "); NX410_SSEG_setAllDigits(SSEGHI, CC_BLANK, CC_B, CC_LCY, CC_E, DP_NONE); NX410_SSEG_setAllDigits(SSEGLO, CC_B, CC_LCY, CC_E, CC_BLANK, DP_NONE); delay_msecs(5000); // turn the lights out PMDIO_LCD_clrd(); NX410_SSEG_setAllDigits(SSEGHI, CC_BLANK, CC_BLANK, CC_BLANK, CC_BLANK, DP_NONE); NX410_SSEG_setAllDigits(SSEGLO, CC_BLANK, CC_BLANK, CC_BLANK, CC_BLANK, DP_NONE); NX4IO_RGBLED_setDutyCycle(RGB1, 0, 0, 0); NX4IO_RGBLED_setChnlEn(RGB1, false, false, false); // exit gracefully cleanup_platform(); exit(0); }
/***** * DoTest_Characterize() - Perform the Characterization test * * This function starts the duty cycle at the minimum duty cycle and * then sweeps it to the max duty cycle for the test. * Samples are collected into the global array sample[]. * The function toggles the TEST_RUNNING signal high for the duration * of the test as a debug aid and adjusts the global "pwm_duty" * * The test also sets the global frequency count min and max counts to * help limit the counts to the active range for the circuit *****/ XStatus DoTest_Characterize(void) { XStatus Status; // Xilinx return status unsigned tss; // starting timestamp int n; // number of samples Xuint32 freq_max_cnt = 1000; int i = 0; double diff = 0; // stabilize the PWM output (and thus the lamp intensity) at the // minimum before starting the test pwm_duty = STEPDC_MIN; Status = PWM_SetParams(&PWMTimerInst, pwm_freq, pwm_duty); if (Status == XST_SUCCESS) { PWM_Start(&PWMTimerInst); } else { return -1; } //Wait for the LED output to settle before starting delay_msecs(1500); // sweep the duty cycle from STEPDC_MIN to STEPDC_MAX smpl_idx = STEPDC_MIN; n = 0; tss = timestamp; while (smpl_idx <= STEPDC_MAX) { Status = PWM_SetParams(&PWMTimerInst, pwm_freq, smpl_idx); if (Status == XST_SUCCESS) { PWM_Start(&PWMTimerInst); } else { return -1; } sample[smpl_idx++] = LIGHTSENSOR_Capture(LIGHTSENSOR_BASEADDR, slope, offset, is_scaled, freq_min_cnt); n++; delay_msecs(50); } frq_smple_interval = (timestamp - tss) / smpl_idx; //Find min and max values to set scaling for (i = 1; i < STEPDC_MAX ; i++) { if (sample[i] < freq_min_cnt) { freq_min_cnt = sample[i]; } if (sample[i] > freq_max_cnt) { freq_max_cnt = sample[i]; } } // Send min and max to set scaling and calculate slope and offset diff = freq_max_cnt - freq_min_cnt; slope = 4095.0 / diff; is_scaled = true; return n; }
/***** * DoTest_PID() - Perform PID control and it's derivitives * * This function adjusts the global "pwm_duty", "offset" and gains (GP, GI, GD) values to try to * bring the control system simulator close to the ADC setpoint. The initial state of the PWM * is derived from the global "init_high" flag. NUM_ADC_SAMPLES are collected * into the global array sample[] and the count returned. The function toggles the TEST_RUNNING * signal high for the duration of the test as a debug aid. An approximate * ADC sample interval is written to the global variable "adc_smpl_interval" * * PID control provides finer control over the control input than that offered by Bang-bang control. * The biggest contributor to the control input is a value proportional to the distance between the * setpoint and the actual point. Integral and Derivitive terms based on the history of the control * system are used to fine tune the control input. * * NOTE: THIS ALGORIHM IS LEFT AS AN EXERCISE TO THE READER *****/ int DoTest_PID(void) { XStatus Status; // Xilinx return status unsigned tss; // starting timestamp u16 adc_1, adc_2; // holds the ADC count - sampled twice and averaged u16 adc_cnt; // ADC counts to display int n; // number of samples Xfloat32 integral, derivative; // integral, derivative terms Xfloat32 error, prev_error; // error and prev error terms Xfloat32 setpoint_volt, currentadc_volt; // Setpoint and ADC count in volts //The initial state of the PWM is derived from the global "init_high" flag. if(init_high) pwm_duty = PWM_STEPDC_MIN; else pwm_duty = PWM_STEPDC_MAX; // Get the PWM status Status = PWM_SetParams(&PWMTimerInst, pwm_freq, pwm_duty); if(Status == XST_SUCCESS) PWM_Start(&PWMTimerInst); else return -1; delay_msecs(1000); integral = 0; derivative = 0; prev_error = 0; smpl_idx = 0; n = 0; tss = timestamp; setpoint_volt = PmodCtlSys_ADCVolts(setpoint); while (smpl_idx <= NUM_ADC_SAMPLES) { // sample ADC twice and average the readings adc_1=PmodCtlSys_readADC(&SPIInst); delay_msecs(1); adc_2=PmodCtlSys_readADC(&SPIInst); adc_cnt = (adc_1 + adc_2) / 2; currentadc_volt = PmodCtlSys_ADCVolts( adc_cnt + offset); // calculate error: Negate the value to avoid -ve PID control parameters error = currentadc_volt - setpoint_volt; derivative = error - prev_error; prev_error = error; if (abs(error) < setpoint_volt/10) integral += error; else integral = 0; pwm_duty = (int)((error*GP) + (integral *GI) + (derivative*GD)); // Set the duty cycle based on the calculated value if (pwm_duty < PWM_STEPDC_MIN) pwm_duty = PWM_STEPDC_MIN; else if (pwm_duty > PWM_STEPDC_MAX) pwm_duty = PWM_STEPDC_MIN; Status = PWM_SetParams(&PWMTimerInst, pwm_freq, pwm_duty); if (Status == XST_SUCCESS) PWM_Start(&PWMTimerInst); else return -1; sample[smpl_idx++] = adc_cnt; n++; delay_msecs(5); } adc_smple_interval = (timestamp - tss) / smpl_idx; return n; }
int main() { XStatus Status; u32 btnsw = 0x00000000, old_btnsw = 0x000000FF, diff_btnsw; u32 leds; int rotcnt, old_rotcnt; Test_t test; ParamSel_t param_select; bool wrlcd_dynamic; bool wrlcd_static; // initialize devices and set up interrupts, etc. Status = do_init(); if (Status != XST_SUCCESS) { LCD_setcursor(1, 0); LCD_wrstring("****** ERROR *******"); LCD_setcursor(2, 0); LCD_wrstring("INIT FAILED- EXITING"); exit(XST_FAILURE); } // initialize the global variables timestamp = 0; pwm_freq = PWM_FREQUENCY_HZ; pwm_duty = PWM_STEPDC_MIN; // initialize the local variables btnsw = 0x00; old_btnsw = 0x00; rotcnt = 0; old_rotcnt = 0; param_select = SLCT_GP; wrlcd_dynamic = true; wrlcd_static = true; leds = LEDS_ALLOFF; _prev_button_down_count = 0; // Enable the Microblaze caches and // kick off the processing by enabling the Microblaze interrupt // this starts the FIT timer which updates the timestamp. if (USE_ICACHE == 1) { microblaze_invalidate_icache(); microblaze_enable_icache(); } if (USE_DCACHE == 1) { microblaze_invalidate_dcache(); microblaze_enable_dcache(); } microblaze_enable_interrupts(); // display the greeting LCD_setcursor(1, 0); LCD_wrstring("ECE544 Project 2"); LCD_setcursor(2, 0); LCD_wrstring("Starter App-R5.0"); NX3_writeleds(LEDS_ALLON); delay_msecs(2000); NX3_writeleds(LEDS_ALLOFF); // Set the PWM and ADC min and max counts by forcing a characterization LCD_clrd(); LCD_setcursor(1, 0); LCD_wrstring("Characterizing.."); DoTest_Characterize(); LCD_setcursor(2, 0); LCD_wrstring("...Done "); //*****GAIN AND OFFSET ARE HARDWIRED IN THE STARTER APP ***** // initialize the control parameters // start the set point in the middle of the range setpoint = (ADC_max_cnt - ADC_min_cnt) / 2; offset = 100; GP = 10; GD = 5; GI = 5; init_high = false; //*****GAIN AND OFFSET ARE HARDWIRED IN THE STARTER APP ***** // main loop - there is no exit except by hardware reset while (1) { // write static portion of output to display if (wrlcd_static) { LCD_clrd(); LCD_setcursor(1, 0); LCD_wrstring("G|Pxxx Ixxx Dxxx"); LCD_setcursor(2, 0); LCD_wrstring("SP:+x.xx OFF:xxx"); wrlcd_static = false; } // write the dynamic portion of output to display if (wrlcd_dynamic) { Xfloat32 v; u16 count; char s[20]; u32 row, col; // display GP, GI, and GD LCD_setcursor(1, 3); LCD_wrstring(" "); LCD_setcursor(1, 3); LCD_putnum(GP, 10); LCD_setcursor(1, 8); LCD_wrstring(" "); LCD_setcursor(1, 8); LCD_putnum(GI, 10); LCD_setcursor(1, 13); LCD_wrstring(" "); LCD_setcursor(1, 13); LCD_putnum(GD, 10); LCD_setcursor(2, 13); LCD_wrstring(" "); LCD_setcursor(2, 13); LCD_putnum(offset, 10); // display the setpoint in volts count = setpoint; v = PmodCtlSys_ADCVolts(count); voltstostrng(v, s); LCD_setcursor(2, 3); LCD_wrstring(" "); LCD_setcursor(2, 3); LCD_wrstring(s); // place the cursor under the currently selected parameter LCD_docmd(LCD_DISPLAYONOFF, LCD_CURSOR_OFF); switch (param_select) { case SLCT_OFFSET: row = 2; col = 13; break; case SLCT_GP: row = 1; col = 3; break; case SLCT_GD: row = 1; col = 13; break; case SLCT_GI: row = 1; col = 8; break; case SLCT_INVALID: break; } if (param_select != SLCT_INVALID) { LCD_setcursor(row, col); LCD_docmd(LCD_DISPLAYONOFF, LCD_CURSOR_ON); } wrlcd_dynamic = false; } // read switches and buttons to get the test to perform and its initial value // display the selected test on the LEDs NX3_readBtnSw(&btnsw); init_high = (btnsw & SW_INIT_HILO) ? true : false; test = btnsw & SW_TEST_SELECT; //update the HI/LO and TEST LEDs leds &= ~(LEDS_HILO | LEDS_TEST); leds |= (init_high == true) ? LEDS_HILO : 0; leds |= test << 3; NX3_writeleds(leds); // read rotary count and handle setpoint changes // accelerate setpoint if speedup threshold has been exceeded // Use MIN and MAX to keep scaled ADC count within range ROT_readRotcnt(&rotcnt); if (rotcnt != old_rotcnt) { if (abs(rotcnt - old_rotcnt) > ROTCNT_SPEEDUP_GATE) { setpoint += (rotcnt - old_rotcnt) * ROTCNT_DELTA * ROTCNT_SPEEDUP_FACTOR; } else { setpoint += (rotcnt - old_rotcnt) * ROTCNT_DELTA; } setpoint = MAX(ADC_min_cnt, MIN(setpoint, ADC_max_cnt)); old_rotcnt = rotcnt; wrlcd_dynamic = true; } // rotary count changed //***** NOTE: User interface handling should go in this section. ***** //***** The starter app just lets the user select the setpoint and ***** //***** run the test selected by the switches ***** // look at the buttons and take action on the rising edge of a button press bool north_button = btnsw & msk_BTN_NORTH; bool east_button = btnsw & msk_BTN_EAST; bool west_button = btnsw & msk_BTN_WEST; bool button_down = north_button || east_button || west_button; if (button_down) { _prev_button_down_count++; if (_prev_button_down_count > 5) _prev_button_down_count = 5; if (north_button) { switch (param_select) { case SLCT_GP: param_select = SLCT_GI; break; case SLCT_GI: param_select = SLCT_GD; break; case SLCT_GD: param_select = SLCT_OFFSET; break; case SLCT_OFFSET: param_select = SLCT_GP; break; } wrlcd_dynamic = true; } if (east_button) { switch (param_select) { case SLCT_GP: GP+=_prev_button_down_count; break; case SLCT_GI: GI+=_prev_button_down_count; break; case SLCT_GD: GD+=_prev_button_down_count; break; case SLCT_OFFSET: offset+=_prev_button_down_count; break; } wrlcd_dynamic = true; } if (west_button) { switch (param_select) { case SLCT_GP: GP-=_prev_button_down_count; break; case SLCT_GI: GI-=_prev_button_down_count; break; case SLCT_GD: GD-=_prev_button_down_count; break; case SLCT_OFFSET: offset-=_prev_button_down_count; break; } wrlcd_dynamic = true; } } else { _prev_button_down_count = 0; } btnsw &= BTN_MSK_ALLBUTTONS; diff_btnsw = (btnsw ^ old_btnsw) & btnsw; old_btnsw = btnsw; if (diff_btnsw & BTN_RUN_XFER) // run a test { Xfloat32 vADC, vSP; // VADC from circuit and Vsetpoint char s1[20], s2[30]; // display and print strings int (*funcPtr)(void); // pointer to test function int n; // number of samples to transfer (returned by test functions) switch (test) // set up for the selected test { case TEST_BB: // Bit Bang control strcpy(s1, "|BB |Press RBtn"); strcpy(s2, "Bit Bang Control Test Data"); funcPtr = DoTest_BB; break; case TEST_PID: // PID control strcpy(s1, "|PID |Press RBtn"); strcpy(s2, "PID Control Test Data"); funcPtr = DoTest_PID; break; case TEST_CHARACTERIZE: // characterize control system simulator strcpy(s1, "|CHAR|Press RBtn"); strcpy(s2, "Characterization Test Data"); funcPtr = DoTest_Characterize; break; default: // no test to run strcpy(s1, ""); strcpy(s2, ""); funcPtr = NULL; break; } // Change the display to indicate that a test will be run LCD_clrd(); LCD_setcursor(1, 0); LCD_wrstring(s1); LCD_setcursor(2, 0); LCD_wrstring("LED OFF-Release "); // turn on Run LED to show the test has begun // and do the test. The test will return when the ADC samples array // has been filled. Turn off the rightmost LED after the data has been // captured to let the user know he/she can release the button if (funcPtr != NULL) { leds |= LEDS_RUN; NX3_writeleds(leds); n = funcPtr(); leds &= ~LEDS_RUN; NX3_writeleds(leds); // wait for the Rotary Encoder button to be released // and then send the sample data to stdout do { NX3_readBtnSw(&btnsw); delay_msecs(10); } while (btnsw & BTN_RUN_XFER); // turn on Transfer LED to indicate that data is being transmitted // Show the transfer traffic on the LCD leds |= LEDS_XFER; NX3_writeleds(leds); LCD_clrd(); LCD_setcursor(1, 0); LCD_wrstring("Sending Data...."); LCD_setcursor(2, 0); LCD_wrstring("S: DATA: "); // transfer the descriptive heading followed by the data xil_printf("\n\r%s\tAppx. Sample Interval: %d msec\n\r", s2, adc_smple_interval); xil_printf("sample\tADCCount\tVout\tsetpoint\tPWMCount\n\r"); // tell SerialCharter to start gathering data) xil_printf("===STARTPLOT===\n"); for (smpl_idx = 2; smpl_idx < n; smpl_idx++) { u16 count; count = sample[smpl_idx]; vADC = PmodCtlSys_ADCVolts(count); vSP = PmodCtlSys_ADCVolts(setpoint); voltstostrng(vADC, s1); voltstostrng(vSP, s2); xil_printf("%d\t%d\t%s\t%s\t%d\n\r", smpl_idx, count, s1, s2, PIDdebug[smpl_idx].pwm_count); LCD_setcursor(2, 2); LCD_wrstring(" "); LCD_setcursor(2, 2); LCD_putnum(smpl_idx, 10); LCD_setcursor(2, 11); LCD_wrstring(" "); LCD_setcursor(2, 11); LCD_putnum(count, 10); } // tell SeriaCharter to stop gathering data and display the graph xil_printf("===ENDPLOT===\n"); // transfer complete - turn Transfer LED off and wrap up command processing leds &= ~LEDS_XFER; NX3_writeleds(leds); wrlcd_static = true; wrlcd_dynamic = true; } } // run a test // wait a bit and start again delay_msecs(100); } // while(1) loop } // end main()
/***** * DoTest_Characterize() - Perform the Characterization test * * This function starts the duty cycle at the minimum duty cycle and * then sweeps it to the max duty cycle for the test. * Samples are collected into the global array sample[]. * The function toggles the TEST_RUNNING signal high for the duration * of the test as a debug aid and adjusts the global "pwm_duty" * * The test also sets the global frequency count min and max counts to * help limit the counts to the active range for the circuit *****/ XStatus DoTest_Characterize(void) { XStatus Status; // Xilinx return status unsigned tss; // starting timestamp volatile u16 frq_cnt; // counts to display int n; // number of samples Xuint32 freq, dutyfactor; // current frequency and duty factor Xuint32 freq_max_cnt = 3000; Xuint32 freq_min_cnt = 3000; int i; double diff = 0; // stabilize the PWM output (and thus the lamp intensity) at the // minimum before starting the test pwm_duty = STEPDC_MIN; Status = PWM_SetParams(&PWMTimerInst, pwm_freq, pwm_duty); if (Status == XST_SUCCESS) { PWM_Start(&PWMTimerInst); } else { return -1; } //Wait for the LED output to settle before starting delay_msecs(1500); // sweep the duty cycle from STEPDC_MIN to STEPDC_MAX smpl_idx = STEPDC_MIN; n = 0; tss = timestamp; while (smpl_idx <= STEPDC_MAX) { Status = PWM_SetParams(&PWMTimerInst, pwm_freq, smpl_idx); if (Status == XST_SUCCESS) { PWM_Start(&PWMTimerInst); } else { return -1; } //ECE544 Students: // make the light sensor measurement //frq_cnt = LIGHTSENSOR_mReadPERIOD(LIGHTSENSOR_BASEADDR); frq_cnt = LIGHTSENSOR_Capture(LIGHTSENSOR_BASEADDR, slope, offset, is_scaled); sample[smpl_idx++] = frq_cnt; n++; delay_msecs(50); } frq_smple_interval = (timestamp - tss) / smpl_idx; //ECE544 Students: //Find the min and max values and set the scaling/offset factors to use for your convert to 'voltage' function. //NOTE: It may also be useful to scale the actual 'count' values to a range of 0 - 4095 for the SerialCharter application to work correctly for (i = 0; i < STEPDC_MAX ; i++) { if (sample[i] < freq_min_cnt) { freq_min_cnt = sample[i]; } if (sample[i] > freq_max_cnt) { freq_max_cnt = sample[i]; } } // YOUR_FUNCTION(FRQ_min_cnt,FRQ_max_cnt); //LIGHTSENSOR_SetScaling(freq_max_cnt, freq_min_cnt, &slope, &offset); diff = freq_max_cnt - freq_min_cnt; slope = 4095.0 / diff; offset = freq_min_cnt; is_scaled = true; return n; }