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