Added board test suite
This commit is contained in:
parent
3d597aae92
commit
52dbbcb23f
56
tests/board_test_suite/README.rst
Normal file
56
tests/board_test_suite/README.rst
Normal file
@ -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.
|
BIN
tests/board_test_suite/doc/test_jib.png
Normal file
BIN
tests/board_test_suite/doc/test_jib.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 164 KiB |
BIN
tests/board_test_suite/doc/test_jig.fzz
Normal file
BIN
tests/board_test_suite/doc/test_jig.fzz
Normal file
Binary file not shown.
BIN
tests/board_test_suite/doc/test_jig_bb.png
Normal file
BIN
tests/board_test_suite/doc/test_jig_bb.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 146 KiB |
BIN
tests/board_test_suite/lib/adafruit_bus_device/i2c_device.mpy
Normal file
BIN
tests/board_test_suite/lib/adafruit_bus_device/i2c_device.mpy
Normal file
Binary file not shown.
BIN
tests/board_test_suite/lib/adafruit_bus_device/spi_device.mpy
Normal file
BIN
tests/board_test_suite/lib/adafruit_bus_device/spi_device.mpy
Normal file
Binary file not shown.
BIN
tests/board_test_suite/lib/adafruit_sdcard.mpy
Normal file
BIN
tests/board_test_suite/lib/adafruit_sdcard.mpy
Normal file
Binary file not shown.
BIN
tests/board_test_suite/lib/gpio_test.mpy
Normal file
BIN
tests/board_test_suite/lib/gpio_test.mpy
Normal file
Binary file not shown.
BIN
tests/board_test_suite/lib/i2c_test.mpy
Normal file
BIN
tests/board_test_suite/lib/i2c_test.mpy
Normal file
Binary file not shown.
BIN
tests/board_test_suite/lib/led_test.mpy
Normal file
BIN
tests/board_test_suite/lib/led_test.mpy
Normal file
Binary file not shown.
BIN
tests/board_test_suite/lib/sd_cd_test.mpy
Normal file
BIN
tests/board_test_suite/lib/sd_cd_test.mpy
Normal file
Binary file not shown.
BIN
tests/board_test_suite/lib/sd_test.mpy
Normal file
BIN
tests/board_test_suite/lib/sd_test.mpy
Normal file
Binary file not shown.
BIN
tests/board_test_suite/lib/spi_test.mpy
Normal file
BIN
tests/board_test_suite/lib/spi_test.mpy
Normal file
Binary file not shown.
BIN
tests/board_test_suite/lib/uart_test.mpy
Normal file
BIN
tests/board_test_suite/lib/uart_test.mpy
Normal file
Binary file not shown.
BIN
tests/board_test_suite/lib/voltage_monitor_test.mpy
Normal file
BIN
tests/board_test_suite/lib/voltage_monitor_test.mpy
Normal file
Binary file not shown.
235
tests/board_test_suite/main.py
Normal file
235
tests/board_test_suite/main.py
Normal file
@ -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')
|
BIN
tests/board_test_suite/mpy-cross
Normal file
BIN
tests/board_test_suite/mpy-cross
Normal file
Binary file not shown.
154
tests/board_test_suite/source/gpio_test.py
Normal file
154
tests/board_test_suite/source/gpio_test.py
Normal file
@ -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()
|
191
tests/board_test_suite/source/i2c_test.py
Normal file
191
tests/board_test_suite/source/i2c_test.py
Normal file
@ -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()
|
142
tests/board_test_suite/source/led_test.py
Normal file
142
tests/board_test_suite/source/led_test.py
Normal file
@ -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()
|
110
tests/board_test_suite/source/sd_cd_test.py
Normal file
110
tests/board_test_suite/source/sd_cd_test.py
Normal file
@ -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()
|
157
tests/board_test_suite/source/sd_test.py
Normal file
157
tests/board_test_suite/source/sd_test.py
Normal file
@ -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()
|
232
tests/board_test_suite/source/spi_test.py
Normal file
232
tests/board_test_suite/source/spi_test.py
Normal file
@ -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()
|
121
tests/board_test_suite/source/uart_test.py
Normal file
121
tests/board_test_suite/source/uart_test.py
Normal file
@ -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()
|
111
tests/board_test_suite/source/voltage_monitor_test.py
Normal file
111
tests/board_test_suite/source/voltage_monitor_test.py
Normal file
@ -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()
|
Loading…
Reference in New Issue
Block a user