From b1f456ee98ebad3d7520d6eed439d23721c99e7f Mon Sep 17 00:00:00 2001 From: vimalrajr Date: Thu, 2 Jul 2015 11:54:32 +0530 Subject: [PATCH] Adding pinmap functions and common mux pading logic for SERCOM --- .../TARGET_SAM21/PeripheralNames.h | 17 ++ .../TARGET_SAM21/PeripheralPins.h | 3 + .../TARGET_SAMR21G18A/PeripheralPins.c | 57 +++++ .../hal/TARGET_Atmel/TARGET_SAM21/objects.h | 1 + .../hal/TARGET_Atmel/TARGET_SAM21/pinmap.c | 108 +++++++++ .../TARGET_SAM21/pinmap_function.c | 207 ++++++++++++++++++ .../TARGET_SAM21/pinmap_function.h | 82 +++++++ .../hal/TARGET_Atmel/TARGET_SAM21/spi_api.c | 157 ++++++++----- 8 files changed, 572 insertions(+), 60 deletions(-) create mode 100644 libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM21/pinmap.c create mode 100644 libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM21/pinmap_function.c create mode 100644 libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM21/pinmap_function.h diff --git a/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM21/PeripheralNames.h b/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM21/PeripheralNames.h index 7f7fef0b98..cf2acbaaa7 100644 --- a/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM21/PeripheralNames.h +++ b/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM21/PeripheralNames.h @@ -27,6 +27,9 @@ extern "C" { #define _SERCOM_SPI_NAME(n, unused) \ SPI##n, +#define _SERCOM_PAD_NAME(n, pad) \ + SERCOM##n##_PAD##pad = ((n & 0xF) | ((pad & 0xF) << 4)), + #define _SERCOM_I2C_NAME(n, unused) \ I2C##n, @@ -76,6 +79,20 @@ typedef enum { typedef enum { MREPEAT(SERCOM_INST_NUM, _SERCOM_I2C_NAME, ~) } I2CName; + +typedef enum { + /* Pad 0 definitions */ + MREPEAT(SERCOM_INST_NUM, _SERCOM_PAD_NAME, 0) + + /* Pad 1 definitions */ + MREPEAT(SERCOM_INST_NUM, _SERCOM_PAD_NAME, 1) + + /* Pad 2 definitions */ + MREPEAT(SERCOM_INST_NUM, _SERCOM_PAD_NAME, 2) + + /* Pad 3 definitions */ + MREPEAT(SERCOM_INST_NUM, _SERCOM_PAD_NAME, 3) +} SercomPadName; /* typedef enum { PWM_1 = 1, diff --git a/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM21/PeripheralPins.h b/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM21/PeripheralPins.h index eb8b18ea4d..c6aab215b4 100644 --- a/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM21/PeripheralPins.h +++ b/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM21/PeripheralPins.h @@ -39,6 +39,9 @@ extern const PinMap PinMap_ADC[]; extern const PinMap PinMap_UART_TX[]; extern const PinMap PinMap_UART_RX[]; +extern const PinMap PinMap_SERCOM_PAD[]; +extern const PinMap PinMap_SERCOM_PADEx[]; + /************SPI***************/ //extern const PinMap PinMap_SPI_SCLK[]; //extern const PinMap PinMap_SPI_MOSI[]; diff --git a/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM21/TARGET_SAMR21G18A/PeripheralPins.c b/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM21/TARGET_SAMR21G18A/PeripheralPins.c index 80db805efa..c8fc9c5f76 100644 --- a/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM21/TARGET_SAMR21G18A/PeripheralPins.c +++ b/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM21/TARGET_SAMR21G18A/PeripheralPins.c @@ -48,6 +48,62 @@ const PinMap PinMap_ADC[] = { const PinMap PinMap_DAC[] = { }; +/************SERCOM Pins***********/ +const PinMap PinMap_SERCOM_PAD[] = { + {PA04, SERCOM0_PAD0, 3}, + {PA05, SERCOM0_PAD1, 3}, + {PA06, SERCOM0_PAD2, 3}, + {PA07, SERCOM0_PAD3, 3}, + {PA08, SERCOM0_PAD0, 2}, + {PA09, SERCOM0_PAD1, 2}, + {PA12, SERCOM2_PAD0, 2}, + {PA13, SERCOM2_PAD1, 2}, + {PA14, SERCOM2_PAD2, 2}, + {PA15, SERCOM2_PAD3, 2}, + {PA16, SERCOM1_PAD0, 2}, + {PA17, SERCOM1_PAD1, 2}, + {PA18, SERCOM1_PAD2, 2}, + {PA19, SERCOM1_PAD3, 2}, + {PA22, SERCOM3_PAD0, 2}, + {PA23, SERCOM3_PAD1, 2}, + {PA24, SERCOM3_PAD2, 2}, + {PA25, SERCOM3_PAD3, 2}, + {PA27, SERCOM3_PAD0, 5}, + {PA28, SERCOM3_PAD1, 5}, + {PB02, SERCOM5_PAD0, 3}, + {PB03, SERCOM5_PAD1, 3}, + {PB22, SERCOM5_PAD2, 3}, + {PB23, SERCOM5_PAD3, 3}, + {PB30, SERCOM4_PAD2, 5}, + {PB31, SERCOM4_PAD1, 5}, + {PC18, SERCOM4_PAD3, 5}, + {PC19, SERCOM4_PAD0, 5}, + + /* Not connected */ + {NC , NC , NC} +}; + +/*******SERCOM Pins extended*******/ +const PinMap PinMap_SERCOM_PADEx[] = { + {PA00, SERCOM1_PAD0, 3}, + {PA01, SERCOM1_PAD1, 3}, + {PA08, SERCOM2_PAD0, 3}, + {PA09, SERCOM2_PAD1, 3}, + {PA16, SERCOM3_PAD0, 3}, + {PA17, SERCOM3_PAD1, 3}, + {PA18, SERCOM3_PAD2, 3}, + {PA19, SERCOM3_PAD3, 3}, + {PA22, SERCOM5_PAD0, 3}, + {PA23, SERCOM5_PAD1, 3}, + {PA24, SERCOM5_PAD2, 3}, + {PA25, SERCOM5_PAD3, 3}, + {PA30, SERCOM1_PAD2, 3}, + {PA31, SERCOM1_PAD3, 3}, + + /* Not connected */ + {NC , NC , NC} +}; + /************I2C***************/ const PinMap PinMap_I2C_SDA[] = { }; @@ -432,6 +488,7 @@ uint32_t find_sercom_pinmux (struct pin_values* PinValues) } break; } + return NC; } uint32_t find_mux_setting (PinName output, PinName input, PinName clock, PinName chipsel) { diff --git a/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM21/objects.h b/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM21/objects.h index 8111c29b6c..4b70819087 100644 --- a/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM21/objects.h +++ b/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM21/objects.h @@ -92,6 +92,7 @@ struct i2c_s { struct spi_s { Sercom *spi; uint8_t mode; + PinName pins[4]; #if DEVICE_SPI_ASYNCH uint8_t status; uint32_t mask; diff --git a/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM21/pinmap.c b/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM21/pinmap.c new file mode 100644 index 0000000000..ae217cf18f --- /dev/null +++ b/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM21/pinmap.c @@ -0,0 +1,108 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include "us_ticker_api.h" +#include "cmsis.h" +#include "mbed_assert.h" +#include "ins_gclk.h" +#include "compiler.h" +#include "system.h" + +#include "pinmux.h" +#include "pinmap.h" + +extern uint8_t g_sys_init; + + +static inline void pinmux_get_current_config(PinName pin, struct system_pinmux_config *const config) +{ + MBED_ASSERT(pin != (PinName)NC); + uint32_t pin_index = pin % 32; + uint32_t pin_mask = (uint32_t)(1UL << pin_index); + + PortGroup *const port = system_pinmux_get_group_from_gpio_pin(pin); + MBED_ASSERT(port); + + config->mux_position = system_pinmux_pin_get_mux_position(pin); + + if (port->PINCFG[pin_index].reg & PORT_PINCFG_INEN) { + if (port->DIR.reg & pin_mask) { + config->direction = SYSTEM_PINMUX_PIN_DIR_OUTPUT_WITH_READBACK; + config->input_pull = SYSTEM_PINMUX_PIN_PULL_NONE; + } else { + config->direction = SYSTEM_PINMUX_PIN_DIR_INPUT; + if (port->PINCFG[pin_index].reg & PORT_PINCFG_PULLEN) { + if (port->OUT.reg & pin_mask) { + config->input_pull = SYSTEM_PINMUX_PIN_PULL_UP; + } else { + config->input_pull = SYSTEM_PINMUX_PIN_PULL_DOWN; + } + } else { + config->input_pull = SYSTEM_PINMUX_PIN_PULL_NONE; + } + } + } else { + config->input_pull = SYSTEM_PINMUX_PIN_PULL_NONE; + config->direction = SYSTEM_PINMUX_PIN_DIR_OUTPUT; + } + + /* Not relevant for now */ + config->powersave = false; +} + +/** Change the MUX padding of input pin + * + * Configure the pin for specific module + * @param[in] pin Pin name whose MUX padding is to be changed + * @param[in] function The MUX mode to be selected + * @return void + */ +void pin_function(PinName pin, int function) +{ + MBED_ASSERT(pin != (PinName)NC); + + struct system_pinmux_config pin_conf; + + pinmux_get_current_config(pin, &pin_conf); + pin_conf.mux_position = function; + + system_pinmux_pin_set_config(pin, &pin_conf); +} + +/** Change the pin pull mode + * + * Configure the pin pull mode + * @param[in] pin Pin name whose MUX padding is to be changed + * @param[in] mode Pin pull mode to be set + * @return void + */ +void pin_mode(PinName pin, PinMode mode) +{ + MBED_ASSERT(pin != (PinName)NC); + + struct system_pinmux_config pin_conf; + + pinmux_get_current_config(pin, &pin_conf); + if (mode == PullUp) { + pin_conf.input_pull = SYSTEM_PINMUX_PIN_PULL_UP; + } else if (mode == PullDown) { + pin_conf.input_pull = SYSTEM_PINMUX_PIN_PULL_DOWN; + } else { + pin_conf.input_pull = SYSTEM_PINMUX_PIN_PULL_NONE; + } + + system_pinmux_pin_set_config(pin, &pin_conf); +} \ No newline at end of file diff --git a/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM21/pinmap_function.c b/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM21/pinmap_function.c new file mode 100644 index 0000000000..5e122796fb --- /dev/null +++ b/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM21/pinmap_function.c @@ -0,0 +1,207 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include "us_ticker_api.h" +#include "cmsis.h" +#include "mbed_assert.h" +#include "ins_gclk.h" +#include "compiler.h" +#include "system.h" + +#include "pinmap_function.h" + +/** Find the common SERCOM shared by two pins + * + * Finds the common SERCOM index of two input pins. + * If swapping the input argument gives different result, it means, two SERCOMs share both pins + * @param[in] pin1 First pin + * @param[in] pin2 Second pin + * @return SERCOM index if found, else, NC + */ +uint32_t pinmap_merge_sercom(PinName pin1, PinName pin2) +{ + int i, j; + uint32_t pin1_sercom[2]; + uint32_t pin2_sercom[2]; + uint32_t sercom_index[4]; + + uint32_t pin_com = NC; + uint32_t pin_alt = NC; + uint32_t count_com = 0; + uint32_t count_alt = 0; + + /* Adding a condition check just in case we need a different result when swapping arguments */ + if (pin1 >= pin2) { + pin1_sercom[0] = pinmap_find_peripheral(pin1, PinMap_SERCOM_PAD); + pin1_sercom[1] = pinmap_find_peripheral(pin1, PinMap_SERCOM_PADEx); + } else { + pin1_sercom[0] = pinmap_find_peripheral(pin1, PinMap_SERCOM_PADEx); + pin1_sercom[1] = pinmap_find_peripheral(pin1, PinMap_SERCOM_PAD); + } + + pin2_sercom[0] = pinmap_find_peripheral(pin2, PinMap_SERCOM_PAD); + pin2_sercom[1] = pinmap_find_peripheral(pin2, PinMap_SERCOM_PADEx); + + for (i=0; i<2; i++) { + if (pin1_sercom[i] != NC) { + pin1_sercom[i] &= 0x0F; + } + for (j=0; j<2; j++) { + if (pin2_sercom[i] != NC) { + pin2_sercom[i] &= 0x0F; + } + sercom_index[(i*2) + j] = pinmap_merge(pin1_sercom[i], pin2_sercom[j]); + } + } + + for (i=0; i<4; i++) { + if (sercom_index[i] != NC) { + if (pin_com == NC) { + pin_com = sercom_index[i]; + count_com++; + } else if (pin_com == sercom_index[i]) { + count_com++; + } else if (pin_alt == NC) { + pin_alt = sercom_index[i]; + count_alt++; + } else if (pin_alt == sercom_index[i]) { + count_alt++; + } else {} + } + } + return ((count_com >= count_alt) ? pin_com : pin_alt); +} + +/** Find the common SERCOM shared by four pins + * + * Finds the common SERCOM index shared by four input pins. + * If reversing the input argument order gives different result, it means, two SERCOMs share the pins + * @param[in] pin1 First pin + * @param[in] pin2 Second pin + * @param[in] pin3 Third pin + * @param[in] pin4 Fourth pin + * @return SERCOM index if found, else, NC + */ +uint32_t pinmap_find_sercom(PinName pin1, PinName pin2, PinName pin3, PinName pin4) +{ + int i; + uint32_t sercom_index[4]; + uint32_t pin_com = NC; + uint32_t pin_alt = NC; + uint32_t count_com = 0; + uint32_t count_alt = 0; + + sercom_index[0] = pinmap_merge_sercom(pin1, pin2); + sercom_index[1] = pinmap_merge_sercom(pin3, pin3); + sercom_index[2] = pinmap_merge_sercom(pin1, pin3); + sercom_index[3] = pinmap_merge_sercom(pin2, pin4); + + + for (i=0; i<4; i++) { + if (sercom_index[i] != NC) { + if (pin_com == NC) { + pin_com = sercom_index[i]; + count_com++; + } else if (pin_com == sercom_index[i]) { + count_com++; + } else if (pin_alt == NC) { + pin_alt = sercom_index[i]; + count_alt++; + } else if (pin_alt == sercom_index[i]) { + count_alt++; + } else {} + } + } + return ((count_com >= count_alt) ? pin_com : pin_alt); +} + +/** Find the MUX function of input pin specific to given SERCOM index + * + * @param[in] pin Pin whose function is to be found out + * @param[in] sercom_index SERCOM index + * @return MUX function if found, else, NC + */ +uint32_t pinmap_function_sercom(PinName pin, uint32_t sercom_index) +{ + uint32_t func = NC; + uint32_t index; + sercom_index &= 0x0F; + + if ((pin == NC) || (sercom_index >= SERCOM_INST_NUM)) { + return NC; + } + index = pinmap_peripheral(pin, PinMap_SERCOM_PAD); + if ((index & 0x0F) == sercom_index) { + func = pinmap_function(pin, PinMap_SERCOM_PAD); + return func; + } + index = pinmap_peripheral(pin, PinMap_SERCOM_PADEx); + if ((index & 0x0F) == sercom_index) { + func = pinmap_function(pin, PinMap_SERCOM_PADEx); + return func; + } + return NC; +} + +/** Find the MUX pad of input pin specific to given SERCOM index + * + * @param[in] pin Pin whose function is to be found out + * @param[in] sercom_index SERCOM index + * @return MUX pad if found, else, NC + */ +uint32_t pinmap_pad_sercom(PinName pin, uint32_t sercom_index) +{ + uint32_t func = NC; + uint32_t index; + sercom_index &= 0x0F; + + if ((pin == NC) || (sercom_index >= SERCOM_INST_NUM)) { + return NC; + } + index = pinmap_peripheral(pin, PinMap_SERCOM_PAD); + if ((index & 0x0F) == sercom_index) { + return ((index >> 4) & 0x0F); + } + index = pinmap_peripheral(pin, PinMap_SERCOM_PADEx); + if ((index & 0x0F) == sercom_index) { + return ((index >> 4) & 0x0F); + } + return NC; +} + +/** Find the MUX function of input pin specific to given SERCOM index + * + * @param[in] pin unused + * @param[in] sercom_index SERCOM index + * @return base address to SERCOM if found, else NC + */ +uint32_t pinmap_peripheral_sercom(PinName pin, uint32_t sercom_index) +{ + uint32_t sercom_address[6] = { + 0x42000800UL, // Base address of SERCOM0 + 0x42000C00UL, // Base address of SERCOM1 + 0x42001000UL, // Base address of SERCOM2 + 0x42001400UL, // Base address of SERCOM3 + 0x42001800UL, // Base address of SERCOM4 + 0x42001C00UL // Base address of SERCOM5 + }; + uint32_t index = sercom_index & 0x0F; + + if (index >= SERCOM_INST_NUM) { + return NC; + } + return sercom_address[(sercom_index&0x0F)]; +} \ No newline at end of file diff --git a/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM21/pinmap_function.h b/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM21/pinmap_function.h new file mode 100644 index 0000000000..afab1bc2e6 --- /dev/null +++ b/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM21/pinmap_function.h @@ -0,0 +1,82 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef PINMAP_FUNCTION_H +#define PINMAP_FUNCTION_H + +#include +#include "cmsis.h" +#include "PinNames.h" +#include "pinmux.h" +#include "pinmap.h" + +#include "PeripheralPins.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/** Find the common SERCOM shared by two pins + * + * Finds the common SERCOM index of two input pins. + * If swapping the input argument gives different result, it means, two SERCOMs share both pins + * @param[in] pin1 First pin + * @param[in] pin2 Second pin + * @return SERCOM index if found, else, NC + */ +uint32_t pinmap_merge_sercom(PinName pin1, PinName pin2); + +/** Find the common SERCOM shared by four pins + * + * Finds the common SERCOM index shared by four input pins. + * If reversing the input argument order gives different result, it means, two SERCOMs share the pins + * @param[in] pin1 First pin + * @param[in] pin2 Second pin + * @param[in] pin3 Third pin + * @param[in] pin4 Fourth pin + * @return SERCOM index if found, else, NC + */ +uint32_t pinmap_find_sercom(PinName pin1, PinName pin2, PinName pin3, PinName pin4); + +/** Find the MUX function of input pin specific to given SERCOM index + * + * @param[in] pin Pin whose function is to be found out + * @param[in] sercom_index SERCOM index + * @return MUX function if found, else, NC + */ +uint32_t pinmap_function_sercom(PinName pin, uint32_t sercom_index); + +/** Find the MUX pad of input pin specific to given SERCOM index + * + * @param[in] pin Pin whose function is to be found out + * @param[in] sercom_index SERCOM index + * @return MUX pad if found, else, NC + */ +uint32_t pinmap_pad_sercom(PinName pin, uint32_t sercom_index); + +/** Find the MUX function of input pin specific to given SERCOM index + * + * @param[in] pin unused + * @param[in] sercom_index SERCOM index + * @return base address to SERCOM if found, else NC + */ +uint32_t pinmap_peripheral_sercom(PinName pin, uint32_t sercom_index); + +#ifdef __cplusplus +} +#endif + +#endif /* PINMAP_FUNCTION_H */ diff --git a/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM21/spi_api.c b/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM21/spi_api.c index ea0b23c156..6007f25e86 100644 --- a/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM21/spi_api.c +++ b/libraries/mbed/targets/hal/TARGET_Atmel/TARGET_SAM21/spi_api.c @@ -22,27 +22,12 @@ #include "pinmap.h" #include "sercom.h" -/** Temporary definitions START - * Need to implement Pinmux APIs. For now, have hard coded to external SPIs available in SAM21 */ -#ifdef SAMR21 -#define EXT1_SPI_MODULE SERCOM5 -#define EXT1_SPI_SERCOM_MUX_SETTING ((0x1 << SERCOM_SPI_CTRLA_DOPO_Pos) | (0x0 << SERCOM_SPI_CTRLA_DIPO_Pos)) -#define EXT1_SPI_SERCOM_PINMUX_PAD0 PINMUX_PB02D_SERCOM5_PAD0 -#define EXT1_SPI_SERCOM_PINMUX_PAD1 PINMUX_PB03D_SERCOM5_PAD1 -#define EXT1_SPI_SERCOM_PINMUX_PAD2 PINMUX_PB22D_SERCOM5_PAD2 -#define EXT1_SPI_SERCOM_PINMUX_PAD3 PINMUX_PB23D_SERCOM5_PAD3 -#define EXT1_SPI_SERCOM_DMAC_ID_TX SERCOM5_DMAC_ID_TX -#define EXT1_SPI_SERCOM_DMAC_ID_RX SERCOM5_DMAC_ID_RX -#elif SAMD21 -#define EXT1_SPI_MODULE SERCOM0 -#define EXT1_SPI_SERCOM_MUX_SETTING ((0x1 << SERCOM_SPI_CTRLA_DOPO_Pos) | (0x0 << SERCOM_SPI_CTRLA_DIPO_Pos)) -#define EXT1_SPI_SERCOM_PINMUX_PAD0 PINMUX_PA04D_SERCOM0_PAD0 -#define EXT1_SPI_SERCOM_PINMUX_PAD1 PINMUX_PA05D_SERCOM0_PAD1 -#define EXT1_SPI_SERCOM_PINMUX_PAD2 PINMUX_PA06D_SERCOM0_PAD2 -#define EXT1_SPI_SERCOM_PINMUX_PAD3 PINMUX_PA07D_SERCOM0_PAD3 -#define EXT1_SPI_SERCOM_DMAC_ID_TX SERCOM0_DMAC_ID_TX -#define EXT1_SPI_SERCOM_DMAC_ID_RX SERCOM0_DMAC_ID_RX -#endif +#include "pinmap_function.h" + +#define SPI_MOSI_INDEX 0 +#define SPI_MISO_INDEX 1 +#define SPI_SCLK_INDEX 2 +#define SPI_SSEL_INDEX 3 /** Default pinmux. */ # define PINMUX_DEFAULT 0 @@ -221,6 +206,59 @@ static inline bool spi_read(spi_t *obj, uint16_t *rx_data) return true; } +static uint32_t spi_find_mux_settings(spi_t *obj) +{ + /* Sanity check arguments */ + MBED_ASSERT(obj); + uint8_t i_dipo; + uint8_t i_dopo; + uint32_t dipo = 0; + uint32_t dopo = 0; + uint32_t mux_pad; + + uint32_t mux_settings = 0; + + uint32_t sercom_index = _sercom_get_sercom_inst_index(pSPI_SERCOM(obj)); + + if (pSPI_S(obj)->mode == SPI_MODE_MASTER) { + i_dipo = SPI_MISO_INDEX; + i_dopo = SPI_MOSI_INDEX; + } else { + i_dipo = SPI_MOSI_INDEX; + i_dopo = SPI_MISO_INDEX; + } + + /* Find MUX setting */ + if (pSPI_S(obj)->pins[i_dipo] != NC) { + /* Set Data input MUX padding for master */ + mux_pad = pinmap_pad_sercom(pSPI_S(obj)->pins[i_dipo], sercom_index); + if (mux_pad != NC) { + /* MUX pad value is same as DIPO value */ + dipo = mux_pad; + mux_settings |= ((dipo << SERCOM_SPI_CTRLA_DIPO_Pos) & SERCOM_SPI_CTRLA_DIPO_Msk); + } + } + + if (pSPI_S(obj)->pins[i_dopo] != NC) { + /* Set Data output MUX padding for master */ + mux_pad = pinmap_pad_sercom(pSPI_S(obj)->pins[i_dopo], sercom_index); + if (mux_pad != NC) { + if (mux_pad != 0) { + dopo = mux_pad - 1; + } else { + if (3 == pinmap_pad_sercom(pSPI_S(obj)->pins[SPI_SCLK_INDEX], sercom_index)) { + dopo = 3; + } else { + dopo = 0; + } + } + mux_settings |= ((dopo << SERCOM_SPI_CTRLA_DOPO_Pos) & SERCOM_SPI_CTRLA_DOPO_Msk); + } + } + + return mux_settings; +} + /** * \defgroup GeneralSPI SPI Configuration Functions * @{ @@ -247,9 +285,9 @@ void spi_init(spi_t *obj, PinName mosi, PinName miso, PinName sclk, PinName ssel g_sys_init = 1; } - /* TODO: Calculate SERCOM instance from pins */ - /* TEMP: Giving external SPI module value of SAMR21 for now */ - pSPI_SERCOM(obj) = EXT1_SPI_MODULE; + /* Calculate SERCOM instance from pins */ + uint32_t sercom_index = pinmap_find_sercom(mosi, miso, sclk, ssel); + pSPI_SERCOM(obj) = pinmap_peripheral_sercom(NC, sercom_index); /* Disable SPI */ spi_disable(obj); @@ -258,7 +296,7 @@ void spi_init(spi_t *obj, PinName mosi, PinName miso, PinName sclk, PinName ssel if (_SPI(obj).CTRLA.reg & SERCOM_SPI_CTRLA_SWRST) { return; } - uint32_t sercom_index = _sercom_get_sercom_inst_index(pSPI_SERCOM(obj)); + uint32_t pm_index, gclk_index; #if (SAML21) if (sercom_index == 5) { @@ -309,17 +347,20 @@ void spi_init(spi_t *obj, PinName mosi, PinName miso, PinName sclk, PinName ssel system_pinmux_get_config_defaults(&pin_conf); pin_conf.direction = SYSTEM_PINMUX_PIN_DIR_INPUT; - uint32_t pad_pinmuxes[] = { - EXT1_SPI_SERCOM_PINMUX_PAD0, EXT1_SPI_SERCOM_PINMUX_PAD1, - EXT1_SPI_SERCOM_PINMUX_PAD2, EXT1_SPI_SERCOM_PINMUX_PAD3 - }; - + uint32_t mux_func; + pSPI_S(obj)->pins[SPI_MOSI_INDEX] = mosi; + pSPI_S(obj)->pins[SPI_MISO_INDEX] = miso; + pSPI_S(obj)->pins[SPI_SCLK_INDEX] = sclk; + pSPI_S(obj)->pins[SPI_SSEL_INDEX] = ssel; /* Configure the SERCOM pins according to the user configuration */ for (uint8_t pad = 0; pad < 4; pad++) { - uint32_t current_pinmux = pad_pinmuxes[pad]; - if (current_pinmux != PINMUX_UNUSED) { - pin_conf.mux_position = current_pinmux & 0xFFFF; - system_pinmux_pin_set_config(current_pinmux >> 16, &pin_conf); + uint32_t current_pin = pSPI_S(obj)->pins[pad]; + if (current_pin != NC) { + mux_func = pinmap_function_sercom(current_pin, sercom_index); + if (NC != mux_func) { + system_pinmux_pin_set_config(current_pin, &pin_conf); + pin_function(current_pin, mux_func); + } } } @@ -333,8 +374,8 @@ void spi_init(spi_t *obj, PinName mosi, PinName miso, PinName sclk, PinName ssel } _SPI(obj).BAUD.reg = (uint8_t)baud; - /* Set MUX setting */ - ctrla |= EXT1_SPI_SERCOM_MUX_SETTING; /* TODO: Change this to appropriate Settings */ + /* TODO: Find MUX settings */ + ctrla |= spi_find_mux_settings(obj); /* Set SPI character size */ ctrlb |= SERCOM_SPI_CTRLB_CHSIZE(0); @@ -377,37 +418,36 @@ void spi_free(spi_t *obj) */ void spi_format(spi_t *obj, int bits, int mode, int slave) { + PinMode pull_mode; /* Disable SPI */ spi_disable(obj); + uint32_t ctrla = _SPI(obj).CTRLA.reg; + uint32_t sercom_index = _sercom_get_sercom_inst_index(pSPI_SERCOM(obj)); + if (slave) { /* Set the SERCOM in SPI mode */ _SPI(obj).CTRLA.bit.MODE = 0x2; pSPI_S(obj)->mode = SPI_MODE_SLAVE; - - struct system_pinmux_config pin_conf; - system_pinmux_get_config_defaults(&pin_conf); - pin_conf.direction = SYSTEM_PINMUX_PIN_DIR_INPUT; - pin_conf.input_pull = SYSTEM_PINMUX_PIN_PULL_NONE; - - uint32_t pad_pinmuxes[] = { - EXT1_SPI_SERCOM_PINMUX_PAD0, EXT1_SPI_SERCOM_PINMUX_PAD1, - EXT1_SPI_SERCOM_PINMUX_PAD2, EXT1_SPI_SERCOM_PINMUX_PAD3 - }; - - /* Configure the SERCOM pins according to the user configuration */ - for (uint8_t pad = 0; pad < 4; pad++) { - uint32_t current_pinmux = pad_pinmuxes[pad]; - if (current_pinmux != PINMUX_UNUSED) { - pin_conf.mux_position = current_pinmux & 0xFFFF; - system_pinmux_pin_set_config(current_pinmux >> 16, &pin_conf); - } - } + pull_mode = PullNone; } else { - /* Already in SPI master mode */ + /* Set the SERCOM in SPI mode */ + _SPI(obj).CTRLA.bit.MODE = 0x3; + pSPI_S(obj)->mode = SPI_MODE_MASTER; + pull_mode = PullUp; } - /* TODO: Change MUX settings to appropriate value */ + /* Change pull mode of pins */ + for (uint8_t pad = 0; pad < 4; pad++) { + if (pSPI_S(obj)->pins[pad] != NC) { + pin_mode(pSPI_S(obj)->pins[pad], pull_mode); + } + } + + /* Change MUX settings */ + ctrla &= ~(SERCOM_SPI_CTRLA_DIPO_Msk | SERCOM_SPI_CTRLA_DOPO_Msk); + ctrla |= spi_find_mux_settings(obj); + _SPI(obj).CTRLA.reg = ctrla; /* Set SPI Frame size - only 8-bit and 9-bit supported now */ _SPI(obj).CTRLB.bit.CHSIZE = (bits > 8)? 1 : 0; @@ -896,9 +936,6 @@ void spi_master_transfer(spi_t *obj, const void *tx, size_t tx_length, void *rx, uint32_t spi_irq_handler_asynch(spi_t *obj) { uint32_t transfer_event = 0; - uint32_t bytes_to_transfer = 0; - - uint8_t sercom_index = _sercom_get_sercom_inst_index(obj->spi.spi); /*if (obj->spi.dma_usage == DMA_USAGE_NEVER) {** TEMP: Commented as DMA is not implemented now */ /* IRQ method */