Skip to content

Pinmap extensions #9449

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 14 commits into from
Feb 11, 2019
  •  
  •  
  •  
127 changes: 127 additions & 0 deletions TESTS/mbed_hal/pinmap/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
/* mbed Microcontroller Library
* Copyright (c) 2019 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 "utest/utest.h"
#include "unity/unity.h"
#include "greentea-client/test_env.h"

using namespace utest::v1;

#include "analogin_api.h"
#include "analogout_api.h"
#include "can_api.h"
#include "i2c_api.h"
#include "pwmout_api.h"
#include "qspi_api.h"
#include "serial_api.h"
#include "spi_api.h"

#define PINMAP_TEST_ENTRY(function) {function, #function}

typedef const PinMap *(*get_pinmap_func_t)(void);
typedef struct {
get_pinmap_func_t function;
const char *name;
} pinmap_info_t;

const pinmap_info_t pinmap_functions[] = {
#if DEVICE_ANALOGIN
PINMAP_TEST_ENTRY(analogin_pinmap),
#endif
#if DEVICE_ANALOGOUT
PINMAP_TEST_ENTRY(analogout_pinmap),
#endif
#if DEVICE_CAN
PINMAP_TEST_ENTRY(can_rd_pinmap),
PINMAP_TEST_ENTRY(can_td_pinmap),
#endif
#if DEVICE_I2C
PINMAP_TEST_ENTRY(i2c_master_sda_pinmap),
PINMAP_TEST_ENTRY(i2c_master_scl_pinmap),
#if DEVICE_I2CSLAVE
PINMAP_TEST_ENTRY(i2c_slave_sda_pinmap),
PINMAP_TEST_ENTRY(i2c_slave_scl_pinmap),
#endif
#endif
#if DEVICE_PWMOUT
PINMAP_TEST_ENTRY(pwmout_pinmap),
#endif
#if DEVICE_QSPI
PINMAP_TEST_ENTRY(qspi_master_sclk_pinmap),
PINMAP_TEST_ENTRY(qspi_master_ssel_pinmap),
PINMAP_TEST_ENTRY(qspi_master_data0_pinmap),
PINMAP_TEST_ENTRY(qspi_master_data1_pinmap),
PINMAP_TEST_ENTRY(qspi_master_data2_pinmap),
PINMAP_TEST_ENTRY(qspi_master_data3_pinmap),
#endif
#if DEVICE_SERIAL
PINMAP_TEST_ENTRY(serial_tx_pinmap),
PINMAP_TEST_ENTRY(serial_rx_pinmap),
#if DEVICE_SERIAL_FC
PINMAP_TEST_ENTRY(serial_cts_pinmap),
PINMAP_TEST_ENTRY(serial_rts_pinmap),
#endif
#endif
#if DEVICE_SPI
PINMAP_TEST_ENTRY(spi_master_mosi_pinmap),
PINMAP_TEST_ENTRY(spi_master_miso_pinmap),
PINMAP_TEST_ENTRY(spi_master_clk_pinmap),
PINMAP_TEST_ENTRY(spi_master_cs_pinmap),
#if DEVICE_SPISLAVE
PINMAP_TEST_ENTRY(spi_slave_mosi_pinmap),
PINMAP_TEST_ENTRY(spi_slave_miso_pinmap),
PINMAP_TEST_ENTRY(spi_slave_clk_pinmap),
PINMAP_TEST_ENTRY(spi_slave_cs_pinmap),
#endif
#endif
{NULL, NULL}
};

void pinmap_validation()
{
for (size_t i = 0; i < sizeof(pinmap_functions) / sizeof(pinmap_functions[0]) - 1; i++) {
printf("Testing pinmap %s\r\n", pinmap_functions[i].name);

get_pinmap_func_t function = pinmap_functions[i].function;
TEST_ASSERT_NOT_EQUAL(NULL, function);

const PinMap *map = function();
TEST_ASSERT_NOT_EQUAL(NULL, map);

while (map->pin != NC) {
map++;
}

TEST_ASSERT_EQUAL(NC, map->peripheral);
}
}

Case cases[] = {
Case("pinmap - validation", pinmap_validation)
};

utest::v1::status_t greentea_test_setup(const size_t number_of_cases)
{
GREENTEA_SETUP(20, "default_auto");
return greentea_test_setup_handler(number_of_cases);
}

Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler);

int main()
{
Harness::run(specification);
}
10 changes: 10 additions & 0 deletions hal/analogin_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#define MBED_ANALOGIN_API_H

#include "device.h"
#include "pinmap.h"

#if DEVICE_ANALOGIN

Expand Down Expand Up @@ -59,6 +60,15 @@ float analogin_read(analogin_t *obj);
*/
uint16_t analogin_read_u16(analogin_t *obj);

