/************************************************************************************* * 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; }
/***** * 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 init_feedback_system(void) { // Calibrating the sensor PWM_SetParams(&instPWMTimer, PWM_FREQ_005KHZ, 0); MB_Sleep(2000); TSL235R_SetMinThreshold((void*) XPAR_TSL235R_0_S00_AXI_BASEADDR); PWM_SetParams(&instPWMTimer, PWM_FREQ_005KHZ, 99); MB_Sleep(2000); TSL235R_SetMaxThreshold((void*) XPAR_TSL235R_0_S00_AXI_BASEADDR); // Putting PWM in a know state before returning PWM_SetParams(&instPWMTimer, PWM_FREQ_005KHZ, 0); }
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; }
/***** * 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 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); }
/***** * 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; }
/***** * 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; }
/***** * 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; 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_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; }
int main () { XStatus status; // VARS : to hold user input stuff int encoderCurn = 0x0000; int encoderPrev = 0x1000; int PWMDutyGen = 50; bool PWMGenUpdateFlag = false; u32 PWMFreqGenRead; u32 PWMDutyGenRead; /*u32 tsl235rHiTimePrev = 0;*/ /*int PWMCycTime;*/ /*int PWMFreqMeas;*/ int tsl235rFreqPrev = 0; // Initializations init_platform(); status = init_axi_devices(); if (status != XST_SUCCESS) errorExit(); init_welcom(); // SET : PWM generator begin, enable microblaze interrupts /*PWM_SetParams(&instPWMTimer, PWM_FREQ_005KHZ, PWMDutyGen); */ PWM_Start(&instPWMTimer); microblaze_enable_interrupts(); init_feedback_system(); while(1) { PWMGenUpdateFlag = false; // CHECK : Updates on ENCODER PMDIO_ROT_readRotcnt(&encoderCurn); if (encoderCurn != encoderPrev) { // SET seven-seg with encoder value NX4IO_SSEG_putU16Hex(SSEGLO, encoderCurn); PWMDutyGen = MAX(0, MIN(encoderCurn, 99)); encoderPrev = encoderCurn; PWMGenUpdateFlag = true; } // SET : Update PWM Generator if (PWMGenUpdateFlag) { // set the new PWM parameters - PWM_SetParams stops the timer status = PWM_SetParams(&instPWMTimer, PWM_FREQ_005KHZ, PWMDutyGen); if (status != XST_SUCCESS) errorExit(); // GET : read the PWM parameters back from the PWM generator PWM_GetParams(&instPWMTimer, &PWMFreqGenRead, &PWMDutyGenRead); update_lcd(PWMFreqGenRead, PWMDutyGenRead, 1); PWM_Start(&instPWMTimer); } /*if (tsl235rHiTimePrev != tsl235rHiTime) {*/ /*PWMCycTime = (int) tsl235rHiTime * 2;*/ /*PWMFreqMeas = 100000000 / PWMCycTime;*/ /*update_lcd(PWMFreqMeas, 0, 2);*/ /*tsl235rHiTimePrev = tsl235rHiTime;*/ /*}*/ if (tsl235rFreqPrev != tsl235rFreq) { update_lcd(tsl235rFreq, 50, 2); tsl235rFreq = tsl235rFreqPrev; } } }