My Project
My Project Documentation

Authors: Connor Lowe, Leonard Dul
Date: 9-June-2021
Brief: Lab 4 : FREERTOS Scheduling and multitasking

     Summary
This lab shows correct implementation of various FreeRTOS tasks.
The first demo includes 4 tasks, one which blinks an external led on
pin 47. The second task plays the tune from close encounters 3 times then stops.
Task3 and 4 compute and FFT of 256 random ints and computes the average
time for every 5 FFTs back on the serial link to the computer.

The second part of this lab includes implementing a driving game that is played
using a rotary encoder for movement, 2 buttons for movement, a button to reset,
a 4 digit seven segment display to show the time driving and keep track of the best
time, a speaker to play the music ,and a 8x8 red led matrix to play the game on.
The rotary encoder is attatched to pins 50 and 52, and the two buttons for movement
are connected to pins 51 and 53. The reset button is attatched to pin 12, the speaker
is attatched to pin 6. The 4 digit seven segment display is attatched to pins 22-32,
and the 8x8 led matrix is attatched to pins 42, 44, and 46.

Throughout the lab and after each task was implemented we tested the output
to the led pin on a handheld oscilliscope to ensure the signal was 3.33Hz and about 1.5V
or have an on time of 100ms and an off time of 200ms. This allowed us to have confidence
in our tasks and ensured we kept correct timing and FreeRTOS specs.

     External Led / RT1(void *pvParameters)
After we finished wiring the external led we identified the correct port (PORTL),
data direction register (DDDRL), and bit to manipulate (2) in order to flash the led.
We then utilized a method of writing to the register at the correct
time in order to flash the led. The code for RT1 can be found on lines 75-96 of lab4.ino
With the appriopriate defines found in lab4_define.h lines 13-21.

     16-Bit Timer/Counter and sound / RT2(void *pvParameters)
     playMusic(void *pvParameters) / playMusicEnd(void *pvParameters)
To begin this portion of the lab we first needed to identify all
the components we would need in our code to use the 16-Bit Timer/Counter.
The first step in this process was to choose our timer and then enable it.
Using PRTIM4 we set the bit to 0 to enable it as per datasheet instructions.
Following this we identified that our 16-bit Timer/Counter used two 8 bit control
registers called TCCR4A and TCCR4B. By manipulating the specific bits in our
register (WGM40/41/42/43) we could select the desired waveform, in this case a
SquareWave output with a 50% duty cycle. Using bits 2:0 on the TCCR4B we also
defined the clock select as clkI/O/1 (no prescaling). We also set COM4A0 to control
the output pin OCR4A. Using the datasheet we ascertained that we needed to use Pin 6
and set its respective port (PORT H) to have its register (DDRH) output data. With the
16-Bit Timer/Counter established the remaining steps involved creating a function that
would loop through our defined melody for the different mario tunes.
Our functions playMusic() and playMusicEnd() loop
through their respective melodies and tempo arrays to find the correct duration for each note.
Once this duration is found the function will set the timer compare for the appropriate
frequency to be played and then delay for the note duration. When the function starts again
it will play the next note in the sequenece. This is done only once for the music when a crash
happens, but the notes loop continuously when driving so that music is always playing.
These functions are found on line 5559-583 of lab4.ino with the appropriate defines found
in lab4_define.h lines 63-148 and 252-434. For the RTOS task of playing the close encouters tune,
that can be found on lines 98-130 and operates the same way as the previous tasks, but the close
encounters tune will halt or stop itself after it plays 3 times.

     RT3(void *pvParameters) / RT4(void *pvParameters)
RT3 and RT4 compute FFTs and report the average time every 5 takes back on the serial link.
The code for these tasks can be found on lines 132-194 of lab4.ino with the appropriate defines
in lab4_define.h lines 230-240. The functions are implemented using two queues. One queues send the
pointer to the data to preform an FFT on to RT4 and the second queue lets RT3 know when RT4 is done.
This allowed us to use the millis() command to track the time every 5 takes.

     Rotary Encoder / readRotaryEncoder(void *pvParameters)
The implementation of a rotary encoder was new and exciting for this lab. To do this we needed
to define the appropriate variable and pin numbers on lines 23-32 of lab4_define.h. As well as write
a task readRotaryEncoder() that would scan the rotary encoders two inputs. It checks
to see if the state is equal to the other, and makes a determination if the knob was spun clockwise
or counterclockwise. This allows us to manipulate a global int to keep track of the car position
very accurately.

     Buttons / readButtons(void *pvParameters) / restart(void *pvParameters)
3 different push buttons were used in this project. 2 buttons are used to provide an alternative input
to the rotary encoder movement, in other words two of the buttons also control the car movement.
The third button implements a soft reset for the game, that keeps track of the best score, so that the best score is always displayed when you crash. The movement for the car is found on lines 497-525
of lab4.ino with the appropriate defines on lines 439-444 of lab4_define.h. The function readButtons()
that also manipulates the car movements checks for the posedge signal of the pin and moves the car
whenever it is recieved. The restart utilizes the same logic for reading the pin but instead starts
up the suspended taks that keep the game running and reset their initial conditions. This is done
with the FreeRTOS vTaskResume(&taskHandle) function and can be found on lines 426-452 of lab4.ino with
the appropriate defines on lines 439-44 of lab4_define.h. A restart is only valid after a crash happens,
meaning the tasks must be suspended for them to be resumed again.

     4 digit 7 segment display / Task_Counter(void *pvParameters)
The implementation of the 4 digit 7 segment display in our project is taken from Blake Hannaford's
implementation given in ECE474 Spring 2021. The task utilizes an ISR to keep track of time accuratly.
The code can be found in lines 207-357 of lab4.ino with the appropriate defines found on lines 193-213
of lab4_define.h. A few key functions are used such as i2ds(int i) which converts an int into a stuct
containing 4 ints that represent the different decimal places. This makes it easy for the
segLightUp(volatile int segs[8]) function to appropriatly turn on the correct segement digits based
on the number from i2ds(int i).

     8x8 led matrix / setLeds(void *pvParameters)
Our 8x8 led matrix used the previously given spiTranfer function written by Ishaan Bhimani and can
be found on line 359-368 of lab4.ino. We wrote one new task and two functions to control the led
matrix throughout the game. This consists of a clearLeds() function that clears all leds on the matrix and
can be found on lines 380-389 of lab4s.ino. The task to set leds is found on lines 391-424 and works by
shifting the rows of the matrix from right to left, while generating new object to dodge on the right.
Objects are generated one at a time randomly on the right, and the delay is controlled by the time the
user has spent driving. The chooseDelay() function takes into account the time spent driving and will
delay the task for a shorter period of time, meaning objects will start coming at the car quicker.
If an object in the final row is ever in the same position as the car a crash happens and all tasks that
control the game are suspended. When this happends, the best score is saved and displayed on the 4 digit
seven segment display and the intro to the underworld theme plays from mario to signal a crash.
Once this happens the user has the option to reset the game.