/** * \brief Set callback for given GPIO pin * * \param [in] pin The pin number * \param [in] callback callback function pointer * \param [in] irq_level interrupt level * * \retval true Set successfully * \retval false Wrong parameters or maximum number of interrupt * sources has been exceeding */ bool gpio_set_pin_callback(ioport_pin_t pin, gpio_pin_callback_t callback, uint8_t irq_level) { int8_t i; int8_t irq_line; if (gpio_nb_sources >= GPIO_MAX_INTERRUPT_SOURCES) { return false; } /* * Get IRQ line for the given pin. * * \note Grouping interrupt generators into groups of eight, four * different interrupt handlers can be installed for each GPIO port. */ for (i = 0; i < 4; i++) { if (ioport_pin_to_mask(pin) & (GPIO_INT_GROUP_MASK << (i * 8))) { break; } } irq_line = GPIO_0_IRQn + ioport_pin_to_port_id(pin) * 4 + i; gpio_int_sources[gpio_nb_sources].pin = pin; gpio_int_sources[gpio_nb_sources].callback = callback; NVIC_ClearPendingIRQ((IRQn_Type)irq_line); NVIC_SetPriority((IRQn_Type)irq_line, irq_level); NVIC_EnableIRQ((IRQn_Type)irq_line); gpio_nb_sources++; return true; }
OSStatus platform_gpio_irq_disable( const platform_gpio_t* gpio ) { OSStatus err = kNoErr; ioport_port_mask_t mask = ioport_pin_to_mask ( gpio->pin ); ioport_port_t port = ioport_pin_to_port_id( gpio->pin ); volatile Pio* port_register = arch_ioport_port_to_base( port ); platform_mcu_powersave_disable(); require_action_quiet( gpio != NULL, exit, err = kParamErr); /* Disable interrupt on pin */ port_register->PIO_IDR = mask; /* Disable Cortex-M interrupt vector as well if no pin interrupt is enabled */ if ( port_register->PIO_IMR == 0 ) { NVIC_DisableIRQ( irq_vectors[port] ); } gpio_irq_data[port][mask].wakeup_pin = false; gpio_irq_data[port][mask].arg = 0; gpio_irq_data[port][mask].callback = NULL; exit: platform_mcu_powersave_enable(); return err; }
/** * \brief Test physical loop-back with some characters in sunc mode. * * This function sends a character over USART on loop back to verify that init * and sending/receiving works. A jumper is connected on the USART. * * \param test Current test case. */ static void run_loopback_syncmode_test(const struct test_case *test) { uint8_t out_c = 'c'; uint8_t in_c = 0; port_pin_t sck_pin; sysclk_enable_module(POWER_RED_REG0, PRUSART0_bm); usart_set_mode(&CONF_UNIT_USART, USART_CMODE_SYNCHRONOUS_gc); sck_pin = IOPORT_CREATE_PIN(PORTE, 2); ioport_configure_port_pin(ioport_pin_to_port(sck_pin), ioport_pin_to_mask(sck_pin), IOPORT_DIR_OUTPUT | IOPORT_INIT_HIGH ); usart_spi_set_baudrate(&CONF_UNIT_USART, CONF_UNIT_BAUDRATE, sysclk_get_source_clock_hz()); usart_tx_enable(&CONF_UNIT_USART); usart_rx_enable(&CONF_UNIT_USART); usart_putchar(&CONF_UNIT_USART, out_c); in_c = usart_getchar(&CONF_UNIT_USART); test_assert_true(test, in_c == out_c, "Read character through sync mode is not correct: %d != %d", in_c, out_c); }
/** * \brief Initialize USART in SPI master mode. * * This function initializes the USART module in SPI master mode using the * usart_spi_options_t configuration structure and CPU frequency. * * \param usart The USART module. * \param opt The RS232 configuration option. */ void usart_init_spi(USART_t *usart, const usart_spi_options_t *opt) { usart->UBRR = 0; usart_enable_module_clock(usart); usart_set_mode(usart, USART_CMODE_MSPI_gc); port_pin_t sck_pin; #ifdef USARTA0 if ((uintptr_t)usart == (uintptr_t)&UCSR0A) { sck_pin = IOPORT_CREATE_PIN(PORTE, 2); ioport_configure_port_pin(ioport_pin_to_port(sck_pin), ioport_pin_to_mask(sck_pin), IOPORT_DIR_OUTPUT | IOPORT_INIT_HIGH ); } #endif #ifdef USARTA1 if ((uintptr_t)usart == (uintptr_t)&UCSR1A) { sck_pin = IOPORT_CREATE_PIN(PORTD, 5); ioport_configure_port_pin(ioport_pin_to_port(sck_pin), ioport_pin_to_mask(sck_pin), IOPORT_DIR_OUTPUT | IOPORT_INIT_HIGH ); } #endif if (opt->spimode == 1 || opt->spimode == 3) { usart->UCSRnC |= USART_UCPHA_bm; } else { usart->UCSRnC &= ~USART_UCPHA_bm; } if (opt->spimode == 2 || opt->spimode == 3) { usart->UCSRnC |= USART_UCPOL_bm; } else { usart->UCSRnC &= ~USART_UCPOL_bm; } if (opt->data_order) { usart->UCSRnC |= USART_DORD_bm; } else { usart->UCSRnC &= ~USART_DORD_bm; } usart_spi_set_baudrate(usart, opt->baudrate, sysclk_get_source_clock_hz()); usart_tx_enable(usart); usart_rx_enable(usart); }
OSStatus gpio_irq_disable( gpio_port_t gpio_port, gpio_pin_number_t gpio_pin_number ) { Pio *p_pio = arch_ioport_port_to_base(gpio_port); ioport_port_mask_t ul_mask = ioport_pin_to_mask(CREATE_IOPORT_PIN(gpio_port, gpio_pin_number)); pio_disable_interrupt(p_pio, ul_mask); return kGeneralErr; }
OSStatus gpio_irq_enable( gpio_port_t gpio_port, gpio_pin_number_t gpio_pin_number, gpio_irq_trigger_t trigger, gpio_irq_handler_t handler, void* arg ) { //gpio_irq_data_t *pSource; uint32_t ul_attr; if (gs_ul_nb_sources >= MAX_INTERRUPT_SOURCES) return 1; //Pio *p_pio = (Pio *)ioport_port_to_base(gpio_port); Pio *p_pio = arch_ioport_port_to_base(gpio_port); //ioport_pin_t pin = CREATE_IOPORT_PIN(gpio_port, gpio_pin_number); ioport_port_mask_t ul_mask = ioport_pin_to_mask(CREATE_IOPORT_PIN(gpio_port, gpio_pin_number)); if ( gpio_irq_management_initted == 0 ) { memset( (void*)gpio_irq_data, 0, sizeof( gpio_irq_data ) ); gpio_irq_management_initted = 1; } if (trigger == IRQ_TRIGGER_RISING_EDGE ) { ul_attr = PIO_IT_RISE_EDGE; } else if (trigger == IRQ_TRIGGER_FALLING_EDGE ) { ul_attr = PIO_IT_FALL_EDGE; } else if (trigger == IRQ_TRIGGER_BOTH_EDGES ) { ul_attr = PIO_IT_EDGE; } //pSource = &(gpio_irq_data[gs_ul_nb_sources]); gpio_irq_data[gs_ul_nb_sources].owner_port = gpio_port; if ( gpio_port == PORTA) { gpio_irq_data[gs_ul_nb_sources].id = ID_PIOA; // pmc_enable_periph_clk(ID_PIOA); } else if (gpio_port == PORTB) { gpio_irq_data[gs_ul_nb_sources].id = ID_PIOB; // pmc_enable_periph_clk(ID_PIOB); } gpio_irq_data[gs_ul_nb_sources].mask = ul_mask; gpio_irq_data[gs_ul_nb_sources].handler = handler; gpio_irq_data[gs_ul_nb_sources].arg = arg; gs_ul_nb_sources++; /* Configure interrupt mode */ pio_configure_interrupt(p_pio, ul_mask, ul_attr); if ( gpio_port == PORTA){ NVIC_EnableIRQ( PIOA_IRQn ); pio_handler_set_priority(PIOA, PIOA_IRQn, IRQ_PRIORITY_PIO); } else if (gpio_port == PORTB) { NVIC_EnableIRQ( PIOB_IRQn); pio_handler_set_priority(PIOB, PIOB_IRQn, IRQ_PRIORITY_PIO); } pio_enable_interrupt(p_pio, ul_mask); return kGeneralErr; }
/** * Common GPIO handler. */ static void gpio_common_handler(uint32_t port_id, uint32_t port_mask) { GpioPort *gpio_port = &(GPIO->GPIO_PORT[port_id]); uint32_t i; uint32_t int_flags; ioport_pin_t pin; int_flags = gpio_port->GPIO_IFR; for (i = 0; i < gpio_nb_sources; i++) { pin = gpio_int_sources[i].pin; if ((ioport_pin_to_port_id(pin) == port_id) && (ioport_pin_to_mask(pin) & int_flags)) { if (gpio_int_sources[i].callback != NULL) { gpio_int_sources[i].callback(); } else { Assert(false); /* Catch unexpected interrupt */ } } } gpio_port->GPIO_IFRC = (int_flags & port_mask); }
OSStatus platform_gpio_irq_enable( const platform_gpio_t* gpio, platform_gpio_irq_trigger_t trigger, platform_gpio_irq_callback_t handler, void* arg ) { ioport_port_mask_t mask = ioport_pin_to_mask( gpio->pin ); ioport_port_t port = ioport_pin_to_port_id( gpio->pin ); volatile Pio* port_register = arch_ioport_port_to_base( port ); uint8_t pin_number = (gpio->pin) & 0x1F; uint32_t temp; uint8_t samg5x_irq_trigger; OSStatus err = kNoErr; platform_mcu_powersave_disable(); require_action_quiet( gpio != NULL, exit, err = kParamErr); NVIC_DisableIRQ( irq_vectors[port] ); NVIC_ClearPendingIRQ( irq_vectors[port] ); gpio_irq_data[port][pin_number].wakeup_pin = gpio->is_wakeup_pin; gpio_irq_data[port][pin_number].arg = arg; gpio_irq_data[port][pin_number].callback = handler; switch ( trigger ) { case IRQ_TRIGGER_RISING_EDGE: samg5x_irq_trigger = IOPORT_SENSE_RISING; break; case IRQ_TRIGGER_FALLING_EDGE: samg5x_irq_trigger = IOPORT_SENSE_FALLING; break; case IRQ_TRIGGER_BOTH_EDGES: samg5x_irq_trigger = IOPORT_SENSE_BOTHEDGES; break; default: err = kParamErr; goto exit; } if( gpio->is_wakeup_pin == true ) { platform_powersave_enable_wakeup_pin( gpio ); } if ( samg5x_irq_trigger == IOPORT_SENSE_RISING || samg5x_irq_trigger == IOPORT_SENSE_BOTHEDGES ) { port_register->PIO_AIMER |= mask; port_register->PIO_ESR |= mask; port_register->PIO_REHLSR |= mask; } if ( samg5x_irq_trigger == IOPORT_SENSE_FALLING || samg5x_irq_trigger == IOPORT_SENSE_BOTHEDGES ) { port_register->PIO_AIMER |= mask; port_register->PIO_ESR |= mask; port_register->PIO_FELLSR |= mask; } /* Read ISR to clear residual interrupt status */ temp = port_register->PIO_ISR; UNUSED_PARAMETER( temp ); /* Enable interrupt source */ port_register->PIO_IER |= mask; NVIC_EnableIRQ( irq_vectors[port] ); exit: platform_mcu_powersave_enable(); return err; }
/** * \brief Initialize USART in SPI master mode. * * This function initializes the USART module in SPI master mode using the * usart_spi_options_t configuration structure and CPU frequency. * * \param usart The USART module. * \param opt The RS232 configuration option. */ void usart_init_spi(USART_t *usart, const usart_spi_options_t *opt) { usart_enable_module_clock(usart); usart_set_mode(usart, USART_CMODE_MSPI_gc); port_pin_t sck_pin; if (opt->spimode == 1 || opt->spimode == 3) { //! \todo Fix when UCPHA_bm is added to header file. usart->CTRLC |= 0x02; } else { //! \todo Fix when UCPHA_bm is added to header file. usart->CTRLC &= ~0x02; } // configure Clock polarity using INVEN bit of the correct SCK I/O port if (opt->spimode == 2 || opt->spimode == 3) { #ifdef USARTC0 if ((uint16_t)usart == (uint16_t)&USARTC0) { sck_pin = IOPORT_CREATE_PIN(PORTC, 1); ioport_configure_port_pin(ioport_pin_to_port(sck_pin), ioport_pin_to_mask(sck_pin), IOPORT_DIR_OUTPUT | IOPORT_INIT_HIGH | IOPORT_INV_ENABLED); } #endif #ifdef USARTC1 if ((uint16_t)usart == (uint16_t)&USARTC1) { sck_pin = IOPORT_CREATE_PIN(PORTC, 5); ioport_configure_port_pin(ioport_pin_to_port(sck_pin), ioport_pin_to_mask(sck_pin), IOPORT_DIR_OUTPUT | IOPORT_INIT_HIGH | IOPORT_INV_ENABLED); } #endif #ifdef USARTD0 if ((uint16_t)usart == (uint16_t)&USARTD0) { sck_pin = IOPORT_CREATE_PIN(PORTD, 1); ioport_configure_port_pin(ioport_pin_to_port(sck_pin), ioport_pin_to_mask(sck_pin), IOPORT_DIR_OUTPUT | IOPORT_INIT_HIGH | IOPORT_INV_ENABLED); } #endif #ifdef USARTD1 if ((uint16_t)usart == (uint16_t)&USARTD1) { sck_pin = IOPORT_CREATE_PIN(PORTD, 5); ioport_configure_port_pin(ioport_pin_to_port(sck_pin), ioport_pin_to_mask(sck_pin), IOPORT_DIR_OUTPUT | IOPORT_INIT_HIGH | IOPORT_INV_ENABLED); } #endif #ifdef USARTE0 if ((uint16_t)usart == (uint16_t)&USARTE0) { sck_pin = IOPORT_CREATE_PIN(PORTE, 1); ioport_configure_port_pin(ioport_pin_to_port(sck_pin), ioport_pin_to_mask(sck_pin), IOPORT_DIR_OUTPUT | IOPORT_INIT_HIGH | IOPORT_INV_ENABLED); } #endif #ifdef USARTE1 if ((uint16_t)usart == (uint16_t)&USARTE1) { sck_pin = IOPORT_CREATE_PIN(PORTE, 5); ioport_configure_port_pin(ioport_pin_to_port(sck_pin), ioport_pin_to_mask(sck_pin), IOPORT_DIR_OUTPUT | IOPORT_INIT_HIGH | IOPORT_INV_ENABLED); } #endif #ifdef USARTF0 if ((uint16_t)usart == (uint16_t)&USARTF0) { sck_pin = IOPORT_CREATE_PIN(PORTF, 1); ioport_configure_port_pin(ioport_pin_to_port(sck_pin), ioport_pin_to_mask(sck_pin), IOPORT_DIR_OUTPUT | IOPORT_INIT_HIGH | IOPORT_INV_ENABLED); } #endif #ifdef USARTF1 if ((uint16_t)usart == (uint16_t)&USARTF1) { sck_pin = IOPORT_CREATE_PIN(PORTF, 5); ioport_configure_port_pin(ioport_pin_to_port(sck_pin), ioport_pin_to_mask(sck_pin), IOPORT_DIR_OUTPUT | IOPORT_INIT_HIGH | IOPORT_INV_ENABLED); } #endif } usart_spi_set_baudrate(usart, opt->baudrate, sysclk_get_per_hz()); usart_tx_enable(usart); usart_rx_enable(usart); }
/*! \brief Install a sensor interrupt handler * * The Sensors Xplained add-on boards route sensor device I/O pins to GPIO * pins for the MCU installed on an Xplained platform board. Some sensor * devices can be configured to generate interrupts on these pins to indicate * the availability of new sensor data or the occurrence of configurable * events related to sensor data thresholds, for example. * * This routine will enable interrupts on the GPIO pin specified by the * \c gpio_pin parameter and call a user-defined callback \c handler when an * interrupt is detected. The \c arg parameter is used to pass the address * of user-defined input and output storage for the callback handler. Calling * the routine with the \c handler parameter set to 0 (the NULL pointer) will * fail with \c false returned to the caller. * * \param gpio_pin Board-specific GPIO pin interface to the MCU. * \param handler The address of a driver-defined interrupt handler. * \param arg An optional address passed to the interrupt handler. * * \return bool true if the call succeeds, else false. */ bool sensor_board_irq_connect(uint32_t gpio_pin, SENSOR_IRQ_HANDLER handler, void *arg) { bool status = false; #if XMEGA PORT_t *sensor_port; #endif /* Ensure that the caller has specified a function address. */ if (handler == NULL) { return status; } /* Save the interrupt flag state and disable MCU interrupts. */ irqflags_t const irq_flags = cpu_irq_save(); cpu_irq_disable(); /* Initialize an interrupt for a specified I/O pin. */ if (SENSOR_BOARD_PIN3 == gpio_pin) { sensor_pin3_handler = handler; sensor_pin3_arg = arg; #if UC3 # if defined(SENSOR_PIN3_EIC_LINE) eic_irq_connect(SENSOR_PIN3_EIC_LINE, SENSOR_PIN3_EIC_PIN, SENSOR_PIN3_EIC_FUNC, SENSOR_PIN3_EIC_IRQ, eic_pin3_handler); # else gpio_irq_connect(gpio_pin, SENSOR_PIN3_IRQ); # endif #elif XMEGA sensor_port = ioport_pin_to_port(SENSOR_BOARD_PIN3); sensor_port->INTCTRL = PORT_INT0LVL_LO_gc; sensor_port->INT0MASK |= ioport_pin_to_mask(SENSOR_BOARD_PIN3); /* Some Xplained kits have limited asynchronous sensing on most * pins, which requires them to be sensing on both edges. */ ioport_set_pin_sense_mode(SENSOR_BOARD_PIN3, IOPORT_SENSE_BOTHEDGES); #endif status = true; } else if (SENSOR_BOARD_PIN4 == gpio_pin) { sensor_pin4_handler = handler; sensor_pin4_arg = arg; #if UC3 # if defined(SENSOR_PIN4_EIC_LINE) eic_irq_connect(SENSOR_PIN4_EIC_LINE, SENSOR_PIN4_EIC_PIN, SENSOR_PIN4_EIC_FUNC, SENSOR_PIN4_EIC_IRQ, eic_pin4_handler); # else gpio_irq_connect(gpio_pin, SENSOR_PIN4_IRQ); # endif #elif XMEGA sensor_port = ioport_pin_to_port(SENSOR_BOARD_PIN4); sensor_port->INTCTRL = PORT_INT0LVL_LO_gc; sensor_port->INT0MASK |= ioport_pin_to_mask(SENSOR_BOARD_PIN4); /* Some Xplained kits have limited asynchronous sensing on most * pins, which requires them to be sensing on both edges. */ ioport_set_pin_sense_mode(SENSOR_BOARD_PIN4, IOPORT_SENSE_BOTHEDGES); #endif status = true; } else if (SENSOR_BOARD_PIN5 == gpio_pin) { sensor_pin5_handler = handler; sensor_pin5_arg = arg; #if UC3 # if defined(SENSOR_PIN5_EIC_LINE) eic_irq_connect(SENSOR_PIN5_EIC_LINE, SENSOR_PIN5_EIC_PIN, SENSOR_PIN5_EIC_FUNC, SENSOR_PIN5_EIC_IRQ, eic_pin5_handler); # else gpio_irq_connect(gpio_pin, SENSOR_PIN5_IRQ); # endif #elif XMEGA sensor_port = ioport_pin_to_port(SENSOR_BOARD_PIN5); sensor_port->INTCTRL = PORT_INT0LVL_LO_gc; sensor_port->INT0MASK |= ioport_pin_to_mask(SENSOR_BOARD_PIN5); /* Some Xplained kits have limited asynchronous sensing on most * pins, which requires them to be sensing on both edges. */ ioport_set_pin_sense_mode(SENSOR_BOARD_PIN5, IOPORT_SENSE_BOTHEDGES); #endif status = true; } /* Restore the MCU interrupt flag state. */ cpu_irq_restore(irq_flags); return status; }