Initial commit - working code for programming an original trinket/gemma using your friendly circuitpython board

This commit is contained in:
ladyada 2018-01-07 01:25:33 -05:00
commit 86276dd8d1
13 changed files with 1283 additions and 0 deletions

6
.gitignore vendored Normal file
View file

@ -0,0 +1,6 @@
__pycache__
_build
*.pyc
.env
build*
bundles

433
.pylintrc Normal file
View file

@ -0,0 +1,433 @@
[MASTER]
# A comma-separated list of package or module names from where C extensions may
# be loaded. Extensions are loading into the active Python interpreter and may
# run arbitrary code
extension-pkg-whitelist=
# Add files or directories to the blacklist. They should be base names, not
# paths.
ignore=CVS
# Add files or directories matching the regex patterns to the blacklist. The
# regex matches against base names, not paths.
ignore-patterns=
# Python code to execute, usually for sys.path manipulation such as
# pygtk.require().
#init-hook=
# Use multiple processes to speed up Pylint.
# jobs=1
jobs=2
# List of plugins (as comma separated values of python modules names) to load,
# usually to register additional checkers.
load-plugins=
# Pickle collected data for later comparisons.
persistent=yes
# Specify a configuration file.
#rcfile=
# Allow loading of arbitrary C extensions. Extensions are imported into the
# active Python interpreter and may run arbitrary code.
unsafe-load-any-extension=no
[MESSAGES CONTROL]
# Only show warnings with the listed confidence levels. Leave empty to show
# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED
confidence=
# Disable the message, report, category or checker with the given id(s). You
# can either give multiple identifiers separated by comma (,) or put this
# option multiple times (only on the command line, not in the configuration
# file where it should appear only once).You can also use "--disable=all" to
# disable everything first and then reenable specific checks. For example, if
# you want to run only the similarities checker, you can use "--disable=all
# --enable=similarities". If you want to run only the classes checker, but have
# no Warning level messages displayed, use"--disable=all --enable=classes
# --disable=W"
# disable=import-error,print-statement,parameter-unpacking,unpacking-in-except,old-raise-syntax,backtick,long-suffix,old-ne-operator,old-octal-literal,import-star-module-level,raw-checker-failed,bad-inline-option,locally-disabled,locally-enabled,file-ignored,suppressed-message,useless-suppression,deprecated-pragma,apply-builtin,basestring-builtin,buffer-builtin,cmp-builtin,coerce-builtin,execfile-builtin,file-builtin,long-builtin,raw_input-builtin,reduce-builtin,standarderror-builtin,unicode-builtin,xrange-builtin,coerce-method,delslice-method,getslice-method,setslice-method,no-absolute-import,old-division,dict-iter-method,dict-view-method,next-method-called,metaclass-assignment,indexing-exception,raising-string,reload-builtin,oct-method,hex-method,nonzero-method,cmp-method,input-builtin,round-builtin,intern-builtin,unichr-builtin,map-builtin-not-iterating,zip-builtin-not-iterating,range-builtin-not-iterating,filter-builtin-not-iterating,using-cmp-argument,eq-without-hash,div-method,idiv-method,rdiv-method,exception-message-attribute,invalid-str-codec,sys-max-int,bad-python3-import,deprecated-string-function,deprecated-str-translate-call
disable=print-statement,parameter-unpacking,unpacking-in-except,old-raise-syntax,backtick,long-suffix,old-ne-operator,old-octal-literal,import-star-module-level,raw-checker-failed,bad-inline-option,locally-disabled,locally-enabled,file-ignored,suppressed-message,useless-suppression,deprecated-pragma,apply-builtin,basestring-builtin,buffer-builtin,cmp-builtin,coerce-builtin,execfile-builtin,file-builtin,long-builtin,raw_input-builtin,reduce-builtin,standarderror-builtin,unicode-builtin,xrange-builtin,coerce-method,delslice-method,getslice-method,setslice-method,no-absolute-import,old-division,dict-iter-method,dict-view-method,next-method-called,metaclass-assignment,indexing-exception,raising-string,reload-builtin,oct-method,hex-method,nonzero-method,cmp-method,input-builtin,round-builtin,intern-builtin,unichr-builtin,map-builtin-not-iterating,zip-builtin-not-iterating,range-builtin-not-iterating,filter-builtin-not-iterating,using-cmp-argument,eq-without-hash,div-method,idiv-method,rdiv-method,exception-message-attribute,invalid-str-codec,sys-max-int,bad-python3-import,deprecated-string-function,deprecated-str-translate-call,import-error
# Enable the message, report, category or checker with the given id(s). You can
# either give multiple identifier separated by comma (,) or put this option
# multiple time (only on the command line, not in the configuration file where
# it should appear only once). See also the "--disable" option for examples.
enable=
[REPORTS]
# Python expression which should return a note less than 10 (10 is the highest
# note). You have access to the variables errors warning, statement which
# respectively contain the number of errors / warnings messages and the total
# number of statements analyzed. This is used by the global evaluation report
# (RP0004).
evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
# Template used to display messages. This is a python new-style format string
# used to format the message information. See doc for all details
#msg-template=
# Set the output format. Available formats are text, parseable, colorized, json
# and msvs (visual studio).You can also give a reporter class, eg
# mypackage.mymodule.MyReporterClass.
output-format=text
# Tells whether to display a full report or only the messages
reports=no
# Activate the evaluation score.
score=yes
[REFACTORING]
# Maximum number of nested blocks for function / method body
max-nested-blocks=5
[LOGGING]
# Logging modules to check that the string format arguments are in logging
# function parameter format
logging-modules=logging
[SPELLING]
# Spelling dictionary name. Available dictionaries: none. To make it working
# install python-enchant package.
spelling-dict=
# List of comma separated words that should not be checked.
spelling-ignore-words=
# A path to a file that contains private dictionary; one word per line.
spelling-private-dict-file=
# Tells whether to store unknown words to indicated private dictionary in
# --spelling-private-dict-file option instead of raising a message.
spelling-store-unknown-words=no
[MISCELLANEOUS]
# List of note tags to take in consideration, separated by a comma.
# notes=FIXME,XXX,TODO
notes=FIXME,XXX
[TYPECHECK]
# List of decorators that produce context managers, such as
# contextlib.contextmanager. Add to this list to register other decorators that
# produce valid context managers.
contextmanager-decorators=contextlib.contextmanager
# List of members which are set dynamically and missed by pylint inference
# system, and so shouldn't trigger E1101 when accessed. Python regular
# expressions are accepted.
generated-members=
# Tells whether missing members accessed in mixin class should be ignored. A
# mixin class is detected if its name ends with "mixin" (case insensitive).
ignore-mixin-members=yes
# This flag controls whether pylint should warn about no-member and similar
# checks whenever an opaque object is returned when inferring. The inference
# can return multiple potential results while evaluating a Python object, but
# some branches might not be evaluated, which results in partial inference. In
# that case, it might be useful to still emit no-member and other checks for
# the rest of the inferred objects.
ignore-on-opaque-inference=yes
# List of class names for which member attributes should not be checked (useful
# for classes with dynamically set attributes). This supports the use of
# qualified names.
ignored-classes=optparse.Values,thread._local,_thread._local
# List of module names for which member attributes should not be checked
# (useful for modules/projects where namespaces are manipulated during runtime
# and thus existing member attributes cannot be deduced by static analysis. It
# supports qualified module names, as well as Unix pattern matching.
ignored-modules=
# Show a hint with possible names when a member name was not found. The aspect
# of finding the hint is based on edit distance.
missing-member-hint=yes
# The minimum edit distance a name should have in order to be considered a
# similar match for a missing member name.
missing-member-hint-distance=1
# The total number of similar names that should be taken in consideration when
# showing a hint for a missing member.
missing-member-max-choices=1
[VARIABLES]
# List of additional names supposed to be defined in builtins. Remember that
# you should avoid to define new builtins when possible.
additional-builtins=
# Tells whether unused global variables should be treated as a violation.
allow-global-unused-variables=yes
# List of strings which can identify a callback function by name. A callback
# name must start or end with one of those strings.
callbacks=cb_,_cb
# A regular expression matching the name of dummy variables (i.e. expectedly
# not used).
dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_
# Argument names that match this expression will be ignored. Default to name
# with leading underscore
ignored-argument-names=_.*|^ignored_|^unused_
# Tells whether we should check for unused import in __init__ files.
init-import=no
# List of qualified module names which can have objects that can redefine
# builtins.
redefining-builtins-modules=six.moves,future.builtins
[FORMAT]
# Expected format of line ending, e.g. empty (any line ending), LF or CRLF.
# expected-line-ending-format=
expected-line-ending-format=LF
# Regexp for a line that is allowed to be longer than the limit.
ignore-long-lines=^\s*(# )?<?https?://\S+>?$
# Number of spaces of indent required inside a hanging or continued line.
indent-after-paren=4
# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
# tab).
indent-string=' '
# Maximum number of characters on a single line.
max-line-length=100
# Maximum number of lines in a module
max-module-lines=1000
# List of optional constructs for which whitespace checking is disabled. `dict-
# separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}.
# `trailing-comma` allows a space between comma and closing bracket: (a, ).
# `empty-line` allows space-only lines.
no-space-check=trailing-comma,dict-separator
# Allow the body of a class to be on the same line as the declaration if body
# contains single statement.
single-line-class-stmt=no
# Allow the body of an if to be on the same line as the test if there is no
# else.
single-line-if-stmt=no
[SIMILARITIES]
# Ignore comments when computing similarities.
ignore-comments=yes
# Ignore docstrings when computing similarities.
ignore-docstrings=yes
# Ignore imports when computing similarities.
ignore-imports=no
# Minimum lines number of a similarity.
min-similarity-lines=4
[BASIC]
# Naming hint for argument names
argument-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
# Regular expression matching correct argument names
argument-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
# Naming hint for attribute names
attr-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
# Regular expression matching correct attribute names
attr-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
# Bad variable names which should always be refused, separated by a comma
bad-names=foo,bar,baz,toto,tutu,tata
# Naming hint for class attribute names
class-attribute-name-hint=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$
# Regular expression matching correct class attribute names
class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$
# Naming hint for class names
# class-name-hint=[A-Z_][a-zA-Z0-9]+$
class-name-hint=[A-Z_][a-zA-Z0-9_]+$
# Regular expression matching correct class names
# class-rgx=[A-Z_][a-zA-Z0-9]+$
class-rgx=[A-Z_][a-zA-Z0-9_]+$
# Naming hint for constant names
const-name-hint=(([A-Z_][A-Z0-9_]*)|(__.*__))$
# Regular expression matching correct constant names
const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$
# Minimum line length for functions/classes that require docstrings, shorter
# ones are exempt.
docstring-min-length=-1
# Naming hint for function names
function-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
# Regular expression matching correct function names
function-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
# Good variable names which should always be accepted, separated by a comma
# good-names=i,j,k,ex,Run,_
good-names=r,g,b,w,i,j,k,n,x,y,z,ex,ok,Run,_
# Include a hint for the correct naming format with invalid-name
include-naming-hint=no
# Naming hint for inline iteration names
inlinevar-name-hint=[A-Za-z_][A-Za-z0-9_]*$
# Regular expression matching correct inline iteration names
inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$
# Naming hint for method names
method-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
# Regular expression matching correct method names
method-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
# Naming hint for module names
module-name-hint=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
# Regular expression matching correct module names
module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
# Colon-delimited sets of names that determine each other's naming style when
# the name regexes allow several styles.
name-group=
# Regular expression which should only match function or class names that do
# not require a docstring.
no-docstring-rgx=^_
# List of decorators that produce properties, such as abc.abstractproperty. Add
# to this list to register other decorators that produce valid properties.
property-classes=abc.abstractproperty
# Naming hint for variable names
variable-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
# Regular expression matching correct variable names
variable-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
[IMPORTS]
# Allow wildcard imports from modules that define __all__.
allow-wildcard-with-all=no
# Analyse import fallback blocks. This can be used to support both Python 2 and
# 3 compatible code, which means that the block might have code that exists
# only in one or another interpreter, leading to false positives when analysed.
analyse-fallback-blocks=no
# Deprecated modules which should not be used, separated by a comma
deprecated-modules=optparse,tkinter.tix
# Create a graph of external dependencies in the given file (report RP0402 must
# not be disabled)
ext-import-graph=
# Create a graph of every (i.e. internal and external) dependencies in the
# given file (report RP0402 must not be disabled)
import-graph=
# Create a graph of internal dependencies in the given file (report RP0402 must
# not be disabled)
int-import-graph=
# Force import order to recognize a module as part of the standard
# compatibility libraries.
known-standard-library=
# Force import order to recognize a module as part of a third party library.
known-third-party=enchant
[CLASSES]
# List of method names used to declare (i.e. assign) instance attributes.
defining-attr-methods=__init__,__new__,setUp
# List of member names, which should be excluded from the protected access
# warning.
exclude-protected=_asdict,_fields,_replace,_source,_make
# List of valid names for the first argument in a class method.
valid-classmethod-first-arg=cls
# List of valid names for the first argument in a metaclass class method.
valid-metaclass-classmethod-first-arg=mcs
[DESIGN]
# Maximum number of arguments for function / method
max-args=6
# Maximum number of attributes for a class (see R0902).
# max-attributes=7
max-attributes=11
# Maximum number of boolean expressions in a if statement
max-bool-expr=5
# Maximum number of branch for function / method body
max-branches=12
# Maximum number of locals for function / method body
max-locals=15
# Maximum number of parents for a class (see R0901).
max-parents=7
# Maximum number of public methods for a class (see R0904).
max-public-methods=20
# Maximum number of return / yield for function / method body
max-returns=6
# Maximum number of statements in function / method body
max-statements=50
# Minimum number of public methods for a class (see R0903).
min-public-methods=1
[EXCEPTIONS]
# Exceptions that will emit a warning when being caught. Defaults to
# "Exception"
overgeneral-exceptions=Exception

31
.travis.yml Normal file
View file

@ -0,0 +1,31 @@
# This is a common .travis.yml for generating library release zip files for
# CircuitPython library releases using circuitpython-build-tools.
# See https://github.com/adafruit/circuitpython-build-tools for detailed setup
# instructions.
dist: trusty
sudo: false
language: python
python:
- "3.6"
cache:
pip: true
deploy:
provider: releases
api_key: $GITHUB_TOKEN
file_glob: true
file: bundles/*
skip_cleanup: true
overwrite: true
on:
tags: true
install:
- pip install pylint circuitpython-build-tools
script:
- pylint adafruit_avrprog.py
- ([[ ! -d "examples" ]] || pylint --disable=missing-docstring,invalid-name examples/*.py)
- circuitpython-build-bundles --filename_prefix adafruit-circuitpython-avrprog --library_location .

74
CODE_OF_CONDUCT.md Normal file
View file

@ -0,0 +1,74 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, gender identity and expression, level of experience,
nationality, personal appearance, race, religion, or sexual identity and
orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at support@adafruit.com. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at [http://contributor-covenant.org/version/1/4][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/

21
LICENSE Normal file
View file

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2017 ladyada 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.

69
README.rst Normal file
View file

@ -0,0 +1,69 @@
Introduction
============
.. image:: https://readthedocs.org/projects/adafruit-circuitpython-avrprog/badge/?version=latest
:target: https://circuitpython.readthedocs.io/projects/avrprog/en/latest/
:alt: Documentation Status
.. image :: https://img.shields.io/discord/327254708534116352.svg
:target: https://discord.gg/nBQh6qu
:alt: Discord
TODO
Dependencies
=============
This driver depends on:
* `Adafruit CircuitPython <https://github.com/adafruit/circuitpython>`_
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
=============
TODO
API Reference
=============
.. toctree::
:maxdepth: 2
api
Contributing
============
Contributions are welcome! Please read our `Code of Conduct
<https://github.com/adafruit/Adafruit_CircuitPython_AVRprog/blob/master/CODE_OF_CONDUCT.md>`_
before contributing to help this project stay welcoming.
Building locally
================
To build this library locally you'll need to install the
`circuitpython-build-tools <https://github.com/adafruit/circuitpython-build-tools>`_ package.
.. code-block:: shell
python3 -m venv .env
source .env/bin/activate
pip install circuitpython-build-tools
Once installed, make sure you are in the virtual environment:
.. code-block:: shell
source .env/bin/activate
Then run the build:
.. code-block:: shell
circuitpython-build-bundles --filename_prefix adafruit-circuitpython-avrprog --library_location .

362
adafruit_avrprog.py Normal file
View file

@ -0,0 +1,362 @@
# The MIT License (MIT)
#
# Copyright (c) 2017 ladyada 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.
"""
`adafruit_AVRprog`
====================================================
TODO(description)
* Author(s): ladyada
"""
# imports
__version__ = "0.0.0-auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_AVRprog.git"
import busio
from digitalio import Direction, DigitalInOut
class AVRprog:
"""
Program your favorite AVR chips directly from CircuitPython with this
handy helper class that will let you make stand-alone programmers right
from your REPL
"""
_spi = None
_rst = None
_mosi = None
_miso = None
_sck = None
def init(self, sck_pin, mosi_pin, miso_pin, rst_pin):
"""
Initialize the programmer with SPI pins that will be used to
communicate with the chip. Currently only hardware-SPI pins are
supported!
"""
self._spi = busio.SPI(sck_pin, mosi_pin, miso_pin)
#except:
# pins = [DigitalInOut(p) for p in (sck_pin, mosi_pin, miso_pin)]
# self._sck, self._mosi, self._miso = pins
# self._sck.direction = Direction.OUTPUT
# self._sck.value = False
# self._mosi.direction = Direction.OUTPUT
# self._miso.direction = Direction.INPUT
self._rst = DigitalInOut(rst_pin)
self._rst.direction = Direction.OUTPUT
self._rst.value = True
def verify_sig(self, chip):
"""
Verify that the chip is connected properly, responds to commands,
and has the correct signature. Returns True/False based on success
"""
self.begin()
sig = self.read_signature()
self.end()
#print("Signature: ", [hex(i) for i in sig])
if sig != chip['sig']:
return False
return True
def program_file(self, chip, file_name, verbose=False):
"""
Perform a chip erase and program from a file that
contains Intel HEX data. Does not verify the memory post-write!
"""
if not self.verify_sig(chip):
raise RuntimeError("Signature read failure")
self.begin()
if verbose:
print("Erasing chip....")
self.erase_chip()
hexfile = open(file_name, 'r')
page_size = chip['page_size']
for page_addr in range(0, chip['flash_size'], page_size):
#print("Programming page $%04X" % page_addr)
page_buffer = bytearray(page_size)
for b in range(page_size):
page_buffer[b] = 0xFF # make an empty page
read_hex_page(hexfile, page_addr, page_size, page_buffer)
if all([v == 0xFF for v in page_buffer]):
#print("Skipping empty page")
continue
if verbose:
print("Programming page @ $%04X" % (page_addr))
#print("From HEX file: ", page_buffer)
self._flash_page(bytearray(page_buffer), page_addr, page_size)
hexfile.close()
self.end()
def verify_file(self, chip, file_name, verbose=False):
"""
Perform a chip full-flash verification from a file that
contains Intel HEX data. Returns True/False on success/fail.
"""
if not self.verify_sig(chip):
raise RuntimeError("Signature read failure")
hexfile = open(file_name, 'r')
page_size = chip['page_size']
self.begin()
for page_addr in range(0, chip['flash_size'], page_size):
page_buffer = bytearray(page_size)
for b in range(page_size):
page_buffer[b] = 0xFF # make an empty page
read_hex_page(hexfile, page_addr, page_size, page_buffer)
if verbose:
print("Verifying page @ $%04X" % page_addr)
read_buffer = bytearray(page_size)
self.read(page_addr, read_buffer)
#print("From memory: ", read_buffer)
if page_buffer != read_buffer:
if verbose:
# pylint: disable=line-too-long
print("Verify fail at address %04X\nPage should be: %s\nBut contains: %s" % (page_addr, page_buffer, read_buffer))
# pylint: enable=line-too-long
self.end()
return False
hexfile.close()
self.end()
return True
def read_fuses(self, chip):
"""
Read the 4 fuses and return them in a list (low, high, ext, lock)
Each fuse is bitwise-&'s with the chip's fuse mask for simplicity
"""
mask = chip['fuse_mask']
self.begin()
low = self._transaction((0x50, 0, 0, 0))[2] & mask[0]
high = self._transaction((0x58, 0x08, 0, 0))[2] & mask[1]
ext = self._transaction((0x50, 0x08, 0, 0))[2] & mask[2]
lock = self._transaction((0x58, 0, 0, 0))[2] & mask[3]
self.end()
return (low, high, ext, lock)
# pylint: disable=unused-argument,expression-not-assigned
def write_fuses(self, chip, low=None, high=None, ext=None, lock=None):
"""
Write any of the 4 fuses. If the kwarg low/high/ext/lock is not
passed in or is None, that fuse is skipped
"""
self.begin()
lock and self._transaction((0xAC, 0xE0, 0, lock))
low and self._transaction((0xAC, 0xA0, 0, low))
high and self._transaction((0xAC, 0xA8, 0, high))
ext and self._transaction((0xAC, 0xA4, 0, ext))
self.end()
# pylint: enable=unused-argument,expression-not-assigned
def verify_fuses(self, chip, low=None, high=None, ext=None, lock=None):
"""
Verify the 4 fuses. If the kwarg low/high/ext/lock is not
passed in or is None, that fuse is not checked.
Each fuse is bitwise-&'s with the chip's fuse mask.
Returns True on success, False on a fuse verification failure
"""
fuses = self.read_fuses(chip)
verify = (low, high, ext, lock)
for i in range(4):
# check each fuse if we requested to check it!
if verify[i] and verify[i] != fuses[i]:
return False
return True
#################### Mid level
def begin(self):
"""
Begin programming mode: pull reset pin low, initialize SPI, and
send the initialization command to get the AVR's attention.
"""
self._rst.value = False
if self._spi:
while self._spi and not self._spi.try_lock():
pass
self._spi.configure(baudrate=1000000)
self._transaction((0xAC, 0x53, 0, 0))
def end(self):
"""
End programming mode: SPI is released, and reset pin set high.
"""
if self._spi:
self._spi.unlock()
self._rst.value = True
def read_signature(self):
"""
Read and return the signature of the chip as two bytes in an array.
Requires calling begin() beforehand to put in programming mode.
"""
# signature is last byte of two transactions:
sig = [self._transaction((0x30, 0, 0x01, 0))[2]]
sig.append(self._transaction((0x30, 0, 0x02, 0))[2])
return sig
def read(self, addr, read_buffer):
"""
Read a chunk of memory from address 'addr'. The amount read is the
same as the size of the bytearray 'read_buffer'. Data read is placed
directly into 'read_buffer'
Requires calling begin() beforehand to put in programming mode.
"""
for i in range(len(read_buffer)//2):
read_addr = addr//2 + i # read 'words' so address is half
high = self._transaction((0x28, read_addr >> 8, read_addr, 0))[2]
low = self._transaction((0x20, read_addr >> 8, read_addr, 0))[2]
#print("%04X: %02X %02X" % (read_addr*2, low, high))
read_buffer[i*2] = low
read_buffer[i*2+1] = high
def erase_chip(self):
"""
Fully erases the chip.
Requires calling begin() beforehand to put in programming mode.
"""
self._transaction((0xAC, 0x80, 0, 0))
self._busy_wait()
#################### Low level
def _flash_word(self, addr, low, high):
self._transaction((0x40, addr >> 8, addr, low))
self._transaction((0x48, addr >> 8, addr, high))
def _flash_page(self, page_buffer, page_addr, page_size):
for i in range(page_size/2):
lo_byte, hi_byte = page_buffer[2*i:2*i+2]
self._flash_word(i, lo_byte, hi_byte)
page_addr //= 2
commit_reply = self._transaction((0x4C, page_addr >> 8, page_addr, 0))
if ((commit_reply[1] << 8) + commit_reply[2]) != page_addr:
raise RuntimeError("Failed to commit page to flash")
self._busy_wait()
def _transaction(self, command):
reply = bytearray(4)
command = bytearray([i & 0xFF for i in command])
if self._spi:
self._spi.write_readinto(command, reply)
#s = [hex(i) for i in command]
#print("Sending %s reply %s" % (command, reply))
if reply[2] != command[1]:
raise RuntimeError("SPI transaction failed")
return reply[1:] # first byte is ignored
def _busy_wait(self):
while self._transaction((0xF0, 0, 0, 0))[2] & 0x01:
pass
def read_hex_page(hexfile, page_addr, page_size, page_buffer):
"""
Helper function that does the Intel Hex parsing. Given an open file
'hexfile' and our desired buffer address start (page_addr), size
(page_size) and an allocated bytearray. This function will try to
read the file and fill the page_buffer. If the next line has data
that is beyond the size of the page_address, it will return without
changing the buffer, so pre-fill it with 0xFF (for sparsely-defined
HEX files.
Returns False if the file has no more data to read. Returns True if
we've done the best job we can with filling the buffer and the next
line does not contain any more data we can use.
"""
while True: # read until our page_buff is full!
orig_loc = hexfile.tell() # in case we have to 'back up'
line = hexfile.readline() # read one line from the HEX file
if not line:
return False
#print(line)
if line[0] != ':': # lines must start with ':'
raise RuntimeError("HEX line doesn't start with :")
# Try to parse the line length, address, and record type
try:
hex_len = int(line[1:3], 16)
line_addr = int(line[3:7], 16)
rec_type = int(line[7:9], 16)
except ValueError:
raise RuntimeError("Could not parse HEX line addr")
#print("Hex len: %d, addr %04X, record type %d " % (hex_len, line_addr, rec_type))
# We should only look for data type records (0x00)
if rec_type == 0x01:
return False # reached end of file
elif rec_type != 0x00:
raise RuntimeError("Unsupported record type %d" % rec_type)
# check if this file file is either after the current page
# (in which case, we've read all we can for this page and should
# commence flashing...)
if line_addr >= (page_addr + page_size):
#print("Hex is past page address range")
hexfile.seek(orig_loc) # back up!
return True
# or, this line does not yet reach the current page address, in which
# case which should just keep reading in hopes we reach the address
# we're looking for next time!
if (line_addr + hex_len) <= page_addr:
#print("Hex is prior to page address range")
continue
# parse out all remaining hex bytes including the checksum
byte_buffer = []
for i in range(hex_len + 1):
byte_buffer.append(int(line[9+i*2:11+i*2], 16))
# check chksum now!
chksum = hex_len + (line_addr >> 8) + (line_addr & 0xFF) + rec_type + sum(byte_buffer)
#print("checksum: "+hex(chksum))
if (chksum & 0xFF) != 0:
raise RuntimeError("HEX Checksum fail")
# get rid of that checksum byte
byte_buffer.pop()
#print([hex(i) for i in byte_buffer])
#print("line addr $%04X page addr $%04X" % (line_addr, page_addr))
page_idx = line_addr - page_addr
line_idx = 0
while (page_idx < page_size) and (line_idx < hex_len):
#print("page_idx = %d, line_idx = %d" % (page_idx, line_idx))
page_buffer[page_idx] = byte_buffer[line_idx]
line_idx += 1
page_idx += 1
if page_idx == page_size:
return True # ok we've read a full page, can bail now!
return False # we...shouldn't get here?

5
api.rst Normal file
View file

@ -0,0 +1,5 @@
.. If you created a package, create one automodule per module in the package.
.. automodule:: adafruit_avrprog
:members:

147
conf.py Normal file
View file

@ -0,0 +1,147 @@
# -*- coding: utf-8 -*-
import os
import sys
sys.path.insert(0, os.path.abspath('.'))
# -- General configuration ------------------------------------------------
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
'sphinx.ext.autodoc',
'sphinx.ext.intersphinx',
'sphinx.ext.viewcode',
]
# Uncomment the below if you use native CircuitPython modules such as
# digitalio, micropython and busio. List the modules you use. Without it, the
# autodoc module docs will fail to generate with a warning.
# autodoc_mock_imports = ["digitalio", "busio"]
intersphinx_mapping = {'python': ('https://docs.python.org/3.4', None),'CircuitPython': ('https://circuitpython.readthedocs.io/en/latest/', None)}
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
source_suffix = '.rst'
# The master toctree document.
master_doc = 'README'
# General information about the project.
project = u'Adafruit AVRprog Library'
copyright = u'2017 ladyada'
author = u'ladyada'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = u'1.0'
# The full version, including alpha/beta/rc tags.
release = u'1.0'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = None
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This patterns also effect to html_static_path and html_extra_path
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
# The reST default role (used for this markup: `text`) to use for all
# documents.
#
default_role = "any"
# If true, '()' will be appended to :func: etc. cross-reference text.
#
add_function_parentheses = True
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos = False
# -- Options for HTML output ----------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
on_rtd = os.environ.get('READTHEDOCS', None) == 'True'
if not on_rtd: # only import and set the theme if we're building docs locally
try:
import sphinx_rtd_theme
html_theme = 'sphinx_rtd_theme'
html_theme_path = [sphinx_rtd_theme.get_html_theme_path(), '.']
except:
html_theme = 'default'
html_theme_path = ['.']
else:
html_theme_path = ['.']
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# Output file base name for HTML help builder.
htmlhelp_basename = 'AdafruitAvrprogLibrarydoc'
# -- Options for LaTeX output ---------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#
# 'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#
# 'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#
# 'preamble': '',
# Latex figure (float) alignment
#
# 'figure_align': 'htbp',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
(master_doc, 'AdafruitAVRprogLibrary.tex', u'AdafruitAVRprog Library Documentation',
author, 'manual'),
]
# -- Options for manual page output ---------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
(master_doc, 'AdafruitAVRproglibrary', u'Adafruit AVRprog Library Documentation',
[author], 1)
]
# -- Options for Texinfo output -------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
(master_doc, 'AdafruitAVRprogLibrary', u'Adafruit AVRprog Library Documentation',
author, 'AdafruitAVRprogLibrary', 'One line description of project.',
'Miscellaneous'),
]

View file

@ -0,0 +1,94 @@
:2000000093CA15C0EBCA13C012C011C010C00FC00EC00DC00CC00BC00AC009C008C0112422
:200020001FBECFE5D2E0DEBFCDBF02D002C0E8CFFFCFF89400C0F894FFCF00000000000095
:20148000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6C
:2014A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB8C5AFC557
:2014C00033C05FC08BC05DC05CC05BC05AC059C058C057C056C055C054C053C052C009028A
:2014E0001200010100803209040000000000000012011001FF00000881179F0C05010102A2
:20150000000110035400720069006E006B006500740012034100640061006600720075006E
:20152000690074000403090411241FBECFE5D2E0DEBFCDBF84B7877F84BF88E10FB6F894DB
:2015400081BD11BC0FBE91E080E80FB6F89486BD96BD0FBE0AEA0F9310E0A0E6B0E0EEEDAF
:20156000FFE102C005900D92A236B107D9F711E0A2E6B0E001C01D92A832B107E1F7F2D38D
:201580002CC59ECFA82FB92F80E090E041E050EA609530E009C02D9182279795879510F086
:2015A00084279527305EC8F36F5FA8F30895EADF8D939D930895A6E088279927AA9569F032
:2015C0000197E1F3B399FCCFB39BFECF81E09927A6B3019611F0A871D9F70895CF93CFB7ED
:2015E000CF93C0915F02CA3A21F0CF91CFBFCF9165CFCC27C395B39BE9F7B39B0BC0B39B60
:2016000009C0B39B07C0B39B05C0B39B03C0B39B01C0D3C00F92DF93C0910B01DD27CE5E86
:20162000DE4F012EB39B03C0DF910F90E6CF2F930F931F934F932FEF4F6F06B303FB20F9D5
:201640005F933F9350E03BE065C016B30126502953FDC89556B3012703FB25F92F7306B398
:20166000B1F05027102713FB26F906B22230F0F000C016B3012703FB27F90126502906B2DD
:201680002430E8F54F77206816B30000F6CF50274F7D206206B2102F000000C006B30026E2
:2016A0005029102713FB26F906B2E2CF4F7B06B3206400C0DACF01265029187106B269F139
:2016C0004E7F2160012F16B328C0002650294D7F06B22260102F29C0012650294B7F06B2EC
:2016E0002460012F2DC016B301265029477F2860000006B22EC04F7E06B3206130C042278C
:2017000006B3499300265029102706B24FEF13FB20F9297F16B379F2187159F101265029F2
:2017200006B2012703FB21F9237F06B371F2002650293150D0F006B2102713FB22F9277E56
:2017400016B351F201265029012703FB06B223F92F7C49F2000006B3102713FB24F90026BC
:20176000502906B22F7939F270CF10E21ABF002717C03B503195C31BD04010E21ABF0881CA
:20178000033CF9F00B34E9F0209109011981110F1213EDCF093651F10D3211F0013E39F783
:2017A000009310013F915F914F911F910F912F91DF910F90CAB7C5FD1DCFCF91CFBFCF9149
:2017C000189520911001222369F310910E01112321F5343022F130930E0120930A01109157
:2017E0000B013BE0311B30930B0119C000910E0101309CF40AE53091600034FD11C00093C8
:201800006000CEEFD0E010C0052710E000C021C0052710E0C89508BB14C03AE501C032ED5F
:20182000032EC0E0D0E032E017B31861C39A08B317BB58E120E84FEF20FF052708BB27959F
:2018400017951C3F28F700004552B0F720FF0527279508BB17951C3FB8F629913A9561F7C4
:20186000077E10910F01110F08BBC250D04011F01093090110E21ABF086017B3177E402F7E
:20188000477E54E05A95F1F708BB17BB48BB8ACF20916F00309170002D3B3441B8F421E0AC
:2018A00020937100F894E0916F00F09170000C0120935700E8951124789480916F00909131
:2018C000700002969093700080936F00089580917100882309F43CC080916F009091700017
:2018E000813C944108F034C0F89480916F00909170008238944110F121E080917200909198
:2019000073008F559A409F70906CEEEBF4E10C0120935700E895112480917A0090917B00ED
:201920008C559A409F70906CECEBF4E10C0120935700E8951124789420936E00E0916F005F
:20194000F0917000329785E080935700E8957894109271000895FF920F931F93CF93DF930C
:2019600080910E01835087FD4EC190910B01ACE0B0E0A91BB109AE5EBE4F31E030936200CB
:2019800090910A019D3209F0FBC0883009F039C183EC8093FE008AE5809360001092F200F7
:2019A0008C91807609F478C010926C0010926B0010926A0011962C911197213009F4C5C1D8
:2019C000263009F447C0273009F042C03093670083EF90E090930D0180930C0113969C9128
:2019E00013979093F5001092F60012968C911297803379F49111ABC11496EC911497F0E04F
:201A0000EE0FFF1F81E280935700E491E093F6009EC18C3A89F4903809F099C114968C917C
:201A20001497811194C115968C91159781118FC181E0809363008BC18C3409F088C11596EE
:201A40008C911597811183C181E0809366007FC1283019F4309367007CC114968D919C910C
:201A600015979093700080936F0016968C9116978093FB00822F8950843008F06AC18FE74A
:201A800088BD309368002093FC002A3009F458C181E08093670054C112969C9112971092A7
:201AA000070111968C911197811106C01092080187E091E022E04CC0853019F490930F01D4
:201AC0003DC0863091F513968C911397813019F480EF94E104C0823041F48EED94E19093FD
:201AE0000D0180930C0122E11CC08330C9F4911108C084E295E190930D0180930C0124E0CE
:201B000010C0913019F482E195E1E9CF923041F482E095E190930D0180930C0120E101C0B4
:201B200020E080E48093F2001EC0883059F0893019F49093110102C08A3039F087E091E0E5
:201B400020E006C081E191E002C087E091E021E090930D0180930C0106C016962C9180E869
:201B60008093F2000AC017968C911797811105C016968C91821708F4282F2093610041C0FD
:201B80009091F20097FF3DC09091FB00182F981708F4192F092F011B0093FB00109267005E
:201BA0008091FC008C3019F4002349F12AC08A30D9F7FA2ECA2FDB2F1DC080916F009091D5
:201BC00070008034910590F421E020936D00FC01EE0FFF1FEE58FF4F288139813183208340
:201BE00002969093700080936F0003C0888199814FDE22968C2F8F198117F8F2D5CF109242
:201C0000610010920E018091600084FF80C0809161008F3F09F47BC0182F893008F018E016
:201C2000811B809361008091FE0098E889278093FE00112309F45AC08091F20087FF38C078
:201C40008091FB00811708F4182F811B8093FB003091FC00E0916F00F091700020E0AFEFC7
:201C6000B0E01FC03B3009F476C03930D9F7E034F10560F4EF01CC0FDD1FCE58DF4F88819C
:201C800099818D939D9332962E5F0BC0EC3B84E1F80710F08FEF01C084918C93119631964E
:201CA0002F5F2117F8F2F0937000E0936F001CC0E0910C01F0910D01AFEFB0E086FF09C03A
:201CC00084918D9331968FEF90E0810F8A13F8CF07C081918D938FEF90E0810F8A13F9CF4A
:201CE000F0930D01E0930C01193058F4612F8FEF90E05DDC1C5F1C3041F08FEF809361009D
:201D000004C08FEF809361001EE11093600084E196B3987131F48150D9F710920F0110923A
:201D20000901C1E08111C0E08091FD008C17A1F0C11103C0F8940FD17894C093FD000CC05B
:201D40008C9187FD0ACF2FEF0ACF21E00CCF24E00ACF20E008CFFFCFDF91CF911F910F9194
:201D6000FF900895C1B7B99A83E28ABD81E083BF8BB780628BBFAC9ABB9A2FE132E18AE087
:201D8000215030408040E1F700C00000BB987894E2DD80916300882321F182E090E09093C6
:201DA00065008093640013C0CF018F739927892B21F483E080935700E895CDDD80916400B0
:201DC0009091650002969093650080936400E0916400F0916500E03C94E1F90728F31092DD
:201DE000630080916600882329F0B5DD70DD10926600B1DD80916200882341F08091670009
:201E0000811104C0809168008111C2CF80916200882371F08091690081110AC088B5805F5F
:201E200088BD88B5811104C08AB590E189278ABD809169008F5F809369008EEC90E00197BD
:201E4000F1F780916A0090916B00019690936B0080936A0020916C00009711F42F5F00C0EA
:201E600020936C0030916200311105C081323EE4930708F05BC030916700332321F0813156
:201E8000974208F053C080916200882309F480CF8091680081117CCF233008F047C078CF05
:201EA00080916E0081114AC08CEB94E19093700080936F0081E08093710009DD3FC0DF015C
:201EC000AA0FBB1FAE58BF4F8D919C91309719F0E430F10531F4E054FB4E85919491805A7F
:201EE000954FD6DCE0916F00F0917000E034F10530F3EDDC10925F0217BA13BE1ABC03C047
:201F000081B78F5F81BF81B78C17D0F303C081B7815081BF81B7C817D0F391E080E80FB639
:201F2000F89486BD96BD0FBECACA13C01BBE15BAF89480916D008111B3CFDCCFE0E0F0E04A
:201F400083E080935700E8951092700010926F00C9CF80E090E0FF920F931F93CF93DF93F3
:201F600090E080E80FB6F89486BD96BD0FBEC8E0D0E010E000E8F12EF00EF1BE1CDB84332B
:201F800029E092070CF41F2D06952197A1F7212F215021BFEC01012F10C00DDB8453994042
:201FA00097FF03C09195819591098C179D0714F401B7EC0181B78F5F81BF81B790E0212FA0
:201FC00030E02F5F3F4F281739073CF701BFDF91CF911F910F91FF900895F894FFCF5AFF64
:00000001FF

View file

@ -0,0 +1,37 @@
# Original Trinket or Gemma (ATtiny85) programming example
import board
import adafruit_avrprog
avrprog = adafruit_avrprog.AVRprog()
avrprog.init(board.SCK, board.MOSI, board.MISO, board.D5)
# Each chip has to have a definition so the script knows how to find it
attiny85 = {'name': "ATtiny85"}
attiny85['sig'] = [0x93, 0x0b]
attiny85['flash_size'] = 8192
attiny85['page_size'] = 64
attiny85['fuse_mask'] = (0xFF, 0xFF, 0x07, 0x3F)
# Helper to print out errors for us
def error(err):
print("ERROR: "+err)
avrprog.end()
while True:
pass
if not avrprog.verify_sig(attiny85):
error("Signature read failure")
print("Found", attiny85['name'])
avrprog.write_fuses(attiny85, low=0xF1, high=0xD5, ext=0x06, lock=0x3F)
if not avrprog.verify_fuses(attiny85, low=0xF1, high=0xD5, ext=0x06, lock=0x3F):
error("Failure verifying fuses!")
print("Programming flash from file")
avrprog.program_file(attiny85, "trinket.hex", verbose=True)
print("Verifying flash vs file")
avrprog.verify_file(attiny85, "trinket.hex", verbose=True)
print("Done!")

3
readthedocs.yml Normal file
View file

@ -0,0 +1,3 @@
python:
version: 3
requirements_file: requirements.txt

1
requirements.txt Normal file
View file

@ -0,0 +1 @@