Compare commits

...

113 commits

Author SHA1 Message Date
Melissa LeBlanc-Williams
3ca62375a9
Merge pull request #41 from makermelissa/master
Added grayscale image mode support because why not
2020-08-18 14:01:38 -07:00
Melissa LeBlanc-Williams
732e1a0d7e Added grayscale image support just because 2020-08-18 13:51:29 -07:00
Limor "Ladyada" Fried
be557c4a00
Merge pull request #40 from makermelissa/master
Split out spi to make guide changes easier
2020-08-17 23:29:16 -04:00
Melissa LeBlanc-Williams
8b94ab6048 Same hanges to Pillow Demo too 2020-08-17 16:44:46 -07:00
Melissa LeBlanc-Williams
75cff623c3 Split out spi to make guide changes easier 2020-08-17 16:36:15 -07:00
dherrada
2028a7c556 Fixed discord invite link 2020-07-08 16:49:04 -04:00
Scott Shawcroft
57cd0da24a
Merge pull request #38 from adafruit/black-update
Black reformatting with Python 3 target.
2020-04-09 09:38:51 -07:00
Kattni Rembor
3cdab905e6 Black reformatting with Python 3 target. 2020-04-08 15:03:55 -04:00
sommersoft
9a4bff491f build.yml: add black formatting check
Signed-off-by: sommersoft <sommersoft@gmail.com>
2020-04-07 16:06:03 -05:00
Kattni
70012786fe
Merge pull request #37 from adafruit/pylint-update
Ran black, updated to pylint 2.x
2020-03-17 13:11:13 -04:00
dherrada
c13f9f53c1 Ran black, updated to pylint 2.x 2020-03-16 14:41:40 -04:00
sommersoft
faeb1a75d8 update code of coduct: discord moderation contact section
Signed-off-by: sommersoft <sommersoft@gmail.com>
2020-03-15 18:32:12 -05:00
Kattni
55c07effaa
Merge pull request #36 from sommersoft/patch_coc
Update Code of Conduct
2020-03-13 15:59:31 -04:00
sommersoft
b68223a2fb update code of conduct 2020-03-13 13:52:36 -05:00
sommersoft
70ace79fa1 update pylintrc for black
Signed-off-by: sommersoft <sommersoft@gmail.com>
2020-03-08 19:10:23 -05:00
sommersoft
1de1df49dc build.yml: move pylint, black, and Sphinx installs to each repo; add description to 'actions-ci/install.sh'
Signed-off-by: sommersoft <sommersoft@gmail.com>
2020-03-05 10:09:37 -06:00
Melissa LeBlanc-Williams
1f18b62616
Merge pull request #35 from mariovisic/nice_to_cpu
Reduce the CPU load when waiting for the display
2020-02-10 18:14:11 -08:00
Mario Visic
7b064da754 Call sleep() on time 2020-02-06 21:35:46 +11:00
Mario Visic
7ac5141509 Reduce the CPU load when waiting for the display
In many places a `pass` instruction is used in loops to wait until we hear back
back from the display. This causes the loop to execute continuously which uses
all of the available CPU, if we instead sleep for 1ms, we don't lose much time
(less than 1ms each wait) and we dramatically reduce the load on the CPU.

