[SOLVED] Comp2300 Lab 10

35.00 $

Category:
Click Category Button to View Your Next Assignment | Homework

You will receive the following solution file(s) instantly after successful payment:

zip file icon comp2300-2021-lab-10-eokrtr.zip (97.7 KB)
Assignment Instructions Updated Recently? Submit Below and we will provide new Solution!
Submit New Instructions
πŸ”’ Securely Powered by:
Secure Checkout
1/5 - (1 vote)

Before you attend this week’s lab, make sure:

  1. you have completedΒ lab 9Β and understand how signals (i.e. voltage changes) on your GPIO pins can trigger interrupts

In this week’s lab you will:

  1. configure the GPIO pins on your board for both input and output
  2. connect the GPIO pins to one another with physical wires
  3. configure and write interrupt handlers toΒ do thingsΒ when stuff happens on these wires
  4. simulateΒ a multiboard setup where you connect the two sides of your discoboard to each other with wires and turn the LEDs on from either side

Introduction

This week you’ll take a deeper dive into the GPIO & interrupt capability on your discoboard. TheΒ GPΒ inΒ GPIO stands forΒ GeneralΒ Purpose, which means that each pin (the pointy little gold-coloured bits of metal sticking up in rows along the sides of your discoboard) can be used for either digital inputΒ orΒ output (or even other things). The mode (input mode, output mode, alternate mode) of a given pin is configured (you guessed it!) by writing certain bits to special GPIO configuration registers.

In this week’s lab you’ll learn more about the stuff you did in Week 8 when you set the joystick pins to input mode, and you’ll learn how to control the signals (i.e. high and low voltages) coming out of the pins in software.

Exercise 1Β lays the groundwork (and is pretty wordy) but then things pick up inΒ Exercise 2, and by the end of the lab you’ll get to be really creative. This lab might seem a bit similar toΒ last week, but it goes into a bit more depth about exactly what it means for you to configure, read & write to the GPIO pins, which is going to be super-helpful for assignment 3.

