Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
vielex
/
bes_labs_2019
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
9939810d
authored
May 07, 2019
by
vielex
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add new file
parent
a67d173c
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
462 additions
and
0 deletions
Labware/Lab4_Fitness_4C123/os.c
Labware/Lab4_Fitness_4C123/os.c
0 → 100644
View file @
9939810d
// os.c
// Runs on LM4F120/TM4C123/MSP432
// A priority/blocking real-time operating system
// Lab 4 starter file.
// Daniel Valvano
// March 25, 2016
// Hint: Copy solutions from Lab 3 into Lab 4
#include <stdint.h>
#include "os.h"
#include "CortexM.h"
#include "BSP.h"
#include "../inc/tm4c123gh6pm.h"
// function definitions in osasm.s
void
StartOS
(
void
);
void
(
*
PeriodUserTask1
)(
void
);
void
(
*
PeriodUserTask2
)(
void
);
uint32_t
period1
,
period2
=
0
;
uint32_t
periodicCounter1
,
periodicCounter2
=
0
;
#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
int32_t
*
block
;
// nonzero if blocked on this semaphore
int32_t
sleep
;
// nonzero if this thread is sleeping
int8_t
priority
;
//*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****
tcbs
[
i
].
sp
=
&
Stacks
[
i
][
STACKSIZE
-
16
];
// thread stack pointer
Stacks
[
i
][
STACKSIZE
-
1
]
=
0x01000000
;
// thumb bit
Stacks
[
i
][
STACKSIZE
-
3
]
=
0x14141414
;
// R14
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 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****
int32_t
status
;
status
=
StartCritical
();
tcbs
[
0
].
next
=
&
tcbs
[
1
];
// 0 points to 1
tcbs
[
1
].
next
=
&
tcbs
[
2
];
// 1 points to 2
tcbs
[
2
].
next
=
&
tcbs
[
3
];
// 2 points to 3
tcbs
[
3
].
next
=
&
tcbs
[
4
];
// 3 points to 4
tcbs
[
4
].
next
=
&
tcbs
[
5
];
// 4 points to 5
tcbs
[
5
].
next
=
&
tcbs
[
6
];
// 5 points to 6
tcbs
[
6
].
next
=
&
tcbs
[
7
];
// 6 points to 7
tcbs
[
7
].
next
=
&
tcbs
[
0
];
// 7 points to 0
SetInitialStack
(
0
);
Stacks
[
0
][
STACKSIZE
-
2
]
=
(
int32_t
)(
thread0
);
// PC
SetInitialStack
(
1
);
Stacks
[
1
][
STACKSIZE
-
2
]
=
(
int32_t
)(
thread1
);
// PC
SetInitialStack
(
2
);
Stacks
[
2
][
STACKSIZE
-
2
]
=
(
int32_t
)(
thread2
);
// PC
SetInitialStack
(
3
);
Stacks
[
3
][
STACKSIZE
-
2
]
=
(
int32_t
)(
thread3
);
// PC
SetInitialStack
(
4
);
Stacks
[
4
][
STACKSIZE
-
2
]
=
(
int32_t
)(
thread4
);
// PC
SetInitialStack
(
5
);
Stacks
[
5
][
STACKSIZE
-
2
]
=
(
int32_t
)(
thread5
);
// PC
SetInitialStack
(
6
);
Stacks
[
6
][
STACKSIZE
-
2
]
=
(
int32_t
)(
thread6
);
// PC
SetInitialStack
(
7
);
Stacks
[
7
][
STACKSIZE
-
2
]
=
(
int32_t
)(
thread7
);
// PC
tcbs
[
0
].
block
=
0
;
tcbs
[
0
].
sleep
=
0
;
//No thread blocked or slepping
tcbs
[
1
].
block
=
0
;
tcbs
[
1
].
sleep
=
0
;
tcbs
[
2
].
block
=
0
;
tcbs
[
2
].
sleep
=
0
;
tcbs
[
3
].
block
=
0
;
tcbs
[
3
].
sleep
=
0
;
tcbs
[
4
].
block
=
0
;
tcbs
[
4
].
sleep
=
0
;
tcbs
[
5
].
block
=
0
;
tcbs
[
5
].
sleep
=
0
;
tcbs
[
6
].
block
=
0
;
tcbs
[
6
].
sleep
=
0
;
tcbs
[
7
].
block
=
0
;
tcbs
[
7
].
sleep
=
0
;
tcbs
[
0
].
priority
=
p0
;
// Setting priority
tcbs
[
1
].
priority
=
p1
;
tcbs
[
2
].
priority
=
p2
;
tcbs
[
3
].
priority
=
p3
;
tcbs
[
4
].
priority
=
p4
;
tcbs
[
5
].
priority
=
p5
;
tcbs
[
6
].
priority
=
p6
;
tcbs
[
7
].
priority
=
p7
;
RunPt
=
&
tcbs
[
0
];
// thread 0 will run first
EndCritical
(
status
);
return
1
;
// successful
}
void
static
runperiodicevents
(
void
){
// ****IMPLEMENT THIS****
// **DECREMENT SLEEP COUNTERS
// In Lab 4, handle periodic events in RealTimeEvents
// static int32_t periodicCounter1, periodicCounter2;
for
(
int
i
=
0
;
i
<
NUMTHREADS
;
i
++
)
{
if
(
tcbs
[
i
].
sleep
)
tcbs
[
i
].
sleep
--
;
}
/*if(periodicCounter1 == 0) {
PeriodUserTask1();
periodicCounter1 = period1;
}
if(periodicCounter2 == 0) {
PeriodUserTask2();
periodicCounter2 = period2;
}
periodicCounter1--;
periodicCounter2--;*/
}
//******** 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
BSP_PeriodicTask_Init
(
&
runperiodicevents
,
1000
,
1
);
BSP_PeriodicTask_Restart
();
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
uint32_t
max
=
255
;
// max
tcbType
*
pt
;
tcbType
*
bestPt
;
pt
=
RunPt
;
// search for highest thread not blocked or sleeping
do
{
pt
=
pt
->
next
;
// skips at least one
if
((
pt
->
priority
<
max
)
&&
(
pt
->
sleep
==
0
)
&&
(
pt
->
block
==
0
)){
bestPt
=
pt
;
max
=
pt
->
priority
;
}
}
while
(
RunPt
!=
pt
);
// look at all possible threads
RunPt
=
bestPt
;
}
//******** 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
RunPt
->
sleep
=
sleepTime
;
OS_Suspend
();
}
// ******** 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
*
semaPt
=
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
){
// ****IMPLEMENT THIS****
// Same as Lab 3
DisableInterrupts
();
(
*
semaPt
)
=
(
*
semaPt
)
-
1
;
if
((
*
semaPt
)
<
0
){
RunPt
->
block
=
semaPt
;
EnableInterrupts
();
OS_Suspend
();
}
EnableInterrupts
();
}
// ******** 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
int
flag
=
0
;
tcbType
*
pt
;
DisableInterrupts
();
(
*
semaPt
)
=
(
*
semaPt
)
+
1
;
if
((
*
semaPt
)
<=
0
){
flag
=
1
;
pt
=
RunPt
->
next
;
while
(
pt
->
block
!=
semaPt
){
pt
=
pt
->
next
;
}
pt
->
block
=
0
;
}
EnableInterrupts
();
if
(
flag
){
OS_Suspend
();
}
}
#define FSIZE 10 // can be any size
uint32_t
volatile
*
PutI
;
// index of where to put next
uint32_t
volatile
*
GetI
;
// index of where to get next
uint32_t
Fifo
[
FSIZE
];
int32_t
CurrentSize
;
// 0 means FIFO empty, FSIZE means full
int32_t
RoomLeft
;
// 0 means FIFO full
int32_t
FIFOmutex
;
// exclusive access to FIFO
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
PutI
=
GetI
=
&
Fifo
[
0
];
// Empty
OS_InitSemaphore
(
&
CurrentSize
,
0
);
// Current amonut of data in FIFO
OS_InitSemaphore
(
&
FIFOmutex
,
1
);
// Protecs pointers towards multiple access
LostData
=
0
;
}
// ******** 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
if
(
CurrentSize
==
FSIZE
)
{
LostData
++
;
return
-
1
;
}
*
(
PutI
)
=
data
;
PutI
++
;
if
(
PutI
==
&
Fifo
[
FSIZE
])
{
PutI
=
&
Fifo
[
0
];
// wrap
}
OS_Signal
(
&
CurrentSize
);
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
OS_Wait
(
&
CurrentSize
);
// block if empty
OS_Wait
(
&
FIFOmutex
);
data
=
*
(
GetI
);
// get data
GetI
++
;
// points to next data to get
if
(
GetI
==
&
Fifo
[
FSIZE
]){
GetI
=
&
Fifo
[
0
];
// wrap
}
OS_Signal
(
&
FIFOmutex
);
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
();
}
}
}
void
RealTimeEventB
(
void
){
OS_Signal
(
PeriodicSemaphore0
);
OS_Suspend
();
}
void
RealTimeEventC
(
void
){
OS_Signal
(
PeriodicSemaphore1
);
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_InitB
(
&
RealTimeEventB
,
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
(
&
RealTimeEventC
,
10
,
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
volatile
unsigned
long
FallingEdges
=
0
;
void
OS_EdgeTrigger_Init
(
int32_t
*
semaPt
,
uint8_t
priority
){
edgeSemaphore
=
semaPt
;
//***IMPLEMENT THIS***
SYSCTL_RCGCGPIO_R
|=
0x08
;
// 1) activate clock for Port D
FallingEdges
=
0
;
// allow time for clock to stabilize
// 2) no need to unlock PD6
GPIO_PORTD_AMSEL_R
&=
~
0x40
;
// 3) disable analog on PD6
GPIO_PORTD_PCTL_R
&=
~
0x000F0000
;
// 4) configure PD6 as GPIO
GPIO_PORTD_DIR_R
=
0x00
;
// 5) make PD6 input
GPIO_PORTD_AFSEL_R
&=
~
0x40
;
// 6) disable alt funct on PD6
GPIO_PORTD_PDR_R
|=
0x40
;
// disable pull-up on PD6
GPIO_PORTD_DEN_R
|=
0x40
;
// 7) enable digital I/O on PD6
GPIO_PORTD_IS_R
&=
~
0x40
;
// (d) PD6 is edge-sensitive
GPIO_PORTD_IBE_R
&=
~
0x40
;
// PD6 is not both edges
GPIO_PORTD_IEV_R
&=
~
0x40
;
// PD6 is falling edge event
GPIO_PORTD_ICR_R
=
0x40
;
// (e) clear PD6 flag
GPIO_PORTD_IM_R
|=
0x40
;
// (f) arm interrupt on PD6
NVIC_PRI0_R
=
0x00FFFFFF
|
(
priority
<<
29
)
;
// priority on Port D edge trigger is NVIC_PRI0_R 31 ? 29
NVIC_EN0_R
=
0x00000008
;
// 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***
//GPIO_PORTD_ICR_R = 0x40; // clear flag6
GPIO_PORTD_IM_R
|=
0x40
;
// rearm interrupt 3 in NVIC
}
void
GPIOPortD_Handler
(
void
){
//***IMPLEMENT THIS***
GPIO_PORTD_ICR_R
=
0x08
;
// step 1 acknowledge by clearing flag
FallingEdges
=
FallingEdges
+
1
;
OS_Signal
(
edgeSemaphore
);
// step 2 signal semaphore (no need to run scheduler)
GPIO_PORTD_ICR_R
=
0x40
;
// clear flag6
GPIO_PORTD_IM_R
&=
~
0x40
;
// step 3 disarm interrupt to prevent bouncing to create multiple signals
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment