Lab Assignment: Interrupt + Lookup Tables + Binary Semaphores

Objective

To learn how to create a single dynamic user defined interrupt service routine callback driver/library.

This lab will utilize:

  • Semaphores
    • Wait on Semaphore Design pattern
  • Lookup table structures
  • Function pointers
  • Interrupts

Port Interrupts

You will configure GPIO interrupts.  This is supported for Port0 and Port2 and the following registers are relevant.

Assignment

Part 1: Design GPIOInterrupt driver

You are designing a library that will allow the programmer using your library to be able to "attach" a function callback to any and each pin on port 0 or port 2. 

  1. Implement ALL class methods.
  2. All methods must function work as expected by their comment description.
#ifndef LABGPIOINTERRUPTS_H
#define LABGPIOINTERRUPTS_H

class LabGPIOInterrupts
{
private:
    /**
     * Your job here is to construct a lookup table matrix that correlates a pin
     * and port to a registered ISR. You may want to make additional probably need
     * more than one. Be clever here. How can you do this such that you and the
     * cpu do the least amount of work.
     */
public:
    /**
     * LabGPIOInterrupts should be a singleton, meaning, only one instance can exist at a time.
     * Look up how to implement this.
     */
    LabGPIOInterrupts();
    /**
     * 1) Should setup register "externalIRQHandler" as the EINT3 ISR.
     * 2) Should configure NVIC to notice EINT3 IRQs.
     */
    void init();
    /**
     * This handler should place a function pointer within the lookup table for the externalIRQHandler to find.
     *
     * @param[in] port         specify the GPIO port
     * @param[in] pin          specify the GPIO pin to assign an ISR to
     * @param[in] pin_isr      function to run when the interrupt event occurs
     * @param[in] condition    condition for the interrupt to occur on. RISING, FALLING or BOTH edges.
     * @return should return true if valid ports, pins, isrs were supplied and pin isr insertion was sucessful
     */
    bool attachInterruptHandler(uint8_t port, uint32_t pin, void (*pin_isr)(void), InterruptCondition_E condition);
    /**
     * After the init function has run, this will be executed whenever a proper
     * EINT3 external GPIO interrupt occurs. This function figure out which pin
     * has been interrupted and run the ccorrespondingISR for it using the lookup table.
     *
     * VERY IMPORTANT! Be sure to clear the interrupt flag that caused this
     * interrupt, or this function will be called again and again and again, ad infinitum.
     *
     * Also, NOTE that your code needs to be able to handle two GPIO interrupts occurring
     * at the same time.
     */
    static void externalIRQHandler(void);
    ~LabGPIOInterrupts();
};

#endif

Code Block 1. GPIO Interrupt Driver Template Class

Part 2: Use Driver to Optimize GPIO Application

As the title says, you will attempt to optimize your previous lab by utilizing interrupts and semaphores. This time, you will eliminate the vReadSwitch task, and utilize a interrupt service routine to send semaphores (fromISR) to the vControlLED task.

Requirements

  • Should be able to specify a callback function for any port/pin for an exposed GPIO given a rising, falling, or both condition.
    • We may ask you change which port and pin causes a particular callback to be executed in your code and then recompile and re-flash your board to and prove it works with any port 0 or port 2 pin.
  • You will need to use two external switches for this lab.
  • The ISR must use a semaphore (fromISR) to the communicate with the vControlLED task.

You cannot use printf() to print anything from inside an ISR (if FreeRTOS is running), but you can use the u0_dbg_printf() API from printf_lib.h.

Note that printing 4 chars inside an ISR can take 1ms, and this is an eternity for the processor and should never be done (other than debug).

Hints:

/**
 * LPC datasheet indicates that all of Port0 and Port2 interrupts use
 * a single interrupt vector called EINT3
 */

void LabGPIOInterrupts::init(void)
{
  // Register your ISR using lpc_isr.h
    
  // Enable interrupt for the EINT3
  NVIC_EnableIRQ(EINT3_IRQ_n);
}

void eint3_isr(void)
{
  // This interrupt must check the port that triggered the interrupt and clear the source
  // For instance, here is how to clear an interrupt for Port2.3
  IO2IntClr = (1 << 3);
}

What to turn in:

  • Place everything inside of main file or include all relevant files.
  • Turn in the screenshots of terminal output. 
Back to top