Compare commits
5 commits
e1419da297
...
f64dbda320
Author | SHA1 | Date | |
---|---|---|---|
f64dbda320 | |||
281c0f68d5 | |||
e8946f2a03 | |||
564d05b183 | |||
6004eaac27 |
4 changed files with 189 additions and 71 deletions
91
buttons.c
91
buttons.c
|
@ -6,6 +6,17 @@
|
||||||
*
|
*
|
||||||
* ECE 3849 Lab button handling
|
* ECE 3849 Lab button handling
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* XDCtools Header files */
|
||||||
|
#include <xdc/std.h>
|
||||||
|
#include <xdc/runtime/System.h>
|
||||||
|
#include <xdc/cfg/global.h>
|
||||||
|
|
||||||
|
/* BIOS Header files */
|
||||||
|
#include <ti/sysbios/BIOS.h>
|
||||||
|
#include <ti/sysbios/knl/Task.h>
|
||||||
|
#include <ti/sysbios/knl/Semaphore.h>
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
@ -32,17 +43,6 @@ extern volatile uint32_t gTime; // time in hundredths of a second
|
||||||
// initialize all button and joystick handling hardware
|
// initialize all button and joystick handling hardware
|
||||||
void ButtonInit(void)
|
void ButtonInit(void)
|
||||||
{
|
{
|
||||||
// initialize a general purpose timer for periodic interrupts
|
|
||||||
SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
|
|
||||||
TimerDisable(TIMER0_BASE, TIMER_BOTH);
|
|
||||||
TimerConfigure(TIMER0_BASE, TIMER_CFG_PERIODIC);
|
|
||||||
TimerLoadSet(TIMER0_BASE, TIMER_A, roundf((float)gSystemClock / BUTTON_SCAN_RATE) - 1);
|
|
||||||
TimerIntEnable(TIMER0_BASE, TIMER_TIMA_TIMEOUT);
|
|
||||||
TimerEnable(TIMER0_BASE, TIMER_BOTH);
|
|
||||||
|
|
||||||
// initialize interrupt controller to respond to timer interrupts
|
|
||||||
IntPrioritySet(INT_TIMER0A, BUTTON_INT_PRIORITY);
|
|
||||||
IntEnable(INT_TIMER0A);
|
|
||||||
// GPIO PJ0 and PJ1 = EK-TM4C1294XL buttons 1 and 2
|
// GPIO PJ0 and PJ1 = EK-TM4C1294XL buttons 1 and 2
|
||||||
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOJ);
|
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOJ);
|
||||||
GPIOPinTypeGPIOInput(GPIO_PORTJ_BASE, GPIO_PIN_0 | GPIO_PIN_1);
|
GPIOPinTypeGPIOInput(GPIO_PORTJ_BASE, GPIO_PIN_0 | GPIO_PIN_1);
|
||||||
|
@ -153,9 +153,19 @@ uint32_t ButtonAutoRepeat(void)
|
||||||
return presses;
|
return presses;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ISR for scanning and debouncing buttons
|
void clock_buttons(void) {
|
||||||
void ButtonISR(void) {
|
Semaphore_post(button_clock_sem);
|
||||||
TimerIntClear(TIMER0_BASE, TIMER_TIMA_TIMEOUT); // clear interrupt flag
|
}
|
||||||
|
|
||||||
|
void button_task(void) {
|
||||||
|
while(1) {
|
||||||
|
Semaphore_pend(button_clock_sem, BIOS_WAIT_FOREVER);
|
||||||
|
handle_buttons();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Task for scanning and debouncing buttons
|
||||||
|
void handle_buttons(void) {
|
||||||
// read hardware button state
|
// read hardware button state
|
||||||
uint32_t gpio_buttons =
|
uint32_t gpio_buttons =
|
||||||
~GPIOPinRead(GPIO_PORTJ_BASE, 0xff) & (GPIO_PIN_1 | GPIO_PIN_0); // EK-TM4C1294XL buttons in positions 0 and 1
|
~GPIOPinRead(GPIO_PORTJ_BASE, 0xff) & (GPIO_PIN_1 | GPIO_PIN_0); // EK-TM4C1294XL buttons in positions 0 and 1
|
||||||
|
@ -181,25 +191,12 @@ void ButtonISR(void) {
|
||||||
ButtonReadJoystick(); // Convert joystick state to button presses. The result is in gButtons.
|
ButtonReadJoystick(); // Convert joystick state to button presses. The result is in gButtons.
|
||||||
uint32_t presses = ~old_buttons & gButtons; // detect button presses (transitions from not pressed to pressed)
|
uint32_t presses = ~old_buttons & gButtons; // detect button presses (transitions from not pressed to pressed)
|
||||||
presses |= ButtonAutoRepeat(); // autorepeat presses if a button is held long enough
|
presses |= ButtonAutoRepeat(); // autorepeat presses if a button is held long enough
|
||||||
#ifdef DISPLAY_TIME
|
|
||||||
static bool tic = false;
|
|
||||||
static bool running = true;
|
|
||||||
if (presses & 1) { // EK-TM4C1294XL button 1 pressed
|
|
||||||
running = !running;
|
|
||||||
}
|
|
||||||
if (presses & 2) { // EK-TM4C1294XL button 2 pressed
|
|
||||||
gTime = 0;
|
|
||||||
}
|
|
||||||
if (running) {
|
|
||||||
if (tic) gTime++; // increment time every other ISR call
|
|
||||||
tic = !tic;
|
|
||||||
}
|
|
||||||
#endif // DISPLAY_TIME
|
|
||||||
Button buttons[9];
|
Button buttons[9];
|
||||||
uint8_t length, i;
|
uint8_t length, i;
|
||||||
length = buttons_from_mask(buttons, presses);
|
length = buttons_from_mask(buttons, presses);
|
||||||
for (i=0; i<length; i++) {
|
for (i=0; i<length; i++) {
|
||||||
fifo_put(buttons[i]);
|
Mailbox_post(button_mailbox,buttons+i, BIOS_WAIT_FOREVER);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,39 +214,3 @@ uint8_t buttons_from_mask(Button *array, uint32_t buttons) {
|
||||||
|
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
volatile DataType button_fifo[FIFO_SIZE]; // FIFO storage array
|
|
||||||
volatile int fifo_head = 0; // index of the first item in the FIFO
|
|
||||||
volatile int fifo_tail = 0; // index one step past the last item
|
|
||||||
|
|
||||||
// put data into the FIFO, skip if full
|
|
||||||
// returns 1 on success, 0 if FIFO was full
|
|
||||||
int fifo_put(DataType data)
|
|
||||||
{
|
|
||||||
int new_tail = fifo_tail + 1;
|
|
||||||
if (new_tail >= FIFO_SIZE) new_tail = 0; // wrap around
|
|
||||||
if (fifo_head != new_tail) { // if the FIFO is not full
|
|
||||||
button_fifo[fifo_tail] = data; // store data into the FIFO
|
|
||||||
fifo_tail = new_tail; // advance FIFO tail index
|
|
||||||
return 1; // success
|
|
||||||
}
|
|
||||||
return 0; // full
|
|
||||||
}
|
|
||||||
|
|
||||||
// get data from the FIFO
|
|
||||||
// returns 1 on success, 0 if FIFO was empty
|
|
||||||
int fifo_get(DataType *data)
|
|
||||||
{
|
|
||||||
if (fifo_head != fifo_tail) { // if the FIFO is not empty
|
|
||||||
*data = button_fifo[fifo_head]; // read data from the FIFO
|
|
||||||
|
|
||||||
if (fifo_head >= FIFO_SIZE-1) {
|
|
||||||
fifo_head = 0; // reset if past end
|
|
||||||
} else {
|
|
||||||
fifo_head++; // increment if within buffer
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1; // success
|
|
||||||
}
|
|
||||||
return 0; // empty
|
|
||||||
}
|
|
||||||
|
|
|
@ -69,9 +69,6 @@ typedef enum {
|
||||||
// returns length
|
// returns length
|
||||||
uint8_t buttons_from_mask(Button *array, uint32_t buttons);
|
uint8_t buttons_from_mask(Button *array, uint32_t buttons);
|
||||||
|
|
||||||
#define FIFO_SIZE 11 // FIFO capacity is 1 item fewer
|
void handle_buttons(void);
|
||||||
typedef Button DataType; // FIFO data type
|
|
||||||
int fifo_put(DataType data);
|
|
||||||
int fifo_get(DataType *data);
|
|
||||||
|
|
||||||
#endif /* BUTTONS_H_ */
|
#endif /* BUTTONS_H_ */
|
||||||
|
|
137
main.c
137
main.c
|
@ -34,6 +34,10 @@
|
||||||
|
|
||||||
uint32_t gSystemClock = 120000000; // [Hz] system clock frequency
|
uint32_t gSystemClock = 120000000; // [Hz] system clock frequency
|
||||||
|
|
||||||
|
tContext sContext;
|
||||||
|
|
||||||
|
uint32_t cputime_unloaded;
|
||||||
|
|
||||||
#define LOCAL_BUF_LEN 128
|
#define LOCAL_BUF_LEN 128
|
||||||
uint16_t adc_buffer_sample[LOCAL_BUF_LEN]; // copy of g adc buffer
|
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 adc_buffer_processed[LOCAL_BUF_LEN]; // copy of g adc buffer
|
||||||
|
@ -98,6 +102,26 @@ void start_signal() {
|
||||||
PWMGenEnable(PWM0_BASE, PWM_GEN_1);
|
PWMGenEnable(PWM0_BASE, PWM_GEN_1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8_t cpu_load_active = 0; // Clock_isActive does not change
|
||||||
|
uint32_t cpu_load_count(void)
|
||||||
|
{
|
||||||
|
uint32_t i = 0;
|
||||||
|
cpu_load_active = 1;
|
||||||
|
Clock_start(cpu_clock);
|
||||||
|
while (cpu_load_active)
|
||||||
|
i++;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cpu_timer_end(void) {
|
||||||
|
cpu_load_active = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
void start_cputimer() {
|
||||||
|
// baseline load
|
||||||
|
cputime_unloaded = cpu_load_count();
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ======== main ========
|
* ======== main ========
|
||||||
*/
|
*/
|
||||||
|
@ -108,6 +132,13 @@ int main(void)
|
||||||
// hardware initialization goes here
|
// hardware initialization goes here
|
||||||
start_signal();
|
start_signal();
|
||||||
start_sampler();
|
start_sampler();
|
||||||
|
ButtonInit();
|
||||||
|
|
||||||
|
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 */
|
/* Start BIOS */
|
||||||
BIOS_start();
|
BIOS_start();
|
||||||
|
@ -126,6 +157,9 @@ void task0_func(UArg arg1, UArg arg2)
|
||||||
|
|
||||||
void capture_waveform(UArg arg1, UArg arg2)
|
void capture_waveform(UArg arg1, UArg arg2)
|
||||||
{
|
{
|
||||||
|
IntMasterEnable();
|
||||||
|
start_cputimer();
|
||||||
|
|
||||||
while(true) {
|
while(true) {
|
||||||
Semaphore_pend(capture_sem, BIOS_WAIT_FOREVER);
|
Semaphore_pend(capture_sem, BIOS_WAIT_FOREVER);
|
||||||
|
|
||||||
|
@ -168,8 +202,111 @@ void process_waveform(UArg arg1, UArg arg2) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 %= 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)
|
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<LOCAL_BUF_LEN; j++) {
|
||||||
|
#define MIN(a,b) (((a)<(b))?(a):(b))
|
||||||
|
#define MAX(a,b) (((a)>(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
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
27
rtos.cfg
27
rtos.cfg
|
@ -566,10 +566,33 @@ task2Params.priority = 2;
|
||||||
Program.global.processing = Task.create("&process_waveform", task2Params);
|
Program.global.processing = Task.create("&process_waveform", task2Params);
|
||||||
var task3Params = new Task.Params();
|
var task3Params = new Task.Params();
|
||||||
task3Params.instance.name = "display";
|
task3Params.instance.name = "display";
|
||||||
task3Params.priority = 3;
|
task3Params.priority = 5;
|
||||||
task3Params.stackSize = 1024;
|
task3Params.stackSize = 2048;
|
||||||
Program.global.display = Task.create("&display_waveform", task3Params);
|
Program.global.display = Task.create("&display_waveform", task3Params);
|
||||||
var semaphore2Params0 = new Semaphore.Params();
|
var semaphore2Params0 = new Semaphore.Params();
|
||||||
semaphore2Params0.instance.name = "display_sem";
|
semaphore2Params0.instance.name = "display_sem";
|
||||||
semaphore2Params0.mode = Semaphore.Mode_BINARY;
|
semaphore2Params0.mode = Semaphore.Mode_BINARY;
|
||||||
Program.global.display_sem = Semaphore.create(null, semaphore2Params0);
|
Program.global.display_sem = Semaphore.create(null, semaphore2Params0);
|
||||||
|
var clock0Params = new Clock.Params();
|
||||||
|
clock0Params.instance.name = "button_clock";
|
||||||
|
clock0Params.period = 5;
|
||||||
|
clock0Params.startFlag = true;
|
||||||
|
Program.global.button_clock = Clock.create("&clock_buttons", 1, clock0Params);
|
||||||
|
var semaphore3Params = new Semaphore.Params();
|
||||||
|
semaphore3Params.instance.name = "button_clock_sem";
|
||||||
|
semaphore3Params.mode = Semaphore.Mode_BINARY;
|
||||||
|
Program.global.button_clock_sem = Semaphore.create(null, semaphore3Params);
|
||||||
|
var task4Params = new Task.Params();
|
||||||
|
task4Params.instance.name = "button";
|
||||||
|
task4Params.priority = 14;
|
||||||
|
Program.global.button = Task.create("&button_task", task4Params);
|
||||||
|
var mailbox0Params = new Mailbox.Params();
|
||||||
|
mailbox0Params.instance.name = "button_mailbox";
|
||||||
|
Program.global.button_mailbox = Mailbox.create(1, 9, mailbox0Params);
|
||||||
|
var task5Params = new Task.Params();
|
||||||
|
task5Params.instance.name = "user_input";
|
||||||
|
task5Params.priority = 6;
|
||||||
|
Program.global.user_input = Task.create("&handle_user_input", task5Params);
|
||||||
|
var clock1Params = new Clock.Params();
|
||||||
|
clock1Params.instance.name = "cpu_clock";
|
||||||
|
Program.global.cpu_clock = Clock.create("&cpu_timer_end", 10, clock1Params);
|
||||||
|
|
Loading…
Reference in a new issue