diff --git a/tests/board_test_suite/README.rst b/tests/board_test_suite/README.rst new file mode 100644 index 0000000000..7fed9d35b1 --- /dev/null +++ b/tests/board_test_suite/README.rst @@ -0,0 +1,56 @@ + +Introduction +============ + +Board test suite for CircuitPython. Run these tests to ensure that a CircuitPython port was created correctly, individual pin mappings are correct, and buses (e.g. SPI) work. + +Tests can be run individually. Copy code found in each *_test.py* module (found in *source* directory) to main.py in your CIRCUITPYTHON device drive. + +Alternatively, tests can be imported as modules. Copy the *lib* directory to CIRCUITPYTHON device drive and import the test in your own code. Each test can be run with the `run_test(pins)` function. + +The *main.py* example shows how to call tests from within a script. *main.py* runs the following tests: + + * LED Test + * GPIO Test + * Voltage Monitor Test + * UART Test + * SPI Test + * I2C Test + +Dependencies +============= + +This test suite depends on: + +* `Adafruit CircuitPython `_ +* `SD Card `_ +* `Bus Device `_ + +Please ensure all dependencies are available on the CircuitPython filesystem. +This is easily achieved by downloading +`the Adafruit library and driver bundle `_. + +Usage Example +============= + +You will need the following components: + +* Multimeter +* LED +* 1x 330 Ohm resistor +* 2x 4.7k Ohm resistor +* Microchip 25AA040A SPI EEPROM +* Microchip AT24HC04B I2C EEPROM +* Breadboard +* Wires + +Connect the components as shown to your board. + +![Test jig Fritzing diagram](doc/test_jig.png) + +Copy the *lib* folder to the CIRCUITPYTHON drive. Copy *main.py* to the root directory of your CIRCUITPYTHON drive. Open a Serial terminal and connect to the board. Follow the directions given to run through the tests. + +Building +======== + +Individual test modules can be built with the mpy-cross cross-compiler. This is required to save RAM space if you plan to run more than one test at a time. See [the mpy-cross directory in circuitpython](https://github.com/adafruit/circuitpython/tree/master/mpy-cross) to learn more. diff --git a/tests/board_test_suite/doc/test_jib.png b/tests/board_test_suite/doc/test_jib.png new file mode 100644 index 0000000000..22dd927b29 Binary files /dev/null and b/tests/board_test_suite/doc/test_jib.png differ diff --git a/tests/board_test_suite/doc/test_jig.fzz b/tests/board_test_suite/doc/test_jig.fzz new file mode 100644 index 0000000000..e97a840245 Binary files /dev/null and b/tests/board_test_suite/doc/test_jig.fzz differ diff --git a/tests/board_test_suite/doc/test_jig_bb.png b/tests/board_test_suite/doc/test_jig_bb.png new file mode 100644 index 0000000000..89ec28dbeb Binary files /dev/null and b/tests/board_test_suite/doc/test_jig_bb.png differ diff --git a/tests/board_test_suite/lib/adafruit_bus_device/__init__.py b/tests/board_test_suite/lib/adafruit_bus_device/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/board_test_suite/lib/adafruit_bus_device/i2c_device.mpy b/tests/board_test_suite/lib/adafruit_bus_device/i2c_device.mpy new file mode 100644 index 0000000000..f33d4d495f Binary files /dev/null and b/tests/board_test_suite/lib/adafruit_bus_device/i2c_device.mpy differ diff --git a/tests/board_test_suite/lib/adafruit_bus_device/spi_device.mpy b/tests/board_test_suite/lib/adafruit_bus_device/spi_device.mpy new file mode 100644 index 0000000000..f43100ee88 Binary files /dev/null and b/tests/board_test_suite/lib/adafruit_bus_device/spi_device.mpy differ diff --git a/tests/board_test_suite/lib/adafruit_sdcard.mpy b/tests/board_test_suite/lib/adafruit_sdcard.mpy new file mode 100644 index 0000000000..03f65fa63f Binary files /dev/null and b/tests/board_test_suite/lib/adafruit_sdcard.mpy differ diff --git a/tests/board_test_suite/lib/gpio_test.mpy b/tests/board_test_suite/lib/gpio_test.mpy new file mode 100644 index 0000000000..9e90b9ca64 Binary files /dev/null and b/tests/board_test_suite/lib/gpio_test.mpy differ diff --git a/tests/board_test_suite/lib/i2c_test.mpy b/tests/board_test_suite/lib/i2c_test.mpy new file mode 100644 index 0000000000..201d2c9743 Binary files /dev/null and b/tests/board_test_suite/lib/i2c_test.mpy differ diff --git a/tests/board_test_suite/lib/led_test.mpy b/tests/board_test_suite/lib/led_test.mpy new file mode 100644 index 0000000000..4bb0b4134b Binary files /dev/null and b/tests/board_test_suite/lib/led_test.mpy differ diff --git a/tests/board_test_suite/lib/sd_cd_test.mpy b/tests/board_test_suite/lib/sd_cd_test.mpy new file mode 100644 index 0000000000..b2839120b0 Binary files /dev/null and b/tests/board_test_suite/lib/sd_cd_test.mpy differ diff --git a/tests/board_test_suite/lib/sd_test.mpy b/tests/board_test_suite/lib/sd_test.mpy new file mode 100644 index 0000000000..81ec614cc0 Binary files /dev/null and b/tests/board_test_suite/lib/sd_test.mpy differ diff --git a/tests/board_test_suite/lib/spi_test.mpy b/tests/board_test_suite/lib/spi_test.mpy new file mode 100644 index 0000000000..d07d186859 Binary files /dev/null and b/tests/board_test_suite/lib/spi_test.mpy differ diff --git a/tests/board_test_suite/lib/uart_test.mpy b/tests/board_test_suite/lib/uart_test.mpy new file mode 100644 index 0000000000..ecb47c908d Binary files /dev/null and b/tests/board_test_suite/lib/uart_test.mpy differ diff --git a/tests/board_test_suite/lib/voltage_monitor_test.mpy b/tests/board_test_suite/lib/voltage_monitor_test.mpy new file mode 100644 index 0000000000..b04c848b97 Binary files /dev/null and b/tests/board_test_suite/lib/voltage_monitor_test.mpy differ diff --git a/tests/board_test_suite/main.py b/tests/board_test_suite/main.py new file mode 100644 index 0000000000..1c472f1ff6 --- /dev/null +++ b/tests/board_test_suite/main.py @@ -0,0 +1,235 @@ +# The MIT License (MIT) +# +# Copyright (c) 2018 Shawn Hymel for Adafruit Industries +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +""" +`board_test_suite` +==================================================== +CircuitPython board hardware test suite + +* Author(s): Shawn Hymel +* Date: December 8, 2018 + +Implementation Notes +-------------------- +Run this to test various input/output abilities of a board. Tests the following: + +* Onboard LEDs +* GPIO output +* Onboard battery voltage monitor +* SPI +* I2C + +You will need the following components: + +* Multimeter +* LED +* 1x 330 Ohm resistor +* 2x 4.7k Ohm resistor +* Microchip 25AA040A SPI EEPROM +* Microchip AT24HC04B I2C EEPROM +* Breadboard +* Wires + +Copy lib directory to CIRCUITPYTHON drive. Copy the contents of this file to +main.py in root of CIRCUITPYTHON. Open Serial terminal to board and follow +prompts given. +""" + +import board + +import led_test +import gpio_test +import voltage_monitor_test +import uart_test +import spi_test +import i2c_test + +# Constants +UART_TX_PIN_NAME = 'TX' +UART_RX_PIN_NAME = 'RX' +UART_BAUD_RATE = 9600 +SPI_MOSI_PIN_NAME = 'MOSI' +SPI_MISO_PIN_NAME = 'MISO' +SPI_SCK_PIN_NAME = 'SCK' +SPI_CS_PIN_NAME = 'D2' +I2C_SDA_PIN_NAME = 'SDA' +I2C_SCL_PIN_NAME = 'SCL' + +# Results dictionary +test_results = {} + +# Save tested pins +pins_tested = [] + +# Print welcome message +print() +print(" .... ") +print(" #@@%%%%%%&@@/ ") +print(" (&@%%%%%%%%%%%%%@& ") +print(" .(@&%%%@* *&%%%%%%@. ") +print(" ,@@&&%%%%%%%%//@%,/ /&%%%%%%@ ") +print(" %@%%%&%%%%%%%#(@@@&&%%%%%%%%@* ") +print(" @&%%&%%%%%%%%%%%%%%%%%%%%%%@/ ") +print(" &@@&%%%%&&&%%%%%%%%%%%%%%@, ") +print(" ,/ &@&&%%%%%%%%%%%%%%%%%@ ") +print(" ,* *@&%%%%%%%%%%%%# ") +print(" ( @%%%%%%%%%%%@ ") +print(" , @%%%%%%%%%%&@ ") +print(" #&%%%%%%%%%%@. ") +print(" #@###%%%%%%%@/ ") +print(" (@##(%%%%%%%@% ") +print(" /@###(#%%%%%&@ ") +print(" #@####%%%%%%%@ ") +print(" (@###(%%%%%%%@, ") +print(" .@##(((#%%%%%&( .,,. ") +print(" ,@#####%%%%%%%@ ,%@@%%%%%%%&@% ") +print(" ,#&@####(%%%%%%%@@@@@&%%%%%%%%%%%###& ") +print(" @%%@%####(#%%%%%&@%%%%%%%%%%%%%%##/((@@@@&* ") +print(" (##@%#####%%%%%%%@(#%%%(/####(/####(%@%%%%%%@/ ") +print(" (@&%@@###(#%%%%%%@&/####(/#####/#&@@&%%%%%%%##@ ") +print(" #@%%%%@#####(#%%%%%%@@@@@@@@@@@@@&%%%%%%%%%%%%#/(@@@@@/ ") +print(" @%(/#@%######%%%%%%%@%%%%%%%%%%%%%%%%%%%%%(/(###@%%%%%%@% ") +print(" .@@#(#@#####(#%%%%%%&@###//#####/#####/(####/#%@&%%%%%%%%&& ") +print(" /@%%&@@@(#((((#%%%%%%&@###((#####/#####((##%@@&%%%%%%%%%%%/@. ") +print(" ,@%%%%%%#####%%%%%%%%@@@@&&&&&&&%&@@@@@@&%%%%%%%%%%%%%%%##@, ") +print(" %%%%%%%%@######(%%%%%%%@&%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#/(#&& ") +print(" (@###/(%@##((##(%%%%%%%%@%%%%%%%%%%%%%%%%%%%%%%%%%##%###/(&& ") +print(" ,@@%@%##((#%@#######%%%%%%%%@&%%%%##%%%%##%%%%#/#####((####(@* ") +print(" *&(, %@@%##%@#######(%%%%%%%%@#/#####((#####(#####(/#&@&. ") +print(" .@###((#%%%%%%%%%&@@###((#####(###%@@&, ") +print(" #@#(#######%&@@&* .*#&@@@@@@@%(, ") +print(" .,,,.. ") +print() +print("**********************************************************************") +print("* Welcome to the CircuitPython board test suite! *") +print("* Follow the directions to run each test. *") +print("**********************************************************************") +print() + +# List out all the pins available to us +pins = [p for p in dir(board)] +print("All pins found:", end=' ') + +# Print pins +for p in pins: + print(p, end=' ') +print('\n') + +# Run LED test +print("@)}---^----- LED TEST -----^---{(@") +print() +result = led_test.run_test(pins) +test_results["LED Test"] = result[0] +pins_tested.append(result[1]) +print() +print(result[0]) +print() + +# Run GPIO test +print("@)}---^----- GPIO TEST -----^---{(@") +print() +result = gpio_test.run_test(pins) +test_results["GPIO Test"] = result[0] +pins_tested.append(result[1]) +print() +print(result[0]) +print() + +# Run voltage monitor test +print("@)}---^----- VOLTAGE MONITOR TEST -----^---{(@") +print() +result = voltage_monitor_test.run_test(pins) +test_results["Voltage Monitor Test"] = result[0] +pins_tested.append(result[1]) +print() +print(result[0]) +print() + +# Run UART test +print("@)}---^----- UART TEST -----^---{(@") +print() +result = uart_test.run_test(pins, UART_TX_PIN_NAME, UART_RX_PIN_NAME, UART_BAUD_RATE) +test_results["UART Test"] = result[0] +pins_tested.append(result[1]) +print() +print(result[0]) +print() + +# Run SPI test +print("@)}---^----- SPI TEST -----^---{(@") +print() +result = spi_test.run_test( pins, + mosi_pin=SPI_MOSI_PIN_NAME, + miso_pin=SPI_MISO_PIN_NAME, + sck_pin=SPI_SCK_PIN_NAME, + cs_pin=SPI_CS_PIN_NAME) +test_results["SPI Test"] = result[0] +pins_tested.append(result[1]) +print() +print(result[0]) +print() + +# Run I2C test +print("@)}---^----- I2C TEST -----^---{(@") +print() +result = i2c_test.run_test(pins, sda_pin=I2C_SDA_PIN_NAME, scl_pin=I2C_SCL_PIN_NAME) +test_results["I2C Test"] = result[0] +pins_tested.append(result[1]) +print() +print(result[0]) +print() + +# Print out test results +print("@)}---^----- TEST RESULTS -----^---{(@") +print() + +# Find appropriate spaces for printing test results +num_spaces = 0 +for key in test_results: + if len(key) > num_spaces: + num_spaces = len(key) + +# Print test results +for key in test_results: + print(key + ":", end=' ') + for i in range(num_spaces - len(key)): + print(end=' ') + print(test_results[key]) +print() + +# Figure out which pins were tested and not tested +tested = [] +for sublist in pins_tested: + for p in sublist: + tested.append(p) +not_tested = list(set(pins).difference(set(tested))) + +# Print tested pins +print("The following pins were tested:", end=' ') +for p in tested: + print(p, end=' ') +print('\n') + +# Print pins not tested +print("The following pins were NOT tested:", end=' ') +for p in not_tested: + print(p, end=' ') +print('\n') \ No newline at end of file diff --git a/tests/board_test_suite/mpy-cross b/tests/board_test_suite/mpy-cross new file mode 100644 index 0000000000..8dbdb9ab9d Binary files /dev/null and b/tests/board_test_suite/mpy-cross differ diff --git a/tests/board_test_suite/source/gpio_test.py b/tests/board_test_suite/source/gpio_test.py new file mode 100644 index 0000000000..eb88a1d2e0 --- /dev/null +++ b/tests/board_test_suite/source/gpio_test.py @@ -0,0 +1,154 @@ +# The MIT License (MIT) +# +# Copyright (c) 2018 Shawn Hymel for Adafruit Industries +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +""" +`gpio_test` +==================================================== +GPIO Test Module + +* Author(s): Shawn Hymel +* Date: December 8, 2018 + +Implementation Notes +-------------------- +Toggles all available GPIO on a board. Verify their operation with an LED, +multimeter, another microcontroller, etc. + +Run this script as its own main.py to individually run the test, or compile +with mpy-cross and call from separate test script. +""" + +import board +import digitalio +import supervisor +import time + +# Constants +LED_ON_DELAY_TIME = 0.2 # Seconds +LED_OFF_DELAY_TIME = 0.2 # Seconds +LED_PIN_NAMES = ['L', 'LED', 'RED_LED', 'GREEN_LED', 'BLUE_LED'] + +# Test result strings +PASS = "PASS" +FAIL = "FAIL" +NA = "N/A" + +# Determine if given value is a number +def _is_number(s): + try: + float(s) + return True + except ValueError: + return False + +# Release pins +def _deinit_pins(gpios): + for g in gpios: + g.deinit() + +# Toggle IO pins while waiting for answer +def _toggle_wait(gpios): + + global test_results + + timestamp = time.monotonic() + led_state = False + print("Are the pins listed above toggling? [y/n]") + while True: + if led_state: + if time.monotonic() > timestamp + LED_ON_DELAY_TIME: + led_state = False + timestamp = time.monotonic() + else: + if time.monotonic() > timestamp + LED_OFF_DELAY_TIME: + led_state = True + timestamp = time.monotonic() + for gpio in gpios: + gpio.value = led_state + if supervisor.runtime.serial_bytes_available: + answer = input() + if answer == 'y': + return True + else: + return False + break + +def run_test(pins): + + # Create a list of analog GPIO pins + analog_pins = [p for p in pins if p[0] == 'A' and _is_number(p[1])] + + # Create a list of digital GPIO + digital_pins = [p for p in pins if p[0] == 'D' and _is_number(p[1])] + + # Toggle LEDs if we find any + gpio_pins = analog_pins + digital_pins + if gpio_pins: + + # Create a list of IO objects for us to toggle + gpios = [digitalio.DigitalInOut(getattr(board, p)) for p in gpio_pins] + + # Print out the LEDs found + print("GPIO pins found:", end=' ') + for p in gpio_pins: + print(p, end=' ') + print('\n') + + # Set all IO to output + for gpio in gpios: + gpio.direction = digitalio.Direction.OUTPUT + + # Toggle pins while waiting for user to verify LEDs blinking + result = _toggle_wait(gpios) + + # Release pins + _deinit_pins(gpios) + + if result: + return PASS, gpio_pins + else: + return FAIL, gpio_pins + + else: + print("No GPIO pins found") + return NA, [] + +def _main(): + + # List out all the pins available to us + pins = [p for p in dir(board)] + print() + print("All pins found:", end=' ') + + # Print pins + for p in pins: + print(p, end=' ') + print('\n') + + # Run test + result = run_test(pins) + print() + print(result[0]) + print("Pins tested: " + str(result[1])) + +# Execute only if run as main.py or code.py +if __name__ == "__main__": + _main() \ No newline at end of file diff --git a/tests/board_test_suite/source/i2c_test.py b/tests/board_test_suite/source/i2c_test.py new file mode 100644 index 0000000000..ef8d5f07f0 --- /dev/null +++ b/tests/board_test_suite/source/i2c_test.py @@ -0,0 +1,191 @@ +# The MIT License (MIT) +# +# Copyright (c) 2018 Shawn Hymel for Adafruit Industries +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +""" +`i2c_test` +==================================================== +I2C Test Module + +* Author(s): Shawn Hymel +* Date: December 8, 2018 + +Implementation Notes +-------------------- +Performs random writes and reads to I2C EEPROM. + +Requires Microchip AT24HC04B I2C EEPROM. + +Run this script as its own main.py to individually run the test, or compile +with mpy-cross and call from separate test script. +""" + +import board +import busio +import random +import time + +# Constants +SDA_PIN_NAME = 'SDA' +SCL_PIN_NAME = 'SCL' +NUM_I2C_TESTS = 10 # Number of times to write and read EEPROM values +EEPROM_I2C_MAX_ADDR = 255 # Self-imposed max memory address + +# Microchip AT24HC04B EEPROM I2C address +EEPROM_I2C_ADDR = 0x50 + +# Test result strings +PASS = "PASS" +FAIL = "FAIL" +NA = "N/A" + +# Open comms to I2C EEPROM by trying a write to memory address +def _eeprom_i2c_wait(i2c, i2c_addr, mem_addr, timeout = 1.0): + + # Try to access the I2C EEPROM (it becomes unresonsive during a write) + timestamp = time.monotonic() + while time.monotonic() < timestamp + timeout: + try: + i2c.writeto(i2c_addr, bytearray([mem_addr]), end=1, stop=False) + return True + except: + pass + + return False + +# Write to address. Returns status (True for successful write, False otherwise) +def _eeprom_i2c_write_byte(i2c, i2c_addr, mem_addr, mem_data, timeout = 1.0): + + # Make sure address is only one byte: + if mem_addr > 255: + return False + + # Make sure data is only one byte: + if mem_data > 255: + return False + + # Write data to memory at given address + try: + i2c.writeto(i2c_addr, bytearray([mem_addr, mem_data])) + except: + return False + + return True + +# Read from address. Returns tuple [status, result] +def _eeprom_i2c_read_byte(i2c, i2c_addr, mem_addr, timeout = 1.0): + + # Make sure address is only one byte: + if mem_addr > 255: + return False, bytearray() + + # Try writing to address (EEPROM is unresponsive while writing) + if _eeprom_i2c_wait(i2c, i2c_addr, mem_addr, timeout) == False: + return False, bytearray() + + # Finish the read + buf = bytearray(1) + i2c.readfrom_into(i2c_addr, buf) + + return True, buf + +def run_test(pins, sda_pin=SDA_PIN_NAME, scl_pin=SCL_PIN_NAME): + + # Write values to I2C EEPROM and verify the values match + if list(set(pins).intersection(set([sda_pin, scl_pin]))): + + # Tell user to connect EEPROM chip + print("Connect a Microchip AT24HC04B EEPROM I2C chip. " + + "Press enter to continue.") + input() + + # Set up I2C + i2c = busio.I2C(getattr(board, scl_pin), getattr(board, sda_pin)) + + # Wait for I2C lock + while not i2c.try_lock(): + pass + + # Pick a random address, write to it, read from it, and see if they match + pass_test = True + for i in range(NUM_I2C_TESTS): + + # Randomly pick an address and a data value (one byte) + mem_addr = random.randint(0, EEPROM_I2C_MAX_ADDR) + mem_data = random.randint(0, 255) + print("Address:\t" + hex(mem_addr)) + print("Writing:\t" + hex(mem_data)) + + # Try writing this random value to the random address + result = _eeprom_i2c_write_byte(i2c, EEPROM_I2C_ADDR, mem_addr, mem_data) + if result == False: + print("FAIL: I2C could not communicate") + pass_test = False + break + + # Try reading the written value back from EEPROM + result = _eeprom_i2c_read_byte(i2c, EEPROM_I2C_ADDR, mem_addr) + print("Read:\t\t" + hex(result[1][0])) + print() + if result[0] == False: + print("FAIL: I2C could not communicate") + pass_test = False + break + + # Compare the read value to the original value + if result[1][0] != mem_data: + print("FAIL: Data does not match") + pass_test = False + break + + # Release I2C pins + i2c.deinit() + + # Store results + if pass_test: + return PASS, [sda_pin, scl_pin] + else: + return FAIL, [sda_pin, scl_pin] + + else: + print("No I2C pins found") + return NA, [] + +def _main(): + + # List out all the pins available to us + pins = [p for p in dir(board)] + print() + print("All pins found:", end=' ') + + # Print pins + for p in pins: + print(p, end=' ') + print('\n') + + # Run test + result = run_test(pins) + print() + print(result[0]) + print("Pins tested: " + str(result[1])) + +# Execute only if run as main.py or code.py +if __name__ == "__main__": + _main() \ No newline at end of file diff --git a/tests/board_test_suite/source/led_test.py b/tests/board_test_suite/source/led_test.py new file mode 100644 index 0000000000..57e7b8b6c2 --- /dev/null +++ b/tests/board_test_suite/source/led_test.py @@ -0,0 +1,142 @@ +# The MIT License (MIT) +# +# Copyright (c) 2018 Shawn Hymel for Adafruit Industries +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +""" +`led_test` +==================================================== +LED Test Module + +* Author(s): Shawn Hymel +* Date: December 8, 2018 + +Implementation Notes +-------------------- +Toggles all available onboard LEDs. You will need to manually verify their +operation by watching them. + +Run this script as its own main.py to individually run the test, or compile +with mpy-cross and call from separate test script. +""" + +import board +import digitalio +import supervisor +import time + +# Constants +LED_ON_DELAY_TIME = 0.2 # Seconds +LED_OFF_DELAY_TIME = 0.2 # Seconds +LED_PIN_NAMES = ['L', 'LED', 'RED_LED', 'GREEN_LED', 'BLUE_LED'] + +# Test result strings +PASS = "PASS" +FAIL = "FAIL" +NA = "N/A" + +# Release pins +def _deinit_pins(gpios): + for g in gpios: + g.deinit() + +# Toggle IO pins while waiting for answer +def _toggle_wait(gpios): + + global test_results + + timestamp = time.monotonic() + led_state = False + print("Are the pins listed above toggling? [y/n]") + while True: + if led_state: + if time.monotonic() > timestamp + LED_ON_DELAY_TIME: + led_state = False + timestamp = time.monotonic() + else: + if time.monotonic() > timestamp + LED_OFF_DELAY_TIME: + led_state = True + timestamp = time.monotonic() + for gpio in gpios: + gpio.value = led_state + if supervisor.runtime.serial_bytes_available: + answer = input() + if answer == 'y': + return True + else: + return False + break + +def run_test(pins): + + # Look for pins with LED names + led_pins = list(set(pins).intersection(set(LED_PIN_NAMES))) + + # Toggle LEDs if we find any + if led_pins: + + # Print out the LEDs found + print("LEDs found:", end=' ') + for p in led_pins: + print(p, end=' ') + print('\n') + + # Create a list of IO objects for us to toggle + leds = [digitalio.DigitalInOut(getattr(board, p)) for p in led_pins] + + # Set all LEDs to output + for led in leds: + led.direction = digitalio.Direction.OUTPUT + + # Blink LEDs and wait for user to verify test + result = _toggle_wait(leds) + + # Release pins + _deinit_pins(leds) + + if result: + return PASS, led_pins + else: + return FAIL, led_pins + + else: + print("No LED pins found") + return NA, [] + +def _main(): + + # List out all the pins available to us + pins = [p for p in dir(board)] + print() + print("All pins found:", end=' ') + + # Print pins + for p in pins: + print(p, end=' ') + print('\n') + + # Run test + result = run_test(pins) + print() + print(result[0]) + print("Pins tested: " + str(result[1])) + +# Execute only if run as main.py or code.py +if __name__ == "__main__": + _main() \ No newline at end of file diff --git a/tests/board_test_suite/source/sd_cd_test.py b/tests/board_test_suite/source/sd_cd_test.py new file mode 100644 index 0000000000..cee1fd7ba2 --- /dev/null +++ b/tests/board_test_suite/source/sd_cd_test.py @@ -0,0 +1,110 @@ +# The MIT License (MIT) +# +# Copyright (c) 2018 Shawn Hymel for Adafruit Industries +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +""" +`sd_cd_test` +==================================================== +SD CD Test Module + +* Author(s): Shawn Hymel +* Date: December 8, 2018 + +Implementation Notes +-------------------- +Reports the output of an SD card's chip detect (CD) pin. + +Requires SD card. + +Run this script as its own main.py to individually run the test, or compile +with mpy-cross and call from separate test script. +""" + +import board +import digitalio + +# Constants +SD_CD_PIN_NAME = 'SD_CD' + +# Test result strings +PASS = "PASS" +FAIL = "FAIL" +NA = "N/A" + +def run_test(pins, cd_pin=SD_CD_PIN_NAME): + + # Ask user to insert and remove SD card + if list(set(pins).intersection(set([cd_pin]))): + + # Configure CD pin as input with pullup + cd = digitalio.DigitalInOut(getattr(board, cd_pin)) + cd.direction = digitalio.Direction.INPUT + cd.pull = digitalio.Pull.UP + + # Tell user to insert SD card + print("Connect " + cd_pin + " to CD pin on SD card holder.") + print("Insert SD card into holder.") + print("Press enter to continue.") + input() + + # Make sure we see that the pin is low + if cd.value == True: + print("Error: Card not detected") + return FAIL, [cd_pin] + + # Tell user to remove SD card + print("Card detected. Remove card and press enter to continue.") + input() + + # Make sure we see that the pin is high + if cd.value == False: + print("Error: Card detected") + return FAIL, [cd_pin] + + # Test passed + print("Card removed") + return PASS, [cd_pin] + + else: + print("No CD pin found") + return NA, [] + + +def _main(): + + # List out all the pins available to us + pins = [p for p in dir(board)] + print() + print("All pins found:", end=' ') + + # Print pins + for p in pins: + print(p, end=' ') + print('\n') + + # Run test + result = run_test(pins) + print() + print(result[0]) + print("Pins tested: " + str(result[1])) + +# Execute only if run as main.py or code.py +if __name__ == "__main__": + _main() \ No newline at end of file diff --git a/tests/board_test_suite/source/sd_test.py b/tests/board_test_suite/source/sd_test.py new file mode 100644 index 0000000000..47f4510f7c --- /dev/null +++ b/tests/board_test_suite/source/sd_test.py @@ -0,0 +1,157 @@ +# The MIT License (MIT) +# +# Copyright (c) 2018 Shawn Hymel for Adafruit Industries +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +""" +`sd_test` +==================================================== +SD Test Module + +* Author(s): Shawn Hymel +* Date: December 8, 2018 + +Implementation Notes +-------------------- +Performs random writes and reads to SD card over SPI. + +Requires SD card. + +Requires adafruit_sdcard.mpy and adafruit_bus_device modules. + +Run this script as its own main.py to individually run the test, or compile +with mpy-cross and call from separate test script. +""" + +import adafruit_sdcard +import board +import busio +import digitalio +import storage +import random + +# Constants +MOSI_PIN_NAME = 'SD_MOSI' +MISO_PIN_NAME = 'SD_MISO' +SCK_PIN_NAME = 'SD_SCK' +CS_PIN_NAME = 'SD_CS' +FILENAME = "test.txt" # File that will be written to +BAUD_RATE = 100000 # Bits per second +NUM_UART_BYTES = 40 # Number of bytes to transmit over UART +ASCII_MIN = 0x21 # '!' Lowest ASCII char in random range (inclusive) +ASCII_MAX = 0x7E # '~' Highest ASCII char in random range (inclusive) + +# Test result strings +PASS = "PASS" +FAIL = "FAIL" +NA = "N/A" + +def run_test( pins, + mosi_pin=MOSI_PIN_NAME, + miso_pin=MISO_PIN_NAME, + sck_pin=SCK_PIN_NAME, + cs_pin=CS_PIN_NAME, + filename=FILENAME): + + # Write characters to file on SD card and verify they were written + if list(set(pins).intersection(set([mosi_pin, miso_pin, sck_pin]))): + + # Tell user to connect SD card + print("Insert SD card into holder and connect SPI lines to holder.") + print("Connect " + cs_pin + " to the CS (CD/DAT3) pin on the SD " + + "card holder.") + print("WARNING: " + filename + " will be created or overwritten.") + print("Press enter to continue.") + input() + + # Configure CS pin + cs = digitalio.DigitalInOut(getattr(board, cs_pin)) + cs.direction = digitalio.Direction.OUTPUT + cs.value = True + + # Set up SPI + spi = busio.SPI(getattr(board, sck_pin), + MOSI=getattr(board, mosi_pin), + MISO=getattr(board, miso_pin)) + + # Try to connect to the card and mount the filesystem + try: + sdcard = adafruit_sdcard.SDCard(spi, cs) + vfs = storage.VfsFat(sdcard) + storage.mount(vfs, "/sd") + except: + print("Could not mount SD card") + return FAIL, [mosi_pin, miso_pin, sck_pin] + + # Generate test string + test_str = "" + for i in range(NUM_UART_BYTES): + test_str += chr(random.randint(ASCII_MIN, ASCII_MAX)) + + # Write test string to a text file on the card + try: + with open("/sd/" + filename, "w") as f: + print("Writing:\t" + test_str) + f.write(test_str) + except: + print("Could not write to SD card") + return FAIL, [mosi_pin, miso_pin, sck_pin] + + # Read from test file on the card + read_str = "" + try: + with open("/sd/" + filename, "r") as f: + lines = f.readlines() + for line in lines: + read_str += line + print("Read:\t\t" + read_str) + except: + print("Could not read from SD card") + return FAIL, [mosi_pin, miso_pin, sck_pin] + + # Release SPI + spi.deinit() + + # Compare strings + if read_str == test_str: + return PASS, [mosi_pin, miso_pin, sck_pin] + else: + return FAIL, [mosi_pin, miso_pin, sck_pin] + +def _main(): + + # List out all the pins available to us + pins = [p for p in dir(board)] + print() + print("All pins found:", end=' ') + + # Print pins + for p in pins: + print(p, end=' ') + print('\n') + + # Run test + result = run_test(pins) + print() + print(result[0]) + print("Pins tested: " + str(result[1])) + +# Execute only if run as main.py or code.py +if __name__ == "__main__": + _main() \ No newline at end of file diff --git a/tests/board_test_suite/source/spi_test.py b/tests/board_test_suite/source/spi_test.py new file mode 100644 index 0000000000..9d508af9c8 --- /dev/null +++ b/tests/board_test_suite/source/spi_test.py @@ -0,0 +1,232 @@ +# The MIT License (MIT) +# +# Copyright (c) 2018 Shawn Hymel for Adafruit Industries +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +""" +`spi_test` +==================================================== +SPI Test Module + +* Author(s): Shawn Hymel +* Date: December 8, 2018 + +Implementation Notes +-------------------- +Performs random writes and reads to SPI EEPROM. + +Requires Microchip 25AA040A SPI EEPROM. + +Run this script as its own main.py to individually run the test, or compile +with mpy-cross and call from separate test script. +""" + +import board +import digitalio +import busio +import random +import time + +# Constants +MOSI_PIN_NAME = 'MOSI' +MISO_PIN_NAME = 'MISO' +SCK_PIN_NAME = 'SCK' +CS_PIN_NAME = 'D2' +BAUD_RATE = 100000 # Bits per second +NUM_SPI_TESTS = 10 # Number of times to write and read EEPROM values + +# Microchip 25AA040A EEPROM SPI commands and bits +EEPROM_SPI_WRSR = 0x01 +EEPROM_SPI_WRITE = 0x02 +EEPROM_SPI_READ = 0x03 +EEPROM_SPI_WRDI = 0x04 +EEPROM_SPI_RDSR = 0x05 +EEPROM_SPI_WREN = 0x06 +EEPROM_SPI_WIP_BIT = 0 +EEPROM_SPI_MAX_ADDR = 255 # Self-imposed max memory address +EEPROM_I2C_MAX_ADDR = 255 # Self-imposed max memory address + +# Test result strings +PASS = "PASS" +FAIL = "FAIL" +NA = "N/A" + +# Wait for WIP bit to go low +def _eeprom_spi_wait(spi, cs, timeout = 1.0): + + # Continually read from STATUS register + timestamp = time.monotonic() + while time.monotonic() < timestamp + timeout: + + # Perfrom RDSR operation + cs.value = False + result = bytearray(1) + spi.write(bytearray([EEPROM_SPI_RDSR])) + spi.readinto(result) + cs.value = True + + # Mask out and compare WIP bit + if (result[0] & (1 << EEPROM_SPI_WIP_BIT)) == 0: + return True + + return False + +# Write to address. Returns status (True for successful write, False otherwise) +def _eeprom_spi_write_byte(spi, cs, address, data, timeout = 1.0): + + # Make sure address is only one byte: + if address > 255: + return False + + # Make sure data is only one byte: + if data > 255: + return False + + # Wait for WIP to be low + if _eeprom_spi_wait(spi, cs, timeout) == False: + return False + + # Enable writing + cs.value = False + spi.write(bytearray([EEPROM_SPI_WREN])) + cs.value = True + + # Write to address + cs.value = False + spi.write(bytearray([EEPROM_SPI_WRITE, address, data])) + cs.value = True + + return True + +# Read from address. Returns tuple [status, result] +def _eeprom_spi_read_byte(spi, cs, address, timeout = 1.0): + + # Make sure address is only one byte: + if address > 255: + return False, bytearray() + + # Wait for WIP to be low + if _eeprom_spi_wait(spi, cs, timeout) == False: + return False, bytearray() + + # Read byte from address + cs.value = False + result = bytearray(1) + spi.write(bytearray([EEPROM_SPI_READ, address])) + spi.readinto(result) + cs.value = True + + return True, result + +def run_test( pins, + mosi_pin=MOSI_PIN_NAME, + miso_pin=MISO_PIN_NAME, + sck_pin=SCK_PIN_NAME, + cs_pin=CS_PIN_NAME): + + # Write values to SPI EEPROM and verify the values match + if list(set(pins).intersection(set([mosi_pin, miso_pin, sck_pin]))): + + # Tell user to connect EEPROM chip + print("Connect a Microchip 25AA040A EEPROM SPI chip.") + print("Connect " + cs_pin + " to the CS pin on the 25AA040.") + print("Press enter to continue.") + input() + + # Configure CS pin + cs = digitalio.DigitalInOut(getattr(board, cs_pin)) + cs.direction = digitalio.Direction.OUTPUT + cs.value = True + + # Set up SPI + spi = busio.SPI(getattr(board, sck_pin), + MOSI=getattr(board, mosi_pin), + MISO=getattr(board, miso_pin)) + + # Wait for SPI lock + while not spi.try_lock(): + pass + spi.configure(baudrate=BAUD_RATE, phase=0, polarity=0) + + # Pick a random address, write to it, read from it, and see if they match + pass_test = True + for i in range(NUM_SPI_TESTS): + + # Randomly pick an address and a data value (one byte) + mem_addr = random.randint(0, EEPROM_SPI_MAX_ADDR) + mem_data = random.randint(0, 255) + print("Address:\t" + hex(mem_addr)) + print("Writing:\t" + hex(mem_data)) + + # Try writing this random value to the random address + result = _eeprom_spi_write_byte(spi, cs, mem_addr, mem_data) + if result == False: + print("FAIL: SPI could not communicate") + pass_test = False + break + + # Try reading the written value back from EEPRom + result = _eeprom_spi_read_byte(spi, cs, mem_addr) + print("Read:\t\t" + hex(result[1][0])) + print() + if result[0] == False: + print("FAIL: SPI could not communicate") + pass_test = False + break + + # Compare the read value to the original value + if result[1][0] != mem_data: + print("FAIL: Data does not match") + pass_test = False + break + + # Release SPI pins + spi.deinit() + + # Return results + if pass_test: + return PASS, [mosi_pin, miso_pin, sck_pin] + else: + return FAIL, [mosi_pin, miso_pin, sck_pin] + + else: + print("No SPI pins found") + return NA, [] + +def _main(): + + # List out all the pins available to us + pins = [p for p in dir(board)] + print() + print("All pins found:", end=' ') + + # Print pins + for p in pins: + print(p, end=' ') + print('\n') + + # Run test + result = run_test(pins) + print() + print(result[0]) + print("Pins tested: " + str(result[1])) + +# Execute only if run as main.py or code.py +if __name__ == "__main__": + _main() \ No newline at end of file diff --git a/tests/board_test_suite/source/uart_test.py b/tests/board_test_suite/source/uart_test.py new file mode 100644 index 0000000000..1478a37386 --- /dev/null +++ b/tests/board_test_suite/source/uart_test.py @@ -0,0 +1,121 @@ +# The MIT License (MIT) +# +# Copyright (c) 2018 Shawn Hymel for Adafruit Industries +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +""" +`uart_test` +==================================================== +UART Test Module + +* Author(s): Shawn Hymel +* Date: December 8, 2018 + +Implementation Notes +-------------------- +Performs random writes and reads across UART. + +You will need to connect a loopback wire from TX to RX on your board. + +Run this script as its own main.py to individually run the test, or compile +with mpy-cross and call from separate test script. +""" + +import board +import busio +import random + +# Constants +TX_PIN_NAME = 'TX' +RX_PIN_NAME = 'RX' +BAUD_RATE = 9600 +NUM_UART_BYTES = 40 # Number of bytes to transmit over UART +ASCII_MIN = 0x21 # '!' Lowest ASCII char in random range (inclusive) +ASCII_MAX = 0x7E # '~' Highest ASCII char in random range (inclusive) + +# Test result strings +PASS = "PASS" +FAIL = "FAIL" +NA = "N/A" + +def run_test(pins, tx_pin=TX_PIN_NAME, rx_pin=RX_PIN_NAME, baud_rate=BAUD_RATE): + + # Echo some values over the UART + if list(set(pins).intersection(set([tx_pin, rx_pin]))): + + # Tell user to create loopback connection + print("Connect a wire from TX to RX. Press enter to continue.") + input() + + # Initialize UART + uart = busio.UART(getattr(board, tx_pin), + getattr(board, rx_pin), + baudrate=baud_rate) + uart.reset_input_buffer() + + # Generate test string + test_str = "" + for i in range(NUM_UART_BYTES): + test_str += chr(random.randint(ASCII_MIN, ASCII_MAX)) + + # Transmit test string + uart.write(test_str) + print("Transmitting:\t" + test_str) + + # Wait for received string + data = uart.read(len(test_str)) + recv_str = '' + if data is not None: + recv_str = ''.join([chr(b) for b in data]) + print("Received:\t" + recv_str) + + # Release UART pins + uart.deinit() + + # Compare strings + if recv_str == test_str: + return PASS, [tx_pin, rx_pin] + else: + return FAIL, [tx_pin, rx_pin] + + else: + print("No UART pins found") + return NA, [] + +def _main(): + + # List out all the pins available to us + pins = [p for p in dir(board)] + print() + print("All pins found:", end=' ') + + # Print pins + for p in pins: + print(p, end=' ') + print('\n') + + # Run test + result = run_test(pins) + print() + print(result[0]) + print("Pins tested: " + str(result[1])) + +# Execute only if run as main.py or code.py +if __name__ == "__main__": + _main() \ No newline at end of file diff --git a/tests/board_test_suite/source/voltage_monitor_test.py b/tests/board_test_suite/source/voltage_monitor_test.py new file mode 100644 index 0000000000..8cc742cf25 --- /dev/null +++ b/tests/board_test_suite/source/voltage_monitor_test.py @@ -0,0 +1,111 @@ +# The MIT License (MIT) +# +# Copyright (c) 2018 Shawn Hymel for Adafruit Industries +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +""" +`voltage_monitor_test` +==================================================== +Voltage Monitor Test Module + +* Author(s): Shawn Hymel +* Date: December 8, 2018 + +Implementation Notes +-------------------- +Prints out the measured voltage on any onboard voltage/battery monitor pins. +Note that these pins sometimes have an onboard voltage divider to decrease +the voltage. + +Requires multimeter + +Run this script as its own main.py to individually run the test, or compile +with mpy-cross and call from separate test script. +""" + +import board +import analogio + +# Constants +VOLTAGE_MONITOR_PIN_NAMES = ['VOLTAGE_MONITOR', 'BATTERY'] +ANALOG_REF = 3.3 # Reference analog voltage +ANALOGIN_BITS = 16 # ADC resolution (bits) for CircuitPython + +# Test result strings +PASS = "PASS" +FAIL = "FAIL" +NA = "N/A" + +def run_test(pins): + + # Look for pins with battery monitoring names + monitor_pins = list(set(pins).intersection(set(VOLTAGE_MONITOR_PIN_NAMES))) + + # Print out voltage found on these pins + if monitor_pins: + + # Print out the monitor pins found + print("Voltage monitor pins found:", end=' ') + for p in monitor_pins: + print(p, end=' ') + print('\n') + + # Print out the voltage found on each pin + for p in monitor_pins: + monitor = analogio.AnalogIn(getattr(board, p)) + voltage = (monitor.value * ANALOG_REF) / (2**ANALOGIN_BITS) + print(p + ": {:.2f}".format(voltage) + " V") + monitor.deinit() + print() + + # Ask the user to check these voltages + print("Use a multimeter to verify these voltages.") + print("Note that some battery monitor pins might have onboard " + + "voltage dividers.") + print("Do the values look reasonable? [y/n]") + if input() == 'y': + return PASS, monitor_pins + else: + return FAIL, monitor_pins + + else: + print("No battery monitor pins found") + return NA, [] + +def _main(): + + # List out all the pins available to us + pins = [p for p in dir(board)] + print() + print("All pins found:", end=' ') + + # Print pins + for p in pins: + print(p, end=' ') + print('\n') + + # Run test + result = run_test(pins) + print() + print(result[0]) + print("Pins tested: " + str(result[1])) + +# Execute only if run as main.py or code.py +if __name__ == "__main__": + _main() \ No newline at end of file