diff --git a/atmel-samd/boards/circuitplayground_express/mpconfigboard.h b/atmel-samd/boards/circuitplayground_express/mpconfigboard.h index 243e50358c..c31e7f8eb5 100644 --- a/atmel-samd/boards/circuitplayground_express/mpconfigboard.h +++ b/atmel-samd/boards/circuitplayground_express/mpconfigboard.h @@ -30,6 +30,8 @@ #define MICROPY_PORT_A (PORT_PA16 | PORT_PA20 | PORT_PA21 | PORT_PA24 | PORT_PA25) #define MICROPY_PORT_B (PORT_PB22) +#define SPEAKER_ENABLE_PIN (&pin_PA30) + #define AUTORESET_DELAY_MS 500 #include "spi_flash.h" diff --git a/atmel-samd/common-hal/microcontroller/Pin.c b/atmel-samd/common-hal/microcontroller/Pin.c index 3ac3430b2f..56d8f88393 100644 --- a/atmel-samd/common-hal/microcontroller/Pin.c +++ b/atmel-samd/common-hal/microcontroller/Pin.c @@ -26,6 +26,8 @@ #include "shared-bindings/microcontroller/Pin.h" +#include "asf/sam0/drivers/port/port.h" + #include "rgb_led_status.h" #include "samd21_pins.h" @@ -36,6 +38,47 @@ bool neopixel_in_use; bool apa102_sck_in_use; bool apa102_mosi_in_use; #endif +#ifdef SPEAKER_ENABLE_PIN +bool speaker_enable_in_use; +#endif + +void reset_all_pins(void) { + struct system_pinmux_config config; + system_pinmux_get_config_defaults(&config); + config.powersave = true; + + uint32_t pin_mask[2] = PORT_OUT_IMPLEMENTED; + + // Do not full reset USB or SWD lines. + pin_mask[0] &= ~(PIN_PA24 | PIN_PA25 | PIN_PA30 | PIN_PA31); + + system_pinmux_group_set_config(&(PORT->Group[0]), pin_mask[0] & ~MICROPY_PORT_A, &config); + system_pinmux_group_set_config(&(PORT->Group[1]), pin_mask[1] & ~MICROPY_PORT_B, &config); + + // Configure SWD + system_pinmux_get_config_defaults(&config); + config.mux_position = 0x6; + system_pinmux_group_set_config(&(PORT->Group[0]), PIN_PA30 | PIN_PA31, &config); + + #ifdef MICROPY_HW_NEOPIXEL + neopixel_in_use = false; + #endif + #ifdef MICROPY_HW_APA102_MOSI + apa102_sck_in_use = false; + apa102_mosi_in_use = false; + #endif + + // After configuring SWD because it may be shared. + #ifdef SPEAKER_ENABLE_PIN + speaker_enable_in_use = false; + struct port_config pin_conf; + port_get_config_defaults(&pin_conf); + + pin_conf.direction = PORT_PIN_DIR_OUTPUT; + port_pin_set_config(SPEAKER_ENABLE_PIN->pin, &pin_conf); + port_pin_set_output_level(SPEAKER_ENABLE_PIN->pin, false); + #endif +} void reset_pin(uint8_t pin) { if (pin >= PORT_BITS) { @@ -63,8 +106,24 @@ void reset_pin(uint8_t pin) { struct system_pinmux_config config; system_pinmux_get_config_defaults(&config); - config.powersave = true; + if (pin == PIN_PA30 || pin == PIN_PA31) { + config.mux_position = 0x6; + } else { + config.powersave = true; + } system_pinmux_pin_set_config(pin, &config); + + #ifdef SPEAKER_ENABLE_PIN + if (pin == SPEAKER_ENABLE_PIN->pin) { + speaker_enable_in_use = false; + struct port_config pin_conf; + port_get_config_defaults(&pin_conf); + + pin_conf.direction = PORT_PIN_DIR_OUTPUT; + port_pin_set_config(SPEAKER_ENABLE_PIN->pin, &pin_conf); + port_pin_set_output_level(SPEAKER_ENABLE_PIN->pin, false); + } + #endif } void claim_pin(const mcu_pin_obj_t* pin) { @@ -81,6 +140,12 @@ void claim_pin(const mcu_pin_obj_t* pin) { apa102_sck_in_use = true; } #endif + + #ifdef SPEAKER_ENABLE_PIN + if (pin == SPEAKER_ENABLE_PIN) { + speaker_enable_in_use = true; + } + #endif } bool common_hal_mcu_pin_is_free(const mcu_pin_obj_t* pin) { @@ -98,10 +163,21 @@ bool common_hal_mcu_pin_is_free(const mcu_pin_obj_t* pin) { } #endif + #ifdef SPEAKER_ENABLE_PIN + if (pin == SPEAKER_ENABLE_PIN) { + return !speaker_enable_in_use; + } + #endif + PortGroup *const port = system_pinmux_get_group_from_gpio_pin(pin->pin); uint32_t pin_index = (pin->pin); - PORT_PINCFG_Type state = port->PINCFG[pin_index]; + volatile PORT_PINCFG_Type *state = &port->PINCFG[pin_index]; + volatile PORT_PMUX_Type *pmux = &port->PMUX[pin_index / 2]; - return state.bit.PMUXEN == 0 && state.bit.INEN == 0 && - state.bit.PULLEN == 0 && (port->DIR.reg & (1 << pin_index)) == 0; + if (pin->pin == PIN_PA30 || pin->pin == PIN_PA31) { + return state->bit.PMUXEN == 1 && ((pmux->reg >> (4 * pin_index % 2)) & 0xf) == 0x6; + } + + return state->bit.PMUXEN == 0 && state->bit.INEN == 0 && + state->bit.PULLEN == 0 && (port->DIR.reg & (1 << pin_index)) == 0; } diff --git a/atmel-samd/common-hal/microcontroller/Pin.h b/atmel-samd/common-hal/microcontroller/Pin.h index 27c998e5c5..fdf05885df 100644 --- a/atmel-samd/common-hal/microcontroller/Pin.h +++ b/atmel-samd/common-hal/microcontroller/Pin.h @@ -78,6 +78,7 @@ extern bool apa102_sck_in_use; extern bool apa102_mosi_in_use; #endif +void reset_all_pins(void); // reset_pin takes the pin number instead of the pointer so that objects don't // need to store a full pointer. void reset_pin(uint8_t pin); diff --git a/atmel-samd/main.c b/atmel-samd/main.c index 6184d64ebf..da9c08019c 100644 --- a/atmel-samd/main.c +++ b/atmel-samd/main.c @@ -172,15 +172,7 @@ void reset_samd21(void) { while (DAC->STATUS.reg & DAC_STATUS_SYNCBUSY) {} DAC->CTRLA.reg |= DAC_CTRLA_SWRST; - // Reset pins - struct system_pinmux_config config; - system_pinmux_get_config_defaults(&config); - config.powersave = true; - - uint32_t pin_mask[2] = PORT_OUT_IMPLEMENTED; - - system_pinmux_group_set_config(&(PORT->Group[0]), pin_mask[0] & ~MICROPY_PORT_A, &config); - system_pinmux_group_set_config(&(PORT->Group[1]), pin_mask[1] & ~MICROPY_PORT_B, &config); + reset_all_pins(); audioout_reset(); pwmout_reset();