rtos labs
This commit is contained in:
commit
b275f4d83e
|
@ -0,0 +1,544 @@
|
||||||
|
// Lab1.c
|
||||||
|
// Runs on either MSP432 or TM4C123
|
||||||
|
// Start project to Lab 1. Take sensor readings, process the data,
|
||||||
|
// and output the results. Specifically, this program will
|
||||||
|
// measure steps using the accelerometer, audio noise using
|
||||||
|
// microphone, and light intensity using the light sensor.
|
||||||
|
// Daniel and Jonathan Valvano
|
||||||
|
// February 3, 2016
|
||||||
|
|
||||||
|
/* This example accompanies the books
|
||||||
|
"Embedded Systems: Real Time Interfacing to ARM Cortex M Microcontrollers",
|
||||||
|
ISBN: 978-1463590154, Jonathan Valvano, copyright (c) 2016
|
||||||
|
|
||||||
|
"Embedded Systems: Real-Time Operating Systems for ARM Cortex-M Microcontrollers",
|
||||||
|
ISBN: 978-1466468863, Jonathan Valvano, copyright (c) 2016
|
||||||
|
|
||||||
|
"Embedded Systems: Introduction to the MSP432 Microcontroller",
|
||||||
|
ISBN: 978-1512185676, Jonathan Valvano, copyright (c) 2016
|
||||||
|
|
||||||
|
"Embedded Systems: Real-Time Interfacing to the MSP432 Microcontroller",
|
||||||
|
ISBN: 978-1514676585, Jonathan Valvano, copyright (c) 2016
|
||||||
|
|
||||||
|
Copyright 2016 by Jonathan W. Valvano, valvano@mail.utexas.edu
|
||||||
|
You may use, edit, run or distribute this file
|
||||||
|
as long as the above copyright notice remains
|
||||||
|
THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED
|
||||||
|
OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
|
||||||
|
VALVANO SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL,
|
||||||
|
OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
|
||||||
|
For more information about my classes, my research, and my books, see
|
||||||
|
http://users.ece.utexas.edu/~valvano/
|
||||||
|
*/
|
||||||
|
|
||||||
|
// J1 J3 J4 J2
|
||||||
|
// [ 1] [21] [40] [20]
|
||||||
|
// [ 2] [22] [39] [19]
|
||||||
|
// [ 3] [23] [38] [18]
|
||||||
|
// [ 4] [24] [37] [17]
|
||||||
|
// [ 5] [25] [36] [16]
|
||||||
|
// [ 6] [26] [35] [15]
|
||||||
|
// [ 7] [27] [34] [14]
|
||||||
|
// [ 8] [28] [33] [13]
|
||||||
|
// [ 9] [29] [32] [12]
|
||||||
|
// [10] [30] [31] [11]
|
||||||
|
|
||||||
|
// +3.3V connected to J1.1 (power)
|
||||||
|
// joystick horizontal (X) connected to J1.2 (analog)
|
||||||
|
// UART from BoosterPack to LaunchPad connected to J1.3 (UART)
|
||||||
|
// UART from LaunchPad to BoosterPack connected to J1.4 (UART)
|
||||||
|
// joystick Select button connected to J1.5 (digital)
|
||||||
|
// microphone connected to J1.6 (analog)
|
||||||
|
// LCD SPI clock connected to J1.7 (SPI)
|
||||||
|
// ambient light (OPT3001) interrupt connected to J1.8 (digital)
|
||||||
|
// ambient light (OPT3001) and temperature sensor (TMP006) I2C SCL connected to J1.9 (I2C)
|
||||||
|
// ambient light (OPT3001) and temperature sensor (TMP006) I2C SDA connected to J1.10 (I2C)
|
||||||
|
|
||||||
|
// temperature sensor (TMP006) interrupt connected to J2.11 (digital)
|
||||||
|
// nothing connected to J2.12 (SPI CS_Other)
|
||||||
|
// LCD SPI CS connected to J2.13 (SPI)
|
||||||
|
// nothing connected to J2.14 (SPI MISO)
|
||||||
|
// LCD SPI data connected to J2.15 (SPI)
|
||||||
|
// nothing connected to J2.16 (reset)
|
||||||
|
// LCD !RST connected to J2.17 (digital)
|
||||||
|
// nothing connected to J2.18 (SPI CS_Wireless)
|
||||||
|
// servo PWM connected to J2.19 (PWM)
|
||||||
|
// GND connected to J2.20 (ground)
|
||||||
|
|
||||||
|
// +5V connected to J3.21 (power)
|
||||||
|
// GND connected to J3.22 (ground)
|
||||||
|
// accelerometer X connected to J3.23 (analog)
|
||||||
|
// accelerometer Y connected to J3.24 (analog)
|
||||||
|
// accelerometer Z connected to J3.25 (analog)
|
||||||
|
// joystick vertical (Y) connected to J3.26 (analog)
|
||||||
|
// nothing connected to J3.27 (I2S WS)
|
||||||
|
// nothing connected to J3.28 (I2S SCLK)
|
||||||
|
// nothing connected to J3.29 (I2S SDout)
|
||||||
|
// nothing connected to J3.30 (I2S SDin)
|
||||||
|
|
||||||
|
// LCD RS connected to J4.31 (digital)
|
||||||
|
// user Button2 (bottom) connected to J4.32 (digital)
|
||||||
|
// user Button1 (top) connected to J4.33 (digital)
|
||||||
|
// gator hole switch connected to J4.34 (digital)
|
||||||
|
// nothing connected to J4.35
|
||||||
|
// nothing connected to J4.36
|
||||||
|
// RGB LED blue connected to J4.37 (PWM)
|
||||||
|
// RGB LED green connected to J4.38 (PWM)
|
||||||
|
// RGB LED red (jumper up) or LCD backlight (jumper down) connected to J4.39 (PWM)
|
||||||
|
// buzzer connected to J4.40 (PWM)
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "BSP.h"
|
||||||
|
#include "Profile.h"
|
||||||
|
#include "Texas.h"
|
||||||
|
#include "CortexM.h"
|
||||||
|
|
||||||
|
uint32_t sqrt32(uint32_t s);
|
||||||
|
|
||||||
|
//---------------- Global variables shared between tasks ----------------
|
||||||
|
uint32_t Time; // elasped time in seconds
|
||||||
|
uint32_t Steps; // number of steps counted
|
||||||
|
uint32_t Magnitude; // will not overflow (3*1,023^2 = 3,139,587)
|
||||||
|
// Exponentially Weighted Moving Average
|
||||||
|
uint32_t EWMA; // https://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average
|
||||||
|
uint16_t SoundData; // raw data sampled from the microphone
|
||||||
|
uint32_t SoundRMS; // Root Mean Square average of most recent sound samples
|
||||||
|
uint32_t LightData;
|
||||||
|
int ReDrawAxes = 0; // non-zero means redraw axes on next display task
|
||||||
|
|
||||||
|
enum plotstate{
|
||||||
|
Accelerometer,
|
||||||
|
Microphone,
|
||||||
|
Light
|
||||||
|
};
|
||||||
|
enum plotstate PlotState = Accelerometer;
|
||||||
|
//color constants
|
||||||
|
#define BGCOLOR LCD_BLACK
|
||||||
|
#define AXISCOLOR LCD_ORANGE
|
||||||
|
#define MAGCOLOR LCD_YELLOW
|
||||||
|
#define EWMACOLOR LCD_CYAN
|
||||||
|
#define SOUNDCOLOR LCD_CYAN
|
||||||
|
#define LIGHTCOLOR LCD_LIGHTGREEN
|
||||||
|
#define TOPTXTCOLOR LCD_WHITE
|
||||||
|
#define TOPNUMCOLOR LCD_ORANGE
|
||||||
|
//------------ end of Global variables shared between tasks -------------
|
||||||
|
|
||||||
|
//---------------- Task0 samples sound from microphone ----------------
|
||||||
|
//#define SOUNDRMSLENGTH 10 // number of samples to collect before calculating RMS (may overflow if greater than 4104)
|
||||||
|
#define SOUNDRMSLENGTH 1000 // number of samples to collect before calculating RMS (may overflow if greater than 4104)
|
||||||
|
int16_t SoundArray[SOUNDRMSLENGTH];
|
||||||
|
// *********Task0_Init*********
|
||||||
|
// initializes microphone
|
||||||
|
// Task0 measures sound intensity
|
||||||
|
// Inputs: none
|
||||||
|
// Outputs: none
|
||||||
|
void Task0_Init(void){
|
||||||
|
BSP_Microphone_Init();
|
||||||
|
SoundRMS = 0;
|
||||||
|
}
|
||||||
|
// *********Task0*********
|
||||||
|
// collects data from microphone
|
||||||
|
// Inputs: none
|
||||||
|
// Outputs: none
|
||||||
|
void Task0(void){
|
||||||
|
static int32_t soundSum = 0;
|
||||||
|
static int time = 0;// units of microphone sampling rate
|
||||||
|
int32_t soundAvg;
|
||||||
|
int i;
|
||||||
|
TExaS_Task0(); // record system time in array, toggle virtual logic analyzer
|
||||||
|
Profile_Toggle0(); // viewed by the logic analyzer to know Task0 started
|
||||||
|
BSP_Microphone_Input(&SoundData);
|
||||||
|
soundSum = soundSum + (int32_t)SoundData;
|
||||||
|
SoundArray[time] = SoundData;
|
||||||
|
time = time + 1;
|
||||||
|
if(time == SOUNDRMSLENGTH){
|
||||||
|
time = 0;
|
||||||
|
soundAvg = soundSum/SOUNDRMSLENGTH;
|
||||||
|
soundSum = 0;
|
||||||
|
for(i=0; i<SOUNDRMSLENGTH; i=i+1){
|
||||||
|
soundSum = soundSum + (SoundArray[i] - soundAvg)*(SoundArray[i] - soundAvg);
|
||||||
|
}
|
||||||
|
SoundRMS = sqrt32(soundSum/SOUNDRMSLENGTH);
|
||||||
|
soundSum = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* ****************************************** */
|
||||||
|
/* End of Task0 Section */
|
||||||
|
/* ****************************************** */
|
||||||
|
|
||||||
|
//---------------- Task1 measures acceleration ----------------
|
||||||
|
uint16_t AccX, AccY, AccZ; // returned by BSP as 10-bit numbers
|
||||||
|
#define ALPHA 128 // The degree of weighting decrease, a constant smoothing factor between 0 and 1,023. A higher ALPHA discounts older observations faster.
|
||||||
|
// basic step counting algorithm is based on a forum post from
|
||||||
|
// http://stackoverflow.com/questions/16392142/android-accelerometer-profiling/16539643#16539643
|
||||||
|
enum state{ // the step counting algorithm cycles through four states
|
||||||
|
LookingForMax, // looking for a local maximum in current magnitude
|
||||||
|
LookingForCross1, // looking for current magnitude to cross average magnitude, minus a constant
|
||||||
|
LookingForMin, // looking for a local minimum in current magnitude
|
||||||
|
LookingForCross2 // looking for current magnitude to cross average magnitude, plus a constant
|
||||||
|
};
|
||||||
|
enum state AlgorithmState = LookingForMax;
|
||||||
|
uint32_t LocalMin = 1024; // smallest measured magnitude since odd-numbered step detected
|
||||||
|
uint32_t LocalMax = 0; // largest measured magnitude since even-numbered step detected
|
||||||
|
uint32_t LocalCount = 0; // number of measured magnitudes above local min or below local max
|
||||||
|
#define LOCALCOUNTTARGET 5 // The number of valid measured magnitudes needed to confirm a local min or local max. Increase this number for longer strides or more frequent measurements.
|
||||||
|
#define AVGOVERSHOOT 25 // The amount above or below average a measurement must be to count as "crossing" the average. Increase this number to reject increasingly hard shaking as steps.
|
||||||
|
// *********Task1_Init*********
|
||||||
|
// initializes accelerometer
|
||||||
|
// Task1 counts Steps
|
||||||
|
// Inputs: none
|
||||||
|
// Outputs: none
|
||||||
|
void Task1_Init(void){
|
||||||
|
BSP_Accelerometer_Init();
|
||||||
|
// initialize the exponential weighted moving average filter
|
||||||
|
BSP_Accelerometer_Input(&AccX, &AccY, &AccZ);
|
||||||
|
Magnitude = sqrt32(AccX*AccX + AccY*AccY + AccZ*AccZ);
|
||||||
|
EWMA = Magnitude; // this is a guess; there are many options
|
||||||
|
Steps = 0;
|
||||||
|
}
|
||||||
|
// *********Task1*********
|
||||||
|
// collects data from accelerometer
|
||||||
|
// counts Steps
|
||||||
|
// Inputs: none
|
||||||
|
// Outputs: none
|
||||||
|
void Task1(void){
|
||||||
|
TExaS_Task1(); // record system time in array, toggle virtual logic analyzer
|
||||||
|
Profile_Toggle1(); // viewed by the logic analyzer to know Task1 started
|
||||||
|
|
||||||
|
BSP_Accelerometer_Input(&AccX, &AccY, &AccZ);
|
||||||
|
Magnitude = sqrt32(AccX*AccX + AccY*AccY + AccZ*AccZ);
|
||||||
|
EWMA = (ALPHA*Magnitude + (1023 - ALPHA)*EWMA)/1024;
|
||||||
|
|
||||||
|
if(AlgorithmState == LookingForMax){
|
||||||
|
if(Magnitude > LocalMax){
|
||||||
|
LocalMax = Magnitude;
|
||||||
|
LocalCount = 0;
|
||||||
|
} else{
|
||||||
|
LocalCount = LocalCount + 1;
|
||||||
|
if(LocalCount >= LOCALCOUNTTARGET){
|
||||||
|
AlgorithmState = LookingForCross1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if(AlgorithmState == LookingForCross1){
|
||||||
|
if(Magnitude > LocalMax){
|
||||||
|
// somehow measured a very large magnitude
|
||||||
|
LocalMax = Magnitude;
|
||||||
|
LocalCount = 0;
|
||||||
|
AlgorithmState = LookingForMax;
|
||||||
|
} else if(Magnitude < (EWMA - AVGOVERSHOOT)){
|
||||||
|
// step detected
|
||||||
|
Steps = Steps + 1;
|
||||||
|
LocalMin = 1024;
|
||||||
|
LocalCount = 0;
|
||||||
|
AlgorithmState = LookingForMin;
|
||||||
|
}
|
||||||
|
} else if(AlgorithmState == LookingForMin){
|
||||||
|
if(Magnitude < LocalMin){
|
||||||
|
LocalMin = Magnitude;
|
||||||
|
LocalCount = 0;
|
||||||
|
} else{
|
||||||
|
LocalCount = LocalCount + 1;
|
||||||
|
if(LocalCount >= LOCALCOUNTTARGET){
|
||||||
|
AlgorithmState = LookingForCross2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if(AlgorithmState == LookingForCross2){
|
||||||
|
if(Magnitude < LocalMin){
|
||||||
|
// somehow measured a very small magnitude
|
||||||
|
LocalMin = Magnitude;
|
||||||
|
LocalCount = 0;
|
||||||
|
AlgorithmState = LookingForMin;
|
||||||
|
} else if(Magnitude > (EWMA + AVGOVERSHOOT)){
|
||||||
|
// step detected
|
||||||
|
Steps = Steps + 1;
|
||||||
|
LocalMax = 0;
|
||||||
|
LocalCount = 0;
|
||||||
|
AlgorithmState = LookingForMax;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* ****************************************** */
|
||||||
|
/* End of Task1 Section */
|
||||||
|
/* ****************************************** */
|
||||||
|
|
||||||
|
|
||||||
|
//---------------- Task2 measures light ----------------
|
||||||
|
uint32_t Task2Failures; // number of times Light wasn't ready
|
||||||
|
// *********Task2_Init*********
|
||||||
|
// initializes light sensor
|
||||||
|
// Task2 measures light intensity
|
||||||
|
// Inputs: none
|
||||||
|
// Outputs: none
|
||||||
|
void Task2_Init(void){
|
||||||
|
Task2Failures = 0;
|
||||||
|
BSP_LightSensor_Init();
|
||||||
|
LightData = BSP_LightSensor_Input();
|
||||||
|
BSP_LightSensor_Start();
|
||||||
|
}
|
||||||
|
// *********Task2*********
|
||||||
|
// collects data from light sensor
|
||||||
|
// Inputs: none
|
||||||
|
// Outputs: none
|
||||||
|
// must be called less than once a second
|
||||||
|
void Task2(void){
|
||||||
|
TExaS_Task2(); // record system time in array, toggle virtual logic analyzer
|
||||||
|
Profile_Toggle2(); // viewed by the logic analyzer to know Task2 started
|
||||||
|
|
||||||
|
if(BSP_LightSensor_End(&LightData)==0){
|
||||||
|
Task2Failures++; // should have been ready
|
||||||
|
}
|
||||||
|
BSP_LightSensor_Start(); // start measurement for next time
|
||||||
|
}
|
||||||
|
/* ****************************************** */
|
||||||
|
/* End of Task2 Section */
|
||||||
|
/* ****************************************** */
|
||||||
|
|
||||||
|
//------------Task3 handles switch input, buzzer output, LED output-------
|
||||||
|
// *********Task3_Init*********
|
||||||
|
// initializes switches, buzzer, and LEDs
|
||||||
|
// Task3 checks the switches, updates the mode, and outputs to the buzzer and LED
|
||||||
|
// Inputs: none
|
||||||
|
// Outputs: none
|
||||||
|
void Task3_Init(void){
|
||||||
|
BSP_Button1_Init();
|
||||||
|
BSP_Button2_Init();
|
||||||
|
BSP_Buzzer_Init(0);
|
||||||
|
BSP_RGB_Init(0, 0, 0);
|
||||||
|
}
|
||||||
|
// *********Task3*********
|
||||||
|
// non-real-time task
|
||||||
|
// checks the switches, updates the mode, and outputs to the buzzer and LED
|
||||||
|
// Inputs: none
|
||||||
|
// Outputs: none
|
||||||
|
void Task3(void){
|
||||||
|
static uint8_t prev1 = 0, prev2 = 0;
|
||||||
|
uint8_t current;
|
||||||
|
TExaS_Task3(); // record system time in array, toggle virtual logic analyzer
|
||||||
|
Profile_Toggle3(); // viewed by the logic analyzer to know Task3 started
|
||||||
|
|
||||||
|
BSP_Buzzer_Set(0);
|
||||||
|
current = BSP_Button1_Input();
|
||||||
|
if((current == 0) && (prev1 != 0)){
|
||||||
|
// Button1 was pressed since last loop
|
||||||
|
if(PlotState == Accelerometer){
|
||||||
|
PlotState = Microphone;
|
||||||
|
} else if(PlotState == Microphone){
|
||||||
|
PlotState = Light;
|
||||||
|
} else if(PlotState == Light){
|
||||||
|
PlotState = Accelerometer;
|
||||||
|
}
|
||||||
|
ReDrawAxes = 1; // redraw axes on next call of display task
|
||||||
|
BSP_Buzzer_Set(512); // beep until next call of this task
|
||||||
|
}
|
||||||
|
prev1 = current;
|
||||||
|
current = BSP_Button2_Input();
|
||||||
|
if((current == 0) && (prev2 != 0)){
|
||||||
|
// Button2 was pressed since last loop
|
||||||
|
if(PlotState == Accelerometer){
|
||||||
|
PlotState = Light;
|
||||||
|
} else if(PlotState == Microphone){
|
||||||
|
PlotState = Accelerometer;
|
||||||
|
} else if(PlotState == Light){
|
||||||
|
PlotState = Microphone;
|
||||||
|
}
|
||||||
|
ReDrawAxes = 1; // redraw axes on next call of display task
|
||||||
|
BSP_Buzzer_Set(512); // beep until next call of this task
|
||||||
|
}
|
||||||
|
prev2 = current;
|
||||||
|
// update the LED
|
||||||
|
switch(AlgorithmState){
|
||||||
|
case LookingForMax: BSP_RGB_Set(500, 0, 0); break;
|
||||||
|
case LookingForCross1: BSP_RGB_Set(350, 350, 0); break;
|
||||||
|
case LookingForMin: BSP_RGB_Set(0, 500, 0); break;
|
||||||
|
case LookingForCross2: BSP_RGB_Set(0, 0, 500); break;
|
||||||
|
default: BSP_RGB_Set(0, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* ****************************************** */
|
||||||
|
/* End of Task3 Section */
|
||||||
|
/* ****************************************** */
|
||||||
|
|
||||||
|
|
||||||
|
//---------------- Task4 plots data on LCD ----------------
|
||||||
|
#define ACCELERATION_MAX 1400
|
||||||
|
#define ACCELERATION_MIN 600
|
||||||
|
#define SOUND_MAX 900
|
||||||
|
#define SOUND_MIN 300
|
||||||
|
#define LIGHT_MAX 200000
|
||||||
|
#define LIGHT_MIN 0
|
||||||
|
void drawaxes(void){
|
||||||
|
if(PlotState == Accelerometer){
|
||||||
|
BSP_LCD_Drawaxes(AXISCOLOR, BGCOLOR, "Time", "Mag", MAGCOLOR, "Ave", EWMACOLOR, ACCELERATION_MAX, ACCELERATION_MIN);
|
||||||
|
} else if(PlotState == Microphone){
|
||||||
|
BSP_LCD_Drawaxes(AXISCOLOR, BGCOLOR, "Time", "Sound", SOUNDCOLOR, "", 0, SoundData+100, SoundData-100);
|
||||||
|
} else if(PlotState == Light){
|
||||||
|
BSP_LCD_Drawaxes(AXISCOLOR, BGCOLOR, "Time", "Light", LIGHTCOLOR, "", 0, LIGHT_MAX, LIGHT_MIN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// return the number of digits
|
||||||
|
int numlength(uint32_t n){
|
||||||
|
if(n < 10) return 1;
|
||||||
|
if(n < 100) return 2;
|
||||||
|
if(n < 1000) return 3;
|
||||||
|
if(n < 10000) return 4;
|
||||||
|
if(n < 100000) return 5;
|
||||||
|
if(n < 1000000) return 6;
|
||||||
|
if(n < 10000000) return 7;
|
||||||
|
if(n < 100000000) return 8;
|
||||||
|
if(n < 1000000000) return 9;
|
||||||
|
return 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
// *********Task4_Init*********
|
||||||
|
// initializes LCD
|
||||||
|
// Task4 updates the plot and Task5 updates the text at the top of the plot
|
||||||
|
// Inputs: none
|
||||||
|
// Outputs: none
|
||||||
|
void Task4_Init(void){
|
||||||
|
BSP_LCD_Init();
|
||||||
|
BSP_LCD_FillScreen(BSP_LCD_Color565(0, 0, 0));
|
||||||
|
drawaxes();
|
||||||
|
ReDrawAxes = 0;
|
||||||
|
}
|
||||||
|
// *********Task4*********
|
||||||
|
// updates the plot
|
||||||
|
// Inputs: none
|
||||||
|
// Outputs: none
|
||||||
|
void Task4(void){
|
||||||
|
TExaS_Task4(); // record system time in array, toggle virtual logic analyzer
|
||||||
|
Profile_Toggle4(); // viewed by the logic analyzer to know Task4 started
|
||||||
|
|
||||||
|
if(ReDrawAxes){
|
||||||
|
ReDrawAxes = 0;
|
||||||
|
drawaxes();
|
||||||
|
}
|
||||||
|
if(PlotState == Accelerometer){
|
||||||
|
BSP_LCD_PlotPoint(Magnitude, MAGCOLOR);
|
||||||
|
BSP_LCD_PlotPoint(EWMA, EWMACOLOR);
|
||||||
|
} else if(PlotState == Microphone){
|
||||||
|
BSP_LCD_PlotPoint(SoundData, SOUNDCOLOR);
|
||||||
|
} else if(PlotState == Light){
|
||||||
|
BSP_LCD_PlotPoint(LightData, LIGHTCOLOR);
|
||||||
|
}
|
||||||
|
BSP_LCD_PlotIncrement();
|
||||||
|
}
|
||||||
|
/* ****************************************** */
|
||||||
|
/* End of Task4 Section */
|
||||||
|
/* ****************************************** */
|
||||||
|
|
||||||
|
|
||||||
|
/* ------------------------------------------ */
|
||||||
|
//------- Task5 displays text on LCD -----------
|
||||||
|
/* ------------------------------------------ */
|
||||||
|
// *********Task5_Init*********
|
||||||
|
// initializes LCD
|
||||||
|
// Task5 updates the text at the top of the plot
|
||||||
|
// Inputs: none
|
||||||
|
// Outputs: none
|
||||||
|
void Task5_Init(void){
|
||||||
|
// assumes BSP_LCD_Init(); has been called
|
||||||
|
BSP_LCD_DrawString(0, 0, "Time=", TOPTXTCOLOR);
|
||||||
|
BSP_LCD_DrawString(0, 1, "Step=", TOPTXTCOLOR);
|
||||||
|
BSP_LCD_DrawString(10, 0, "Light=", TOPTXTCOLOR);
|
||||||
|
BSP_LCD_DrawString(10, 1, "Sound=", TOPTXTCOLOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
// *********Task5*********
|
||||||
|
// updates the text at the top of the LCD
|
||||||
|
// Inputs: none
|
||||||
|
// Outputs: none
|
||||||
|
void Task5(void){
|
||||||
|
TExaS_Task5(); // record system time in array, toggle virtual logic analyzer
|
||||||
|
Profile_Toggle5(); // viewed by the logic analyzer to know Task5 started
|
||||||
|
|
||||||
|
BSP_LCD_SetCursor(5, 0); BSP_LCD_OutUDec4(Time, TOPNUMCOLOR);
|
||||||
|
BSP_LCD_SetCursor(5, 1); BSP_LCD_OutUDec4(Steps, MAGCOLOR);
|
||||||
|
BSP_LCD_SetCursor(16, 0); BSP_LCD_OutUDec4(LightData/100, LIGHTCOLOR);
|
||||||
|
BSP_LCD_SetCursor(16, 1); BSP_LCD_OutUDec4(SoundRMS, SOUNDCOLOR);
|
||||||
|
}
|
||||||
|
/* ****************************************** */
|
||||||
|
/* End of Task5 Section */
|
||||||
|
/* ****************************************** */
|
||||||
|
|
||||||
|
int main(void){
|
||||||
|
DisableInterrupts();
|
||||||
|
BSP_Clock_InitFastest();
|
||||||
|
Profile_Init(); // initialize the 7 hardware profiling pins
|
||||||
|
// change 1000 to 4-digit number from edX
|
||||||
|
TExaS_Init(GRADER, 1000 ); // initialize the Lab 1 grader
|
||||||
|
// TExaS_Init(LOGICANALYZER, 1000); // initialize the Lab 1 logic analyzer
|
||||||
|
Task0_Init(); // microphone init
|
||||||
|
Task1_Init(); // accelerometer init
|
||||||
|
Task2_Init(); // light init
|
||||||
|
Task3_Init(); // buttons init
|
||||||
|
Task4_Init(); // LCD graphics init
|
||||||
|
Task5_Init(); // LCD text init
|
||||||
|
Time = 0;
|
||||||
|
EnableInterrupts(); // interrupts needed for grader to run
|
||||||
|
|
||||||
|
/*
|
||||||
|
Task0 runs approximately every 1ms
|
||||||
|
Task1 runs approximately every 100ms
|
||||||
|
Task2 runs approximately every 1s
|
||||||
|
Task3 runs approximately every 100ms
|
||||||
|
Task4 runs approximately every 100ms
|
||||||
|
Task5 runs approximately every 1s
|
||||||
|
*/
|
||||||
|
|
||||||
|
for(int i = 0;; i = (i + 1) % 1000){
|
||||||
|
BSP_Delay1ms(1);
|
||||||
|
Task0();
|
||||||
|
|
||||||
|
if (i % 100 == 0)
|
||||||
|
Task1();
|
||||||
|
if (i == 1)
|
||||||
|
Task2();
|
||||||
|
if (i % 100 == 2)
|
||||||
|
Task3();
|
||||||
|
if (i % 100 == 3)
|
||||||
|
Task4();
|
||||||
|
if (i == 4)
|
||||||
|
Task5();
|
||||||
|
|
||||||
|
|
||||||
|
Profile_Toggle6();
|
||||||
|
if (i == 5)
|
||||||
|
++Time;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
while(1){
|
||||||
|
for(int i=0; i<10; i++){ // runs at about 10 Hz
|
||||||
|
Task0(); // sample microphone
|
||||||
|
Task1(); // sample accelerometer
|
||||||
|
Task3(); // check the buttons and change mode if pressed
|
||||||
|
Task4(); // update the plot
|
||||||
|
BSP_Delay1ms(100);
|
||||||
|
}
|
||||||
|
Task2(); // sample light at 1 Hz
|
||||||
|
Task5(); // update the LCD text at 1 Hz
|
||||||
|
Time++; // 1 Hz
|
||||||
|
Profile_Toggle6();
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Newton's method
|
||||||
|
// s is an integer
|
||||||
|
// sqrt(s) is an integer
|
||||||
|
uint32_t sqrt32(uint32_t s){
|
||||||
|
uint32_t t; // t*t will become s
|
||||||
|
int n; // loop counter
|
||||||
|
t = s/16+1; // initial guess
|
||||||
|
for(n = 16; n; --n){ // will finish
|
||||||
|
t = ((t*t+s)/t)/2;
|
||||||
|
}
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,118 @@
|
||||||
|
// *****************Texas.h**************
|
||||||
|
// grading engine for Lab 1
|
||||||
|
//
|
||||||
|
// Runs on TM4C123
|
||||||
|
// Daniel and Jonathan Valvano
|
||||||
|
// July 17, 2016
|
||||||
|
|
||||||
|
/* This example accompanies the books
|
||||||
|
"Embedded Systems: Real Time Interfacing to ARM Cortex M Microcontrollers",
|
||||||
|
ISBN: 978-1463590154, Jonathan Valvano, copyright (c) 2016
|
||||||
|
|
||||||
|
"Embedded Systems: Real-Time Operating Systems for ARM Cortex-M Microcontrollers",
|
||||||
|
ISBN: 978-1466468863, Jonathan Valvano, copyright (c) 2016
|
||||||
|
|
||||||
|
Copyright 2016 by Jonathan W. Valvano, valvano@mail.utexas.edu
|
||||||
|
You may use, edit, run or distribute this file
|
||||||
|
as long as the above copyright notice remains
|
||||||
|
THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED
|
||||||
|
OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
|
||||||
|
VALVANO SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL,
|
||||||
|
OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
|
||||||
|
For more information about my classes, my research, and my books, see
|
||||||
|
http://users.ece.utexas.edu/~valvano/
|
||||||
|
*/
|
||||||
|
|
||||||
|
// J1 J3 J4 J2
|
||||||
|
// [ 1] [21] [40] [20]
|
||||||
|
// [ 2] [22] [39] [19]
|
||||||
|
// [ 3] [23] [38] [18]
|
||||||
|
// [ 4] [24] [37] [17]
|
||||||
|
// [ 5] [25] [36] [16]
|
||||||
|
// [ 6] [26] [35] [15]
|
||||||
|
// [ 7] [27] [34] [14]
|
||||||
|
// [ 8] [28] [33] [13]
|
||||||
|
// [ 9] [29] [32] [12]
|
||||||
|
// [10] [30] [31] [11]
|
||||||
|
|
||||||
|
// +3.3V connected to J1.1 (power)
|
||||||
|
// joystick horizontal (X) connected to J1.2 (analog)
|
||||||
|
// UART from BoosterPack to LaunchPad connected to J1.3 (UART)
|
||||||
|
// UART from LaunchPad to BoosterPack connected to J1.4 (UART)
|
||||||
|
// joystick Select button connected to J1.5 (digital)
|
||||||
|
// microphone connected to J1.6 (analog)
|
||||||
|
// LCD SPI clock connected to J1.7 (SPI)
|
||||||
|
// ambient light (OPT3001) interrupt connected to J1.8 (digital)
|
||||||
|
// ambient light (OPT3001) and temperature sensor (TMP006) I2C SCL connected to J1.9 (I2C)
|
||||||
|
// ambient light (OPT3001) and temperature sensor (TMP006) I2C SDA connected to J1.10 (I2C)
|
||||||
|
|
||||||
|
// temperature sensor (TMP006) interrupt connected to J2.11 (digital)
|
||||||
|
// nothing connected to J2.12 (SPI CS_Other)
|
||||||
|
// LCD SPI CS connected to J2.13 (SPI)
|
||||||
|
// nothing connected to J2.14 (SPI MISO)
|
||||||
|
// LCD SPI data connected to J2.15 (SPI)
|
||||||
|
// nothing connected to J2.16 (reset)
|
||||||
|
// LCD !RST connected to J2.17 (digital)
|
||||||
|
// nothing connected to J2.18 (SPI CS_Wireless)
|
||||||
|
// servo PWM connected to J2.19 (PWM)
|
||||||
|
// GND connected to J2.20 (ground)
|
||||||
|
|
||||||
|
// +5V connected to J3.21 (power)
|
||||||
|
// GND connected to J3.22 (ground)
|
||||||
|
// accelerometer X connected to J3.23 (analog)
|
||||||
|
// accelerometer Y connected to J3.24 (analog)
|
||||||
|
// accelerometer Z connected to J3.25 (analog)
|
||||||
|
// joystick vertical (Y) connected to J3.26 (analog)
|
||||||
|
// nothing connected to J3.27 (I2S WS)
|
||||||
|
// nothing connected to J3.28 (I2S SCLK)
|
||||||
|
// nothing connected to J3.29 (I2S SDout)
|
||||||
|
// nothing connected to J3.30 (I2S SDin)
|
||||||
|
|
||||||
|
// LCD RS connected to J4.31 (digital)
|
||||||
|
// user Button2 (bottom) connected to J4.32 (digital)
|
||||||
|
// user Button1 (top) connected to J4.33 (digital)
|
||||||
|
// gator hole switch connected to J4.34 (digital)
|
||||||
|
// nothing connected to J4.35
|
||||||
|
// nothing connected to J4.36
|
||||||
|
// RGB LED blue connected to J4.37 (PWM)
|
||||||
|
// RGB LED green connected to J4.38 (PWM)
|
||||||
|
// RGB LED red (jumper up) or LCD backlight (jumper down) connected to J4.39 (PWM)
|
||||||
|
// buzzer connected to J4.40 (PWM)
|
||||||
|
|
||||||
|
enum TExaSmode{
|
||||||
|
GRADER,
|
||||||
|
LOGICANALYZER
|
||||||
|
};
|
||||||
|
|
||||||
|
// ************TExaS_Init*****************
|
||||||
|
// Initialize grader, triggered by periodic timer
|
||||||
|
// This needs to be called once
|
||||||
|
// Inputs: Grading or Logic analyzer
|
||||||
|
// 4 digit edX number 1000 to 9999
|
||||||
|
// Outputs: none
|
||||||
|
void TExaS_Init(enum TExaSmode mode, uint32_t edXcode);
|
||||||
|
|
||||||
|
// ************TExaS_Stop*****************
|
||||||
|
// Stop the transfer
|
||||||
|
// Inputs: none
|
||||||
|
// Outputs: none
|
||||||
|
void TExaS_Stop(void);
|
||||||
|
|
||||||
|
// record time Task 0 is started
|
||||||
|
void TExaS_Task0(void);
|
||||||
|
|
||||||
|
// record time Task 0 is started
|
||||||
|
void TExaS_Task1(void);
|
||||||
|
|
||||||
|
// record time Task 2 is started
|
||||||
|
void TExaS_Task2(void);
|
||||||
|
|
||||||
|
// record time Task 3 is started
|
||||||
|
void TExaS_Task3(void);
|
||||||
|
|
||||||
|
// record time Task 4 is started
|
||||||
|
void TExaS_Task4(void);
|
||||||
|
|
||||||
|
// record time Task 5 is started
|
||||||
|
void TExaS_Task5(void);
|
|
@ -0,0 +1,544 @@
|
||||||
|
// Lab2.c
|
||||||
|
// Runs on either MSP432 or TM4C123
|
||||||
|
// Starter project to Lab 2. Take sensor readings, process the data,
|
||||||
|
// and output the results. Specifically, this program will
|
||||||
|
// measure steps using the accelerometer, audio sound amplitude using
|
||||||
|
// microphone, and temperature. (we will add light back in Lab 3)
|
||||||
|
// Daniel and Jonathan Valvano
|
||||||
|
// July 12, 2016
|
||||||
|
|
||||||
|
/* This example accompanies the books
|
||||||
|
"Embedded Systems: Real Time Interfacing to ARM Cortex M Microcontrollers",
|
||||||
|
ISBN: 978-1463590154, Jonathan Valvano, copyright (c) 2016
|
||||||
|
|
||||||
|
"Embedded Systems: Real-Time Operating Systems for ARM Cortex-M Microcontrollers",
|
||||||
|
ISBN: 978-1466468863, Jonathan Valvano, copyright (c) 2016
|
||||||
|
|
||||||
|
"Embedded Systems: Introduction to the MSP432 Microcontroller",
|
||||||
|
ISBN: 978-1512185676, Jonathan Valvano, copyright (c) 2016
|
||||||
|
|
||||||
|
"Embedded Systems: Real-Time Interfacing to the MSP432 Microcontroller",
|
||||||
|
ISBN: 978-1514676585, Jonathan Valvano, copyright (c) 2016
|
||||||
|
|
||||||
|
Copyright 2016 by Jonathan W. Valvano, valvano@mail.utexas.edu
|
||||||
|
You may use, edit, run or distribute this file
|
||||||
|
as long as the above copyright notice remains
|
||||||
|
THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED
|
||||||
|
OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
|
||||||
|
VALVANO SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL,
|
||||||
|
OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
|
||||||
|
For more information about my classes, my research, and my books, see
|
||||||
|
http://users.ece.utexas.edu/~valvano/
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "../inc/BSP.h"
|
||||||
|
#include "../inc/Profile.h"
|
||||||
|
#include "Texas.h"
|
||||||
|
#include "../inc/CortexM.h"
|
||||||
|
#include "os.h"
|
||||||
|
|
||||||
|
uint32_t sqrt32(uint32_t s);
|
||||||
|
#define THREADFREQ 1000 // frequency in Hz of round robin scheduler
|
||||||
|
|
||||||
|
//---------------- Global variables shared between tasks ----------------
|
||||||
|
uint32_t Time; // elasped time in 100 ms units
|
||||||
|
uint32_t Steps; // number of steps counted
|
||||||
|
uint32_t Magnitude; // will not overflow (3*1,023^2 = 3,139,587)
|
||||||
|
// Exponentially Weighted Moving Average
|
||||||
|
uint32_t EWMA; // https://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average
|
||||||
|
uint16_t SoundData; // raw data sampled from the microphone
|
||||||
|
int32_t SoundAvg;
|
||||||
|
|
||||||
|
uint32_t LightData;
|
||||||
|
int32_t TemperatureData; // 0.1C
|
||||||
|
// semaphores
|
||||||
|
int32_t NewData; // true when new numbers to display on top of LCD
|
||||||
|
int32_t LCDmutex; // exclusive access to LCD
|
||||||
|
int ReDrawAxes = 0; // non-zero means redraw axes on next display task
|
||||||
|
|
||||||
|
enum plotstate{
|
||||||
|
Accelerometer,
|
||||||
|
Microphone,
|
||||||
|
Temperature
|
||||||
|
};
|
||||||
|
enum plotstate PlotState = Accelerometer;
|
||||||
|
//color constants
|
||||||
|
#define BGCOLOR LCD_BLACK
|
||||||
|
#define AXISCOLOR LCD_ORANGE
|
||||||
|
#define MAGCOLOR LCD_YELLOW
|
||||||
|
#define EWMACOLOR LCD_CYAN
|
||||||
|
#define SOUNDCOLOR LCD_CYAN
|
||||||
|
#define TEMPCOLOR LCD_LIGHTGREEN
|
||||||
|
#define TOPTXTCOLOR LCD_WHITE
|
||||||
|
#define TOPNUMCOLOR LCD_ORANGE
|
||||||
|
//------------ end of Global variables shared between tasks -------------
|
||||||
|
|
||||||
|
//---------------- Task0 samples sound from microphone ----------------
|
||||||
|
// Event thread run by OS in real time at 1000 Hz
|
||||||
|
#define SOUNDRMSLENGTH 1000 // number of samples to collect before calculating RMS (may overflow if greater than 4104)
|
||||||
|
int16_t SoundArray[SOUNDRMSLENGTH];
|
||||||
|
// *********Task0_Init*********
|
||||||
|
// initializes microphone
|
||||||
|
// Task0 measures sound intensity
|
||||||
|
// Inputs: none
|
||||||
|
// Outputs: none
|
||||||
|
void Task0_Init(void){
|
||||||
|
BSP_Microphone_Init();
|
||||||
|
}
|
||||||
|
// *********Task0*********
|
||||||
|
// Periodic event thread runs in real time at 1000 Hz
|
||||||
|
// collects data from microphone
|
||||||
|
// Inputs: none
|
||||||
|
// Outputs: none
|
||||||
|
void Task0(void){
|
||||||
|
static int32_t soundSum = 0;
|
||||||
|
static int time = 0; // units of microphone sampling rate
|
||||||
|
|
||||||
|
TExaS_Task0(); // record system time in array, toggle virtual logic analyzer
|
||||||
|
Profile_Toggle0(); // viewed by a real logic analyzer to know Task0 started
|
||||||
|
// ADC is shared, but on the TM4C123 it is not critical with other ADC inputs
|
||||||
|
BSP_Microphone_Input(&SoundData);
|
||||||
|
soundSum = soundSum + (int32_t)SoundData;
|
||||||
|
SoundArray[time] = SoundData;
|
||||||
|
time = time + 1;
|
||||||
|
if(time == SOUNDRMSLENGTH){
|
||||||
|
SoundAvg = soundSum/SOUNDRMSLENGTH;
|
||||||
|
soundSum = 0;
|
||||||
|
OS_Signal(&NewData); // makes task5 run every 1 sec
|
||||||
|
time = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* ****************************************** */
|
||||||
|
/* End of Task0 Section */
|
||||||
|
/* ****************************************** */
|
||||||
|
|
||||||
|
//---------------- Task1 measures acceleration ----------------
|
||||||
|
// Event thread run by OS in real time at 10 Hz
|
||||||
|
uint16_t AccX, AccY, AccZ; // returned by BSP as 10-bit numbers
|
||||||
|
// *********Task1_Init*********
|
||||||
|
// initializes accelerometer
|
||||||
|
// Task1 counts Steps
|
||||||
|
// Inputs: none
|
||||||
|
// Outputs: none
|
||||||
|
void Task1_Init(void){
|
||||||
|
BSP_Accelerometer_Init();
|
||||||
|
// initialize the exponential weighted moving average filter
|
||||||
|
BSP_Accelerometer_Input(&AccX, &AccY, &AccZ);
|
||||||
|
Magnitude = sqrt32(AccX*AccX + AccY*AccY + AccZ*AccZ);
|
||||||
|
EWMA = Magnitude; // this is a guess; there are many options
|
||||||
|
Steps = 0;
|
||||||
|
}
|
||||||
|
// *********Task1*********
|
||||||
|
// collects data from accelerometer
|
||||||
|
// sends data to Task2
|
||||||
|
// Inputs: none
|
||||||
|
// Outputs: none
|
||||||
|
void Task1(void){uint32_t squared;
|
||||||
|
TExaS_Task1(); // records system time in array, toggles virtual logic analyzer
|
||||||
|
Profile_Toggle1(); // viewed by a real logic analyzer to know Task1 started
|
||||||
|
|
||||||
|
BSP_Accelerometer_Input(&AccX, &AccY, &AccZ);
|
||||||
|
squared = AccX*AccX + AccY*AccY + AccZ*AccZ;
|
||||||
|
OS_MailBox_Send(squared); // makes Task2 run every 100ms
|
||||||
|
Time++; // in 100ms units
|
||||||
|
}
|
||||||
|
/* ****************************************** */
|
||||||
|
/* End of Task1 Section */
|
||||||
|
/* ****************************************** */
|
||||||
|
|
||||||
|
|
||||||
|
//---------------- Task2 calculates steps and plots data on LCD ----------------
|
||||||
|
// Main thread scheduled by OS round robin preemptive scheduler
|
||||||
|
// accepts data from accelerometer, calculates steps, plots on LCD, and output to LED
|
||||||
|
// If no data are lost, the main loop in Task2 runs exactly at 10 Hz, but not in real time
|
||||||
|
enum state{ // the step counting algorithm cycles through four states
|
||||||
|
LookingForMax, // looking for a local maximum in current magnitude
|
||||||
|
LookingForCross1, // looking for current magnitude to cross average magnitude, minus a constant
|
||||||
|
LookingForMin, // looking for a local minimum in current magnitude
|
||||||
|
LookingForCross2 // looking for current magnitude to cross average magnitude, plus a constant
|
||||||
|
};
|
||||||
|
enum state AlgorithmState = LookingForMax;
|
||||||
|
#define LOCALCOUNTTARGET 5 // The number of valid measured magnitudes needed to confirm a local min or local max. Increase this number for longer strides or more frequent measurements.
|
||||||
|
#define AVGOVERSHOOT 25 // The amount above or below average a measurement must be to count as "crossing" the average. Increase this number to reject increasingly hard shaking as steps.
|
||||||
|
#define ACCELERATION_MAX 1400
|
||||||
|
#define ACCELERATION_MIN 600
|
||||||
|
#define ALPHA 128 // The degree of weighting decrease, a constant smoothing factor between 0 and 1,023. A higher ALPHA discounts older observations faster.
|
||||||
|
// basic step counting algorithm is based on a forum post from
|
||||||
|
// http://stackoverflow.com/questions/16392142/android-accelerometer-profiling/16539643#16539643
|
||||||
|
#define SOUND_MAX 900
|
||||||
|
#define SOUND_MIN 300
|
||||||
|
#define LIGHT_MAX 200000
|
||||||
|
#define LIGHT_MIN 0
|
||||||
|
#define TEMP_MAX 1023
|
||||||
|
#define TEMP_MIN 0
|
||||||
|
void drawaxes(void){
|
||||||
|
OS_Wait(&LCDmutex);
|
||||||
|
if(PlotState == Accelerometer){
|
||||||
|
BSP_LCD_Drawaxes(AXISCOLOR, BGCOLOR, "Time", "Mag", MAGCOLOR, "Ave", EWMACOLOR, ACCELERATION_MAX, ACCELERATION_MIN);
|
||||||
|
} else if(PlotState == Microphone){
|
||||||
|
BSP_LCD_Drawaxes(AXISCOLOR, BGCOLOR, "Time", "Sound", SOUNDCOLOR, "", 0, SoundData+100, SoundData-100);
|
||||||
|
} else if(PlotState == Temperature){
|
||||||
|
BSP_LCD_Drawaxes(AXISCOLOR, BGCOLOR, "Time", "Temp", TEMPCOLOR, "", 0, TEMP_MAX, TEMP_MIN);
|
||||||
|
}
|
||||||
|
OS_Signal(&LCDmutex); ReDrawAxes = 0;
|
||||||
|
}
|
||||||
|
void Task2(void){uint32_t data;
|
||||||
|
uint32_t localMin; // smallest measured magnitude since odd-numbered step detected
|
||||||
|
uint32_t localMax; // largest measured magnitude since even-numbered step detected
|
||||||
|
uint32_t localCount; // number of measured magnitudes above local min or below local max
|
||||||
|
localMin = 1024;
|
||||||
|
localMax = 0;
|
||||||
|
localCount = 0;
|
||||||
|
drawaxes();
|
||||||
|
while(1){
|
||||||
|
data = OS_MailBox_Recv(); // acceleration data from Task 1
|
||||||
|
TExaS_Task2(); // records system time in array, toggles virtual logic analyzer
|
||||||
|
Profile_Toggle2(); // viewed by a real logic analyzer to know Task2 started
|
||||||
|
Magnitude = sqrt32(data);
|
||||||
|
EWMA = (ALPHA*Magnitude + (1023 - ALPHA)*EWMA)/1024;
|
||||||
|
if(AlgorithmState == LookingForMax){
|
||||||
|
if(Magnitude > localMax){
|
||||||
|
localMax = Magnitude;
|
||||||
|
localCount = 0;
|
||||||
|
} else{
|
||||||
|
localCount = localCount + 1;
|
||||||
|
if(localCount >= LOCALCOUNTTARGET){
|
||||||
|
AlgorithmState = LookingForCross1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if(AlgorithmState == LookingForCross1){
|
||||||
|
if(Magnitude > localMax){
|
||||||
|
// somehow measured a very large magnitude
|
||||||
|
localMax = Magnitude;
|
||||||
|
localCount = 0;
|
||||||
|
AlgorithmState = LookingForMax;
|
||||||
|
} else if(Magnitude < (EWMA - AVGOVERSHOOT)){
|
||||||
|
// step detected
|
||||||
|
Steps = Steps + 1;
|
||||||
|
localMin = 1024;
|
||||||
|
localCount = 0;
|
||||||
|
AlgorithmState = LookingForMin;
|
||||||
|
}
|
||||||
|
} else if(AlgorithmState == LookingForMin){
|
||||||
|
if(Magnitude < localMin){
|
||||||
|
localMin = Magnitude;
|
||||||
|
localCount = 0;
|
||||||
|
} else{
|
||||||
|
localCount = localCount + 1;
|
||||||
|
if(localCount >= LOCALCOUNTTARGET){
|
||||||
|
AlgorithmState = LookingForCross2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if(AlgorithmState == LookingForCross2){
|
||||||
|
if(Magnitude < localMin){
|
||||||
|
// somehow measured a very small magnitude
|
||||||
|
localMin = Magnitude;
|
||||||
|
localCount = 0;
|
||||||
|
AlgorithmState = LookingForMin;
|
||||||
|
} else if(Magnitude > (EWMA + AVGOVERSHOOT)){
|
||||||
|
// step detected
|
||||||
|
Steps = Steps + 1;
|
||||||
|
localMax = 0;
|
||||||
|
localCount = 0;
|
||||||
|
AlgorithmState = LookingForMax;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(ReDrawAxes){
|
||||||
|
drawaxes();
|
||||||
|
ReDrawAxes = 0;
|
||||||
|
}
|
||||||
|
OS_Wait(&LCDmutex);
|
||||||
|
if(PlotState == Accelerometer){
|
||||||
|
BSP_LCD_PlotPoint(Magnitude, MAGCOLOR);
|
||||||
|
BSP_LCD_PlotPoint(EWMA, EWMACOLOR);
|
||||||
|
} else if(PlotState == Microphone){
|
||||||
|
BSP_LCD_PlotPoint(SoundData, SOUNDCOLOR);
|
||||||
|
} else if(PlotState == Temperature){
|
||||||
|
BSP_LCD_PlotPoint(TemperatureData, TEMPCOLOR);
|
||||||
|
}
|
||||||
|
BSP_LCD_PlotIncrement();
|
||||||
|
OS_Signal(&LCDmutex);
|
||||||
|
// update the LED
|
||||||
|
switch(AlgorithmState){
|
||||||
|
case LookingForMax: BSP_RGB_Set(500, 0, 0); break;
|
||||||
|
case LookingForCross1: BSP_RGB_Set(350, 350, 0); break;
|
||||||
|
case LookingForMin: BSP_RGB_Set(0, 500, 0); break;
|
||||||
|
case LookingForCross2: BSP_RGB_Set(0, 0, 500); break;
|
||||||
|
default: BSP_RGB_Set(0, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* ****************************************** */
|
||||||
|
/* End of Task2 Section */
|
||||||
|
/* ****************************************** */
|
||||||
|
|
||||||
|
|
||||||
|
//------------Task3 handles switch input, buzzer output, LED output-------
|
||||||
|
// *********Task3*********
|
||||||
|
// Main thread scheduled by OS round robin preemptive scheduler
|
||||||
|
// non-real-time task
|
||||||
|
// checks the switches, updates the mode, and outputs to the buzzer
|
||||||
|
// Inputs: none
|
||||||
|
// Outputs: none
|
||||||
|
void Task3(void){
|
||||||
|
static uint8_t prev1 = 0, prev2 = 0;
|
||||||
|
uint8_t current;
|
||||||
|
BSP_Button1_Init();
|
||||||
|
BSP_Button2_Init();
|
||||||
|
BSP_Buzzer_Init(0);
|
||||||
|
BSP_RGB_Init(0, 0, 0);
|
||||||
|
while(1){
|
||||||
|
TExaS_Task3(); // records system time in array, toggles virtual logic analyzer
|
||||||
|
Profile_Toggle3(); // viewed by a real logic analyzer to know Task3 started
|
||||||
|
BSP_Buzzer_Set(0);
|
||||||
|
current = BSP_Button1_Input();
|
||||||
|
if((current == 0) && (prev1 != 0)){
|
||||||
|
// Button1 was pressed since last loop
|
||||||
|
if(PlotState == Accelerometer){
|
||||||
|
PlotState = Microphone;
|
||||||
|
} else if(PlotState == Microphone){
|
||||||
|
PlotState = Temperature;
|
||||||
|
} else if(PlotState == Temperature){
|
||||||
|
PlotState = Accelerometer;
|
||||||
|
}
|
||||||
|
ReDrawAxes = 1; // redraw axes on next call of display task
|
||||||
|
BSP_Buzzer_Set(512); // beep until next call of this task
|
||||||
|
}
|
||||||
|
prev1 = current;
|
||||||
|
current = BSP_Button2_Input();
|
||||||
|
if((current == 0) && (prev2 != 0)){
|
||||||
|
// Button2 was pressed since last loop
|
||||||
|
if(PlotState == Accelerometer){
|
||||||
|
PlotState = Temperature;
|
||||||
|
} else if(PlotState == Microphone){
|
||||||
|
PlotState = Accelerometer;
|
||||||
|
} else if(PlotState == Temperature){
|
||||||
|
PlotState = Microphone;
|
||||||
|
}
|
||||||
|
ReDrawAxes = 1; // redraw axes on next call of display task
|
||||||
|
BSP_Buzzer_Set(512); // beep until next call of this task
|
||||||
|
}
|
||||||
|
prev2 = current;
|
||||||
|
|
||||||
|
BSP_Delay1ms(5); // very inefficient, but does debounce the switches
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* ****************************************** */
|
||||||
|
/* End of Task3 Section */
|
||||||
|
/* ****************************************** */
|
||||||
|
|
||||||
|
|
||||||
|
//------------Task4 measures temperature-------
|
||||||
|
// *********Task4*********
|
||||||
|
// Main thread scheduled by OS round robin preemptive scheduler
|
||||||
|
// measures temperature
|
||||||
|
// Inputs: none
|
||||||
|
// Outputs: none
|
||||||
|
void Task4(void){int32_t voltData,tempData;
|
||||||
|
int done;
|
||||||
|
BSP_TempSensor_Init();
|
||||||
|
while(1){
|
||||||
|
TExaS_Task4(); // records system time in array, toggles virtual logic analyzer
|
||||||
|
Profile_Toggle4(); // viewed by a real logic analyzer to know Task4 started
|
||||||
|
BSP_TempSensor_Start();
|
||||||
|
done = 0;
|
||||||
|
while(done == 0){
|
||||||
|
done = BSP_TempSensor_End(&voltData,&tempData); // waits about 1 sec
|
||||||
|
}
|
||||||
|
TemperatureData = tempData/10000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* ****************************************** */
|
||||||
|
/* End of Task4 Section */
|
||||||
|
/* ****************************************** */
|
||||||
|
|
||||||
|
|
||||||
|
/* ------------------------------------------ */
|
||||||
|
//------- Task5 displays text on LCD -----------
|
||||||
|
/* ------------------------------------------ */
|
||||||
|
// If no data are lost, the main loop in Task5 runs exactly at 1 Hz, but not in real time
|
||||||
|
|
||||||
|
// *********Task5*********
|
||||||
|
// Main thread scheduled by OS round robin preemptive scheduler
|
||||||
|
// updates the text at the top of the LCD
|
||||||
|
// Inputs: none
|
||||||
|
// Outputs: none
|
||||||
|
void Task5(void){int32_t soundSum;
|
||||||
|
uint32_t soundRMS; // Root Mean Square average of most recent sound samples
|
||||||
|
OS_Wait(&LCDmutex);
|
||||||
|
BSP_LCD_DrawString(0, 0, "Time=", TOPTXTCOLOR);
|
||||||
|
BSP_LCD_DrawString(0, 1, "Step=", TOPTXTCOLOR);
|
||||||
|
BSP_LCD_DrawString(10, 0, "Temp =", TOPTXTCOLOR);
|
||||||
|
BSP_LCD_DrawString(10, 1, "Sound=", TOPTXTCOLOR);
|
||||||
|
OS_Signal(&LCDmutex);
|
||||||
|
while(1){
|
||||||
|
OS_Wait(&NewData);
|
||||||
|
TExaS_Task5(); // records system time in array, toggles virtual logic analyzer
|
||||||
|
Profile_Toggle5(); // viewed by a real logic analyzer to know Task5 started
|
||||||
|
soundSum = 0;
|
||||||
|
for(int i=0; i<SOUNDRMSLENGTH; i=i+1){
|
||||||
|
soundSum = soundSum + (SoundArray[i] - SoundAvg)*(SoundArray[i] - SoundAvg);
|
||||||
|
}
|
||||||
|
soundRMS = sqrt32(soundSum/SOUNDRMSLENGTH);
|
||||||
|
OS_Wait(&LCDmutex);
|
||||||
|
BSP_LCD_SetCursor(5, 0); BSP_LCD_OutUDec4(Time/10, TOPNUMCOLOR);
|
||||||
|
BSP_LCD_SetCursor(5, 1); BSP_LCD_OutUDec4(Steps, MAGCOLOR);
|
||||||
|
BSP_LCD_SetCursor(16, 0); BSP_LCD_OutUFix2_1(TemperatureData, TEMPCOLOR);
|
||||||
|
BSP_LCD_SetCursor(16, 1); BSP_LCD_OutUDec4(soundRMS, SOUNDCOLOR);
|
||||||
|
OS_Signal(&LCDmutex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* ****************************************** */
|
||||||
|
/* End of Task5 Section */
|
||||||
|
/* ****************************************** */
|
||||||
|
int main_step1(void); // OK
|
||||||
|
int main_step2(void); // OK
|
||||||
|
int main_step3(void); // OK
|
||||||
|
int main_step4(void); // OK
|
||||||
|
int main_step5(void); // BROKEN
|
||||||
|
|
||||||
|
int main(void){
|
||||||
|
//TExaS_Init(LOGICANALYZER, 1000);
|
||||||
|
//main_step5();
|
||||||
|
//return 0;
|
||||||
|
|
||||||
|
OS_Init();
|
||||||
|
Profile_Init(); // initialize the 7 hardware profiling pins
|
||||||
|
Task0_Init(); // microphone init
|
||||||
|
Task1_Init(); // accelerometer init
|
||||||
|
BSP_LCD_Init();
|
||||||
|
BSP_LCD_FillScreen(BSP_LCD_Color565(0, 0, 0));
|
||||||
|
Time = 0;
|
||||||
|
OS_InitSemaphore(&NewData, 0); // 0 means no data
|
||||||
|
OS_InitSemaphore(&LCDmutex, 1); // 1 means free
|
||||||
|
OS_MailBox_Init(); // initialize mailbox used to send data between Task1 and Task2
|
||||||
|
// Task 0 should run every 1ms and Task 1 should run every 100ms
|
||||||
|
OS_AddPeriodicEventThreads(&Task0, 1, &Task1, 100);
|
||||||
|
// Task2, Task3, Task4, Task5 are main threads
|
||||||
|
OS_AddThreads(&Task2, &Task3, &Task4, &Task5);
|
||||||
|
// when grading change 1000 to 4-digit number from edX
|
||||||
|
TExaS_Init(GRADER, 1000); // initialize the Lab 2 grader
|
||||||
|
//TExaS_Init(LOGICANALYZER, 1000); // initialize the Lab 2 logic analyzer
|
||||||
|
OS_Launch(BSP_Clock_GetFreq()/THREADFREQ); // doesn't return, interrupts enabled in here
|
||||||
|
return 0; // this never executes
|
||||||
|
}
|
||||||
|
//******************Step 1************************** done
|
||||||
|
// implement and test the semaphores
|
||||||
|
int32_t s1,s2;
|
||||||
|
int main_step1(void){
|
||||||
|
OS_InitSemaphore(&s1,0);
|
||||||
|
OS_InitSemaphore(&s2,1);
|
||||||
|
while(1){
|
||||||
|
OS_Wait(&s2); //now s1=0, s2=0
|
||||||
|
OS_Signal(&s1); //now s1=1, s2=0
|
||||||
|
OS_Signal(&s2); //now s1=1, s2=1
|
||||||
|
OS_Signal(&s1); //now s1=2, s2=1
|
||||||
|
OS_Wait(&s1); //now s1=1, s2=1
|
||||||
|
OS_Wait(&s1); //now s1=0, s2=1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//***************Step 2************************* done
|
||||||
|
// Implement the three mailbox functions as defined in OS.c and OS.h
|
||||||
|
// Use this a simple main program to test the mailbox functions.
|
||||||
|
uint32_t Out;
|
||||||
|
int main_step2(void){ uint32_t in=0;
|
||||||
|
OS_MailBox_Init();
|
||||||
|
while(1){
|
||||||
|
OS_MailBox_Send(in);
|
||||||
|
Out = OS_MailBox_Recv();
|
||||||
|
in++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//***************Step 3************************* done
|
||||||
|
// Test the round robin scheduler
|
||||||
|
// The minimal set of functions you need to write to get the system running is
|
||||||
|
// SysTick_Handler (without calling the C function and without running periodic threads)
|
||||||
|
// StartOS
|
||||||
|
// OS_Init
|
||||||
|
// OS_AddThreads3 (with just 3 threads for now)
|
||||||
|
// OS_Launch
|
||||||
|
int main_step3(void){
|
||||||
|
OS_Init();
|
||||||
|
Profile_Init(); // initialize the 7 hardware profiling pins
|
||||||
|
Task0_Init(); // microphone init
|
||||||
|
Task1_Init(); // accelerometer init
|
||||||
|
BSP_LCD_Init();
|
||||||
|
BSP_LCD_FillScreen(BSP_LCD_Color565(0, 0, 0));
|
||||||
|
Time = 0;
|
||||||
|
// semaphores and mailbox not used
|
||||||
|
// Tasks 0, 1, 2 will not run
|
||||||
|
// Task3, Task4, Task5 are main threads
|
||||||
|
// Task2 will stall
|
||||||
|
OS_AddThreads3(&Task3, &Task4, &Task5);
|
||||||
|
// when grading change 1000 to 4-digit number from edX
|
||||||
|
TExaS_Init(GRADER, 1000); // initialize the Lab 2 grader
|
||||||
|
//TExaS_Init(LOGICANALYZER, 1000); // initialize the Lab 2 logic analyzer
|
||||||
|
OS_Launch(BSP_Clock_GetFreq()/THREADFREQ); // doesn't return, interrupts enabled in here
|
||||||
|
return 0; // this never executes
|
||||||
|
}
|
||||||
|
//***************Step 4*************************
|
||||||
|
// Increase to 4 threads
|
||||||
|
int main_step4(void){
|
||||||
|
OS_Init();
|
||||||
|
Profile_Init(); // initialize the 7 hardware profiling pins
|
||||||
|
Task0_Init(); // microphone init
|
||||||
|
Task1_Init(); // accelerometer init
|
||||||
|
BSP_LCD_Init();
|
||||||
|
BSP_LCD_FillScreen(BSP_LCD_Color565(0, 0, 0));
|
||||||
|
Time = 0;
|
||||||
|
OS_InitSemaphore(&NewData, 0); // 0 means no data
|
||||||
|
OS_InitSemaphore(&LCDmutex, 1); // 1 means free
|
||||||
|
OS_MailBox_Init(); // initialize mailbox used to send data between Task1 and Task2
|
||||||
|
// Tasks 0, 1 will not run
|
||||||
|
// Task2, Task3, Task4, Task5 are main threads
|
||||||
|
// Tasks 2 and 5 will stall
|
||||||
|
OS_AddThreads(&Task2, &Task3, &Task4, &Task5);
|
||||||
|
// when grading change 1000 to 4-digit number from edX
|
||||||
|
TExaS_Init(GRADER, 1000); // initialize the Lab 2 grader
|
||||||
|
//TExaS_Init(LOGICANALYZER, 1000); // initialize the Lab 2 logic analyzer
|
||||||
|
OS_Launch(BSP_Clock_GetFreq()/THREADFREQ); // doesn't return, interrupts enabled in here
|
||||||
|
return 0; // this never executes
|
||||||
|
}
|
||||||
|
|
||||||
|
//***************Step 5*************************
|
||||||
|
// add one periodic task
|
||||||
|
void Dummy(void){}; // place holder
|
||||||
|
int main_step5(void){
|
||||||
|
OS_Init();
|
||||||
|
Profile_Init(); // initialize the 7 hardware profiling pins
|
||||||
|
Task0_Init(); // microphone init
|
||||||
|
Task1_Init(); // accelerometer init
|
||||||
|
BSP_LCD_Init();
|
||||||
|
BSP_LCD_FillScreen(BSP_LCD_Color565(0, 0, 0));
|
||||||
|
Time = 0;
|
||||||
|
OS_InitSemaphore(&NewData, 0); // 0 means no data
|
||||||
|
OS_InitSemaphore(&LCDmutex, 1); // 1 means free
|
||||||
|
OS_MailBox_Init(); // initialize mailbox used to send data between Task1 and Task2
|
||||||
|
|
||||||
|
// Task1 will not run
|
||||||
|
// Task5 will stall
|
||||||
|
// Task 0 should run every 1ms and dummy is not run
|
||||||
|
OS_AddPeriodicEventThreads(&Task0, 1, &Dummy, 100);
|
||||||
|
// Task2, Task3, Task4, Task5 are main threads
|
||||||
|
OS_AddThreads(&Task2, &Task3, &Task4, &Task5);
|
||||||
|
// when grading change 1000 to 4-digit number from edX
|
||||||
|
TExaS_Init(GRADER, 1000); // initialize the Lab 2 grader
|
||||||
|
//TExaS_Init(LOGICANALYZER, 1000); // initialize the Lab 2 logic analyzer
|
||||||
|
OS_Launch(BSP_Clock_GetFreq()/THREADFREQ); // doesn't return, interrupts enabled in here
|
||||||
|
return 0; // this never executes
|
||||||
|
}
|
||||||
|
// Newton's method
|
||||||
|
// s is an integer
|
||||||
|
// sqrt(s) is an integer
|
||||||
|
uint32_t sqrt32(uint32_t s){
|
||||||
|
uint32_t t; // t*t will become s
|
||||||
|
int n; // loop counter
|
||||||
|
t = s/16+1; // initial guess
|
||||||
|
for(n = 16; n; --n){ // will finish
|
||||||
|
t = ((t*t+s)/t)/2;
|
||||||
|
}
|
||||||
|
return t;
|
||||||
|
}
|
|
@ -0,0 +1,118 @@
|
||||||
|
// *****************Texas.h**************
|
||||||
|
// grading engine for Lab 2
|
||||||
|
//
|
||||||
|
// Runs on TM4C123
|
||||||
|
// Daniel and Jonathan Valvano
|
||||||
|
// February 24, 2016
|
||||||
|
|
||||||
|
/* This example accompanies the books
|
||||||
|
"Embedded Systems: Real Time Interfacing to ARM Cortex M Microcontrollers",
|
||||||
|
ISBN: 978-1463590154, Jonathan Valvano, copyright (c) 2016
|
||||||
|
|
||||||
|
"Embedded Systems: Real-Time Operating Systems for ARM Cortex-M Microcontrollers",
|
||||||
|
ISBN: 978-1466468863, Jonathan Valvano, copyright (c) 2016
|
||||||
|
|
||||||
|
Copyright 2016 by Jonathan W. Valvano, valvano@mail.utexas.edu
|
||||||
|
You may use, edit, run or distribute this file
|
||||||
|
as long as the above copyright notice remains
|
||||||
|
THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED
|
||||||
|
OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
|
||||||
|
VALVANO SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL,
|
||||||
|
OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
|
||||||
|
For more information about my classes, my research, and my books, see
|
||||||
|
http://users.ece.utexas.edu/~valvano/
|
||||||
|
*/
|
||||||
|
|
||||||
|
// J1 J3 J4 J2
|
||||||
|
// [ 1] [21] [40] [20]
|
||||||
|
// [ 2] [22] [39] [19]
|
||||||
|
// [ 3] [23] [38] [18]
|
||||||
|
// [ 4] [24] [37] [17]
|
||||||
|
// [ 5] [25] [36] [16]
|
||||||
|
// [ 6] [26] [35] [15]
|
||||||
|
// [ 7] [27] [34] [14]
|
||||||
|
// [ 8] [28] [33] [13]
|
||||||
|
// [ 9] [29] [32] [12]
|
||||||
|
// [10] [30] [31] [11]
|
||||||
|
|
||||||
|
// +3.3V connected to J1.1 (power)
|
||||||
|
// joystick horizontal (X) connected to J1.2 (analog)
|
||||||
|
// UART from BoosterPack to LaunchPad connected to J1.3 (UART)
|
||||||
|
// UART from LaunchPad to BoosterPack connected to J1.4 (UART)
|
||||||
|
// joystick Select button connected to J1.5 (digital)
|
||||||
|
// microphone connected to J1.6 (analog)
|
||||||
|
// LCD SPI clock connected to J1.7 (SPI)
|
||||||
|
// ambient light (OPT3001) interrupt connected to J1.8 (digital)
|
||||||
|
// ambient light (OPT3001) and temperature sensor (TMP006) I2C SCL connected to J1.9 (I2C)
|
||||||
|
// ambient light (OPT3001) and temperature sensor (TMP006) I2C SDA connected to J1.10 (I2C)
|
||||||
|
|
||||||
|
// temperature sensor (TMP006) interrupt connected to J2.11 (digital)
|
||||||
|
// nothing connected to J2.12 (SPI CS_Other)
|
||||||
|
// LCD SPI CS connected to J2.13 (SPI)
|
||||||
|
// nothing connected to J2.14 (SPI MISO)
|
||||||
|
// LCD SPI data connected to J2.15 (SPI)
|
||||||
|
// nothing connected to J2.16 (reset)
|
||||||
|
// LCD !RST connected to J2.17 (digital)
|
||||||
|
// nothing connected to J2.18 (SPI CS_Wireless)
|
||||||
|
// servo PWM connected to J2.19 (PWM)
|
||||||
|
// GND connected to J2.20 (ground)
|
||||||
|
|
||||||
|
// +5V connected to J3.21 (power)
|
||||||
|
// GND connected to J3.22 (ground)
|
||||||
|
// accelerometer X connected to J3.23 (analog)
|
||||||
|
// accelerometer Y connected to J3.24 (analog)
|
||||||
|
// accelerometer Z connected to J3.25 (analog)
|
||||||
|
// joystick vertical (Y) connected to J3.26 (analog)
|
||||||
|
// nothing connected to J3.27 (I2S WS)
|
||||||
|
// nothing connected to J3.28 (I2S SCLK)
|
||||||
|
// nothing connected to J3.29 (I2S SDout)
|
||||||
|
// nothing connected to J3.30 (I2S SDin)
|
||||||
|
|
||||||
|
// LCD RS connected to J4.31 (digital)
|
||||||
|
// user Button2 (bottom) connected to J4.32 (digital)
|
||||||
|
// user Button1 (top) connected to J4.33 (digital)
|
||||||
|
// gator hole switch connected to J4.34 (digital)
|
||||||
|
// nothing connected to J4.35
|
||||||
|
// nothing connected to J4.36
|
||||||
|
// RGB LED blue connected to J4.37 (PWM)
|
||||||
|
// RGB LED green connected to J4.38 (PWM)
|
||||||
|
// RGB LED red (jumper up) or LCD backlight (jumper down) connected to J4.39 (PWM)
|
||||||
|
// buzzer connected to J4.40 (PWM)
|
||||||
|
|
||||||
|
enum TExaSmode{
|
||||||
|
GRADER,
|
||||||
|
LOGICANALYZER
|
||||||
|
};
|
||||||
|
|
||||||
|
// ************TExaS_Init*****************
|
||||||
|
// Initialize grader, triggered by periodic timer
|
||||||
|
// This needs to be called once
|
||||||
|
// Inputs: Grading or Logic analyzer
|
||||||
|
// 4-digit number from edX
|
||||||
|
// Outputs: none
|
||||||
|
void TExaS_Init(enum TExaSmode mode, uint32_t edXcode);
|
||||||
|
|
||||||
|
// ************TExaS_Stop*****************
|
||||||
|
// Stop the transfer
|
||||||
|
// Inputs: none
|
||||||
|
// Outputs: none
|
||||||
|
void TExaS_Stop(void);
|
||||||
|
|
||||||
|
// record time Task 0 is started
|
||||||
|
void TExaS_Task0(void);
|
||||||
|
|
||||||
|
// record time Task 0 is started
|
||||||
|
void TExaS_Task1(void);
|
||||||
|
|
||||||
|
// record time Task 2 is started
|
||||||
|
void TExaS_Task2(void);
|
||||||
|
|
||||||
|
// record time Task 3 is started
|
||||||
|
void TExaS_Task3(void);
|
||||||
|
|
||||||
|
// record time Task 4 is started
|
||||||
|
void TExaS_Task4(void);
|
||||||
|
|
||||||
|
// record time Task 5 is started
|
||||||
|
void TExaS_Task5(void);
|
|
@ -0,0 +1,237 @@
|
||||||
|
// os.c
|
||||||
|
// Runs on LM4F120/TM4C123/MSP432
|
||||||
|
// Lab 2 starter file.
|
||||||
|
// Daniel Valvano
|
||||||
|
// February 20, 2016
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "os.h"
|
||||||
|
#include "../inc/CortexM.h"
|
||||||
|
#include "../inc/BSP.h"
|
||||||
|
|
||||||
|
// function definitions in osasm.s
|
||||||
|
void StartOS(void);
|
||||||
|
|
||||||
|
periodicType periodic[2];
|
||||||
|
tcbType tcbs[4];
|
||||||
|
tcbType *RunPt;
|
||||||
|
int32_t Stacks[4][STACKSIZE];
|
||||||
|
|
||||||
|
|
||||||
|
// ******** OS_Init ************
|
||||||
|
// Initialize operating system, disable interrupts
|
||||||
|
// Initialize OS controlled I/O: systick, bus clock as fast as possible
|
||||||
|
// Initialize OS global variables
|
||||||
|
// Inputs: none
|
||||||
|
// Outputs: none
|
||||||
|
void OS_Init(void){
|
||||||
|
DisableInterrupts();
|
||||||
|
BSP_Clock_InitFastest();// set processor clock to fastest speed
|
||||||
|
// initialize any global variables as needed
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetInitialStack(int i){
|
||||||
|
tcbs[i].sp = &Stacks[i][STACKSIZE - 16];
|
||||||
|
|
||||||
|
Stacks[i][STACKSIZE-1] = 0x01000000; // Thumb bit
|
||||||
|
//Stacks[i][STACKSIZE-2] is reserved for PC
|
||||||
|
//and is initialized with start address of task
|
||||||
|
Stacks[i][STACKSIZE-3] = 0x14141414; // R14 = LR
|
||||||
|
Stacks[i][STACKSIZE-4] = 0x12121212; // R12
|
||||||
|
Stacks[i][STACKSIZE-5] = 0x03030303; // R3
|
||||||
|
Stacks[i][STACKSIZE-6] = 0x02020202; // R2
|
||||||
|
Stacks[i][STACKSIZE-7] = 0x01010101; // R1
|
||||||
|
Stacks[i][STACKSIZE-8] = 0x00000000; // R0
|
||||||
|
Stacks[i][STACKSIZE-9] = 0x11111111; // R11
|
||||||
|
Stacks[i][STACKSIZE-10] = 0x10101010; // R10
|
||||||
|
Stacks[i][STACKSIZE-11] = 0x09090909; // R9
|
||||||
|
Stacks[i][STACKSIZE-12] = 0x08080808; // R8
|
||||||
|
Stacks[i][STACKSIZE-13] = 0x07070707; // R7
|
||||||
|
Stacks[i][STACKSIZE-14] = 0x06060606; // R6
|
||||||
|
Stacks[i][STACKSIZE-15] = 0x05050505; // R5
|
||||||
|
Stacks[i][STACKSIZE-16] = 0x04040404; // R4
|
||||||
|
}
|
||||||
|
|
||||||
|
//******** OS_AddThreads ***************
|
||||||
|
// Add four main threads to the scheduler
|
||||||
|
// Inputs: function pointers to four void/void main threads
|
||||||
|
// Outputs: 1 if successful, 0 if this thread can not be added
|
||||||
|
// This function will only be called once, after OS_Init and before OS_Launch
|
||||||
|
int OS_AddThreads(void(*thread0)(void),
|
||||||
|
void(*thread1)(void),
|
||||||
|
void(*thread2)(void),
|
||||||
|
void(*thread3)(void)){
|
||||||
|
// initialize TCB circular list
|
||||||
|
// initialize RunPt
|
||||||
|
// initialize four stacks, including initial PC
|
||||||
|
uint32_t status = StartCritical();
|
||||||
|
tcbs[0].next = &tcbs[1];
|
||||||
|
tcbs[1].next = &tcbs[2];
|
||||||
|
tcbs[2].next = &tcbs[3];
|
||||||
|
tcbs[3].next = &tcbs[0];
|
||||||
|
|
||||||
|
SetInitialStack(0); Stacks[0][STACKSIZE-2] = (int32_t)(thread0);
|
||||||
|
SetInitialStack(1); Stacks[1][STACKSIZE-2] = (int32_t)(thread1);
|
||||||
|
SetInitialStack(2); Stacks[2][STACKSIZE-2] = (int32_t)(thread2);
|
||||||
|
SetInitialStack(3); Stacks[3][STACKSIZE-2] = (int32_t)(thread3);
|
||||||
|
|
||||||
|
RunPt = &tcbs[0];
|
||||||
|
EndCritical(status);
|
||||||
|
return 1; // successful
|
||||||
|
}
|
||||||
|
|
||||||
|
//******** OS_AddThreads3 ***************
|
||||||
|
// add three foregound threads to the scheduler
|
||||||
|
// This is needed during debugging and not part of final solution
|
||||||
|
// Inputs: three pointers to a void/void foreground tasks
|
||||||
|
// Outputs: 1 if successful, 0 if this thread can not be added
|
||||||
|
int OS_AddThreads3(void(*task0)(void),
|
||||||
|
void(*task1)(void),
|
||||||
|
void(*task2)(void)){
|
||||||
|
// initialize TCB circular list (same as RTOS project)
|
||||||
|
// initialize RunPt
|
||||||
|
// initialize four stacks, including initial PC
|
||||||
|
uint32_t status = StartCritical();
|
||||||
|
tcbs[0].next = &tcbs[1];
|
||||||
|
tcbs[1].next = &tcbs[2];
|
||||||
|
tcbs[2].next = &tcbs[0];
|
||||||
|
|
||||||
|
SetInitialStack(0); Stacks[0][STACKSIZE-2] = (int32_t)(task0);
|
||||||
|
SetInitialStack(1); Stacks[1][STACKSIZE-2] = (int32_t)(task1);
|
||||||
|
SetInitialStack(2); Stacks[2][STACKSIZE-2] = (int32_t)(task2);
|
||||||
|
|
||||||
|
RunPt = &tcbs[0];
|
||||||
|
EndCritical(status);
|
||||||
|
return 1; // successful
|
||||||
|
}
|
||||||
|
|
||||||
|
//******** OS_AddPeriodicEventThreads ***************
|
||||||
|
// Add two background periodic event threads
|
||||||
|
// Typically this function receives the highest priority
|
||||||
|
// Inputs: pointers to a void/void event thread function2
|
||||||
|
// periods given in units of OS_Launch (Lab 2 this will be msec)
|
||||||
|
// Outputs: 1 if successful, 0 if this thread cannot be added
|
||||||
|
// It is assumed that the event threads will run to completion and return
|
||||||
|
// It is assumed the time to run these event threads is short compared to 1 msec
|
||||||
|
// These threads cannot spin, block, loop, sleep, or kill
|
||||||
|
// These threads can call OS_Signal
|
||||||
|
int OS_AddPeriodicEventThreads(void(*thread1)(void), uint32_t period1,
|
||||||
|
void(*thread2)(void), uint32_t period2){ //TODO
|
||||||
|
int32_t status;
|
||||||
|
status = StartCritical();
|
||||||
|
periodic[0].period = period1;
|
||||||
|
periodic[0].task = thread1;
|
||||||
|
periodic[1].period = period2;
|
||||||
|
periodic[1].task = thread2;
|
||||||
|
EndCritical(status);
|
||||||
|
return 1; // successful
|
||||||
|
}
|
||||||
|
|
||||||
|
//******** OS_Launch ***************
|
||||||
|
// Start the scheduler, enable interrupts
|
||||||
|
// Inputs: number of clock cycles for each time slice
|
||||||
|
// Outputs: none (does not return)
|
||||||
|
// Errors: theTimeSlice must be less than 16,777,216
|
||||||
|
void OS_Launch(uint32_t theTimeSlice){
|
||||||
|
STCTRL = 0; // disable SysTick during setup
|
||||||
|
STCURRENT = 0; // any write to current clears it
|
||||||
|
SYSPRI3 =(SYSPRI3&0x00FFFFFF)|0xE0000000; // priority 7
|
||||||
|
STRELOAD = theTimeSlice - 1; // reload value
|
||||||
|
STCTRL = 0x00000007; // enable, core clock and interrupt arm
|
||||||
|
StartOS(); // start on the first task
|
||||||
|
}
|
||||||
|
static uint32_t timer = 0;
|
||||||
|
// runs every ms
|
||||||
|
void Scheduler(void){ // every time slice
|
||||||
|
// run any periodic event threads if needed
|
||||||
|
// implement round robin scheduler, update RunPt
|
||||||
|
|
||||||
|
for (int i = 0; i < 2; ++i) {
|
||||||
|
if ((timer % periodic[i].period) == 0) {
|
||||||
|
periodic[i].task();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
++timer;
|
||||||
|
|
||||||
|
RunPt = RunPt->next; // Round Robin
|
||||||
|
}
|
||||||
|
|
||||||
|
// ******** OS_InitSemaphore ************
|
||||||
|
// Initialize counting semaphore
|
||||||
|
// Inputs: pointer to a semaphore
|
||||||
|
// initial value of semaphore
|
||||||
|
// Outputs: none
|
||||||
|
void OS_InitSemaphore(int32_t *semaPt, int32_t value){
|
||||||
|
*semaPt = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ******** OS_Wait ************
|
||||||
|
// Decrement semaphore
|
||||||
|
// Lab2 spinlock (does not suspend while spinning)
|
||||||
|
// Lab3 block if less than zero
|
||||||
|
// Inputs: pointer to a counting semaphore
|
||||||
|
// Outputs: none
|
||||||
|
void OS_Wait(int32_t *semaPt){
|
||||||
|
uint32_t status = StartCritical();
|
||||||
|
while (*semaPt <= 0) {
|
||||||
|
EndCritical(status);
|
||||||
|
status = StartCritical();
|
||||||
|
}
|
||||||
|
--(*semaPt);
|
||||||
|
EndCritical(status);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ******** OS_Signal ************
|
||||||
|
// Increment semaphore
|
||||||
|
// Lab2 spinlock
|
||||||
|
// Lab3 wakeup blocked thread if appropriate
|
||||||
|
// Inputs: pointer to a counting semaphore
|
||||||
|
// Outputs: none
|
||||||
|
void OS_Signal(int32_t *semaPt){
|
||||||
|
uint32_t status = StartCritical();
|
||||||
|
++(*semaPt);
|
||||||
|
EndCritical(status);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// ******** OS_MailBox_Init ************
|
||||||
|
// Initialize communication channel
|
||||||
|
// Producer is an event thread, consumer is a main thread
|
||||||
|
// Inputs: none
|
||||||
|
// Outputs: none
|
||||||
|
uint32_t MailBox;
|
||||||
|
int32_t MailBox_Send;
|
||||||
|
int32_t MailBox_Ack;
|
||||||
|
void OS_MailBox_Init(void){
|
||||||
|
// include data field and semaphore
|
||||||
|
MailBox = 0;
|
||||||
|
OS_InitSemaphore(&MailBox_Send, 0);
|
||||||
|
OS_InitSemaphore(&MailBox_Ack, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ******** OS_MailBox_Send ************
|
||||||
|
// Enter data into the MailBox, do not spin/block if full
|
||||||
|
// Use semaphore to synchronize with OS_MailBox_Recv
|
||||||
|
// Inputs: data to be sent
|
||||||
|
// Outputs: none
|
||||||
|
// Errors: data lost if MailBox already has data
|
||||||
|
void OS_MailBox_Send(uint32_t data){
|
||||||
|
MailBox = data; // Overwrite data (may lose old data)
|
||||||
|
OS_Signal(&MailBox_Send); // Signal data availability
|
||||||
|
}
|
||||||
|
|
||||||
|
// ******** OS_MailBox_Recv ************
|
||||||
|
// retreive mail from the MailBox
|
||||||
|
// Use semaphore to synchronize with OS_MailBox_Send
|
||||||
|
// Lab 2 spin on semaphore if mailbox empty
|
||||||
|
// Lab 3 block on semaphore if mailbox empty
|
||||||
|
// Inputs: none
|
||||||
|
// Outputs: data retreived
|
||||||
|
// Errors: none
|
||||||
|
uint32_t OS_MailBox_Recv(void){
|
||||||
|
OS_Wait(&MailBox_Send);
|
||||||
|
int32_t data = MailBox; // read mail
|
||||||
|
return data;
|
||||||
|
}
|
|
@ -0,0 +1,142 @@
|
||||||
|
// os.h
|
||||||
|
// Runs on LM4F120/TM4C123/MSP432
|
||||||
|
// A very simple real time operating system with minimal features.
|
||||||
|
// Daniel Valvano
|
||||||
|
// February 20, 2016
|
||||||
|
|
||||||
|
/* This example accompanies the book
|
||||||
|
|
||||||
|
"Embedded Systems: Real-Time Operating Systems for ARM Cortex-M Microcontrollers",
|
||||||
|
ISBN: 978-1466468863, , Jonathan Valvano, copyright (c) 2016
|
||||||
|
Programs 4.4 through 4.12, section 4.2
|
||||||
|
|
||||||
|
Copyright 2016 by Jonathan W. Valvano, valvano@mail.utexas.edu
|
||||||
|
You may use, edit, run or distribute this file
|
||||||
|
as long as the above copyright notice remains
|
||||||
|
THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED
|
||||||
|
OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
|
||||||
|
VALVANO SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL,
|
||||||
|
OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
|
||||||
|
For more information about my classes, my research, and my books, see
|
||||||
|
http://users.ece.utexas.edu/~valvano/
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef __OS_H
|
||||||
|
#define __OS_H 1
|
||||||
|
// grader needs access to TCBs and stacks
|
||||||
|
#define NUMTHREADS 4 // maximum number of threads
|
||||||
|
#define NUMEVENTTHREADS 2
|
||||||
|
#define STACKSIZE 100 // number of 32-bit words in stack per thread
|
||||||
|
struct tcb{
|
||||||
|
int32_t *sp; // pointer to stack (valid for threads not running
|
||||||
|
struct tcb *next; // linked-list pointer
|
||||||
|
};
|
||||||
|
typedef struct tcb tcbType;
|
||||||
|
|
||||||
|
struct periodic{
|
||||||
|
uint32_t period;
|
||||||
|
void(*task)(void);
|
||||||
|
};
|
||||||
|
typedef struct periodic periodicType;
|
||||||
|
|
||||||
|
// ******** OS_Init ************
|
||||||
|
// Initialize operating system, disable interrupts
|
||||||
|
// Initialize OS controlled I/O: systick, bus clock as fast as possible
|
||||||
|
// Initialize OS global variables
|
||||||
|
// Inputs: none
|
||||||
|
// Outputs: none
|
||||||
|
void OS_Init(void);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//******** OS_AddThreads ***************
|
||||||
|
// Add four main threads to the scheduler
|
||||||
|
// Inputs: function pointers to four void/void main threads
|
||||||
|
// Outputs: 1 if successful, 0 if this thread can not be added
|
||||||
|
// This function will only be called once, after OS_Init and before OS_Launch
|
||||||
|
int OS_AddThreads(void(*thread0)(void),
|
||||||
|
void(*thread1)(void),
|
||||||
|
void(*thread2)(void),
|
||||||
|
void(*thread3)(void));
|
||||||
|
|
||||||
|
//******** OS_AddThreads3 ***************
|
||||||
|
// add three foregound threads to the scheduler
|
||||||
|
// This is needed during debugging and not part of final solution
|
||||||
|
// Inputs: three pointers to a void/void foreground tasks
|
||||||
|
// Outputs: 1 if successful, 0 if this thread can not be added
|
||||||
|
int OS_AddThreads3(void(*task0)(void),
|
||||||
|
void(*task1)(void),
|
||||||
|
void(*task2)(void));
|
||||||
|
|
||||||
|
//******** OS_AddPeriodicEventThreads ***************
|
||||||
|
// Add two background periodic event threads
|
||||||
|
// Typically this function receives the highest priority
|
||||||
|
// Inputs: pointers to a void/void event thread function2
|
||||||
|
// periods given in units of OS_Launch (Lab 2 this will be msec)
|
||||||
|
// Outputs: 1 if successful, 0 if this thread cannot be added
|
||||||
|
// It is assumed that the event threads will run to completion and return
|
||||||
|
// It is assumed the time to run these event threads is short compared to 1 msec
|
||||||
|
// These threads cannot spin, block, loop, sleep, or kill
|
||||||
|
// These threads can call OS_Signal
|
||||||
|
int OS_AddPeriodicEventThreads(void(*thread1)(void), uint32_t period1,
|
||||||
|
void(*thread2)(void), uint32_t period2);
|
||||||
|
|
||||||
|
//******** OS_Launch ***************
|
||||||
|
// Start the scheduler, enable interrupts
|
||||||
|
// Inputs: number of clock cycles for each time slice
|
||||||
|
// Outputs: none (does not return)
|
||||||
|
// Errors: theTimeSlice must be less than 16,777,216
|
||||||
|
void OS_Launch(uint32_t theTimeSlice);
|
||||||
|
|
||||||
|
|
||||||
|
// ******** OS_InitSemaphore ************
|
||||||
|
// Initialize counting semaphore
|
||||||
|
// Inputs: pointer to a semaphore
|
||||||
|
// initial value of semaphore
|
||||||
|
// Outputs: none
|
||||||
|
void OS_InitSemaphore(int32_t *semaPt, int32_t value);
|
||||||
|
|
||||||
|
// ******** OS_Wait ************
|
||||||
|
// Decrement semaphore
|
||||||
|
// Lab2 spinlock (does not suspend while spinning)
|
||||||
|
// Lab3 block if less than zero
|
||||||
|
// Inputs: pointer to a counting semaphore
|
||||||
|
// Outputs: none
|
||||||
|
void OS_Wait(int32_t *semaPt);
|
||||||
|
|
||||||
|
// ******** OS_Signal ************
|
||||||
|
// Increment semaphore
|
||||||
|
// Lab2 spinlock
|
||||||
|
// Lab3 wakeup blocked thread if appropriate
|
||||||
|
// Inputs: pointer to a counting semaphore
|
||||||
|
// Outputs: none
|
||||||
|
void OS_Signal(int32_t *semaPt);
|
||||||
|
|
||||||
|
// ******** OS_MailBox_Init ************
|
||||||
|
// Initialize communication channel
|
||||||
|
// Producer is an event thread, consumer is a main thread
|
||||||
|
// Inputs: none
|
||||||
|
// Outputs: none
|
||||||
|
void OS_MailBox_Init(void);
|
||||||
|
|
||||||
|
// ******** OS_MailBox_Send ************
|
||||||
|
// Enter data into the MailBox, do not spin/block if full
|
||||||
|
// Use semaphore to synchronize with OS_MailBox_Recv
|
||||||
|
// Inputs: data to be sent
|
||||||
|
// Outputs: none
|
||||||
|
// Errors: data lost if MailBox already has data
|
||||||
|
void OS_MailBox_Send(uint32_t data);
|
||||||
|
|
||||||
|
// ******** OS_MailBox_Recv ************
|
||||||
|
// retreive mail from the MailBox
|
||||||
|
// Use semaphore to synchronize with OS_MailBox_Send
|
||||||
|
// Lab 2 spin on semaphore if mailbox empty
|
||||||
|
// Lab 3 block on semaphore if mailbox empty
|
||||||
|
// Inputs: none
|
||||||
|
// Outputs: data retreived
|
||||||
|
// Errors: none
|
||||||
|
uint32_t OS_MailBox_Recv(void);
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,49 @@
|
||||||
|
;/*****************************************************************************/
|
||||||
|
; OSasm.s: low-level OS commands, written in assembly */
|
||||||
|
; Runs on LM4F120/TM4C123/MSP432
|
||||||
|
; Lab 2 starter file
|
||||||
|
; February 10, 2016
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
|
AREA |.text|, CODE, READONLY, ALIGN=2
|
||||||
|
THUMB
|
||||||
|
REQUIRE8
|
||||||
|
PRESERVE8
|
||||||
|
|
||||||
|
EXTERN RunPt ; currently running thread
|
||||||
|
EXPORT StartOS
|
||||||
|
EXPORT SysTick_Handler
|
||||||
|
IMPORT Scheduler
|
||||||
|
|
||||||
|
|
||||||
|
SysTick_Handler ; 1) Saves R0-R3,R12,LR,PC,PSR
|
||||||
|
CPSID I ; 2) Prevent interrupt during switch
|
||||||
|
PUSH {R4-R11} ; 3) Save remaining regs r4-11
|
||||||
|
LDR R0, =RunPt ; 4) R0=pointer to RunPt, old thread
|
||||||
|
LDR R1, [R0] ; R1 = RunPt
|
||||||
|
STR SP, [R1] ; 5) Save SP into TCB
|
||||||
|
PUSH {R0,LR}
|
||||||
|
BL Scheduler
|
||||||
|
POP {R0,LR}
|
||||||
|
LDR R1, [R0] ; 6) R1 = RunPt, new thread
|
||||||
|
LDR SP, [R1] ; 7) new thread SP; SP = RunPt->sp;
|
||||||
|
POP {R4-R11} ; 8) restore regs r4-11
|
||||||
|
CPSIE I ; 9) tasks run with interrupts enabled
|
||||||
|
BX LR ; 10) restore R0-R3,R12,LR,PC,PSR
|
||||||
|
|
||||||
|
StartOS
|
||||||
|
LDR R0, =RunPt ; currently running thread
|
||||||
|
LDR R2, [R0] ; R2 = value of RunPt
|
||||||
|
LDR SP, [R2] ; new thread SP; SP = RunPt->stackPointer;
|
||||||
|
POP {R4-R11} ; restore regs r4-11
|
||||||
|
POP {R0-R3} ; restore regs r0-3
|
||||||
|
POP {R12}
|
||||||
|
ADD SP,SP,#4 ; discard LR from initial stack
|
||||||
|
POP {LR} ; start location
|
||||||
|
ADD SP,SP,#4 ; discard PSR
|
||||||
|
CPSIE I ; Enable interrupts at processor level
|
||||||
|
BX LR ; start first thread
|
||||||
|
|
||||||
|
ALIGN
|
||||||
|
END
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,125 @@
|
||||||
|
// *****************Texas.h**************
|
||||||
|
// grading engine for Lab 3
|
||||||
|
//
|
||||||
|
// Runs on TM4C123
|
||||||
|
// Daniel and Jonathan Valvano
|
||||||
|
// March 23, 2016
|
||||||
|
|
||||||
|
/* This example accompanies the books
|
||||||
|
"Embedded Systems: Real Time Interfacing to ARM Cortex M Microcontrollers",
|
||||||
|
ISBN: 978-1463590154, Jonathan Valvano, copyright (c) 2016
|
||||||
|
|
||||||
|
"Embedded Systems: Real-Time Operating Systems for ARM Cortex-M Microcontrollers",
|
||||||
|
ISBN: 978-1466468863, Jonathan Valvano, copyright (c) 2016
|
||||||
|
|
||||||
|
Copyright 2016 by Jonathan W. Valvano, valvano@mail.utexas.edu
|
||||||
|
You may use, edit, run or distribute this file
|
||||||
|
as long as the above copyright notice remains
|
||||||
|
THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED
|
||||||
|
OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
|
||||||
|
VALVANO SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL,
|
||||||
|
OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
|
||||||
|
For more information about my classes, my research, and my books, see
|
||||||
|
http://users.ece.utexas.edu/~valvano/
|
||||||
|
*/
|
||||||
|
|
||||||
|
// J1 J3 J4 J2
|
||||||
|
// [ 1] [21] [40] [20]
|
||||||
|
// [ 2] [22] [39] [19]
|
||||||
|
// [ 3] [23] [38] [18]
|
||||||
|
// [ 4] [24] [37] [17]
|
||||||
|
// [ 5] [25] [36] [16]
|
||||||
|
// [ 6] [26] [35] [15]
|
||||||
|
// [ 7] [27] [34] [14]
|
||||||
|
// [ 8] [28] [33] [13]
|
||||||
|
// [ 9] [29] [32] [12]
|
||||||
|
// [10] [30] [31] [11]
|
||||||
|
|
||||||
|
// +3.3V connected to J1.1 (power)
|
||||||
|
// joystick horizontal (X) connected to J1.2 (analog)
|
||||||
|
// UART from BoosterPack to LaunchPad connected to J1.3 (UART)
|
||||||
|
// UART from LaunchPad to BoosterPack connected to J1.4 (UART)
|
||||||
|
// joystick Select button connected to J1.5 (digital)
|
||||||
|
// microphone connected to J1.6 (analog)
|
||||||
|
// LCD SPI clock connected to J1.7 (SPI)
|
||||||
|
// ambient light (OPT3001) interrupt connected to J1.8 (digital)
|
||||||
|
// ambient light (OPT3001) and temperature sensor (TMP006) I2C SCL connected to J1.9 (I2C)
|
||||||
|
// ambient light (OPT3001) and temperature sensor (TMP006) I2C SDA connected to J1.10 (I2C)
|
||||||
|
|
||||||
|
// temperature sensor (TMP006) interrupt connected to J2.11 (digital)
|
||||||
|
// nothing connected to J2.12 (SPI CS_Other)
|
||||||
|
// LCD SPI CS connected to J2.13 (SPI)
|
||||||
|
// nothing connected to J2.14 (SPI MISO)
|
||||||
|
// LCD SPI data connected to J2.15 (SPI)
|
||||||
|
// nothing connected to J2.16 (reset)
|
||||||
|
// LCD !RST connected to J2.17 (digital)
|
||||||
|
// nothing connected to J2.18 (SPI CS_Wireless)
|
||||||
|
// servo PWM connected to J2.19 (PWM)
|
||||||
|
// GND connected to J2.20 (ground)
|
||||||
|
|
||||||
|
// +5V connected to J3.21 (power)
|
||||||
|
// GND connected to J3.22 (ground)
|
||||||
|
// accelerometer X connected to J3.23 (analog)
|
||||||
|
// accelerometer Y connected to J3.24 (analog)
|
||||||
|
// accelerometer Z connected to J3.25 (analog)
|
||||||
|
// joystick vertical (Y) connected to J3.26 (analog)
|
||||||
|
// nothing connected to J3.27 (I2S WS)
|
||||||
|
// nothing connected to J3.28 (I2S SCLK)
|
||||||
|
// nothing connected to J3.29 (I2S SDout)
|
||||||
|
// nothing connected to J3.30 (I2S SDin)
|
||||||
|
|
||||||
|
// LCD RS connected to J4.31 (digital)
|
||||||
|
// user Button2 (bottom) connected to J4.32 (digital)
|
||||||
|
// user Button1 (top) connected to J4.33 (digital)
|
||||||
|
// gator hole switch connected to J4.34 (digital)
|
||||||
|
// nothing connected to J4.35
|
||||||
|
// nothing connected to J4.36
|
||||||
|
// RGB LED blue connected to J4.37 (PWM)
|
||||||
|
// RGB LED green connected to J4.38 (PWM)
|
||||||
|
// RGB LED red (jumper up) or LCD backlight (jumper down) connected to J4.39 (PWM)
|
||||||
|
// buzzer connected to J4.40 (PWM)
|
||||||
|
|
||||||
|
enum TExaSmode{
|
||||||
|
GRADER,
|
||||||
|
GRADESTEP2,
|
||||||
|
GRADESTEP3,
|
||||||
|
GRADESTEP4,
|
||||||
|
GRADESTEP5,
|
||||||
|
LOGICANALYZER
|
||||||
|
};
|
||||||
|
|
||||||
|
// ************TExaS_Init*****************
|
||||||
|
// Initialize grader, triggered by periodic timer
|
||||||
|
// This needs to be called once
|
||||||
|
// Inputs: Grading or Logic analyzer
|
||||||
|
// 4-digit number from edX
|
||||||
|
// Outputs: none
|
||||||
|
void TExaS_Init(enum TExaSmode mode, uint32_t edXcode);
|
||||||
|
|
||||||
|
// ************TExaS_Stop*****************
|
||||||
|
// Stop the transfer
|
||||||
|
// Inputs: none
|
||||||
|
// Outputs: none
|
||||||
|
void TExaS_Stop(void);
|
||||||
|
|
||||||
|
// record time Task 0 is started
|
||||||
|
void TExaS_Task0(void);
|
||||||
|
|
||||||
|
// record time Task 0 is started
|
||||||
|
void TExaS_Task1(void);
|
||||||
|
|
||||||
|
// record time Task 2 is started
|
||||||
|
void TExaS_Task2(void);
|
||||||
|
|
||||||
|
// record time Task 3 is started
|
||||||
|
void TExaS_Task3(void);
|
||||||
|
|
||||||
|
// record time Task 4 is started
|
||||||
|
void TExaS_Task4(void);
|
||||||
|
|
||||||
|
// record time Task 5 is started
|
||||||
|
void TExaS_Task5(void);
|
||||||
|
|
||||||
|
// record time Task 6 is started
|
||||||
|
void TExaS_Task6(void);
|
|
@ -0,0 +1,215 @@
|
||||||
|
// os.c
|
||||||
|
// Runs on LM4F120/TM4C123/MSP432
|
||||||
|
// Lab 3 starter file.
|
||||||
|
// Daniel Valvano
|
||||||
|
// March 24, 2016
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "os.h"
|
||||||
|
#include "CortexM.h"
|
||||||
|
#include "BSP.h"
|
||||||
|
|
||||||
|
// function definitions in osasm.s
|
||||||
|
void StartOS(void);
|
||||||
|
|
||||||
|
#define NUMTHREADS 6 // maximum number of threads
|
||||||
|
#define NUMPERIODIC 2 // maximum number of periodic threads
|
||||||
|
#define STACKSIZE 100 // number of 32-bit words in stack per thread
|
||||||
|
struct tcb{
|
||||||
|
int32_t *sp; // pointer to stack (valid for threads not running
|
||||||
|
struct tcb *next; // linked-list pointer
|
||||||
|
// nonzero if blocked on this semaphore
|
||||||
|
// nonzero if this thread is sleeping
|
||||||
|
//*FILL THIS IN****
|
||||||
|
};
|
||||||
|
typedef struct tcb tcbType;
|
||||||
|
tcbType tcbs[NUMTHREADS];
|
||||||
|
tcbType *RunPt;
|
||||||
|
int32_t Stacks[NUMTHREADS][STACKSIZE];
|
||||||
|
|
||||||
|
|
||||||
|
// ******** OS_Init ************
|
||||||
|
// Initialize operating system, disable interrupts
|
||||||
|
// Initialize OS controlled I/O: periodic interrupt, bus clock as fast as possible
|
||||||
|
// Initialize OS global variables
|
||||||
|
// Inputs: none
|
||||||
|
// Outputs: none
|
||||||
|
void OS_Init(void){
|
||||||
|
DisableInterrupts();
|
||||||
|
BSP_Clock_InitFastest();// set processor clock to fastest speed
|
||||||
|
// perform any initializations needed
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetInitialStack(int i){
|
||||||
|
// **Same as Lab 2****
|
||||||
|
tcbs[i].sp = &Stacks[i][STACKSIZE - 16];
|
||||||
|
|
||||||
|
Stacks[i][STACKSIZE-1] = 0x01000000; // Thumb bit
|
||||||
|
//Stacks[i][STACKSIZE-2] is reserved for PC
|
||||||
|
//and is initialized with start address of task
|
||||||
|
Stacks[i][STACKSIZE-3] = 0x14141414; // R14 = LR
|
||||||
|
Stacks[i][STACKSIZE-4] = 0x12121212; // R12
|
||||||
|
Stacks[i][STACKSIZE-5] = 0x03030303; // R3
|
||||||
|
Stacks[i][STACKSIZE-6] = 0x02020202; // R2
|
||||||
|
Stacks[i][STACKSIZE-7] = 0x01010101; // R1
|
||||||
|
Stacks[i][STACKSIZE-8] = 0x00000000; // R0
|
||||||
|
Stacks[i][STACKSIZE-9] = 0x11111111; // R11
|
||||||
|
Stacks[i][STACKSIZE-10] = 0x10101010; // R10
|
||||||
|
Stacks[i][STACKSIZE-11] = 0x09090909; // R9
|
||||||
|
Stacks[i][STACKSIZE-12] = 0x08080808; // R8
|
||||||
|
Stacks[i][STACKSIZE-13] = 0x07070707; // R7
|
||||||
|
Stacks[i][STACKSIZE-14] = 0x06060606; // R6
|
||||||
|
Stacks[i][STACKSIZE-15] = 0x05050505; // R5
|
||||||
|
Stacks[i][STACKSIZE-16] = 0x04040404; // R4
|
||||||
|
}
|
||||||
|
|
||||||
|
//******** OS_AddThreads ***************
|
||||||
|
// Add six main threads to the scheduler
|
||||||
|
// Inputs: function pointers to six void/void main threads
|
||||||
|
// Outputs: 1 if successful, 0 if this thread can not be added
|
||||||
|
// This function will only be called once, after OS_Init and before OS_Launch
|
||||||
|
int OS_AddThreads(void(*thread0)(void),
|
||||||
|
void(*thread1)(void),
|
||||||
|
void(*thread2)(void),
|
||||||
|
void(*thread3)(void),
|
||||||
|
void(*thread4)(void),
|
||||||
|
void(*thread5)(void)){
|
||||||
|
// **similar to Lab 2. initialize as not blocked, not sleeping****
|
||||||
|
|
||||||
|
return 1; // successful
|
||||||
|
}
|
||||||
|
|
||||||
|
//******** OS_AddPeriodicEventThread ***************
|
||||||
|
// Add one background periodic event thread
|
||||||
|
// Typically this function receives the highest priority
|
||||||
|
// Inputs: pointer to a void/void event thread function
|
||||||
|
// period given in units of OS_Launch (Lab 3 this will be msec)
|
||||||
|
// Outputs: 1 if successful, 0 if this thread cannot be added
|
||||||
|
// It is assumed that the event threads will run to completion and return
|
||||||
|
// It is assumed the time to run these event threads is short compared to 1 msec
|
||||||
|
// These threads cannot spin, block, loop, sleep, or kill
|
||||||
|
// These threads can call OS_Signal
|
||||||
|
// In Lab 3 this will be called exactly twice
|
||||||
|
int OS_AddPeriodicEventThread(void(*thread)(void), uint32_t period){
|
||||||
|
// ****IMPLEMENT THIS****
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void static runperiodicevents(void){
|
||||||
|
// ****IMPLEMENT THIS****
|
||||||
|
// **RUN PERIODIC THREADS, DECREMENT SLEEP COUNTERS
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//******** OS_Launch ***************
|
||||||
|
// Start the scheduler, enable interrupts
|
||||||
|
// Inputs: number of clock cycles for each time slice
|
||||||
|
// Outputs: none (does not return)
|
||||||
|
// Errors: theTimeSlice must be less than 16,777,216
|
||||||
|
void OS_Launch(uint32_t theTimeSlice){
|
||||||
|
STCTRL = 0; // disable SysTick during setup
|
||||||
|
STCURRENT = 0; // any write to current clears it
|
||||||
|
SYSPRI3 =(SYSPRI3&0x00FFFFFF)|0xE0000000; // priority 7
|
||||||
|
STRELOAD = theTimeSlice - 1; // reload value
|
||||||
|
STCTRL = 0x00000007; // enable, core clock and interrupt arm
|
||||||
|
StartOS(); // start on the first task
|
||||||
|
}
|
||||||
|
// runs every ms
|
||||||
|
void Scheduler(void){ // every time slice
|
||||||
|
// ROUND ROBIN, skip blocked and sleeping threads
|
||||||
|
}
|
||||||
|
|
||||||
|
//******** OS_Suspend ***************
|
||||||
|
// Called by main thread to cooperatively suspend operation
|
||||||
|
// Inputs: none
|
||||||
|
// Outputs: none
|
||||||
|
// Will be run again depending on sleep/block status
|
||||||
|
void OS_Suspend(void){
|
||||||
|
STCURRENT = 0; // any write to current clears it
|
||||||
|
INTCTRL = 0x04000000; // trigger SysTick
|
||||||
|
// next thread gets a full time slice
|
||||||
|
}
|
||||||
|
|
||||||
|
// ******** OS_Sleep ************
|
||||||
|
// place this thread into a dormant state
|
||||||
|
// input: number of msec to sleep
|
||||||
|
// output: none
|
||||||
|
// OS_Sleep(0) implements cooperative multitasking
|
||||||
|
void OS_Sleep(uint32_t sleepTime){
|
||||||
|
// set sleep parameter in TCB
|
||||||
|
// suspend, stops running
|
||||||
|
}
|
||||||
|
|
||||||
|
// ******** OS_InitSemaphore ************
|
||||||
|
// Initialize counting semaphore
|
||||||
|
// Inputs: pointer to a semaphore
|
||||||
|
// initial value of semaphore
|
||||||
|
// Outputs: none
|
||||||
|
void OS_InitSemaphore(int32_t *semaPt, int32_t value){
|
||||||
|
//***IMPLEMENT THIS***
|
||||||
|
}
|
||||||
|
|
||||||
|
// ******** OS_Wait ************
|
||||||
|
// Decrement semaphore and block if less than zero
|
||||||
|
// Lab2 spinlock (does not suspend while spinning)
|
||||||
|
// Lab3 block if less than zero
|
||||||
|
// Inputs: pointer to a counting semaphore
|
||||||
|
// Outputs: none
|
||||||
|
void OS_Wait(int32_t *semaPt){
|
||||||
|
//***IMPLEMENT THIS***
|
||||||
|
}
|
||||||
|
|
||||||
|
// ******** OS_Signal ************
|
||||||
|
// Increment semaphore
|
||||||
|
// Lab2 spinlock
|
||||||
|
// Lab3 wakeup blocked thread if appropriate
|
||||||
|
// Inputs: pointer to a counting semaphore
|
||||||
|
// Outputs: none
|
||||||
|
void OS_Signal(int32_t *semaPt){
|
||||||
|
//***IMPLEMENT THIS***
|
||||||
|
}
|
||||||
|
|
||||||
|
#define FSIZE 10 // can be any size
|
||||||
|
uint32_t PutI; // index of where to put next
|
||||||
|
uint32_t GetI; // index of where to get next
|
||||||
|
uint32_t Fifo[FSIZE];
|
||||||
|
int32_t CurrentSize;// 0 means FIFO empty, FSIZE means full
|
||||||
|
uint32_t LostData; // number of lost pieces of data
|
||||||
|
|
||||||
|
// ******** OS_FIFO_Init ************
|
||||||
|
// Initialize FIFO.
|
||||||
|
// One event thread producer, one main thread consumer
|
||||||
|
// Inputs: none
|
||||||
|
// Outputs: none
|
||||||
|
void OS_FIFO_Init(void){
|
||||||
|
//***IMPLEMENT THIS***
|
||||||
|
}
|
||||||
|
|
||||||
|
// ******** OS_FIFO_Put ************
|
||||||
|
// Put an entry in the FIFO.
|
||||||
|
// Exactly one event thread puts,
|
||||||
|
// do not block or spin if full
|
||||||
|
// Inputs: data to be stored
|
||||||
|
// Outputs: 0 if successful, -1 if the FIFO is full
|
||||||
|
int OS_FIFO_Put(uint32_t data){
|
||||||
|
//***IMPLEMENT THIS***
|
||||||
|
|
||||||
|
return 0; // success
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// ******** OS_FIFO_Get ************
|
||||||
|
// Get an entry from the FIFO.
|
||||||
|
// Exactly one main thread get,
|
||||||
|
// do block if empty
|
||||||
|
// Inputs: none
|
||||||
|
// Outputs: data retrieved
|
||||||
|
uint32_t OS_FIFO_Get(void){uint32_t data;
|
||||||
|
//***IMPLEMENT THIS***
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,132 @@
|
||||||
|
// os.h
|
||||||
|
// Runs on LM4F120/TM4C123/MSP432
|
||||||
|
// A very simple real time operating system with minimal features.
|
||||||
|
// Daniel Valvano
|
||||||
|
// March 24, 2016
|
||||||
|
|
||||||
|
/* This example accompanies the book
|
||||||
|
"Embedded Systems: Real Time Interfacing to ARM Cortex M Microcontrollers",
|
||||||
|
ISBN: 978-1463590154, Jonathan Valvano, copyright (c) 2016
|
||||||
|
|
||||||
|
"Embedded Systems: Real-Time Operating Systems for ARM Cortex-M Microcontrollers",
|
||||||
|
ISBN: 978-1466468863, , Jonathan Valvano, copyright (c) 2016
|
||||||
|
Programs 4.4 through 4.12, section 4.2
|
||||||
|
|
||||||
|
Copyright 2016 by Jonathan W. Valvano, valvano@mail.utexas.edu
|
||||||
|
You may use, edit, run or distribute this file
|
||||||
|
as long as the above copyright notice remains
|
||||||
|
THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED
|
||||||
|
OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
|
||||||
|
VALVANO SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL,
|
||||||
|
OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
|
||||||
|
For more information about my classes, my research, and my books, see
|
||||||
|
http://users.ece.utexas.edu/~valvano/
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef __OS_H
|
||||||
|
#define __OS_H 1
|
||||||
|
|
||||||
|
|
||||||
|
// ******** OS_Init ************
|
||||||
|
// Initialize operating system, disable interrupts
|
||||||
|
// Initialize OS controlled I/O: periodic interrupt, bus clock as fast as possible
|
||||||
|
// Initialize OS global variables
|
||||||
|
// Inputs: none
|
||||||
|
// Outputs: none
|
||||||
|
void OS_Init(void);
|
||||||
|
|
||||||
|
//******** OS_AddThreads ***************
|
||||||
|
// Add six main threads to the scheduler
|
||||||
|
// Inputs: function pointers to six void/void main threads
|
||||||
|
// Outputs: 1 if successful, 0 if this thread can not be added
|
||||||
|
// This function will only be called once, after OS_Init and before OS_Launch
|
||||||
|
int OS_AddThreads(void(*thread0)(void),
|
||||||
|
void(*thread1)(void),
|
||||||
|
void(*thread2)(void),
|
||||||
|
void(*thread3)(void),
|
||||||
|
void(*thread4)(void),
|
||||||
|
void(*thread5)(void));
|
||||||
|
|
||||||
|
//******** OS_AddPeriodicEventThread ***************
|
||||||
|
// Add one background periodic event thread
|
||||||
|
// Typically this function receives the highest priority
|
||||||
|
// Inputs: pointer to a void/void event thread function
|
||||||
|
// period given in units of OS_Launch (Lab 3 this will be msec)
|
||||||
|
// Outputs: 1 if successful, 0 if this thread cannot be added
|
||||||
|
// It is assumed that the event threads will run to completion and return
|
||||||
|
// It is assumed the time to run these event threads is short compared to 1 msec
|
||||||
|
// These threads cannot spin, block, loop, sleep, or kill
|
||||||
|
// These threads can call OS_Signal
|
||||||
|
// In Lab 3 this will be called exactly twice
|
||||||
|
int OS_AddPeriodicEventThread(void(*thread)(void), uint32_t period);
|
||||||
|
|
||||||
|
//******** OS_Launch ***************
|
||||||
|
// Start the scheduler, enable interrupts
|
||||||
|
// Inputs: number of clock cycles for each time slice
|
||||||
|
// Outputs: none (does not return)
|
||||||
|
// Errors: theTimeSlice must be less than 16,777,216
|
||||||
|
void OS_Launch(uint32_t theTimeSlice);
|
||||||
|
|
||||||
|
//******** OS_Suspend ***************
|
||||||
|
// Called by main thread to cooperatively suspend operation
|
||||||
|
// Inputs: none
|
||||||
|
// Outputs: none
|
||||||
|
// Will be run again depending on sleep/block status
|
||||||
|
void OS_Suspend(void);
|
||||||
|
|
||||||
|
// ******** OS_Sleep ************
|
||||||
|
// place this thread into a dormant state
|
||||||
|
// input: number of msec to sleep
|
||||||
|
// output: none
|
||||||
|
// OS_Sleep(0) implements cooperative multitasking
|
||||||
|
void OS_Sleep(uint32_t sleepTime);
|
||||||
|
|
||||||
|
// ******** OS_InitSemaphore ************
|
||||||
|
// Initialize counting semaphore
|
||||||
|
// Inputs: pointer to a semaphore
|
||||||
|
// initial value of semaphore
|
||||||
|
// Outputs: none
|
||||||
|
void OS_InitSemaphore(int32_t *semaPt, int32_t value);
|
||||||
|
|
||||||
|
// ******** OS_Wait ************
|
||||||
|
// Decrement semaphore and block if less than zero
|
||||||
|
// Lab2 spinlock (does not suspend while spinning)
|
||||||
|
// Lab3 block if less than zero
|
||||||
|
// Inputs: pointer to a counting semaphore
|
||||||
|
// Outputs: none
|
||||||
|
void OS_Wait(int32_t *semaPt);
|
||||||
|
|
||||||
|
// ******** OS_Signal ************
|
||||||
|
// Increment semaphore
|
||||||
|
// Lab2 spinlock
|
||||||
|
// Lab3 wakeup blocked thread if appropriate
|
||||||
|
// Inputs: pointer to a counting semaphore
|
||||||
|
// Outputs: none
|
||||||
|
void OS_Signal(int32_t *semaPt);
|
||||||
|
|
||||||
|
// ******** OS_FIFO_Init ************
|
||||||
|
// Initialize FIFO.
|
||||||
|
// One event thread producer, one main thread consumer
|
||||||
|
// Inputs: none
|
||||||
|
// Outputs: none
|
||||||
|
void OS_FIFO_Init(void);
|
||||||
|
|
||||||
|
// ******** OS_FIFO_Put ************
|
||||||
|
// Put an entry in the FIFO.
|
||||||
|
// Exactly one event thread puts,
|
||||||
|
// do not block or spin if full
|
||||||
|
// Inputs: data to be stored
|
||||||
|
// Outputs: 0 if successful, -1 if the FIFO is full
|
||||||
|
int OS_FIFO_Put(uint32_t data);
|
||||||
|
|
||||||
|
// ******** OS_FIFO_Get ************
|
||||||
|
// Get an entry from the FIFO.
|
||||||
|
// Exactly one main thread get,
|
||||||
|
// do block if empty
|
||||||
|
// Inputs: none
|
||||||
|
// Outputs: data retrieved
|
||||||
|
uint32_t OS_FIFO_Get(void);
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,34 @@
|
||||||
|
;/*****************************************************************************/
|
||||||
|
; OSasm.s: low-level OS commands, written in assembly */
|
||||||
|
; Runs on LM4F120/TM4C123/MSP432
|
||||||
|
; Lab 3 starter file
|
||||||
|
; March 2, 2016
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
AREA |.text|, CODE, READONLY, ALIGN=2
|
||||||
|
THUMB
|
||||||
|
REQUIRE8
|
||||||
|
PRESERVE8
|
||||||
|
|
||||||
|
EXTERN RunPt ; currently running thread
|
||||||
|
EXPORT StartOS
|
||||||
|
EXPORT SysTick_Handler
|
||||||
|
IMPORT Scheduler
|
||||||
|
|
||||||
|
|
||||||
|
SysTick_Handler ; 1) Saves R0-R3,R12,LR,PC,PSR
|
||||||
|
CPSID I ; 2) Prevent interrupt during switch
|
||||||
|
;YOU IMPLEMENT THIS (same as Lab 2)
|
||||||
|
CPSIE I ; 9) tasks run with interrupts enabled
|
||||||
|
BX LR ; 10) restore R0-R3,R12,LR,PC,PSR
|
||||||
|
|
||||||
|
StartOS
|
||||||
|
;YOU IMPLEMENT THIS (same as Lab 2)
|
||||||
|
|
||||||
|
CPSIE I ; Enable interrupts at processor level
|
||||||
|
BX LR ; start first thread
|
||||||
|
|
||||||
|
ALIGN
|
||||||
|
END
|
|
@ -0,0 +1,783 @@
|
||||||
|
// Lab4.c
|
||||||
|
// Runs on either MSP432 or TM4C123
|
||||||
|
// Starter project to Lab 4. Take sensor readings, process the data,
|
||||||
|
// and output the results. Specifically, this program will
|
||||||
|
// measure steps using the accelerometer, audio sound amplitude using
|
||||||
|
// the microphone, temperature using the TMP006, and light using the
|
||||||
|
// OPT3001.
|
||||||
|
// Daniel and Jonathan Valvano
|
||||||
|
// August 22, 2016
|
||||||
|
|
||||||
|
/* This example accompanies the books
|
||||||
|
"Embedded Systems: Real Time Interfacing to ARM Cortex M Microcontrollers",
|
||||||
|
ISBN: 978-1463590154, Jonathan Valvano, copyright (c) 2016
|
||||||
|
|
||||||
|
"Embedded Systems: Real-Time Operating Systems for ARM Cortex-M Microcontrollers",
|
||||||
|
ISBN: 978-1466468863, Jonathan Valvano, copyright (c) 2016
|
||||||
|
|
||||||
|
"Embedded Systems: Introduction to the MSP432 Microcontroller",
|
||||||
|
ISBN: 978-1512185676, Jonathan Valvano, copyright (c) 2016
|
||||||
|
|
||||||
|
"Embedded Systems: Real-Time Interfacing to the MSP432 Microcontroller",
|
||||||
|
ISBN: 978-1514676585, Jonathan Valvano, copyright (c) 2016
|
||||||
|
|
||||||
|
Copyright 2016 by Jonathan W. Valvano, valvano@mail.utexas.edu
|
||||||
|
You may use, edit, run or distribute this file
|
||||||
|
as long as the above copyright notice remains
|
||||||
|
THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED
|
||||||
|
OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
|
||||||
|
VALVANO SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL,
|
||||||
|
OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
|
||||||
|
For more information about my classes, my research, and my books, see
|
||||||
|
http://users.ece.utexas.edu/~valvano/
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "BSP.h"
|
||||||
|
#include "Profile.h"
|
||||||
|
#include "Texas.h"
|
||||||
|
#include "CortexM.h"
|
||||||
|
#include "os.h"
|
||||||
|
|
||||||
|
uint32_t sqrt32(uint32_t s);
|
||||||
|
#define THREADFREQ 1000 // frequency in Hz of round robin scheduler
|
||||||
|
|
||||||
|
//---------------- Global variables shared between tasks ----------------
|
||||||
|
uint32_t Time; // elasped time in 100 ms units
|
||||||
|
uint32_t Steps; // number of steps counted
|
||||||
|
uint32_t Magnitude; // will not overflow (3*1,023^2 = 3,139,587)
|
||||||
|
// Exponentially Weighted Moving Average
|
||||||
|
uint32_t EWMA; // https://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average
|
||||||
|
uint16_t SoundData; // raw data sampled from the microphone
|
||||||
|
int32_t SoundAvg;
|
||||||
|
|
||||||
|
uint32_t SoundRMS; // Root Mean Square average of most recent sound samples
|
||||||
|
uint32_t LightData; // 100 lux
|
||||||
|
int32_t TemperatureData; // 0.1C
|
||||||
|
// semaphores
|
||||||
|
int32_t NewData; // true when new numbers to display on top of LCD
|
||||||
|
int32_t LCDmutex; // exclusive access to LCD
|
||||||
|
int32_t I2Cmutex; // exclusive access to I2C
|
||||||
|
int ReDrawAxes = 0; // non-zero means redraw axes on next display task
|
||||||
|
|
||||||
|
enum plotstate{
|
||||||
|
Accelerometer,
|
||||||
|
Microphone,
|
||||||
|
Temperature,
|
||||||
|
Light
|
||||||
|
};
|
||||||
|
enum plotstate PlotState = Accelerometer;
|
||||||
|
//color constants
|
||||||
|
#define BGCOLOR LCD_BLACK
|
||||||
|
#define AXISCOLOR LCD_ORANGE
|
||||||
|
#define MAGCOLOR LCD_YELLOW
|
||||||
|
#define EWMACOLOR LCD_CYAN
|
||||||
|
#define SOUNDCOLOR LCD_CYAN
|
||||||
|
#define LIGHTCOLOR LCD_RED
|
||||||
|
#define TEMPCOLOR LCD_LIGHTGREEN
|
||||||
|
#define TOPTXTCOLOR LCD_WHITE
|
||||||
|
#define TOPNUMCOLOR LCD_ORANGE
|
||||||
|
//------------ end of Global variables shared between tasks -------------
|
||||||
|
|
||||||
|
//---------------- Task0 samples sound from microphone ----------------
|
||||||
|
// High priority thread run by OS in real time at 1000 Hz
|
||||||
|
#define SOUNDRMSLENGTH 1000 // number of samples to collect before calculating RMS (may overflow if greater than 4104)
|
||||||
|
int16_t SoundArray[SOUNDRMSLENGTH];
|
||||||
|
int32_t TakeSoundData; // binary semaphore
|
||||||
|
int32_t ADCmutex; // access to ADC
|
||||||
|
// *********Task0*********
|
||||||
|
// Task0 measures sound intensity
|
||||||
|
// Periodic main thread runs in real time at 1000 Hz
|
||||||
|
// collects data from microphone, high priority
|
||||||
|
// Inputs: none
|
||||||
|
// Outputs: none
|
||||||
|
void Task0(void){
|
||||||
|
static int32_t soundSum = 0;
|
||||||
|
static int time = 0;// units of microphone sampling rate
|
||||||
|
|
||||||
|
SoundRMS = 0;
|
||||||
|
while(1){
|
||||||
|
OS_Wait(&TakeSoundData); // signaled by OS every 1ms
|
||||||
|
TExaS_Task0(); // record system time in array, toggle virtual logic analyzer
|
||||||
|
Profile_Toggle0(); // viewed by the logic analyzer to know Task0 started
|
||||||
|
OS_Wait(&ADCmutex);
|
||||||
|
BSP_Microphone_Input(&SoundData);
|
||||||
|
OS_Signal(&ADCmutex);
|
||||||
|
soundSum = soundSum + (int32_t)SoundData;
|
||||||
|
SoundArray[time] = SoundData;
|
||||||
|
time = time + 1;
|
||||||
|
if(time == SOUNDRMSLENGTH){
|
||||||
|
SoundAvg = soundSum/SOUNDRMSLENGTH;
|
||||||
|
soundSum = 0;
|
||||||
|
OS_Signal(&NewData); // makes task5 run every 1 sec
|
||||||
|
time = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* ****************************************** */
|
||||||
|
/* End of Task0 Section */
|
||||||
|
/* ****************************************** */
|
||||||
|
|
||||||
|
//---------------- Task1 measures acceleration ----------------
|
||||||
|
// Event thread run by OS in real time at 10 Hz
|
||||||
|
int32_t TakeAccelerationData;
|
||||||
|
uint32_t LostTask1Data; // number of times that the FIFO was full when acceleration data was ready
|
||||||
|
uint16_t AccX, AccY, AccZ; // returned by BSP as 10-bit numbers
|
||||||
|
#define ALPHA 128 // The degree of weighting decrease, a constant smoothing factor between 0 and 1,023. A higher ALPHA discounts older observations faster.
|
||||||
|
// basic step counting algorithm is based on a forum post from
|
||||||
|
// http://stackoverflow.com/questions/16392142/android-accelerometer-profiling/16539643#16539643
|
||||||
|
enum state{ // the step counting algorithm cycles through four states
|
||||||
|
LookingForMax, // looking for a local maximum in current magnitude
|
||||||
|
LookingForCross1, // looking for current magnitude to cross average magnitude, minus a constant
|
||||||
|
LookingForMin, // looking for a local minimum in current magnitude
|
||||||
|
LookingForCross2 // looking for current magnitude to cross average magnitude, plus a constant
|
||||||
|
};
|
||||||
|
enum state AlgorithmState = LookingForMax;
|
||||||
|
#define LOCALCOUNTTARGET 5 // The number of valid measured magnitudes needed to confirm a local min or local max. Increase this number for longer strides or more frequent measurements.
|
||||||
|
#define AVGOVERSHOOT 25 // The amount above or below average a measurement must be to count as "crossing" the average. Increase this number to reject increasingly hard shaking as steps.
|
||||||
|
// *********Task1*********
|
||||||
|
// Task1 collects data from accelerometer in real time
|
||||||
|
// Periodic main thread runs in real time at 10 Hz
|
||||||
|
// Inputs: none
|
||||||
|
// Outputs: none
|
||||||
|
void Task1(void){uint32_t squared;
|
||||||
|
// initialize the exponential weighted moving average filter
|
||||||
|
BSP_Accelerometer_Input(&AccX, &AccY, &AccZ);
|
||||||
|
Magnitude = sqrt32(AccX*AccX + AccY*AccY + AccZ*AccZ);
|
||||||
|
EWMA = Magnitude; // this is a guess; there are many options
|
||||||
|
Steps = 0;
|
||||||
|
LostTask1Data = 0;
|
||||||
|
while(1){
|
||||||
|
OS_Wait(&TakeAccelerationData); // signaled by OS every 100ms
|
||||||
|
TExaS_Task1(); // records system time in array, toggles virtual logic analyzer
|
||||||
|
Profile_Toggle1(); // viewed by the logic analyzer to know Task1 started
|
||||||
|
OS_Wait(&ADCmutex);
|
||||||
|
BSP_Accelerometer_Input(&AccX, &AccY, &AccZ);
|
||||||
|
OS_Signal(&ADCmutex);
|
||||||
|
squared = AccX*AccX + AccY*AccY + AccZ*AccZ;
|
||||||
|
if(OS_FIFO_Put(squared) == -1){ // makes Task2 run every 100ms
|
||||||
|
LostTask1Data = LostTask1Data + 1;
|
||||||
|
}
|
||||||
|
Time++; // in 100ms units
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* ****************************************** */
|
||||||
|
/* End of Task1 Section */
|
||||||
|
/* ****************************************** */
|
||||||
|
|
||||||
|
|
||||||
|
//---------------- Task2 calculates steps and plots data on LCD ----------------
|
||||||
|
// Main thread scheduled by OS round robin preemptive scheduler
|
||||||
|
// accepts data from accelerometer, calculates steps, plots on LCD
|
||||||
|
// If no data are lost, the main loop in Task2 runs exactly at 10 Hz, but not in real time
|
||||||
|
#define ACCELERATION_MAX 1400
|
||||||
|
#define ACCELERATION_MIN 600
|
||||||
|
#define SOUND_MAX 900
|
||||||
|
#define SOUND_MIN 300
|
||||||
|
#define LIGHT_MAX 2000
|
||||||
|
#define LIGHT_MIN 0
|
||||||
|
#define TEMP_MAX 1023
|
||||||
|
#define TEMP_MIN 0
|
||||||
|
void drawaxes(void){
|
||||||
|
OS_Wait(&LCDmutex);
|
||||||
|
if(PlotState == Accelerometer){
|
||||||
|
BSP_LCD_Drawaxes(AXISCOLOR, BGCOLOR, "Time", "Mag", MAGCOLOR, "Ave", EWMACOLOR, ACCELERATION_MAX, ACCELERATION_MIN);
|
||||||
|
} else if(PlotState == Microphone){
|
||||||
|
BSP_LCD_Drawaxes(AXISCOLOR, BGCOLOR, "Time", "Sound", SOUNDCOLOR, "", 0, SoundData+100, SoundData-100);
|
||||||
|
} else if(PlotState == Temperature){
|
||||||
|
BSP_LCD_Drawaxes(AXISCOLOR, BGCOLOR, "Time", "Temp", TEMPCOLOR, "", 0, TEMP_MAX, TEMP_MIN);
|
||||||
|
} else if(PlotState == Light){
|
||||||
|
BSP_LCD_Drawaxes(AXISCOLOR, BGCOLOR, "Time", "Light", LIGHTCOLOR, "", 0, LIGHT_MAX, LIGHT_MIN);
|
||||||
|
}
|
||||||
|
OS_Signal(&LCDmutex); ReDrawAxes = 0;
|
||||||
|
}
|
||||||
|
void Task2(void){uint32_t data;
|
||||||
|
uint32_t localMin; // smallest measured magnitude since odd-numbered step detected
|
||||||
|
uint32_t localMax; // largest measured magnitude since even-numbered step detected
|
||||||
|
uint32_t localCount; // number of measured magnitudes above local min or below local max
|
||||||
|
localMin = 1024;
|
||||||
|
localMax = 0;
|
||||||
|
localCount = 0;
|
||||||
|
drawaxes();
|
||||||
|
while(1){
|
||||||
|
data = OS_FIFO_Get();
|
||||||
|
TExaS_Task2(); // records system time in array, toggles virtual logic analyzer
|
||||||
|
Profile_Toggle2(); // viewed by the logic analyzer to know Task2 started
|
||||||
|
Magnitude = sqrt32(data);
|
||||||
|
EWMA = (ALPHA*Magnitude + (1023 - ALPHA)*EWMA)/1024;
|
||||||
|
if(AlgorithmState == LookingForMax){
|
||||||
|
if(Magnitude > localMax){
|
||||||
|
localMax = Magnitude;
|
||||||
|
localCount = 0;
|
||||||
|
} else{
|
||||||
|
localCount = localCount + 1;
|
||||||
|
if(localCount >= LOCALCOUNTTARGET){
|
||||||
|
AlgorithmState = LookingForCross1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if(AlgorithmState == LookingForCross1){
|
||||||
|
if(Magnitude > localMax){
|
||||||
|
// somehow measured a very large magnitude
|
||||||
|
localMax = Magnitude;
|
||||||
|
localCount = 0;
|
||||||
|
AlgorithmState = LookingForMax;
|
||||||
|
} else if(Magnitude < (EWMA - AVGOVERSHOOT)){
|
||||||
|
// step detected
|
||||||
|
Steps = Steps + 1;
|
||||||
|
localMin = 1024;
|
||||||
|
localCount = 0;
|
||||||
|
AlgorithmState = LookingForMin;
|
||||||
|
}
|
||||||
|
} else if(AlgorithmState == LookingForMin){
|
||||||
|
if(Magnitude < localMin){
|
||||||
|
localMin = Magnitude;
|
||||||
|
localCount = 0;
|
||||||
|
} else{
|
||||||
|
localCount = localCount + 1;
|
||||||
|
if(localCount >= LOCALCOUNTTARGET){
|
||||||
|
AlgorithmState = LookingForCross2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if(AlgorithmState == LookingForCross2){
|
||||||
|
if(Magnitude < localMin){
|
||||||
|
// somehow measured a very small magnitude
|
||||||
|
localMin = Magnitude;
|
||||||
|
localCount = 0;
|
||||||
|
AlgorithmState = LookingForMin;
|
||||||
|
} else if(Magnitude > (EWMA + AVGOVERSHOOT)){
|
||||||
|
// step detected
|
||||||
|
Steps = Steps + 1;
|
||||||
|
localMax = 0;
|
||||||
|
localCount = 0;
|
||||||
|
AlgorithmState = LookingForMax;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(ReDrawAxes){
|
||||||
|
drawaxes();
|
||||||
|
ReDrawAxes = 0;
|
||||||
|
}
|
||||||
|
OS_Wait(&LCDmutex);
|
||||||
|
if(PlotState == Accelerometer){
|
||||||
|
BSP_LCD_PlotPoint(Magnitude, MAGCOLOR);
|
||||||
|
BSP_LCD_PlotPoint(EWMA, EWMACOLOR);
|
||||||
|
} else if(PlotState == Microphone){
|
||||||
|
BSP_LCD_PlotPoint(SoundData, SOUNDCOLOR);
|
||||||
|
} else if(PlotState == Temperature){
|
||||||
|
BSP_LCD_PlotPoint(TemperatureData, TEMPCOLOR);
|
||||||
|
} else if(PlotState == Light){
|
||||||
|
BSP_LCD_PlotPoint(LightData, LIGHTCOLOR);
|
||||||
|
}
|
||||||
|
BSP_LCD_PlotIncrement();
|
||||||
|
OS_Signal(&LCDmutex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* ****************************************** */
|
||||||
|
/* End of Task2 Section */
|
||||||
|
/* ****************************************** */
|
||||||
|
|
||||||
|
|
||||||
|
//------------Task3 handles switch input, buzzer output-------
|
||||||
|
// *********Task3*********
|
||||||
|
// Main thread scheduled by OS round robin preemptive scheduler
|
||||||
|
// real-time task, signaled on touch
|
||||||
|
// with bouncing, may also be called on release
|
||||||
|
// checks the switches, updates the mode, and outputs to the buzzer and LED
|
||||||
|
// Inputs: none
|
||||||
|
// Outputs: none
|
||||||
|
int32_t SwitchTouch;
|
||||||
|
void Task3(void){
|
||||||
|
uint8_t current;
|
||||||
|
OS_InitSemaphore(&SwitchTouch,0); // signaled on touch button1
|
||||||
|
OS_EdgeTrigger_Init(&SwitchTouch, 3);
|
||||||
|
while(1){
|
||||||
|
OS_Wait(&SwitchTouch); // OS signals on touch
|
||||||
|
TExaS_Task3(); // records system time in array, toggles virtual logic analyzer
|
||||||
|
Profile_Toggle3(); // viewed by the logic analyzer to know Task3 started
|
||||||
|
OS_Sleep(10); // debounce the switches
|
||||||
|
current = BSP_Button1_Input();
|
||||||
|
if(current == 0){ // Button1 was pressed
|
||||||
|
BSP_Buzzer_Set(512); // beep for 20ms
|
||||||
|
OS_Sleep(20);
|
||||||
|
BSP_Buzzer_Set(0);
|
||||||
|
if(PlotState == Accelerometer){
|
||||||
|
PlotState = Microphone;
|
||||||
|
} else if(PlotState == Microphone){
|
||||||
|
PlotState = Temperature;
|
||||||
|
} else if(PlotState == Temperature){
|
||||||
|
PlotState = Light;
|
||||||
|
} else if(PlotState == Light){
|
||||||
|
PlotState = Accelerometer;
|
||||||
|
}
|
||||||
|
ReDrawAxes = 1; // redraw axes on next call of display task
|
||||||
|
}
|
||||||
|
OS_EdgeTrigger_Restart();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* ****************************************** */
|
||||||
|
/* End of Task3 Section */
|
||||||
|
/* ****************************************** */
|
||||||
|
|
||||||
|
|
||||||
|
//------------Task4 measures temperature-------
|
||||||
|
// *********Task4*********
|
||||||
|
// Main thread scheduled by OS round robin preemptive scheduler
|
||||||
|
// measures temperature
|
||||||
|
// Inputs: none
|
||||||
|
// Outputs: none
|
||||||
|
void Task4(void){int32_t voltData,tempData;
|
||||||
|
int done;
|
||||||
|
while(1){
|
||||||
|
TExaS_Task4(); // records system time in array, toggles virtual logic analyzer
|
||||||
|
Profile_Toggle4(); // viewed by the logic analyzer to know Task4 started
|
||||||
|
|
||||||
|
OS_Wait(&I2Cmutex);
|
||||||
|
BSP_TempSensor_Start();
|
||||||
|
OS_Signal(&I2Cmutex);
|
||||||
|
done = 0;
|
||||||
|
OS_Sleep(1000); // waits about 1 sec
|
||||||
|
while(done == 0){
|
||||||
|
OS_Wait(&I2Cmutex);
|
||||||
|
done = BSP_TempSensor_End(&voltData, &tempData);
|
||||||
|
OS_Signal(&I2Cmutex);
|
||||||
|
}
|
||||||
|
TemperatureData = tempData/10000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* ****************************************** */
|
||||||
|
/* End of Task4 Section */
|
||||||
|
/* ****************************************** */
|
||||||
|
|
||||||
|
|
||||||
|
/* ------------------------------------------ */
|
||||||
|
//------- Task5 displays text on LCD -----------
|
||||||
|
/* ------------------------------------------ */
|
||||||
|
// If no data are lost, the main loop in Task5 runs exactly at 1 Hz, but not in real time
|
||||||
|
|
||||||
|
// *********Task5*********
|
||||||
|
// Main thread scheduled by OS round robin preemptive scheduler
|
||||||
|
// updates the text at the top and bottom of the LCD
|
||||||
|
// Inputs: none
|
||||||
|
// Outputs: none
|
||||||
|
void Task5(void){int32_t soundSum;
|
||||||
|
OS_Wait(&LCDmutex);
|
||||||
|
BSP_LCD_DrawString(0, 0, "Temp=", TOPTXTCOLOR);
|
||||||
|
BSP_LCD_DrawString(0, 1, "Step=", TOPTXTCOLOR);
|
||||||
|
BSP_LCD_DrawString(10, 0, "Light=", TOPTXTCOLOR);
|
||||||
|
BSP_LCD_DrawString(10, 1, "Sound=", TOPTXTCOLOR);
|
||||||
|
OS_Signal(&LCDmutex);
|
||||||
|
while(1){
|
||||||
|
OS_Wait(&NewData);
|
||||||
|
TExaS_Task5(); // records system time in array, toggles virtual logic analyzer
|
||||||
|
Profile_Toggle5(); // viewed by the logic analyzer to know Task5 started
|
||||||
|
soundSum = 0;
|
||||||
|
for(int i=0; i<SOUNDRMSLENGTH; i=i+1){
|
||||||
|
soundSum = soundSum + (SoundArray[i] - SoundAvg)*(SoundArray[i] - SoundAvg);
|
||||||
|
}
|
||||||
|
SoundRMS = sqrt32(soundSum/SOUNDRMSLENGTH);
|
||||||
|
OS_Wait(&LCDmutex);
|
||||||
|
BSP_LCD_SetCursor(5, 0); BSP_LCD_OutUFix2_1(TemperatureData, TEMPCOLOR);
|
||||||
|
BSP_LCD_SetCursor(5, 1); BSP_LCD_OutUDec4(Steps, MAGCOLOR);
|
||||||
|
BSP_LCD_SetCursor(16, 0); BSP_LCD_OutUDec4(LightData, LIGHTCOLOR);
|
||||||
|
BSP_LCD_SetCursor(16, 1); BSP_LCD_OutUDec4(SoundRMS, SOUNDCOLOR);
|
||||||
|
BSP_LCD_SetCursor(16,12); BSP_LCD_OutUDec4(Time/10, TOPNUMCOLOR);
|
||||||
|
//debug code
|
||||||
|
if(LostTask1Data){
|
||||||
|
BSP_LCD_SetCursor(0, 12); BSP_LCD_OutUDec4(LostTask1Data, BSP_LCD_Color565(255, 0, 0));
|
||||||
|
}
|
||||||
|
//end of debug code
|
||||||
|
OS_Signal(&LCDmutex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* ****************************************** */
|
||||||
|
/* End of Task5 Section */
|
||||||
|
/* ****************************************** */
|
||||||
|
|
||||||
|
//---------------- Task6 measures light ----------------
|
||||||
|
// *********Task6*********
|
||||||
|
// Main thread scheduled by OS round robin preemptive scheduler
|
||||||
|
// Task6 measures light intensity
|
||||||
|
// Inputs: none
|
||||||
|
// Outputs: none
|
||||||
|
void Task6(void){ uint32_t lightData;
|
||||||
|
int done;
|
||||||
|
while(1){
|
||||||
|
TExaS_Task6(); // records system time in array, toggles virtual logic analyzer
|
||||||
|
Profile_Toggle6(); // viewed by the logic analyzer to know Task6 started
|
||||||
|
|
||||||
|
OS_Wait(&I2Cmutex);
|
||||||
|
BSP_LightSensor_Start();
|
||||||
|
OS_Signal(&I2Cmutex);
|
||||||
|
done = 0;
|
||||||
|
OS_Sleep(800); // waits about 0.8 sec
|
||||||
|
while(done == 0){
|
||||||
|
OS_Wait(&I2Cmutex);
|
||||||
|
done = BSP_LightSensor_End(&lightData);
|
||||||
|
OS_Signal(&I2Cmutex);
|
||||||
|
}
|
||||||
|
LightData = lightData/100;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* ****************************************** */
|
||||||
|
/* End of Task6 Section */
|
||||||
|
/* ****************************************** */
|
||||||
|
|
||||||
|
//---------------- Task7 dummy function ----------------
|
||||||
|
// *********Task7*********
|
||||||
|
// Main thread scheduled by OS round robin preemptive scheduler
|
||||||
|
// Task7 does nothing but never blocks or sleeps
|
||||||
|
// Inputs: none
|
||||||
|
// Outputs: none
|
||||||
|
uint32_t Count7;
|
||||||
|
void Task7(void){
|
||||||
|
Count7 = 0;
|
||||||
|
while(1){
|
||||||
|
Count7++;
|
||||||
|
WaitForInterrupt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* ****************************************** */
|
||||||
|
/* End of Task7 Section */
|
||||||
|
/* ****************************************** */
|
||||||
|
|
||||||
|
//---------------- Step 6 ----------------
|
||||||
|
// Step 6 is to implement the fitness device by combining the
|
||||||
|
// OS functions that were implemented and tested in the earlier
|
||||||
|
// steps with the user tasks in this file. Completing this
|
||||||
|
// step will give you your grade, so remember to change the
|
||||||
|
// second parameter in TExaS_Init() to your 4-digit number.
|
||||||
|
// Task Purpose When to Run
|
||||||
|
// Task0 microphone periodically exactly every 1 ms
|
||||||
|
// Task1 accelerometer periodically exactly every 100 ms
|
||||||
|
// Task2 plot on LCD after Task1 finishes
|
||||||
|
// Task3 switch/buzzer whenever button 1 touched
|
||||||
|
// Task4 temperature periodically every 1 sec
|
||||||
|
// Task5 numbers on LCD after Task0 runs SOUNDRMSLENGTH times
|
||||||
|
// Task6 light periodically every 800 ms
|
||||||
|
// Task7 dummy no timing requirement
|
||||||
|
// Remember that you must have exactly one main() function, so
|
||||||
|
// to work on this step, you must rename all other main()
|
||||||
|
// functions in this file.
|
||||||
|
int main(void){
|
||||||
|
OS_Init();
|
||||||
|
Profile_Init(); // initialize the 7 hardware profiling pins
|
||||||
|
BSP_Button1_Init();
|
||||||
|
BSP_Button2_Init();
|
||||||
|
BSP_RGB_Init(0, 0, 0);
|
||||||
|
BSP_Buzzer_Init(0);
|
||||||
|
BSP_LCD_Init();
|
||||||
|
BSP_LCD_FillScreen(BSP_LCD_Color565(0, 0, 0));
|
||||||
|
BSP_LightSensor_Init();
|
||||||
|
BSP_TempSensor_Init();
|
||||||
|
Time = 0;
|
||||||
|
OS_InitSemaphore(&NewData, 0); // 0 means no data
|
||||||
|
OS_InitSemaphore(&LCDmutex, 1); // 1 means free
|
||||||
|
OS_InitSemaphore(&I2Cmutex, 1); // 1 means free
|
||||||
|
OS_InitSemaphore(&TakeSoundData,0);
|
||||||
|
OS_InitSemaphore(&ADCmutex,1);
|
||||||
|
BSP_Microphone_Init();
|
||||||
|
BSP_Accelerometer_Init();
|
||||||
|
OS_InitSemaphore(&TakeAccelerationData,0);
|
||||||
|
OS_FIFO_Init(); // initialize FIFO used to send data between Task1 and Task2
|
||||||
|
OS_AddThreads(&Task0,0, &Task1,1, &Task2,2, &Task3,3,
|
||||||
|
&Task4,3, &Task5,3, &Task6,3, &Task7,4);
|
||||||
|
OS_PeriodTrigger0_Init(&TakeSoundData,1); // every 1 ms
|
||||||
|
OS_PeriodTrigger1_Init(&TakeAccelerationData,100); //every 100ms
|
||||||
|
// when grading change 1000 to 4-digit number from edX
|
||||||
|
TExaS_Init(GRADER, 8864 ); // initialize the Lab 4 grader
|
||||||
|
// TExaS_Init(LOGICANALYZER, 1000); // initialize the Lab 4 logic analyzer
|
||||||
|
OS_Launch(BSP_Clock_GetFreq()/THREADFREQ); // doesn't return, interrupts enabled in here
|
||||||
|
return 0; // this never executes
|
||||||
|
}
|
||||||
|
/* ****************************************** */
|
||||||
|
/* End of Step 6 Section */
|
||||||
|
/* ****************************************** */
|
||||||
|
|
||||||
|
// Newton's method
|
||||||
|
// s is an integer
|
||||||
|
// sqrt(s) is an integer
|
||||||
|
uint32_t sqrt32(uint32_t s){
|
||||||
|
uint32_t t; // t*t will become s
|
||||||
|
int n; // loop counter
|
||||||
|
t = s/16+1; // initial guess
|
||||||
|
for(n = 16; n; --n){ // will finish
|
||||||
|
t = ((t*t+s)/t)/2;
|
||||||
|
}
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//---------------- Step 1 ----------------
|
||||||
|
// Step 1 is to extend OS_AddThreads from Lab 4 to handle eight
|
||||||
|
// main threads, add a status field to the TCB, and rewrite
|
||||||
|
// the scheduler to handle priority.
|
||||||
|
// Task Type When to Run
|
||||||
|
// TaskA data producer periodically every 20 ms (sleep)
|
||||||
|
// TaskB data consumer after TaskA finishes
|
||||||
|
// TaskC data producer periodically every 50 ms (sleep)
|
||||||
|
// TaskD data consumer after TaskC finishes
|
||||||
|
// TaskE data producer periodically every 100 ms (sleep)
|
||||||
|
// TaskF data consumer after TaskE finishes
|
||||||
|
// TaskG low level task, runs a lot
|
||||||
|
// TaskH low level task, never runs
|
||||||
|
// Remember that you must have exactly one main() function, so
|
||||||
|
// to work on this step, you must rename all other main()
|
||||||
|
// functions in this file.
|
||||||
|
int32_t sAB,sCD,sEF;
|
||||||
|
int32_t CountA,CountB,CountC,CountD,CountE,CountF,CountG,CountH;
|
||||||
|
void TaskA(void){ // producer highest priority
|
||||||
|
CountA = 0;
|
||||||
|
while(1){
|
||||||
|
CountA++;
|
||||||
|
TExaS_Task0();
|
||||||
|
Profile_Toggle0();
|
||||||
|
OS_Signal(&sAB); // TaskB can proceed
|
||||||
|
OS_Sleep(20);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void TaskB(void){ // consumer
|
||||||
|
CountB = 0;
|
||||||
|
while(1){
|
||||||
|
CountB++;
|
||||||
|
OS_Wait(&sAB); // signaled by TaskA
|
||||||
|
TExaS_Task1();
|
||||||
|
Profile_Toggle1();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void TaskC(void){ // producer
|
||||||
|
CountC = 0;
|
||||||
|
while(1){
|
||||||
|
CountC++;
|
||||||
|
TExaS_Task2();
|
||||||
|
Profile_Toggle2();
|
||||||
|
OS_Signal(&sCD); // TaskD can proceed
|
||||||
|
OS_Sleep(50);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void TaskD(void){ // consumer
|
||||||
|
CountD = 0;
|
||||||
|
while(1){
|
||||||
|
CountD++;
|
||||||
|
OS_Wait(&sCD); // signaled by TaskC
|
||||||
|
TExaS_Task3();
|
||||||
|
Profile_Toggle3();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void TaskE(void){ // producer
|
||||||
|
CountE = 0;
|
||||||
|
while(1){
|
||||||
|
CountE++;
|
||||||
|
TExaS_Task4();
|
||||||
|
Profile_Toggle4();
|
||||||
|
OS_Signal(&sEF); // TaskF can proceed
|
||||||
|
OS_Sleep(100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void TaskF(void){ // consumer
|
||||||
|
CountF = 0;
|
||||||
|
while(1){
|
||||||
|
CountF++;
|
||||||
|
OS_Wait(&sEF); // signaled by TaskE
|
||||||
|
TExaS_Task5();
|
||||||
|
Profile_Toggle5();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void TaskG(void){ // dummy
|
||||||
|
CountG = 0; // this should run a lot
|
||||||
|
while(1){
|
||||||
|
CountG++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void TaskH(void){ // dummy
|
||||||
|
CountH = 0; // this one should never run
|
||||||
|
while(1){
|
||||||
|
CountH++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int main_step1(void){
|
||||||
|
OS_Init();
|
||||||
|
Profile_Init(); // initialize the 7 hardware profiling pins
|
||||||
|
OS_InitSemaphore(&sAB, 0);
|
||||||
|
OS_InitSemaphore(&sCD, 0);
|
||||||
|
OS_InitSemaphore(&sEF, 0);
|
||||||
|
OS_AddThreads(&TaskA,0, &TaskB,1, &TaskC,2, &TaskD,3,
|
||||||
|
&TaskE,4, &TaskF,5, &TaskG,6, &TaskH,7);
|
||||||
|
TExaS_Init(LOGICANALYZER, 1000); // initialize the Lab 4 grader
|
||||||
|
// TExaS_Init(GRADESTEP1, 1000); // initialize the Lab 4 grader
|
||||||
|
OS_Launch(BSP_Clock_GetFreq()/1000);
|
||||||
|
return 0; // this never executes
|
||||||
|
}
|
||||||
|
/* ****************************************** */
|
||||||
|
/* End of Step 1 Section */
|
||||||
|
/* ****************************************** */
|
||||||
|
|
||||||
|
//---------------- Step 2 ----------------
|
||||||
|
// Step 2 id to extend the OS to implement OS_PeriodTrigger0_Init
|
||||||
|
// and OS_PeriodTrigger1_Init.
|
||||||
|
// Task Type When to Run
|
||||||
|
// TaskI data producer periodically every 20 ms(timer)
|
||||||
|
// TaskJ data consumer after TaskI finishes
|
||||||
|
// TaskK data producer periodically every 50 ms(timer)
|
||||||
|
// TaskL data consumer after TaskK finishes
|
||||||
|
// TaskM data producer periodically every 100 ms(sleep)
|
||||||
|
// TaskN data consumer after TaskL finishes
|
||||||
|
// TaskO low level task runs a lot
|
||||||
|
// TaskP low level (never runs)
|
||||||
|
// Remember that you must have exactly one main() function, so
|
||||||
|
// to work on this step, you must rename all other main()
|
||||||
|
// functions in this file.
|
||||||
|
int32_t sIJ,sKL,sMN;
|
||||||
|
int32_t sI,sK;
|
||||||
|
int32_t CountI,CountJ,CountK,CountL,CountM,CountN,CountO,CountP;
|
||||||
|
void TaskI(void){ // producer highest priority
|
||||||
|
CountI = 0;
|
||||||
|
while(1){
|
||||||
|
OS_Wait(&sI); // signaled by OS every 20ms
|
||||||
|
CountI++;
|
||||||
|
TExaS_Task0();
|
||||||
|
Profile_Toggle0();
|
||||||
|
OS_Signal(&sIJ); // TaskJ can proceed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void TaskJ(void){ // consumer
|
||||||
|
CountJ = 0;
|
||||||
|
while(1){
|
||||||
|
CountJ++;
|
||||||
|
OS_Wait(&sIJ); // signaled by TaskI
|
||||||
|
TExaS_Task1();
|
||||||
|
Profile_Toggle1();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void TaskK(void){ // producer
|
||||||
|
CountK = 0;
|
||||||
|
while(1){
|
||||||
|
OS_Wait(&sK); // signaled by OS every 50ms
|
||||||
|
CountK++;
|
||||||
|
TExaS_Task2();
|
||||||
|
Profile_Toggle2();
|
||||||
|
OS_Signal(&sKL); // TaskL can proceed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TaskL(void){ // consumer
|
||||||
|
CountL = 0;
|
||||||
|
while(1){
|
||||||
|
CountL++;
|
||||||
|
OS_Wait(&sKL); // signaled by TaskL
|
||||||
|
TExaS_Task3();
|
||||||
|
Profile_Toggle3();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void TaskM(void){ // producer
|
||||||
|
CountM = 0;
|
||||||
|
while(1){
|
||||||
|
CountM++;
|
||||||
|
TExaS_Task4();
|
||||||
|
Profile_Toggle4();
|
||||||
|
OS_Signal(&sMN); // TaskN can proceed
|
||||||
|
OS_Sleep(100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void TaskN(void){ // consumer
|
||||||
|
CountN = 0;
|
||||||
|
while(1){
|
||||||
|
CountN++;
|
||||||
|
OS_Wait(&sMN); // signaled by TaskM
|
||||||
|
TExaS_Task5();
|
||||||
|
Profile_Toggle5();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void TaskO(void){ // dummy
|
||||||
|
CountO = 0; // this should run a lot
|
||||||
|
while(1){
|
||||||
|
CountO++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void TaskP(void){ // dummy
|
||||||
|
CountP = 0; // this one should never run
|
||||||
|
while(1){
|
||||||
|
CountP++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int main_step2(void){
|
||||||
|
OS_Init();
|
||||||
|
Profile_Init(); // initialize the 7 hardware profiling pins
|
||||||
|
OS_InitSemaphore(&sI, 0);
|
||||||
|
OS_InitSemaphore(&sK, 0);
|
||||||
|
OS_InitSemaphore(&sIJ, 0);
|
||||||
|
OS_InitSemaphore(&sKL, 0);
|
||||||
|
OS_InitSemaphore(&sMN, 0);
|
||||||
|
OS_PeriodTrigger0_Init(&sI,20); // every 20 ms
|
||||||
|
OS_PeriodTrigger1_Init(&sK,50); // every 50ms
|
||||||
|
OS_AddThreads(&TaskI,0, &TaskJ,1, &TaskK,2, &TaskL,3,
|
||||||
|
&TaskM,4, &TaskN,5, &TaskO,6, &TaskP,7);
|
||||||
|
TExaS_Init(LOGICANALYZER, 1000); // initialize the Lab 4 grader
|
||||||
|
// TExaS_Init(GRADESTEP2, 1000); // initialize the Lab 4 grader
|
||||||
|
OS_Launch(BSP_Clock_GetFreq()/1000);
|
||||||
|
return 0; // this never executes
|
||||||
|
}
|
||||||
|
/* ****************************************** */
|
||||||
|
/* End of Step 2 Section */
|
||||||
|
/* ****************************************** */
|
||||||
|
|
||||||
|
//---------------- Step 3 ----------------
|
||||||
|
// Step 3 is to extend the OS to implement OS_EdgeTrigger_Init
|
||||||
|
// Task Type When to Run
|
||||||
|
// TaskI data producer periodically every 20 ms(timer)
|
||||||
|
// TaskJ data consumer after TaskI finishes
|
||||||
|
// TaskK data producer periodically every 50 ms(timer)
|
||||||
|
// TaskL data consumer after TaskK finishes
|
||||||
|
// TaskQ data producer runs on touch button1
|
||||||
|
// TaskR data consumer after TaskQ finishes
|
||||||
|
// TaskO low level task runs a lot
|
||||||
|
// TaskP low level (never runs)
|
||||||
|
// Remember that you must have exactly one main() function, so
|
||||||
|
// to work on this step, you must rename all other main()
|
||||||
|
// functions in this file.
|
||||||
|
int32_t sQR;
|
||||||
|
int32_t sQ;
|
||||||
|
int32_t CountQ,CountR;
|
||||||
|
void TaskQ(void){ // producer
|
||||||
|
CountQ = 0;
|
||||||
|
while(1){
|
||||||
|
OS_Wait(&sQ); // signaled in OS on button1 touch
|
||||||
|
CountQ++;
|
||||||
|
TExaS_Task4();
|
||||||
|
Profile_Toggle4();
|
||||||
|
OS_Signal(&sQR); // TaskQ can proceed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void TaskR(void){ // consumer
|
||||||
|
CountR = 0;
|
||||||
|
while(1){
|
||||||
|
OS_Wait(&sQR); // signaled by TaskQ
|
||||||
|
TExaS_Task5();
|
||||||
|
Profile_Toggle5();
|
||||||
|
CountR++;
|
||||||
|
OS_Sleep(10);
|
||||||
|
OS_EdgeTrigger_Restart();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int main_step3(void){
|
||||||
|
OS_Init();
|
||||||
|
Profile_Init(); // initialize the 7 hardware profiling pins
|
||||||
|
OS_InitSemaphore(&sI, 0);
|
||||||
|
OS_InitSemaphore(&sK, 0);
|
||||||
|
OS_InitSemaphore(&sQ, 0);
|
||||||
|
OS_InitSemaphore(&sIJ, 0);
|
||||||
|
OS_InitSemaphore(&sKL, 0);
|
||||||
|
OS_InitSemaphore(&sQR, 0);
|
||||||
|
OS_PeriodTrigger0_Init(&sI,50); // every 50 ms
|
||||||
|
OS_PeriodTrigger1_Init(&sK,200); // every 200ms
|
||||||
|
OS_EdgeTrigger_Init(&sQ,2);
|
||||||
|
OS_AddThreads(&TaskI,0, &TaskJ,1, &TaskK,2, &TaskL,3,
|
||||||
|
&TaskQ,4, &TaskR,5, &TaskO,6, &TaskP,7);
|
||||||
|
TExaS_Init(LOGICANALYZER, 1000); // initialize the Lab 4 grader
|
||||||
|
// TExaS_Init(GRADESTEP3, 1000); // initialize the Lab 4 grader
|
||||||
|
OS_Launch(BSP_Clock_GetFreq()/1000);
|
||||||
|
return 0; // this never executes
|
||||||
|
}
|
||||||
|
/* ****************************************** */
|
||||||
|
/* End of Step 3 Section */
|
||||||
|
/* ****************************************** */
|
|
@ -0,0 +1,69 @@
|
||||||
|
// *****************Texas.h**************
|
||||||
|
// grading engine for Lab 4
|
||||||
|
//
|
||||||
|
// Runs on TM4C123/MSP432
|
||||||
|
// Daniel and Jonathan Valvano
|
||||||
|
// August 22, 2016
|
||||||
|
|
||||||
|
/* This example accompanies the books
|
||||||
|
"Embedded Systems: Real Time Interfacing to ARM Cortex M Microcontrollers",
|
||||||
|
ISBN: 978-1463590154, Jonathan Valvano, copyright (c) 2016
|
||||||
|
|
||||||
|
"Embedded Systems: Real-Time Operating Systems for ARM Cortex-M Microcontrollers",
|
||||||
|
ISBN: 978-1466468863, Jonathan Valvano, copyright (c) 2016
|
||||||
|
|
||||||
|
Copyright 2016 by Jonathan W. Valvano, valvano@mail.utexas.edu
|
||||||
|
You may use, edit, run or distribute this file
|
||||||
|
as long as the above copyright notice remains
|
||||||
|
THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED
|
||||||
|
OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
|
||||||
|
VALVANO SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL,
|
||||||
|
OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
|
||||||
|
For more information about my classes, my research, and my books, see
|
||||||
|
http://users.ece.utexas.edu/~valvano/
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
enum TExaSmode{
|
||||||
|
GRADER,
|
||||||
|
GRADESTEP1,
|
||||||
|
GRADESTEP2,
|
||||||
|
GRADESTEP3,
|
||||||
|
LOGICANALYZER
|
||||||
|
};
|
||||||
|
|
||||||
|
// ************TExaS_Init*****************
|
||||||
|
// Initialize grader, triggered by periodic timer
|
||||||
|
// This needs to be called once
|
||||||
|
// Inputs: Grading or Logic analyzer
|
||||||
|
// 4-digit number from edX
|
||||||
|
// Outputs: none
|
||||||
|
void TExaS_Init(enum TExaSmode mode, uint32_t edXcode);
|
||||||
|
|
||||||
|
// ************TExaS_Stop*****************
|
||||||
|
// Stop the transfer
|
||||||
|
// Inputs: none
|
||||||
|
// Outputs: none
|
||||||
|
void TExaS_Stop(void);
|
||||||
|
|
||||||
|
// record time Task 0 is started
|
||||||
|
void TExaS_Task0(void);
|
||||||
|
|
||||||
|
// record time Task 0 is started
|
||||||
|
void TExaS_Task1(void);
|
||||||
|
|
||||||
|
// record time Task 2 is started
|
||||||
|
void TExaS_Task2(void);
|
||||||
|
|
||||||
|
// record time Task 3 is started
|
||||||
|
void TExaS_Task3(void);
|
||||||
|
|
||||||
|
// record time Task 4 is started
|
||||||
|
void TExaS_Task4(void);
|
||||||
|
|
||||||
|
// record time Task 5 is started
|
||||||
|
void TExaS_Task5(void);
|
||||||
|
|
||||||
|
// record time Task 6 is started
|
||||||
|
void TExaS_Task6(void);
|
|
@ -0,0 +1,298 @@
|
||||||
|
// os.c
|
||||||
|
// Runs on LM4F120/TM4C123/MSP432
|
||||||
|
// A priority/blocking real-time operating system
|
||||||
|
// Lab 4 starter file.
|
||||||
|
// Daniel Valvano
|
||||||
|
// March 25, 2016
|
||||||
|
// Hint: Copy solutions from Lab 3 into Lab 4
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "os.h"
|
||||||
|
#include "CortexM.h"
|
||||||
|
#include "BSP.h"
|
||||||
|
#include "../inc/tm4c123gh6pm.h"
|
||||||
|
|
||||||
|
// function definitions in osasm.s
|
||||||
|
void StartOS(void);
|
||||||
|
|
||||||
|
#define NUMTHREADS 8 // maximum number of threads
|
||||||
|
#define NUMPERIODIC 2 // maximum number of periodic threads
|
||||||
|
#define STACKSIZE 100 // number of 32-bit words in stack per thread
|
||||||
|
struct tcb{
|
||||||
|
int32_t *sp; // pointer to stack (valid for threads not running
|
||||||
|
struct tcb *next; // linked-list pointer
|
||||||
|
//*FILL THIS IN****
|
||||||
|
};
|
||||||
|
typedef struct tcb tcbType;
|
||||||
|
tcbType tcbs[NUMTHREADS];
|
||||||
|
tcbType *RunPt;
|
||||||
|
int32_t Stacks[NUMTHREADS][STACKSIZE];
|
||||||
|
void static runperiodicevents(void);
|
||||||
|
|
||||||
|
// ******** OS_Init ************
|
||||||
|
// Initialize operating system, disable interrupts
|
||||||
|
// Initialize OS controlled I/O: periodic interrupt, bus clock as fast as possible
|
||||||
|
// Initialize OS global variables
|
||||||
|
// Inputs: none
|
||||||
|
// Outputs: none
|
||||||
|
void OS_Init(void){
|
||||||
|
DisableInterrupts();
|
||||||
|
BSP_Clock_InitFastest();// set processor clock to fastest speed
|
||||||
|
// perform any initializations needed,
|
||||||
|
// set up periodic timer to run runperiodicevents to implement sleeping
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetInitialStack(int i){
|
||||||
|
// ****IMPLEMENT THIS****
|
||||||
|
// **Same as Lab 2 and Lab 3****
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//******** OS_AddThreads ***************
|
||||||
|
// Add eight main threads to the scheduler
|
||||||
|
// Inputs: function pointers to eight void/void main threads
|
||||||
|
// priorites for each main thread (0 highest)
|
||||||
|
// Outputs: 1 if successful, 0 if this thread can not be added
|
||||||
|
// This function will only be called once, after OS_Init and before OS_Launch
|
||||||
|
int OS_AddThreads(void(*thread0)(void), uint32_t p0,
|
||||||
|
void(*thread1)(void), uint32_t p1,
|
||||||
|
void(*thread2)(void), uint32_t p2,
|
||||||
|
void(*thread3)(void), uint32_t p3,
|
||||||
|
void(*thread4)(void), uint32_t p4,
|
||||||
|
void(*thread5)(void), uint32_t p5,
|
||||||
|
void(*thread6)(void), uint32_t p6,
|
||||||
|
void(*thread7)(void), uint32_t p7){
|
||||||
|
// **similar to Lab 3. initialize priority field****
|
||||||
|
|
||||||
|
return 1; // successful
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void static runperiodicevents(void){
|
||||||
|
// ****IMPLEMENT THIS****
|
||||||
|
// **DECREMENT SLEEP COUNTERS
|
||||||
|
// In Lab 4, handle periodic events in RealTimeEvents
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//******** OS_Launch ***************
|
||||||
|
// Start the scheduler, enable interrupts
|
||||||
|
// Inputs: number of clock cycles for each time slice
|
||||||
|
// Outputs: none (does not return)
|
||||||
|
// Errors: theTimeSlice must be less than 16,777,216
|
||||||
|
void OS_Launch(uint32_t theTimeSlice){
|
||||||
|
STCTRL = 0; // disable SysTick during setup
|
||||||
|
STCURRENT = 0; // any write to current clears it
|
||||||
|
SYSPRI3 =(SYSPRI3&0x00FFFFFF)|0xE0000000; // priority 7
|
||||||
|
STRELOAD = theTimeSlice - 1; // reload value
|
||||||
|
STCTRL = 0x00000007; // enable, core clock and interrupt arm
|
||||||
|
StartOS(); // start on the first task
|
||||||
|
}
|
||||||
|
// runs every ms
|
||||||
|
void Scheduler(void){ // every time slice
|
||||||
|
// ****IMPLEMENT THIS****
|
||||||
|
// look at all threads in TCB list choose
|
||||||
|
// highest priority thread not blocked and not sleeping
|
||||||
|
// If there are multiple highest priority (not blocked, not sleeping) run these round robin
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//******** OS_Suspend ***************
|
||||||
|
// Called by main thread to cooperatively suspend operation
|
||||||
|
// Inputs: none
|
||||||
|
// Outputs: none
|
||||||
|
// Will be run again depending on sleep/block status
|
||||||
|
void OS_Suspend(void){
|
||||||
|
STCURRENT = 0; // any write to current clears it
|
||||||
|
INTCTRL = 0x04000000; // trigger SysTick
|
||||||
|
// next thread gets a full time slice
|
||||||
|
}
|
||||||
|
|
||||||
|
// ******** OS_Sleep ************
|
||||||
|
// place this thread into a dormant state
|
||||||
|
// input: number of msec to sleep
|
||||||
|
// output: none
|
||||||
|
// OS_Sleep(0) implements cooperative multitasking
|
||||||
|
void OS_Sleep(uint32_t sleepTime){
|
||||||
|
// ****IMPLEMENT THIS****
|
||||||
|
// set sleep parameter in TCB, same as Lab 3
|
||||||
|
// suspend, stops running
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// ******** OS_InitSemaphore ************
|
||||||
|
// Initialize counting semaphore
|
||||||
|
// Inputs: pointer to a semaphore
|
||||||
|
// initial value of semaphore
|
||||||
|
// Outputs: none
|
||||||
|
void OS_InitSemaphore(int32_t *semaPt, int32_t value){
|
||||||
|
// ****IMPLEMENT THIS****
|
||||||
|
// Same as Lab 3
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// ******** OS_Wait ************
|
||||||
|
// Decrement semaphore and block if less than zero
|
||||||
|
// Lab2 spinlock (does not suspend while spinning)
|
||||||
|
// Lab3 block if less than zero
|
||||||
|
// Inputs: pointer to a counting semaphore
|
||||||
|
// Outputs: none
|
||||||
|
void OS_Wait(int32_t *semaPt){
|
||||||
|
// ****IMPLEMENT THIS****
|
||||||
|
// Same as Lab 3
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// ******** OS_Signal ************
|
||||||
|
// Increment semaphore
|
||||||
|
// Lab2 spinlock
|
||||||
|
// Lab3 wakeup blocked thread if appropriate
|
||||||
|
// Inputs: pointer to a counting semaphore
|
||||||
|
// Outputs: none
|
||||||
|
void OS_Signal(int32_t *semaPt){
|
||||||
|
// ****IMPLEMENT THIS****
|
||||||
|
// Same as Lab 3
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#define FSIZE 10 // can be any size
|
||||||
|
uint32_t PutI; // index of where to put next
|
||||||
|
uint32_t GetI; // index of where to get next
|
||||||
|
uint32_t Fifo[FSIZE];
|
||||||
|
int32_t CurrentSize;// 0 means FIFO empty, FSIZE means full
|
||||||
|
uint32_t LostData; // number of lost pieces of data
|
||||||
|
|
||||||
|
// ******** OS_FIFO_Init ************
|
||||||
|
// Initialize FIFO. The "put" and "get" indices initially
|
||||||
|
// are equal, which means that the FIFO is empty. Also
|
||||||
|
// initialize semaphores to track properties of the FIFO
|
||||||
|
// such as size and busy status for Put and Get operations,
|
||||||
|
// which is important if there are multiple data producers
|
||||||
|
// or multiple data consumers.
|
||||||
|
// Inputs: none
|
||||||
|
// Outputs: none
|
||||||
|
void OS_FIFO_Init(void){
|
||||||
|
// ****IMPLEMENT THIS****
|
||||||
|
// Same as Lab 3
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// ******** OS_FIFO_Put ************
|
||||||
|
// Put an entry in the FIFO. Consider using a unique
|
||||||
|
// semaphore to wait on busy status if more than one thread
|
||||||
|
// is putting data into the FIFO and there is a chance that
|
||||||
|
// this function may interrupt itself.
|
||||||
|
// Inputs: data to be stored
|
||||||
|
// Outputs: 0 if successful, -1 if the FIFO is full
|
||||||
|
int OS_FIFO_Put(uint32_t data){
|
||||||
|
// ****IMPLEMENT THIS****
|
||||||
|
// Same as Lab 3
|
||||||
|
|
||||||
|
return 0; // success
|
||||||
|
}
|
||||||
|
|
||||||
|
// ******** OS_FIFO_Get ************
|
||||||
|
// Get an entry from the FIFO. Consider using a unique
|
||||||
|
// semaphore to wait on busy status if more than one thread
|
||||||
|
// is getting data from the FIFO and there is a chance that
|
||||||
|
// this function may interrupt itself.
|
||||||
|
// Inputs: none
|
||||||
|
// Outputs: data retrieved
|
||||||
|
uint32_t OS_FIFO_Get(void){uint32_t data;
|
||||||
|
// ****IMPLEMENT THIS****
|
||||||
|
// Same as Lab 3
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
// *****periodic events****************
|
||||||
|
int32_t *PeriodicSemaphore0;
|
||||||
|
uint32_t Period0; // time between signals
|
||||||
|
int32_t *PeriodicSemaphore1;
|
||||||
|
uint32_t Period1; // time between signals
|
||||||
|
void RealTimeEvents(void){int flag=0;
|
||||||
|
static int32_t realCount = -10; // let all the threads execute once
|
||||||
|
// Note to students: we had to let the system run for a time so all user threads ran at least one
|
||||||
|
// before signalling the periodic tasks
|
||||||
|
realCount++;
|
||||||
|
if(realCount >= 0){
|
||||||
|
if((realCount%Period0)==0){
|
||||||
|
OS_Signal(PeriodicSemaphore0);
|
||||||
|
flag = 1;
|
||||||
|
}
|
||||||
|
if((realCount%Period1)==0){
|
||||||
|
OS_Signal(PeriodicSemaphore1);
|
||||||
|
flag=1;
|
||||||
|
}
|
||||||
|
if(flag){
|
||||||
|
OS_Suspend();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ******** OS_PeriodTrigger0_Init ************
|
||||||
|
// Initialize periodic timer interrupt to signal
|
||||||
|
// Inputs: semaphore to signal
|
||||||
|
// period in ms
|
||||||
|
// priority level at 0 (highest
|
||||||
|
// Outputs: none
|
||||||
|
void OS_PeriodTrigger0_Init(int32_t *semaPt, uint32_t period){
|
||||||
|
PeriodicSemaphore0 = semaPt;
|
||||||
|
Period0 = period;
|
||||||
|
BSP_PeriodicTask_InitC(&RealTimeEvents,1000,0);
|
||||||
|
}
|
||||||
|
// ******** OS_PeriodTrigger1_Init ************
|
||||||
|
// Initialize periodic timer interrupt to signal
|
||||||
|
// Inputs: semaphore to signal
|
||||||
|
// period in ms
|
||||||
|
// priority level at 0 (highest
|
||||||
|
// Outputs: none
|
||||||
|
void OS_PeriodTrigger1_Init(int32_t *semaPt, uint32_t period){
|
||||||
|
PeriodicSemaphore1 = semaPt;
|
||||||
|
Period1 = period;
|
||||||
|
BSP_PeriodicTask_InitC(&RealTimeEvents,1000,0);
|
||||||
|
}
|
||||||
|
|
||||||
|
//****edge-triggered event************
|
||||||
|
int32_t *edgeSemaphore;
|
||||||
|
// ******** OS_EdgeTrigger_Init ************
|
||||||
|
// Initialize button1, PD6, to signal on a falling edge interrupt
|
||||||
|
// Inputs: semaphore to signal
|
||||||
|
// priority
|
||||||
|
// Outputs: none
|
||||||
|
void OS_EdgeTrigger_Init(int32_t *semaPt, uint8_t priority){
|
||||||
|
edgeSemaphore = semaPt;
|
||||||
|
//***IMPLEMENT THIS***
|
||||||
|
// 1) activate clock for Port D
|
||||||
|
// allow time for clock to stabilize
|
||||||
|
// 2) no need to unlock PD6
|
||||||
|
// 3) disable analog on PD6
|
||||||
|
// 4) configure PD6 as GPIO
|
||||||
|
// 5) make PD6 input
|
||||||
|
// 6) disable alt funct on PD6
|
||||||
|
// disable pull-up on PD6
|
||||||
|
// 7) enable digital I/O on PD6
|
||||||
|
// (d) PD6 is edge-sensitive
|
||||||
|
// PD6 is not both edges
|
||||||
|
// PD6 is falling edge event
|
||||||
|
// (e) clear PD6 flag
|
||||||
|
// (f) arm interrupt on PD6
|
||||||
|
// priority on Port D edge trigger is NVIC_PRI0_R 31 – 29
|
||||||
|
// enable is bit 3 in NVIC_EN0_R
|
||||||
|
}
|
||||||
|
|
||||||
|
// ******** OS_EdgeTrigger_Restart ************
|
||||||
|
// restart button1 to signal on a falling edge interrupt
|
||||||
|
// rearm interrupt
|
||||||
|
// Inputs: none
|
||||||
|
// Outputs: none
|
||||||
|
void OS_EdgeTrigger_Restart(void){
|
||||||
|
//***IMPLEMENT THIS***
|
||||||
|
// rearm interrupt 3 in NVIC
|
||||||
|
// clear flag6
|
||||||
|
}
|
||||||
|
void GPIOPortD_Handler(void){
|
||||||
|
//***IMPLEMENT THIS***
|
||||||
|
// step 1 acknowledge by clearing flag
|
||||||
|
// step 2 signal semaphore (no need to run scheduler)
|
||||||
|
// step 3 disarm interrupt to prevent bouncing to create multiple signals
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,159 @@
|
||||||
|
// os.h
|
||||||
|
// Runs on LM4F120/TM4C123/MSP432
|
||||||
|
// A priority/blocking real-time operating system
|
||||||
|
// Daniel Valvano
|
||||||
|
// March 25, 2016
|
||||||
|
|
||||||
|
/* This example accompanies the book
|
||||||
|
"Embedded Systems: Real Time Interfacing to ARM Cortex M Microcontrollers",
|
||||||
|
ISBN: 978-1463590154, Jonathan Valvano, copyright (c) 2016
|
||||||
|
|
||||||
|
"Embedded Systems: Real-Time Operating Systems for ARM Cortex-M Microcontrollers",
|
||||||
|
ISBN: 978-1466468863, , Jonathan Valvano, copyright (c) 2016
|
||||||
|
Programs 4.4 through 4.12, section 4.2
|
||||||
|
|
||||||
|
Copyright 2016 by Jonathan W. Valvano, valvano@mail.utexas.edu
|
||||||
|
You may use, edit, run or distribute this file
|
||||||
|
as long as the above copyright notice remains
|
||||||
|
THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED
|
||||||
|
OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
|
||||||
|
VALVANO SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL,
|
||||||
|
OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
|
||||||
|
For more information about my classes, my research, and my books, see
|
||||||
|
http://users.ece.utexas.edu/~valvano/
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef __OS_H
|
||||||
|
#define __OS_H 1
|
||||||
|
|
||||||
|
|
||||||
|
// ******** OS_Init ************
|
||||||
|
// Initialize operating system, disable interrupts
|
||||||
|
// Initialize OS controlled I/O: periodic interrupt, bus clock as fast as possible
|
||||||
|
// Initialize OS global variables
|
||||||
|
// Inputs: none
|
||||||
|
// Outputs: none
|
||||||
|
void OS_Init(void);
|
||||||
|
|
||||||
|
//******** OS_AddThreads ***************
|
||||||
|
// Add eight main threads to the scheduler
|
||||||
|
// Inputs: function pointers to eight void/void main threads
|
||||||
|
// priorites for each main thread (0 highest)
|
||||||
|
// Outputs: 1 if successful, 0 if this thread can not be added
|
||||||
|
// This function will only be called once, after OS_Init and before OS_Launch
|
||||||
|
int OS_AddThreads(void(*thread0)(void), uint32_t p0,
|
||||||
|
void(*thread1)(void), uint32_t p1,
|
||||||
|
void(*thread2)(void), uint32_t p2,
|
||||||
|
void(*thread3)(void), uint32_t p3,
|
||||||
|
void(*thread4)(void), uint32_t p4,
|
||||||
|
void(*thread5)(void), uint32_t p5,
|
||||||
|
void(*thread6)(void), uint32_t p6,
|
||||||
|
void(*thread7)(void), uint32_t p7);
|
||||||
|
|
||||||
|
|
||||||
|
//******** OS_Launch ***************
|
||||||
|
// Start the scheduler, enable interrupts
|
||||||
|
// Inputs: number of clock cycles for each time slice
|
||||||
|
// Outputs: none (does not return)
|
||||||
|
// Errors: theTimeSlice must be less than 16,777,216
|
||||||
|
void OS_Launch(uint32_t theTimeSlice);
|
||||||
|
|
||||||
|
//******** OS_Suspend ***************
|
||||||
|
// Called by main thread to cooperatively suspend operation
|
||||||
|
// Inputs: none
|
||||||
|
// Outputs: none
|
||||||
|
// Will be run again depending on sleep/block status
|
||||||
|
void OS_Suspend(void);
|
||||||
|
|
||||||
|
// ******** OS_Sleep ************
|
||||||
|
// place this thread into a dormant state
|
||||||
|
// input: number of msec to sleep
|
||||||
|
// output: none
|
||||||
|
// OS_Sleep(0) implements cooperative multitasking
|
||||||
|
void OS_Sleep(uint32_t sleepTime);
|
||||||
|
|
||||||
|
// ******** OS_InitSemaphore ************
|
||||||
|
// Initialize counting semaphore
|
||||||
|
// Inputs: pointer to a semaphore
|
||||||
|
// initial value of semaphore
|
||||||
|
// Outputs: none
|
||||||
|
void OS_InitSemaphore(int32_t *semaPt, int32_t value);
|
||||||
|
|
||||||
|
// ******** OS_Wait ************
|
||||||
|
// Decrement semaphore and block if less than zero
|
||||||
|
// Lab2 spinlock (does not suspend while spinning)
|
||||||
|
// Lab3 block if less than zero
|
||||||
|
// Inputs: pointer to a counting semaphore
|
||||||
|
// Outputs: none
|
||||||
|
void OS_Wait(int32_t *semaPt);
|
||||||
|
|
||||||
|
// ******** OS_Signal ************
|
||||||
|
// Increment semaphore
|
||||||
|
// Lab2 spinlock
|
||||||
|
// Lab3 wakeup blocked thread if appropriate
|
||||||
|
// Inputs: pointer to a counting semaphore
|
||||||
|
// Outputs: none
|
||||||
|
void OS_Signal(int32_t *semaPt);
|
||||||
|
|
||||||
|
// ******** OS_FIFO_Init ************
|
||||||
|
// Initialize FIFO. The "put" and "get" indices initially
|
||||||
|
// are equal, which means that the FIFO is empty. Also
|
||||||
|
// initialize semaphores to track properties of the FIFO
|
||||||
|
// such as size and busy status for Put and Get operations,
|
||||||
|
// which is important if there are multiple data producers
|
||||||
|
// or multiple data consumers.
|
||||||
|
// Inputs: none
|
||||||
|
// Outputs: none
|
||||||
|
void OS_FIFO_Init(void);
|
||||||
|
|
||||||
|
// ******** OS_FIFO_Put ************
|
||||||
|
// Put an entry in the FIFO. Consider using a unique
|
||||||
|
// semaphore to wait on busy status if more than one thread
|
||||||
|
// is putting data into the FIFO and there is a chance that
|
||||||
|
// this function may interrupt itself.
|
||||||
|
// Inputs: data to be stored
|
||||||
|
// Outputs: 0 if successful, -1 if the FIFO is full
|
||||||
|
int OS_FIFO_Put(uint32_t data);
|
||||||
|
|
||||||
|
// ******** OS_FIFO_Get ************
|
||||||
|
// Get an entry from the FIFO. Consider using a unique
|
||||||
|
// semaphore to wait on busy status if more than one thread
|
||||||
|
// is getting data from the FIFO and there is a chance that
|
||||||
|
// this function may interrupt itself.
|
||||||
|
// Inputs: none
|
||||||
|
// Outputs: data retrieved
|
||||||
|
uint32_t OS_FIFO_Get(void);
|
||||||
|
|
||||||
|
// ******** OS_PeriodTrigger0_Init ************
|
||||||
|
// Initialize periodic timer interrupt to signal
|
||||||
|
// Inputs: semaphore to signal
|
||||||
|
// period in ms
|
||||||
|
// priority level at 0 (highest)
|
||||||
|
// Outputs: none
|
||||||
|
void OS_PeriodTrigger0_Init(int32_t *semaPt, uint32_t period);
|
||||||
|
|
||||||
|
// ******** OS_PeriodTrigger1_Init ************
|
||||||
|
// Initialize periodic timer interrupt to signal
|
||||||
|
// Inputs: semaphore to signal
|
||||||
|
// period in ms
|
||||||
|
// priority level at 0 (highest)
|
||||||
|
// Outputs: none
|
||||||
|
void OS_PeriodTrigger1_Init(int32_t *semaPt, uint32_t period);
|
||||||
|
|
||||||
|
// ******** OS_EdgeTrigger_Init ************
|
||||||
|
// Initialize button1, PD6, to signal on a falling edge interrupt
|
||||||
|
// Inputs: semaphore to signal
|
||||||
|
// priority
|
||||||
|
// Outputs: none
|
||||||
|
void OS_EdgeTrigger_Init(int32_t *semaPt, uint8_t priority);
|
||||||
|
|
||||||
|
// ******** OS_EdgeTrigger_Restart ************
|
||||||
|
// restart button1 to signal on a falling edge interrupt
|
||||||
|
// rearm interrupt
|
||||||
|
// Inputs: none
|
||||||
|
// Outputs: none
|
||||||
|
void OS_EdgeTrigger_Restart(void);
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,33 @@
|
||||||
|
;/*****************************************************************************/
|
||||||
|
; OSasm.s: low-level OS commands, written in assembly */
|
||||||
|
; Runs on LM4F120/TM4C123/MSP432
|
||||||
|
; Lab 4 starter file
|
||||||
|
; March 25, 2016
|
||||||
|
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
|
AREA |.text|, CODE, READONLY, ALIGN=2
|
||||||
|
THUMB
|
||||||
|
REQUIRE8
|
||||||
|
PRESERVE8
|
||||||
|
|
||||||
|
EXTERN RunPt ; currently running thread
|
||||||
|
EXPORT StartOS
|
||||||
|
EXPORT SysTick_Handler
|
||||||
|
IMPORT Scheduler
|
||||||
|
|
||||||
|
|
||||||
|
SysTick_Handler ; 1) Saves R0-R3,R12,LR,PC,PSR
|
||||||
|
CPSID I ; 2) Prevent interrupt during switch
|
||||||
|
;YOU IMPLEMENT THIS (same as Lab 3)
|
||||||
|
CPSIE I ; 9) tasks run with interrupts enabled
|
||||||
|
BX LR ; 10) restore R0-R3,R12,LR,PC,PSR
|
||||||
|
|
||||||
|
StartOS
|
||||||
|
;YOU IMPLEMENT THIS (same as Lab 3)
|
||||||
|
CPSIE I ; Enable interrupts at processor level
|
||||||
|
BX LR ; start first thread
|
||||||
|
|
||||||
|
ALIGN
|
||||||
|
END
|
|
@ -0,0 +1,208 @@
|
||||||
|
// FlashProgram.c
|
||||||
|
// Runs on LM4F120/TM4C123
|
||||||
|
// Provide functions that initialize the flash memory, write
|
||||||
|
// 32-bit data to flash, write an array of 32-bit data to flash,
|
||||||
|
// and erase a 1 KB block.
|
||||||
|
// Daniel Valvano
|
||||||
|
// August 29, 2016
|
||||||
|
|
||||||
|
/* This example accompanies the book
|
||||||
|
"Embedded Systems: Real Time Interfacing to Arm Cortex M Microcontrollers",
|
||||||
|
ISBN: 978-1463590154, Jonathan Valvano, copyright (c) 2016
|
||||||
|
"Embedded Systems: Real-Time Operating Systems for ARM Cortex-M Microcontrollers",
|
||||||
|
ISBN: 978-1466468863, Jonathan Valvano, copyright (c) 2016
|
||||||
|
|
||||||
|
Copyright 2016 by Jonathan W. Valvano, valvano@mail.utexas.edu
|
||||||
|
You may use, edit, run or distribute this file
|
||||||
|
as long as the above copyright notice remains
|
||||||
|
THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED
|
||||||
|
OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
|
||||||
|
VALVANO SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL,
|
||||||
|
OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
|
||||||
|
For more information about my classes, my research, and my books, see
|
||||||
|
http://users.ece.utexas.edu/~valvano/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "FlashProgram.h"
|
||||||
|
|
||||||
|
#define FLASH_FMA_R (*((volatile uint32_t *)0x400FD000))
|
||||||
|
#define FLASH_FMA_OFFSET_MAX 0x0003FFFF // Address Offset max
|
||||||
|
#define FLASH_FMD_R (*((volatile uint32_t *)0x400FD004))
|
||||||
|
#define FLASH_FMC_R (*((volatile uint32_t *)0x400FD008))
|
||||||
|
#define FLASH_FMC_WRKEY 0xA4420000 // FLASH write key (KEY bit of FLASH_BOOTCFG_R set)
|
||||||
|
#define FLASH_FMC_WRKEY2 0x71D50000 // FLASH write key (KEY bit of FLASH_BOOTCFG_R cleared)
|
||||||
|
#define FLASH_FMC_MERASE 0x00000004 // Mass Erase Flash Memory
|
||||||
|
#define FLASH_FMC_ERASE 0x00000002 // Erase a Page of Flash Memory
|
||||||
|
#define FLASH_FMC_WRITE 0x00000001 // Write a Word into Flash Memory
|
||||||
|
#define FLASH_FMC2_R (*((volatile uint32_t *)0x400FD020))
|
||||||
|
#define FLASH_FMC2_WRBUF 0x00000001 // Buffered Flash Memory Write
|
||||||
|
#define FLASH_FWBN_R (*((volatile uint32_t *)0x400FD100))
|
||||||
|
#define FLASH_BOOTCFG_R (*((volatile uint32_t *)0x400FE1D0))
|
||||||
|
#define FLASH_BOOTCFG_KEY 0x00000010 // KEY Select
|
||||||
|
|
||||||
|
void DisableInterrupts(void); // Disable interrupts
|
||||||
|
void EnableInterrupts(void); // Enable interrupts
|
||||||
|
long StartCritical (void); // previous I bit, disable interrupts
|
||||||
|
void EndCritical(long sr); // restore I bit to previous value
|
||||||
|
void WaitForInterrupt(void); // low power mode
|
||||||
|
|
||||||
|
// Check if address offset is valid for write operation
|
||||||
|
// Writing addresses must be 4-byte aligned and within range
|
||||||
|
static int WriteAddrValid(uint32_t addr){
|
||||||
|
// check if address offset works for writing
|
||||||
|
// must be 4-byte aligned
|
||||||
|
return (((addr % 4) == 0) && (addr <= FLASH_FMA_OFFSET_MAX));
|
||||||
|
}
|
||||||
|
// Check if address offset is valid for mass writing operation
|
||||||
|
// Mass writing addresses must be 32-word (128-byte) aligned and within range
|
||||||
|
static int MassWriteAddrValid(uint32_t addr){
|
||||||
|
// check if address offset works for mass writing
|
||||||
|
// must be 32-word (128-byte) aligned
|
||||||
|
return (((addr % 128) == 0) && (addr <= FLASH_FMA_OFFSET_MAX));
|
||||||
|
}
|
||||||
|
// Check if address offset is valid for erase operation
|
||||||
|
// Erasing addresses must be 1 KB aligned and within range
|
||||||
|
static int EraseAddrValid(uint32_t addr){
|
||||||
|
// check if address offset works for erasing
|
||||||
|
// must be 1 KB aligned
|
||||||
|
return (((addr % 1024) == 0) && (addr <= FLASH_FMA_OFFSET_MAX));
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------Flash_Init------------
|
||||||
|
// This function was critical to the write and erase
|
||||||
|
// operations of the flash memory on the LM3S811
|
||||||
|
// microcontroller. But newer processors work slightly
|
||||||
|
// differently, and for the TM4C123 the timing parameters
|
||||||
|
// for the flash and EEPROM memories are configured along
|
||||||
|
// with the PLL. This function prototype is preserved to
|
||||||
|
// try to make it easier to reuse program code between the
|
||||||
|
// LM3S811, TM4C123, and TM4C1294.
|
||||||
|
// Input: systemClockFreqMHz system clock frequency (units of MHz)
|
||||||
|
// Output: none
|
||||||
|
void Flash_Init(uint8_t systemClockFreqMHz){
|
||||||
|
// do nothing; flash and EEPROM memory configured in PLL_Init()
|
||||||
|
// if the processor is executing code out of flash memory,
|
||||||
|
// presumably everything is configured correctly
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------Flash_Write------------
|
||||||
|
// Write 32-bit data to flash at given address.
|
||||||
|
// Input: addr 4-byte aligned flash memory address to write
|
||||||
|
// data 32-bit data
|
||||||
|
// Output: 'NOERROR' if successful, 'ERROR' if fail (defined in FlashProgram.h)
|
||||||
|
// Note: disables interrupts while writing
|
||||||
|
int Flash_Write(uint32_t addr, uint32_t data){
|
||||||
|
uint32_t flashkey;
|
||||||
|
if(WriteAddrValid(addr)){
|
||||||
|
DisableInterrupts(); // may be optional step
|
||||||
|
// wait for hardware idle
|
||||||
|
while(FLASH_FMC_R&(FLASH_FMC_WRITE|FLASH_FMC_ERASE|FLASH_FMC_MERASE)){
|
||||||
|
// to do later: return ERROR if this takes too long
|
||||||
|
// remember to re-enable interrupts
|
||||||
|
};
|
||||||
|
FLASH_FMD_R = data;
|
||||||
|
FLASH_FMA_R = addr;
|
||||||
|
if(FLASH_BOOTCFG_R&FLASH_BOOTCFG_KEY){ // by default, the key is 0xA442
|
||||||
|
flashkey = FLASH_FMC_WRKEY;
|
||||||
|
} else{ // otherwise, the key is 0x71D5
|
||||||
|
flashkey = FLASH_FMC_WRKEY2;
|
||||||
|
}
|
||||||
|
FLASH_FMC_R = (flashkey|FLASH_FMC_WRITE); // start writing
|
||||||
|
while(FLASH_FMC_R&FLASH_FMC_WRITE){
|
||||||
|
// to do later: return ERROR if this takes too long
|
||||||
|
// remember to re-enable interrupts
|
||||||
|
}; // wait for completion (~3 to 4 usec)
|
||||||
|
EnableInterrupts();
|
||||||
|
return NOERROR;
|
||||||
|
}
|
||||||
|
return ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------Flash_WriteArray------------
|
||||||
|
// Write an array of 32-bit data to flash starting at given address.
|
||||||
|
// Input: source pointer to array of 32-bit data
|
||||||
|
// addr 4-byte aligned flash memory address to start writing
|
||||||
|
// count number of 32-bit writes
|
||||||
|
// Output: number of successful writes; return value == count if completely successful
|
||||||
|
// Note: at 80 MHz, it takes 678 usec to write 10 words
|
||||||
|
// Note: disables interrupts while writing
|
||||||
|
int Flash_WriteArray(uint32_t *source, uint32_t addr, uint16_t count){
|
||||||
|
uint16_t successfulWrites = 0;
|
||||||
|
while((successfulWrites < count) && (Flash_Write(addr + 4*successfulWrites, source[successfulWrites]) == NOERROR)){
|
||||||
|
successfulWrites = successfulWrites + 1;
|
||||||
|
}
|
||||||
|
return successfulWrites;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------Flash_FastWrite------------
|
||||||
|
// Write an array of 32-bit data to flash starting at given address.
|
||||||
|
// This is twice as fast as Flash_WriteArray(), but the address has
|
||||||
|
// to be 128-byte aligned, and the count has to be <= 32.
|
||||||
|
// Input: source pointer to array of 32-bit data
|
||||||
|
// addr 128-byte aligned flash memory address to start writing
|
||||||
|
// count number of 32-bit writes (<=32)
|
||||||
|
// Output: number of successful writes; return value == count if completely successful
|
||||||
|
// Note: at 80 MHz, it takes 335 usec to write 10 words
|
||||||
|
// Note: disables interrupts while writing
|
||||||
|
int Flash_FastWrite(uint32_t *source, uint32_t addr, uint16_t count){
|
||||||
|
uint32_t flashkey;
|
||||||
|
uint32_t volatile *FLASH_FWBn_R = (uint32_t volatile*)0x400FD100;
|
||||||
|
int writes = 0;
|
||||||
|
if(MassWriteAddrValid(addr)){
|
||||||
|
DisableInterrupts(); // may be optional step
|
||||||
|
while(FLASH_FMC2_R&FLASH_FMC2_WRBUF){ // wait for hardware idle
|
||||||
|
// to do later: return ERROR if this takes too long
|
||||||
|
// remember to re-enable interrupts
|
||||||
|
};
|
||||||
|
while((writes < 32) && (writes < count)){
|
||||||
|
FLASH_FWBn_R[writes] = source[writes];
|
||||||
|
writes = writes + 1;
|
||||||
|
}
|
||||||
|
FLASH_FMA_R = addr;
|
||||||
|
if(FLASH_BOOTCFG_R&FLASH_BOOTCFG_KEY){ // by default, the key is 0xA442
|
||||||
|
flashkey = FLASH_FMC_WRKEY;
|
||||||
|
} else{ // otherwise, the key is 0x71D5
|
||||||
|
flashkey = FLASH_FMC_WRKEY2;
|
||||||
|
}
|
||||||
|
FLASH_FMC2_R = (flashkey|FLASH_FMC2_WRBUF); // start writing
|
||||||
|
while(FLASH_FMC2_R&FLASH_FMC2_WRBUF){
|
||||||
|
// to do later: return ERROR if this takes too long
|
||||||
|
// remember to re-enable interrupts
|
||||||
|
}; // wait for completion (~3 to 4 usec)
|
||||||
|
EnableInterrupts();
|
||||||
|
}
|
||||||
|
return writes;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------Flash_Erase------------
|
||||||
|
// Erase 1 KB block of flash.
|
||||||
|
// Input: addr 1-KB aligned flash memory address to erase
|
||||||
|
// Output: 'NOERROR' if successful, 'ERROR' if fail (defined in FlashProgram.h)
|
||||||
|
// Note: disables interrupts while erasing
|
||||||
|
int Flash_Erase(uint32_t addr){
|
||||||
|
uint32_t flashkey;
|
||||||
|
if(EraseAddrValid(addr)){
|
||||||
|
DisableInterrupts(); // may be optional step
|
||||||
|
// wait for hardware idle
|
||||||
|
while(FLASH_FMC_R&(FLASH_FMC_WRITE|FLASH_FMC_ERASE|FLASH_FMC_MERASE)){
|
||||||
|
// to do later: return ERROR if this takes too long
|
||||||
|
// remember to re-enable interrupts
|
||||||
|
};
|
||||||
|
FLASH_FMA_R = addr;
|
||||||
|
if(FLASH_BOOTCFG_R&FLASH_BOOTCFG_KEY){ // by default, the key is 0xA442
|
||||||
|
flashkey = FLASH_FMC_WRKEY;
|
||||||
|
} else{ // otherwise, the key is 0x71D5
|
||||||
|
flashkey = FLASH_FMC_WRKEY2;
|
||||||
|
}
|
||||||
|
FLASH_FMC_R = (flashkey|FLASH_FMC_ERASE); // start erasing 1 KB block
|
||||||
|
while(FLASH_FMC_R&FLASH_FMC_ERASE){
|
||||||
|
// to do later: return ERROR if this takes too long
|
||||||
|
// remember to re-enable interrupts
|
||||||
|
}; // wait for completion (~3 to 4 usec)
|
||||||
|
EnableInterrupts();
|
||||||
|
return NOERROR;
|
||||||
|
}
|
||||||
|
return ERROR;
|
||||||
|
}
|
|
@ -0,0 +1,78 @@
|
||||||
|
// FlashProgram.h
|
||||||
|
// Runs on LM4F120/TM4C123
|
||||||
|
// Provide functions that initialize the flash memory, write
|
||||||
|
// 32-bit data to flash, write an array of 32-bit data to flash,
|
||||||
|
// and erase a 1 KB block.
|
||||||
|
// Daniel Valvano
|
||||||
|
// August 29, 2016
|
||||||
|
|
||||||
|
/* This example accompanies the book
|
||||||
|
"Embedded Systems: Real Time Interfacing to Arm Cortex M Microcontrollers",
|
||||||
|
ISBN: 978-1463590154, Jonathan Valvano, copyright (c) 2016
|
||||||
|
"Embedded Systems: Real-Time Operating Systems for ARM Cortex-M Microcontrollers",
|
||||||
|
ISBN: 978-1466468863, Jonathan Valvano, copyright (c) 2016
|
||||||
|
|
||||||
|
Copyright 2016 by Jonathan W. Valvano, valvano@mail.utexas.edu
|
||||||
|
You may use, edit, run or distribute this file
|
||||||
|
as long as the above copyright notice remains
|
||||||
|
THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED
|
||||||
|
OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
|
||||||
|
VALVANO SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL,
|
||||||
|
OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
|
||||||
|
For more information about my classes, my research, and my books, see
|
||||||
|
http://users.ece.utexas.edu/~valvano/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define ERROR 1 // Value returned if failure
|
||||||
|
#define NOERROR 0 // Value returned if success
|
||||||
|
|
||||||
|
//------------Flash_Init------------
|
||||||
|
// This function was critical to the write and erase
|
||||||
|
// operations of the flash memory on the LM3S811
|
||||||
|
// microcontroller. But newer processors work slightly
|
||||||
|
// differently, and for the TM4C123 the timing parameters
|
||||||
|
// for the flash and EEPROM memories are configured along
|
||||||
|
// with the PLL. This function prototype is preserved to
|
||||||
|
// try to make it easier to reuse program code between the
|
||||||
|
// LM3S811, TM4C123, and TM4C1294.
|
||||||
|
// Input: systemClockFreqMHz system clock frequency (units of MHz)
|
||||||
|
// Output: none
|
||||||
|
void Flash_Init(uint8_t systemClockFreqMHz);
|
||||||
|
|
||||||
|
//------------Flash_Write------------
|
||||||
|
// Write 32-bit data to flash at given address.
|
||||||
|
// Input: addr 4-byte aligned flash memory address to write
|
||||||
|
// data 32-bit data
|
||||||
|
// Output: 'NOERROR' if successful, 'ERROR' if fail (defined in FlashProgram.h)
|
||||||
|
// Note: disables interrupts while writing
|
||||||
|
int Flash_Write(uint32_t addr, uint32_t data);
|
||||||
|
|
||||||
|
//------------Flash_WriteArray------------
|
||||||
|
// Write an array of 32-bit data to flash starting at given address.
|
||||||
|
// Input: source pointer to array of 32-bit data
|
||||||
|
// addr 4-byte aligned flash memory address to start writing
|
||||||
|
// count number of 32-bit writes
|
||||||
|
// Output: number of successful writes; return value == count if completely successful
|
||||||
|
// Note: at 80 MHz, it takes 678 usec to write 10 words
|
||||||
|
// Note: disables interrupts while writing
|
||||||
|
int Flash_WriteArray(uint32_t *source, uint32_t addr, uint16_t count);
|
||||||
|
|
||||||
|
//------------Flash_FastWrite------------
|
||||||
|
// Write an array of 32-bit data to flash starting at given address.
|
||||||
|
// This is twice as fast as Flash_WriteArray(), but the address has
|
||||||
|
// to be 128-byte aligned, and the count has to be <= 32.
|
||||||
|
// Input: source pointer to array of 32-bit data
|
||||||
|
// addr 128-byte aligned flash memory address to start writing
|
||||||
|
// count number of 32-bit writes (<=32)
|
||||||
|
// Output: number of successful writes; return value == count if completely successful
|
||||||
|
// Note: at 80 MHz, it takes 335 usec to write 10 words
|
||||||
|
// Note: disables interrupts while writing
|
||||||
|
int Flash_FastWrite(uint32_t *source, uint32_t addr, uint16_t count);
|
||||||
|
|
||||||
|
//------------Flash_Erase------------
|
||||||
|
// Erase 1 KB block of flash.
|
||||||
|
// Input: addr 1-KB aligned flash memory address to erase
|
||||||
|
// Output: 'NOERROR' if successful, 'ERROR' if fail (defined in FlashProgram.h)
|
||||||
|
// Note: disables interrupts while erasing
|
||||||
|
int Flash_Erase(uint32_t addr);
|
|
@ -0,0 +1,266 @@
|
||||||
|
// Lab5.c
|
||||||
|
// Runs on either MSP432 or TM4C123
|
||||||
|
// Start project to Lab 5. High level test of the file
|
||||||
|
// system will initialize variables, store files, and access
|
||||||
|
// files.
|
||||||
|
// Daniel and Jonathan Valvano
|
||||||
|
// August 29, 2016
|
||||||
|
|
||||||
|
/* This example accompanies the books
|
||||||
|
"Embedded Systems: Real Time Interfacing to ARM Cortex M Microcontrollers",
|
||||||
|
ISBN: 978-1463590154, Jonathan Valvano, copyright (c) 2016
|
||||||
|
|
||||||
|
"Embedded Systems: Real-Time Operating Systems for ARM Cortex-M Microcontrollers",
|
||||||
|
ISBN: 978-1466468863, Jonathan Valvano, copyright (c) 2016
|
||||||
|
|
||||||
|
"Embedded Systems: Introduction to the MSP432 Microcontroller",
|
||||||
|
ISBN: 978-1512185676, Jonathan Valvano, copyright (c) 2016
|
||||||
|
|
||||||
|
"Embedded Systems: Real-Time Interfacing to the MSP432 Microcontroller",
|
||||||
|
ISBN: 978-1514676585, Jonathan Valvano, copyright (c) 2016
|
||||||
|
|
||||||
|
Copyright 2016 by Jonathan W. Valvano, valvano@mail.utexas.edu
|
||||||
|
You may use, edit, run or distribute this file
|
||||||
|
as long as the above copyright notice remains
|
||||||
|
THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED
|
||||||
|
OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
|
||||||
|
VALVANO SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL,
|
||||||
|
OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
|
||||||
|
For more information about my classes, my research, and my books, see
|
||||||
|
http://users.ece.utexas.edu/~valvano/
|
||||||
|
*/
|
||||||
|
|
||||||
|
// J1 J3 J4 J2
|
||||||
|
// [ 1] [21] [40] [20]
|
||||||
|
// [ 2] [22] [39] [19]
|
||||||
|
// [ 3] [23] [38] [18]
|
||||||
|
// [ 4] [24] [37] [17]
|
||||||
|
// [ 5] [25] [36] [16]
|
||||||
|
// [ 6] [26] [35] [15]
|
||||||
|
// [ 7] [27] [34] [14]
|
||||||
|
// [ 8] [28] [33] [13]
|
||||||
|
// [ 9] [29] [32] [12]
|
||||||
|
// [10] [30] [31] [11]
|
||||||
|
|
||||||
|
// +3.3V connected to J1.1 (power)
|
||||||
|
// joystick horizontal (X) connected to J1.2 (analog)
|
||||||
|
// UART from BoosterPack to LaunchPad connected to J1.3 (UART)
|
||||||
|
// UART from LaunchPad to BoosterPack connected to J1.4 (UART)
|
||||||
|
// joystick Select button connected to J1.5 (digital)
|
||||||
|
// microphone connected to J1.6 (analog)
|
||||||
|
// LCD SPI clock connected to J1.7 (SPI)
|
||||||
|
// ambient light (OPT3001) interrupt connected to J1.8 (digital)
|
||||||
|
// ambient light (OPT3001) and temperature sensor (TMP006) I2C SCL connected to J1.9 (I2C)
|
||||||
|
// ambient light (OPT3001) and temperature sensor (TMP006) I2C SDA connected to J1.10 (I2C)
|
||||||
|
|
||||||
|
// temperature sensor (TMP006) interrupt connected to J2.11 (digital)
|
||||||
|
// nothing connected to J2.12 (SPI CS_Other)
|
||||||
|
// LCD SPI CS connected to J2.13 (SPI)
|
||||||
|
// nothing connected to J2.14 (SPI MISO)
|
||||||
|
// LCD SPI data connected to J2.15 (SPI)
|
||||||
|
// nothing connected to J2.16 (reset)
|
||||||
|
// LCD !RST connected to J2.17 (digital)
|
||||||
|
// nothing connected to J2.18 (SPI CS_Wireless)
|
||||||
|
// servo PWM connected to J2.19 (PWM)
|
||||||
|
// GND connected to J2.20 (ground)
|
||||||
|
|
||||||
|
// +5V connected to J3.21 (power)
|
||||||
|
// GND connected to J3.22 (ground)
|
||||||
|
// accelerometer X connected to J3.23 (analog)
|
||||||
|
// accelerometer Y connected to J3.24 (analog)
|
||||||
|
// accelerometer Z connected to J3.25 (analog)
|
||||||
|
// joystick vertical (Y) connected to J3.26 (analog)
|
||||||
|
// nothing connected to J3.27 (I2S WS)
|
||||||
|
// nothing connected to J3.28 (I2S SCLK)
|
||||||
|
// nothing connected to J3.29 (I2S SDout)
|
||||||
|
// nothing connected to J3.30 (I2S SDin)
|
||||||
|
|
||||||
|
// LCD RS connected to J4.31 (digital)
|
||||||
|
// user Button2 (bottom) connected to J4.32 (digital)
|
||||||
|
// user Button1 (top) connected to J4.33 (digital)
|
||||||
|
// gator hole switch connected to J4.34 (digital)
|
||||||
|
// nothing connected to J4.35
|
||||||
|
// nothing connected to J4.36
|
||||||
|
// RGB LED blue connected to J4.37 (PWM)
|
||||||
|
// RGB LED green connected to J4.38 (PWM)
|
||||||
|
// RGB LED red (jumper up) or LCD backlight (jumper down) connected to J4.39 (PWM)
|
||||||
|
// buzzer connected to J4.40 (PWM)
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "../inc/BSP.h"
|
||||||
|
#include "../inc/CortexM.h"
|
||||||
|
#include "eDisk.h"
|
||||||
|
#include "../inc/Profile.h"
|
||||||
|
#include "Texas.h"
|
||||||
|
#include "eFile.h"
|
||||||
|
|
||||||
|
// normally this access would be poor style,
|
||||||
|
// but the access to internal data is used here for debugging
|
||||||
|
extern uint8_t Buff[512];
|
||||||
|
extern uint8_t Directory[256], FAT[256];
|
||||||
|
|
||||||
|
// Test function: Copy a NULL-terminated 'inString' into the
|
||||||
|
// 'Buff' global variable with a maximum of 512 characters.
|
||||||
|
// Uninitialized characters are set to 0xFF.
|
||||||
|
// Inputs: inString pointer to NULL-terminated character string
|
||||||
|
// Outputs: none
|
||||||
|
void testbuildbuff(char *inString){
|
||||||
|
uint32_t i = 0;
|
||||||
|
while((i < 512) && (inString[i] != 0)){
|
||||||
|
Buff[i] = inString[i];
|
||||||
|
i = i + 1;
|
||||||
|
}
|
||||||
|
while(i < 512){
|
||||||
|
Buff[i] = 0xFF; // fill the remainder of the buffer with 0xFF
|
||||||
|
i = i + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test function: Draw a visual representation of the file
|
||||||
|
// system to the screen. It should resemble Figure 5.13.
|
||||||
|
// This function reads the contents of the flash memory, so
|
||||||
|
// first call OS_File_Flush() to synchronize.
|
||||||
|
// Inputs: index starting index of directory and FAT
|
||||||
|
// Outputs: none
|
||||||
|
#define COLORSIZE 9
|
||||||
|
#define LCD_GRAY 0xCE59 // 200, 200, 200
|
||||||
|
const uint16_t ColorArray[COLORSIZE] = {LCD_YELLOW, LCD_BLUE, LCD_GREEN, LCD_RED, LCD_CYAN, LCD_LIGHTGREEN, LCD_ORANGE, LCD_MAGENTA, LCD_WHITE};
|
||||||
|
// display 12 lines of the directory and FAT
|
||||||
|
// used for debugging
|
||||||
|
// Input: index is starting line number
|
||||||
|
// Output: none
|
||||||
|
void DisplayDirectory(uint8_t index){
|
||||||
|
uint16_t dirclr[256], fatclr[256];
|
||||||
|
volatile uint8_t *diraddr = (volatile uint8_t *)(EDISK_ADDR_MAX - 511); /* address of directory */
|
||||||
|
volatile uint8_t *fataddr = (volatile uint8_t *)(EDISK_ADDR_MAX - 255); /* address of FAT */
|
||||||
|
int i, j;
|
||||||
|
// set default color to gray
|
||||||
|
for(i=0; i<256; i=i+1){
|
||||||
|
dirclr[i] = LCD_GRAY;
|
||||||
|
fatclr[i] = LCD_GRAY;
|
||||||
|
}
|
||||||
|
// set color for each active file
|
||||||
|
for(i=0; i<255; i=i+1){
|
||||||
|
j = diraddr[i];
|
||||||
|
if(j != 255){
|
||||||
|
dirclr[i] = ColorArray[i%COLORSIZE];
|
||||||
|
}
|
||||||
|
while(j != 255){
|
||||||
|
fatclr[j] = ColorArray[i%COLORSIZE];
|
||||||
|
j = fataddr[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// clear the screen if necessary (very slow but helps with button bounce)
|
||||||
|
if((index + 11) > 255){
|
||||||
|
BSP_LCD_FillScreen(LCD_BLACK);
|
||||||
|
}
|
||||||
|
// print the column headers
|
||||||
|
BSP_LCD_DrawString(5, 0, "DIR", LCD_GRAY);
|
||||||
|
BSP_LCD_DrawString(15, 0, "FAT", LCD_GRAY);
|
||||||
|
// print the cloumns
|
||||||
|
i = 0;
|
||||||
|
while((i <= 11) && ((index + i) <= 255)){
|
||||||
|
BSP_LCD_SetCursor(0, i+1);
|
||||||
|
BSP_LCD_OutUDec4((uint32_t)(index + i), LCD_GRAY);
|
||||||
|
BSP_LCD_SetCursor(4, i+1);
|
||||||
|
BSP_LCD_OutUDec4((uint32_t)diraddr[index+i], dirclr[index+i]);
|
||||||
|
BSP_LCD_SetCursor(10, i+1);
|
||||||
|
BSP_LCD_OutUDec4((uint32_t)(index + i), LCD_GRAY);
|
||||||
|
BSP_LCD_SetCursor(14, i+1);
|
||||||
|
BSP_LCD_OutUDec4((uint32_t)fataddr[index+i], fatclr[index+i]);
|
||||||
|
i = i + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void){
|
||||||
|
uint8_t m, n, p; // file numbers
|
||||||
|
uint8_t index = 0; // row index
|
||||||
|
volatile int i;
|
||||||
|
DisableInterrupts();
|
||||||
|
BSP_Clock_InitFastest();
|
||||||
|
Profile_Init(); // initialize the 7 hardware profiling pins
|
||||||
|
eDisk_Init(0);
|
||||||
|
BSP_Button1_Init();
|
||||||
|
BSP_Button2_Init();
|
||||||
|
BSP_LCD_Init();
|
||||||
|
BSP_LCD_FillScreen(LCD_BLACK);
|
||||||
|
|
||||||
|
if(BSP_Button1_Input() == 0){ // run TExaS if Button1 is pressed
|
||||||
|
BSP_LCD_DrawString(0, 0, "Running TExaS grader", LCD_YELLOW);
|
||||||
|
// change 1000 to 4-digit number from edX
|
||||||
|
TExaS_Init(GRADER, 1000); // initialize the Lab 5 grader
|
||||||
|
// TExaS_Init(LOGICANALYZER, 1000);
|
||||||
|
// Logic analyzer will run, but the Lab 5 doesn't really use the logic analyzer
|
||||||
|
while(BSP_Button1_Input() == 0){};
|
||||||
|
BSP_LCD_DrawString(0, 0, " ", LCD_YELLOW);
|
||||||
|
}
|
||||||
|
if(BSP_Button2_Input() == 0){ // erase if Button2 is pressed
|
||||||
|
BSP_LCD_DrawString(0, 0, "Erasing entire disk", LCD_YELLOW);
|
||||||
|
OS_File_Format();
|
||||||
|
while(BSP_Button2_Input() == 0){};
|
||||||
|
BSP_LCD_DrawString(0, 0, " ", LCD_YELLOW);
|
||||||
|
}
|
||||||
|
EnableInterrupts();
|
||||||
|
n = OS_File_New(); // n = 0, 3, 6, 9, ...
|
||||||
|
testbuildbuff("buf0");
|
||||||
|
OS_File_Append(n, Buff); // 0x00020000
|
||||||
|
testbuildbuff("buf1");
|
||||||
|
OS_File_Append(n, Buff); // 0x00020200
|
||||||
|
testbuildbuff("buf2");
|
||||||
|
OS_File_Append(n, Buff); // 0x00020400
|
||||||
|
testbuildbuff("buf3");
|
||||||
|
OS_File_Append(n, Buff); // 0x00020600
|
||||||
|
testbuildbuff("buf4");
|
||||||
|
OS_File_Append(n, Buff); // 0x00020800
|
||||||
|
testbuildbuff("buf5");
|
||||||
|
OS_File_Append(n, Buff); // 0x00020A00
|
||||||
|
testbuildbuff("buf6");
|
||||||
|
OS_File_Append(n, Buff); // 0x00020C00
|
||||||
|
testbuildbuff("buf7");
|
||||||
|
OS_File_Append(n, Buff); // 0x00020E00
|
||||||
|
m = OS_File_New(); // m = 1, 4, 7, 10, ...
|
||||||
|
testbuildbuff("dat0");
|
||||||
|
OS_File_Append(m, Buff); // 0x00021000
|
||||||
|
testbuildbuff("dat1");
|
||||||
|
OS_File_Append(m, Buff); // 0x00021200
|
||||||
|
testbuildbuff("dat2");
|
||||||
|
OS_File_Append(m, Buff); // 0x00021400
|
||||||
|
testbuildbuff("dat3");
|
||||||
|
OS_File_Append(m, Buff); // 0x00021600
|
||||||
|
p = OS_File_New(); // p = 2, 5, 8, 11, ...
|
||||||
|
testbuildbuff("arr0");
|
||||||
|
OS_File_Append(p, Buff); // 0x00021800
|
||||||
|
testbuildbuff("arr1");
|
||||||
|
OS_File_Append(p, Buff); // 0x00021A00
|
||||||
|
testbuildbuff("buf8");
|
||||||
|
OS_File_Append(n, Buff); // 0x00021C00
|
||||||
|
testbuildbuff("buf9");
|
||||||
|
OS_File_Append(n, Buff); // 0x00021E00
|
||||||
|
testbuildbuff("arr2");
|
||||||
|
OS_File_Append(p, Buff); // 0x00022000
|
||||||
|
testbuildbuff("dat4");
|
||||||
|
OS_File_Append(m, Buff); // 0x00022200
|
||||||
|
i = OS_File_Size(n); // i = 10
|
||||||
|
i = OS_File_Size(m); // i = 5
|
||||||
|
i = OS_File_Size(p); // i = 3
|
||||||
|
i = OS_File_Size(p+1); // i = 0
|
||||||
|
OS_File_Flush(); // 0x0003FE00
|
||||||
|
while(1){
|
||||||
|
DisplayDirectory(index);
|
||||||
|
while((BSP_Button1_Input() != 0) && (BSP_Button2_Input() != 0)){};
|
||||||
|
if(BSP_Button1_Input() == 0){
|
||||||
|
if(index > 11){
|
||||||
|
index = index - 11;
|
||||||
|
} else{
|
||||||
|
index = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(BSP_Button2_Input() == 0){
|
||||||
|
if((index + 11) <= 255){
|
||||||
|
index = index + 11;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while((BSP_Button1_Input() == 0) || (BSP_Button2_Input() == 0)){};
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,125 @@
|
||||||
|
// *****************Texas.h**************
|
||||||
|
// grading engine for Lab 5
|
||||||
|
//
|
||||||
|
// Runs on either MSP432 or TM4C123
|
||||||
|
// Daniel and Jonathan Valvano
|
||||||
|
// May 19, 2016
|
||||||
|
|
||||||
|
/* This example accompanies the books
|
||||||
|
"Embedded Systems: Real Time Interfacing to ARM Cortex M Microcontrollers",
|
||||||
|
ISBN: 978-1463590154, Jonathan Valvano, copyright (c) 2016
|
||||||
|
|
||||||
|
"Embedded Systems: Real-Time Operating Systems for ARM Cortex-M Microcontrollers",
|
||||||
|
ISBN: 978-1466468863, Jonathan Valvano, copyright (c) 2016
|
||||||
|
|
||||||
|
Copyright 2016 by Jonathan W. Valvano, valvano@mail.utexas.edu
|
||||||
|
You may use, edit, run or distribute this file
|
||||||
|
as long as the above copyright notice remains
|
||||||
|
THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED
|
||||||
|
OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
|
||||||
|
VALVANO SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL,
|
||||||
|
OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
|
||||||
|
For more information about my classes, my research, and my books, see
|
||||||
|
http://users.ece.utexas.edu/~valvano/
|
||||||
|
*/
|
||||||
|
|
||||||
|
// J1 J3 J4 J2
|
||||||
|
// [ 1] [21] [40] [20]
|
||||||
|
// [ 2] [22] [39] [19]
|
||||||
|
// [ 3] [23] [38] [18]
|
||||||
|
// [ 4] [24] [37] [17]
|
||||||
|
// [ 5] [25] [36] [16]
|
||||||
|
// [ 6] [26] [35] [15]
|
||||||
|
// [ 7] [27] [34] [14]
|
||||||
|
// [ 8] [28] [33] [13]
|
||||||
|
// [ 9] [29] [32] [12]
|
||||||
|
// [10] [30] [31] [11]
|
||||||
|
|
||||||
|
// +3.3V connected to J1.1 (power)
|
||||||
|
// joystick horizontal (X) connected to J1.2 (analog)
|
||||||
|
// UART from BoosterPack to LaunchPad connected to J1.3 (UART)
|
||||||
|
// UART from LaunchPad to BoosterPack connected to J1.4 (UART)
|
||||||
|
// joystick Select button connected to J1.5 (digital)
|
||||||
|
// microphone connected to J1.6 (analog)
|
||||||
|
// LCD SPI clock connected to J1.7 (SPI)
|
||||||
|
// ambient light (OPT3001) interrupt connected to J1.8 (digital)
|
||||||
|
// ambient light (OPT3001) and temperature sensor (TMP006) I2C SCL connected to J1.9 (I2C)
|
||||||
|
// ambient light (OPT3001) and temperature sensor (TMP006) I2C SDA connected to J1.10 (I2C)
|
||||||
|
|
||||||
|
// temperature sensor (TMP006) interrupt connected to J2.11 (digital)
|
||||||
|
// nothing connected to J2.12 (SPI CS_Other)
|
||||||
|
// LCD SPI CS connected to J2.13 (SPI)
|
||||||
|
// nothing connected to J2.14 (SPI MISO)
|
||||||
|
// LCD SPI data connected to J2.15 (SPI)
|
||||||
|
// nothing connected to J2.16 (reset)
|
||||||
|
// LCD !RST connected to J2.17 (digital)
|
||||||
|
// nothing connected to J2.18 (SPI CS_Wireless)
|
||||||
|
// servo PWM connected to J2.19 (PWM)
|
||||||
|
// GND connected to J2.20 (ground)
|
||||||
|
|
||||||
|
// +5V connected to J3.21 (power)
|
||||||
|
// GND connected to J3.22 (ground)
|
||||||
|
// accelerometer X connected to J3.23 (analog)
|
||||||
|
// accelerometer Y connected to J3.24 (analog)
|
||||||
|
// accelerometer Z connected to J3.25 (analog)
|
||||||
|
// joystick vertical (Y) connected to J3.26 (analog)
|
||||||
|
// nothing connected to J3.27 (I2S WS)
|
||||||
|
// nothing connected to J3.28 (I2S SCLK)
|
||||||
|
// nothing connected to J3.29 (I2S SDout)
|
||||||
|
// nothing connected to J3.30 (I2S SDin)
|
||||||
|
|
||||||
|
// LCD RS connected to J4.31 (digital)
|
||||||
|
// user Button2 (bottom) connected to J4.32 (digital)
|
||||||
|
// user Button1 (top) connected to J4.33 (digital)
|
||||||
|
// gator hole switch connected to J4.34 (digital)
|
||||||
|
// nothing connected to J4.35
|
||||||
|
// nothing connected to J4.36
|
||||||
|
// RGB LED blue connected to J4.37 (PWM)
|
||||||
|
// RGB LED green connected to J4.38 (PWM)
|
||||||
|
// RGB LED red (jumper up) or LCD backlight (jumper down) connected to J4.39 (PWM)
|
||||||
|
// buzzer connected to J4.40 (PWM)
|
||||||
|
|
||||||
|
enum TExaSmode{
|
||||||
|
GRADER,
|
||||||
|
LOGICANALYZER
|
||||||
|
};
|
||||||
|
|
||||||
|
// ************TExaS_Init*****************
|
||||||
|
// Initialize grader, test low, middle, and high level
|
||||||
|
// functions, print the grade to the UART, and return.
|
||||||
|
// Inputs: Grading or Logic analyzer
|
||||||
|
// 4-digit number from edX
|
||||||
|
// Outputs: none
|
||||||
|
void TExaS_Init(enum TExaSmode mode, uint32_t edXcode);
|
||||||
|
|
||||||
|
// ************TExaS_Stop*****************
|
||||||
|
// Stop the transfer if in LOGICANALYZER mode. Unlike
|
||||||
|
// past labs, this grader completes its process in the
|
||||||
|
// initialization function, so this function has no
|
||||||
|
// effect if in GRADER mode.
|
||||||
|
// Inputs: none
|
||||||
|
// Outputs: none
|
||||||
|
void TExaS_Stop(void);
|
||||||
|
|
||||||
|
// ************TExaS_Task*****************
|
||||||
|
// Toggle the corresponding bit of the logic analyzer.
|
||||||
|
// When TExaS_Init() is called in LOGICANALYZER mode,
|
||||||
|
// these seven bits are sent through the UART at 10kHz.
|
||||||
|
// Unlike past labs, these functions are not graded,
|
||||||
|
// and this lab has no timing requirements.
|
||||||
|
// Inputs: none
|
||||||
|
// Outputs: none
|
||||||
|
void TExaS_Task0(void);
|
||||||
|
|
||||||
|
void TExaS_Task1(void);
|
||||||
|
|
||||||
|
void TExaS_Task2(void);
|
||||||
|
|
||||||
|
void TExaS_Task3(void);
|
||||||
|
|
||||||
|
void TExaS_Task4(void);
|
||||||
|
|
||||||
|
void TExaS_Task5(void);
|
||||||
|
|
||||||
|
void TExaS_Task6(void);
|
|
@ -0,0 +1,118 @@
|
||||||
|
// eDisk.c
|
||||||
|
// Runs on TM4C123
|
||||||
|
// Mid-level implementation of the solid state disk device
|
||||||
|
// driver. Below this is the low level, hardware-specific
|
||||||
|
// flash memory interface. Above this is the high level
|
||||||
|
// file system implementation.
|
||||||
|
// Daniel and Jonathan Valvano
|
||||||
|
// August 29, 2016
|
||||||
|
|
||||||
|
/* This example accompanies the books
|
||||||
|
"Embedded Systems: Real Time Interfacing to ARM Cortex M Microcontrollers",
|
||||||
|
ISBN: 978-1463590154, Jonathan Valvano, copyright (c) 2016
|
||||||
|
|
||||||
|
"Embedded Systems: Real-Time Operating Systems for ARM Cortex-M Microcontrollers",
|
||||||
|
ISBN: 978-1466468863, Jonathan Valvano, copyright (c) 2016
|
||||||
|
|
||||||
|
"Embedded Systems: Introduction to the MSP432 Microcontroller",
|
||||||
|
ISBN: 978-1512185676, Jonathan Valvano, copyright (c) 2016
|
||||||
|
|
||||||
|
"Embedded Systems: Real-Time Interfacing to the MSP432 Microcontroller",
|
||||||
|
ISBN: 978-1514676585, Jonathan Valvano, copyright (c) 2016
|
||||||
|
|
||||||
|
Copyright 2016 by Jonathan W. Valvano, valvano@mail.utexas.edu
|
||||||
|
You may use, edit, run or distribute this file
|
||||||
|
as long as the above copyright notice remains
|
||||||
|
THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED
|
||||||
|
OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
|
||||||
|
VALVANO SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL,
|
||||||
|
OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
|
||||||
|
For more information about my classes, my research, and my books, see
|
||||||
|
http://users.ece.utexas.edu/~valvano/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "eDisk.h"
|
||||||
|
#include "FlashProgram.h"
|
||||||
|
|
||||||
|
//*************** eDisk_Init ***********
|
||||||
|
// Initialize the interface between microcontroller and disk
|
||||||
|
// Inputs: drive number (only drive 0 is supported)
|
||||||
|
// Outputs: status
|
||||||
|
// RES_OK 0: Successful
|
||||||
|
// RES_ERROR 1: Drive not initialized
|
||||||
|
enum DRESULT eDisk_Init(uint32_t drive){
|
||||||
|
// if drive is 0, return RES_OK, otherwise return RES_ERROR
|
||||||
|
// for some configurations the physical drive needs initialization
|
||||||
|
// however for the internal flash, no initialization is required
|
||||||
|
// so this function doesn't do anything
|
||||||
|
if(drive == 0){ // only drive 0 is supported
|
||||||
|
return RES_OK;
|
||||||
|
}
|
||||||
|
return RES_ERROR;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//*************** eDisk_ReadSector ***********
|
||||||
|
// Read 1 sector of 512 bytes from the disk, data goes to RAM
|
||||||
|
// Inputs: pointer to an empty RAM buffer
|
||||||
|
// sector number of disk to read: 0,1,2,...255
|
||||||
|
// Outputs: result
|
||||||
|
// RES_OK 0: Successful
|
||||||
|
// RES_ERROR 1: R/W Error
|
||||||
|
// RES_WRPRT 2: Write Protected
|
||||||
|
// RES_NOTRDY 3: Not Ready
|
||||||
|
// RES_PARERR 4: Invalid Parameter
|
||||||
|
enum DRESULT eDisk_ReadSector(
|
||||||
|
uint8_t *buff, // Pointer to a RAM buffer into which to store
|
||||||
|
uint8_t sector){ // sector number to read from
|
||||||
|
// starting ROM address of the sector is EDISK_ADDR_MIN + 512*sector
|
||||||
|
// return RES_PARERR if EDISK_ADDR_MIN + 512*sector > EDISK_ADDR_MAX
|
||||||
|
// copy 512 bytes from ROM (disk) into RAM (buff)
|
||||||
|
// **write this function**
|
||||||
|
|
||||||
|
|
||||||
|
return RES_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
//*************** eDisk_WriteSector ***********
|
||||||
|
// Write 1 sector of 512 bytes of data to the disk, data comes from RAM
|
||||||
|
// Inputs: pointer to RAM buffer with information
|
||||||
|
// sector number of disk to write: 0,1,2,...,255
|
||||||
|
// Outputs: result
|
||||||
|
// RES_OK 0: Successful
|
||||||
|
// RES_ERROR 1: R/W Error
|
||||||
|
// RES_WRPRT 2: Write Protected
|
||||||
|
// RES_NOTRDY 3: Not Ready
|
||||||
|
// RES_PARERR 4: Invalid Parameter
|
||||||
|
enum DRESULT eDisk_WriteSector(
|
||||||
|
const uint8_t *buff, // Pointer to the data to be written
|
||||||
|
uint8_t sector){ // sector number
|
||||||
|
// starting ROM address of the sector is EDISK_ADDR_MIN + 512*sector
|
||||||
|
// return RES_PARERR if EDISK_ADDR_MIN + 512*sector > EDISK_ADDR_MAX
|
||||||
|
// write 512 bytes from RAM (buff) into ROM (disk)
|
||||||
|
// you can use Flash_FastWrite or Flash_WriteArray
|
||||||
|
// **write this function**
|
||||||
|
|
||||||
|
|
||||||
|
return RES_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
//*************** eDisk_Format ***********
|
||||||
|
// Erase all files and all data by resetting the flash to all 1's
|
||||||
|
// Inputs: none
|
||||||
|
// Outputs: result
|
||||||
|
// RES_OK 0: Successful
|
||||||
|
// RES_ERROR 1: R/W Error
|
||||||
|
// RES_WRPRT 2: Write Protected
|
||||||
|
// RES_NOTRDY 3: Not Ready
|
||||||
|
// RES_PARERR 4: Invalid Parameter
|
||||||
|
enum DRESULT eDisk_Format(void){
|
||||||
|
// erase all flash from EDISK_ADDR_MIN to EDISK_ADDR_MAX
|
||||||
|
// **write this function**
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return RES_OK;
|
||||||
|
}
|
|
@ -0,0 +1,91 @@
|
||||||
|
// eDisk.h
|
||||||
|
// Runs on either MSP432 or TM4C123
|
||||||
|
// Mid-level implementation of the solid state disk device
|
||||||
|
// driver. Below this is the low level, hardware-specific
|
||||||
|
// flash memory interface. Above this is the high level
|
||||||
|
// file system implementation.
|
||||||
|
// Daniel and Jonathan Valvano
|
||||||
|
// August 29, 2016
|
||||||
|
|
||||||
|
/* This example accompanies the books
|
||||||
|
"Embedded Systems: Real Time Interfacing to ARM Cortex M Microcontrollers",
|
||||||
|
ISBN: 978-1463590154, Jonathan Valvano, copyright (c) 2016
|
||||||
|
|
||||||
|
"Embedded Systems: Real-Time Operating Systems for ARM Cortex-M Microcontrollers",
|
||||||
|
ISBN: 978-1466468863, Jonathan Valvano, copyright (c) 2016
|
||||||
|
|
||||||
|
"Embedded Systems: Introduction to the MSP432 Microcontroller",
|
||||||
|
ISBN: 978-1512185676, Jonathan Valvano, copyright (c) 2016
|
||||||
|
|
||||||
|
"Embedded Systems: Real-Time Interfacing to the MSP432 Microcontroller",
|
||||||
|
ISBN: 978-1514676585, Jonathan Valvano, copyright (c) 2016
|
||||||
|
|
||||||
|
Copyright 2016 by Jonathan W. Valvano, valvano@mail.utexas.edu
|
||||||
|
You may use, edit, run or distribute this file
|
||||||
|
as long as the above copyright notice remains
|
||||||
|
THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED
|
||||||
|
OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
|
||||||
|
VALVANO SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL,
|
||||||
|
OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
|
||||||
|
For more information about my classes, my research, and my books, see
|
||||||
|
http://users.ece.utexas.edu/~valvano/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define EDISK_ADDR_MIN 0x00020000 // Flash Bank1 minimum address
|
||||||
|
#define EDISK_ADDR_MAX 0x0003FFFF // Flash Bank1 maximum address
|
||||||
|
|
||||||
|
enum DRESULT{
|
||||||
|
RES_OK = 0, // Successful
|
||||||
|
RES_ERROR = 1, // R/W Error
|
||||||
|
RES_WRPRT = 2, // Write Protected
|
||||||
|
RES_NOTRDY = 3, // Not Ready
|
||||||
|
RES_PARERR = 4 // Invalid Parameter
|
||||||
|
};
|
||||||
|
|
||||||
|
//*************** eDisk_Init ***********
|
||||||
|
// Initialize the interface between microcontroller and disk
|
||||||
|
// Inputs: drive number (only drive 0 is supported)
|
||||||
|
// Outputs: status
|
||||||
|
// RES_OK 0: Successful
|
||||||
|
// RES_ERROR 1: Drive not initialized
|
||||||
|
enum DRESULT eDisk_Init(uint32_t drive);
|
||||||
|
|
||||||
|
//*************** eDisk_ReadSector ***********
|
||||||
|
// Read 1 sector of 512 bytes from the disk, data goes to RAM
|
||||||
|
// Inputs: pointer to an empty RAM buffer
|
||||||
|
// sector number of disk to read: 0,1,2,...255
|
||||||
|
// Outputs: result
|
||||||
|
// RES_OK 0: Successful
|
||||||
|
// RES_ERROR 1: R/W Error
|
||||||
|
// RES_WRPRT 2: Write Protected
|
||||||
|
// RES_NOTRDY 3: Not Ready
|
||||||
|
// RES_PARERR 4: Invalid Parameter
|
||||||
|
enum DRESULT eDisk_ReadSector(
|
||||||
|
uint8_t *buff, // Pointer to a RAM buffer into which to store
|
||||||
|
uint8_t sector); // sector number to read from
|
||||||
|
|
||||||
|
//*************** eDisk_WriteSector ***********
|
||||||
|
// Write 1 sector of 512 bytes of data to the disk, data comes from RAM
|
||||||
|
// Inputs: pointer to RAM buffer with information
|
||||||
|
// sector number of disk to write: 0,1,2,...,255
|
||||||
|
// Outputs: result
|
||||||
|
// RES_OK 0: Successful
|
||||||
|
// RES_ERROR 1: R/W Error
|
||||||
|
// RES_WRPRT 2: Write Protected
|
||||||
|
// RES_NOTRDY 3: Not Ready
|
||||||
|
// RES_PARERR 4: Invalid Parameter
|
||||||
|
enum DRESULT eDisk_WriteSector(
|
||||||
|
const uint8_t *buff, // Pointer to the data to be written
|
||||||
|
uint8_t sector); // sector number
|
||||||
|
|
||||||
|
//*************** eDisk_Format ***********
|
||||||
|
// Erase all files and all data by resetting the flash to all 1's
|
||||||
|
// Inputs: none
|
||||||
|
// Outputs: result
|
||||||
|
// RES_OK 0: Successful
|
||||||
|
// RES_ERROR 1: R/W Error
|
||||||
|
// RES_WRPRT 2: Write Protected
|
||||||
|
// RES_NOTRDY 3: Not Ready
|
||||||
|
// RES_PARERR 4: Invalid Parameter
|
||||||
|
enum DRESULT eDisk_Format(void);
|
|
@ -0,0 +1,141 @@
|
||||||
|
// eFile.c
|
||||||
|
// Runs on either TM4C123 or MSP432
|
||||||
|
// High-level implementation of the file system implementation.
|
||||||
|
// Daniel and Jonathan Valvano
|
||||||
|
// August 29, 2016
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "eDisk.h"
|
||||||
|
|
||||||
|
uint8_t Buff[512]; // temporary buffer used during file I/O
|
||||||
|
uint8_t Directory[256], FAT[256];
|
||||||
|
int32_t bDirectoryLoaded =0; // 0 means disk on ROM is complete, 1 means RAM version active
|
||||||
|
|
||||||
|
// Return the larger of two integers.
|
||||||
|
int16_t max(int16_t a, int16_t b){
|
||||||
|
if(a > b){
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
//*****MountDirectory******
|
||||||
|
// if directory and FAT are not loaded in RAM,
|
||||||
|
// bring it into RAM from disk
|
||||||
|
void MountDirectory(void){
|
||||||
|
// if bDirectoryLoaded is 0,
|
||||||
|
// read disk sector 255 and populate Directory and FAT
|
||||||
|
// set bDirectoryLoaded=1
|
||||||
|
// if bDirectoryLoaded is 1, simply return
|
||||||
|
// **write this function**
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the index of the last sector in the file
|
||||||
|
// associated with a given starting sector.
|
||||||
|
// Note: This function will loop forever without returning
|
||||||
|
// if the file has no end (i.e. the FAT is corrupted).
|
||||||
|
uint8_t lastsector(uint8_t start){
|
||||||
|
// **write this function**
|
||||||
|
|
||||||
|
|
||||||
|
return 0; // replace this line
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the index of the first free sector.
|
||||||
|
// Note: This function will loop forever without returning
|
||||||
|
// if a file has no end or if (Directory[255] != 255)
|
||||||
|
// (i.e. the FAT is corrupted).
|
||||||
|
uint8_t findfreesector(void){
|
||||||
|
// **write this function**
|
||||||
|
|
||||||
|
return 0; // replace this line
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append a sector index 'n' at the end of file 'num'.
|
||||||
|
// This helper function is part of OS_File_Append(), which
|
||||||
|
// should have already verified that there is free space,
|
||||||
|
// so it always returns 0 (successful).
|
||||||
|
// Note: This function will loop forever without returning
|
||||||
|
// if the file has no end (i.e. the FAT is corrupted).
|
||||||
|
uint8_t appendfat(uint8_t num, uint8_t n){
|
||||||
|
// **write this function**
|
||||||
|
|
||||||
|
|
||||||
|
return 0; // replace this line
|
||||||
|
}
|
||||||
|
|
||||||
|
//********OS_File_New*************
|
||||||
|
// Returns a file number of a new file for writing
|
||||||
|
// Inputs: none
|
||||||
|
// Outputs: number of a new file
|
||||||
|
// Errors: return 255 on failure or disk full
|
||||||
|
uint8_t OS_File_New(void){
|
||||||
|
// **write this function**
|
||||||
|
|
||||||
|
|
||||||
|
return 255;
|
||||||
|
}
|
||||||
|
|
||||||
|
//********OS_File_Size*************
|
||||||
|
// Check the size of this file
|
||||||
|
// Inputs: num, 8-bit file number, 0 to 254
|
||||||
|
// Outputs: 0 if empty, otherwise the number of sectors
|
||||||
|
// Errors: none
|
||||||
|
uint8_t OS_File_Size(uint8_t num){
|
||||||
|
// **write this function**
|
||||||
|
|
||||||
|
|
||||||
|
return 0; // replace this line
|
||||||
|
}
|
||||||
|
|
||||||
|
//********OS_File_Append*************
|
||||||
|
// Save 512 bytes into the file
|
||||||
|
// Inputs: num, 8-bit file number, 0 to 254
|
||||||
|
// buf, pointer to 512 bytes of data
|
||||||
|
// Outputs: 0 if successful
|
||||||
|
// Errors: 255 on failure or disk full
|
||||||
|
uint8_t OS_File_Append(uint8_t num, uint8_t buf[512]){
|
||||||
|
// **write this function**
|
||||||
|
|
||||||
|
return 0; // replace this line
|
||||||
|
}
|
||||||
|
|
||||||
|
//********OS_File_Read*************
|
||||||
|
// Read 512 bytes from the file
|
||||||
|
// Inputs: num, 8-bit file number, 0 to 254
|
||||||
|
// location, logical address, 0 to 254
|
||||||
|
// buf, pointer to 512 empty spaces in RAM
|
||||||
|
// Outputs: 0 if successful
|
||||||
|
// Errors: 255 on failure because no data
|
||||||
|
uint8_t OS_File_Read(uint8_t num, uint8_t location,
|
||||||
|
uint8_t buf[512]){
|
||||||
|
// **write this function**
|
||||||
|
|
||||||
|
return 0; // replace this line
|
||||||
|
}
|
||||||
|
|
||||||
|
//********OS_File_Flush*************
|
||||||
|
// Update working buffers onto the disk
|
||||||
|
// Power can be removed after calling flush
|
||||||
|
// Inputs: none
|
||||||
|
// Outputs: 0 if success
|
||||||
|
// Errors: 255 on disk write failure
|
||||||
|
uint8_t OS_File_Flush(void){
|
||||||
|
// **write this function**
|
||||||
|
|
||||||
|
return 0; // replace this line
|
||||||
|
}
|
||||||
|
|
||||||
|
//********OS_File_Format*************
|
||||||
|
// Erase all files and all data
|
||||||
|
// Inputs: none
|
||||||
|
// Outputs: 0 if success
|
||||||
|
// Errors: 255 on disk write failure
|
||||||
|
uint8_t OS_File_Format(void){
|
||||||
|
// call eDiskFormat
|
||||||
|
// clear bDirectoryLoaded to zero
|
||||||
|
// **write this function**
|
||||||
|
|
||||||
|
return 0; // replace this line
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
// eFile.h
|
||||||
|
// Runs on either TM4C123 or MSP432
|
||||||
|
// High-level implementation of the file system implementation.
|
||||||
|
// Daniel and Jonathan Valvano
|
||||||
|
// August 29, 2016
|
||||||
|
|
||||||
|
|
||||||
|
//********OS_File_New*************
|
||||||
|
// Returns a file number of a new file for writing
|
||||||
|
// Inputs: none
|
||||||
|
// Outputs: number of a new file
|
||||||
|
// Errors: return 255 on failure or disk full
|
||||||
|
uint8_t OS_File_New(void);
|
||||||
|
|
||||||
|
//********OS_File_Size*************
|
||||||
|
// Check the size of this file
|
||||||
|
// Inputs: num, 8-bit file number, 0 to 254
|
||||||
|
// Outputs: 0 if empty, otherwise the number of sectors
|
||||||
|
// Errors: none
|
||||||
|
uint8_t OS_File_Size(uint8_t num);
|
||||||
|
|
||||||
|
//********OS_File_Append*************
|
||||||
|
// Save 512 bytes into the file
|
||||||
|
// Inputs: num, 8-bit file number, 0 to 254
|
||||||
|
// buf, pointer to 512 bytes of data
|
||||||
|
// Outputs: 0 if successful
|
||||||
|
// Errors: 255 on failure or disk full
|
||||||
|
uint8_t OS_File_Append(uint8_t num, uint8_t buf[512]);
|
||||||
|
|
||||||
|
//********OS_File_Read*************
|
||||||
|
// Read 512 bytes from the file
|
||||||
|
// Inputs: num, 8-bit file number, 0 to 254
|
||||||
|
// location, logical address, 0 to 254
|
||||||
|
// buf, pointer to 512 empty spaces in RAM
|
||||||
|
// Outputs: 0 if successful
|
||||||
|
// Errors: 255 on failure because no data
|
||||||
|
uint8_t OS_File_Read(uint8_t num, uint8_t location,
|
||||||
|
uint8_t buf[512]);
|
||||||
|
|
||||||
|
//********OS_File_Flush*************
|
||||||
|
// Update working buffers onto the disk
|
||||||
|
// Power can be removed after calling flush
|
||||||
|
// Inputs: none
|
||||||
|
// Outputs: 0 if success
|
||||||
|
// Errors: 255 on disk write failure
|
||||||
|
uint8_t OS_File_Flush(void);
|
||||||
|
|
||||||
|
//********OS_File_Format*************
|
||||||
|
// Erase all files and all data
|
||||||
|
// Inputs: none
|
||||||
|
// Outputs: 0 if success
|
||||||
|
// Errors: 255 on disk write failure
|
||||||
|
uint8_t OS_File_Format(void);
|
Loading…
Reference in New Issue