I am using the Atmel SAM3x8E micro-controller and trying to do a simple LED toggle when I press a button. I am using pull-up configuration button to trigger an interrupt routine.
This is the initialization for the interrupt:
// Set button pins as pull-up inputs
pio_set_input(PIOC, BUTTON_1, PIO_PULLUP);
pio_set_input(PIOC, BUTTON_2, PIO_PULLUP);
// Configure button input pin interrupt mode and handler (Rising Edge)
pio_handler_set(PIOC, ID_PIOC, BUTTON_1, PIO_IT_RISE_EDGE, button_press_handler);
pio_handler_set(PIOC, ID_PIOC, BUTTON_2, PIO_IT_RISE_EDGE, button_press_handler);
// Enable the interrupts
pio_enable_interrupt(PIOC, BUTTON_1);
pio_enable_interrupt(PIOC, BUTTON_2);
NVIC_EnableIRQ(PIOC_IRQn);
NVIC_EnableIRQ(PIOC_IRQn);
Then this is the interrupt routine:
// Interrupt handler for button press
void button_press_handler(uint32_t a, uint32_t b)
{
pio_toggle_pin_group(PIOC, BLUE_LED4); // NOT TOGGLING LED (ONLY TURNS IT ON)
}
Yet when I run it, I cannot get the LED to toggle. It simply turns on and stays on. The function that pio_toggle_pin_group calls is the following:
* \param p_pio Pointer to a PIO instance.
* \param ul_mask Bitmask of one or more pin(s) to configure.
*/
void pio_toggle_pin_group(Pio *p_pio, uint32_t ul_mask)
{
if (p_pio->PIO_ODSR & ul_mask) {
/* Value to be driven on the I/O line: 0. */
p_pio->PIO_CODR = ul_mask;
} else {
/* Value to be driven on the I/O line: 1. */
p_pio->PIO_SODR = ul_mask;
}
}
Any ideas as to why my LED is not toggling the way I want? I've refereed to the Atmel ASF documentation but I still cannot figure this out.
I cannot help you with the actual function calls, but suppose you use a edge interrupt. As far as I see, you call an interrupt handler for each rising edge. However, after the first rising edge, you need to trigger on button release, which would be a falling edge, so you need to change the edge within the interrupt handler.
But you must take into account that mechanical buttons do not generate a clean, single edge when pressed or released. It does instead bounce. For normal momentary contact buttons with pullup (or down) resistor, this results in multiple pulses for each event, so the LED may turn on/off multiple times and stay in an arbitrary state which might - by chance - be "on" far by most times. If available, check with an oscilloscope.
This can be circumvented in hardware by a capacitor or in software using a timer with a dead time after the relevant edge before reacting to any other button event. The dead time depends on the type of button, but typical values are 5 to 20ms and should be mentioned in the datasheet of the button. If in doubt, use the highest acceptable value.