
Figure 1. The
LPCXpresso LPC1114 board.
For the
pre-lab, read the LPC1114 User Manual and Cortex-M0 materials,
understand the structure of CMSIS Library and how NVIC works,
then write the following 'GPIOInit()' function according to the
Code Requirements. You may use physical address or CMSIS defined
Register/GPIO symbol referring to a specific register or GPIO.
/* GPIO and
GPIO Interrupt Initialization */
void
GPIOInit() {
/* Your
code here */
}
First, some background information. You will be asked by
the project creation wizard if you would like to include two
modules in your code, the CMSIS and CRP. For this lab, we
will only be using the CMSIS library, as it provides many useful
definitions to access the Nested Vector Interrupt Controller
(NVIC). Download the CMSIS archive here,
and import it into your workspace following the same procedures
you used to import the example projects in Lab 1. You may
read more about CMSIS and CRP in more detail below.
Figure 2. CMSIS - Cortex Microcontroller Software Interface Standard.
CRP is not important for us academics,
but let's learn about it anyway! When releasing an embedded system
as a product, the protection of the intellectual property held
within it (i.e. the embedded software) is of paramount
importance. CRP is intended to provide this protection by
preventing people from reading back any data contained in the code
space of the Cortex M0. Since our purposes are academic, we
will not need to use this feature. See this document from NXP to read more
about CRP and the different levels of security offered by it.
This lab revisits the digital oscilloscope portion of Lab
1. In that lab, we accomplished the task of driving our LED
with a voltage supplied from the Function Generator on your lab
bench through leveraging the ADC peripheral. We polled the
ADC on a fixed interval, read its value, and made a decision on
how to light the LED based on that value.
In this lab we wish to accomplish a similar effect, but in doing
so we will follow a completely different approach (a purely
interrupt-driven approach). Using interrupts is incredibly
powerful, as doing so allows the Arm to spend almost all of its
time asleep. Being asleep is great and yields us a
potentially massive power savings. Because power usage is a
critical design factor for embedded systems, we really need such
savings and should structure our code with power at the forefront
of our mind.
The high-level goal of this lab
assignment is this: Light the LED when a square
wave from 0V to 3.3V (logic low to logic high--rising edge) provided by
the Function Generator. Change between a 25% and 75% LED duty cycle at a 30 second intervals, toggled by an internal process (a timer interrupt). Have the GPIO port 2 pin 1 also
configured as an interrupt, sensing for the period of the function generator waveform (see
the Reference Materials section at the bottom for resources for
where to find this information). When the GPIO interrupt trigger condition
occurs, the interrupt handler for the GPIO will execute, whereby
we can set the frequency of the LED to match the frequency of the function generator square wave.
The Timer will interrupt each 30 seconds, and each time will toggle the duty cycle between 25% and 75%.
When the timer interrupts, toggle the duty cycle of the LED. The result
should be that the LED toggles at half the frequency of the square
wave provided by the function generator, and either at a 25% or 75% duty cycle--all using only
interrupts to do the work!
Hint: Since we will be sleeping almost all of the time, we need
to periodically wake up to check this global variable to see if it
has changed. If so, we need to toggle the LED before going
back to sleep. Therefore, we need to set up a Timer
Interrupt to wake us up with a fast enough period to catch
frequencies of operation from the Function Generator of up to
100Hz. Therefore, we suggest that your timer interrupts at a
rate of every 1ms.
| Function definition | Description | |
|---|---|---|
| void | NVIC_SystemReset (void) | Resets the whole system including peripherals. |
| void | NVIC_EnableIRQ(IRQn_Type IRQn) | Enables the interrupt IRQn. |
| void | NVIC_DisableIRQ (IRQn_Type IRQn) | Disables the interrupt IRQn. |
| void | NVIC_SetPriority (IRQn_Type IRQn, int32_t priority) | Sets the priority for the interrupt IRQn. |
| uint32_t | NVIC_GetPriority (IRQn_Type IRQn) | Returns the priority for the specified interrupt. |
| void | NVIC_SetPendingIRQ (IRQn_Type IRQn) | Sets the interrupt IRQn pending. |
| IRQn_Type | NVIC_GetPendingIRQ (IRQn_Type IRQn) | Returns the pending status of the interrupt IRQn. |
| void | NVIC_ClearPendingIRQ (IRQn_Type IRQn) | Clears the pending status of the interrupt IRQn, if it is not already running or active. |