Starting from:

$35

COMP2300-Assignment 1 Part-1 Solved

This assignment has two parts: in Part 1, you need to generate a specific (simple) signal to be output through your discoboard’s headphone jack. In Part 2, you get to be creative and program your discoboard to make a more interesting sound. Your discoboard has a standard 3.5mm headphone jack, which means that any 3.5mm headphones will work.

 

To complete this assignment you will need to have a solid understanding of the course material provided in the week 1, week 2 and week 3 labs. If you have not completed these or do not understand the content then it is strongly recommended that you go and complete these labs before starting on the assignment.

Background
A synthesizer (or synth for short) is an electronic device which produces a musical sound. It’s called a synthesizer because while an acoustic instrument uses a resonating cavity or string to produce “natural” sound waves, the synth uses digital logic to calculate and produce a synthetic signal which is amplified electronically and turned into a soundwave through a loudspeaker.

Although computers have been used for making music since they were first invented, it was in the 70s that improvements in technology led to an explosion of digital devices like synths in popular music—check out Kraftwerk’s The Robots.

 
In this assignment, you’re going to turn your discoboard into a synthesizer. The maths and physics behind this aren’t rocket science, it’s just generating values in simple patterns and writing them to a special register one-after-the-other. The key part is that it involves controlling the execution of your program in time. This might be a fairly new idea—you might not be used to worrying about exactly how fast your program runs, and if you do care about it you only care about making it run faster, not about making sure that the instructions run at specific times.

Getting started
The initialisation sequence for the discoboard’s audio hardware (i.e. the headphone jack) is a little bit fiddly, so for this assignment we’ve provided some setup code to get you up and running (optionally, check out the lib/audio.S and lib/clock.S files if you’re curious).

Fork & clone the assignment 1 template repo and open it up in VSCode as usual. There are two things you need to know about the setup code:

The template repo contains two git branches: part-1 and part-2 (initially, they both point to the same commit). Both of these branches have all the setup code you need—the only difference between them will be the commits you make in doing your assignment. So, you should write your Part 1 code on the part-1 branch, and your Part 2 code on the part-2 branch.
Although your code still goes in main.S, the template includes a couple of functions for you to call from your code: init and BSP_AUDIO_OUT_Play_Sample.

When you bl (branch with link) to the init function your program will execute the setup code to turn on your discoboard’s headphone jack. Your code should call this function once at the start.
When you bl to the BSP_AUDIO_OUT_Play_Sample function, whatever is in the lowest (least-significant) 16 bits of r0 will be “played” through the headphone jack (treated as a signed 16-bit number as shown in the picture). Your code should call this function repeatedly to generate the audio signal. Calculating exactly what that data in r0 should be to generate the right signal is up to you!
If this is a bit confusing, head down to the FAQ section on this page—there’s a lot of answers which should help you understand. Furthermore, check out the sitewide FAQ for answers that apply more generally to all assignments.

Part 1 (50%)
In the first part of the assignment you need to write a program which produces an audible constant-amplitude square wave with a frequency of 440Hz (440 cycles per second) and a duty cycle out of the headphone jack.

All of these properties are shown in the this picture:  

Using the init function provided, the audio output is configured to use signed 16-bit values for the signal, so a value of 0x8000 represents the “bottom” of the signal range, 0x0 represents the “middle” and 0x7FFF is the “top”. The output sample rate (the rate at which these 16-bit values come out of the headphone jack as “sound”) is 48kHz. This is all the info you need to put the right sequence of values in r0 and branch to BSP_AUDIO_OUT_Play_Sample to make the music come out of the headphones.

You can see the “sample-by-sample” nature of digital audio in the picture—the square wave signal is actually just a sequence of dots—these are the values which you’ll output through your r0 register and BSP_AUDIO_OUT_Play_Sample function. Remember that the value in r0 immediately before this branch will be the one that comes out the headphone jack.

How will you know if you’re doing it right? You’ll need to plug your headphones in and listen! Your square wave should sound like a constant-pitch, slightly “buzzy” sound. Like below:

 

You can hear a normal square wave (without a 20% duty cycle, and of whatever pitch you want) at onlinetonegenerator.com.