Before the change (updating a 3-color 2.13" display):

```
time python3 ./update_display

real    0m19.664s
user    0m17.622s
sys     0m1.046s
```

After the change:

time python3 ./update_display

real    0m19.730s
user    0m3.563s
sys     0m0.792s1

The total time to run the script is about the same, but the CPU time has reduced dramatically.
2020-02-06 21:03:43 +11:00
sommersoft
dfcdd62ee2 update pylint examples directive
Signed-off-by: sommersoft <sommersoft@gmail.com>
2020-01-14 17:15:23 -06:00
Limor "Ladyada" Fried
9d3b4bff13
Merge pull request #34 from adafruit/dherrada-patch-1
Moved repository from Travis to GitHub Actions
2020-01-04 21:50:56 -05:00
dherrada
14a086eadb Moved repository from Travis to GitHub Actions 2020-01-04 14:17:32 -05:00
Melissa LeBlanc-Williams
92323d3384
Merge pull request #33 from makermelissa/master
Added EPD Pillow Shapes and Text demo
2019-10-22 10:35:12 -07:00
Melissa LeBlanc-Williams
1b43ad5ccc Added EPD Pillow Shapes and Text demo 2019-10-22 10:23:33 -07:00
Melissa LeBlanc-Williams
81caa6374f
Merge pull request #32 from makermelissa/master
Added Pillow Image drawing example
2019-10-21 17:23:27 -07:00
Melissa LeBlanc-Williams
0846fe003d Removed ImageDraw code which wasn't necessary 2019-10-21 16:49:02 -07:00
Kattni
8d6209bd55
Merge pull request #29 from adafruit/dherrada-patch-1
Removed building locally section from README, replaced with documenta…
2019-10-21 19:45:18 -04:00
Melissa LeBlanc-Williams
cc338c7b3c Simplified code a bit 2019-10-21 16:39:39 -07:00
Melissa LeBlanc-Williams
7040e6b904 Removed unused import 2019-10-21 15:38:52 -07:00
Melissa LeBlanc-Williams
739ed0b684 Added Pillow Image drawing example 2019-10-21 15:34:29 -07:00
Melissa LeBlanc-Williams
cdcd1a5e9a
Merge pull request #31 from makermelissa/master
Added Framebuf to requirements
2019-10-20 11:18:38 -07:00
Melissa LeBlanc-Williams
de931a6cdd Added Framebuf to requirements 2019-10-20 11:02:15 -07:00
dherrada
5a1474cbab
Added PyPi installation instructions 2019-10-18 21:37:20 -04:00
dherrada
16fc85386f
Removed building locally section from README, replaced with documentation section 2019-10-17 18:33:14 -04:00
Limor "Ladyada" Fried
ce9dfde1ec
Merge pull request #28 from ladyada/master
add two more eink displays, fix linux support
2019-10-08 16:23:23 -04:00
Limor "Ladyada" Fried
bd4737aa52
Merge pull request #1 from dherrada/master
Fixed some syntax in order to get the examples pylint to pass
2019-10-08 16:20:29 -04:00
dherrada
037480b30d Fixed some syntax in order to get the examples pylint to pass 2019-10-08 10:47:17 -04:00
ladyada
3761c4dad7 test switches 2019-09-29 14:31:13 -04:00
ladyada
7d08a07fa3 bonnet demo 2019-09-29 14:27:02 -04:00
ladyada
8022b3427e fix stride for rotation of odd-pixel-counts 2019-09-29 12:29:29 -04:00
ladyada
3f9bc2665a remove another dup 2019-09-29 01:51:44 -04:00
ladyada
2d2c841773 fix dup register and docname 2019-09-29 01:49:51 -04:00
ladyada
5ce4a71d6a lint3 2019-09-29 01:43:59 -04:00
ladyada
14ed40f901 lintlint 2019-09-29 01:41:06 -04:00
ladyada
b202863f31 lint 2019-09-29 01:38:04 -04:00
ladyada
f557beff1a run correct lut, checked with both 2.13"s 2019-09-29 01:32:52 -04:00
ladyada
058a11e7bf add new displays 2019-09-28 14:13:37 -04:00
ladyada
be57b80782 fix orientation. needs lutwork 2019-09-28 14:09:53 -04:00
ladyada
da1a8ef8d9 rough beginnings of an ssd1375b driver 2019-09-28 13:57:52 -04:00
ladyada
24a7c80756 fix display 2019-09-28 03:42:17 -04:00
ladyada
3090292ce7 start of ssd1681 driver 2019-09-28 03:14:28 -04:00
ladyada
432dacf019 fix image(), working now. blinka demo improvements 2019-09-28 00:12:52 -04:00
ladyada
30434cc6c3 add missing displays 2019-09-27 23:41:26 -04:00
ladyada
039f94aeec fix simpletest 2.13" mono 2019-09-27 23:39:42 -04:00
sommersoft
6da61f7ce1
Merge pull request #27 from ladyada/master
dont forget set frequency (as we dont use busdevice)
2019-09-27 22:35:45 -05:00
ladyada
62676fef5b dont forget set frequency (as we dont use busdevice) 2019-09-27 23:22:43 -04:00
Limor "Ladyada" Fried
82ce2b28d3
Merge pull request #26 from makermelissa/master
Added version and Repo URL
2019-09-06 15:33:43 -04:00
Melissa LeBlanc-Williams
f78e77a935 Added version and Repo URL 2019-09-06 12:00:25 -07:00
Limor "Ladyada" Fried
5385963bff
Merge pull request #23 from mrmcwethy/issue22t2
fixed issue #22 and #21
2019-06-13 13:29:39 -04:00
mrmcwethy
a6f24ebd24 fixed issue #22 and #21 2019-05-29 16:44:08 -07:00
Melissa LeBlanc-Williams
ecdede6041
Merge pull request #20 from mrmcwethy/issue19
Fix for issue #19 OverflowError:  value must fit in 1 byte(s)
2019-05-19 18:34:00 -07:00
mrmcwethy
b900b300ea Fix for issue #19 OverflowError: value must fit in 1 byte(s) 2019-05-19 15:55:59 -07:00
Carter Nelson
efdd7d360d
Merge pull request #18 from kattni/readme-update
Update usage example in README
2019-04-29 15:54:56 -07:00
Kattni Rembor
2eb545c119 Update usage example in README 2019-04-24 11:32:46 -04:00
Dan Halbert
def87f05f2
Merge pull request #15 from kattni/readme-update
Add font5x8.bin dependency
2019-04-23 13:48:59 -04:00
Kattni Rembor
906c11d134 Add font5x8.bin dependency 2019-04-23 13:43:59 -04:00
Limor "Ladyada" Fried
c72a7bbf10
Merge pull request #13 from kattni/add-213-mono
Adding 2.13 mono to example
2019-04-12 18:08:06 -04:00
Kattni Rembor
db4b01219b Adding 2.13 mono to example 2019-04-12 17:11:07 -04:00
Kattni
c1adb0ab6b
Merge pull request #12 from kattni/example-update
Update pins to be more universal.
2019-04-12 15:22:07 -04:00
Kattni Rembor
8334bf2f52 Update pins to be more universal. 2019-04-12 15:19:13 -04:00
Limor "Ladyada" Fried
1598e48e4d
Merge pull request #10 from ladyada/master
Add two more chipsets - SSD1675 and SSD1608
2019-04-01 15:13:43 -04:00
ladyada
83abd0a4ff lint & add new chip 2019-03-31 21:38:01 -04:00
ladyada
c410494ebc some lintin 2019-03-31 20:37:00 -04:00
ladyada
03b18bf71c add 1.5" example 2019-03-31 20:25:58 -04:00
ladyada
df3b5e049b initial add of SSD1308 2019-03-31 20:25:17 -04:00
ladyada
51fdef1908 nodebug 2019-03-31 19:37:17 -04:00
ladyada
0f8584fe67 fix up bitmap example 2019-03-31 19:36:17 -04:00
Melissa LeBlanc-Williams
c974cecf36
Merge pull request #9 from ladyada/master
Big refactor to match arduino logic separation
2019-03-31 16:22:57 -07:00
ladyada
09f16e05d5 lint example 2019-03-31 19:21:07 -04:00
ladyada
0e5395497a upcoming shield 2019-03-31 18:59:25 -04:00
ladyada
f10cbbd61e linted example 2019-03-31 18:18:27 -04:00
ladyada
b04d3e7ab5 lint 2019-03-31 18:16:31 -04:00
ladyada
59827d6673 woops forgot to unset 2019-03-31 18:11:50 -04:00
ladyada
f8081ff868 add more displays 2019-03-31 18:11:10 -04:00
ladyada
eb8fe05329 add tri-color 4.2" 2019-03-31 18:10:33 -04:00
ladyada
d37b6432cd matchy up 2.7" to new buffer assignment 2019-03-31 17:58:37 -04:00
ladyada
11c3179f08 allow rearranging of buffers (for flex displays) 2019-03-31 17:56:59 -04:00
ladyada
0921380674 add line for 2.7" and also more complete framebuf test 2019-03-31 16:01:35 -04:00
ladyada
9010050ded linting 2019-03-31 15:53:46 -04:00
ladyada
e69578744a add 2.7" tricolor and single byte transfer support for weird chips 2019-03-31 15:46:12 -04:00
ladyada
42de3be9f6 lintylint 2019-03-31 01:29:43 -04:00
ladyada
cf64f48eeb so close! 2019-03-31 01:27:01 -04:00
ladyada
d908c69726 lint examples 2019-03-31 01:25:11 -04:00
ladyada
ad5b467d40 fix pylint spi.write complaint 2019-03-31 01:22:54 -04:00
ladyada
fe0cb4d9f4 linty!@ 2019-03-31 01:18:08 -04:00
ladyada
b32893c930 fix width and height 2019-03-30 23:26:56 -04:00
ladyada
7fd35d081a big refactor but now works with ram or sram 2019-03-30 22:31:15 -04:00
ladyada
2c20e845ee fix incorrect init order 2019-03-04 21:30:52 -05:00
ladyada
642cb0dada width/height change with rotation 2019-01-06 15:08:38 -05:00
ladyada
cf49a1d23f ahh, orientation is always with inkdots at bottom 2019-01-06 14:45:01 -05:00
ladyada
0728206b49 fix none-8-bit boundary sizes 2019-01-06 14:35:24 -05:00
ladyada
4f9b90c4c0 add const underscores and rotation 2019-01-06 11:45:12 -05:00
ladyada
f7c350111d begin framebuffification 2019-01-05 21:43:42 -05:00
ladyada
346a9d47ff use mem buffer if no SRAM pin 2019-01-05 20:51:55 -05:00
ladyada
c4002d039b new format 2019-01-05 20:33:51 -05:00
ladyada
fb19eea29f fix bitmap example, tested! 2019-01-01 17:31:18 -05:00
ladyada
9c51956625 charge arg order/kwarg, make busy/reset optional 2019-01-01 17:07:51 -05:00
ladyada
bdda66890a get rid of clear_display/clear_buffer and replace with just fill() 2019-01-01 16:27:16 -05:00
Kattni
f447249e21
Merge pull request #6 from sommersoft/readme_fix_travis
Update README Travis Badge
2018-12-21 13:18:28 -06:00
sommersoft
3597426aec change 'travis-ci.org' to 'travis-ci.com' 2018-12-21 13:12:49 -06:00
Scott Shawcroft
e4b1946fd6
Merge pull request #4 from adafruit/tannewt-patch-1
Truncated division because its faster
2018-10-14 23:31:51 -07:00
sommersoft
455a082364 ignore the board module imports in .pylintrc
Signed-off-by: sommersoft <sommersoft@gmail.com>
2018-08-25 14:07:42 +00:00
Scott Shawcroft
fd8672b292
Truncated division because its faster 2018-08-09 12:00:28 -07:00
26 changed files with 2406 additions and 555 deletions

57
.github/workflows/build.yml vendored Normal file
View file

@ -0,0 +1,57 @@
name: Build CI
on: [pull_request, push]
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Dump GitHub context
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
run: echo "$GITHUB_CONTEXT"
- name: Translate Repo Name For Build Tools filename_prefix
id: repo-name
run: |
echo ::set-output name=repo-name::$(
echo ${{ github.repository }} |
awk -F '\/' '{ print tolower($2) }' |
tr '_' '-'
)
- name: Set up Python 3.6
uses: actions/setup-python@v1
with:
python-version: 3.6
- name: Versions
run: |
python3 --version
- name: Checkout Current Repo
uses: actions/checkout@v1
with:
submodules: true
- name: Checkout tools repo
uses: actions/checkout@v2
with:
repository: adafruit/actions-ci-circuitpython-libs
path: actions-ci
- name: Install dependencies
# (e.g. - apt-get: gettext, etc; pip: circuitpython-build-tools, requirements.txt; etc.)
run: |
source actions-ci/install.sh
- name: Pip install pylint, black, & Sphinx
run: |
pip install --force-reinstall pylint black==19.10b0 Sphinx sphinx-rtd-theme
- name: Library version
run: git describe --dirty --always --tags
- name: Check formatting
run: |
black --check --target-version=py35 .
- name: PyLint
run: |
pylint $( find . -path './adafruit*.py' )
([[ ! -d "examples" ]] || pylint --disable=missing-docstring,invalid-name,bad-whitespace $( find . -path "./examples/*.py" ))
- name: Build assets
run: circuitpython-build-bundles --filename_prefix ${{ steps.repo-name.outputs.repo-name }} --library_location .
- name: Build docs
working-directory: docs
run: sphinx-build -E -W -b html . _build/html

81
.github/workflows/release.yml vendored Normal file
View file

@ -0,0 +1,81 @@
name: Release Actions
on:
release:
types: [published]
jobs:
upload-release-assets:
runs-on: ubuntu-latest
steps:
- name: Dump GitHub context
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
run: echo "$GITHUB_CONTEXT"
- name: Translate Repo Name For Build Tools filename_prefix
id: repo-name
run: |
echo ::set-output name=repo-name::$(
echo ${{ github.repository }} |
awk -F '\/' '{ print tolower($2) }' |
tr '_' '-'
)
- name: Set up Python 3.6
uses: actions/setup-python@v1
with:
python-version: 3.6
- name: Versions
run: |
python3 --version
- name: Checkout Current Repo
uses: actions/checkout@v1
with:
submodules: true
- name: Checkout tools repo
uses: actions/checkout@v2
with:
repository: adafruit/actions-ci-circuitpython-libs
path: actions-ci
- name: Install deps
run: |
source actions-ci/install.sh
- name: Build assets
run: circuitpython-build-bundles --filename_prefix ${{ steps.repo-name.outputs.repo-name }} --library_location .
- name: Upload Release Assets
# the 'official' actions version does not yet support dynamically
# supplying asset names to upload. @csexton's version chosen based on
# discussion in the issue below, as its the simplest to implement and
# allows for selecting files with a pattern.
# https://github.com/actions/upload-release-asset/issues/4
#uses: actions/upload-release-asset@v1.0.1
uses: csexton/release-asset-action@master
with:
pattern: "bundles/*"
github-token: ${{ secrets.GITHUB_TOKEN }}
upload-pypi:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Check For setup.py
id: need-pypi
run: |
echo ::set-output name=setup-py::$( find . -wholename './setup.py' )
- name: Set up Python
if: contains(steps.need-pypi.outputs.setup-py, 'setup.py')
uses: actions/setup-python@v1
with:
python-version: '3.x'
- name: Install dependencies
if: contains(steps.need-pypi.outputs.setup-py, 'setup.py')
run: |
python -m pip install --upgrade pip
pip install setuptools wheel twine
- name: Build and publish
if: contains(steps.need-pypi.outputs.setup-py, 'setup.py')
env:
TWINE_USERNAME: ${{ secrets.pypi_username }}
TWINE_PASSWORD: ${{ secrets.pypi_password }}
run: |
python setup.py sdist
twine upload dist/*

1
.gitignore vendored
View file

@ -4,7 +4,6 @@ __pycache__
_build
*.pyc
.env
build*
bundles
*.DS_Store
.eggs

View file

@ -52,7 +52,7 @@ confidence=
# 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
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,bad-continuation
# 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
@ -156,7 +156,7 @@ ignored-classes=optparse.Values,thread._local,_thread._local
# (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=
ignored-modules=board
# Show a hint with possible names when a member name was not found. The aspect
# of finding the hint is based on edit distance.

View file

@ -1,33 +0,0 @@
dist: trusty
sudo: false
language: python
python:
- '3.6'
cache:
pip: true
deploy:
- provider: releases
api_key: "$GITHUB_TOKEN"
file_glob: true
file: "$TRAVIS_BUILD_DIR/bundles/*"
skip_cleanup: true
overwrite: true
on:
tags: true
- provider: pypi
user: adafruit-travis
on:
tags: true
password:
secure: qcc4jJ7uVD270sLdbvyiBdsVS7JOLDO02XsWXsSL4HPuiIlAddBD1/NWUBC7e9APPFojQZnK6lHx6HFIduRG3clZRYawePPsclCQ7KxgDaXDRUKW2CcpvdrBBvHpoaCsbzdB9QDFH3JIrZPksKRiCMRSxdbFmdzucoBIdQ1ERgcRSB1ncnBywVqzSj1kiMXUtGLFqN6wo5x4kF2z8/bZ7FACyzzOGTpqq3wQLb/CropSpZ8bmoW0Q8fJmoaUR39kRfEHu1g3KW8Nvd6Sv0RbUbe5SkW2fdrHoRT2/FN00HElL7Lc3ShiD+aHujvzdmm4FAic2iMrrAKI74fr5b6dlNcLHwEtOiq6zxtkedydk1dN3NWMdyKCaYYKRwxSXEa9DkCC2w+DCx1ExJWO8r3oz+AaLUNhCrzww9GR8JBUP+siAtus3GaBB3B8njymM59NkOfd8rdKaN4E7x0eOqRV/gDjAoz1JqBNXR/BKM/np5UJ5UMRbY7sy8mB6hdF+wvnEOJfjYX4C3Ao/ZT8IVieNAYRojHHmKi4bh6aqK9noJ33belGgPewyeg3NXZE7uprL1XGnC9lCi0P4lWTskdPlhtysXOKOos3vuIpRHxZC6uiP/zE3Y7PO9WPs9fSMdQKBCExqu9OwZEFMKiJiOyM3quInQuxKSBYrlh3bXe69lA=
install:
- pip install -r requirements.txt
- pip install pylint circuitpython-build-tools Sphinx sphinx-rtd-theme
- pip install --force-reinstall pylint==1.9.2
script:
- pylint adafruit_epd
- ([[ ! -d "examples" ]] || pylint --disable=missing-docstring,invalid-name,bad-whitespace
examples/*.py)
- circuitpython-build-bundles --filename_prefix adafruit-circuitpython-epd --library_location
.
- cd docs && sphinx-build -E -W -b html . _build/html && cd ..

View file

@ -34,6 +34,8 @@ Examples of unacceptable behavior by participants include:
* Excessive or unwelcome helping; answering outside the scope of the question
asked
* Trolling, insulting/derogatory comments, and personal or political attacks
* Promoting or spreading disinformation, lies, or conspiracy theories against
a person, group, organisation, project, or community
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
@ -72,10 +74,10 @@ You may report in the following ways:
In any situation, you may send an email to <support@adafruit.com>.
On the Adafruit Discord, you may send an open message from any channel
to all Community Helpers by tagging @community helpers. You may also send an
open message from any channel, or a direct message to @kattni#1507,
@tannewt#4653, @Dan Halbert#1614, @cater#2442, @sommersoft#0222, or
@Andon#8175.
to all Community Moderators by tagging @community moderators. You may
also send an open message from any channel, or a direct message to
@kattni#1507, @tannewt#4653, @Dan Halbert#1614, @cater#2442,
@sommersoft#0222, @Mr. Certainly#0472 or @Andon#8175.
Email and direct message reports will be kept confidential.

View file

@ -6,11 +6,11 @@ Introduction
:alt: Documentation Status
.. image:: https://img.shields.io/discord/327254708534116352.svg
:target: https://discord.gg/nBQh6qu
:target: https://adafru.it/discord
:alt: Discord
.. image:: https://travis-ci.org/adafruit/Adafruit_CircuitPython_EPD.svg?branch=master
:target: https://travis-ci.org/adafruit/Adafruit_CircuitPython_EPD
.. image:: https://github.com/adafruit/Adafruit_CircuitPython_EPD/workflows/Build%20CI/badge.svg
:target: https://github.com/adafruit/Adafruit_CircuitPython_EPD/actions/
:alt: Build Status
This library is for using CircuitPython with e-ink displays with built in SRAM.
@ -21,11 +21,37 @@ This driver depends on:
* `Adafruit CircuitPython <https://github.com/adafruit/circuitpython>`_
* `Bus Device <https://github.com/adafruit/Adafruit_CircuitPython_BusDevice>`_
* `font5x8.bin found in the examples bundle <https://github.com/adafruit/Adafruit_CircuitPython_Bundle>`_
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>`_.
Installing from PyPI
====================
On supported GNU/Linux systems like the Raspberry Pi, you can install the driver locally `from
PyPI <https://pypi.org/project/adafruit-circuitpython-epd/>`_. To install for current user:
.. code-block:: shell
pip3 install adafruit-circuitpython-epd
To install system-wide (this may be required in some cases):
.. code-block:: shell
sudo pip3 install adafruit-circuitpython-epd
To install in a virtual environment in your current project:
.. code-block:: shell
mkdir project-name && cd project-name
python3 -m venv .env
source .env/bin/activate
pip3 install adafruit-circuitpython-epd
Usage Example
=============
@ -39,31 +65,35 @@ Usage Example
# create the spi device and pins we will need
spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO)
ecs = digitalio.DigitalInOut(board.D10)
dc = digitalio.DigitalInOut(board.D9)
srcs = digitalio.DigitalInOut(board.D8)
rst = digitalio.DigitalInOut(board.D7)
busy = digitalio.DigitalInOut(board.D6)
ecs = digitalio.DigitalInOut(board.D12)
dc = digitalio.DigitalInOut(board.D11)
srcs = digitalio.DigitalInOut(board.D10) # can be None to use internal memory
rst = digitalio.DigitalInOut(board.D9) # can be None to not use this pin
busy = digitalio.DigitalInOut(board.D5) # can be None to not use this pin
# give them all to our driver
display = Adafruit_IL0373(152, 152, rst, dc, busy, srcs, ecs, spi)
print("Creating display")
display = Adafruit_IL0373(104, 212, spi, # 2.13" Tri-color display
cs_pin=ecs, dc_pin=dc, sramcs_pin=srcs,
rst_pin=rst, busy_pin=busy)
display.rotation = 1
# clear the buffer
display.clear_buffer()
print("Clear buffer")
display.fill(Adafruit_EPD.WHITE)
display.pixel(10, 100, Adafruit_EPD.BLACK)
r_width = 5
r_pos = display.height
print("Draw Rectangles")
display.fill_rect(5, 5, 10, 10, Adafruit_EPD.RED)
display.rect(0, 0, 20, 30, Adafruit_EPD.BLACK)
#draw some rectangles!
color = Adafruit_EPD.BLACK
while r_pos > display.height/2:
if r_pos < display.height - 50:
color = Adafruit_EPD.RED
display.rect(display.width - r_pos, display.height - r_pos,
display.width - 2*(display.width - r_pos),
display.height - 2*(display.height - r_pos), color)
r_pos = r_pos - r_width
print("Draw lines")
display.line(0, 0, display.width-1, display.height-1, Adafruit_EPD.BLACK)
display.line(0, display.height-1, display.width-1, 0, Adafruit_EPD.RED)
print("Draw text")
display.text('hello world', 25, 10, Adafruit_EPD.BLACK)
display.display()
@ -74,52 +104,7 @@ Contributions are welcome! Please read our `Code of Conduct
<https://github.com/adafruit/Adafruit_CircuitPython_EPD/blob/master/CODE_OF_CONDUCT.md>`_
before contributing to help this project stay welcoming.
Building locally
================
Documentation
=============
Zip release files
-----------------
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-epd --library_location .
Sphinx documentation
-----------------------
Sphinx is used to build the documentation based on rST files and comments in the code. First,
install dependencies (feel free to reuse the virtual environment from above):
.. code-block:: shell
python3 -m venv .env
source .env/bin/activate
pip install Sphinx sphinx-rtd-theme
Now, once you have the virtual environment activated:
.. code-block:: shell
cd docs
sphinx-build -E -W -b html . _build/html
This will output the documentation to ``docs/_build/html``. Open the index.html in your browser to
view them. It will also (due to -W) error out on any warning like Travis will. This is a good way to
locally verify it will pass.
For information on building library documentation, please check out `this guide <https://learn.adafruit.com/creating-and-sharing-a-circuitpython-library/sharing-our-docs-on-readthedocs#sphinx-5-1>`_.

View file

@ -27,120 +27,318 @@ CircuitPython driver for Adafruit ePaper display breakouts
"""
import time
import digitalio
from micropython import const
from digitalio import Direction
from adafruit_epd import mcp_sram
class Adafruit_EPD:
__version__ = "0.0.0-auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_EPD.git"
class Adafruit_EPD: # pylint: disable=too-many-instance-attributes, too-many-public-methods
"""Base class for EPD displays
"""
BLACK = 0
WHITE = 1
INVERSE = 2
RED = 3
DARK = 4
LIGHT = 5
# pylint: disable=too-many-arguments
def __init__(self, width, height, rst_pin, dc_pin, busy_pin, srcs_pin, cs_pin, spi):
self.width = width
self.height = height
BLACK = const(0)
WHITE = const(1)
INVERSE = const(2)
RED = const(3)
DARK = const(4)
LIGHT = const(5)
# Setup reset pin.
def __init__(
self, width, height, spi, cs_pin, dc_pin, sramcs_pin, rst_pin, busy_pin
): # pylint: disable=too-many-arguments
self._width = width
self._height = height
# Setup reset pin, if we have one
self._rst = rst_pin
self._rst.direction = digitalio.Direction.OUTPUT
if rst_pin:
self._rst.direction = Direction.OUTPUT
# Setup busy pin.
# Setup busy pin, if we have one
self._busy = busy_pin
self._busy.direction = digitalio.Direction.INPUT
if busy_pin:
self._busy.direction = Direction.INPUT
# Setup dc pin.
# Setup dc pin (required)
self._dc = dc_pin
self._dc.direction = digitalio.Direction.OUTPUT
# Setup cs pin.
self._cs = cs_pin
self._cs.direction = digitalio.Direction.OUTPUT
self.spi_device = spi
self.sram = mcp_sram.Adafruit_MCP_SRAM(srcs_pin, spi)
# pylint: enable=too-many-arguments
def begin(self, reset=True):
"""Begin display and reset if desired."""
self._cs.value = True
self._dc.direction = Direction.OUTPUT
self._dc.value = False
if reset:
# Setup cs pin (required)
self._cs = cs_pin
self._cs.direction = Direction.OUTPUT
self._cs.value = True
# SPI interface (required)
self.spi_device = spi
while not self.spi_device.try_lock():
time.sleep(0.01)
self.spi_device.configure(baudrate=1000000) # 1 Mhz
self.spi_device.unlock()
self._spibuf = bytearray(1)
self._single_byte_tx = False
self.sram = None
if sramcs_pin:
self.sram = mcp_sram.Adafruit_MCP_SRAM(sramcs_pin, spi)
self._buf = bytearray(3)
self._buffer1_size = self._buffer2_size = 0
self._buffer1 = self._buffer2 = None
self._framebuf1 = self._framebuf2 = None
self._colorframebuf = self._blackframebuf = None
self._black_inverted = self._color_inverted = True
self.hardware_reset()
def display(self): # pylint: disable=too-many-branches
"""show the contents of the display buffer"""
self.power_up()
self.set_ram_address(0, 0)
if self.sram:
while not self.spi_device.try_lock():
time.sleep(0.01)
self.sram.cs_pin.value = False
# send read command
self._buf[0] = mcp_sram.Adafruit_MCP_SRAM.SRAM_READ
# send start address
self._buf[1] = 0
self._buf[2] = 0
self.spi_device.write(self._buf, end=3)
self.spi_device.unlock()
# first data byte from SRAM will be transfered in at the
# same time as the EPD command is transferred out
databyte = self.write_ram(0)
while not self.spi_device.try_lock():
time.sleep(0.01)
self._dc.value = True
if self.sram:
for _ in range(self._buffer1_size):
databyte = self._spi_transfer(databyte)
self.sram.cs_pin.value = True
else:
for databyte in self._buffer1:
self._spi_transfer(databyte)
self._cs.value = True
self.spi_device.unlock()
time.sleep(0.002)
if self.sram:
while not self.spi_device.try_lock():
time.sleep(0.01)
self.sram.cs_pin.value = False
# send read command
self._buf[0] = mcp_sram.Adafruit_MCP_SRAM.SRAM_READ
# send start address
self._buf[1] = (self._buffer1_size >> 8) & 0xFF
self._buf[2] = self._buffer1_size & 0xFF
self.spi_device.write(self._buf, end=3)
self.spi_device.unlock()
if self._buffer2_size != 0:
# first data byte from SRAM will be transfered in at the
# same time as the EPD command is transferred out
databyte = self.write_ram(1)
while not self.spi_device.try_lock():
time.sleep(0.01)
self._dc.value = True
if self.sram:
for _ in range(self._buffer2_size):
databyte = self._spi_transfer(databyte)
self.sram.cs_pin.value = True
else:
for databyte in self._buffer2:
self._spi_transfer(databyte)
self._cs.value = True
self.spi_device.unlock()
else:
if self.sram:
self.sram.cs_pin.value = True
self.update()
def hardware_reset(self):
"""If we have a reset pin, do a hardware reset by toggling it"""
if self._rst:
self._rst.value = False
time.sleep(.1)
time.sleep(0.1)
self._rst.value = True
time.sleep(.1)
time.sleep(0.1)
def command(self, cmd, data=None, end=True):
"""Send command byte to display."""
self._cs.value = True
self._dc.value = False
self._cs.value = False
outbuf = bytearray(1)
while not self.spi_device.try_lock():
pass
self.spi_device.write_readinto(bytearray([cmd]), outbuf)
time.sleep(0.01)
ret = self._spi_transfer(cmd)
if data is not None:
self.data(data)
else:
self.spi_device.unlock()
self._dc.value = True
for b in data:
self._spi_transfer(b)
if end:
self._cs.value = True
return outbuf[0]
def data(self, dat):
"""Send data to display."""
self._dc.value = True
self.spi_device.write(dat)
self._cs.value = True
self.spi_device.unlock()
def draw_pixel(self, x, y, color):
"""This should be overridden in the subclass"""
pass
return ret
def _spi_transfer(self, databyte):
"""Transfer one byte, toggling the cs pin if required by the EPD chipset"""
self._spibuf[0] = databyte
if self._single_byte_tx:
self._cs.value = False
self.spi_device.write_readinto(self._spibuf, self._spibuf)
if self._single_byte_tx:
self._cs.value = True
return self._spibuf[0]
def power_up(self):
"""Power up the display in preparation for writing RAM and updating.
must be implemented in subclass"""
raise NotImplementedError()
def power_down(self):
"""Power down the display, must be implemented in subclass"""
raise NotImplementedError()
def update(self):
"""Update the display from internal memory, must be implemented in subclass"""
raise NotImplementedError()
def write_ram(self, index):
"""Send the one byte command for starting the RAM write process. Returns
the byte read at the same time over SPI. index is the RAM buffer, can be
0 or 1 for tri-color displays. must be implemented in subclass"""
raise NotImplementedError()
def set_ram_address(self, x, y):
"""Set the RAM address location, must be implemented in subclass"""
raise NotImplementedError()
def set_black_buffer(self, index, inverted):
"""Set the index for the black buffer data (0 or 1) and whether its inverted"""
if index == 0:
self._blackframebuf = self._framebuf1
elif index == 1:
self._blackframebuf = self._framebuf2
else:
raise RuntimeError("Buffer index must be 0 or 1")
self._black_inverted = inverted
def set_color_buffer(self, index, inverted):
"""Set the index for the color buffer data (0 or 1) and whether its inverted"""
if index == 0:
self._colorframebuf = self._framebuf1
elif index == 1:
self._colorframebuf = self._framebuf2
else:
raise RuntimeError("Buffer index must be 0 or 1")
self._color_inverted = inverted
def _color_dup(self, func, args, color):
black = getattr(self._blackframebuf, func)
red = getattr(self._colorframebuf, func)
if self._blackframebuf is self._colorframebuf: # monochrome
black(*args, color=(color != Adafruit_EPD.WHITE) != self._black_inverted)
else:
black(*args, color=(color == Adafruit_EPD.BLACK) != self._black_inverted)
red(*args, color=(color == Adafruit_EPD.RED) != self._color_inverted)
def pixel(self, x, y, color):
"""draw a single pixel in the display buffer"""
self._color_dup("pixel", (x, y), color)
#framebuf methods
def fill(self, color):
"""fill the screen with the passed color"""
self.fill_rect(0, 0, self.width, self.height, color)
red_fill = ((color == Adafruit_EPD.RED) != self._color_inverted) * 0xFF
black_fill = ((color == Adafruit_EPD.BLACK) != self._black_inverted) * 0xFF
# pylint: disable=too-many-arguments
def fill_rect(self, x, y, width, height, color):
if self.sram:
self.sram.erase(0x00, self._buffer1_size, black_fill)
self.sram.erase(self._buffer1_size, self._buffer2_size, red_fill)
else:
self._blackframebuf.fill(black_fill)
self._colorframebuf.fill(red_fill)
def rect(self, x, y, width, height, color): # pylint: disable=too-many-arguments
"""draw a rectangle"""
self._color_dup("rect", (x, y, width, height), color)
def fill_rect(
self, x, y, width, height, color
): # pylint: disable=too-many-arguments
"""fill a rectangle with the passed color"""
if width < 1 or height < 1 or (x+width) <= 0:
return
if (y+height) <= 0 or y >= self.height or x >= self.width:
return
xend = min(self.width, x+width)
yend = min(self.height, y+height)
x = max(x, 0)
y = max(y, 0)
for _x in range(xend - x):
for _y in range(yend - y):
self.draw_pixel(x + _x, y + _y, color)
return
self._color_dup("fill_rect", (x, y, width, height), color)
def pixel(self, x, y, color=None):
"""draw a pixel"""
if x < 0 or x >= self.width or y < 0 or y >= self.height:
return None
#TODO: figure this out when we know what framebuffer we
# will actually use
#if color is None:
# return self.get_pixel(self, x, y)
def line(self, x_0, y_0, x_1, y_1, color): # pylint: disable=too-many-arguments
"""Draw a line from (x_0, y_0) to (x_1, y_1) in passed color"""
self._color_dup("line", (x_0, y_0, x_1, y_1), color)
self.draw_pixel(x, y, color)
return None
def text(self, string, x, y, color, *, font_name="font5x8.bin"):
"""Write text string at location (x, y) in given color, using font file"""
if self._blackframebuf is self._colorframebuf: # monochrome
self._blackframebuf.text(
string,
x,
y,
font_name=font_name,
color=(color != Adafruit_EPD.WHITE) != self._black_inverted,
)
else:
self._blackframebuf.text(
string,
x,
y,
font_name=font_name,
color=(color == Adafruit_EPD.BLACK) != self._black_inverted,
)
self._colorframebuf.text(
string,
x,
y,
font_name=font_name,
color=(color == Adafruit_EPD.RED) != self._color_inverted,
)
@property
def width(self):
"""The width of the display, accounting for rotation"""
if self.rotation in (0, 2):
return self._width
return self._height
@property
def height(self):
"""The height of the display, accounting for rotation"""
if self.rotation in (0, 2):
return self._height
return self._width
@property
def rotation(self):
"""The rotation of the display, can be one of (0, 1, 2, 3)"""
return self._framebuf1.rotation
@rotation.setter
def rotation(self, val):
self._framebuf1.rotation = val
if self._framebuf2:
self._framebuf2.rotation = val
def hline(self, x, y, width, color):
"""draw a horizontal line"""
@ -150,9 +348,39 @@ class Adafruit_EPD:
"""draw a vertical line"""
self.fill_rect(x, y, 1, height, color)
def rect(self, x, y, width, height, color):
"""draw a rectangle"""
self.fill_rect(x, y, width, 1, color)
self.fill_rect(x, y+height, width, 1, color)
self.fill_rect(x, y, 1, height, color)
self.fill_rect(x+width, y, 1, height, color)
def image(self, image):
"""Set buffer to value of Python Imaging Library image. The image should
be in RGB mode and a size equal to the display size.
"""
imwidth, imheight = image.size
if imwidth != self.width or imheight != self.height:
raise ValueError(
"Image must be same dimensions as display ({0}x{1}).".format(
self.width, self.height
)
)
if self.sram:
raise RuntimeError("PIL image is not for use with SRAM assist")
# Grab all the pixels from the image, faster than getpixel.
pix = image.load()
# clear out any display buffers
self.fill(Adafruit_EPD.WHITE)
if image.mode == "RGB": # RGB Mode
for y in range(image.size[1]):
for x in range(image.size[0]):
pixel = pix[x, y]
if (pixel[1] < 0x80 <= pixel[0]) and (pixel[2] < 0x80):
# reddish
self.pixel(x, y, Adafruit_EPD.RED)
elif (pixel[0] < 0x80) and (pixel[1] < 0x80) and (pixel[2] < 0x80):
# dark
self.pixel(x, y, Adafruit_EPD.BLACK)
elif image.mode == "L": # Grayscale
for y in range(image.size[1]):
for x in range(image.size[0]):
pixel = pix[x, y]
if pixel < 0x80:
self.pixel(x, y, Adafruit_EPD.BLACK)
else:
raise ValueError("Image must be in mode RGB or mode L.")

View file

@ -28,205 +28,132 @@ CircuitPython driver for Adafruit il0373 display breakouts
import time
from micropython import const
import adafruit_framebuf
from adafruit_epd.epd import Adafruit_EPD
from adafruit_epd.mcp_sram import Adafruit_MCP_SRAM
IL0373_PANEL_SETTING = const(0x00)
IL0373_POWER_SETTING = const(0x01)
IL0373_POWER_OFF = const(0x02)
IL0373_POWER_OFF_SEQUENCE = const(0x03)
IL0373_POWER_ON = const(0x04)
IL0373_POWER_ON_MEASURE = const(0x05)
IL0373_BOOSTER_SOFT_START = const(0x06)
IL0373_DEEP_SLEEP = const(0x07)
IL0373_DTM1 = const(0x10)
IL0373_DATA_STOP = const(0x11)
IL0373_DISPLAY_REFRESH = const(0x12)
IL0373_DTM2 = const(0x13)
IL0373_PDTM1 = const(0x14)
IL0373_PDTM2 = const(0x15)
IL0373_PDRF = const(0x16)
IL0373_LUT1 = const(0x20)
IL0373_LUTWW = const(0x21)
IL0373_LUTBW = const(0x22)
IL0373_LUTWB = const(0x23)
IL0373_LUTBB = const(0x24)
IL0373_PLL = const(0x30)
IL0373_CDI = const(0x50)
IL0373_RESOLUTION = const(0x61)
IL0373_VCM_DC_SETTING = const(0x82)
__version__ = "0.0.0-auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_EPD.git"
_IL0373_PANEL_SETTING = const(0x00)
_IL0373_POWER_SETTING = const(0x01)
_IL0373_POWER_OFF = const(0x02)
_IL0373_POWER_OFF_SEQUENCE = const(0x03)
_IL0373_POWER_ON = const(0x04)
_IL0373_POWER_ON_MEASURE = const(0x05)
_IL0373_BOOSTER_SOFT_START = const(0x06)
_IL0373_DEEP_SLEEP = const(0x07)
_IL0373_DTM1 = const(0x10)
_IL0373_DATA_STOP = const(0x11)
_IL0373_DISPLAY_REFRESH = const(0x12)
_IL0373_DTM2 = const(0x13)
_IL0373_PDTM1 = const(0x14)
_IL0373_PDTM2 = const(0x15)
_IL0373_PDRF = const(0x16)
_IL0373_LUT1 = const(0x20)
_IL0373_LUTWW = const(0x21)
_IL0373_LUTBW = const(0x22)
_IL0373_LUTWB = const(0x23)
_IL0373_LUTBB = const(0x24)
_IL0373_PLL = const(0x30)
_IL0373_CDI = const(0x50)
_IL0373_RESOLUTION = const(0x61)
_IL0373_VCM_DC_SETTING = const(0x82)
class Adafruit_IL0373(Adafruit_EPD):
"""driver class for Adafruit IL0373 ePaper display breakouts"""
# pylint: disable=too-many-arguments
def __init__(self, width, height, rst_pin, dc_pin, busy_pin, srcs_pin, cs_pin, spi):
super(Adafruit_IL0373, self).__init__(width, height, rst_pin, dc_pin, busy_pin,
srcs_pin, cs_pin, spi)
def __init__(
self, width, height, spi, *, cs_pin, dc_pin, sramcs_pin, rst_pin, busy_pin
):
super(Adafruit_IL0373, self).__init__(
width, height, spi, cs_pin, dc_pin, sramcs_pin, rst_pin, busy_pin
)
self.bw_bufsize = int(width * height / 8)
self.red_bufsize = int(width * height / 8)
self._buffer1_size = int(width * height / 8)
self._buffer2_size = int(width * height / 8)
self.begin()
if sramcs_pin:
self._buffer1 = self.sram.get_view(0)
self._buffer2 = self.sram.get_view(self._buffer1_size)
else:
self._buffer1 = bytearray((width * height) // 8)
self._buffer2 = bytearray((width * height) // 8)
# since we have *two* framebuffers - one for red and one for black
# we dont subclass but manage manually
self._framebuf1 = adafruit_framebuf.FrameBuffer(
self._buffer1, width, height, buf_format=adafruit_framebuf.MHMSB
)
self._framebuf2 = adafruit_framebuf.FrameBuffer(
self._buffer2, width, height, buf_format=adafruit_framebuf.MHMSB
)
self.set_black_buffer(0, True)
self.set_color_buffer(1, True)
# pylint: enable=too-many-arguments
def begin(self, reset=True):
"""Begin communication with the display and set basic settings"""
super(Adafruit_IL0373, self).begin(reset)
if reset:
self.hardware_reset()
self.power_down()
while self._busy.value is False:
pass
self.command(IL0373_POWER_SETTING, bytearray([0x03, 0x00, 0x2b, 0x2b, 0x09]))
self.command(IL0373_BOOSTER_SOFT_START, bytearray([0x17, 0x17, 0x17]))
def update(self):
"""update the display"""
self.command(IL0373_DISPLAY_REFRESH)
while self._busy.value is False:
pass
self.command(IL0373_CDI, bytearray([0x17]))
self.command(IL0373_VCM_DC_SETTING, bytearray([0x00]))
self.command(IL0373_POWER_OFF)
time.sleep(2)
def busy_wait(self):
"""Wait for display to be done with current task, either by polling the
busy pin, or pausing"""
if self._busy:
while not self._busy.value:
time.sleep(0.01)
else:
time.sleep(0.5)
def power_up(self):
"""power up the display"""
self.command(IL0373_POWER_ON)
"""Power up the display in preparation for writing RAM and updating"""
self.hardware_reset()
self.busy_wait()
while self._busy.value is False:
pass
self.command(_IL0373_POWER_SETTING, bytearray([0x03, 0x00, 0x2B, 0x2B, 0x09]))
self.command(_IL0373_BOOSTER_SOFT_START, bytearray([0x17, 0x17, 0x17]))
self.command(_IL0373_POWER_ON)
time.sleep(.2)
self.busy_wait()
time.sleep(0.2)
self.command(IL0373_PANEL_SETTING, bytearray([0xCF]))
self.command(IL0373_CDI, bytearray([0x37]))
self.command(IL0373_PLL, bytearray([0x29]))
_b1 = self.height & 0xFF
_b2 = (self.height >> 8) & 0xFF
_b3 = self.width & 0xFF
_b4 = (self.width >> 8) & 0xFF
self.command(IL0373_RESOLUTION, bytearray([_b1, _b2, _b3, _b4]))
self.command(IL0373_VCM_DC_SETTING, bytearray([0x0A]))
self.command(_IL0373_PANEL_SETTING, bytearray([0xCF]))
self.command(_IL0373_CDI, bytearray([0x37]))
self.command(_IL0373_PLL, bytearray([0x29]))
_b1 = self._width & 0xFF
_b2 = (self._height >> 8) & 0xFF
_b3 = self._height & 0xFF
self.command(_IL0373_RESOLUTION, bytearray([_b1, _b2, _b3]))
self.command(_IL0373_VCM_DC_SETTING, bytearray([0x0A]))
time.sleep(0.05)
def power_down(self):
"""Power down the display - required when not actively displaying!"""
self.command(_IL0373_CDI, bytearray([0x17]))
self.command(_IL0373_VCM_DC_SETTING, bytearray([0x00]))
self.command(_IL0373_POWER_OFF)
def display(self):
"""show the contents of the display buffer"""
self.power_up()
def update(self):
"""Update the display from internal memory"""
self.command(_IL0373_DISPLAY_REFRESH)
time.sleep(0.1)
self.busy_wait()
if not self._busy:
time.sleep(15) # wait 15 seconds
while not self.spi_device.try_lock():
pass
self.sram.cs_pin.value = False
#send read command
self.spi_device.write(bytearray([Adafruit_MCP_SRAM.SRAM_READ]))
#send start address
self.spi_device.write(bytearray([0x00, 0x00]))
self.spi_device.unlock()
def write_ram(self, index):
"""Send the one byte command for starting the RAM write process. Returns
the byte read at the same time over SPI. index is the RAM buffer, can be
0 or 1 for tri-color displays."""
if index == 0:
return self.command(_IL0373_DTM1, end=False)
if index == 1:
return self.command(_IL0373_DTM2, end=False)
raise RuntimeError("RAM index must be 0 or 1")
#first data byte from SRAM will be transfered in at the
#same time as the EPD command is transferred out
cmd = self.command(IL0373_DTM1, end=False)
while not self.spi_device.try_lock():
pass
self._dc.value = True
xfer = bytearray([cmd])
outbuf = bytearray(1)
for _ in range(self.bw_bufsize):
outbuf[0] = xfer[0]
self.spi_device.write_readinto(outbuf, xfer)
self._cs.value = True
self.sram.cs_pin.value = True
time.sleep(.002)
self.sram.cs_pin.value = False
#send read command
self.spi_device.write(bytearray([Adafruit_MCP_SRAM.SRAM_READ]))
#send start address
self.spi_device.write(bytearray([(self.bw_bufsize >> 8), (self.bw_bufsize & 0xFF)]))
self.spi_device.unlock()
#first data byte from SRAM will be transfered in at the
#same time as the EPD command is transferred out
cmd = self.command(IL0373_DTM2, end=False)
while not self.spi_device.try_lock():
pass
self._dc.value = True
xfer = bytearray([cmd])
outbuf = bytearray(1)
for _ in range(self.bw_bufsize):
outbuf[0] = xfer[0]
self.spi_device.write_readinto(outbuf, xfer)
self._cs.value = True
self.sram.cs_pin.value = True
self.spi_device.unlock()
self.update()
def image(self, image):
"""Set buffer to value of Python Imaging Library image. The image should
be in RGB mode and a size equal to the display size.
"""
if image.mode != 'RGB':
raise ValueError('Image must be in mode RGB.')
imwidth, imheight = image.size
if imwidth != self.width or imheight != self.height:
raise ValueError('Image must be same dimensions as display ({0}x{1}).' \
.format(self.width, self.height))
# Grab all the pixels from the image, faster than getpixel.
pix = image.load()
for y in iter(range(image.size[1])):
for x in iter(range(image.size[0])):
if x == 0:
x = 1
pixel = pix[x, y]
addr = int(((self.width - x) * self.height + y)/8)
if pixel == (0xFF, 0, 0):
addr = addr + self.bw_bufsize
current = self.sram.read8(addr)
if pixel in ((0xFF, 0, 0), (0, 0, 0)):
current = current & ~(1 << (7 - y%8))
else:
current = current | (1 << (7 - y%8))
self.sram.write8(addr, current)
def draw_pixel(self, x, y, color):
"""draw a single pixel in the display buffer"""
if (x < 0) or (x >= self.width) or (y < 0) or (y >= self.height):
return
if x == 0:
x = 1
addr = int(((self.width - x) * self.height + y)/8)
if color == Adafruit_EPD.RED:
addr = addr + self.bw_bufsize
current = self.sram.read8(addr)
if color == Adafruit_EPD.WHITE:
current = current | (1 << (7 - y%8))
elif color in (Adafruit_EPD.RED, Adafruit_EPD.BLACK):
current = current & ~(1 << (7 - y%8))
elif color == Adafruit_EPD.INVERSE:
current = current ^ (1 << (7 - y%8))
self.sram.write8(addr, current)
return
def clear_buffer(self):
"""clear the display buffer"""
self.sram.erase(0x00, self.bw_bufsize, 0xFF)
self.sram.erase(self.bw_bufsize, self.red_bufsize, 0xFF)
def clear_display(self):
"""clear the entire display"""
self.clear_buffer()
self.display()
def set_ram_address(self, x, y): # pylint: disable=unused-argument, no-self-use
"""Set the RAM address location, not used on this chipset but required by
the superclass"""
return # on this chip it does nothing

159
adafruit_epd/il0398.py Normal file
View file

@ -0,0 +1,159 @@
# The MIT License (MIT)
#
# Copyright (c) 2018 Dean Miller 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_epd.il0398` - Adafruit IL0398 - ePaper display driver
====================================================================================
CircuitPython driver for Adafruit IL0398 display breakouts
* Author(s): Dean Miller, ladyada
"""
import time
from micropython import const
import adafruit_framebuf
from adafruit_epd.epd import Adafruit_EPD
__version__ = "0.0.0-auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_EPD.git"
_IL0398_PANEL_SETTING = const(0x00)
_IL0398_POWER_SETTING = const(0x01)
_IL0398_POWER_OFF = const(0x02)
_IL0398_POWER_OFF_SEQUENCE = const(0x03)
_IL0398_POWER_ON = const(0x04)
_IL0398_POWER_ON_MEASURE = const(0x05)
_IL0398_BOOSTER_SOFT_START = const(0x06)
_IL0398_DEEP_SLEEP = const(0x07)
_IL0398_DTM1 = const(0x10)
_IL0398_DATA_STOP = const(0x11)
_IL0398_DISPLAY_REFRESH = const(0x12)
_IL0398_DTM2 = const(0x13)
_IL0398_PDTM1 = const(0x14)
_IL0398_PDTM2 = const(0x15)
_IL0398_PDRF = const(0x16)
_IL0398_LUT1 = const(0x20)
_IL0398_LUTWW = const(0x21)
_IL0398_LUTBW = const(0x22)
_IL0398_LUTWB = const(0x23)
_IL0398_LUTBB = const(0x24)
_IL0398_PLL = const(0x30)
_IL0398_CDI = const(0x50)
_IL0398_RESOLUTION = const(0x61)
_IL0398_GETSTATUS = const(0x71)
_IL0398_VCM_DC_SETTING = const(0x82)
class Adafruit_IL0398(Adafruit_EPD):
"""driver class for Adafruit IL0373 ePaper display breakouts"""
# pylint: disable=too-many-arguments
def __init__(
self, width, height, spi, *, cs_pin, dc_pin, sramcs_pin, rst_pin, busy_pin
):
super(Adafruit_IL0398, self).__init__(
width, height, spi, cs_pin, dc_pin, sramcs_pin, rst_pin, busy_pin
)
self._buffer1_size = int(width * height / 8)
self._buffer2_size = int(width * height / 8)
if sramcs_pin:
self._buffer1 = self.sram.get_view(0)
self._buffer2 = self.sram.get_view(self._buffer1_size)
else:
self._buffer1 = bytearray((width * height) // 8)
self._buffer2 = bytearray((width * height) // 8)
# since we have *two* framebuffers - one for red and one for black
# we dont subclass but manage manually
self._framebuf1 = adafruit_framebuf.FrameBuffer(
self._buffer1, width, height, buf_format=adafruit_framebuf.MHMSB
)
self._framebuf2 = adafruit_framebuf.FrameBuffer(
self._buffer2, width, height, buf_format=adafruit_framebuf.MHMSB
)
self.set_black_buffer(0, True)
self.set_color_buffer(1, True)
# pylint: enable=too-many-arguments
def begin(self, reset=True):
"""Begin communication with the display and set basic settings"""
if reset:
self.hardware_reset()
self.power_down()
def busy_wait(self):
"""Wait for display to be done with current task, either by polling the
busy pin, or pausing"""
if self._busy:
while not self._busy.value:
# self.command(_IL0398_GETSTATUS)
time.sleep(0.01)
else:
time.sleep(0.5)
def power_up(self):
"""Power up the display in preparation for writing RAM and updating"""
self.hardware_reset()
self.busy_wait()
self.command(_IL0398_BOOSTER_SOFT_START, bytearray([0x17, 0x17, 0x17]))
self.command(_IL0398_POWER_ON)
self.busy_wait()
time.sleep(0.2)
self.command(_IL0398_PANEL_SETTING, bytearray([0x0F]))
_b0 = (self._width >> 8) & 0xFF
_b1 = self._width & 0xFF
_b2 = (self._height >> 8) & 0xFF
_b3 = self._height & 0xFF
self.command(_IL0398_RESOLUTION, bytearray([_b0, _b1, _b2, _b3]))
time.sleep(0.05)
def power_down(self):
"""Power down the display - required when not actively displaying!"""
self.command(_IL0398_CDI, bytearray([0xF7]))
self.command(_IL0398_POWER_OFF)
self.busy_wait()
self.command(_IL0398_DEEP_SLEEP, bytearray([0xA5]))
def update(self):
"""Update the display from internal memory"""
self.command(_IL0398_DISPLAY_REFRESH)
time.sleep(0.1)
self.busy_wait()
if not self._busy:
time.sleep(15) # wait 15 seconds
def write_ram(self, index):
"""Send the one byte command for starting the RAM write process. Returns
the byte read at the same time over SPI. index is the RAM buffer, can be
0 or 1 for tri-color displays."""
if index == 0:
return self.command(_IL0398_DTM1, end=False)
if index == 1:
return self.command(_IL0398_DTM2, end=False)
raise RuntimeError("RAM index must be 0 or 1")
def set_ram_address(self, x, y): # pylint: disable=unused-argument, no-self-use
"""Set the RAM address location, not used on this chipset but required by
the superclass"""
return # on this chip it does nothing

182
adafruit_epd/il91874.py Normal file
View file

@ -0,0 +1,182 @@
# The MIT License (MIT)
#
# Copyright (c) 2018 Dean Miller 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_epd.il91874` - Adafruit IL91874 - ePaper display driver
====================================================================================
CircuitPython driver for Adafruit IL91874 display breakouts
* Author(s): Dean Miller, Ladyada
"""
import time
from micropython import const
import adafruit_framebuf
from adafruit_epd.epd import Adafruit_EPD
__version__ = "0.0.0-auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_EPD.git"
_IL91874_PANEL_SETTING = const(0x00)
_IL91874_POWER_SETTING = const(0x01)
_IL91874_POWER_OFF = const(0x02)
_IL91874_POWER_OFF_SEQUENCE = const(0x03)
_IL91874_POWER_ON = const(0x04)
_IL91874_POWER_ON_MEASURE = const(0x05)
_IL91874_BOOSTER_SOFT_START = const(0x06)
_IL91874_DEEP_SLEEP = const(0x07)
_IL91874_DTM1 = const(0x10)
_IL91874_DATA_STOP = const(0x11)
_IL91874_DISPLAY_REFRESH = const(0x12)
_IL91874_DTM2 = const(0x13)
_IL91874_PDTM1 = const(0x14)
_IL91874_PDTM2 = const(0x15)
_IL91874_PDRF = const(0x16)
_IL91874_LUT1 = const(0x20)
_IL91874_LUTWW = const(0x21)
_IL91874_LUTBW = const(0x22)
_IL91874_LUTWB = const(0x23)
_IL91874_LUTBB = const(0x24)
_IL91874_PLL = const(0x30)
_IL91874_CDI = const(0x50)
_IL91874_RESOLUTION = const(0x61)
_IL91874_VCM_DC_SETTING = const(0x82)
# pylint: disable=line-too-long
_LUT_VCOMDC = b"\x00\x00\x00\x1a\x1a\x00\x00\x01\x00\n\n\x00\x00\x08\x00\x0e\x01\x0e\x01\x10\x00\n\n\x00\x00\x08\x00\x04\x10\x00\x00\x05\x00\x03\x0e\x00\x00\n\x00#\x00\x00\x00\x01"
_LUT_WW = b"\x90\x1a\x1a\x00\x00\x01@\n\n\x00\x00\x08\x84\x0e\x01\x0e\x01\x10\x80\n\n\x00\x00\x08\x00\x04\x10\x00\x00\x05\x00\x03\x0e\x00\x00\n\x00#\x00\x00\x00\x01"
_LUT_BW = b"\xa0\x1a\x1a\x00\x00\x01\x00\n\n\x00\x00\x08\x84\x0e\x01\x0e\x01\x10\x90\n\n\x00\x00\x08\xb0\x04\x10\x00\x00\x05\xb0\x03\x0e\x00\x00\n\xc0#\x00\x00\x00\x01"
_LUT_BB = b"\x90\x1a\x1a\x00\x00\x01@\n\n\x00\x00\x08\x84\x0e\x01\x0e\x01\x10\x80\n\n\x00\x00\x08\x00\x04\x10\x00\x00\x05\x00\x03\x0e\x00\x00\n\x00#\x00\x00\x00\x01"
_LUT_WB = b"\x90\x1a\x1a\x00\x00\x01 \n\n\x00\x00\x08\x84\x0e\x01\x0e\x01\x10\x10\n\n\x00\x00\x08\x00\x04\x10\x00\x00\x05\x00\x03\x0e\x00\x00\n\x00#\x00\x00\x00\x01"
# pylint: enable=line-too-long
class Adafruit_IL91874(Adafruit_EPD):
"""driver class for Adafruit IL91874 ePaper display breakouts"""
# pylint: disable=too-many-arguments
def __init__(
self, width, height, spi, *, cs_pin, dc_pin, sramcs_pin, rst_pin, busy_pin
):
super(Adafruit_IL91874, self).__init__(
width, height, spi, cs_pin, dc_pin, sramcs_pin, rst_pin, busy_pin
)
self._buffer1_size = int(width * height / 8)
self._buffer2_size = int(width * height / 8)
if sramcs_pin:
self._buffer1 = self.sram.get_view(0)
self._buffer2 = self.sram.get_view(self._buffer1_size)
else:
self._buffer1 = bytearray((width * height) // 8)
self._buffer2 = bytearray((width * height) // 8)
# since we have *two* framebuffers - one for red and one for black
# we dont subclass but manage manually
self._framebuf1 = adafruit_framebuf.FrameBuffer(
self._buffer1, width, height, buf_format=adafruit_framebuf.MHMSB
)
self._framebuf2 = adafruit_framebuf.FrameBuffer(
self._buffer2, width, height, buf_format=adafruit_framebuf.MHMSB
)
self.set_black_buffer(0, True)
self.set_color_buffer(1, False)
self._single_byte_tx = True
def begin(self, reset=True):
"""Begin communication with the display and set basic settings"""
if reset:
self.hardware_reset()
self.power_down()
def busy_wait(self):
"""Wait for display to be done with current task, either by polling the
busy pin, or pausing"""
if self._busy:
while not self._busy.value:
time.sleep(0.01)
else:
time.sleep(0.5)
def power_up(self):
"""Power up the display in preparation for writing RAM and updating"""
self.hardware_reset()
time.sleep(0.2)
self.command(_IL91874_POWER_ON)
self.busy_wait()
self.command(_IL91874_PANEL_SETTING, bytearray([0xAF]))
self.command(_IL91874_PLL, bytearray([0x3A]))
self.command(_IL91874_POWER_SETTING, bytearray([0x03, 0x00, 0x2B, 0x2B, 0x09]))
self.command(_IL91874_BOOSTER_SOFT_START, bytearray([0x07, 0x07, 0x17]))
self.command(0xF8, bytearray([0x60, 0xA5])) # mystery command in example code
self.command(0xF8, bytearray([0x89, 0xA5])) # mystery command in example code
self.command(0xF8, bytearray([0x90, 0x00])) # mystery command in example code
self.command(0xF8, bytearray([0x93, 0xA2])) # mystery command in example code
self.command(0xF8, bytearray([0x73, 0x41])) # mystery command in example code
self.command(_IL91874_VCM_DC_SETTING, bytearray([0x12]))
self.command(_IL91874_CDI, bytearray([0x87]))
# Look Up Tables
self.command(_IL91874_LUT1, _LUT_VCOMDC)
self.command(_IL91874_LUTWW, _LUT_WW)
self.command(_IL91874_LUTBW, _LUT_BW)
self.command(_IL91874_LUTWB, _LUT_WB)
self.command(_IL91874_LUTBB, _LUT_BB)
_b0 = (self._width >> 8) & 0xFF
_b1 = self._width & 0xFF
_b2 = (self._height >> 8) & 0xFF
_b3 = self._height & 0xFF
self.command(_IL91874_RESOLUTION, bytearray([_b0, _b1, _b2, _b3]))
self.command(_IL91874_PDRF, bytearray([0x00]))
def power_down(self):
"""Power down the display - required when not actively displaying!"""
self.command(_IL91874_POWER_OFF, bytearray([0x17]))
self.busy_wait()
if self._rst: # Only deep sleep if we can get out of it
self.command(_IL91874_DEEP_SLEEP, bytearray([0xA5]))
def update(self):
"""Update the display from internal memory"""
self.command(_IL91874_DISPLAY_REFRESH)
self.busy_wait()
if not self._busy:
time.sleep(16) # wait 16 seconds
def write_ram(self, index):
"""Send the one byte command for starting the RAM write process. Returns
the byte read at the same time over SPI. index is the RAM buffer, can be
0 or 1 for tri-color displays."""
if index == 0:
return self.command(_IL91874_DTM1, end=False)
if index == 1:
return self.command(_IL91874_DTM2, end=False)
raise RuntimeError("RAM index must be 0 or 1")
def set_ram_address(self, x, y): # pylint: disable=unused-argument, no-self-use
"""Set the RAM address location, not used on this chipset but required by
the superclass"""
return # on this chip it does nothing

View file

@ -27,13 +27,34 @@ CircuitPython driver for Microchip SRAM chips
"""
from micropython import const
import digitalio
from adafruit_bus_device import spi_device
__version__ = "0.0.0-auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_EPD.git"
SRAM_SEQUENTIAL_MODE = const(1 << 6)
class Adafruit_MCP_SRAM_View:
"""A interface class that turns an SRAM chip into something like a memoryview"""
def __init__(self, sram, offset):
self._sram = sram
self._offset = offset
self._buf = [0]
def __getitem__(self, i):
return self._sram.read(self._offset + i, 1)[0]
def __setitem__(self, i, val):
self._buf[0] = val
self._sram.write(self._offset + i, self._buf)
class Adafruit_MCP_SRAM:
"""supporting class for communicating with
Microchip SRAM chips"""
SRAM_READ = 0x03
SRAM_WRITE = 0x02
SRAM_RDSR = 0x05
@ -41,40 +62,39 @@ class Adafruit_MCP_SRAM:
def __init__(self, cs_pin, spi):
# Handle hardware SPI
self._spi = spi_device.SPIDevice(spi, cs_pin, baudrate=8000000)
self.spi_device = spi
self.cs_pin = cs_pin
self._buf = bytearray(3)
self._buf[0] = Adafruit_MCP_SRAM.SRAM_WRSR
self._buf[1] = 0x43
with self._spi as spidev:
spidev.write(self._buf, end=2) # pylint: disable=no-member
self.cs_pin.direction = digitalio.Direction.OUTPUT
while not self.spi_device.try_lock():
pass
self.cs_pin.value = False
self.spi_device.write(bytearray([Adafruit_MCP_SRAM.SRAM_WRSR, 0x43]))
self.cs_pin.value = True
self.spi_device.unlock()
def get_view(self, offset):
"""Create an object that can be used as a memoryview, with a given offset"""
return Adafruit_MCP_SRAM_View(self, offset)
def write(self, addr, buf, reg=SRAM_WRITE):
"""write the passed buffer to the passed address"""
cmd = bytearray([reg, (addr >> 8) & 0xFF, addr & 0xFF] + buf)
self._buf[0] = reg
self._buf[1] = (addr >> 8) & 0xFF
self._buf[2] = addr & 0xFF
while not self.spi_device.try_lock():
pass
self.cs_pin.value = False
self.spi_device.write(cmd)
self.cs_pin.value = True
self.spi_device.unlock()
with self._spi as spi:
spi.write(self._buf, end=3) # pylint: disable=no-member
spi.write(bytearray(buf)) # pylint: disable=no-member
def read(self, addr, length, reg=SRAM_READ):
"""read passed number of bytes at the passed address"""
cmd = bytearray([reg, (addr >> 8) & 0xFF, addr & 0xFF])
self._buf[0] = reg
self._buf[1] = (addr >> 8) & 0xFF
self._buf[2] = addr & 0xFF
buf = bytearray(length)
while not self.spi_device.try_lock():
pass
self.cs_pin.value = False
self.spi_device.write(cmd)
self.spi_device.readinto(buf)
self.cs_pin.value = True
self.spi_device.unlock()
with self._spi as spi:
spi.write(self._buf, end=3) # pylint: disable=no-member
spi.readinto(buf) # pylint: disable=no-member
return buf
def read8(self, addr, reg=SRAM_READ):
@ -96,13 +116,11 @@ class Adafruit_MCP_SRAM:
def erase(self, addr, length, value):
"""erase the passed number of bytes starting at the passed address"""
cmd = bytearray([Adafruit_MCP_SRAM.SRAM_WRITE, (addr >> 8) & 0xFF, addr & 0xFF])
while not self.spi_device.try_lock():
pass
self.cs_pin.value = False
self.spi_device.write(cmd)
self._buf[0] = Adafruit_MCP_SRAM.SRAM_WRITE
self._buf[1] = (addr >> 8) & 0xFF
self._buf[2] = addr & 0xFF
fill = bytearray([value])
with self._spi as spi:
spi.write(self._buf, end=3) # pylint: disable=no-member
for _ in range(length):
self.spi_device.write(bytearray([value]))
self.cs_pin.value = True
self.spi_device.unlock()
spi.write(fill) # pylint: disable=no-member

172
adafruit_epd/ssd1608.py Normal file
View file

@ -0,0 +1,172 @@
# The MIT License (MIT)
#
# Copyright (c) 2018 Dean Miller 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_epd.ssd1608` - Adafruit SSD1608 - ePaper display driver
====================================================================================
CircuitPython driver for Adafruit SSD1608 display breakouts
* Author(s): Dean Miller, Ladyada
"""
import time
from micropython import const
import adafruit_framebuf
from adafruit_epd.epd import Adafruit_EPD
__version__ = "0.0.0-auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_EPD.git"
_SSD1608_DRIVER_CONTROL = const(0x01)
_SSD1608_GATE_VOLTAGE = const(0x03)
_SSD1608_SOURCE_VOLTAGE = const(0x04)
_SSD1608_DISPLAY_CONTROL = const(0x07)
_SSD1608_NON_OVERLAP = const(0x0B)
_SSD1608_BOOSTER_SOFT_START = const(0x0C)
_SSD1608_GATE_SCAN_START = const(0x0F)
_SSD1608_DEEP_SLEEP = const(0x10)
_SSD1608_DATA_MODE = const(0x11)
_SSD1608_SW_RESET = const(0x12)
_SSD1608_TEMP_WRITE = const(0x1A)
_SSD1608_TEMP_READ = const(0x1B)
_SSD1608_TEMP_CONTROL = const(0x1C)
_SSD1608_TEMP_LOAD = const(0x1D)
_SSD1608_MASTER_ACTIVATE = const(0x20)
_SSD1608_DISP_CTRL1 = const(0x21)
_SSD1608_DISP_CTRL2 = const(0x22)
_SSD1608_WRITE_RAM = const(0x24)
_SSD1608_READ_RAM = const(0x25)
_SSD1608_VCOM_SENSE = const(0x28)
_SSD1608_VCOM_DURATION = const(0x29)
_SSD1608_WRITE_VCOM = const(0x2C)
_SSD1608_READ_OTP = const(0x2D)
_SSD1608_WRITE_LUT = const(0x32)
_SSD1608_WRITE_DUMMY = const(0x3A)
_SSD1608_WRITE_GATELINE = const(0x3B)
_SSD1608_WRITE_BORDER = const(0x3C)
_SSD1608_SET_RAMXPOS = const(0x44)
_SSD1608_SET_RAMYPOS = const(0x45)
_SSD1608_SET_RAMXCOUNT = const(0x4E)
_SSD1608_SET_RAMYCOUNT = const(0x4F)
_SSD1608_NOP = const(0xFF)
_LUT_DATA = b'\x02\x02\x01\x11\x12\x12""fiiYX\x99\x99\x88\x00\x00\x00\x00\xf8\xb4\x13Q5QQ\x19\x01\x00' # pylint: disable=line-too-long
class Adafruit_SSD1608(Adafruit_EPD):
"""driver class for Adafruit SSD1608 ePaper display breakouts"""
# pylint: disable=too-many-arguments
def __init__(
self, width, height, spi, *, cs_pin, dc_pin, sramcs_pin, rst_pin, busy_pin
):
super(Adafruit_SSD1608, self).__init__(
width, height, spi, cs_pin, dc_pin, sramcs_pin, rst_pin, busy_pin
)
if height % 8 != 0:
height += 8 - height % 8
self._height = height
self._buffer1_size = int(width * height / 8)
if sramcs_pin:
self._buffer1 = self.sram.get_view(0)
else:
self._buffer1 = bytearray((width * height) // 8)
self._framebuf1 = adafruit_framebuf.FrameBuffer(
self._buffer1, width, height, buf_format=adafruit_framebuf.MHMSB
)
self.set_black_buffer(0, True)
self.set_color_buffer(0, True)
# pylint: enable=too-many-arguments
def begin(self, reset=True):
"""Begin communication with the display and set basic settings"""
if reset:
self.hardware_reset()
self.power_down()
def busy_wait(self):
"""Wait for display to be done with current task, either by polling the
busy pin, or pausing"""
if self._busy:
while self._busy.value:
time.sleep(0.01)
else:
time.sleep(0.5)
def power_up(self):
"""Power up the display in preparation for writing RAM and updating"""
self.hardware_reset()
self.busy_wait()
self.command(_SSD1608_SW_RESET)
self.busy_wait()
# driver output control
self.command(
_SSD1608_DRIVER_CONTROL,
bytearray([self._width - 1, (self._width - 1) >> 8, 0x00]),
)
# Set dummy line period
self.command(_SSD1608_WRITE_DUMMY, bytearray([0x1B]))
# Set gate line width
self.command(_SSD1608_WRITE_GATELINE, bytearray([0x0B]))
# Data entry sequence
self.command(_SSD1608_DATA_MODE, bytearray([0x03]))
# Set ram X start/end postion
self.command(_SSD1608_SET_RAMXPOS, bytearray([0x00, self._height // 8 - 1]))
# Set ram Y start/end postion
self.command(
_SSD1608_SET_RAMYPOS,
bytearray([0, 0, self._height - 1, (self._height - 1) >> 8]),
)
# Vcom Voltage
self.command(_SSD1608_WRITE_VCOM, bytearray([0x70]))
# LUT
self.command(_SSD1608_WRITE_LUT, _LUT_DATA)
self.busy_wait()
def power_down(self):
"""Power down the display - required when not actively displaying!"""
self.command(_SSD1608_DEEP_SLEEP, bytearray([0x01]))
time.sleep(0.1)
def update(self):
"""Update the display from internal memory"""
self.command(_SSD1608_DISP_CTRL2, bytearray([0xC7]))
self.command(_SSD1608_MASTER_ACTIVATE)
self.busy_wait()
if not self._busy:
time.sleep(3) # wait 3 seconds
def write_ram(self, index):
"""Send the one byte command for starting the RAM write process. Returns
the byte read at the same time over SPI. index is the RAM buffer, can be
0 or 1 for tri-color displays."""
if index == 0:
return self.command(_SSD1608_WRITE_RAM, end=False)
raise RuntimeError("RAM index must be 0")
def set_ram_address(self, x, y): # pylint: disable=unused-argument, no-self-use
"""Set the RAM address location, not used on this chipset but required by
the superclass"""
# Set RAM X address counter
self.command(_SSD1608_SET_RAMXCOUNT, bytearray([x]))
# Set RAM Y address counter
self.command(_SSD1608_SET_RAMYCOUNT, bytearray([y >> 8, y]))

194
adafruit_epd/ssd1675.py Normal file
View file

@ -0,0 +1,194 @@
# The MIT License (MIT)
#
# Copyright (c) 2018 Dean Miller 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_epd.ssd1675` - Adafruit SSD1675 - ePaper display driver
====================================================================================
CircuitPython driver for Adafruit SSD1675 display breakouts
* Author(s): Dean Miller, Ladyada
"""
import time
from micropython import const
import adafruit_framebuf
from adafruit_epd.epd import Adafruit_EPD
__version__ = "0.0.0-auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_EPD.git"
_SSD1675_DRIVER_CONTROL = const(0x01)
_SSD1675_GATE_VOLTAGE = const(0x03)
_SSD1675_SOURCE_VOLTAGE = const(0x04)
_SSD1675_DEEP_SLEEP = const(0x10)
_SSD1675_DATA_MODE = const(0x11)
_SSD1675_SW_RESET = const(0x12)
_SSD1675_HV_READY = const(0x14)
_SSD1675_VCI_READY = const(0x15)
_SSD1675_TEMP_WRITE = const(0x1A)
_SSD1675_MASTER_ACTIVATE = const(0x20)
_SSD1675_DISP_CTRL1 = const(0x21)
_SSD1675_DISP_CTRL2 = const(0x22)
_SSD1675_WRITE_RAM1 = const(0x24)
_SSD1675_WRITE_RAM2 = const(0x26)
_SSD1675_WRITE_VCOM = const(0x2C)
_SSD1675_READ_OTP = const(0x2D)
_SSD1675_WRITE_LUT = const(0x32)
_SSD1675_WRITE_DUMMY = const(0x3A)
_SSD1675_WRITE_GATELINE = const(0x3B)
_SSD1675_WRITE_BORDER = const(0x3C)
_SSD1675_SET_RAMXPOS = const(0x44)
_SSD1675_SET_RAMYPOS = const(0x45)
_SSD1675_SET_RAMXCOUNT = const(0x4E)
_SSD1675_SET_RAMYCOUNT = const(0x4F)
_SSD1675_SET_ANALOGBLOCK = const(0x74)
_SSD1675_SET_DIGITALBLOCK = const(0x7E)
_LUT_DATA = b"\x80`@\x00\x00\x00\x00\x10` \x00\x00\x00\x00\x80`@\x00\x00\x00\x00\x10` \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x03\x00\x00\x02\t\t\x00\x00\x02\x03\x03\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x15A\xa820\n" # pylint: disable=line-too-long
class Adafruit_SSD1675(Adafruit_EPD):
"""driver class for Adafruit SSD1675 ePaper display breakouts"""
# pylint: disable=too-many-arguments
def __init__(
self, width, height, spi, *, cs_pin, dc_pin, sramcs_pin, rst_pin, busy_pin
):
super(Adafruit_SSD1675, self).__init__(
width, height, spi, cs_pin, dc_pin, sramcs_pin, rst_pin, busy_pin
)
stride = width
if stride % 8 != 0:
stride += 8 - stride % 8
self._buffer1_size = int(stride * height / 8)
self._buffer2_size = self._buffer1_size
if sramcs_pin:
self._buffer1 = self.sram.get_view(0)
self._buffer2 = self.sram.get_view(self._buffer1_size)
else:
self._buffer1 = bytearray(self._buffer1_size)
self._buffer2 = bytearray(self._buffer2_size)
# since we have *two* framebuffers - one for red and one for black
# we dont subclass but manage manually
self._framebuf1 = adafruit_framebuf.FrameBuffer(
self._buffer1,
width,
height,
stride=stride,
buf_format=adafruit_framebuf.MHMSB,
)
self._framebuf2 = adafruit_framebuf.FrameBuffer(
self._buffer2,
width,
height,
stride=stride,
buf_format=adafruit_framebuf.MHMSB,
)
self.set_black_buffer(0, True)
self.set_color_buffer(0, True)
# pylint: enable=too-many-arguments
def begin(self, reset=True):
"""Begin communication with the display and set basic settings"""
if reset:
self.hardware_reset()
self.power_down()
def busy_wait(self):
"""Wait for display to be done with current task, either by polling the
busy pin, or pausing"""
if self._busy:
while self._busy.value:
time.sleep(0.01)
else:
time.sleep(0.5)
def power_up(self):
"""Power up the display in preparation for writing RAM and updating"""
self.hardware_reset()
time.sleep(0.1)
self.busy_wait()
self.command(_SSD1675_SW_RESET)
self.busy_wait()
# set analog block control
self.command(_SSD1675_SET_ANALOGBLOCK, bytearray([0x54]))
# set digital block control
self.command(_SSD1675_SET_DIGITALBLOCK, bytearray([0x3B]))
# driver output control
self.command(_SSD1675_DRIVER_CONTROL, bytearray([0xFA, 0x01, 0x00]))
# Data entry sequence
self.command(_SSD1675_DATA_MODE, bytearray([0x03]))
# Set ram X start/end postion
self.command(_SSD1675_SET_RAMXPOS, bytearray([0x00, 0x0F]))
# Set ram Y start/end postion
self.command(_SSD1675_SET_RAMYPOS, bytearray([0, 0, 0xF9, 0]))
# Border color
self.command(_SSD1675_WRITE_BORDER, bytearray([0x03]))
# Vcom Voltage
self.command(_SSD1675_WRITE_VCOM, bytearray([0x70]))
# Set gate voltage
self.command(_SSD1675_GATE_VOLTAGE, _LUT_DATA[70:71])
# Set gate voltage
self.command(_SSD1675_SOURCE_VOLTAGE, _LUT_DATA[71:74])
# Set dummy line period
self.command(_SSD1675_WRITE_DUMMY, _LUT_DATA[74:75])
# Set gate line width
self.command(_SSD1675_WRITE_GATELINE, _LUT_DATA[75:76])
# LUT
self.command(_SSD1675_WRITE_LUT, _LUT_DATA[0:70])
self.command(_SSD1675_SET_RAMXCOUNT, bytearray([0]))
# Set RAM Y address counter
self.command(_SSD1675_SET_RAMYCOUNT, bytearray([0xF9, 0]))
self.busy_wait()
def power_down(self):
"""Power down the display - required when not actively displaying!"""
self.command(_SSD1675_DEEP_SLEEP, bytearray([0x01]))
time.sleep(0.1)
def update(self):
"""Update the display from internal memory"""
self.command(_SSD1675_DISP_CTRL2, bytearray([0xC7]))
self.command(_SSD1675_MASTER_ACTIVATE)
self.busy_wait()
if not self._busy:
time.sleep(3) # wait 3 seconds
def write_ram(self, index):
"""Send the one byte command for starting the RAM write process. Returns
the byte read at the same time over SPI. index is the RAM buffer, can be
0 or 1 for tri-color displays."""
if index == 0:
return self.command(_SSD1675_WRITE_RAM1, end=False)
if index == 1:
return self.command(_SSD1675_WRITE_RAM2, end=False)
raise RuntimeError("RAM index must be 0 or 1")
def set_ram_address(self, x, y): # pylint: disable=unused-argument, no-self-use
"""Set the RAM address location, not used on this chipset but required by
the superclass"""
self.command(_SSD1675_SET_RAMXCOUNT, bytearray([x]))
self.command(_SSD1675_SET_RAMYCOUNT, bytearray([y, y >> 8]))

236
adafruit_epd/ssd1675b.py Normal file
View file

@ -0,0 +1,236 @@
# The MIT License (MIT)
#
# Copyright (c) 2018 Dean Miller 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_epd.ssd1675b` - Adafruit SSD1675 - ePaper display driver
====================================================================================
CircuitPython driver for Adafruit SSD1675 display breakouts
* Author(s): Dean Miller, Ladyada
"""
import time
from micropython import const
import adafruit_framebuf
from adafruit_epd.epd import Adafruit_EPD
__version__ = "0.0.0-auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_EPD.git"
_SSD1675B_DRIVER_CONTROL = const(0x01)
_SSD1675B_GATE_VOLTAGE = const(0x03)
_SSD1675B_SOURCE_VOLTAGE = const(0x04)
_SSD1675B_INIT_SETTING = const(0x08)
_SSD1675B_INIT_WRITE_REG = const(0x09)
_SSD1675B_INIT_READ_REG = const(0x0A)
_SSD1675B_BOOSTER_SOFT_START = const(0x0C)
_SSD1675B_GATESCAN_START = const(0x0F)
_SSD1675B_DEEP_SLEEP = const(0x10)
_SSD1675B_DATA_MODE = const(0x11)
_SSD1675B_SW_RESET = const(0x12)
_SSD1675B_HV_READY = const(0x14)
_SSD1675B_VCI_READY = const(0x15)
_SSD1675B_TEMP_CONTROL = const(0x18)
_SSD1675B_TEMP_WRITE = const(0x1A)
_SSD1675B_TEMP_READ = const(0x1B)
_SSD1675B_EXTTEMP_WRITE = const(0x1C)
_SSD1675B_MASTER_ACTIVATE = const(0x20)
_SSD1675B_DISP_CTRL1 = const(0x21)
_SSD1675B_DISP_CTRL2 = const(0x22)
_SSD1675B_WRITE_RAM1 = const(0x24)
_SSD1675B_WRITE_RAM2 = const(0x26)
_SSD1675B_READ_RAM = const(0x27)
_SSD1675B_VCOM_SENSE = const(0x28)
_SSD1675B_VCOM_DURATION = const(0x29)
_SSD1675B_WRITE_VCOM_OTP = const(0x2A)
_SSD1675B_WRITE_VCOM_CTRL = const(0x2B)
_SSD1675B_WRITE_VCOM_REG = const(0x2C)
_SSD1675B_READ_OTP = const(0x2D)
_SSD1675B_READ_USERID = const(0x2E)
_SSD1675B_READ_STATUS = const(0x2F)
_SSD1675B_WRITE_WS_OTP = const(0x30)
_SSD1675B_LOAD_WS_OTP = const(0x31)
_SSD1675B_WRITE_LUT = const(0x32)
_SSD1675B_CRC_CALC = const(0x34)
_SSD1675B_CRC_READ = const(0x35)
_SSD1675B_PROG_OTP = const(0x36)
_SSD1675B_WRITE_DISPLAY_OPT = const(0x37)
_SSD1675B_WRITE_USERID = const(0x38)
_SSD1675B_OTP_PROGMODE = const(0x39)
_SSD1675B_WRITE_DUMMY = const(0x3A)
_SSD1675B_WRITE_GATELINE = const(0x3B)
_SSD1675B_WRITE_BORDER = const(0x3C)
_SSD1675B_SET_RAMXPOS = const(0x44)
_SSD1675B_SET_RAMYPOS = const(0x45)
_SSD1675B_AUTOWRITE_RED = const(0x46)
_SSD1675B_AUTOWRITE_BW = const(0x47)
_SSD1675B_SET_RAMXCOUNT = const(0x4E)
_SSD1675B_SET_RAMYCOUNT = const(0x4F)
_SSD1675B_SET_ANALOGBLOCK = const(0x74)
_SSD1675B_SET_DIGITALBLOCK = const(0x7E)
_SSD1675B_NOP = const(0xFF)
_LUT_DATA = b"\xa0\x90P\x00\x00\x00\x00\x00\x00\x00P\x90\xa0\x00\x00\x00\x00\x00\x00\x00\xa0\x90P\x00\x00\x00\x00\x00\x00\x00P\x90\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0f\x0f\x00\x00\x00\x0f\x0f\x00\x00\x03\x0f\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x15A\xa82P,\x0b" # pylint: disable=line-too-long
class Adafruit_SSD1675B(Adafruit_EPD):
"""driver class for Adafruit SSD1675B ePaper display breakouts"""
# pylint: disable=too-many-arguments
def __init__(
self, width, height, spi, *, cs_pin, dc_pin, sramcs_pin, rst_pin, busy_pin
):
super(Adafruit_SSD1675B, self).__init__(
width, height, spi, cs_pin, dc_pin, sramcs_pin, rst_pin, busy_pin
)
stride = width
if stride % 8 != 0:
stride += 8 - stride % 8
self._buffer1_size = int(stride * height / 8)
self._buffer2_size = self._buffer1_size
if sramcs_pin:
self._buffer1 = self.sram.get_view(0)
self._buffer2 = self.sram.get_view(self._buffer1_size)
else:
self._buffer1 = bytearray(self._buffer1_size)
self._buffer2 = bytearray(self._buffer2_size)
# since we have *two* framebuffers - one for red and one for black
# we dont subclass but manage manually
self._framebuf1 = adafruit_framebuf.FrameBuffer(
self._buffer1,
width,
height,
stride=stride,
buf_format=adafruit_framebuf.MHMSB,
)
self._framebuf2 = adafruit_framebuf.FrameBuffer(
self._buffer2,
width,
height,
stride=stride,
buf_format=adafruit_framebuf.MHMSB,
)
self.set_black_buffer(0, True)
self.set_color_buffer(0, True)
# pylint: enable=too-many-arguments
def begin(self, reset=True):
"""Begin communication with the display and set basic settings"""
if reset:
self.hardware_reset()
self.power_down()
def busy_wait(self):
"""Wait for display to be done with current task, either by polling the
busy pin, or pausing"""
if self._busy:
while self._busy.value:
time.sleep(0.01)
else:
time.sleep(0.5)
def power_up(self):
"""Power up the display in preparation for writing RAM and updating"""
self.hardware_reset()
time.sleep(0.1)
self.busy_wait()
self.command(_SSD1675B_SW_RESET)
self.busy_wait()
# set analog block control
self.command(_SSD1675B_SET_ANALOGBLOCK, bytearray([0x54]))
# set digital block control
self.command(_SSD1675B_SET_DIGITALBLOCK, bytearray([0x3B]))
self.command(
_SSD1675B_DRIVER_CONTROL,
bytearray([self._height - 1, (self._height - 1) >> 8, 0x00]),
)
# Data entry sequence
self.command(_SSD1675B_DATA_MODE, bytearray([0x03]))
# Set ram X start/end postion
self.command(_SSD1675B_SET_RAMXPOS, bytearray([0x00, self._width // 8]))
# Set ram Y start/end postion
self.command(
_SSD1675B_SET_RAMYPOS,
bytearray([0x0, 0x0, self._height - 1, (self._height - 1) >> 8]),
)
# Border color
self.command(_SSD1675B_WRITE_BORDER, bytearray([0x03]))
# Vcom Voltage
self.command(_SSD1675B_WRITE_VCOM_REG, bytearray([0x50]))
# Set gate voltage
self.command(_SSD1675B_GATE_VOLTAGE, _LUT_DATA[100:101])
# Set source voltage
self.command(_SSD1675B_SOURCE_VOLTAGE, _LUT_DATA[101:104])
# Set dummy line period
self.command(_SSD1675B_WRITE_DUMMY, _LUT_DATA[105:106])
# Set gate line width
self.command(_SSD1675B_WRITE_GATELINE, _LUT_DATA[106:107])
# LUT
self.command(_SSD1675B_WRITE_LUT, _LUT_DATA[0:100])
# Set temperature control
# self.command(_SSD1675B_TEMP_CONTROL, bytearray([0x80]))
# Set RAM X address counter
self.command(_SSD1675B_SET_RAMXCOUNT, bytearray([0]))
# Set RAM Y address counter
self.command(
_SSD1675B_SET_RAMYCOUNT,
bytearray([self._height - 1, (self._height - 1) >> 8]),
)
self.busy_wait()
def power_down(self):
"""Power down the display - required when not actively displaying!"""
self.command(_SSD1675B_DEEP_SLEEP, bytearray([0x01]))
time.sleep(0.1)
def update(self):
"""Update the display from internal memory"""
self.command(_SSD1675B_DISP_CTRL2, bytearray([0xC7]))
self.command(_SSD1675B_MASTER_ACTIVATE)
self.busy_wait()
if not self._busy:
time.sleep(3) # wait 3 seconds
def write_ram(self, index):
"""Send the one byte command for starting the RAM write process. Returns
the byte read at the same time over SPI. index is the RAM buffer, can be
0 or 1 for tri-color displays."""
if index == 0:
return self.command(_SSD1675B_WRITE_RAM1, end=False)
if index == 1:
return self.command(_SSD1675B_WRITE_RAM2, end=False)
raise RuntimeError("RAM index must be 0 or 1")
def set_ram_address(self, x, y): # pylint: disable=unused-argument, no-self-use
"""Set the RAM address location, not used on this chipset but required by
the superclass"""
self.command(_SSD1675B_SET_RAMXCOUNT, bytearray([x]))
self.command(_SSD1675B_SET_RAMYCOUNT, bytearray([y, y >> 8]))

186
adafruit_epd/ssd1681.py Normal file
View file

@ -0,0 +1,186 @@
# The MIT License (MIT)
#
# Copyright (c) 2018 Dean Miller 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_epd.ssd1681` - Adafruit SSD1681 - ePaper display driver
====================================================================================
CircuitPython driver for Adafruit SSD1681 display breakouts
* Author(s): Dean Miller, Ladyada
"""
import time
from micropython import const
import adafruit_framebuf
from adafruit_epd.epd import Adafruit_EPD
__version__ = "0.0.0-auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_EPD.git"
_SSD1681_DRIVER_CONTROL = const(0x01)
_SSD1681_GATE_VOLTAGE = const(0x03)
_SSD1681_SOURCE_VOLTAGE = const(0x04)
_SSD1681_INIT_SETTING = const(0x08)
_SSD1681_INIT_WRITE_REG = const(0x09)
_SSD1681_INIT_READ_REG = const(0x0A)
_SSD1681_BOOSTER_SOFT_START = const(0x0C)
_SSD1681_DEEP_SLEEP = const(0x10)
_SSD1681_DATA_MODE = const(0x11)
_SSD1681_SW_RESET = const(0x12)
_SSD1681_HV_DETECT = const(0x14)
_SSD1681_VCI_DETECT = const(0x15)
_SSD1681_TEMP_CONTROL = const(0x18)
_SSD1681_TEMP_WRITE = const(0x1A)
_SSD1681_TEMP_READ = const(0x1B)
_SSD1681_EXTTEMP_WRITE = const(0x1C)
_SSD1681_MASTER_ACTIVATE = const(0x20)
_SSD1681_DISP_CTRL1 = const(0x21)
_SSD1681_DISP_CTRL2 = const(0x22)
_SSD1681_WRITE_BWRAM = const(0x24)
_SSD1681_WRITE_REDRAM = const(0x26)
_SSD1681_READ_RAM = const(0x27)
_SSD1681_VCOM_SENSE = const(0x28)
_SSD1681_VCOM_DURATION = const(0x29)
_SSD1681_WRITE_VCOM_OTP = const(0x2A)
_SSD1681_WRITE_VCOM_CTRL = const(0x2B)
_SSD1681_WRITE_VCOM_REG = const(0x2C)
_SSD1681_READ_OTP = const(0x2D)
_SSD1681_READ_USERID = const(0x2E)
_SSD1681_READ_STATUS = const(0x2F)
_SSD1681_WRITE_WS_OTP = const(0x30)
_SSD1681_LOAD_WS_OTP = const(0x31)
_SSD1681_WRITE_LUT = const(0x32)
_SSD1681_CRC_CALC = const(0x34)
_SSD1681_CRC_READ = const(0x35)
_SSD1681_PROG_OTP = const(0x36)
_SSD1681_WRITE_DISPLAY_OPT = const(0x37)
_SSD1681_WRITE_USERID = const(0x38)
_SSD1681_OTP_PROGMODE = const(0x39)
_SSD1681_WRITE_BORDER = const(0x3C)
_SSD1681_END_OPTION = const(0x3F)
_SSD1681_SET_RAMXPOS = const(0x44)
_SSD1681_SET_RAMYPOS = const(0x45)
_SSD1681_AUTOWRITE_RED = const(0x46)
_SSD1681_AUTOWRITE_BW = const(0x47)
_SSD1681_SET_RAMXCOUNT = const(0x4E)
_SSD1681_SET_RAMYCOUNT = const(0x4F)
_SSD1681_NOP = const(0xFF)
_LUT_DATA = b'\x02\x02\x01\x11\x12\x12""fiiYX\x99\x99\x88\x00\x00\x00\x00\xf8\xb4\x13Q5QQ\x19\x01\x00' # pylint: disable=line-too-long
class Adafruit_SSD1681(Adafruit_EPD):
"""driver class for Adafruit SSD1681 ePaper display breakouts"""
# pylint: disable=too-many-arguments
def __init__(
self, width, height, spi, *, cs_pin, dc_pin, sramcs_pin, rst_pin, busy_pin
):
super(Adafruit_SSD1681, self).__init__(
width, height, spi, cs_pin, dc_pin, sramcs_pin, rst_pin, busy_pin
)
if height % 8 != 0:
height += 8 - height % 8
self._height = height
self._buffer1_size = int(width * height / 8)
if sramcs_pin:
self._buffer1 = self.sram.get_view(0)
else:
self._buffer1 = bytearray((width * height) // 8)
self._framebuf1 = adafruit_framebuf.FrameBuffer(
self._buffer1, width, height, buf_format=adafruit_framebuf.MHMSB
)
self.set_black_buffer(0, True)
self.set_color_buffer(0, True)
# pylint: enable=too-many-arguments
def begin(self, reset=True):
"""Begin communication with the display and set basic settings"""
if reset:
self.hardware_reset()
self.power_down()
def busy_wait(self):
"""Wait for display to be done with current task, either by polling the
busy pin, or pausing"""
if self._busy:
while self._busy.value:
time.sleep(0.01)
else:
time.sleep(0.5)
def power_up(self):
"""Power up the display in preparation for writing RAM and updating"""
self.hardware_reset()
self.busy_wait()
self.command(_SSD1681_SW_RESET)
self.busy_wait()
# driver output control
self.command(
_SSD1681_DRIVER_CONTROL,
bytearray([self._width - 1, (self._width - 1) >> 8, 0x00]),
)
# data entry mode
self.command(_SSD1681_DATA_MODE, bytearray([0x03]))
# Set ram X start/end postion
self.command(_SSD1681_SET_RAMXPOS, bytearray([0x00, self._height // 8 - 1]))
# Set ram Y start/end postion
self.command(
_SSD1681_SET_RAMYPOS,
bytearray([0, 0, self._height - 1, (self._height - 1) >> 8]),
)
# Set border waveform
self.command(_SSD1681_WRITE_BORDER, bytearray([0x05]))
# Set temperature control
self.command(_SSD1681_TEMP_CONTROL, bytearray([0x80]))
self.busy_wait()
def power_down(self):
"""Power down the display - required when not actively displaying!"""
self.command(_SSD1681_DEEP_SLEEP, bytearray([0x01]))
time.sleep(0.1)
def update(self):
"""Update the display from internal memory"""
self.command(_SSD1681_DISP_CTRL2, bytearray([0xF7]))
self.command(_SSD1681_MASTER_ACTIVATE)
self.busy_wait()
if not self._busy:
time.sleep(3) # wait 3 seconds
def write_ram(self, index):
"""Send the one byte command for starting the RAM write process. Returns
the byte read at the same time over SPI. index is the RAM buffer, can be
0 or 1 for tri-color displays."""
if index == 0:
return self.command(_SSD1681_WRITE_BWRAM, end=False)
raise RuntimeError("RAM index must be 0")
def set_ram_address(self, x, y): # pylint: disable=unused-argument, no-self-use
"""Set the RAM address location, not used on this chipset but required by
the superclass"""
# Set RAM X address counter
self.command(_SSD1681_SET_RAMXCOUNT, bytearray([x]))
# Set RAM Y address counter
self.command(_SSD1681_SET_RAMYCOUNT, bytearray([y >> 8, y]))

View file

@ -2,7 +2,8 @@
import os
import sys
sys.path.insert(0, os.path.abspath('..'))
sys.path.insert(0, os.path.abspath(".."))
# -- General configuration ------------------------------------------------
@ -10,10 +11,10 @@ sys.path.insert(0, os.path.abspath('..'))
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
'sphinx.ext.autodoc',
'sphinx.ext.intersphinx',
'sphinx.ext.napoleon',
'sphinx.ext.todo',
"sphinx.ext.autodoc",
"sphinx.ext.intersphinx",
"sphinx.ext.napoleon",
"sphinx.ext.todo",
]
# Uncomment the below if you use native CircuitPython modules such as
@ -22,29 +23,40 @@ extensions = [
# autodoc_mock_imports = ["digitalio", "busio", "micropython"]
intersphinx_mapping = {'python': ('https://docs.python.org/3.4', None),'BusDevice': ('https://circuitpython.readthedocs.io/projects/busdevice/en/latest/', None),'Register': ('https://circuitpython.readthedocs.io/projects/register/en/latest/', None),'CircuitPython': ('https://circuitpython.readthedocs.io/en/latest/', None)}
intersphinx_mapping = {
"python": ("https://docs.python.org/3.4", None),
"BusDevice": (
"https://circuitpython.readthedocs.io/projects/busdevice/en/latest/",
None,
),
"Register": (
"https://circuitpython.readthedocs.io/projects/register/en/latest/",
None,
),
"CircuitPython": ("https://circuitpython.readthedocs.io/en/latest/", None),
}
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
templates_path = ["_templates"]
source_suffix = '.rst'
source_suffix = ".rst"
# The master toctree document.
master_doc = 'index'
master_doc = "index"
# General information about the project.
project = u'Adafruit EPD Library'
copyright = u'2018 Dean Miller'
author = u'Dean Miller'
project = "Adafruit EPD Library"
copyright = "2018 Dean Miller"
author = "Dean Miller"
# 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'
version = "1.0"
# The full version, including alpha/beta/rc tags.
release = u'1.0'
release = "1.0"
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
@ -56,7 +68,7 @@ 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', '.env', 'CODE_OF_CONDUCT.md']
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store", ".env", "CODE_OF_CONDUCT.md"]
# The reST default role (used for this markup: `text`) to use for all
# documents.
@ -68,7 +80,7 @@ default_role = "any"
add_function_parentheses = True
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
pygments_style = "sphinx"
# If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos = False
@ -83,32 +95,33 @@ napoleon_numpy_docstring = False
# 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'
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(), '.']
html_theme = "sphinx_rtd_theme"
html_theme_path = [sphinx_rtd_theme.get_html_theme_path(), "."]
except:
html_theme = 'default'
html_theme_path = ['.']
html_theme = "default"
html_theme_path = ["."]
else:
html_theme_path = ['.']
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']
html_static_path = ["_static"]
# The name of an image file (relative to this directory) to use as a favicon of
# the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#
html_favicon = '_static/favicon.ico'
html_favicon = "_static/favicon.ico"
# Output file base name for HTML help builder.
htmlhelp_basename = 'AdafruitEpdLibrarydoc'
htmlhelp_basename = "AdafruitEpdLibrarydoc"
# -- Options for LaTeX output ---------------------------------------------
@ -116,15 +129,12 @@ 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',
@ -134,8 +144,13 @@ latex_elements = {
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
(master_doc, 'AdafruitEPDLibrary.tex', u'AdafruitEPD Library Documentation',
author, 'manual'),
(
master_doc,
"AdafruitEPDLibrary.tex",
"AdafruitEPD Library Documentation",
author,
"manual",
),
]
# -- Options for manual page output ---------------------------------------
@ -143,8 +158,13 @@ latex_documents = [
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
(master_doc, 'AdafruitEPDlibrary', u'Adafruit EPD Library Documentation',
[author], 1)
(
master_doc,
"AdafruitEPDlibrary",
"Adafruit EPD Library Documentation",
[author],
1,
)
]
# -- Options for Texinfo output -------------------------------------------
@ -153,7 +173,13 @@ man_pages = [
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
(master_doc, 'AdafruitEPDLibrary', u'Adafruit EPD Library Documentation',
author, 'AdafruitEPDLibrary', 'One line description of project.',
'Miscellaneous'),
(
master_doc,
"AdafruitEPDLibrary",
"Adafruit EPD Library Documentation",
author,
"AdafruitEPDLibrary",
"One line description of project.",
"Miscellaneous",
),
]

View file

@ -3,22 +3,47 @@ import busio
import board
from adafruit_epd.epd import Adafruit_EPD
from adafruit_epd.il0373 import Adafruit_IL0373
from adafruit_epd.il91874 import Adafruit_IL91874 # pylint: disable=unused-import
from adafruit_epd.il0398 import Adafruit_IL0398 # pylint: disable=unused-import
from adafruit_epd.ssd1608 import Adafruit_SSD1608 # pylint: disable=unused-import
from adafruit_epd.ssd1675 import Adafruit_SSD1675 # pylint: disable=unused-import
# create the spi device and pins we will need
spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO)
ecs = digitalio.DigitalInOut(board.D10)
dc = digitalio.DigitalInOut(board.D9)
srcs = digitalio.DigitalInOut(board.D8)
rst = digitalio.DigitalInOut(board.D7)
busy = digitalio.DigitalInOut(board.D6)
srcs = digitalio.DigitalInOut(board.D7) # can be None to use internal memory
rst = digitalio.DigitalInOut(board.D11) # can be None to not use this pin
busy = digitalio.DigitalInOut(board.D12) # can be None to not use this pin
# give them all to our driver
display = Adafruit_IL0373(152, 152, rst, dc, busy, srcs, ecs, spi)
print("Creating display")
# display = Adafruit_SSD1608(200, 200, spi, # 1.54" HD mono display
# display = Adafruit_SSD1675(122, 250, spi, # 2.13" HD mono display
# display = Adafruit_IL91874(176, 264, spi, # 2.7" Tri-color display
# display = Adafruit_IL0373(152, 152, spi, # 1.54" Tri-color display
# display = Adafruit_IL0373(128, 296, spi, # 2.9" Tri-color display
# display = Adafruit_IL0398(400, 300, spi, # 4.2" Tri-color display
display = Adafruit_IL0373(
104,
212,
spi, # 2.13" Tri-color display
cs_pin=ecs,
dc_pin=dc,
sramcs_pin=srcs,
rst_pin=rst,
busy_pin=busy,
)
FILENAME = "blinka.bmp"
# IF YOU HAVE A FLEXIBLE DISPLAY (2.13" or 2.9") uncomment these lines!
# display.set_black_buffer(1, False)
# display.set_color_buffer(1, False)
display.rotation = 0
FILENAME = "blinka154mono.bmp"
# clear the buffer
display.clear_buffer()
def read_le(s):
# as of this writting, int.from_bytes does not have LE support, DIY!
@ -29,14 +54,21 @@ def read_le(s):
shift += 8
return result
class BMPError(Exception):
pass
def display_bitmap(epd, filename): # pylint: disable=too-many-locals, too-many-branches
try:
with open("/" + FILENAME, "rb") as f:
f = open("/" + filename, "rb")
except OSError:
print("Couldn't open file")
return
print("File opened")
if f.read(2) != b'BM': # check signature
try:
if f.read(2) != b"BM": # check signature
raise BMPError("Not BitMap file")
bmpFileSize = read_le(f.read(4))
@ -48,8 +80,10 @@ try:
bmpHeight = read_le(f.read(4))
flip = True
print("Size: %d\nImage offset: %d\nHeader size: %d" %
(bmpFileSize, bmpImageoffset, headerSize))
print(
"Size: %d\nImage offset: %d\nHeader size: %d"
% (bmpFileSize, bmpImageoffset, headerSize)
)
print("Width: %d\nHeight: %d" % (bmpWidth, bmpHeight))
if read_le(f.read(2)) != 1:
@ -73,22 +107,25 @@ try:
# print ("seek to %d" % pos)
f.seek(pos)
rowdata = f.read(3 * bmpWidth)
for col in range(bmpWidth):
b, g, r = bytearray(f.read(3)) # BMP files store RGB in BGR
b, g, r = rowdata[3 * col : 3 * col + 3] # BMP files store RGB in BGR
if r < 0x80 and g < 0x80 and b < 0x80:
display.draw_pixel(row, col, Adafruit_EPD.BLACK)
epd.pixel(col, row, Adafruit_EPD.BLACK)
elif r >= 0x80 and g >= 0x80 and b >= 0x80:
display.draw_pixel(row, col, Adafruit_EPD.WHITE)
pass # epd.pixel(row, col, Adafruit_EPD.WHITE)
elif r >= 0x80:
display.draw_pixel(row, col, Adafruit_EPD.RED)
except OSError as e:
if e.args[0] == 28:
raise OSError("OS Error 28 0.25")
else:
raise OSError("OS Error 0.5")
epd.pixel(col, row, Adafruit_EPD.RED)
except OSError:
print("Couldn't read file")
except BMPError as e:
print("Failed to parse BMP: " + e.args[0])
finally:
f.close()
print("Finished drawing")
# clear the buffer
display.fill(Adafruit_EPD.WHITE)
display_bitmap(display, FILENAME)
display.display()

View file

@ -5,45 +5,73 @@ import board
from PIL import Image
from PIL import ImageDraw
from PIL import ImageFont
from adafruit_epd.il0373 import Adafruit_IL0373
from adafruit_epd.epd import Adafruit_EPD
from adafruit_epd.il0373 import Adafruit_IL0373 # pylint: disable=unused-import
from adafruit_epd.il91874 import Adafruit_IL91874 # pylint: disable=unused-import
from adafruit_epd.il0398 import Adafruit_IL0398 # pylint: disable=unused-import
from adafruit_epd.ssd1608 import Adafruit_SSD1608 # pylint: disable=unused-import
from adafruit_epd.ssd1675 import Adafruit_SSD1675 # pylint: disable=unused-import
from adafruit_epd.ssd1675b import Adafruit_SSD1675B # pylint: disable=unused-import
from adafruit_epd.ssd1681 import Adafruit_SSD1681 # pylint: disable=unused-import
# create the spi device and pins we will need
spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO)
while not spi.try_lock():
pass
spi.configure(baudrate=16000000)
spi.unlock()
ecs = digitalio.DigitalInOut(board.D22)
dc = digitalio.DigitalInOut(board.D13)
srcs = digitalio.DigitalInOut(board.D6)
rst = digitalio.DigitalInOut(board.D19)
busy = digitalio.DigitalInOut(board.D26)
# create the spi device and pins we will need
spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO)
ecs = digitalio.DigitalInOut(board.D4)
dc = digitalio.DigitalInOut(board.D5)
srcs = None
rst = digitalio.DigitalInOut(board.D6) # can be None to not use this pin
busy = digitalio.DigitalInOut(board.D7) # can be None to not use this pin
# give them all to our driver
display = Adafruit_IL0373(152, 152, rst, dc, busy, srcs, ecs, spi)
print("Creating display")
# display = Adafruit_SSD1608(200, 200, spi, # 1.54" HD mono display
# display = Adafruit_SSD1681(200, 200, spi, # 1.54" HD mono display (alt)
# display = Adafruit_SSD1675(122, 250, spi, # 2.13" HD mono display
# display = Adafruit_IL91874(176, 264, spi, # 2.7" Tri-color display
# display = Adafruit_IL0373(152, 152, spi, # 1.54" Tri-color display
# display = Adafruit_IL0373(128, 296, spi, # 2.9" Tri-color display
# display = Adafruit_IL0398(400, 300, spi, # 4.2" Tri-color display
# display = Adafruit_IL0373(104, 212, spi, # 2.13" Tri-color display
display = Adafruit_SSD1675B(
122,
250,
spi, # 2.13" HD mono display (rev B)
cs_pin=ecs,
dc_pin=dc,
sramcs_pin=srcs,
rst_pin=rst,
busy_pin=busy,
)
display.rotation = 3
# Create blank image for drawing.
# Make sure to create image with mode '1' for 1-bit color.
width = display.width
height = display.height
image = Image.new('RGB', (width, height))
image = Image.new("RGB", (width, height))
WHITE = (0xFF, 0xFF, 0xFF)
RED = (0xFF, 0x00, 0x00)
BLACK = (0x00, 0x00, 0x00)
# clear the buffer
display.clear_buffer()
display.fill(Adafruit_EPD.WHITE)
# Get drawing object to draw on image.
draw = ImageDraw.Draw(image)
# empty it
draw.rectangle((0, 0, width, height), fill=WHITE)
# Draw a white filled box to clear the image.
draw.rectangle((0,0,width,height), outline=BLACK, fill=WHITE)
# Draw an outline box
draw.rectangle((1, 1, width - 2, height - 2), outline=BLACK, fill=WHITE)
# Draw some shapes.
# First define some constants to allow easy resizing of shapes.
padding = 2
padding = 5
shape_width = 30
top = padding
bottom = height - padding
@ -56,8 +84,11 @@ x += shape_width+padding
draw.rectangle((x, top, x + shape_width, bottom), outline=RED, fill=BLACK)
x += shape_width + padding
# Draw a triangle.
draw.polygon([(x, bottom), (x+shape_width/2, top), (x+shape_width, bottom)],
outline=BLACK, fill=RED)
draw.polygon(
[(x, bottom), (x + shape_width / 2, top), (x + shape_width, bottom)],
outline=BLACK,
fill=RED,
)
x += shape_width + padding
# Draw an X.
draw.line((x, bottom, x + shape_width, top), fill=RED)
@ -65,7 +96,7 @@ draw.line((x, top, x+shape_width, bottom), fill=RED)
x += shape_width + padding
# Load default font.
font = ImageFont.load_default()
font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 20)
# Alternatively load a TTF font. Make sure the .ttf font
# file is in the same directory as the python script!
@ -73,8 +104,8 @@ font = ImageFont.load_default()
# font = ImageFont.truetype('Minecraftia.ttf', 8)
# Write two lines of text.
draw.text((x, top), 'Hello', font=font, fill=RED)
draw.text((x, top+20), 'World!', font=font, fill=RED)
draw.text((x, top), "Hello", font=font, fill=RED)
draw.text((x, top + 20), "World!", font=font, fill=RED)
# Display image.
display.image(image)

110
examples/epd_bonnet.py Normal file
View file

@ -0,0 +1,110 @@
import time
import busio
import board
from digitalio import DigitalInOut, Direction
from PIL import Image
from PIL import ImageDraw
from PIL import ImageFont
from adafruit_epd.epd import Adafruit_EPD
from adafruit_epd.ssd1675b import Adafruit_SSD1675B # pylint: disable=unused-import
# create two buttons
switch1 = DigitalInOut(board.D6)
switch2 = DigitalInOut(board.D5)
switch1.direction = Direction.INPUT
switch2.direction = Direction.INPUT
# create the spi device and pins we will need
spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO)
ecs = DigitalInOut(board.D8)
dc = DigitalInOut(board.D22)
rst = DigitalInOut(board.D27)
busy = DigitalInOut(board.D17)
# give them all to our driver
display = Adafruit_SSD1675B(
122,
250,
spi, # 2.13" HD mono display (rev B)
cs_pin=ecs,
dc_pin=dc,
sramcs_pin=None,
rst_pin=rst,
busy_pin=busy,
)
display.rotation = 1
# Create blank image for drawing.
# Make sure to create image with mode '1' for 1-bit color.
width = display.width
height = display.height
image = Image.new("RGB", (width, height))
WHITE = (0xFF, 0xFF, 0xFF)
BLACK = (0x00, 0x00, 0x00)
# clear the buffer
display.fill(Adafruit_EPD.WHITE)
# clear it out
display.display()
# Get drawing object to draw on image.
draw = ImageDraw.Draw(image)
# empty it
draw.rectangle((0, 0, width, height), fill=WHITE)
# Draw an outline box
draw.rectangle((1, 1, width - 2, height - 2), outline=BLACK, fill=WHITE)
# Draw some shapes.
# First define some constants to allow easy resizing of shapes.
padding = 5
shape_width = 30
top = padding
bottom = height - padding
# Move left to right keeping track of the current x position for drawing shapes.
x = padding
# Draw an ellipse.
draw.ellipse((x, top, x + shape_width, bottom), outline=BLACK, fill=WHITE)
x += shape_width + padding
# Draw a rectangle.
draw.rectangle((x, top, x + shape_width, bottom), outline=WHITE, fill=BLACK)
x += shape_width + padding
# Draw a triangle.
draw.polygon(
[(x, bottom), (x + shape_width / 2, top), (x + shape_width, bottom)],
outline=BLACK,
fill=WHITE,
)
x += shape_width + padding
# Draw an X.
draw.line((x, bottom, x + shape_width, top), fill=BLACK)
draw.line((x, top, x + shape_width, bottom), fill=BLACK)
x += shape_width + padding
# Load default font.
font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 20)
# Alternatively load a TTF font. Make sure the .ttf font
# file is in the same directory as the python script!
# Some other nice fonts to try: http://www.dafont.com/bitmap.php
# font = ImageFont.truetype('Minecraftia.ttf', 8)
# Write two lines of text.
draw.text((x, top), "Hello", font=font, fill=BLACK)
draw.text((x, top + 20), "World!", font=font, fill=BLACK)
while True:
if not switch1.value:
print("Switch 1")
display.image(image)
display.display()
while not switch1.value:
time.sleep(0.01)
if not switch2.value:
print("Switch 2")
display.fill(Adafruit_EPD.WHITE)
display.display()
while not switch2.value:
time.sleep(0.01)
time.sleep(0.01)

View file

@ -0,0 +1,90 @@
"""
ePaper Display Shapes and Text demo using the Pillow Library.
Written by Melissa LeBlanc-Williams for Adafruit Industries
"""
import digitalio
import busio
import board
from PIL import Image, ImageDraw, ImageFont
from adafruit_epd.il0373 import Adafruit_IL0373
from adafruit_epd.il91874 import Adafruit_IL91874 # pylint: disable=unused-import
from adafruit_epd.il0398 import Adafruit_IL0398 # pylint: disable=unused-import
from adafruit_epd.ssd1608 import Adafruit_SSD1608 # pylint: disable=unused-import
from adafruit_epd.ssd1675 import Adafruit_SSD1675 # pylint: disable=unused-import
# First define some color constants
WHITE = (0xFF, 0xFF, 0xFF)
BLACK = (0x00, 0x00, 0x00)
RED = (0xFF, 0x00, 0x00)
# Next define some constants to allow easy resizing of shapes and colors
BORDER = 20
FONTSIZE = 24
BACKGROUND_COLOR = BLACK
FOREGROUND_COLOR = WHITE
TEXT_COLOR = RED
# create the spi device and pins we will need
spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO)
ecs = digitalio.DigitalInOut(board.CE0)
dc = digitalio.DigitalInOut(board.D22)
srcs = None
rst = digitalio.DigitalInOut(board.D27)
busy = digitalio.DigitalInOut(board.D17)
# give them all to our driver
# display = Adafruit_SSD1608(200, 200, # 1.54" HD mono display
# display = Adafruit_SSD1675(122, 250, # 2.13" HD mono display
# display = Adafruit_IL91874(176, 264, # 2.7" Tri-color display
# display = Adafruit_IL0373(152, 152, # 1.54" Tri-color display
# display = Adafruit_IL0373(128, 296, # 2.9" Tri-color display
# display = Adafruit_IL0398(400, 300, # 4.2" Tri-color display
display = Adafruit_IL0373(
104,
212, # 2.13" Tri-color display
spi,
cs_pin=ecs,
dc_pin=dc,
sramcs_pin=srcs,
rst_pin=rst,
busy_pin=busy,
)
# IF YOU HAVE A FLEXIBLE DISPLAY (2.13" or 2.9") uncomment these lines!
# display.set_black_buffer(1, False)
# display.set_color_buffer(1, False)
display.rotation = 1
image = Image.new("RGB", (display.width, display.height))
# Get drawing object to draw on image.
draw = ImageDraw.Draw(image)
# Draw a filled box as the background
draw.rectangle((0, 0, display.width, display.height), fill=BACKGROUND_COLOR)
# Draw a smaller inner foreground rectangle
draw.rectangle(
(BORDER, BORDER, display.width - BORDER - 1, display.height - BORDER - 1),
fill=FOREGROUND_COLOR,
)
# Load a TTF Font
font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", FONTSIZE)
# Draw Some Text
text = "Hello World!"
(font_width, font_height) = font.getsize(text)
draw.text(
(display.width // 2 - font_width // 2, display.height // 2 - font_height // 2),
text,
font=font,
fill=TEXT_COLOR,
)
# Display image.
display.image(image)
display.display()

View file

@ -0,0 +1,72 @@
"""
Image resizing and drawing using the Pillow Library. For the image, check out the
associated Adafruit Learn guide at:
https://learn.adafruit.com/adafruit-eink-display-breakouts/python-code
Written by Melissa LeBlanc-Williams for Adafruit Industries
"""
import digitalio
import busio
import board
from PIL import Image
from adafruit_epd.il0373 import Adafruit_IL0373
from adafruit_epd.il91874 import Adafruit_IL91874 # pylint: disable=unused-import
from adafruit_epd.il0398 import Adafruit_IL0398 # pylint: disable=unused-import
from adafruit_epd.ssd1608 import Adafruit_SSD1608 # pylint: disable=unused-import
from adafruit_epd.ssd1675 import Adafruit_SSD1675 # pylint: disable=unused-import
# create the spi device and pins we will need
spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO)
ecs = digitalio.DigitalInOut(board.CE0)
dc = digitalio.DigitalInOut(board.D22)
srcs = None
rst = digitalio.DigitalInOut(board.D27)
busy = digitalio.DigitalInOut(board.D17)
# give them all to our driver
# display = Adafruit_SSD1608(200, 200, # 1.54" HD mono display
# display = Adafruit_SSD1675(122, 250, # 2.13" HD mono display
# display = Adafruit_IL91874(176, 264, # 2.7" Tri-color display
# display = Adafruit_IL0373(152, 152, # 1.54" Tri-color display
# display = Adafruit_IL0373(128, 296, # 2.9" Tri-color display
# display = Adafruit_IL0398(400, 300, # 4.2" Tri-color display
display = Adafruit_IL0373(
104,
212, # 2.13" Tri-color display
spi,
cs_pin=ecs,
dc_pin=dc,
sramcs_pin=srcs,
rst_pin=rst,
busy_pin=busy,
)
# IF YOU HAVE A FLEXIBLE DISPLAY (2.13" or 2.9") uncomment these lines!
# display.set_black_buffer(1, False)
# display.set_color_buffer(1, False)
display.rotation = 1
image = Image.open("blinka.png")
# Scale the image to the smaller screen dimension
image_ratio = image.width / image.height
screen_ratio = display.width / display.height
if screen_ratio < image_ratio:
scaled_width = image.width * display.height // image.height
scaled_height = display.height
else:
scaled_width = display.width
scaled_height = image.height * display.width // image.width
image = image.resize((scaled_width, scaled_height), Image.BICUBIC)
# Crop and center the image
x = scaled_width // 2 - display.width // 2
y = scaled_height // 2 - display.height // 2
image = image.crop((x, y, x + display.width, y + display.height))
# Display image.
display.image(image)
display.display()

View file

@ -0,0 +1,69 @@
# EInk Shield test
import time
import digitalio
import busio
import board
from analogio import AnalogIn
from adafruit_epd.epd import Adafruit_EPD
from adafruit_epd.il91874 import Adafruit_IL91874
# create the spi device and pins we will need
spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO)
ecs = digitalio.DigitalInOut(board.D10)
dc = digitalio.DigitalInOut(board.D9)
srcs = digitalio.DigitalInOut(board.D8) # can be None to use internal memory
# give them all to our driver
print("Creating display")
display = Adafruit_IL91874(
176,
264,
spi, # 2.7" Tri-color display
cs_pin=ecs,
dc_pin=dc,
sramcs_pin=srcs,
rst_pin=None,
busy_pin=None,
)
display.rotation = 1
def read_buttons():
with AnalogIn(board.A3) as ain:
reading = ain.value / 65535
if reading > 0.75:
return None
if reading > 0.4:
return 4
if reading > 0.25:
return 3
if reading > 0.13:
return 2
return 1
while True:
button = read_buttons()
if not button:
continue
print("Button #%d pressed" % button)
if button == 1:
print("Clear buffer")
display.fill(Adafruit_EPD.WHITE)
display.display()
if button == 2:
print("Draw Rectangles")
display.fill_rect(5, 5, 10, 10, Adafruit_EPD.RED)
display.rect(0, 0, 20, 30, Adafruit_EPD.BLACK)
display.display()
if button == 3:
print("Draw lines")
display.line(0, 0, display.width - 1, display.height - 1, Adafruit_EPD.BLACK)
display.line(0, display.height - 1, display.width - 1, 0, Adafruit_EPD.RED)
display.display()
if button == 4:
print("Draw text")
display.text("hello world", 25, 10, Adafruit_EPD.BLACK)
display.display()
time.sleep(0.01)

View file

@ -3,31 +3,57 @@ import busio
import board
from adafruit_epd.epd import Adafruit_EPD
from adafruit_epd.il0373 import Adafruit_IL0373
from adafruit_epd.il91874 import Adafruit_IL91874 # pylint: disable=unused-import
from adafruit_epd.il0398 import Adafruit_IL0398 # pylint: disable=unused-import
from adafruit_epd.ssd1608 import Adafruit_SSD1608 # pylint: disable=unused-import
from adafruit_epd.ssd1675 import Adafruit_SSD1675 # pylint: disable=unused-import
# create the spi device and pins we will need
spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO)
ecs = digitalio.DigitalInOut(board.D10)
dc = digitalio.DigitalInOut(board.D9)
srcs = digitalio.DigitalInOut(board.D8)
rst = digitalio.DigitalInOut(board.D7)
busy = digitalio.DigitalInOut(board.D6)
ecs = digitalio.DigitalInOut(board.D12)
dc = digitalio.DigitalInOut(board.D11)
srcs = digitalio.DigitalInOut(board.D10) # can be None to use internal memory
rst = digitalio.DigitalInOut(board.D9) # can be None to not use this pin
busy = digitalio.DigitalInOut(board.D5) # can be None to not use this pin
# give them all to our driver
display = Adafruit_IL0373(152, 152, rst, dc, busy, srcs, ecs, spi)
print("Creating display")
# display = Adafruit_SSD1608(200, 200, spi, # 1.54" HD mono display
# display = Adafruit_SSD1675(122, 250, spi, # 2.13" HD mono display
# display = Adafruit_IL91874(176, 264, spi, # 2.7" Tri-color display
# display = Adafruit_IL0373(152, 152, spi, # 1.54" Tri-color display
# display = Adafruit_IL0373(128, 296, spi, # 2.9" Tri-color display
# display = Adafruit_IL0398(400, 300, spi, # 4.2" Tri-color display
display = Adafruit_IL0373(
104,
212,
spi, # 2.13" Tri-color display
cs_pin=ecs,
dc_pin=dc,
sramcs_pin=srcs,
rst_pin=rst,
busy_pin=busy,
)
# IF YOU HAVE A FLEXIBLE DISPLAY (2.13" or 2.9") uncomment these lines!
# display.set_black_buffer(1, False)
# display.set_color_buffer(1, False)
display.rotation = 1
# clear the buffer
display.clear_buffer()
print("Clear buffer")
display.fill(Adafruit_EPD.WHITE)
display.pixel(10, 100, Adafruit_EPD.BLACK)
r_width = 5
r_pos = display.height
print("Draw Rectangles")
display.fill_rect(5, 5, 10, 10, Adafruit_EPD.RED)
display.rect(0, 0, 20, 30, Adafruit_EPD.BLACK)
color = Adafruit_EPD.BLACK
while r_pos > display.height/2:
if r_pos < display.height - 50:
color = Adafruit_EPD.RED
display.rect(display.width - r_pos, display.height - r_pos,
display.width - 2*(display.width - r_pos),
display.height - 2*(display.height - r_pos), color)
r_pos = r_pos - r_width
print("Draw lines")
display.line(0, 0, display.width - 1, display.height - 1, Adafruit_EPD.BLACK)
display.line(0, display.height - 1, display.width - 1, 0, Adafruit_EPD.RED)
print("Draw text")
display.text("hello world", 25, 10, Adafruit_EPD.BLACK)
display.display()

View file

@ -1,2 +1,3 @@
Adafruit-Blinka
adafruit-circuitpython-busdevice
adafruit-circuitpython-framebuf

View file

@ -7,6 +7,7 @@ https://github.com/pypa/sampleproject
# Always prefer setuptools over distutils
from setuptools import setup, find_packages
# To use a consistent encoding
from codecs import open
from os import path
@ -14,47 +15,42 @@ from os import path
here = path.abspath(path.dirname(__file__))
# Get the long description from the README file
with open(path.join(here, 'README.rst'), encoding='utf-8') as f:
with open(path.join(here, "README.rst"), encoding="utf-8") as f:
long_description = f.read()
setup(
name='adafruit-circuitpython-epd',
name="adafruit-circuitpython-epd",
use_scm_version=True,
setup_requires=['setuptools_scm'],
description='CircuitPython library for EPD e-ink displays.',
setup_requires=["setuptools_scm"],
description="CircuitPython library for EPD e-ink displays.",
long_description=long_description,
long_description_content_type='text/x-rst',
long_description_content_type="text/x-rst",
# The project's main homepage.
url='https://github.com/adafruit/Adafruit_CircuitPython_EPD',
url="https://github.com/adafruit/Adafruit_CircuitPython_EPD",
# Author details
author='Adafruit Industries',
author_email='circuitpython@adafruit.com',
install_requires=['Adafruit-Blinka', 'adafruit-circuitpython-busdevice'],
author="Adafruit Industries",
author_email="circuitpython@adafruit.com",
install_requires=[
"Adafruit-Blinka",
"adafruit-circuitpython-busdevice",
"adafruit-circuitpython-framebuf",
],
# Choose your license
license='MIT',
license="MIT",
# See https://pypi.python.org/pypi?%3Aaction=list_classifiers
classifiers=[
'Development Status :: 3 - Alpha',
'Intended Audience :: Developers',
'Topic :: Software Development :: Libraries',
'Topic :: System :: Hardware',
'License :: OSI Approved :: MIT License',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
"Development Status :: 3 - Alpha",
"Intended Audience :: Developers",
"Topic :: Software Development :: Libraries",
"Topic :: System :: Hardware",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.4",
"Programming Language :: Python :: 3.5",
],
# What does your project relate to?
keywords='adafruit eink e-ink display epd hardware micropython circuitpython',
keywords="adafruit eink e-ink display epd hardware micropython circuitpython",
# You can just specify the packages manually here if your project is
# simple. Or you can use find_packages().
packages=['adafruit_epd'],
packages=["adafruit_epd"],
)