/** Get the pins that support analogin
*
* Return a PinMap array of pins that support analogin. The
* array is terminated with {NC, NC, 0}.
*
* @return PinMap array
*/
const PinMap *analogin_pinmap(void);

/**@}*/

#ifdef __cplusplus
Expand Down
10 changes: 10 additions & 0 deletions hal/analogout_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#define MBED_ANALOGOUT_API_H

#include "device.h"
#include "pinmap.h"

#if DEVICE_ANALOGOUT

Expand Down Expand Up @@ -81,6 +82,15 @@ float analogout_read(dac_t *obj);
*/
uint16_t analogout_read_u16(dac_t *obj);

/** Get the pins that support analogout
*
* Return a PinMap array of pins that support analogout. The
* array is terminated with {NC, NC, 0}.
*
* @return PinMap array
*/
const PinMap *analogout_pinmap(void);

/**@}*/

#ifdef __cplusplus
Expand Down
19 changes: 19 additions & 0 deletions hal/can_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#define MBED_CAN_API_H

#include "device.h"
#include "pinmap.h"

#if DEVICE_CAN

Expand Down Expand Up @@ -76,6 +77,24 @@ unsigned char can_rderror(can_t *obj);
unsigned char can_tderror(can_t *obj);
void can_monitor(can_t *obj, int silent);

/** Get the pins that support CAN RD
*
* Return a PinMap array of pins that support CAN RD. The
* array is terminated with {NC, NC, 0}.
*
* @return PinMap array
*/
const PinMap *can_rd_pinmap(void);

/** Get the pins that support CAN TD
*
* Return a PinMap array of pins that support CAN TD. The
* array is terminated with {NC, NC, 0}.
*
* @return PinMap array
*/
const PinMap *can_td_pinmap(void);

#ifdef __cplusplus
};
#endif
Expand Down
37 changes: 37 additions & 0 deletions hal/i2c_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#define MBED_I2C_API_H

#include "device.h"
#include "pinmap.h"
#include "hal/buffer.h"

#if DEVICE_I2C_ASYNCH
Expand Down Expand Up @@ -146,6 +147,42 @@ int i2c_byte_read(i2c_t *obj, int last);
*/
int i2c_byte_write(i2c_t *obj, int data);

/** Get the pins that support I2C SDA
*
* Return a PinMap array of pins that support I2C SDA in
* master mode. The array is terminated with {NC, NC, 0}.
*
* @return PinMap array
*/
const PinMap *i2c_master_sda_pinmap(void);

/** Get the pins that support I2C SCL
*
* Return a PinMap array of pins that support I2C SCL in
* master mode. The array is terminated with {NC, NC, 0}.
*
* @return PinMap array
*/
const PinMap *i2c_master_scl_pinmap(void);

/** Get the pins that support I2C SDA
*
* Return a PinMap array of pins that support I2C SDA in
* slave mode. The array is terminated with {NC, NC, 0}.
*
* @return PinMap array
*/
const PinMap *i2c_slave_sda_pinmap(void);

/** Get the pins that support I2C SCL
*
* Return a PinMap array of pins that support I2C SCL in
* slave mode. The array is terminated with {NC, NC, 0}.
*
* @return PinMap array
*/
const PinMap *i2c_slave_scl_pinmap(void);

/**@}*/

#if DEVICE_I2CSLAVE
Expand Down
74 changes: 74 additions & 0 deletions hal/mbed_pinmap_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Loading