Square waves (and similar waveforms) are quite popular in music as “lead” sounds, since they cut through the accompaniment so well—just listen to the opening square wave synth line in Van Halen’s Jump.

 
You might be asking yourself: “What is a duty cycle?”. Duty cycle refers to the percentage of the time the signal is “on” in one cycle (the “period”) of the wave. This leads to (as shown in the diagram above), a much shorter peak than the trough–as opposed to a normal square wave, when the peak and trough are of equal length (a duty cycle of 50%!).

For Part 1, marks will be awarded for:

making a sound
whether the sound has the correct frequency
whether the sound has a peak-to-peak amplitude of at least half the full 0x8000–0x7FFF dynamic range (as depicted in the picture)
how “clean” the square wave signal is (i.e. how close is it to the picture above)
how close the frequency of the wave is to 440Hz (to achieve the closest frequency, and possibility of full marks for this part, you will need to average over many periods)
whether or not it has a duty cycle of 20% (to achieve the possibility of full marks for this part, you should have a value somewhere in your code we can tweak to change the duty cycle to some other value)
code structure & readability (including comments)
If you would like to view a plot of your output, then you can follow the instructions on the resources page to use the sample plotter.

Be careful generating signals with your earphones in your ears—the discoboard can make a pretty loud signal. It’s a good idea to hit “run” on your program with your headphones out of your ears, and then carefully put them in your ears afterwards.

Part 2 (50%)
In the second part, you need to generate a different signal (i.e. not a constant-frequency square wave). You can pick any periodic signal you like as long as it is audible, but here are a few ideas, in approximate order of increasing difficulty:

a different base waveform from the square wave you made in Part 1 (e.g. sawtooth, triangle)
a simple signal with some aspect (e.g. frequency, amplitude, waveform) which changes over time
the weighted sum of multiple simpler waveforms (this is called additive synthesis)
the n-sample moving-average filter of a simple signal
FM synthesis
wavetable synthesis
Marks for Part 2 will be awarded for a design document describing what signal you’re generating and how you implemented it in ARM assembly language. You need to explain the “what”, “how” and “why” (design, implementation, and analysis) of what you have done. Although it’s ok if you don’t do something super-complex, we do take the sophistication of what you have done into account.
Using images/diagrams in this document to help explain what you’ve done is encouraged. Your design document must be in pdf format (2 pages of content + appendix + references) with the filename design-document.pdf in the top-level folder on the part-2 branch.

Submission
Process
Here’s the process for working on & submitting your assignment:

fork the assignment 1 template repository
clone1 & work on your fork of the major project repo
regularly commit & push your changes to the GitLab server
the last commits on the part-1 and part-2 branches on the GitLab server (not on your local machine!) before the submission deadline will count as your submission
Checklist
the code in my part-1 branch generates a square wave as described in Part 1
the code in my part-2 branch generates a different signal as described in Part 2 and I’ve committed my design-document.pdf to the repo as well
my statement-of-originality.yml files for both Part 1 and Part 2 include all the necessary references/acknowledgements, and everything not mentioned in there is my own work
both branches of my completed project have been pushed to the GitLab server
both branches pass all of the Gitlab CI tests (the pipeline does not fail)
FAQ
You can ask a question on the COMP2300 forum and if it’s popular enough I’ll put it up here.

Also, remember that there’s lots of helpful info on the FAQ page which applies to all assignments. You should check it (and the rest of that page) out—I think it’ll really help.

Troubleshooting
I’m totally lost, and I’m freaking out—where should I start?
Take a deep breath, it’s going to be ok. The first thing you should do is read this page carefully. Then read it again (including the FAQs). There’s lots of detail here to help you, so if you have a question then there will almost certainly be clues in this assignment page.

After you’ve done that, think through what you need your program to do to generate a sequence like you can see in the waveform picture above. It’s really just a loop—and you know how to write a loop. The loop needs to put the right bit patterns in the right registers and then branch to the provided “play sample” function. Think: what are the right bit patterns? Again, look carefully at the picture above. How can you organise your program so that it makes the right things happen in the correct sequence?

Here’s some pseudo-code to help you out:

main:
@ do any once-off initialisation stuff first

loop:
  @ 1. calculate the next value in the square signal

  @ 2. bl to BSP_AUDIO_OUT_Play_Sample with that value in r0

  @ 3. go back to the top of the loop and do it again for the *next* value

You can use as many labels as you like, there can be other loops within your “top-level” loop, but that should be the overall shape of your program.

You might also find it helpful to simplify the problem: start by just making a square wave. Once you’ve got that working, then try adding the duty cycle.

