From ea6c0078c72238e6b30ef835f3d57dfb4c2535ea Mon Sep 17 00:00:00 2001 From: Blackstone Engineering Date: Thu, 22 Feb 2018 20:07:47 -0800 Subject: [PATCH] Extended PeripheralPins and pinmap for NRF52 series The NRF52 series can map digital signals to any physical pin which makes it challenging to associate pin names with hardware instances. pinmap_ex: Keep track of which hardware instance is in use and what pins are associated with it. Currently only supports I2C and SPI, but provides a mechanism for allocating the shared I2C/SPI hardware. PeripheralPinsDefault: Optional pin map for pre-assigning hardware instances at compile time. This makes it easier to optimize hardware utilization. --- .../TARGET_NRF5x/PeripheralPinsDefault.c | 32 +++ .../TARGET_NORDIC/TARGET_NRF5x/pinmap_ex.c | 248 ++++++++++++++++++ .../TARGET_NORDIC/TARGET_NRF5x/pinmap_ex.h | 90 +++++++ 3 files changed, 370 insertions(+) create mode 100644 targets/TARGET_NORDIC/TARGET_NRF5x/PeripheralPinsDefault.c create mode 100644 targets/TARGET_NORDIC/TARGET_NRF5x/pinmap_ex.c create mode 100644 targets/TARGET_NORDIC/TARGET_NRF5x/pinmap_ex.h diff --git a/targets/TARGET_NORDIC/TARGET_NRF5x/PeripheralPinsDefault.c b/targets/TARGET_NORDIC/TARGET_NRF5x/PeripheralPinsDefault.c new file mode 100644 index 0000000000..255763e9e5 --- /dev/null +++ b/targets/TARGET_NORDIC/TARGET_NRF5x/PeripheralPinsDefault.c @@ -0,0 +1,32 @@ +/* mbed Microcontroller Library + * Copyright (c) 2018 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 "pinmap_ex.h" +#include "mbed_toolchain.h" + +/* Default mapping between I2C pins and I2C instance. + * Can be overwritten by user. + */ +MBED_WEAK const PinMapI2C PinMap_I2C[1] = { + {NC, NC, NC} +}; + +/* Default mapping between SPI pins and SPI instance. + * Can be overwritten by user. + */ +MBED_WEAK const PinMapSPI PinMap_SPI[1] = { + {NC, NC, NC, NC} +}; diff --git a/targets/TARGET_NORDIC/TARGET_NRF5x/pinmap_ex.c b/targets/TARGET_NORDIC/TARGET_NRF5x/pinmap_ex.c new file mode 100644 index 0000000000..1e1bf7fddf --- /dev/null +++ b/targets/TARGET_NORDIC/TARGET_NRF5x/pinmap_ex.c @@ -0,0 +1,248 @@ +/* mbed Microcontroller Library + * Copyright (c) 2018 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 "pinmap_ex.h" + +#include "mbed_toolchain.h" +#include "nrf.h" +#include "nrf_peripherals.h" + +#include + +#if 0 +#define DEBUG_PRINTF(...) do { printf(__VA_ARGS__); } while(0) +#else +#define DEBUG_PRINTF(...) {} +#endif + +/* Define number of instances */ +#define NORDIC_TWI_COUNT TWI_COUNT +#define NORDIC_SPI_COUNT SPI_COUNT + +/* Define which instance to return when there are no free instances left. + * The Mbed HAL API doesn't provide a way for signaling initialization errors + * so we return the default value. Any instance conflicts must be handled + * by the driver implementation. + */ +#define DEFAULT_I2C_INSTANCE 0 // SPI counts down, choose instance furthest away +#define DEFAULT_SPI_INSTANCE (SPI_COUNT - 1) // I2C counts up, choose instance furthers away + +/* Internal data structure shared between SPI and I2C to keep track of allocated + * instances. The data structure is shared to reflect the hardware sharing. + */ +typedef struct { + PinName locaction0; + PinName locaction1; + PinName locaction2; +} spi2c_t; + +static spi2c_t nordic_internal_spi2c[3] = { + {NC, NC, NC}, + {NC, NC, NC}, + {NC, NC, NC}, +}; + +/** + * Brief Find hardware instance for the provided I2C pins. + * + * The function will search the PeripheralPin map for a pre-allocated + * assignment. If none is found the allocation map will be searched + * to see if the same pins have been assigned an instance before. + * + * If no assignement is found and there is an empty slot left in the + * map, the pins are stored in the map and the hardware instance is + * returned. + * + * If no free instances are available, the default instance is returned. + * + * Parameter sda sda pin. + * Parameter scl scl pin. + * + * Return Hardware instance associated with provided pins. + */ +int pin_instance_i2c(PinName sda, PinName scl) +{ + int instance = NC; + + /* Search pin map for pre-allocated instance */ + for (size_t index = 0; + !((PinMap_I2C[index].sda == NC) && + (PinMap_I2C[index].scl == NC)); + index++) { + + /* Compare pins to entry. */ + if ((PinMap_I2C[index].sda == sda) && + (PinMap_I2C[index].scl == scl)) { + + DEBUG_PRINTF("found: %d %d %d\r\n", sda, scl, PinMap_I2C[index].instance); + + /* Instance found, save result. */ + instance = PinMap_I2C[index].instance; + + /* Lock out entry in map to prevent SPI from grabbing it. */ + nordic_internal_spi2c[instance].locaction0 = sda; + nordic_internal_spi2c[instance].locaction1 = scl; + nordic_internal_spi2c[instance].locaction2 = NC; + break; + } + } + + /* No instance was found in static map. */ + if (instance == NC) { + + /* Search dynamic map for entry. */ + for (size_t index = 0; index < NORDIC_TWI_COUNT; index++) { + + /* Pins match previous dynamic allocation, return instance. */ + if ((nordic_internal_spi2c[index].locaction0 == sda) && + (nordic_internal_spi2c[index].locaction1 == scl) && + (nordic_internal_spi2c[index].locaction2 == NC)) { + + instance = index; + break; + } + } + } + + /* No instance was found in dynamic map. */ + if (instance == NC) { + + /* Search dynamic map for empty slot. */ + for (size_t index = 0; index < NORDIC_TWI_COUNT; index++) { + + /* Empty slot found, reserve slot by storing pins. */ + if ((nordic_internal_spi2c[index].locaction0 == NC) && + (nordic_internal_spi2c[index].locaction1 == NC) && + (nordic_internal_spi2c[index].locaction2 == NC)) { + + nordic_internal_spi2c[index].locaction0 = sda; + nordic_internal_spi2c[index].locaction1 = scl; + + instance = index; + break; + } + } + } + +#if defined(DEFAULT_I2C_INSTANCE) + /* Exhausted all options. Return default value. */ + if (instance == NC) { + instance = DEFAULT_I2C_INSTANCE; + } +#endif + + DEBUG_PRINTF("I2C: %d %d %d\r\n", sda, scl, instance); + + return instance; +} + +/** + * Brief Find hardware instance for the provided SPI pins. + * + * The function will search the PeripheralPin map for a pre-allocated + * assignment. If none is found the allocation map will be searched + * to see if the same pins have been assigned an instance before. + * + * If no assignement is found and there is an empty slot left in the + * map, the pins are stored in the map and the hardware instance is + * returned. + * + * If no free instances are available, the default instance is returned. + * + * Parameter mosi mosi pin. + * Parameter miso miso pin. + * Parameter clk clk pin. + * + * Return Hardware instance associated with provided pins. + */ +int pin_instance_spi(PinName mosi, PinName miso, PinName clk) +{ + int instance = NC; + + /* Search pin map for pre-allocated instance */ + for (size_t index = 0; + !((PinMap_SPI[index].mosi == NC) && + (PinMap_SPI[index].miso == NC) && + (PinMap_SPI[index].clk == NC)); + index++) { + + DEBUG_PRINTF("search: %d %d %d\r\n", PinMap_SPI[index].mosi, PinMap_SPI[index].miso, PinMap_SPI[index].clk); + + /* Compare pins to entry. */ + if ((PinMap_SPI[index].mosi == mosi) && + (PinMap_SPI[index].miso == miso) && + (PinMap_SPI[index].clk == clk)) { + + DEBUG_PRINTF("found: %d %d %d %d\r\n", mosi, miso, clk, PinMap_SPI[index].instance); + + /* Foung instance, save result. */ + instance = PinMap_SPI[index].instance; + + /* Lock out entry in map to prevent I2C from grabbing it. */ + nordic_internal_spi2c[instance].locaction0 = mosi; + nordic_internal_spi2c[instance].locaction1 = miso; + nordic_internal_spi2c[instance].locaction2 = clk; + break; + } + } + + /* No instance was found in static map. */ + if (instance == NC) { + + /* Search dynamic map for entry. */ + for (int index = NORDIC_SPI_COUNT - 1; index > -1; index--) { + if ((nordic_internal_spi2c[index].locaction0 == mosi) && + (nordic_internal_spi2c[index].locaction1 == miso) && + (nordic_internal_spi2c[index].locaction2 == clk)) { + + instance = index; + break; + } + } + } + + /* No instance was found in dynamic map. */ + if (instance == NC) { + + /* Search dynamic map for empty slot. */ + for (int index = NORDIC_SPI_COUNT - 1; index > -1; index--) { + + /* Empty slot found, reserve slot by storing pins. */ + if ((nordic_internal_spi2c[index].locaction0 == NC) && + (nordic_internal_spi2c[index].locaction1 == NC) && + (nordic_internal_spi2c[index].locaction2 == NC)) { + + nordic_internal_spi2c[index].locaction0 = mosi; + nordic_internal_spi2c[index].locaction1 = miso; + nordic_internal_spi2c[index].locaction2 = clk; + + instance = index; + break; + } + } + } + +#if defined(DEFAULT_SPI_INSTANCE) + /* Exhausted all options. Return default value. */ + if (instance == NC) { + instance = DEFAULT_SPI_INSTANCE; + } +#endif + + DEBUG_PRINTF("SPI: %d %d %d %d\r\n", mosi, miso, clk, instance); + + return instance; +} diff --git a/targets/TARGET_NORDIC/TARGET_NRF5x/pinmap_ex.h b/targets/TARGET_NORDIC/TARGET_NRF5x/pinmap_ex.h new file mode 100644 index 0000000000..067a0ea86d --- /dev/null +++ b/targets/TARGET_NORDIC/TARGET_NRF5x/pinmap_ex.h @@ -0,0 +1,90 @@ +/* mbed Microcontroller Library + * Copyright (c) 2018 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_EX_H +#define PINMAP_EX_H + +#include "PinNames.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Data structure for pre-allocated I2C instances. */ +typedef struct { + PinName sda; + PinName scl; + int instance; +} PinMapI2C; + +extern const PinMapI2C PinMap_I2C[]; + +/* Data structure for pre-allocated SPI instances. */ +typedef struct { + PinName mosi; + PinName miso; + PinName clk; + int instance; +} PinMapSPI; + +extern const PinMapSPI PinMap_SPI[]; + +/** + * @brief Find hardware instance for the provided I2C pins. + * + * The function will search the PeripheralPin map for a pre-allocated + * assignment. If none is found the allocation map will be searched + * to see if the same pins have been assigned an instance before. + * + * If no assignement is found and there is an empty slot left in the + * map, the pins are stored in the map and the hardware instance is + * returned. + * + * If no free instances are available, the default instance is returned. + * + * @param[in] sda sda pin. + * @param[in] scl scl pin. + * + * @return Hardware instance associated with provided pins. + */ +int pin_instance_i2c(PinName sda, PinName scl); + +/** + * @brief Find hardware instance for the provided SPI pins. + * + * The function will search the PeripheralPin map for a pre-allocated + * assignment. If none is found the allocation map will be searched + * to see if the same pins have been assigned an instance before. + * + * If no assignement is found and there is an empty slot left in the + * map, the pins are stored in the map and the hardware instance is + * returned. + * + * If no free instances are available, the default instance is returned. + * + * @param[in] mosi mosi pin. + * @param[in] miso miso pin. + * @param[in] clk clk pin. + * + * @return Hardware instance associated with provided pins. + */ +int pin_instance_spi(PinName mosi, PinName miso, PinName clk); + +#ifdef __cplusplus +} +#endif + +#endif // PINMAP_EX_H