Today you’ll be working on sending signals to and from GPIO pins by connecting these pins using jumper cables. To start off, think about: in the context of GPIO pins, what is aΒ signal? Is there a difference between a signal which comes internally through the discoboard (e.g. the joystick input you used in theΒ Week 9 labΒ and the signal which comes in through an external wire?

Exercise 1: click-to-blink recap

This first exercise willΒ seemΒ like a re-hash ofΒ stuff you’veΒ done beforeβ€”clicking the joystick and turning on an LED.

However, this time when you fork & clone theΒ lab 10 templateΒ and have a look inside there’s some good news and some bad news:

  • theΒ bad newsΒ is that you don’t have the sweetΒ joystick.SΒ andΒ led.SΒ helper libraries from last time1
  • theΒ good newsΒ is that you’ll get to write it yourself and see exactly how it works (and there are still some helpful utility functions & macros in the templateβ€”you don’t have to startΒ completelyΒ from scratch)

As you re-do the LED & joystick configuration using a generic GPIO config process you’ll get a better picture of how the GPIO infrastructure and NVIC/EXTI interrupt controllers work together on your discoboard.

GPIOΒ output

To configure a pin in output mode,Β src/libcomp2300/macros.SΒ has a handyΒ GPIO_configure_output_pinΒ macro. For example, to declare pinΒ PH0Β as an output pin, you could call the macro like so:

GPIO_configure_output_pin H, 0

Most of the macros in theΒ macros.SΒ are just simple wrappers around function calls, using the macro to set up correct parameters (remember,Β macros are just kids with scissors!). You still need to be aware (and careful) of which registers the macros might touch. Before you use any macros in this lab,Β make sure you read the macro definition and understand what it is doing.

To use the GPIO pins, you need to turn them on by making sure the corresponding GPIO port receives a clock signal. Remember fromΒ lab 5Β that the discoboard’s red and green LEDs are connected to ports B and E respectively:

GPIOx_clock_enable B
GPIOx_clock_enable E

Make sure you enable portΒ AΒ as well for joystick.

To send data out (i.e. to change the voltage) on the GPIO pin, you write aΒ 0Β orΒ 1Β to the GPIO port’s Output Data Register (ODR). Remember that the red LED is connected on GPIOΒ PB2Β and the green LED is onΒ PE8. So you can turn on the LEDs by writing aΒ 1Β to their output data registers. Most of these helper macros haveΒ set,Β clearΒ andΒ toggleΒ versions, which do what you’d expect.

GPIO_configure_output_pin B, 2 @ (red LED)
GPIO_configure_output_pin E, 8 @ (green LED)

GPIOx_ODR_set B, 2
GPIOx_ODR_set E, 8

Once you write a signal (aΒ 0Β orΒ 1) to the GPIO line, how long does it β€œstay there” for? How could you figure this out?

GPIOΒ input

All good so farβ€”remember that this is just a recap. Now, let’s take the same approach to the joystick, which is similar to the LEDs in that it’s wired to specific GPIO pins (PA0: centre,Β PA1: left,Β PA5: down,Β PA2: right,Β PA3: up) but this time it’s anΒ inputΒ device. There are some macros for this, too:

GPIO_configure_input_pin A, 0 @ (central joystick button)

Here, you’ve declared the pinΒ PA0Β as an input pin. TheΒ GPIO_configure_input_pinΒ macro does a couple of things:

  • sets theΒ inputΒ bit pattern into the appropriate mode register (it’sΒ 0b00Β for input, just like it wasΒ 0b01Β for output)
  • configures the input pin to use aΒ pull-down resistorβ€”this is so that it will reliably read aΒ 0Β even if it’s not connected to anything (if you don’t do this, then you might get weird results when your input isn’t connected to anything)

To read data in from a GPIO pin, you can read the current value (highΒ 1Β or lowΒ 0) on any GPIO pin at any time by reading the appropriate bit from the GPIO port’s Input Data Register (IDR). There’s a helper macro for this as wellβ€”GPIOx_IDR_read, and it sets flags based on the result (so theΒ zero flag will be set if the GPIO line is low, and it won’t be set if the GPIO line is high).

You can do this as often as you likeβ€”reading data from the pin withΒ GPIOx_IDR_readΒ will always leave the current value (0Β orΒ 1) inΒ r0Β and also set the flags appropriately, and it doesn’t change the signal on the pin. You can use this to β€œpoll” a given pin in a loop:

poll_gpio:
  @ read PA0, set flags based on result
  GPIOx_IDR_read A, 0
  
  @ do something based on the flags in here
  
  b poll_gpio

Write a program which enables the central joystick button as an input, and polls (as in the loop above) to turn the green LED on when the button is pressed. Commit & push your program to GitLab.

Exercise 2: let’s do it again, this time using interrupts

As we talked about in the week 8 lectures, polling the current value on the pin in a loop isn’t the best way to do things, because it makes it hard to do other stuff in the meantime. There’s a better way: configure the GPIO line to fire an interrupt when the value changes.

Before you can enable and configure the interrupts, you need to enable the System Configuration Controller (SYSCFG) clock so that you can modify the system configuration (see Chaper 8 and 8.2.3 in theΒ discoboard reference manual).

@ enable SYSCFG clock
RCC_APB2ENR_set 0

This code is included in theΒ template, you can see the relevant configuration register in Section 6.4.21 on p233 of theΒ discoboard reference manual.

There’s one other macro inΒ macros.SΒ which is helpful when setting up GPIO pins as input:Β GPIO_configure_input_pin_itβ€”note theΒ _itΒ suffix. This macro does all the configuration ofΒ GPIO_configure_input_pinΒ and additionally registers the pin as a source for interrupts. There are two parts of the discoboard which are working together to do this:

  • theΒ Extended Interrupts and Events ControllerΒ (EXTI) is the part of your discoboard which allows signals (either a rising or falling edge) on the GPIO pins to trigger an interrupt
  • theΒ Nested Vectored Interrupt Controller2Β (NVIC) is the hardware which β€œreceives” the interrupt, and (depending on the priority, what other interrupts are running, and a few other things) will interrupt the CPU and transfer control to the appropriate handler function in the vector table

TheΒ GPIO_configure_input_pin_itΒ sets the appropriate bits to enable the the pin as a source of interrupts. The next step in the EXTI configuration is to determine whether the interrupt will be triggered on aΒ rising edgeΒ (0Β toΒ 1Β transition) or aΒ falling edgeΒ (1Β toΒ 0Β transition). Again, there are helper macros for this:

GPIO_configure_input_pin_it A, 0
EXTI_set_rising_edge_trigger 0
EXTI_set_falling_edge_trigger 0

There are a couple of quirks here: firstly, the EXTI controller can only listen to one port for a given pin number, so for example you can’t have bothΒ PA0Β andΒ PB0Β triggering an interrupt. This is because the pins are multiplexed in the EXTI controller (see the diagram below). This is to keep things simpleβ€”you probably don’tΒ needΒ separate interrupt triggers on all the pins. Here’s an example of what this looks like for EXTI0β€”pin zero fromΒ allΒ ports goes in there, and the EXTI controller can only listen to one at a time.

GPIO to EXTI mapping

Secondly (and more confusingly) the EXTI controller only has 7 GPIO interrupt lines into the NVIC, and since there are more than 7 pins in each GPIO port (there are 16, in fact) this means that some of the pins have toΒ shareΒ an interrupt. The first 5 (EXTI0Β toΒ EXTI4) get their own interrupts, but 5–9 have to share theΒ EXTI9_5Β interrupt, and 10–15 have to share theΒ EXTI15_10Β interrupt. Here’s a picture to make things clearer (the extra number in the NVIC column is theΒ positionΒ of the interrupt in the NVIC vector table):

EXTI to NVIC mapping

This is all shown (along with the names, positions & priorities) of all the other interrupts in your discoboard in Table 42, Section 11.3 on p321 of theΒ discoboard reference manual. Here’s a simplified version of that table which only contains the rows relevant to the EXTI controller:

position interrupt
6 EXTI0
7 EXTI1
8 EXTI2
9 EXTI3
10 EXTI4
23 EXTI9_5
40 EXTI15_10

For this reason, theΒ GPIO_configure_input_pin_itΒ macro doesn’t enable the NVIC interruptβ€”you need to enable it yourself using theΒ NVIC_setΒ macro like so:

NVIC_set ISER 8

Which interrupt (in the NVIC) does the above line of assembly code enable?

ISER stands forΒ InterruptΒ SetΒ EnableΒ Register; you can also use ISPR (set pending) or other register banks there, see the macros file for details.

Here’s an example of where this gets tricky: if you want to have interrupts on (say) pinsΒ PE13Β andΒ PE14Β they will both trigger the same interrupt handler functionΒ EXTI15_10_IRQHandler, since they’re both in the 10–15 range. To deal with this, the handler function will have to check another register (the EXTI interrupt pending register) to see which pin number triggered the interrupt.

So, the full journey of a GPIO interrupt through your system is:

  1. an edge (rising or falling) is detected on your input GPIO pin
  2. the EXTI controller detects this (assuming the interrupt is enabled and it’s watching the right port) and raises one of theΒ EXTInΒ interrupt lines to the NVIC
  3. if theΒ EXTInΒ interrupt is enabled in the NVIC, your program is interrupted and the handler function (determined by the address in the vector table) is called

If you have trouble, here are a few questions to ask yourself:

  1. have you tried pressing the reset button before debugging?
  2. have you enabled the SYSCFG clock?
  3. have you clocked the GPIO pins?
  4. have you configured the GPIO pins as input pins?
  5. have you configured the GPIO pins to trigger an interrupt?
  6. have you configured the trigger for the interrupt (i.e. rising or falling edge)?
  7. have you enabled the appropriate EXTI interrupt in the NVIC?
  8. have you written the interrupt handler function, and is it globally visible?
  9. does your interrup handler function clear it’s pending register before it exits? (theΒ EXTI_PR_clear_pendingΒ macro will probably help you out here)

Write a program where pressing the central joystick button blinks the red LED, but pressing one of the direction buttons blinks the green LED (don’t forget to enable the correct interrupts in the NVIC, and to disable the interrupt pending flag using theΒ EXTI_PR_clear_pendingΒ macro before the handler function exits). Commit & push your program to GitLab.

The fact that the GPIO interrupts go though both the EXTI and the NVICΒ isΒ complicated, and it also means there are several different ways of enabling/disabling/triggering these interrupts. What you’ve done in this exercise is to enable it inΒ bothΒ places: the EXTI enabling happens in theΒ GPIO_configure_input_pin_itΒ macro, and the NVIC enabling in theΒ NVIC_setΒ macro. If you want to disable it in the EXTI, you disable the interrupt for pinΒ nΒ byΒ clearingΒ (setting toΒ 0) theΒ nth bit in theΒ EXTI_IMR1Β register (base addressΒ 0x40010400).

To disable it in the NVIC, youΒ setΒ (toΒ 1) the correct bit (see mapping diagram above) in theΒ NVIC_ICERnΒ register (base addresses starting atΒ 0xE000E180Β forΒ NVIC_ICER0, but there’s lots of themβ€”e.g.Β EXTI15_10Β spills intoΒ NVIC_ICER1Β register because it’s in slot 40). As before, you can use theΒ NVIC_setΒ macro for this, just useΒ ICERΒ where you usedΒ ISERΒ inΒ Exercise 2. Be careful not to use the normal load-twiddle-store approach for this, thoughβ€”as discussed in theΒ Week 8 lab.

Just to recap: to disable an interrupt in the EXTI youΒ clearΒ a bit, and to disable it in the NVIC youΒ setΒ a bit, and it’s a different bit in each case. Don’t ask me why things are so inconsistent, blame the people who designed the discoboard. TheΒ macros.SΒ file should handle some of this stuff for you, but that’s the full story if you’re getting confused trying to disable/re-enable interrupts in your program.

Exercise 3: click-over-the-wire

So far this lab has been a bit of an information dump, and all you did was turn on the LEDs with the joystick (which you’ve known how to do for ages). In this exercise, you’ll take your knowledge of general GPIO input and output and re-implement the click-to-blink programΒ again, but this time sending the β€œclick” signal over the wire.

Grab one of your jumper leads and connect it to your board from pinΒ PB7Β toΒ PE13. You’ll use one end as the receiver and one end as the senderβ€”it doesn’t matter which. What you need to do in this exercise is:

  • configure your output pin as a GPIO output
  • configure your input pin as an interrupt-enabled GPIO input
  • write your joystickΒ EXTI0Β interrupt handler so that instead of toggling the LED directly, it toggles the value on the sender data pin (using the ODR helper macro)
  • write another interrupt handler function (have a careful think about what should it beΒ called?) and enable it in the NVIC and makeΒ thatΒ handler function toggle the LED

The info in the first two exercises will help you outβ€”there are a few gotchas, so read it carefully and ask for help if you get stuck. Once you’re done with that, add another wire betweenΒ PD0Β andΒ PE14β€”repeat the process so that pressing one of the joystick direction buttons toggles the other LED over the wire.

If you useΒ PD0Β you’ll have to be a bit carefulβ€”sinceΒ EXTIOΒ is used by the center joystick button (wired toΒ PA0), it’s NOT possible to setΒ EXTIOΒ as an interrupt forΒ PD0. Why can’t we use the same handler for both A0 and D0 interrupts?

Write a program where you can toggle the red & green LEDs using the joystick with the signals travelling over the wires (as described above). Commit & push your program to GitLab.

What happens if you experiment with different triggering schemesβ€”rising+falling edge vs rising edge only? Do the triggering schemes have to be the same on both ends of the wire? How many different ways can you configure the wires & interrupts in your click-over-the-wire program?

Exercise 4:Β β€œmulti-player” QuickClick

Due to current circumstances and #socialdistancing the original version of this exercise won’t really work. So here is an altered version that only involves a single discoboard.

Remember theΒ QuickClick gameΒ you made last week? In Exercise 4 you will wire up both sides of your discoboard to build a multi-player3Β variation of QuickClick.

In this instance we are going to pretend that each side of the board is actually two separate boards, this is a bit different to actually having to separate boards but the concept is similar, if you did actually have 2 boards, then how would this be possible?

As you (hopefully) just figured out, the multiplayer part of this is super-easy because you already did all the hard work inΒ Exercise 3. Once you’re sending a signal over a wire, it doesn’t matter whether both ends of the wire are connected to the same discoboard orΒ differentΒ discoboards.

There is one caveat here: voltages, such as the β€œlow” and β€œhigh” voltages you’ve been setting and reading from your GPIO pins, are actuallyΒ relativeΒ measurements. Think of it like the concepts of shortness/tallness: someone might say you’re either tall or short depending on who you’re standing next to. Even though youΒ mightΒ say that a person is tall (or short) what you really mean is that that person is taller (or shorter) than the average of the heights of all the other people you know. Well, voltage is similarβ€”what you care about is the voltageΒ differenceΒ between two places. When your wire is connected to your board only, there’s no problemβ€”both ends have the same common reference orΒ ground. But when two boards are connected to each other they need some way of agreeing on what theΒ 0Β voltage level is. This is achieved by connecting theirΒ GNDΒ groundΒ reference pins together with a separate cable. Your discoboard has severalΒ GNDΒ pins because needing to connect boards to a common ground is so common, so you need to have plenty of pins handy to do it.

To get back to theΒ β€œmultiplayer” QuickClick exercise, what you’ll need to do is:

  1. Reconfigure you’re interrupts and handlers so that each side of the boards have a button on the joystick.
    • The left joystick button will be the left side’s control (wired toΒ PA1)
    • The right joystick button will be the right side’s control (wired toΒ PA2)
  2. configure sender and receiver pins and interrupts for both sides of the board
    • left:
      • Receiver:Β PB7
      • Sender:Β PD0
    • right:
      • Receiver:Β PE14
      • Sender:Β PE13
  3. connect one of theΒ GNDΒ pins on the left of your discoboard to one of theΒ GNDΒ pins on the right of your discoboard4
  4. take two wires and connect the sender on the left (PD0) to the receiver on the right (PE14), then repeat this process from the sender on the right (PE13) to the receiver on the left (PB7).
  5. figure out how the game is going to work:
    • an option here would be to assign an LED to each side and play tennisβ€”let’s say the red led means the ball is in the left player’s court and a green LED means it is in the right player’s court. Now, when you click one of the player’s buttons it shouldΒ β€œpass” the led to the other player.
      • eg: if the green LED is currently on, then pressing the right button will turn the green LED off and send a signal over the wire to the left side that the LED is now in their court and they should turn the red LED on

there are a lot of moving parts here, but some things to think about are:

  • how do you keep track of who’s turn it is?
  • who starts with the ball (LED) in their court?
  • is their implicit communication going on in your implementation?
    • or could you directly take it and use 2 boards and it would work the same?

It may not seem like it, but this is actually similar to what you will do in assignment 3, so do stop and analyse your current program before moving on.

After having thought about and answered the points above, here are some things to evaluate theΒ β€œcorrectness” of your solution:

  • Do you turn the LEDs off and on instead of toggling them?
  • Where do you control the LEDs? the left side should only be changing the red LED and the right side should only be changing the green LED
  • What happens if you try to pass the LED when it isn’t on your side?
    • How do you know if the LED is on your side?
    • Can you make it so that each side alters their output if and only if the LED is on their side?
  • Pull out a connection and play the game, does it behave as you expect it to?
  • Do the left and right sides share any memory locations? If they do then consider the case where they are on two separate boards, would it still function the same?

1 file Β· 97.7 KB

  • comp2300-2021-lab-10-eokrtr.zip 97.7 KB