/* * ECE 3849 Lab2 starter project * * Gene Bogdanov 9/13/2017 */ /* XDCtools Header files */ #include #include #include /* BIOS Header files */ #include #include #include #include #include #include "driverlib/fpu.h" #include "driverlib/sysctl.h" #include "driverlib/interrupt.h" #include "driverlib/timer.h" #include "Crystalfontz128x128_ST7735.h" #include #include "grlib/grlib.h" #include #include #include "inc/hw_memmap.h" #include "driverlib/gpio.h" #include "driverlib/pwm.h" #include "driverlib/pin_map.h" #include "sampling.h" #include "buttons.h" #define PWM_FREQUENCY 20000 // PWM frequency = 20 kHz uint32_t gSystemClock = 120000000; // [Hz] system clock frequency tContext sContext; uint32_t cputime_unloaded; #define LOCAL_BUF_LEN 128 uint16_t adc_buffer_sample[LOCAL_BUF_LEN]; // copy of g adc buffer uint8_t adc_buffer_processed[LOCAL_BUF_LEN]; // copy of g adc buffer uint8_t voltage_scale = 4; // 2v uint8_t time_scale = 5; // 20us uint8_t trigger_mode = 1; // rising // assuming square lcd #define HEIGHT LCD_VERTICAL_MAX #define WIDTH LCD_HORIZONTAL_MAX #define PIXELS_PER_DIV 20 #define VIN_RANGE 3.3 // volts #define ADC_BITS 12 #define ADC_OFFSET 30 #define VOLTAGE_SCALES 5 const char * const gVoltageScaleStr[VOLTAGE_SCALES] = { "100 mV", "200 mV", "500 mV", " 1 V", " 2 V" }; const float gVoltageScale[VOLTAGE_SCALES] = { 0.1, 0.2, 0.5, 1., 2. }; #define TIME_SCALES 6 const char * const gTimeScaleStr[TIME_SCALES] = { "100 ms", "50 ms", "20 ms", " 10 ms", "50 us", "20 us" }; const uint64_t gTImeScale[TIME_SCALES] = { 100 * 1000 / PIXELS_PER_DIV, 50 * 1000 / PIXELS_PER_DIV, 20 * 1000 / PIXELS_PER_DIV, 10 * 1000 / PIXELS_PER_DIV, 50 / PIXELS_PER_DIV, 20 / PIXELS_PER_DIV, }; int Trigger(bool rising); // start a pwm test signal void start_signal() { // configure M0PWM2, at GPIO PF2, BoosterPack 1 header C1 pin 2 SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF); GPIOPinTypePWM(GPIO_PORTF_BASE, GPIO_PIN_2); GPIOPinConfigure(GPIO_PF2_M0PWM2); GPIOPadConfigSet(GPIO_PORTF_BASE, GPIO_PIN_2, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD); // configure the PWM0 peripheral, gen 1, outputs 2 and 3 SysCtlPeripheralEnable(SYSCTL_PERIPH_PWM0); // use system clock without division PWMClockSet(PWM0_BASE, PWM_SYSCLK_DIV_1); PWMGenConfigure(PWM0_BASE, PWM_GEN_1, PWM_GEN_MODE_DOWN | PWM_GEN_MODE_NO_SYNC); PWMGenPeriodSet(PWM0_BASE, PWM_GEN_1, roundf((float)gSystemClock / PWM_FREQUENCY)); PWMPulseWidthSet(PWM0_BASE, PWM_OUT_2, roundf((float)gSystemClock / PWM_FREQUENCY * 0.4f)); PWMOutputState(PWM0_BASE, PWM_OUT_2_BIT, true); PWMGenEnable(PWM0_BASE, PWM_GEN_1); } uint32_t cpu_load_count(void) { uint32_t i = 0; TimerIntClear(TIMER1_BASE, TIMER_TIMA_TIMEOUT); TimerEnable(TIMER1_BASE, TIMER_A); // start one-shot timer while (!(TimerIntStatus(TIMER1_BASE, false) & TIMER_TIMA_TIMEOUT)) i++; return i; } void start_cputimer() { // initialize timer 1 in one-shot mode for polled timing SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER1); TimerDisable(TIMER1_BASE, TIMER_BOTH); TimerConfigure(TIMER1_BASE, TIMER_CFG_ONE_SHOT); TimerLoadSet(TIMER1_BASE, TIMER_A, gSystemClock/100); // 10ms interval // baseline load cputime_unloaded = cpu_load_count(); } /* * ======== main ======== */ int main(void) { IntMasterDisable(); // hardware initialization goes here start_signal(); start_sampler(); ButtonInit(); start_cputimer(); Crystalfontz128x128_Init(); // Initialize the LCD display driver Crystalfontz128x128_SetOrientation(LCD_ORIENTATION_UP); // set screen orientation GrContextInit(&sContext, &g_sCrystalfontz128x128); // Initialize the grlib graphics context GrContextFontSet(&sContext, &g_sFontFixed6x8); // select font /* Start BIOS */ BIOS_start(); return (0); } void task0_func(UArg arg1, UArg arg2) { IntMasterEnable(); while (true) { // do nothing } } void capture_waveform(UArg arg1, UArg arg2) { IntMasterEnable(); while(true) { Semaphore_pend(capture_sem, BIOS_WAIT_FOREVER); int32_t adc_current_index; int32_t j; int trigger; if (trigger_mode == 2) { trigger = gADCBufferIndex - (WIDTH / 2); // show latest if trigger disabled } else { trigger = Trigger(trigger_mode); } adc_current_index = trigger - (WIDTH / 2); for (j=0; j(b))?(a):(b)) #define CONSTRAIN(x) MAX(MIN(HEIGHT - 1, x), 0) #define TRANSPOSE(x) CONSTRAIN((HEIGHT/2) - (int)roundf(fScale * ((int)x - ADC_OFFSET))) adc_buffer_processed[j] = TRANSPOSE(adc_buffer_sample[j]); } Semaphore_post(display_sem); Semaphore_post(capture_sem); } } void handle_user_input() { // handle buttons Button button = (Button) 0; while (true) { Mailbox_pend(button_mailbox, &button, BIOS_WAIT_FOREVER); switch (button) { case S1: // toggle edge trigger_mode = (trigger_mode + 1) % 3; break; case Up: // next scale voltage_scale = (voltage_scale + 1) % VOLTAGE_SCALES; break; case Down: // previous scale voltage_scale = (voltage_scale + VOLTAGE_SCALES - 1) % VOLTAGE_SCALES; break; case Right: // next scale time_scale = (time_scale + 1) % TIME_SCALES; set_frequency(gTImeScale[time_scale]); break; case Left: // previous scale time_scale = (time_scale + TIME_SCALES - 1) % TIME_SCALES; set_frequency(gTImeScale[time_scale]); break; } } } void display_waveform(UArg arg1, UArg arg2) { char str[50]; // string buffer tRectangle rectFullScreen = {0, 0, GrContextDpyWidthGet(&sContext)-1, GrContextDpyHeightGet(&sContext)-1}; while(1) { Semaphore_pend(display_sem, BIOS_WAIT_FOREVER); // calculate cpu usage uint32_t cputime_loaded; cputime_loaded = cpu_load_count(); float usage_percent; usage_percent = (1.0 - (float) cputime_loaded / (float) cputime_unloaded) * (float) 100.; GrContextForegroundSet(&sContext, ClrBlack); GrRectFill(&sContext, &rectFullScreen); // fill screen with black GrContextForegroundSet(&sContext, ClrBlue); // draw gridlines from the center out uint8_t xy_pos; for (xy_pos = HEIGHT/2; xy_pos < HEIGHT; xy_pos += PIXELS_PER_DIV) { GrLineDrawV(&sContext, xy_pos, 0, 128); // right GrLineDrawV(&sContext, HEIGHT - xy_pos, 0, 128); // left GrLineDrawH(&sContext, 0, 128, xy_pos); // down GrLineDrawH(&sContext, 0, 128, HEIGHT - xy_pos); // up } // info GrContextForegroundSet(&sContext, ClrWheat); GrStringDraw(&sContext, gVoltageScaleStr[voltage_scale], /*length*/ -1, /*x*/ 0, /*y*/ 0, /*opaque*/ false); GrStringDraw(&sContext, gTimeScaleStr[time_scale], /*length*/ -1, /*x*/ 60, /*y*/ 0, /*opaque*/ false); snprintf(str, sizeof(str), "CPU Load %.1f%%", usage_percent); GrStringDraw(&sContext, str, /*length*/ -1, /*x*/ 0, /*y*/ HEIGHT - 10, /*opaque*/ false); switch (trigger_mode) { case 1: GrStringDraw(&sContext, "^", /*length*/ -1, /*x*/ WIDTH - 10, /*y*/ 0, /*opaque*/ false); break; case 0: GrStringDraw(&sContext, "v", /*length*/ -1, /*x*/ WIDTH - 10, /*y*/ 0, /*opaque*/ false); break; case 2: GrStringDraw(&sContext, "-", /*length*/ -1, /*x*/ WIDTH - 10, /*y*/ 0, /*opaque*/ false); break; } // display graph GrContextForegroundSet(&sContext, ClrYellow); int j; for(j=0; j(b))?(a):(b)) uint32_t upper,lower, current, last; if (j==0) { upper = adc_buffer_processed[j]; lower = upper; last = upper; } else { current = adc_buffer_processed[j]; upper = MAX(current, last); lower = MIN(current, last); last = current; } GrLineDrawV(&sContext, j, lower, upper); } GrFlush(&sContext); // flush the frame buffer to the LCD } } int Trigger(bool rising) // search for edge trigger { int x = gADCBufferIndex - (WIDTH / 2); // half screen width int x_stop = x - ADC_BUFFER_SIZE/2; for (; x > x_stop; x--) { if (rising) { if ( gADCBuffer[ADC_BUFFER_WRAP(x)] >= ADC_OFFSET && gADCBuffer[ADC_BUFFER_WRAP(x-1)] < ADC_OFFSET) { break; } } else { // falling edge trigger if ( gADCBuffer[ADC_BUFFER_WRAP(x)] <= ADC_OFFSET && gADCBuffer[ADC_BUFFER_WRAP(x-1)] > ADC_OFFSET) { break; } } } if (x == x_stop) // for loop ran to the end x = gADCBufferIndex - (WIDTH / 2); // reset x back to how it was initialized return x; }