From 0dee05a843762865bdf226f6c13f8795568ceff1 Mon Sep 17 00:00:00 2001 From: Russ Butler Date: Mon, 21 Jan 2019 16:30:48 -0600 Subject: [PATCH] Add pinmap utility functions Add 2 new pinmap utility functions: -pinmap_find_peripheral_pins -pinmap_list_has_pin Also add the new type PinList which contains a list of pins allowing for NC and duplicate entries. --- hal/mbed_pinmap_common.c | 74 ++++++++++++++++++++++++++++++++++++ hal/pinmap.h | 81 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 155 insertions(+) diff --git a/hal/mbed_pinmap_common.c b/hal/mbed_pinmap_common.c index 0f2083d92e..aff140ea4d 100644 --- a/hal/mbed_pinmap_common.c +++ b/hal/mbed_pinmap_common.c @@ -104,3 +104,77 @@ uint32_t pinmap_function(PinName pin, const PinMap *map) } return function; } + +bool pinmap_find_peripheral_pins(const PinList *whitelist, const PinList *blacklist, int per, const PinMap *const *maps, PinName **pins, uint32_t count) +{ + /* + * This function uses recursion to find a suitable set of pins which meet the requirements. + * Recursion is at max the number of pinmaps passed in - the 'count' parameter. Because of this + * there is no risk of a stack overflow due to unbounded recursion. + * + * Below is a psuedo code example of this function's operation when finding a set of 4 pins. + * The recursion depth is indicated by the number in front. + * + * 1. Given 4 maps and a peripheral find 4 suitable pins + * 2. Given 4 maps, a peripheral and 1 pin find 3 suitable pins + * 3. Given 4 maps, a peripheral and 2 pins find 2 suitable pins + * 4. Given 4 maps, a peripheral and 3 pins find 1 suitable pin + * 4. Return success if all pins are found, return failure if there are no suitable pins, otherwise choose the next pin and retry + * 3. Return success if all pins are found, return failure if there are no suitable pins, otherwise choose the next pin and retry + * 2. Return success if all pins are found, return failure if there are no suitable pins, otherwise choose the next pin and retry + * 1. Return success if all pins are found, return failure if there are no suitable pins, otherwise choose the next pin and retry + * + */ + + for (uint32_t i = 0; i < count; i++) { + const PinMap *map = maps[i]; + PinName *pin = pins[i]; + if (*pin == NC) { + for (; map->pin != NC; map++) { + if (map->peripheral != per) { + continue; + } + if (!pinmap_list_has_pin(whitelist, map->pin)) { + // Not part of this form factor + continue; + } + if (pinmap_list_has_pin(blacklist, map->pin)) { + // Restricted pin + continue; + } + bool already_in_use = false; + for (uint32_t j = 0; j < count; j++) { + if (j == i) { + // Don't compare with self + continue; + } + if (map->pin == *pins[j]) { + already_in_use = true; + break; + } + } + if (already_in_use) { + continue; + } + *pin = map->pin; + if (pinmap_find_peripheral_pins(whitelist, blacklist, per, maps, pins, count)) { + return true; + } + } + *pin = NC; + return false; + } + } + return true; +} + +bool pinmap_list_has_pin(const PinList *list, PinName pin) +{ + for (uint32_t i = 0; i < list->count; i++) { + if (list->pins[i] == pin) { + return true; + } + } + return false; +} + diff --git a/hal/pinmap.h b/hal/pinmap.h index d94892a7c6..bf688cc4e5 100644 --- a/hal/pinmap.h +++ b/hal/pinmap.h @@ -21,6 +21,7 @@ #define MBED_PINMAP_H #include "PinNames.h" +#include #ifdef __cplusplus extern "C" { @@ -32,6 +33,11 @@ typedef struct { int function; } PinMap; +typedef struct { + uint32_t count; + const PinName *pins; +} PinList; + void pin_function(PinName pin, int function); void pin_mode(PinName pin, PinMode mode); @@ -42,6 +48,81 @@ void pinmap_pinout(PinName pin, const PinMap *map); uint32_t pinmap_find_peripheral(PinName pin, const PinMap *map); uint32_t pinmap_find_function(PinName pin, const PinMap *map); +/** + * Find a combination of pins suitable for use given the constraints + * + * This function finds pins which meet these specific properties: + * - The pin is part of the form factor + * - The pin is not in the restricted list + * - The pin is contained within the respective pinmap + * - The pin belongs to the given peripheral + * - Each pin found is distinct; in the example below + * mosi and miso will never be assigned the same pin + * + * Example: + * @code + * #include "mbed.h" + * #include "pinmap.h" + * + * int main() + * { + * int per = spi_master_cs_pinmap()->peripheral; + * const PinList *pins_ff = pinmap_ff_default_pins(); + * const PinList *pins_avoid = pinmap_restricted_pins(); + * PinName mosi = NC; + * PinName miso = NC; + * PinName sclk = NC; + * PinName ssel = NC; + * const PinMap *maps[] = { + * spi_master_mosi_pinmap(), + * spi_master_miso_pinmap(), + * spi_master_clk_pinmap(), + * spi_master_cs_pinmap() + * }; + * PinName *pins[] = { + * &mosi, + * &miso, + * &sclk, + * &ssel + * }; + * if (pinmap_find_peripheral_pins(pins_ff, pins_avoid, per, maps, pins, sizeof(maps) / sizeof(maps[0]))) { + * printf("Found SPI pins to test instance %i with:\n" + * " mosi=%s\n" + * " miso=%s\n" + * " sclk=%s\n" + * " ssel=%s\n", per, + * pinmap_ff_default_pin_to_string(mosi), + * pinmap_ff_default_pin_to_string(miso), + * pinmap_ff_default_pin_to_string(sclk), + * pinmap_ff_default_pin_to_string(ssel)); + * } else { + * printf("Could not find SPI combination to test %i\n", per); + * } + * return 0; + * } + * @endcode + * + * @param whitelist List of pins to choose from + * @param blacklist List of pins which cannot be used + * @param per Peripheral to which the pins belong + * @param maps An array of pin maps to select from + * @param pins An array of pins to find. Pins already set to a value will be + * left unchanged. Only pins initialized to NC will be updated by this function + * @param count The size of maps and pins + * @return true if a suitable combination of pins was found and + * written to the pins array, otherwise false + */ +bool pinmap_find_peripheral_pins(const PinList *whitelist, const PinList *blacklist, int per, const PinMap *const *maps, PinName **pins, uint32_t count); + +/** + * Check if the pin is in the list + * + * @param list pin list to check + * @param pin pin to check for in the list + * @return true if the pin is in the list, false otherwise + */ +bool pinmap_list_has_pin(const PinList *list, PinName pin); + #ifdef __cplusplus } #endif