jxsl13
October 28, 2019, 7:48pm
#1
Hey, could somone provide some example or reference, how one would configure a GPIO Pin to fire an external interrupt(any interrupt?) that calls an interrupt handler which toggles an LED.
ARM Cortex M3 + CMSIS, Keil MCB1700 (LPC1768)
Thanks for any help.
jxsl13
November 1, 2019, 1:16pm
#2
Here’s an example solution:
#include "LPC17xx.h"
#include <cstring> // std::memcpy
#include <array> //
#ifdef __cplusplus
extern "C" {
#endif
void delay_ms(unsigned int ms)
{
volatile unsigned int i,j;
for(i=0;i<ms;i++)
for(j=0;j<6000;j++);
}
void ToggleLED()
{
#define CHECK_BIT(var,pos) ((var) & (1<<(pos)))
// check if bit is set, then toggle it depending on result.
if(CHECK_BIT(LPC_GPIO1->FIOPIN, 28))
{
LPC_GPIO1->FIOCLR |= (1 << 28);
}
else
{
LPC_GPIO1->FIOSET |= (1 << 28);
}
}
inline void ClearInterruptFlagEINTX(uint32_t X)
{
LPC_SC->EXTINT |= (1<<X); // Clear Interrupt Flag
}
void InitPower()
{
LPC_SC->PCONP |= (1 << 15); // Enable power
}
void InitLED()
{
LPC_PINCON->PINSEL3 &= ~(0 << 25) | ~(0 << 24); // LED connected to P1.28 is in GPIO mode (see Table 83)
LPC_GPIO1->FIODIR = (1<< 28); // Configure LED pins as OUTPUT - P1.28*/
LPC_GPIO1->FIOCLR |= (1 << 28); // set P1.28 to LOW
}
void InitPushButton()
{
LPC_PINCON->PINSEL4 = (1<<20); // Configure P2_10, as EINT0
LPC_GPIO2->FIODIR &= ~(0 << 10); // P2.10 is an input pin
LPC_GPIOINT->IO2IntEnF |= (1 << 10); // P2.10 reads the falling edges to generate an interrupt
}
void InitRAMInterruptVectorTable()
{
constexpr uint32_t VECTORTABLE_SIZE = 256;
/**
* @brief Aligment is in bytes!
* Global static vector table variable
*
* static -> will stay the same after the first initialization.
*/
alignas(VECTORTABLE_SIZE * sizeof(uint32_t)) static std::array<uint32_t, VECTORTABLE_SIZE> g_VectorTable;
uint32_t *vectors = (uint32_t *)SCB->VTOR;
// copy vector table to ram location
std::memcpy(g_VectorTable.data(), vectors, sizeof(uint32_t) * VECTORTABLE_SIZE);
/* relocate vector table into RAM*/
// disable global interrupts
__disable_irq();
// change vectortable location
SCB->VTOR = (uint32_t) g_VectorTable.data();
// wait for memory operations to finish
__DSB();
// enable interrupts again.
__enable_irq();
}
void PushButton_Handler()
{
ClearInterruptFlagEINTX(0);
ToggleLED();
}
void InitEINT0()
{
LPC_SC->EXTINT = (1<<0); // Clear Pending interrupts
LPC_SC->EXTMODE = (1<<0); // Configure EINTx as Edge Triggered
LPC_SC->EXTPOLAR = (1<<0); // Configure EINTx as Falling Edge
}
void BindEINT0Handler()
{
// this can also be done by directly accessing the static array, if it was in the global scope
// but at a position offset by NVIC_USER_IRQ_OFFSET (16 system interrupts with negative indices)
NVIC_SetVector((IRQn)(18), (uint32_t)PushButton_Handler);
}
void EnableEINT0()
{
// EINT0 = 18
NVIC_EnableIRQ((IRQn_Type)(18)); /* Enable the EINT0 interrupt */
}
void FireInterrupt(uint32_t index)
{
if (index < 0 || index > 111)
return;
/**
* Bits 8:0 - 256 Interrupt values
* Values of bits 31:9 are reserved, so should not be read or touched
* Manual UM10360 - Page 92
*/
NVIC->STIR |= (0xFF & index);
}
int main()
{
SystemInit(); // predefined startup stuff, clock etc.
InitPower(); // explicitly enable power
InitPushButton(); // configure pushbutton to trigger the EINT0 interrupt
InitLED(); // configure LED's GPIO pin to be an output & set its value to LOW
InitRAMInterruptVectorTable(); // move vector table to ram
InitEINT0(); // init eint0
BindEINT0Handler(); // make EINT0 execute PushButtonHandler on interrupt
EnableEINT0(); // enable interrupt
while (1)
{
FireInterrupt(18); // 18 = EINT0
delay_ms(500);
}
}
#ifdef __cplusplus
}
#endif
1 Like