Newer
Older
mbed-os / hal / tests / TESTS / pin_names / arduino_uno / main.cpp
/* mbed Microcontroller Library
 * Copyright (c) 2020 ARM Limited
 * SPDX-License-Identifier: Apache-2.0
 *
 * 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"
#include "mbed.h"

/*
Requirements specified in docs/design-documents/hal/0005-pin-names-Arduino-Uno-standard.md
*/

#if !(defined (TARGET_FF_ARDUINO_UNO))
#error [NOT_SUPPORTED] Test needs Arduino Uno form factor
#else

using namespace utest::v1;

template <PinName TestedPin>
void GPIO_test()
{
    utest_printf("GPIO Pin 0x%x\n", TestedPin);

    TEST_SKIP_UNLESS_MESSAGE(TestedPin != CONSOLE_TX, "ARDUINO_UNO pin shared with CONSOLE_TX");
    TEST_SKIP_UNLESS_MESSAGE(TestedPin != CONSOLE_RX, "ARDUINO_UNO pin shared with CONSOLE_RX");

    const PinMap *maps = gpio_pinmap(); // hal/source/mbed_gpio.c
    while (maps->pin != (PinName)NC) { // check each pin from PinMap table till NC pin
        if (maps->pin == TestedPin) {
            {
                DigitalOut   TEST1(maps->pin);
                TEST1 = !TEST1;
            }
            {
                DigitalIn   TEST1(maps->pin);
                // Basic API call
                TEST1.read();
            }
            {
                DigitalInOut   TEST1(maps->pin);
                // Basic API call
                TEST1.input();
                TEST1.output();
            }

            TEST_ASSERT(true);
            return;
        }
        maps++;
    }

    // Pin is not part of gpio PinMap
    TEST_ASSERT(false);
}


template <PinName TestedPin>
void AnalogIn_test()
{
    utest_printf("ADC Pin 0x%x\n", TestedPin);

    const PinMap *maps = analogin_pinmap();
    while (maps->pin != (PinName)NC) { // check each pin from PinMap table till NC pin
        if (maps->pin == TestedPin) {

            AnalogIn TEST(TestedPin);
            // Basic API call
            TEST.read_u16();

            TEST_ASSERT(true);
            return;
        }
        maps++;
    }

    // Pin is not part of analogin PinMap
    TEST_ASSERT(false);
}


template <PinName TestedPin>
void PWM_test()
{
    utest_printf("PWM Pin 0x%x\n", TestedPin);

    const PinMap *maps = pwmout_pinmap();
    while (maps->pin != (PinName)NC) { // check each pin from PinMap table till NC pin
        if (maps->pin == TestedPin) {

            PwmOut pwm(TestedPin);
            // Basic API call
            pwm.period(1.0f);
            pwm.write(0.5f);

            TEST_ASSERT(true);
            return;
        }
        maps++;
    }

    // From docs/design-documents/hal/0005-pin-names-Arduino-Uno-standard.md
    // Although this is recomended as per the Arduino Uno standard,
    // it's not a mandatory as requirement to be compliant with the Arduino Uno standard for Mbed boards.
    TEST_SKIP_UNLESS_MESSAGE(false, "ARDUINO_UNO: this pin doesn’t support PWM");
}