I’ve written a program, why isn’t my discoboard making a sound?
make sure you’re correctly using the provided initialisation and playback functions described above properly
you’ll only hear the signal if it changes over time, so you might be sending a sequence of zeroes (or any other constant value) to the headphone jack—that’s a signal (a really boring one) but you won’t hear it as sound!
sound is a vibration which happens over time, so if your program is paused (e.g. when you’re stepping through your program in the debugger) it’s not generating the thousands of successive samples required to make an audible sound—so make sure your program is running
How can I see exactly what signal my program is generating?
To assist debugging, there is a “sample plotter” in the VSCode COMP2300 extension. It collects the samples you put to BSP_AUDIO_OUT_Play_Sample function and plots them. It’s basically a virtual oscilloscope. See the main FAQ for more information.

What’s with the branch-with-link (bl) instruction?
We’ll cover this in week 5, but you really don’t need to understand it to get started. It’s just like a regular branch instruction (b) except that it also leaves the address of the next instruction (i.e. where execution would have continued to if the program did not branch away) somewhere so that the program can easily “come back” when it’s done.

This is exactly what you want to happen with both the init and BSP_AUDIO_OUT_Play_Sample functions—your program goes off, does some useful stuff, and then comes back and continues executing your code.

Should I treat the init and BSP_AUDIO_OUT_Play_Sample functions differently?
As described above the main difference (from your perspective) is that the init function should only be called once at the start of your program, but the BSP_AUDIO_OUT_Play_Sample function needs to be called repeatedly to generate the output signal.

Part 1
My program for Part 1 isn’t very long—have I done enough?
If you generate a 440Hz square wave which satisfies the criteria above, then yes! The first part is meant to be (relatively) straightforward, so that you can get through it and use your creative energies in Part 2. However, to achieve full marks for this part then you will need to look in to averaging as the criteria mention.

How close to exactly 440Hz does my square wave have to be?
As close as you can get it! You can probably make it fairly close without too much effort, but to get that last bit of precision might require some extra work. If you’re wondering how to do this, think about the problem from the other direction: what would the sequence of samples look like if you recorded a 440Hz wave into a digital audio signal at a sample rate of 48kHz?

However you manage it, make sure your assembly code is still well-organised & understandable (comments can help a lot).

If I generate a square wave, then I get 100% for Part 1, right?
Not quite, code structure & readability (including comments) are part of the marking criteria as well.

Will you mark Part 1 with an oscilloscope?
No. It’s not that oscilloscopes aren’t cool, it’s that this is a course about putting the right values in the registers in the right sequence—so that’s what we’ll look at when we mark it.

Part 2
I’m not musical—does that mean I can’t get a good mark for Part 2?
No—there isn’t any musical knowledge required here—you’re just generating patterns. Any repeating pattern with a frequency in the human hearing range (roughly 20Hz to 20kHz) is a musical signal. There are a few examples above, but you should experiment and see what’s interesting to your ears.

The most important thing for Part 2 is that you clearly explain in your design document what signal you’re generating (use pictures!) and how you designed your assembly program to generate this signal.

Can I play a song for Part 2?
Your job in assignment 1 is just to generate a single, continuous signal (although it may have elements which vary over time). That’s the task you’ve been asked to complete, so playing a song doesn’t really fit this description. As always, you can’t expect to get top marks if you don’t provide what was asked of you, even if what you’ve done is really cool. If there’s any dispute about this, the convenor’s decision is final.

In musical terms, triggering a sequences of “notes” of different pitches isn’t really the synth’s job—the synth’s job is just to produce the waveform. Creating the higher-level structure of notes which make up a song is the job of another machine—the sequencer. You’ll build a sequencer in assignment 2, so be patient :)

Can I use the FPU (or some other peripheral on the discoboard we haven’t covered in class)?
Your program can use any part of the discoboard—as long as it generates the signal you describe in your design document. However, if you decide to use any features we haven’t yet covered (or don’t cover at all) in the course (e.g. the floating-point unit, the timers, the accelerometer, etc.) then you’re on your own to make it work.

If you’re up for a challenge then doing that can be a great learning experience, but you need to know what you’re getting yourself in for—and you need to give yourself plenty of time (in case things don’t work out as planned).

make sure you clone your own fork (i.e. the one with your uni ID in the url) to your local machine, not the template (because obviously you aren’t able to change the template for everyone—GitLab won’t let you) ↩

More products