summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tests/board_test_suite/README.rst56
-rw-r--r--tests/board_test_suite/doc/test_jib.pngbin0 -> 168217 bytes
-rw-r--r--tests/board_test_suite/doc/test_jig.fzzbin0 -> 7586 bytes
-rw-r--r--tests/board_test_suite/doc/test_jig_bb.pngbin0 -> 149724 bytes
-rw-r--r--tests/board_test_suite/lib/adafruit_bus_device/__init__.py0
-rw-r--r--tests/board_test_suite/lib/adafruit_bus_device/i2c_device.mpybin0 -> 1707 bytes
-rw-r--r--tests/board_test_suite/lib/adafruit_bus_device/spi_device.mpybin0 -> 1250 bytes
-rw-r--r--tests/board_test_suite/lib/adafruit_sdcard.mpybin0 -> 5349 bytes
-rw-r--r--tests/board_test_suite/lib/gpio_test.mpybin0 -> 2036 bytes
-rw-r--r--tests/board_test_suite/lib/i2c_test.mpybin0 -> 2420 bytes
-rw-r--r--tests/board_test_suite/lib/led_test.mpybin0 -> 1765 bytes
-rw-r--r--tests/board_test_suite/lib/sd_cd_test.mpybin0 -> 1342 bytes
-rw-r--r--tests/board_test_suite/lib/sd_test.mpybin0 -> 2256 bytes
-rw-r--r--tests/board_test_suite/lib/spi_test.mpybin0 -> 3232 bytes
-rw-r--r--tests/board_test_suite/lib/uart_test.mpybin0 -> 1446 bytes
-rw-r--r--tests/board_test_suite/lib/voltage_monitor_test.mpybin0 -> 1423 bytes
-rw-r--r--tests/board_test_suite/main.py235
-rw-r--r--tests/board_test_suite/mpy-crossbin0 -> 194960 bytes
-rw-r--r--tests/board_test_suite/source/gpio_test.py154
-rw-r--r--tests/board_test_suite/source/i2c_test.py191
-rw-r--r--tests/board_test_suite/source/led_test.py142
-rw-r--r--tests/board_test_suite/source/sd_cd_test.py110
-rw-r--r--tests/board_test_suite/source/sd_test.py157
-rw-r--r--tests/board_test_suite/source/spi_test.py232
-rw-r--r--tests/board_test_suite/source/uart_test.py121
-rw-r--r--tests/board_test_suite/source/voltage_monitor_test.py111
26 files changed, 1509 insertions, 0 deletions
diff --git a/tests/board_test_suite/README.rst b/tests/board_test_suite/README.rst
new file mode 100644
index 000000000..7fed9d35b
--- /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 *<name>_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 <https://github.com/adafruit/circuitpython>`_
+* `SD Card <https://github.com/adafruit/Adafruit_CircuitPython_SD>`_
+* `Bus Device <https://github.com/adafruit/Adafruit_CircuitPython_BusDevice>`_
+
+Please ensure all dependencies are available on the CircuitPython filesystem.
+This is easily achieved by downloading
+`the Adafruit library and driver bundle <https://github.com/adafruit/Adafruit_CircuitPython_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 000000000..22dd927b2
--- /dev/null
+++ b/tests/board_test_suite/doc/test_jib.png
Binary files 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 000000000..e97a84024
--- /dev/null
+++ b/tests/board_test_suite/doc/test_jig.fzz
Binary files 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 000000000..89ec28dbe
--- /dev/null
+++ b/tests/board_test_suite/doc/test_jig_bb.png
Binary files 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 000000000..e69de29bb
--- /dev/null
+++ b/tests/board_test_suite/lib/adafruit_bus_device/__init__.py
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 000000000..f33d4d495
--- /dev/null
+++ b/tests/board_test_suite/lib/adafruit_bus_device/i2c_device.mpy
Binary files 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 000000000..f43100ee8
--- /dev/null
+++ b/tests/board_test_suite/lib/adafruit_bus_device/spi_device.mpy
Binary files 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 000000000..03f65fa63
--- /dev/null
+++ b/tests/board_test_suite/lib/adafruit_sdcard.mpy
Binary files 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 000000000..9e90b9ca6
--- /dev/null
+++ b/tests/board_test_suite/lib/gpio_test.mpy
Binary files 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 000000000..201d2c974
--- /dev/null
+++ b/tests/board_test_suite/lib/i2c_test.mpy
Binary files 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 000000000..4bb0b4134
--- /dev/null
+++ b/tests/board_test_suite/lib/led_test.mpy
Binary files 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 000000000..b2839120b
--- /dev/null
+++ b/tests/board_test_suite/lib/sd_cd_test.mpy
Binary files 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 000000000..81ec614cc
--- /dev/null
+++ b/tests/board_test_suite/lib/sd_test.mpy
Binary files 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 000000000..d07d18685
--- /dev/null
+++ b/tests/board_test_suite/lib/spi_test.mpy
Binary files 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 000000000..ecb47c908
--- /dev/null
+++ b/tests/board_test_suite/lib/uart_test.mpy
Binary files 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 000000000..b04c848b9
--- /dev/null
+++ b/tests/board_test_suite/lib/voltage_monitor_test.mpy
Binary files differ
diff --git a/tests/board_test_suite/main.py b/tests/board_test_suite/main.py
new file mode 100644
index 000000000..1c472f1ff
--- /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 000000000..8dbdb9ab9
--- /dev/null
+++ b/tests/board_test_suite/mpy-cross
Binary files 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 000000000..eb88a1d2e
--- /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 000000000..ef8d5f07f
--- /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 000000000..57e7b8b6c
--- /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 000000000..cee1fd7ba
--- /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 000000000..47f4510f7
--- /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 000000000..9d508af9c
--- /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 000000000..1478a3738
--- /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 000000000..8cc742cf2
--- /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