template <PinName TX_pin, PinName RX_pin>
void UART_test()
{
    utest_printf("UART TX Pin 0x%x RX Pin 0x%x\n", TX_pin, RX_pin);

    // 1. check if Arduino_uno pins are not already used by the console
    TEST_SKIP_UNLESS_MESSAGE(TX_pin != CONSOLE_TX, "ARDUINO_UNO_UART pin shared with CONSOLE_TX");
    TEST_SKIP_UNLESS_MESSAGE(RX_pin != CONSOLE_RX, "ARDUINO_UNO_UART pin shared with CONSOLE_RX");

    // 2. check if Arduino_uno pins are part of pinmap table
    {
        const PinMap *maps = serial_tx_pinmap();
        while (maps->pin != (PinName)NC) { // check each pin from PinMap table till NC pin
            if (maps->pin == TX_pin) {
                break;
            }
            maps++;
        }
        // Pin is not part of serial_tx PinMap
        TEST_ASSERT_NOT_EQUAL(NC, maps->pin);
    }

    {
        const PinMap *maps = serial_rx_pinmap();
        while (maps->pin != (PinName)NC) { // check each pin from PinMap table till NC pin
            if (maps->pin == RX_pin) {
                break;
            }
            maps++;
        }
        // Pin is not part of serial_rx PinMap
        TEST_ASSERT_NOT_EQUAL(NC, maps->pin);
    }

    // 3. check if Arduino_uno pins are not using the same UART instance as console
    int console_uart = pinmap_peripheral(CONSOLE_TX, serial_tx_pinmap());
    if (console_uart != 0) {
        TEST_ASSERT_NOT_EQUAL(console_uart, pinmap_peripheral(TX_pin, serial_tx_pinmap()));
    }

    // 4. check if UART pins can be initialized
    BufferedSerial TEST(TX_pin, RX_pin);

    // 5. check a basic API call
    TEST.set_baud(115200);
}


template <PinName SDA_pin, PinName SCL_pin>
void I2C_test()
{
    utest_printf("I2C SDA Pin 0x%x SCL Pin 0x%x\n", SDA_pin, SCL_pin);

    {
        const PinMap *maps = i2c_master_sda_pinmap();
        while (maps->pin != (PinName)NC) { // check each pin from PinMap table till NC pin
            if (maps->pin == SDA_pin) {
                break;
            }
            maps++;
        }
        // Pin is not part of i2c_master_sda PinMap
        TEST_ASSERT_NOT_EQUAL(NC, maps->pin);
    }
    {
        const PinMap *maps = i2c_master_scl_pinmap();
        while (maps->pin != (PinName)NC) { // check each pin from PinMap table till NC pin
            if (maps->pin == SCL_pin) {
                break;
            }
            maps++;
        }
        // Pin is not part of i2c_master_scl PinMap
        TEST_ASSERT_NOT_EQUAL(NC, maps->pin);
    }

    I2C i2c(SDA_pin, SCL_pin);
}


template <PinName MOSI_pin, PinName MISO_pin, PinName CLK_pin, PinName CS_pin>
void SPI_test()
{
    utest_printf("SPI MOSI Pin 0x%x MISO Pin 0x%x CLOCK Pin 0x%x CS Pin0x%x\n", MOSI_pin, MISO_pin, CLK_pin, CS_pin);

    {
        const PinMap *maps = spi_master_mosi_pinmap();
        while (maps->pin != (PinName)NC) { // check each pin from PinMap table till NC pin
            if (maps->pin == MOSI_pin) {
                break;
            }
            maps++;
        }
        // Pin is not part of spi_master_mosi PinMap
        TEST_ASSERT_NOT_EQUAL(NC, maps->pin);
    }
    {
        const PinMap *maps = spi_master_miso_pinmap();
        while (maps->pin != (PinName)NC) { // check each pin from PinMap table till NC pin
            if (maps->pin == MISO_pin) {
                break;
            }
            maps++;
        }
        // Pin is not part of spi_master_miso PinMap
        TEST_ASSERT_NOT_EQUAL(NC, maps->pin);
    }
    {
        const PinMap *maps = spi_master_clk_pinmap();
        while (maps->pin != (PinName)NC) { // check each pin from PinMap table till NC pin
            if (maps->pin == CLK_pin) {
                break;
            }
            maps++;
        }
        // Pin is not part of spi_master_clk PinMap
        TEST_ASSERT_NOT_EQUAL(NC, maps->pin);
    }
    {
        const PinMap *maps = gpio_pinmap(); // CS pin could be a simple GPIO
        while (maps->pin != (PinName)NC) { // check each pin from PinMap table till NC pin
            if (maps->pin == CS_pin) {
                break;
            }
            maps++;
        }
        // Pin is not part of gpio PinMap
        TEST_ASSERT_NOT_EQUAL(NC, maps->pin);
    }

    SPI device(MOSI_pin, MISO_pin, CLK_pin);
    DigitalOut cs(CS_pin);
    // Basic API call
    device.frequency(10000000);
}


