diff --git a/examples/lm4f/stellaris-ek-lm4f120xl/miniblink/README b/examples/lm4f/stellaris-ek-lm4f120xl/miniblink/README index f6441bec..a19550d6 100644 --- a/examples/lm4f/stellaris-ek-lm4f120xl/miniblink/README +++ b/examples/lm4f/stellaris-ek-lm4f120xl/miniblink/README @@ -2,8 +2,21 @@ README ------------------------------------------------------------------------------ -Flashes the Red, Green and Blue diodes on the board, in order. -RED controlled by PF1 -Green controlled by PF3 -Blue controlled by PF2 +This example demonstrates the following: + * Configuriong GPIO pins + * Toggling GPIO pins + * Setting up and using GPIO interrupts + * Unlocking protected GPIO pins + * Controlling the system clock + * Changing the system clock on the fly + +Flashes the Red, Green and Blue diodes on the board, in order. The system clock +starts at 80MHz. +Pressing SW2 toggles the system clock between 80MHz, 57MHz, 40MHz ,20MHz, and +16MHz by changing the PLL divisor. +Pressing SW1 bypasses the PLL completely, and runs off the raw 16MHz clock +provided by the external crystal oscillator. +The LEDs will toggle at different speeds, depending on the system clock. The +system clock changes are handled within the interrupt service routine. + diff --git a/examples/lm4f/stellaris-ek-lm4f120xl/miniblink/miniblink.c b/examples/lm4f/stellaris-ek-lm4f120xl/miniblink/miniblink.c index e88413fd..d03be0cc 100644 --- a/examples/lm4f/stellaris-ek-lm4f120xl/miniblink/miniblink.c +++ b/examples/lm4f/stellaris-ek-lm4f120xl/miniblink/miniblink.c @@ -27,8 +27,14 @@ * Green controlled by PF3 * Blue controlled by PF2 */ +#include #include +#include #include +#include + +#include +#include /* This is how the RGB LED is connected on the stellaris launchpad */ #define RGB_PORT GPIOF @@ -38,6 +44,44 @@ enum { LED_B = GPIO2, }; +/* This is how the user switches are connected to GPIOF */ +enum { + USR_SW1 = GPIO4, + USR_SW2 = GPIO0, +}; + +/* The divisors we loop through when the user presses SW2 */ +enum { + PLL_DIV_80MHZ = 5, + PLL_DIV_57MHZ = 7, + PLL_DIV_40MHZ = 10, + PLL_DIV_20MHZ = 20, + PLL_DIV_16MHZ = 25, +}; + +static const u8 plldiv[] = { + PLL_DIV_80MHZ, + PLL_DIV_57MHZ, + PLL_DIV_40MHZ, + PLL_DIV_20MHZ, + PLL_DIV_16MHZ, + 0 +}; +/* The PLL divisor we are currently on */ +static size_t ipll = 0; +/* Are we bypassing the PLL, or not? */ +static bool bypass = false; + +/* + * Clock setup: + * Take the main crystal oscillator at 16MHz, run it through the PLL, and divide + * the 400MHz PLL clock to get a system clock of 80MHz. + */ +static void clock_setup(void) +{ + rcc_sysclk_config(OSCSRC_MOSC, XTAL_16M, PLL_DIV_80MHZ); +} + /* * GPIO setup: * Enable the pins driving the RGB LED as outputs. @@ -53,6 +97,46 @@ static void gpio_setup(void) GPIO_DIR(RGB_PORT) |= outpins; /* Configure outputs. */ GPIO_DEN(RGB_PORT) |= outpins; /* Enable digital function on outputs. */ + + /* + * Now take care of our buttons + */ + const u32 btnpins = USR_SW1 | USR_SW2; + + /* + * PF0 is locked by default. We need to unlock the GPIO_CR register, + * then enable PF0 commit. After we do this, we can setup PF0. If we + * don't do this, any configuration done to PF0 is lost, and we will not + * have a PF0 interrupt. + */ + GPIO_LOCK(GPIOF) = 0x4C4F434B; + GPIO_CR(GPIOF) |= USR_SW2; + + /* Configure pins as inputs. */ + GPIO_DIR(GPIOF) &= ~btnpins; + /* Enable digital function on the pins. */ + GPIO_DEN(GPIOF) |= btnpins; + /* Pull-up the pins. We don't have an external pull-up */ + GPIO_PUR(GPIOF) |= btnpins; +} + +/* + * IRQ setup: + * Trigger an interrupt whenever a button is depressed. + */ +static void irq_setup(void) +{ + const u32 btnpins = USR_SW1 | USR_SW2; + /* Configure interrupt as edge-sensitive */ + GPIO_IS(GPIOF) &= ~btnpins; + /* Interrupt only respond to rising or falling edge (single-edge) */ + GPIO_IBE(GPIOF) &= ~btnpins; + /* Trigger interrupt on rising-edge (when button is depressed) */ + GPIO_IEV(GPIOF) |= btnpins; + /* Finally, Enable interrupt */ + GPIO_IM(GPIOF) |= btnpins; + /* Enable the interrupt in the NVIC as well */ + nvic_enable_irq(NVIC_GPIOF_IRQ); } #define FLASH_DELAY 800000 @@ -67,7 +151,9 @@ int main(void) { int i; + clock_setup(); gpio_setup(); + irq_setup(); /* Blink each color of the RGB LED in order. */ while (1) { @@ -98,3 +184,36 @@ int main(void) return 0; } + +void gpiof_isr(void) +{ + if (GPIO_RIS(GPIOF) & USR_SW1) { + /* SW1 was just depressed */ + bypass = !bypass; + if (bypass) { + rcc_pll_bypass_enable(); + /* + * The divisor is still applied to the raw clock. + * Disable the divisor, or we'll divide the raw clock. + */ + SYSCTL_RCC &= ~SYSCTL_RCC_USESYSDIV; + } + else + { + rcc_change_pll_divisor(plldiv[ipll]); + } + /* Clear interrupt source */ + GPIO_ICR(GPIOF) = USR_SW1; + } + + if (GPIO_RIS(GPIOF) & USR_SW2) { + /* SW2 was just depressed */ + if (!bypass) { + if (plldiv[++ipll] == 0) + ipll = 0; + rcc_change_pll_divisor(plldiv[ipll]); + } + /* Clear interrupt source */ + GPIO_ICR(GPIOF) = USR_SW2; + } +}