From b275f4d83e3238abcec109f1e35c1f85627b3724 Mon Sep 17 00:00:00 2001 From: Ondrej Hladuvka Date: Wed, 21 May 2025 21:17:55 +0300 Subject: [PATCH] rtos labs --- Lab1_4C123/Lab1.c | 544 ++++++++++++++++ Lab1_4C123/Texas.h | 118 ++++ Lab2_4C123/Lab2.c | 544 ++++++++++++++++ Lab2_4C123/Texas.h | 118 ++++ Lab2_4C123/os.c | 237 +++++++ Lab2_4C123/os.h | 142 ++++ Lab2_4C123/osasm.s | 49 ++ Lab3_4C123/Lab3.c | 1263 ++++++++++++++++++++++++++++++++++++ Lab3_4C123/Texas.h | 125 ++++ Lab3_4C123/os.c | 215 ++++++ Lab3_4C123/os.h | 132 ++++ Lab3_4C123/osasm.s | 34 + Lab4_Fitness_4C123/Lab4.c | 783 ++++++++++++++++++++++ Lab4_Fitness_4C123/Texas.h | 69 ++ Lab4_Fitness_4C123/os.c | 298 +++++++++ Lab4_Fitness_4C123/os.h | 159 +++++ Lab4_Fitness_4C123/osasm.s | 33 + Lab5_4C123/FlashProgram.c | 208 ++++++ Lab5_4C123/FlashProgram.h | 78 +++ Lab5_4C123/Lab5.c | 266 ++++++++ Lab5_4C123/Texas.h | 125 ++++ Lab5_4C123/eDisk.c | 118 ++++ Lab5_4C123/eDisk.h | 91 +++ Lab5_4C123/eFile.c | 141 ++++ Lab5_4C123/eFile.h | 53 ++ 25 files changed, 5943 insertions(+) create mode 100644 Lab1_4C123/Lab1.c create mode 100644 Lab1_4C123/Texas.h create mode 100644 Lab2_4C123/Lab2.c create mode 100644 Lab2_4C123/Texas.h create mode 100644 Lab2_4C123/os.c create mode 100644 Lab2_4C123/os.h create mode 100644 Lab2_4C123/osasm.s create mode 100644 Lab3_4C123/Lab3.c create mode 100644 Lab3_4C123/Texas.h create mode 100644 Lab3_4C123/os.c create mode 100644 Lab3_4C123/os.h create mode 100644 Lab3_4C123/osasm.s create mode 100644 Lab4_Fitness_4C123/Lab4.c create mode 100644 Lab4_Fitness_4C123/Texas.h create mode 100644 Lab4_Fitness_4C123/os.c create mode 100644 Lab4_Fitness_4C123/os.h create mode 100644 Lab4_Fitness_4C123/osasm.s create mode 100644 Lab5_4C123/FlashProgram.c create mode 100644 Lab5_4C123/FlashProgram.h create mode 100644 Lab5_4C123/Lab5.c create mode 100644 Lab5_4C123/Texas.h create mode 100644 Lab5_4C123/eDisk.c create mode 100644 Lab5_4C123/eDisk.h create mode 100644 Lab5_4C123/eFile.c create mode 100644 Lab5_4C123/eFile.h diff --git a/Lab1_4C123/Lab1.c b/Lab1_4C123/Lab1.c new file mode 100644 index 0000000..762e012 --- /dev/null +++ b/Lab1_4C123/Lab1.c @@ -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 +#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 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; +} + + + + diff --git a/Lab1_4C123/Texas.h b/Lab1_4C123/Texas.h new file mode 100644 index 0000000..1b5cd7b --- /dev/null +++ b/Lab1_4C123/Texas.h @@ -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); diff --git a/Lab2_4C123/Lab2.c b/Lab2_4C123/Lab2.c new file mode 100644 index 0000000..5d67614 --- /dev/null +++ b/Lab2_4C123/Lab2.c @@ -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 +#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 +#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; +} diff --git a/Lab2_4C123/os.h b/Lab2_4C123/os.h new file mode 100644 index 0000000..d8d9a02 --- /dev/null +++ b/Lab2_4C123/os.h @@ -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 diff --git a/Lab2_4C123/osasm.s b/Lab2_4C123/osasm.s new file mode 100644 index 0000000..7b2b25a --- /dev/null +++ b/Lab2_4C123/osasm.s @@ -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 diff --git a/Lab3_4C123/Lab3.c b/Lab3_4C123/Lab3.c new file mode 100644 index 0000000..b612bc1 --- /dev/null +++ b/Lab3_4C123/Lab3.c @@ -0,0 +1,1263 @@ +// Lab3.c +// Runs on either MSP432 or TM4C123 +// Starter project to Lab 3. 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 +// March 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 + + "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 +#include "../inc/BSP.h" +#include "../inc/CortexM.h" +#include "os.h" +#include "../inc/Profile.h" +#include "Texas.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_WHITE //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 ---------------- +// 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(); + SoundRMS = 0; +} +// *********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 + 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 +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_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; + LostTask1Data = 0; +} +// *********Task1********* +// collects data from accelerometer +// 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; + 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 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); + } 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, 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 and LED +// Inputs: none +// Outputs: none +void Task3(void){ + static uint8_t prev1 = 0, prev2 = 0; + uint8_t current; + 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 = 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 == Temperature){ + PlotState = Microphone; + } else if(PlotState == Light){ + PlotState = Temperature; + } + 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); + } + OS_Sleep(10); // 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; + 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 + + 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 a real logic analyzer to know Task5 started + soundSum = 0; + for(int i=0; i +#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; +} + + + diff --git a/Lab3_4C123/os.h b/Lab3_4C123/os.h new file mode 100644 index 0000000..28049ae --- /dev/null +++ b/Lab3_4C123/os.h @@ -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 diff --git a/Lab3_4C123/osasm.s b/Lab3_4C123/osasm.s new file mode 100644 index 0000000..b052c9c --- /dev/null +++ b/Lab3_4C123/osasm.s @@ -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 diff --git a/Lab4_Fitness_4C123/Lab4.c b/Lab4_Fitness_4C123/Lab4.c new file mode 100644 index 0000000..6a2d5e2 --- /dev/null +++ b/Lab4_Fitness_4C123/Lab4.c @@ -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 +#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 +#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 +} + + diff --git a/Lab4_Fitness_4C123/os.h b/Lab4_Fitness_4C123/os.h new file mode 100644 index 0000000..032045e --- /dev/null +++ b/Lab4_Fitness_4C123/os.h @@ -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 diff --git a/Lab4_Fitness_4C123/osasm.s b/Lab4_Fitness_4C123/osasm.s new file mode 100644 index 0000000..176a3cc --- /dev/null +++ b/Lab4_Fitness_4C123/osasm.s @@ -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 diff --git a/Lab5_4C123/FlashProgram.c b/Lab5_4C123/FlashProgram.c new file mode 100644 index 0000000..b7421de --- /dev/null +++ b/Lab5_4C123/FlashProgram.c @@ -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 +#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; +} diff --git a/Lab5_4C123/FlashProgram.h b/Lab5_4C123/FlashProgram.h new file mode 100644 index 0000000..64e3e60 --- /dev/null +++ b/Lab5_4C123/FlashProgram.h @@ -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); diff --git a/Lab5_4C123/Lab5.c b/Lab5_4C123/Lab5.c new file mode 100644 index 0000000..c15ea67 --- /dev/null +++ b/Lab5_4C123/Lab5.c @@ -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 +#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)){}; + } +} diff --git a/Lab5_4C123/Texas.h b/Lab5_4C123/Texas.h new file mode 100644 index 0000000..9108298 --- /dev/null +++ b/Lab5_4C123/Texas.h @@ -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); diff --git a/Lab5_4C123/eDisk.c b/Lab5_4C123/eDisk.c new file mode 100644 index 0000000..348ec13 --- /dev/null +++ b/Lab5_4C123/eDisk.c @@ -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 +#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; +} diff --git a/Lab5_4C123/eDisk.h b/Lab5_4C123/eDisk.h new file mode 100644 index 0000000..e8ef00a --- /dev/null +++ b/Lab5_4C123/eDisk.h @@ -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); diff --git a/Lab5_4C123/eFile.c b/Lab5_4C123/eFile.c new file mode 100644 index 0000000..af65196 --- /dev/null +++ b/Lab5_4C123/eFile.c @@ -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 +#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 +} diff --git a/Lab5_4C123/eFile.h b/Lab5_4C123/eFile.h new file mode 100644 index 0000000..4b32744 --- /dev/null +++ b/Lab5_4C123/eFile.h @@ -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);