-
Notifications
You must be signed in to change notification settings - Fork 136
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Hardcoded for free IOs on STM32F469NI-DISCO board. Test will only be included if the `board.f469ni-disco` module is available.
- Loading branch information
Showing
4 changed files
with
411 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
#!/usr/bin/env python3 | ||
# -*- coding: utf-8 -*- | ||
# | ||
# Copyright (c) 2018, Niklas Hauser | ||
# | ||
# This file is part of the modm project. | ||
# | ||
# This Source Code Form is subject to the terms of the Mozilla Public | ||
# License, v. 2.0. If a copy of the MPL was not distributed with this | ||
# file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||
|
||
from collections import defaultdict, OrderedDict | ||
|
||
# These tests have been hardcoded for the Nucleo-64 boards due to | ||
# lack of some data-driven method for now. | ||
# According to the schematic, the following pins are safe to use as IO and are | ||
# not connected to anything else _on_ the board: | ||
test_io = sorted([ | ||
("A", 0), # A0 | ||
("A", 1), # A1 | ||
("A", 4), # A2 | ||
("B", 0), # A3 | ||
("C", 1), # A4 | ||
("C", 0), # A5 | ||
# ("A", 3), # D0 UART | ||
# ("A", 2), # D1 UART | ||
("A", 10), # D2 | ||
# ("B", 3), # D3 SWO | ||
("B", 5), # D4 | ||
# ("B", 4), # D5 ??? | ||
("B", 10), # D6 | ||
("A", 8), # D7 | ||
("A", 9), # D8 | ||
("C", 7), # D9 | ||
("B", 6), # D10 | ||
("A", 7), # D11 | ||
("A", 6), # D12 | ||
# ("A", 5), # D13 LED! | ||
("B", 9), # D14 | ||
("B", 8), # D15 | ||
]) | ||
|
||
def translate(s): | ||
name = "" | ||
for part in s.split("_"): | ||
name += part.capitalize() | ||
return name | ||
|
||
def get_driver(s): | ||
name = "None" | ||
if "driver" in s: name = translate(s["driver"]); | ||
if "instance" in s: name += translate(s["instance"]); | ||
return name | ||
|
||
def get_name(s): | ||
return translate(s["name"]) | ||
|
||
def get_af(s): | ||
af = None | ||
if "af" in s: af = int(s["af"]); | ||
return af | ||
|
||
|
||
def init(module): | ||
module.name = "gpio" | ||
module.parent = "test:platform" | ||
|
||
def prepare(module, options): | ||
target = options[":target"].identifier | ||
if target["platform"] not in ["stm32"]: | ||
return False | ||
|
||
module.add_option( | ||
BooleanOption( | ||
name="test_gpio_lock", | ||
description="Test locking the GPIOs. This will make the GPIOs unusable until the next reboot!", | ||
default=False)) | ||
|
||
module.depends(":architecture:delay", ":platform:gpio") | ||
return True | ||
|
||
def build(env): | ||
if not env.has_module(":board.nucleo-*"): | ||
env.log.warn("GPIO test has been hardcoded to a Nucleo-64 board. " | ||
"When porting make sure this test does not damage your board!") | ||
return | ||
|
||
device = env[":target"] | ||
driver = device.get_driver("gpio") | ||
gpios = [g for g in driver["gpio"] if (g["port"].upper(), int(g["pin"])) in test_io] | ||
peripherals = sorted([get_driver(s) for g in gpios for s in (g["signal"] if "signal" in g else [])]) | ||
connections = OrderedDict() | ||
for k in peripherals: | ||
rconns = [(g["port"].upper(), int(g["pin"]), get_name(s), get_af(s)) for g in gpios for s in (g["signal"] if "signal" in g else []) if get_driver(s) == k] | ||
# we need to remove duplicate GPIOs from this list | ||
# since we cannot set the same GPIO to multiple different AFs! | ||
conns = [] | ||
for r in rconns: | ||
if any(r[0] == t[0] and r[1] == t[1] for t in conns): | ||
continue | ||
conns.append(r) | ||
connections[k] = conns | ||
|
||
properties = { | ||
"target": device.identifier, | ||
"test_io": test_io, | ||
"test_connections": connections | ||
} | ||
|
||
env.substitutions = properties | ||
env.outbasepath = "modm/test/modm/platform/gpio" | ||
env.copy("platform_gpio_test.hpp") | ||
env.template("platform_gpio_test.cpp.in") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,250 @@ | ||
/* | ||
* Copyright (c) 2016, Antal Szabó | ||
* Copyright (c) 2016, Kevin Läufer | ||
* Copyright (c) 2017, Fabian Greif | ||
* Copyright (c) 2018, Niklas Hauser | ||
* | ||
* This file is part of the modm project. | ||
* | ||
* This Source Code Form is subject to the terms of the Mozilla Public | ||
* License, v. 2.0. If a copy of the MPL was not distributed with this | ||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||
*/ | ||
// ---------------------------------------------------------------------------- | ||
|
||
#include "platform_gpio_test.hpp" | ||
|
||
#include <modm/platform/platform.hpp> | ||
|
||
using namespace modm::platform; | ||
|
||
void | ||
PlatformGpioTest::setUp() | ||
{ | ||
%% for (port, pin) in test_io | ||
// GPIO{{port}}->MODER &= ~(3ul << {{pin*2}}); GPIO{{port}}->OSPEEDR &= ~(3ul << {{pin*2}}); GPIO{{port}}->PUPDR &= ~(3ul << {{pin*2}}); | ||
// GPIO{{port}}->OTYPER &= ~(1ul << {{pin}}); GPIO{{port}}->ODR &= ~(1ul << {{pin}}); GPIO{{port}}->AFR[{{pin//8}}] &= ~(15ul << {{(pin % 8) * 4}}); | ||
%% endfor | ||
} | ||
|
||
void | ||
PlatformGpioTest::testEnabled() | ||
{ | ||
%% if options["modm:platform:gpio:enable_ports"] | length | ||
// checks if the handler in enable.cpp has been called | ||
// if this fails, then the function either wasn't found by the linker | ||
// or the section was garbage collected, or the startup script has a bug | ||
%% if target["family"] in ["f1"] | ||
TEST_ASSERT_TRUE(RCC->APB2ENR & RCC_APB2ENR_AFIOEN); | ||
%% else | ||
TEST_ASSERT_TRUE(RCC->APB2ENR & RCC_APB2ENR_SYSCFGEN); | ||
%% endif | ||
%% if target["family"] in ["f2","f4", "f7"] | ||
TEST_ASSERT_TRUE(SYSCFG->CMPCR & SYSCFG_CMPCR_CMP_PD); | ||
%% endif | ||
// check all ports are clock enabled and all GPIOs are reset | ||
%% for (port, pin) in test_io | ||
%% if target["family"] in ["f1"] | ||
TEST_ASSERT_TRUE((GPIO{{port}}->CR{{"L" if pin<8 else "H"}} & (0xful << {{(pin % 8) * 4}})) == (0b0100ul << {{(pin % 8) * 4}})); | ||
%% else | ||
TEST_ASSERT_TRUE((GPIO{{port}}->MODER & (3ul << {{pin*2}})) == 0ul); | ||
TEST_ASSERT_TRUE((GPIO{{port}}->OSPEEDR & (3ul << {{pin*2}})) == 0ul); | ||
TEST_ASSERT_TRUE((GPIO{{port}}->PUPDR & (3ul << {{pin*2}})) == 0ul); | ||
TEST_ASSERT_TRUE((GPIO{{port}}->OTYPER & (1ul << {{pin}})) == 0ul); | ||
TEST_ASSERT_TRUE((GPIO{{port}}->AFR[{{pin//8}}] & (0xful << {{(pin % 8) * 4}})) == 0ul); | ||
%% endif | ||
TEST_ASSERT_TRUE((GPIO{{port}}->ODR & (1ul << {{pin}})) == 0ul); | ||
TEST_ASSERT_TRUE((GPIO{{port}}->BSRR & (0x10001ul << {{pin}})) == 0ul); | ||
TEST_ASSERT_TRUE((GPIO{{port}}->LCKR & (1ul << {{pin}})) == 0ul); | ||
%% endfor | ||
%% endif | ||
} | ||
|
||
void | ||
PlatformGpioTest::testSetOutput() | ||
{ | ||
%% for (port, pin) in test_io | ||
Gpio{{port ~ pin}}::setOutput(Gpio::OutputType::PushPull, Gpio::OutputSpeed::Low); | ||
%% if target["family"] in ["f1"] | ||
TEST_ASSERT_TRUE((GPIO{{port}}->CR{{"L" if pin<8 else "H"}} & (0xful << {{(pin % 8) * 4}})) == (0b0010ul << {{(pin % 8) * 4}})); | ||
%% else | ||
TEST_ASSERT_TRUE((GPIO{{port}}->MODER & (3ul << {{pin*2}})) == (1ul << {{pin*2}})); | ||
TEST_ASSERT_TRUE((GPIO{{port}}->OSPEEDR & (3ul << {{pin*2}})) == 0ul); | ||
TEST_ASSERT_TRUE((GPIO{{port}}->OTYPER & (1ul << {{pin}})) == 0ul); | ||
%% endif | ||
%% endfor | ||
|
||
%% for (port, pin) in test_io | ||
Gpio{{port ~ pin}}::setOutput(Gpio::OutputType::OpenDrain, Gpio::OutputSpeed::Medium); | ||
%% if target["family"] in ["f1"] | ||
TEST_ASSERT_TRUE((GPIO{{port}}->CR{{"L" if pin<8 else "H"}} & (0xful << {{(pin % 8) * 4}})) == (0b0101ul << {{(pin % 8) * 4}})); | ||
%% else | ||
TEST_ASSERT_TRUE((GPIO{{port}}->MODER & (3ul << {{pin*2}})) == (1ul << {{pin*2}})); | ||
TEST_ASSERT_TRUE((GPIO{{port}}->OSPEEDR & (3ul << {{pin*2}})) == (1ul << {{pin*2}})); | ||
TEST_ASSERT_TRUE((GPIO{{port}}->OTYPER & (1ul << {{pin}})) == (1ul << {{pin}})); | ||
%% endif | ||
%% endfor | ||
|
||
%% for (port, pin) in test_io | ||
Gpio{{port ~ pin}}::setOutput(Gpio::OutputType::PushPull, Gpio::OutputSpeed::High); | ||
%% if target["family"] in ["f1"] | ||
TEST_ASSERT_TRUE((GPIO{{port}}->CR{{"L" if pin<8 else "H"}} & (0xful << {{(pin % 8) * 4}})) == (0b0011ul << {{(pin % 8) * 4}})); | ||
%% else | ||
TEST_ASSERT_TRUE((GPIO{{port}}->MODER & (3ul << {{pin*2}})) == (1ul << {{pin*2}})); | ||
TEST_ASSERT_TRUE((GPIO{{port}}->OSPEEDR & (3ul << {{pin*2}})) == (2ul << {{pin*2}})); | ||
TEST_ASSERT_TRUE((GPIO{{port}}->OTYPER & (1ul << {{pin}})) == 0ul); | ||
%% endif | ||
%% endfor | ||
|
||
%% if target["family"] in ["f2", "f4", "f7", "l4"] | ||
%% for (port, pin) in test_io | ||
Gpio{{port ~ pin}}::setOutput(Gpio::OutputType::PushPull, Gpio::OutputSpeed::VeryHigh); | ||
TEST_ASSERT_TRUE((GPIO{{port}}->MODER & (3ul << {{pin*2}})) == (1ul << {{pin*2}})); | ||
TEST_ASSERT_TRUE((GPIO{{port}}->OSPEEDR & (3ul << {{pin*2}})) == (3ul << {{pin*2}})); | ||
TEST_ASSERT_TRUE((GPIO{{port}}->OTYPER & (1ul << {{pin}})) == 0ul); | ||
%% endfor | ||
%% endif | ||
// configure() and setOutput() method are already tested in the above code paths | ||
} | ||
|
||
void | ||
PlatformGpioTest::testSetInput() | ||
{ | ||
%% for (port, pin) in test_io | ||
Gpio{{port ~ pin}}::setInput(Gpio::InputType::Floating); | ||
%% if target["family"] in ["f1"] | ||
TEST_ASSERT_TRUE((GPIO{{port}}->CR{{"L" if pin<8 else "H"}} & (0xful << {{(pin % 8) * 4}})) == (0b0100ul << {{(pin % 8) * 4}})); | ||
%% else | ||
TEST_ASSERT_TRUE((GPIO{{port}}->MODER & (3ul << {{pin*2}})) == 0ul); | ||
TEST_ASSERT_TRUE((GPIO{{port}}->OSPEEDR & (3ul << {{pin*2}})) == 0ul); | ||
TEST_ASSERT_TRUE((GPIO{{port}}->OTYPER & (1ul << {{pin}})) == 0ul); | ||
TEST_ASSERT_TRUE((GPIO{{port}}->PUPDR & (3ul << {{pin*2}})) == 0ul); | ||
%% endif | ||
%% endfor | ||
|
||
%% for (port, pin) in test_io | ||
Gpio{{port ~ pin}}::setInput(Gpio::InputType::PullUp); | ||
%% if target["family"] in ["f1"] | ||
TEST_ASSERT_TRUE((GPIO{{port}}->CR{{"L" if pin<8 else "H"}} & (0xful << {{(pin % 8) * 4}})) == (0b1000ul << {{(pin % 8) * 4}})); | ||
TEST_ASSERT_TRUE((GPIO{{port}}->ODR & (1ul << {{pin}})) == (1ul << {{pin}})); | ||
%% else | ||
TEST_ASSERT_TRUE((GPIO{{port}}->MODER & (3ul << {{pin*2}})) == 0ul); | ||
TEST_ASSERT_TRUE((GPIO{{port}}->OSPEEDR & (3ul << {{pin*2}})) == 0ul); | ||
TEST_ASSERT_TRUE((GPIO{{port}}->OTYPER & (1ul << {{pin}})) == 0ul); | ||
TEST_ASSERT_TRUE((GPIO{{port}}->PUPDR & (3ul << {{pin*2}})) == (1ul << {{pin*2}})); | ||
%% endif | ||
%% endfor | ||
|
||
%% for (port, pin) in test_io | ||
Gpio{{port ~ pin}}::setInput(Gpio::InputType::PullDown); | ||
%% if target["family"] in ["f1"] | ||
TEST_ASSERT_TRUE((GPIO{{port}}->CR{{"L" if pin<8 else "H"}} & (0xful << {{(pin % 8) * 4}})) == (0b1000ul << {{(pin % 8) * 4}})); | ||
TEST_ASSERT_TRUE((GPIO{{port}}->ODR & (1ul << {{pin}})) == 0ul); | ||
%% else | ||
TEST_ASSERT_TRUE((GPIO{{port}}->MODER & (3ul << {{pin*2}})) == 0ul); | ||
TEST_ASSERT_TRUE((GPIO{{port}}->OSPEEDR & (3ul << {{pin*2}})) == 0ul); | ||
TEST_ASSERT_TRUE((GPIO{{port}}->OTYPER & (1ul << {{pin}})) == 0ul); | ||
TEST_ASSERT_TRUE((GPIO{{port}}->PUPDR & (3ul << {{pin*2}})) == (2ul << {{pin*2}})); | ||
%% endif | ||
%% endfor | ||
} | ||
|
||
void | ||
PlatformGpioTest::testOutput() | ||
{ | ||
%% for (port, pin) in test_io | ||
Gpio{{port ~ pin}}::setOutput(); | ||
Gpio{{port ~ pin}}::set(); | ||
TEST_ASSERT_TRUE((GPIO{{port}}->ODR & (1ul << {{pin}})) == (1ul << {{pin}})); | ||
TEST_ASSERT_TRUE(Gpio{{port ~ pin}}::isSet()); | ||
Gpio{{port ~ pin}}::reset(); | ||
TEST_ASSERT_TRUE((GPIO{{port}}->ODR & (1ul << {{pin}})) == 0ul); | ||
TEST_ASSERT_FALSE(Gpio{{port ~ pin}}::isSet()); | ||
Gpio{{port ~ pin}}::toggle(); | ||
TEST_ASSERT_TRUE((GPIO{{port}}->ODR & (1ul << {{pin}})) == (1ul << {{pin}})); | ||
TEST_ASSERT_TRUE(Gpio{{port ~ pin}}::isSet()); | ||
Gpio{{port ~ pin}}::toggle(); | ||
TEST_ASSERT_TRUE((GPIO{{port}}->ODR & (1ul << {{pin}})) == 0ul); | ||
TEST_ASSERT_FALSE(Gpio{{port ~ pin}}::isSet()); | ||
%% endfor | ||
} | ||
|
||
void | ||
PlatformGpioTest::testInput() | ||
{ | ||
%% for (port, pin) in test_io | ||
Gpio{{port ~ pin}}::setInput(Gpio::InputType::PullUp); | ||
modm::delayMilliseconds(1); | ||
TEST_ASSERT_TRUE((GPIO{{port}}->IDR & (1ul << {{pin}})) == (1ul << {{pin}})); | ||
TEST_ASSERT_TRUE(Gpio{{port ~ pin}}::read()); | ||
Gpio{{port ~ pin}}::setInput(Gpio::InputType::PullDown); | ||
modm::delayMilliseconds(1); | ||
TEST_ASSERT_TRUE((GPIO{{port}}->IDR & (1ul << {{pin}})) == 0ul); | ||
TEST_ASSERT_FALSE(Gpio{{port ~ pin}}::read()); | ||
%% endfor | ||
} | ||
|
||
void | ||
PlatformGpioTest::testAnalog() | ||
{ | ||
%% for (port, pin) in test_io | ||
Gpio{{port ~ pin}}::setAnalogInput(); | ||
%% if target["family"] in ["f1"] | ||
TEST_ASSERT_TRUE((GPIO{{port}}->CR{{"L" if pin<8 else "H"}} & (0xful << {{(pin % 8) * 4}})) == 0ul); | ||
%% else | ||
TEST_ASSERT_TRUE((GPIO{{port}}->MODER & (3ul << {{pin*2}})) == (3ul << {{pin*2}})); | ||
%% if target["family"] in ["l4"] and target["name"] in ["71", "75", "76", "85", "86"] | ||
TEST_ASSERT_TRUE((GPIO{{port}}->ASCR & (1ul << {{pin}})) == (1ul << {{pin}})); | ||
%% endif | ||
%% endif | ||
Gpio{{port ~ pin}}::disconnect(); | ||
%% if target["family"] in ["f1"] | ||
TEST_ASSERT_TRUE((GPIO{{port}}->CR{{"L" if pin<8 else "H"}} & (0xful << {{(pin % 8) * 4}})) == (0b0100ul << {{(pin % 8) * 4}})); | ||
%% else | ||
TEST_ASSERT_TRUE((GPIO{{port}}->MODER & (3ul << {{pin*2}})) == 0ul); | ||
%% if target["family"] in ["l4"] and target["name"] in ["71", "75", "76", "85", "86"] | ||
TEST_ASSERT_TRUE((GPIO{{port}}->ASCR & (1ul << {{pin}})) == 0ul); | ||
%% endif | ||
%% endif | ||
%% endfor | ||
} | ||
|
||
void | ||
PlatformGpioTest::testConnect() | ||
{ | ||
%% if target["family"] not in ["f1"] | ||
%% for peripheral, connections in test_connections.items() | ||
%% if connections | length | ||
using TestConnection{{peripheral}} = GpioConnector<Peripheral::{{peripheral}}, | ||
%% for (port, pin, signal, _) in connections | ||
Gpio{{port~pin}}::{{signal}}{% if loop.last %}>;{% else %},{% endif %} | ||
%% endfor | ||
TestConnection{{peripheral}}::connect(); | ||
%% for (port, pin, signal, af) in connections | ||
%% if af | ||
TEST_ASSERT_TRUE((GPIO{{port}}->MODER & (3ul << {{pin*2}})) == (2ul << {{pin*2}})); | ||
TEST_ASSERT_TRUE((GPIO{{port}}->AFR[{{pin//8}}] & (15ul << {{(pin % 8) * 4}})) == ({{af}}ul << {{(pin % 8) * 4}})); | ||
%% elif peripheral.startswith("Adc") or peripheral.startswith("Dac") | ||
TEST_ASSERT_TRUE((GPIO{{port}}->MODER & (3ul << {{pin*2}})) == (3ul << {{pin*2}})); | ||
%% endif | ||
%% endfor | ||
TestConnection{{peripheral}}::disconnect(); | ||
%% for (port, pin, signal, af) in connections | ||
TEST_ASSERT_TRUE((GPIO{{port}}->MODER & (3ul << {{pin*2}})) == 0ul); | ||
TEST_ASSERT_TRUE((GPIO{{port}}->AFR[{{pin//8}}] & (0xful << {{(pin % 8) * 4}})) == 0ul); | ||
%% endfor | ||
%% endif | ||
%% endfor | ||
%% endif | ||
} | ||
|
||
void | ||
PlatformGpioTest::testLock() | ||
{ | ||
%% if options["::::test_gpio_lock"] | ||
%% for (port, pin) in test_io | ||
Gpio{{port ~ pin}}::lock(); | ||
TEST_ASSERT_TRUE((GPIO{{port}}->LCKR & (1ul << {{pin}})) == (1ul << {{pin}})); | ||
%% endfor | ||
%% endif | ||
} |
Oops, something went wrong.