Case cases[] = {
    Case("GPIO A0", GPIO_test<ARDUINO_UNO_A0>),
    Case("GPIO A1", GPIO_test<ARDUINO_UNO_A1>),
    Case("GPIO A2", GPIO_test<ARDUINO_UNO_A2>),
    Case("GPIO A3", GPIO_test<ARDUINO_UNO_A3>),
    Case("GPIO A4", GPIO_test<ARDUINO_UNO_A4>),
    Case("GPIO A5", GPIO_test<ARDUINO_UNO_A5>),
    Case("GPIO D0", GPIO_test<ARDUINO_UNO_D0>),
    Case("GPIO D1", GPIO_test<ARDUINO_UNO_D1>),
    Case("GPIO D2", GPIO_test<ARDUINO_UNO_D2>),
    Case("GPIO D3", GPIO_test<ARDUINO_UNO_D3>),
    Case("GPIO D4", GPIO_test<ARDUINO_UNO_D4>),
    Case("GPIO D5", GPIO_test<ARDUINO_UNO_D5>),
    Case("GPIO D6", GPIO_test<ARDUINO_UNO_D6>),
    Case("GPIO D7", GPIO_test<ARDUINO_UNO_D7>),
    Case("GPIO D8", GPIO_test<ARDUINO_UNO_D8>),
    Case("GPIO D9", GPIO_test<ARDUINO_UNO_D9>),
    Case("GPIO D10", GPIO_test<ARDUINO_UNO_D10>),
    Case("GPIO D11", GPIO_test<ARDUINO_UNO_D11>),
    Case("GPIO D12", GPIO_test<ARDUINO_UNO_D12>),
    Case("GPIO D13", GPIO_test<ARDUINO_UNO_D13>),
    Case("GPIO D14", GPIO_test<ARDUINO_UNO_D14>),
    Case("GPIO D15", GPIO_test<ARDUINO_UNO_D15>),

    Case("ADC A0", AnalogIn_test<ARDUINO_UNO_A0>),
    Case("ADC A1", AnalogIn_test<ARDUINO_UNO_A1>),
    Case("ADC A2", AnalogIn_test<ARDUINO_UNO_A2>),
    Case("ADC A3", AnalogIn_test<ARDUINO_UNO_A3>),
    Case("ADC A4", AnalogIn_test<ARDUINO_UNO_A4>),
    Case("ADC A5", AnalogIn_test<ARDUINO_UNO_A5>),

    Case("PWM D3", PWM_test<ARDUINO_UNO_D3>),
    Case("PWM D5", PWM_test<ARDUINO_UNO_D5>),
    Case("PWM D6", PWM_test<ARDUINO_UNO_D6>),
    Case("PWM D9", PWM_test<ARDUINO_UNO_D9>),
    Case("PWM D10", PWM_test<ARDUINO_UNO_D10>),
    Case("PWM D11", PWM_test<ARDUINO_UNO_D11>),

    Case("UART", UART_test<ARDUINO_UNO_UART_TX, ARDUINO_UNO_UART_RX>),

    Case("I2C", I2C_test<ARDUINO_UNO_I2C_SDA, ARDUINO_UNO_I2C_SCL>),

    Case("SPI", SPI_test<ARDUINO_UNO_SPI_MOSI, ARDUINO_UNO_SPI_MISO, ARDUINO_UNO_SPI_SCK, ARDUINO_UNO_SPI_CS>),
};

utest::v1::status_t greentea_test_setup(const size_t number_of_cases)
{
    GREENTEA_SETUP(25, "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);
}

#endif