mirror of
https://github.com/supleed2/ELEC60013-ES-CW2.git
synced 2024-12-22 21:55:50 +00:00
Merge branch 'main' into ad3919
This commit is contained in:
commit
8357b2f734
125
README.md
125
README.md
|
@ -1,78 +1,85 @@
|
||||||
# ELEC60013 Embedded Systems - Music Synthesizer Documentation
|
# ELEC60013 Embedded Systems - Music Synthesizer Documentation
|
||||||
The following document outlines the design, implementation and real-time dependecies of a music synthesizer for the 2nd coursework of the Embedded Systems module.
|
The following document outlines the design, implementation and real-time dependecies of a music synthesizer for the 2nd coursework of the Embedded Systems module.
|
||||||
|
|
||||||
## System tasks
|
## System workload
|
||||||
The sytem at hand executes several real-time tasks, including:
|
The sytem at hand executes several real-time tasks, including:
|
||||||
*Reading the key matrix
|
* Scannng the key matrix
|
||||||
*Updating the display
|
* CAN decoding task
|
||||||
*Generating sound
|
* Updating the display
|
||||||
|
* Generating sound
|
||||||
|
|
||||||
### Reading the key matrix
|
### Scanning the key matrix
|
||||||
**Purpose:**
|
**Function:** ```void scanKeysTask(void *pvParameters))```
|
||||||
*Decode the key matrix, obtaining the states of the keys, knobs and joysticks
|
|
||||||
*Obtain the currently selected note from the decoded key matrix
|
|
||||||
*Select the appopriate step size for the currently selected note
|
|
||||||
*Transmit the currently selected note, along side its state (pressed or released) using CAN
|
|
||||||
*Obtain any changes in the knobs from the decoded key matrix, corresponding to volume, octave or waveform
|
|
||||||
|
|
||||||
**Function:** code(void scanKeysTask(void *pvParameters))
|
**Purpose:**
|
||||||
**Implementation:** Thread, executing every 50ms
|
* Decode the key matrix, obtaining the states of the keys, knobs and joysticks
|
||||||
**Minimum initiation time:** TO BE COMPLETED.
|
* Obtain the currently selected note from the decoded key matrix
|
||||||
**Maximum execution time:** TO BE COMPLETED.
|
* Select the appopriate step size for the currently selected note
|
||||||
**Priority:** Highest (1), as playing the appropriate sound is more important than updating the display.
|
* Transmit the currently selected note, along side its state (pressed or released) and octave using CAN
|
||||||
|
* Obtain any changes in the knobs from the decoded key matrix, corresponding to volume, octave or waveform
|
||||||
|
|
||||||
### Updating the display
|
**Implementation:** Thread
|
||||||
**Purpose:**
|
**Minimum initiation time:** 50ms.
|
||||||
*Display the currently selected note (string)
|
**Maximum execution time:** TO BE COMPLETED.
|
||||||
*Display the current volume (int)
|
**Priority:** Highest, as obtaining the note, volume and octave is required for playing the sound, transmitting over CAN and displaying on the screen. All other tasks depend on the results obtained from scanning the key matrix.
|
||||||
*Display the current octave (int)
|
|
||||||
*Display the current waveform (XMB icons)
|
|
||||||
|
|
||||||
**Function:** code(displayUpdateTask(void *pvParameters)
|
### Decode task
|
||||||
**Implementation:** Thread, executing every 100ms. While a refresh rate of 10Hz does not sound impressive; the display is largely static. Therefore, 100ms was perfectly accetable, without any noticeable delays.
|
**Function:** ```void decodeTask(void *pvParameters))```
|
||||||
**Minimum initiation time:** TO BE COMPLETED.
|
|
||||||
**Maximum execution time:** TO BE COMPLETED.
|
|
||||||
**Priority:** Lowest (2).
|
|
||||||
|
|
||||||
### Generating the sound
|
**Purpose:**
|
||||||
**Purpose:**
|
* Receive the incoming CAN message
|
||||||
*Adds the sample rate to the accumulated value, corresponding to the desired frequency
|
* Decide whether the key was pressed, released or the message originated from the main synthesizer
|
||||||
*Sets the output voltage, by using the accumlated value and the desired volume
|
* Update the array of currently active notes
|
||||||
*Writes to analogue output, generating the desired sound
|
* Set the current step size, with respect to the currently active note.
|
||||||
|
|
||||||
**Function:** code(sampleISR())
|
**Implementation:** Thread
|
||||||
**Implementation:** Interrupt executing with a frequency of 44.1kHz
|
**Minimum initiation time:** 70ms, assuming an average speed of 14 notes per second for professional pianist, as explained in the following Journal article - https://www.thejournal.ie/worlds-fastest-pianist-1780480-Nov2014/. This thread is an example for which the initiation time is not set internally, which was the case for ```void scanKeysTask(void *pvParameters))```. Instead, this task is a thread, whose initiation time depends on the purpose of the system - in this case, the speed of the pianist.
|
||||||
**Minimum initiation time:** TO BE COMPLETED.
|
**Maximum execution time:** TO BE COMPLETED.
|
||||||
**Maximum execution time:** TO BE COMPLETED.
|
**Priority:** Medium, due to a lower initiation time, compared to scanning the key matrix. Furthermore, in order to receive CAN messages, they had to be transmitted first - which is handled in ```scanKeyTask```.
|
||||||
|
|
||||||
### CAN
|
### Updating the display
|
||||||
**Purpose:**
|
**Function:** code(displayUpdateTask(void *pvParameters)
|
||||||
* TO BE ADDED
|
|
||||||
|
|
||||||
**Function:**
|
**Purpose:**
|
||||||
**Implementation:**
|
* Display the currently selected note (string)
|
||||||
**Minimum initiation time:**
|
* Display the current volume (int) or an animated icon of the sound (XMB icon)
|
||||||
**Maximum execution time:**
|
* Display the current octave (int)
|
||||||
**Priority:**
|
* Display the current waveform (XMB icons), including sawtooth, triangle, sine and rectangle.
|
||||||
|
|
||||||
## Critical instant analysis of the rate monotonic scheduler
|
**Implementation:** Thread, executing every 100ms.
|
||||||
TO BE ADDED - After system is completed.
|
**Minimum initiation time:** 100ms. While a refresh rate of 10Hz sounds insufficient (compared to modern monitors); the display is largely static. Therefore, 100ms is a perfectly accetable design choice, without any noticeable delays.
|
||||||
|
**Maximum execution time:** TO BE COMPLETED.
|
||||||
|
**Priority:** Lowest, there is no point in updating the display if the current note, volume or octave have not been update - all of which take placee in the scanning key matrix task.
|
||||||
|
|
||||||
## CPU Resource Usage
|
### Generating the sound
|
||||||
TO BE ADDED - After system is completed; see this link: https://edstem.org/us/courses/19499/discussion/1300057
|
**Purpose:**
|
||||||
|
* Adds the sample rate to the accumulated value, corresponding to the desired frequency
|
||||||
|
* Sets the output voltage, by using the accumlated value and the desired volume
|
||||||
|
* Writes to analogue output, generating the desired sound
|
||||||
|
|
||||||
## Shared data structures
|
**Function:** ```sampleISR()```
|
||||||
Shared data structures:
|
**Implementation:** Interrupt, executing with a frequency of 44.1kHz. An interrupt is chosen as responding quickly is needed for playing sound. Otherwise, delays between the key press and the sound would exist.
|
||||||
*code(currentStepSize), safe access guaranteed using code(std::atomic<uint32_t>)
|
**Minimum initiation time:** 22.7ms.
|
||||||
*code(keyArray), each element within the array is of type code(std::atomic<uint8_t>)
|
**Maximum execution time:** TO BE COMPLETED.
|
||||||
*msgInQ, handled by FreeRTOS
|
|
||||||
*code(RX_Message), handled by code(std::atomic_flag)
|
|
||||||
|
|
||||||
It was desiced to use C++ code(std::atomic), as it is easier to use and implement, while providing the same functionality as a mutex. According to the documentation: *"Each instantiation and full specialization of the std::atomic template defines an atomic type. If one thread writes to an atomic object while another thread reads from it, the behavior is well-defined (see memory model for details on data races). In addition, accesses to atomic objects may establish inter-thread synchronization and order non-atomic memory accesses as specified by std::memory_order."* (https://en.cppreference.com/w/cpp/atomic/atomic)
|
## Critical instant analysis of the rate monotonic scheduler
|
||||||
|
TO BE ADDED - After system is completed.
|
||||||
|
|
||||||
TODO - Expand on the memory model for std:: atomic.
|
## CPU Resource Usage
|
||||||
TODO - Explain how FreeRTOS handles msgInQ.
|
TO BE ADDED - After system is completed; see this link: https://edstem.org/us/courses/19499/discussion/1300057
|
||||||
TODO - Once CAN is completed, expand on the protection of RX_Message
|
|
||||||
|
## Shared data structures
|
||||||
|
Shared data structures:
|
||||||
|
* code(currentStepSize), safe access guaranteed using code(std::atomic<uint32_t>)
|
||||||
|
* code(keyArray), each element within the array is of type code(std::atomic<uint8_t>)
|
||||||
|
* msgInQ, handled by FreeRTOS
|
||||||
|
* code(RX_Message), handled by code(std::atomic_flag)
|
||||||
|
|
||||||
|
It was desiced to use C++ code(std::atomic), as it is easier to use and implement, while providing the same functionality as a mutex. According to the documentation: *"Each instantiation and full specialization of the std::atomic template defines an atomic type. If one thread writes to an atomic object while another thread reads from it, the behavior is well-defined (see memory model for details on data races). In addition, accesses to atomic objects may establish inter-thread synchronization and order non-atomic memory accesses as specified by std::memory_order.*"(https://en.cppreference.com/w/cpp/atomic/atomic)
|
||||||
|
|
||||||
|
TODO - Expand on the memory model for std::atomic.
|
||||||
|
TODO - Explain how FreeRTOS handles msgInQ.
|
||||||
|
TODO - Once CAN is completed, expand on the protection of RX_Message
|
||||||
|
|
||||||
## Analysis of inter-task blocking dependencies
|
## Analysis of inter-task blocking dependencies
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue