ECE3849/main.c
2025-04-03 11:30:58 -04:00

233 lines
7.8 KiB
C

/**
* main.c
*
* ECE 3849 Lab 0 Starter Project
* Gene Bogdanov 10/18/2017
*
* This version is using the new hardware for B2017: the EK-TM4C1294XL LaunchPad with BOOSTXL-EDUMKII BoosterPack.
*
*/
#include <stdint.h>
#include <stdbool.h>
#include "driverlib/fpu.h"
#include "driverlib/sysctl.h"
#include "driverlib/interrupt.h"
#include "Crystalfontz128x128_ST7735.h"
#include <stdio.h>
#include "grlib/grlib.h"
#include <math.h>
#include <string.h>
#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; // [Hz] system clock frequency
volatile uint32_t gTime = 0; // time in hundredths of a second
volatile uint8_t drawRequested = 1;
// assumming 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.
};
int RisingTrigger(void);
// 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);
}
int main(void) {
IntMasterDisable();
// Enable the Floating Point Unit, and permit ISRs to use it
FPUEnable();
FPULazyStackingEnable();
// Initialize the system clock to 120 MHz
gSystemClock = SysCtlClockFreqSet(SYSCTL_XTAL_25MHZ | SYSCTL_OSC_MAIN | SYSCTL_USE_PLL | SYSCTL_CFG_VCO_480, 120000000);
start_signal();
start_sampler();
Crystalfontz128x128_Init(); // Initialize the LCD display driver
Crystalfontz128x128_SetOrientation(LCD_ORIENTATION_UP); // set screen orientation
tContext sContext;
GrContextInit(&sContext, &g_sCrystalfontz128x128); // Initialize the grlib graphics context
GrContextFontSet(&sContext, &g_sFontFixed6x8); // select font
#ifdef DISPLAY_TIME
uint32_t time; // local copy of gTime
char str[50]; // string buffer
#endif // DISPLAY_TIME
// full-screen rectangle
tRectangle rectFullScreen = {0, 0, GrContextDpyWidthGet(&sContext)-1, GrContextDpyHeightGet(&sContext)-1};
ButtonInit();
IntMasterEnable();
uint8_t voltage_scale = 0;
while (true) {
// handle buttons
Button button = (Button) 0;
while (fifo_get(&button)) {
switch (button) {
case S2: // draw
drawRequested = 1;
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;
}
}
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
}
// display graph
#define LOCAL_BUF_LEN 128
uint16_t local_adc_buffer[LOCAL_BUF_LEN]; // copy of adc buffer
int32_t adc_current_index;
int32_t j;
if (drawRequested) {
int trigger = RisingTrigger();
adc_current_index = trigger - (WIDTH / 2);
for (j=0; j<LOCAL_BUF_LEN; j++) {
local_adc_buffer[j] = gADCBuffer[ADC_BUFFER_WRAP(adc_current_index + j)];
}
drawRequested = 0;
}
GrContextForegroundSet(&sContext, ClrWheat);
GrStringDraw(&sContext, gVoltageScaleStr[voltage_scale], /*length*/ -1, /*x*/ 0, /*y*/ 0, /*opaque*/ false);
float fVoltsPerDiv = gVoltageScale[voltage_scale];
float fScale = (VIN_RANGE * PIXELS_PER_DIV)/((1 << ADC_BITS) * fVoltsPerDiv);
GrContextForegroundSet(&sContext, ClrPink);
for(j=0; j<LOCAL_BUF_LEN; j++) {
#define TRANSPOSE(x) (HEIGHT/2) - (int)roundf(fScale * ((int)x - ADC_OFFSET));
uint32_t upper,lower, current, last;
if (j==0) {
upper = TRANSPOSE(local_adc_buffer[j]);
lower = upper;
last = upper;
} else {
current = TRANSPOSE(local_adc_buffer[j]);
// couldn't find these anywhere
#define MIN(a,b) (((a)<(b))?(a):(b))
#define MAX(a,b) (((a)>(b))?(a):(b))
upper = MAX(current, last);
lower = MIN(current, last);
last = current;
}
GrLineDrawV(&sContext, j, lower, upper);
}
#ifdef DISPLAY_TIME
// display time
time = gTime; // read shared global only once
uint32_t hundredths = time % 100;
uint32_t seconds = (time / 100) % 60;
uint32_t minutes = (time / (100 * 60));
snprintf(str, sizeof(str), "Time = %02u:%02u:%02u", minutes, seconds, hundredths); // convert time to string
GrContextForegroundSet(&sContext, ClrYellow); // yellow text
GrStringDraw(&sContext, str, /*length*/ -1, /*x*/ 0, /*y*/ 0, /*opaque*/ false);
// display button statuses
char labels[9][7] = {"sw1", "sw2", "s1", "s2", "sel", "right", "left", "up", "down"};
char statuses[2][15] = {"not pressed", "pressed"};
int offset = 20;
uint32_t buttons = gButtons;
uint8_t i;
for (i = 0; i < 9; i++) {
snprintf(str, sizeof(str), "%s: %s",
labels[i],
statuses[buttons & 1]
);
GrStringDraw(&sContext, str, /*length*/ -1, /*x*/ 0, /*y*/ offset, /*opaque*/ false);
offset += 10;
buttons >>= 1;
}
#endif // DISPLAY_TIME
GrFlush(&sContext); // flush the frame buffer to the LCD
}
}
int RisingTrigger(void) // search for rising edge trigger
{
int x = gADCBufferIndex - (WIDTH / 2); // half screen width
int x_stop = x - ADC_BUFFER_SIZE/2;
for (; x > x_stop; x--) {
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 = x = gADCBufferIndex - (WIDTH / 2); // reset x back to how it was initialized
return x;
}