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_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; 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()
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()
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()