mirror of
https://github.com/micropython/micropython.git
synced 2025-12-26 23:00:16 +01:00
Compare commits
470 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c8d31585a0 | ||
|
|
1e3a7c4ac5 | ||
|
|
48feb8ac6e | ||
|
|
57226a2b7f | ||
|
|
ad3724e0bc | ||
|
|
7d0d7215d2 | ||
|
|
6caca3259f | ||
|
|
2750a7b38e | ||
|
|
a3edeb9ea5 | ||
|
|
e9404e5f5f | ||
|
|
453c2e8f55 | ||
|
|
799ccdc789 | ||
|
|
06234a6115 | ||
|
|
36f97f19b4 | ||
|
|
f059563507 | ||
|
|
a97284423e | ||
|
|
824f5c5a32 | ||
|
|
ed878275b0 | ||
|
|
34d0b3f85c | ||
|
|
6a4c6fc023 | ||
|
|
b0a15aa735 | ||
|
|
8298251215 | ||
|
|
e42186d356 | ||
|
|
f2f8ae110b | ||
|
|
11ab807d76 | ||
|
|
e93c1ca5da | ||
|
|
f17f3314d0 | ||
|
|
1a01ed0d2a | ||
|
|
b6a544b917 | ||
|
|
06ee5e947f | ||
|
|
998578a2b8 | ||
|
|
cdbeee0c50 | ||
|
|
4021b1e1b8 | ||
|
|
af8d791bd0 | ||
|
|
11fc6553e8 | ||
|
|
31101d91ce | ||
|
|
deaa57acf3 | ||
|
|
db4e009217 | ||
|
|
f274561e16 | ||
|
|
d02f3a57f4 | ||
|
|
eaef6b5324 | ||
|
|
9e1dec1818 | ||
|
|
39968aaaff | ||
|
|
6dff3df501 | ||
|
|
8bb7d958f1 | ||
|
|
df3e5d2b2f | ||
|
|
48874942f0 | ||
|
|
5e22afce41 | ||
|
|
e49153fb98 | ||
|
|
7f0e563de3 | ||
|
|
7dc2345715 | ||
|
|
93c76d2b06 | ||
|
|
1b76f88e7a | ||
|
|
aa7828f822 | ||
|
|
7e3b21ec54 | ||
|
|
b3a65791b1 | ||
|
|
ac70119779 | ||
|
|
a181340ad8 | ||
|
|
5a699a7017 | ||
|
|
244b02f744 | ||
|
|
cbc0bf6fec | ||
|
|
2ea52cb045 | ||
|
|
7df9f313c6 | ||
|
|
9ad5032164 | ||
|
|
9d9efc0c5a | ||
|
|
cff9f02cd7 | ||
|
|
fa5ac678fc | ||
|
|
3dabaae47d | ||
|
|
d22a04d9c4 | ||
|
|
49e140488d | ||
|
|
3b3612c65b | ||
|
|
dc43508cc2 | ||
|
|
016dba0e98 | ||
|
|
503089ea9d | ||
|
|
23a568240d | ||
|
|
a2bfcbe029 | ||
|
|
e3d29996b3 | ||
|
|
75af908c0e | ||
|
|
06d0083468 | ||
|
|
620c4c32bf | ||
|
|
3a0a771730 | ||
|
|
0363e1d7b5 | ||
|
|
00c1fc6d77 | ||
|
|
82af4d6749 | ||
|
|
dffa383b06 | ||
|
|
9fdba0e09c | ||
|
|
056da75a8a | ||
|
|
0bb3c7d3b7 | ||
|
|
c08f50bcf7 | ||
|
|
7f19b1c3eb | ||
|
|
b89ac9db78 | ||
|
|
b1537a5752 | ||
|
|
bcf60b43ee | ||
|
|
7a9c183c20 | ||
|
|
cecf6bee97 | ||
|
|
161e9f4115 | ||
|
|
52784bf595 | ||
|
|
addd1d3db1 | ||
|
|
99d62c4def | ||
|
|
8f3cf6e6a8 | ||
|
|
eb239b8398 | ||
|
|
03de5a13cf | ||
|
|
cd20027f56 | ||
|
|
1f433c719b | ||
|
|
bd925b59c3 | ||
|
|
b0eb0d6153 | ||
|
|
b932b2dd1f | ||
|
|
9f1e395c16 | ||
|
|
bd87375202 | ||
|
|
5deedd6685 | ||
|
|
d4a5ca5056 | ||
|
|
077dbf4a86 | ||
|
|
d434ce3fca | ||
|
|
a22a67661a | ||
|
|
5bb28c7f10 | ||
|
|
a0d97fe408 | ||
|
|
8de270b4fc | ||
|
|
eca1408f16 | ||
|
|
3be4f886ce | ||
|
|
9f72a14920 | ||
|
|
b04d4a5b13 | ||
|
|
fa6f774b2c | ||
|
|
6aea34ad89 | ||
|
|
17b4509564 | ||
|
|
3c582bc7cb | ||
|
|
216a711cd4 | ||
|
|
6cf2a3966e | ||
|
|
0d10517a45 | ||
|
|
d5495966ce | ||
|
|
3dea8c9e92 | ||
|
|
6ab2c5e6cc | ||
|
|
53bfcc9e84 | ||
|
|
219245e10f | ||
|
|
7165fbd8f4 | ||
|
|
b32c01b748 | ||
|
|
443cc0114d | ||
|
|
2c7716fed0 | ||
|
|
dd4135aeaf | ||
|
|
0c595fa094 | ||
|
|
c71edaed73 | ||
|
|
88ca7ff565 | ||
|
|
7385b018ed | ||
|
|
897129a7ff | ||
|
|
290daa15d9 | ||
|
|
4fb72fe624 | ||
|
|
670376c5cb | ||
|
|
dcf14c1b18 | ||
|
|
791b65f4b2 | ||
|
|
f65e4f0b8f | ||
|
|
71fec076dc | ||
|
|
38b54b65d4 | ||
|
|
3f0c1c2452 | ||
|
|
f040685b0c | ||
|
|
67d52d8cb9 | ||
|
|
d46de80162 | ||
|
|
7b901d6fb7 | ||
|
|
d8a4d9d67c | ||
|
|
4c63986101 | ||
|
|
9cc8ec843e | ||
|
|
6d310a5552 | ||
|
|
eeb9d99333 | ||
|
|
7df9291b6c | ||
|
|
e97df97600 | ||
|
|
46ab042230 | ||
|
|
ec078af985 | ||
|
|
1f69b16d3f | ||
|
|
9310dad15d | ||
|
|
c4a69c75a5 | ||
|
|
6c79980b0e | ||
|
|
79ec869f95 | ||
|
|
c528489eee | ||
|
|
080e4d44f3 | ||
|
|
5f0ecb72c2 | ||
|
|
7f5a541b84 | ||
|
|
b84e1231c9 | ||
|
|
9ea2882317 | ||
|
|
93c4a6a3f7 | ||
|
|
b0a46900de | ||
|
|
7ea3fa2641 | ||
|
|
21c719bd0a | ||
|
|
34e0198436 | ||
|
|
cc7c311b5e | ||
|
|
3f5fe6269e | ||
|
|
bb954d80a4 | ||
|
|
fbddea929d | ||
|
|
60592fd23c | ||
|
|
b85bcd671c | ||
|
|
e60835bac5 | ||
|
|
4874bde104 | ||
|
|
8dd5960ac0 | ||
|
|
5da0d29d3c | ||
|
|
adaf0d865c | ||
|
|
a5624bf381 | ||
|
|
4b3f1d712b | ||
|
|
3fe047f08f | ||
|
|
4ab3eef8d7 | ||
|
|
a2391b5a74 | ||
|
|
5bf1b4e9d9 | ||
|
|
d08c9d342f | ||
|
|
f28efa1971 | ||
|
|
8ae885a0c6 | ||
|
|
ee324c501e | ||
|
|
b9672bcbe8 | ||
|
|
2b7c4a1878 | ||
|
|
67a4813601 | ||
|
|
f84b341618 | ||
|
|
3fea1f014c | ||
|
|
0fd3d8d19f | ||
|
|
081c0648ec | ||
|
|
dd0e6ddfeb | ||
|
|
d14d4cdb8b | ||
|
|
a50b26e4b0 | ||
|
|
b236b1974b | ||
|
|
2f02960607 | ||
|
|
1ba516f475 | ||
|
|
06a1194300 | ||
|
|
d89de18f40 | ||
|
|
f3b19ef634 | ||
|
|
3611dcc260 | ||
|
|
763e04bba5 | ||
|
|
f3b5480be7 | ||
|
|
dab0f316d2 | ||
|
|
742d8bdbe4 | ||
|
|
b4be5a8f34 | ||
|
|
4a9542c0c0 | ||
|
|
9103cbe366 | ||
|
|
b88bf6c76b | ||
|
|
69768c97c0 | ||
|
|
e4d6a10dc9 | ||
|
|
2b882e9aca | ||
|
|
ef47a67cf4 | ||
|
|
9526e24234 | ||
|
|
e2ac8bb3f1 | ||
|
|
cac8dc3414 | ||
|
|
778729c597 | ||
|
|
b4df3e74e1 | ||
|
|
20da9064d7 | ||
|
|
dba40afa70 | ||
|
|
7ddd1a58f6 | ||
|
|
1708fe3cc7 | ||
|
|
61e2dfd97d | ||
|
|
1bc5cb4312 | ||
|
|
fedab995ee | ||
|
|
2d8740a4d1 | ||
|
|
47899a1ab8 | ||
|
|
8c6856d2e7 | ||
|
|
015774a04f | ||
|
|
4a33677c97 | ||
|
|
76c366df56 | ||
|
|
f7c4611523 | ||
|
|
fafd587514 | ||
|
|
a6864a13c7 | ||
|
|
c51c883cc8 | ||
|
|
41ec22632d | ||
|
|
b6bdf18deb | ||
|
|
b4790afdaf | ||
|
|
58f3861358 | ||
|
|
5f3bda422a | ||
|
|
f127bef3e4 | ||
|
|
f98bb2ddcb | ||
|
|
ce1c786297 | ||
|
|
49406b0ac6 | ||
|
|
9b64d1966b | ||
|
|
3be8b688c0 | ||
|
|
5863e15a23 | ||
|
|
0823c1baf8 | ||
|
|
9c04ef2a67 | ||
|
|
1f61fe07a2 | ||
|
|
bae62d9abe | ||
|
|
76dcaddc0f | ||
|
|
efc904c41d | ||
|
|
5c3a2f162e | ||
|
|
d1a366fdd4 | ||
|
|
c777b6950e | ||
|
|
0f8b1ba8a2 | ||
|
|
f2da6467a9 | ||
|
|
57c92d90b0 | ||
|
|
13c5a228c9 | ||
|
|
59a9509703 | ||
|
|
8e9b98e974 | ||
|
|
9fba618356 | ||
|
|
ed0a06a93f | ||
|
|
263aaa7030 | ||
|
|
8f8f699eb7 | ||
|
|
f4ee9f8853 | ||
|
|
581a59a456 | ||
|
|
531217a06b | ||
|
|
fea7fe45ea | ||
|
|
26295e04ff | ||
|
|
fe3cc5bb53 | ||
|
|
3b5affa0d1 | ||
|
|
24df30c133 | ||
|
|
fc73c9b4b2 | ||
|
|
5ffe1d8dc0 | ||
|
|
d29ca28288 | ||
|
|
b0e2106fb8 | ||
|
|
891479e62a | ||
|
|
9897bcaa73 | ||
|
|
a589fa3e0b | ||
|
|
d09b6b9aa1 | ||
|
|
78bc31e294 | ||
|
|
5af6184e72 | ||
|
|
c428367543 | ||
|
|
39799f7564 | ||
|
|
6562076454 | ||
|
|
5a5449d4eb | ||
|
|
253e1a6f67 | ||
|
|
d2d9dfcd40 | ||
|
|
c6983e3ce0 | ||
|
|
f2a21a2489 | ||
|
|
d076fae219 | ||
|
|
8e7dfea803 | ||
|
|
49dd532180 | ||
|
|
64c5a9435c | ||
|
|
567e7fcd12 | ||
|
|
244332df9f | ||
|
|
a6fc90f92a | ||
|
|
ed4ce196ed | ||
|
|
ff1c2b03a9 | ||
|
|
bb19e7b94b | ||
|
|
f003310dee | ||
|
|
ed6a1ada24 | ||
|
|
d2cc7c720b | ||
|
|
095e43a9a5 | ||
|
|
f6a8e84a25 | ||
|
|
675d1c9c60 | ||
|
|
41fceae559 | ||
|
|
b359cf2911 | ||
|
|
d5f42c9daf | ||
|
|
3c82d1d34b | ||
|
|
2196799051 | ||
|
|
1a0d3fd632 | ||
|
|
4aaa5adf9f | ||
|
|
9cf2949356 | ||
|
|
0be4a7712d | ||
|
|
c4a8004933 | ||
|
|
83e0ebabb4 | ||
|
|
8c50f93a41 | ||
|
|
9e1b61dedd | ||
|
|
af9889f99a | ||
|
|
dfb8144037 | ||
|
|
4e36dd570b | ||
|
|
5e01fb01b3 | ||
|
|
72ae3c72c7 | ||
|
|
8a15e0b1c7 | ||
|
|
b203c1774e | ||
|
|
2146cdab5e | ||
|
|
e4e4526954 | ||
|
|
3c9510d767 | ||
|
|
3372f69586 | ||
|
|
6d11918d49 | ||
|
|
5c73de0337 | ||
|
|
3e5534caf7 | ||
|
|
1bc2911174 | ||
|
|
d2cab0b7be | ||
|
|
8897dcb2a1 | ||
|
|
f84dda7111 | ||
|
|
a9923d190e | ||
|
|
919c54f750 | ||
|
|
1966745689 | ||
|
|
31ad1bb606 | ||
|
|
541e76fa45 | ||
|
|
f71f37e426 | ||
|
|
c2070d771a | ||
|
|
1563388001 | ||
|
|
56eb25f049 | ||
|
|
a4aaf82421 | ||
|
|
fdb411a8c5 | ||
|
|
8a0b6f561c | ||
|
|
e15fb33e10 | ||
|
|
cbef0dba2e | ||
|
|
e0d49b7e1b | ||
|
|
6de37864a2 | ||
|
|
ca59f5f208 | ||
|
|
5b9e7e29f6 | ||
|
|
a931c4eeec | ||
|
|
3d19adf9b3 | ||
|
|
d79342d33e | ||
|
|
ed500e4987 | ||
|
|
c16612ee87 | ||
|
|
7fb31479bf | ||
|
|
b67eb20ed0 | ||
|
|
4a27ad040e | ||
|
|
e33d2383d1 | ||
|
|
bf47b71b78 | ||
|
|
a621333a4c | ||
|
|
efb8aa0ef6 | ||
|
|
ce166e6b68 | ||
|
|
3eb532e974 | ||
|
|
8766bc02dc | ||
|
|
b4564841b6 | ||
|
|
0e4cae5212 | ||
|
|
88d3cd582e | ||
|
|
bc3912980a | ||
|
|
eb0e3bab1e | ||
|
|
4d22ade102 | ||
|
|
64ad838fde | ||
|
|
617bda27e9 | ||
|
|
aac9e8cfa3 | ||
|
|
99061d1dcb | ||
|
|
0dfe849413 | ||
|
|
2ec943284a | ||
|
|
460bceca39 | ||
|
|
afd4909a0f | ||
|
|
37b143ce9e | ||
|
|
61e77a4e88 | ||
|
|
58d9d85a56 | ||
|
|
ba2c503541 | ||
|
|
50fea19416 | ||
|
|
c8b80e4740 | ||
|
|
4f1b0292db | ||
|
|
abd5a57ea1 | ||
|
|
3990b1715d | ||
|
|
f039ac5bd7 | ||
|
|
64da62ec2e | ||
|
|
aa4ada943a | ||
|
|
01816068c8 | ||
|
|
a60b0263ba | ||
|
|
ade36806c8 | ||
|
|
8fac939889 | ||
|
|
6ead9f6f3d | ||
|
|
f2f761c0c3 | ||
|
|
243f8988be | ||
|
|
d1771bbae0 | ||
|
|
ed1c194ebf | ||
|
|
6af90b2972 | ||
|
|
16f324641f | ||
|
|
1a7e28d8b7 | ||
|
|
5a38694f55 | ||
|
|
25df419c67 | ||
|
|
0d221775f5 | ||
|
|
2dd21d9a68 | ||
|
|
614deb82c7 | ||
|
|
a53e0e59f3 | ||
|
|
c141584e1e | ||
|
|
77f0cd8027 | ||
|
|
4d4cfc2ee6 | ||
|
|
1e77e25675 | ||
|
|
e47c2ec64a | ||
|
|
9bdb82ef6b | ||
|
|
43473372e6 | ||
|
|
b652ee705b | ||
|
|
40214b9e26 | ||
|
|
918851e836 | ||
|
|
a1b442bc07 | ||
|
|
707cae7494 | ||
|
|
26b7d8a7be | ||
|
|
43963a8d97 | ||
|
|
68815901d4 | ||
|
|
93e353e384 | ||
|
|
04c27e5eaa | ||
|
|
c3f519adfe | ||
|
|
bd6622abe8 | ||
|
|
6aa7c805cc | ||
|
|
bcd0e9a7fa | ||
|
|
0a6f599cf2 | ||
|
|
780114e398 | ||
|
|
0b52228739 | ||
|
|
ad9b9c7621 | ||
|
|
be313ea215 | ||
|
|
20283aec10 | ||
|
|
e32d1e17bb | ||
|
|
dfe056df6f | ||
|
|
ee622cc1ed | ||
|
|
26d5e91bf3 | ||
|
|
3593d8e10c | ||
|
|
e9f3fb7662 | ||
|
|
9626662819 | ||
|
|
7711d87563 | ||
|
|
e3f0f31e07 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -32,6 +32,7 @@ tests/*.out
|
||||
# Python cache files
|
||||
######################
|
||||
__pycache__/
|
||||
*.pyc
|
||||
|
||||
# Customized Makefile/project overrides
|
||||
######################
|
||||
|
||||
@@ -12,7 +12,7 @@ before_script:
|
||||
- sudo add-apt-repository -y ppa:terry.guo/gcc-arm-embedded
|
||||
- sudo dpkg --add-architecture i386
|
||||
- sudo apt-get update -qq || true
|
||||
- sudo apt-get install -y python3 gcc-multilib pkg-config libffi-dev libffi-dev:i386 qemu-system mingw32
|
||||
- sudo apt-get install -y python3 gcc-multilib pkg-config libffi-dev libffi-dev:i386 qemu-system gcc-mingw-w64
|
||||
- sudo apt-get install -y --force-yes gcc-arm-none-eabi
|
||||
# For teensy build
|
||||
- sudo apt-get install realpath
|
||||
@@ -23,6 +23,7 @@ before_script:
|
||||
- python3 --version
|
||||
|
||||
script:
|
||||
- make -C mpy-cross
|
||||
- make -C minimal test
|
||||
- make -C unix deplibs
|
||||
- make -C unix
|
||||
@@ -35,7 +36,7 @@ script:
|
||||
- make -C teensy
|
||||
- make -C cc3200 BTARGET=application BTYPE=release
|
||||
- make -C cc3200 BTARGET=bootloader BTYPE=release
|
||||
- make -C windows CROSS_COMPILE=i586-mingw32msvc-
|
||||
- make -C windows CROSS_COMPILE=i686-w64-mingw32-
|
||||
|
||||
# run tests without coverage info
|
||||
#- (cd tests && MICROPY_CPYTHON3=python3.4 ./run-tests)
|
||||
@@ -46,6 +47,7 @@ script:
|
||||
- (cd tests && MICROPY_CPYTHON3=python3.4 MICROPY_MICROPYTHON=../unix/micropython_coverage ./run-tests)
|
||||
- (cd tests && MICROPY_CPYTHON3=python3.4 MICROPY_MICROPYTHON=../unix/micropython_coverage ./run-tests -d thread)
|
||||
- (cd tests && MICROPY_CPYTHON3=python3.4 MICROPY_MICROPYTHON=../unix/micropython_coverage ./run-tests --emit native)
|
||||
- (cd tests && MICROPY_CPYTHON3=python3.4 MICROPY_MICROPYTHON=../unix/micropython_coverage ./run-tests --via-mpy -d basics)
|
||||
|
||||
after_success:
|
||||
- (cd unix && coveralls --root .. --build-root . --gcov $(which gcov) --gcov-options '\-o build-coverage/' --include py --include extmod)
|
||||
|
||||
@@ -1,12 +1,8 @@
|
||||
[![Build Status][travis-img]][travis-repo] [![Coverage Status][coveralls-img]][coveralls-repo] [![Issue Stats][istats-pr-img]][istats-pr-repo] [![Issue Stats][istats-issue-img]][istats-issue-repo]
|
||||
[![Build Status][travis-img]][travis-repo] [![Coverage Status][coveralls-img]][coveralls-repo]
|
||||
[travis-img]: https://travis-ci.org/micropython/micropython.png?branch=master
|
||||
[travis-repo]: https://travis-ci.org/micropython/micropython
|
||||
[coveralls-img]: https://coveralls.io/repos/micropython/micropython/badge.png?branch=master
|
||||
[coveralls-repo]: https://coveralls.io/r/micropython/micropython?branch=master
|
||||
[istats-pr-img]: http://issuestats.com/github/micropython/micropython/badge/pr
|
||||
[istats-pr-repo]: http://issuestats.com/github/micropython/micropython
|
||||
[istats-issue-img]: http://issuestats.com/github/micropython/micropython/badge/issue
|
||||
[istats-issue-repo]: http://issuestats.com/github/micropython/micropython
|
||||
|
||||
The MicroPython project
|
||||
=======================
|
||||
@@ -26,7 +22,8 @@ MicroPython implements the entire Python 3.4 syntax (including exceptions,
|
||||
The following core datatypes are provided: str (including basic Unicode
|
||||
support), bytes, bytearray, tuple, list, dict, set, frozenset, array.array,
|
||||
collections.namedtuple, classes and instances. Builtin modules include sys,
|
||||
time, and struct. Note that only subset of Python 3.4 functionality
|
||||
time, and struct, etc. Select ports have support for _thread module
|
||||
(multithreading). Note that only subset of Python 3.4 functionality
|
||||
implemented for the data types and modules.
|
||||
|
||||
See the repository www.github.com/micropython/pyboard for the Micro
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
#define MICROPY_CPYTHON_COMPAT (0)
|
||||
#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_NONE)
|
||||
#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_NONE)
|
||||
#define MICROPY_USE_INTERNAL_PRINTF (0)
|
||||
|
||||
// type definitions for the specific machine
|
||||
|
||||
@@ -54,8 +55,6 @@
|
||||
|
||||
typedef int32_t mp_int_t; // must be pointer size
|
||||
typedef uint32_t mp_uint_t; // must be pointer size
|
||||
typedef void *machine_ptr_t; // must be of pointer size
|
||||
typedef const void *machine_const_ptr_t; // must be of pointer size
|
||||
typedef long mp_off_t;
|
||||
|
||||
// dummy print
|
||||
|
||||
@@ -154,7 +154,6 @@ APP_LIB_SRC_C = $(addprefix lib/,\
|
||||
timeutils/timeutils.c \
|
||||
utils/pyexec.c \
|
||||
utils/pyhelp.c \
|
||||
utils/printf.c \
|
||||
)
|
||||
|
||||
APP_STM_SRC_C = $(addprefix stmhal/,\
|
||||
|
||||
@@ -198,7 +198,8 @@ STATIC const mp_map_elem_t machine_module_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_IDLE), MP_OBJ_NEW_SMALL_INT(PYB_PWR_MODE_ACTIVE) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_SLEEP), MP_OBJ_NEW_SMALL_INT(PYB_PWR_MODE_LPDS) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_DEEPSLEEP), MP_OBJ_NEW_SMALL_INT(PYB_PWR_MODE_HIBERNATE) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_POWER_ON), MP_OBJ_NEW_SMALL_INT(PYB_SLP_PWRON_RESET) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_POWER_ON), MP_OBJ_NEW_SMALL_INT(PYB_SLP_PWRON_RESET) }, // legacy constant
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_PWRON_RESET), MP_OBJ_NEW_SMALL_INT(PYB_SLP_PWRON_RESET) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_HARD_RESET), MP_OBJ_NEW_SMALL_INT(PYB_SLP_HARD_RESET) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_WDT_RESET), MP_OBJ_NEW_SMALL_INT(PYB_SLP_WDT_RESET) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_DEEPSLEEP_RESET), MP_OBJ_NEW_SMALL_INT(PYB_SLP_HIB_RESET) },
|
||||
@@ -212,6 +213,5 @@ STATIC MP_DEFINE_CONST_DICT(machine_module_globals, machine_module_globals_table
|
||||
|
||||
const mp_obj_module_t machine_module = {
|
||||
.base = { &mp_type_module },
|
||||
.name = MP_QSTR_umachine,
|
||||
.globals = (mp_obj_dict_t*)&machine_module_globals,
|
||||
};
|
||||
|
||||
@@ -161,7 +161,6 @@ STATIC MP_DEFINE_CONST_DICT(mp_module_network_globals, mp_module_network_globals
|
||||
|
||||
const mp_obj_module_t mp_module_network = {
|
||||
.base = { &mp_type_module },
|
||||
.name = MP_QSTR_network,
|
||||
.globals = (mp_obj_dict_t*)&mp_module_network_globals,
|
||||
};
|
||||
|
||||
|
||||
@@ -58,6 +58,5 @@ STATIC MP_DEFINE_CONST_DICT(mp_module_binascii_globals, mp_module_binascii_globa
|
||||
|
||||
const mp_obj_module_t mp_module_ubinascii = {
|
||||
.base = { &mp_type_module },
|
||||
.name = MP_QSTR_ubinascii,
|
||||
.globals = (mp_obj_dict_t*)&mp_module_binascii_globals,
|
||||
};
|
||||
|
||||
@@ -204,7 +204,6 @@ STATIC MP_DEFINE_CONST_DICT(mp_module_hashlib_globals, mp_module_hashlib_globals
|
||||
|
||||
const mp_obj_module_t mp_module_uhashlib = {
|
||||
.base = { &mp_type_module },
|
||||
.name = MP_QSTR_uhashlib,
|
||||
.globals = (mp_obj_dict_t*)&mp_module_hashlib_globals,
|
||||
};
|
||||
|
||||
|
||||
@@ -602,6 +602,5 @@ STATIC MP_DEFINE_CONST_DICT(os_module_globals, os_module_globals_table);
|
||||
|
||||
const mp_obj_module_t mp_module_uos = {
|
||||
.base = { &mp_type_module },
|
||||
.name = MP_QSTR_uos,
|
||||
.globals = (mp_obj_dict_t*)&os_module_globals,
|
||||
};
|
||||
|
||||
@@ -541,6 +541,5 @@ STATIC MP_DEFINE_CONST_DICT(mp_module_usocket_globals, mp_module_usocket_globals
|
||||
|
||||
const mp_obj_module_t mp_module_usocket = {
|
||||
.base = { &mp_type_module },
|
||||
.name = MP_QSTR_usocket,
|
||||
.globals = (mp_obj_dict_t*)&mp_module_usocket_globals,
|
||||
};
|
||||
|
||||
@@ -78,6 +78,7 @@ STATIC mp_obj_t mod_ssl_wrap_socket(mp_uint_t n_args, const mp_obj_t *pos_args,
|
||||
{ MP_QSTR_certfile, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||
{ MP_QSTR_server_side, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
|
||||
{ MP_QSTR_cert_reqs, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = SSL_CERT_NONE} },
|
||||
{ MP_QSTR_ssl_version, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = SL_SO_SEC_METHOD_TLSV1} },
|
||||
{ MP_QSTR_ca_certs, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||
};
|
||||
|
||||
@@ -93,17 +94,19 @@ STATIC mp_obj_t mod_ssl_wrap_socket(mp_uint_t n_args, const mp_obj_t *pos_args,
|
||||
// retrieve the file paths (with an 6 byte offset in order to strip it from the '/flash' prefix)
|
||||
const char *keyfile = (args[1].u_obj == mp_const_none) ? NULL : &(mp_obj_str_get_str(args[1].u_obj)[6]);
|
||||
const char *certfile = (args[2].u_obj == mp_const_none) ? NULL : &(mp_obj_str_get_str(args[2].u_obj)[6]);
|
||||
const char *cafile = (args[5].u_obj == mp_const_none || args[4].u_int != SSL_CERT_REQUIRED) ?
|
||||
NULL : &(mp_obj_str_get_str(args[5].u_obj)[6]);
|
||||
const char *cafile = (args[6].u_obj == mp_const_none || args[4].u_int != SSL_CERT_REQUIRED) ?
|
||||
NULL : &(mp_obj_str_get_str(args[6].u_obj)[6]);
|
||||
|
||||
// server side requires both certfile and keyfile
|
||||
if (args[3].u_bool && (!keyfile || !certfile)) {
|
||||
goto arg_error;
|
||||
}
|
||||
|
||||
_i16 sd = ((mod_network_socket_obj_t *)args[0].u_obj)->sock_base.sd;
|
||||
_i16 _errno;
|
||||
_u8 method = SL_SO_SEC_METHOD_TLSV1;
|
||||
_i16 sd = ((mod_network_socket_obj_t *)args[0].u_obj)->sock_base.sd;
|
||||
|
||||
// set the requested SSL method
|
||||
_u8 method = args[5].u_int;
|
||||
if ((_errno = sl_SetSockOpt(sd, SL_SOL_SOCKET, SL_SO_SECMETHOD, &method, sizeof(method))) < 0) {
|
||||
goto socket_error;
|
||||
}
|
||||
@@ -146,13 +149,17 @@ STATIC const mp_map_elem_t mp_module_ussl_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_CERT_NONE), MP_OBJ_NEW_SMALL_INT(SSL_CERT_NONE) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_CERT_OPTIONAL), MP_OBJ_NEW_SMALL_INT(SSL_CERT_OPTIONAL) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_CERT_REQUIRED), MP_OBJ_NEW_SMALL_INT(SSL_CERT_REQUIRED) },
|
||||
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_PROTOCOL_SSLv3), MP_OBJ_NEW_SMALL_INT(SL_SO_SEC_METHOD_SSLV3) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_PROTOCOL_TLSv1), MP_OBJ_NEW_SMALL_INT(SL_SO_SEC_METHOD_TLSV1) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_PROTOCOL_TLSv1_1), MP_OBJ_NEW_SMALL_INT(SL_SO_SEC_METHOD_TLSV1_1) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_PROTOCOL_TLSv1_2), MP_OBJ_NEW_SMALL_INT(SL_SO_SEC_METHOD_TLSV1_2) },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(mp_module_ussl_globals, mp_module_ussl_globals_table);
|
||||
|
||||
const mp_obj_module_t mp_module_ussl = {
|
||||
.base = { &mp_type_module },
|
||||
.name = MP_QSTR_ussl,
|
||||
.globals = (mp_obj_dict_t*)&mp_module_ussl_globals,
|
||||
};
|
||||
|
||||
|
||||
@@ -196,6 +196,5 @@ STATIC MP_DEFINE_CONST_DICT(time_module_globals, time_module_globals_table);
|
||||
|
||||
const mp_obj_module_t mp_module_utime = {
|
||||
.base = { &mp_type_module },
|
||||
.name = MP_QSTR_utime,
|
||||
.globals = (mp_obj_dict_t*)&time_module_globals,
|
||||
};
|
||||
|
||||
@@ -26,6 +26,5 @@ STATIC MP_DEFINE_CONST_DICT(wipy_module_globals, wipy_module_globals_table);
|
||||
|
||||
const mp_obj_module_t wipy_module = {
|
||||
.base = { &mp_type_module },
|
||||
.name = MP_QSTR_wipy,
|
||||
.globals = (mp_obj_dict_t*)&wipy_module_globals,
|
||||
};
|
||||
|
||||
@@ -185,8 +185,6 @@ extern const struct _mp_obj_module_t mp_module_ussl;
|
||||
|
||||
typedef int32_t mp_int_t; // must be pointer size
|
||||
typedef unsigned int mp_uint_t; // must be pointer size
|
||||
typedef void *machine_ptr_t; // must be of pointer size
|
||||
typedef const void *machine_const_ptr_t; // must be of pointer size
|
||||
typedef long mp_off_t;
|
||||
|
||||
#define MP_PLAT_PRINT_STRN(str, len) mp_hal_stdout_tx_strn_cooked(str, len)
|
||||
@@ -198,14 +196,6 @@ typedef long mp_off_t;
|
||||
// disabling/enabling and sleep mode enter/exit
|
||||
#include "cc3200_asm.h"
|
||||
|
||||
// There is no classical C heap in bare-metal ports, only Python
|
||||
// garbage-collected heap. For completeness, emulate C heap via
|
||||
// GC heap. Note that MicroPython core never uses malloc() and friends,
|
||||
// so these defines are mostly to help extension module writers.
|
||||
#define malloc gc_alloc
|
||||
#define free gc_free
|
||||
#define realloc gc_realloc
|
||||
|
||||
// We need to provide a declaration/definition of alloca()
|
||||
#include <alloca.h>
|
||||
|
||||
|
||||
@@ -35,6 +35,6 @@ This can be achieved with:
|
||||
make MICROPY_PORT=<port_name> latexpdf
|
||||
|
||||
but require rather complete install of LaTeX with various extensions. On
|
||||
Debiab/Ubuntu, try (500MB+ download):
|
||||
Debian/Ubuntu, try (500MB+ download):
|
||||
|
||||
apt-get install texlive-latex-recommended texlive-latex-extra
|
||||
|
||||
@@ -99,7 +99,7 @@ copyright = '2014-2016, Damien P. George and contributors'
|
||||
# The short X.Y version.
|
||||
version = '1.8'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = '1.8.2'
|
||||
release = '1.8.5'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
|
||||
@@ -52,7 +52,7 @@ For your convenience, some of technical specifications are provided below:
|
||||
external FlashROM, UART, deep sleep wake-up, etc.)
|
||||
* UART: One RX/TX UART (no hardware handshaking), one TX-only UART.
|
||||
* SPI: 2 SPI interfaces (one used for FlashROM).
|
||||
* I2C: No native extenal I2C (bitbang implementation available on any pins).
|
||||
* I2C: No native external I2C (bitbang implementation available on any pins).
|
||||
* I2S: 1.
|
||||
* Programming: using BootROM bootloader from UART. Due to external FlashROM
|
||||
and always-available BootROM bootloader, ESP8266 is not brickable.
|
||||
|
||||
@@ -9,6 +9,12 @@ Quick reference for the ESP8266
|
||||
|
||||
The Adafruit Feather HUZZAH board (image attribution: Adafruit).
|
||||
|
||||
Installing MicroPython
|
||||
----------------------
|
||||
|
||||
See the corresponding section of tutorial: :ref:`intro`. It also includes
|
||||
a troubleshooting subsection.
|
||||
|
||||
General board control
|
||||
---------------------
|
||||
|
||||
@@ -17,14 +23,14 @@ Tab-completion is useful to find out what methods an object has.
|
||||
Paste mode (ctrl-E) is useful to paste a large slab of Python code into
|
||||
the REPL.
|
||||
|
||||
The ``machine`` module::
|
||||
The :mod:`machine` module::
|
||||
|
||||
import machine
|
||||
|
||||
machine.freq() # get the current frequency of the CPU
|
||||
machine.freq(160000000) # set the CPU frequency to 160 MHz
|
||||
|
||||
The ``esp`` module::
|
||||
The :mod:`esp` module::
|
||||
|
||||
import esp
|
||||
|
||||
@@ -34,7 +40,7 @@ The ``esp`` module::
|
||||
Networking
|
||||
----------
|
||||
|
||||
The ``network`` module::
|
||||
The :mod:`network` module::
|
||||
|
||||
import network
|
||||
|
||||
@@ -63,13 +69,13 @@ A useful function for connecting to your local WiFi network is::
|
||||
pass
|
||||
print('network config:', wlan.ifconfig())
|
||||
|
||||
Once the network is established the ``socket`` module can be used
|
||||
Once the network is established the :mod:`socket <usocket>` module can be used
|
||||
to create and use TCP/UDP sockets as usual.
|
||||
|
||||
Delay and timing
|
||||
----------------
|
||||
|
||||
Use the ``time`` module::
|
||||
Use the :mod:`time <utime>` module::
|
||||
|
||||
import time
|
||||
|
||||
@@ -156,17 +162,18 @@ Use the ``machine.ADC`` class::
|
||||
adc = ADC(0) # create ADC object on ADC pin
|
||||
adc.read() # read value, 0-1024
|
||||
|
||||
SPI bus
|
||||
-------
|
||||
Software SPI bus
|
||||
----------------
|
||||
|
||||
The SPI driver is implemented in software and works on all pins::
|
||||
There are two SPI drivers. One is implemented in software (bit-banging)
|
||||
and works on all pins::
|
||||
|
||||
from machine import Pin, SPI
|
||||
|
||||
# construct an SPI bus on the given pins
|
||||
# polarity is the idle state of SCK
|
||||
# phase=0 means sample on the first edge of SCK, phase=1 means the second
|
||||
spi = SPI(baudrate=100000, polarity=1, phase=0, sck=Pin(0), mosi=Pin(2), miso=Pin(4))
|
||||
spi = SPI(-1, baudrate=100000, polarity=1, phase=0, sck=Pin(0), mosi=Pin(2), miso=Pin(4))
|
||||
|
||||
spi.init(baudrate=200000) # set the baudrate
|
||||
|
||||
@@ -183,6 +190,21 @@ The SPI driver is implemented in software and works on all pins::
|
||||
spi.write_readinto(b'1234', buf) # write to MOSI and read from MISO into the buffer
|
||||
spi.write_readinto(buf, buf) # write buf to MOSI and read MISO back into buf
|
||||
|
||||
|
||||
Hardware SPI bus
|
||||
----------------
|
||||
|
||||
The hardware SPI is faster (up to 80Mhz), but only works on following pins:
|
||||
``MISO`` is GPIO12, ``MOSI`` is GPIO13, and ``SCK`` is GPIO14. It has the same
|
||||
methods as the bitbanging SPI class above, except for the pin parameters for the
|
||||
constructor and init (as those are fixed)::
|
||||
|
||||
from machine import Pin, SPI
|
||||
|
||||
hspi = SPI(1, baudrate=80000000, polarity=0, phase=0)
|
||||
|
||||
(``SPI(0)`` is used for FlashROM and not available to users.)
|
||||
|
||||
I2C bus
|
||||
-------
|
||||
|
||||
@@ -233,15 +255,14 @@ The OneWire driver is implemented in software and works on all pins::
|
||||
ow.scan() # return a list of devices on the bus
|
||||
ow.reset() # reset the bus
|
||||
ow.readbyte() # read a byte
|
||||
ow.read(5) # read 5 bytes
|
||||
ow.writebyte(0x12) # write a byte on the bus
|
||||
ow.write('123') # write bytes on the bus
|
||||
ow.select_rom(b'12345678') # select a specific device by its ROM code
|
||||
|
||||
There is a specific driver for DS18B20 devices::
|
||||
There is a specific driver for DS18S20 and DS18B20 devices::
|
||||
|
||||
import time
|
||||
ds = onewire.DS18B20(ow)
|
||||
import time, ds18x20
|
||||
ds = ds18x20.DS18X20(ow)
|
||||
roms = ds.scan()
|
||||
ds.convert_temp()
|
||||
time.sleep_ms(750)
|
||||
@@ -291,6 +312,24 @@ For low-level driving of an APA102::
|
||||
import esp
|
||||
esp.apa102_write(clock_pin, data_pin, rgbi_buf)
|
||||
|
||||
DHT driver
|
||||
----------
|
||||
|
||||
The DHT driver is implemented in software and works on all pins::
|
||||
|
||||
import dht
|
||||
import machine
|
||||
|
||||
d = dht.DHT11(machine.Pin(4))
|
||||
d.measure()
|
||||
d.temperature() # eg. 23 (°C)
|
||||
d.humidity() # eg. 41 (% RH)
|
||||
|
||||
d = dht.DHT22(machine.Pin(4))
|
||||
d.measure()
|
||||
d.temperature() # eg. 23.6 (°C)
|
||||
d.humidity() # eg. 41.3 (% RH)
|
||||
|
||||
WebREPL (web browser interactive prompt)
|
||||
----------------------------------------
|
||||
|
||||
|
||||
65
docs/esp8266/tutorial/dht.rst
Normal file
65
docs/esp8266/tutorial/dht.rst
Normal file
@@ -0,0 +1,65 @@
|
||||
Temperature and Humidity
|
||||
========================
|
||||
|
||||
DHT (Digital Humidity & Temperature) sensors are low cost digital sensors with
|
||||
capacitive humidity sensors and thermistors to measure the surrounding air.
|
||||
They feature a chip that handles analog to digital conversion and provide a
|
||||
1-wire interface. Newer sensors additionally provide an I2C interface.
|
||||
|
||||
The DHT11 (blue) and DHT22 (white) sensors provide the same 1-wire interface,
|
||||
however, the DHT22 requires a separate object as it has more complex
|
||||
calculation. DHT22 have 1 decimal place resolution for both humidity and
|
||||
temperature readings. DHT11 have whole number for both.
|
||||
|
||||
A custom 1-wire protocol, which is different to Dallas 1-wire, is used to get
|
||||
the measurements from the sensor. The payload consists of a humidity value,
|
||||
a temperature value and a checksum.
|
||||
|
||||
To use the 1-wire interface, construct the objects referring to their data pin::
|
||||
|
||||
>>> import dht
|
||||
>>> import machine
|
||||
>>> d = dht.DHT11(machine.Pin(4))
|
||||
|
||||
>>> import dht
|
||||
>>> import machine
|
||||
>>> d = dht.DHT22(machine.Pin(4))
|
||||
|
||||
Then measure and read their values with::
|
||||
|
||||
>>> d.measure()
|
||||
>>> d.temperature()
|
||||
>>> d.humidity()
|
||||
|
||||
Values returned from ``temperature()`` are in degrees Celsius and values
|
||||
returned from ``humidity()`` are a percentage of relative humidity.
|
||||
|
||||
The DHT11 can be called no more than once per second and the DHT22 once every
|
||||
two seconds for most accurate results. Sensor accuracy will degrade over time.
|
||||
Each sensor supports a different operating range. Refer to the product
|
||||
datasheets for specifics.
|
||||
|
||||
In 1-wire mode, only three of the four pins are used and in I2C mode, all four
|
||||
pins are used. Older sensors may still have 4 pins even though they do not
|
||||
support I2C. The 3rd pin is simply not connected.
|
||||
|
||||
Pin configurations:
|
||||
|
||||
Sensor without I2C in 1-wire mode (eg. DHT11, DHT22, AM2301, AM2302):
|
||||
|
||||
1=VDD, 2=Data, 3=NC, 4=GND
|
||||
|
||||
Sensor with I2C in 1-wire mode (eg. DHT12, AM2320, AM2321, AM2322):
|
||||
|
||||
1=VDD, 2=Data, 3=GND, 4=GND
|
||||
|
||||
Sensor with I2C in I2C mode (eg. DHT12, AM2320, AM2321, AM2322):
|
||||
|
||||
1=VDD, 2=SDA, 3=GND, 4=SCL
|
||||
|
||||
You should use pull-up resistors for the Data, SDA and SCL pins.
|
||||
|
||||
To make newer I2C sensors work in backwards compatible 1-wire mode, you must
|
||||
connect both pins 3 and 4 to GND. This disables the I2C interface.
|
||||
|
||||
DHT22 sensors are now sold under the name AM2302 and are otherwise identical.
|
||||
@@ -29,4 +29,5 @@ to `<https://www.python.org>`__.
|
||||
powerctrl.rst
|
||||
onewire.rst
|
||||
neopixel.rst
|
||||
dht.rst
|
||||
nextsteps.rst
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
Introduction to MicroPython on the ESP8266
|
||||
==========================================
|
||||
.. _intro:
|
||||
|
||||
Getting started with MicroPython on the ESP8266
|
||||
===============================================
|
||||
|
||||
Using MicroPython is a great way to get the most of your ESP8266 board. And
|
||||
vice versa, the ESP8266 chip is a great platform for using MicroPython. This
|
||||
@@ -74,8 +76,9 @@ PC. You may also need to reduce the baudrate if you get errors when flashing
|
||||
(eg down to 115200). The filename of the firmware should also match the file
|
||||
that you have.
|
||||
|
||||
If you have a NodeMCU board, you may need to use the following command to deploy
|
||||
the firmware (note the "-fm dio" option)::
|
||||
For some boards with a particular FlashROM configuration (e.g. some variants of
|
||||
a NodeMCU board) you may need to use the following command to deploy
|
||||
the firmware (note the ``-fm dio`` option)::
|
||||
|
||||
esptool.py --port /dev/ttyUSB0 --baud 460800 write_flash --flash_size=8m -fm dio 0 esp8266-2016-05-03-v1.8.bin
|
||||
|
||||
@@ -100,3 +103,64 @@ be the same everytime, and most likely different for all ESP8266 chips). The
|
||||
password for the WiFi is micropythoN (note the upper-case N). Its IP address
|
||||
will be 192.168.4.1 once you connect to its network. WiFi configuration will
|
||||
be discussed in more detail later in the tutorial.
|
||||
|
||||
Troubleshooting installation problems
|
||||
-------------------------------------
|
||||
|
||||
If you experience problems during flashing or with running firmware immediately
|
||||
after it, here are troubleshooting recommendations:
|
||||
|
||||
* Be aware of and try to exclude hardware problems. There are 2 common problems:
|
||||
bad power source quality and worn-out/defective FlashROM. Speaking of power
|
||||
source, not just raw amperage is important, but also low ripple and noise/EMI
|
||||
in general. If you experience issues with self-made or wall-wart style power
|
||||
supply, try USB power from a computer. Unearthed power supplies are also known
|
||||
to cause problems as they source of increased EMI (electromagnetic interference)
|
||||
- at the very least, and may lead to electrical devices breakdown. So, you are
|
||||
advised to avoid using unearthed power connections when working with ESP8266
|
||||
and other boards. In regard to FlashROM hardware problems, there are independent
|
||||
(not related to MicroPython in any way) reports
|
||||
`(e.g.) <http://internetofhomethings.com/homethings/?p=538>`_
|
||||
that on some ESP8266 modules, FlashROM can be programmed as little as 20 times
|
||||
before programming errors occur. This is *much* less than 100,000 programming
|
||||
cycles cited for FlashROM chips of a type used with ESP8266 by reputable
|
||||
vendors, which points to either production rejects, or second-hand worn-out
|
||||
flash chips to be used on some (apparently cheap) modules/boards. You may want
|
||||
to use your best judgement about source, price, documentation, warranty,
|
||||
post-sales support for the modules/boards you purchase.
|
||||
|
||||
* The flashing instructions above use flashing speed of 460800 baud, which is
|
||||
good compromise between speed and stability. However, depending on your
|
||||
module/board, USB-UART convertor, cables, host OS, etc., the above baud
|
||||
rate may be too high and lead to errors. Try a more common 115200 baud
|
||||
rate instead in such cases.
|
||||
|
||||
* If lower baud rate didn't help, you may want to try older version of
|
||||
esptool.py, which had a different programming algorithm::
|
||||
pip install esptool==1.0.1
|
||||
|
||||
* The ``--flash_size`` option in the commands above is mandatory. Omitting
|
||||
it will lead to a corrupted firmware.
|
||||
|
||||
* To catch incorrect flash content (e.g. from a defective sector on a chip),
|
||||
add ``--verify`` switch to the commands above.
|
||||
|
||||
* Additionally, you can check the firmware integrity from a MicroPython REPL
|
||||
prompt (assuming you were able to flash it and ``--verify`` option doesn't
|
||||
report errors)::
|
||||
import esp
|
||||
esp.check_fw()
|
||||
If the last output value is True, the firmware is OK. Otherwise, it's
|
||||
corrupted and need to be reflashed correctly.
|
||||
|
||||
* If you experience any issues with another flashing application (not
|
||||
esptool.py), try esptool.py, it is a generally accepted flashing
|
||||
application in the ESP8266 community.
|
||||
|
||||
* If you still experience problems with even flashing the firmware, please
|
||||
refer to esptool.py project page, https://github.com/themadinventor/esptool
|
||||
for additional documentation and bug tracker where you can report problems.
|
||||
|
||||
* If you are able to flash firmware, but ``--verify`` option or
|
||||
``esp.check_fw()`` return errors even after multiple retries, you
|
||||
may have a defective FlashROM chip, as explained above.
|
||||
|
||||
@@ -6,19 +6,19 @@ The 1-wire bus is a serial bus that uses just a single wire for communication
|
||||
is a very popular 1-wire device, and here we show how to use the onewire module
|
||||
to read from such a device.
|
||||
|
||||
For the following code to work you need to have at least one DS18B20 temperature
|
||||
For the following code to work you need to have at least one DS18S20 or DS18B20 temperature
|
||||
sensor with its data line connected to GPIO12. You must also power the sensors
|
||||
and connect a 4.7k Ohm resistor between the data pin and the power pin. ::
|
||||
|
||||
import time
|
||||
import machine
|
||||
import onewire
|
||||
import onewire, ds18x20
|
||||
|
||||
# the device is on GPIO12
|
||||
dat = machine.Pin(12)
|
||||
|
||||
# create the onewire object
|
||||
ds = onewire.DS18B20(onewire.OneWire(dat))
|
||||
ds = ds18x20.DS18X20(onewire.OneWire(dat))
|
||||
|
||||
# scan for devices on the bus
|
||||
roms = ds.scan()
|
||||
|
||||
@@ -14,7 +14,7 @@ Here, the "0" is the pin that you want to access. Usually you want to
|
||||
configure the pin to be input or output, and you do this when constructing
|
||||
it. To make an input pin use::
|
||||
|
||||
>>> pin = machine.Pin(0, machine.Pin.OUT, machine.Pin.PULL_UP)
|
||||
>>> pin = machine.Pin(0, machine.Pin.IN, machine.Pin.PULL_UP)
|
||||
|
||||
You can either use PULL_UP or None for the input pull-mode. If it's
|
||||
not specified then it defaults to None, which is no pull resistor.
|
||||
|
||||
@@ -36,7 +36,7 @@ WebREPL - a prompt over WiFi
|
||||
WebREPL allows you to use the Python prompt over WiFi, connecting through a
|
||||
browser. The latest versions of Firefox and Chrome are supported.
|
||||
|
||||
For your convinience, WebREPL client is hosted at
|
||||
For your convenience, WebREPL client is hosted at
|
||||
`<http://micropython.org/webrepl>`__ . Alternatively, you can install it
|
||||
locally from the the GitHub repository
|
||||
`<https://github.com/micropython/webrepl>`__ .
|
||||
|
||||
30
docs/library/array.rst
Normal file
30
docs/library/array.rst
Normal file
@@ -0,0 +1,30 @@
|
||||
:mod:`array` -- arrays of numeric data
|
||||
======================================
|
||||
|
||||
.. module:: array
|
||||
:synopsis: efficient arrays of numeric data
|
||||
|
||||
See `Python array <https://docs.python.org/3/library/array.html>`_ for more
|
||||
information.
|
||||
|
||||
Supported format codes: ``b``, ``B``, ``h``, ``H``, ``i``, ``I``, ``l``,
|
||||
``L``, ``q``, ``Q``, ``f``, ``d`` (the latter 2 depending on the
|
||||
floating-point support).
|
||||
|
||||
Classes
|
||||
-------
|
||||
|
||||
.. class:: array.array(typecode, [iterable])
|
||||
|
||||
Create array with elements of given type. Initial contents of the
|
||||
array are given by an `iterable`. If it is not provided, an empty
|
||||
array is created.
|
||||
|
||||
.. method:: append(val)
|
||||
|
||||
Append new element to the end of array, growing it.
|
||||
|
||||
.. method:: extend(iterable)
|
||||
|
||||
Append new elements as contained in an iterable to the end of
|
||||
array, growing it.
|
||||
@@ -1,7 +1,7 @@
|
||||
Builtin Functions
|
||||
=================
|
||||
|
||||
All builtin functions are described here. They are alse available via
|
||||
All builtin functions are described here. They are also available via
|
||||
``builtins`` module.
|
||||
|
||||
.. function:: abs()
|
||||
|
||||
@@ -15,7 +15,7 @@ Functions
|
||||
Get or set the sleep type.
|
||||
|
||||
If the ``sleep_type`` parameter is provided, sets the sleep type to its
|
||||
value. If the function is called wihout parameters, returns the current
|
||||
value. If the function is called without parameters, returns the current
|
||||
sleep type.
|
||||
|
||||
The possible sleep types are defined as constants:
|
||||
|
||||
@@ -51,6 +51,7 @@ library.
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
array.rst
|
||||
builtins.rst
|
||||
cmath.rst
|
||||
gc.rst
|
||||
@@ -75,6 +76,7 @@ library.
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
array.rst
|
||||
builtins.rst
|
||||
cmath.rst
|
||||
gc.rst
|
||||
@@ -99,6 +101,7 @@ library.
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
array.rst
|
||||
builtins.rst
|
||||
gc.rst
|
||||
select.rst
|
||||
@@ -116,6 +119,7 @@ library.
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
array.rst
|
||||
builtins.rst
|
||||
gc.rst
|
||||
math.rst
|
||||
|
||||
@@ -170,8 +170,7 @@ methods are convenience functions to communicate with such devices.
|
||||
|
||||
Read `nbytes` from the slave specified by `addr` starting from the memory
|
||||
address specified by `memaddr`.
|
||||
The argument `addrsize` specifies the address size in bits (on ESP8266
|
||||
this argument is not recognised and the address size is always 8 bits).
|
||||
The argument `addrsize` specifies the address size in bits.
|
||||
Returns a `bytes` object with the data read.
|
||||
|
||||
.. method:: I2C.readfrom_mem_into(addr, memaddr, buf, \*, addrsize=8)
|
||||
|
||||
@@ -84,7 +84,7 @@ Methods
|
||||
|
||||
- ``None`` - no pull up or down resistor.
|
||||
- ``Pin.PULL_UP`` - pull up resistor enabled.
|
||||
- ``Pin.PULL_DOWN`` - pull down resitor enabled.
|
||||
- ``Pin.PULL_DOWN`` - pull down resistor enabled.
|
||||
|
||||
- ``drive`` can be one of:
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ Methods
|
||||
|
||||
.. method:: RTC.alarm(id, time, /*, repeat=False)
|
||||
|
||||
Set the RTC alarm. Time might be either a milllisecond value to program the alarm to
|
||||
Set the RTC alarm. Time might be either a millisecond value to program the alarm to
|
||||
current time + time_in_ms in the future, or a datetimetuple. If the time passed is in
|
||||
milliseconds, repeat can be set to ``True`` to make the alarm periodic.
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ Methods
|
||||
respectively.
|
||||
- ``bits`` is the width of each transfer, accepted values are 8, 16 and 32.
|
||||
- ``firstbit`` can be ``SPI.MSB`` only.
|
||||
- ``pins`` is an optional tupple with the pins to assign to the SPI bus.
|
||||
- ``pins`` is an optional tuple with the pins to assign to the SPI bus.
|
||||
|
||||
.. method:: SPI.deinit()
|
||||
|
||||
|
||||
@@ -104,7 +104,7 @@ Methods
|
||||
If only a channel identifier passed, then a previously initialized channel
|
||||
object is returned (or ``None`` if there is no previous channel).
|
||||
|
||||
Othwerwise, a TimerChannel object is initialized and returned.
|
||||
Otherwise, a TimerChannel object is initialized and returned.
|
||||
|
||||
The operating mode is is the one configured to the Timer object that was used to
|
||||
create the channel.
|
||||
@@ -152,7 +152,7 @@ Methods
|
||||
|
||||
.. method:: timerchannel.irq(\*, trigger, priority=1, handler=None)
|
||||
|
||||
The behavior of this callback is heaviliy dependent on the operating
|
||||
The behavior of this callback is heavily dependent on the operating
|
||||
mode of the timer channel:
|
||||
|
||||
- If mode is ``Timer.PERIODIC`` the callback is executed periodically
|
||||
|
||||
@@ -167,7 +167,7 @@ Methods
|
||||
.. data:: UART.EVEN
|
||||
.. data:: UART.ODD
|
||||
|
||||
parity types (anlong with ``None``)
|
||||
parity types (along with ``None``)
|
||||
|
||||
.. data:: UART.RX_ANY
|
||||
|
||||
|
||||
@@ -14,6 +14,8 @@ Example usage::
|
||||
wdt = WDT(timeout=2000) # enable it with a timeout of 2s
|
||||
wdt.feed()
|
||||
|
||||
Availability of this class: pyboard, WiPy.
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
|
||||
@@ -24,17 +24,15 @@ Interrupt related functions
|
||||
.. function:: disable_irq()
|
||||
|
||||
Disable interrupt requests.
|
||||
Returns the previous IRQ state: ``False``/``True`` for disabled/enabled IRQs
|
||||
respectively. This return value can be passed to enable_irq to restore
|
||||
the IRQ to its original state.
|
||||
Returns the previous IRQ state which should be considered an opaque value.
|
||||
This return value should be passed to the ``enable_irq`` function to restore
|
||||
interrupts to their original state, before ``disable_irq`` was called.
|
||||
|
||||
.. function:: enable_irq(state=True)
|
||||
.. function:: enable_irq(state)
|
||||
|
||||
Enable interrupt requests.
|
||||
If ``state`` is ``True`` (the default value) then IRQs are enabled.
|
||||
If ``state`` is ``False`` then IRQs are disabled. The most common use of
|
||||
this function is to pass it the value returned by ``disable_irq`` to
|
||||
exit a critical section.
|
||||
Re-enable interrupt requests.
|
||||
The ``state`` parameter should be the value that was returned from the most
|
||||
recent call to the ``disable_irq`` function.
|
||||
|
||||
Power related functions
|
||||
-----------------------
|
||||
@@ -57,7 +55,7 @@ Power related functions
|
||||
Gates the clock to the CPU, useful to reduce power consumption at any time during
|
||||
short or long periods. Peripherals continue working and execution resumes as soon
|
||||
as any interrupt is triggered (on many ports this includes system timer
|
||||
interrupt occuring at regular intervals on the order of millisecond).
|
||||
interrupt occurring at regular intervals on the order of millisecond).
|
||||
|
||||
.. function:: sleep()
|
||||
|
||||
@@ -96,7 +94,7 @@ Miscellaneous functions
|
||||
|
||||
.. function:: unique_id()
|
||||
|
||||
Returns a byte string with a unique idenifier of a board/SoC. It will vary
|
||||
Returns a byte string with a unique identifier of a board/SoC. It will vary
|
||||
from a board/SoC instance to another, if underlying hardware allows. Length
|
||||
varies by hardware (so use substring of a full value if you expect a short
|
||||
ID). In some MicroPython ports, ID corresponds to the network MAC address.
|
||||
@@ -125,7 +123,7 @@ Constants
|
||||
|
||||
irq wake values
|
||||
|
||||
.. data:: machine.POWER_ON
|
||||
.. data:: machine.PWRON_RESET
|
||||
.. data:: machine.HARD_RESET
|
||||
.. data:: machine.WDT_RESET
|
||||
.. data:: machine.DEEPSLEEP_RESET
|
||||
|
||||
@@ -237,7 +237,7 @@ For example::
|
||||
Get or set the PHY mode.
|
||||
|
||||
If the ``mode`` parameter is provided, sets the mode to its value. If
|
||||
the function is called wihout parameters, returns the current mode.
|
||||
the function is called without parameters, returns the current mode.
|
||||
|
||||
The possible modes are defined as constants:
|
||||
* ``MODE_11B`` -- IEEE 802.11b,
|
||||
@@ -319,7 +319,7 @@ For example::
|
||||
* ``STAT_WRONG_PASSWORD`` -- failed due to incorrect password,
|
||||
* ``STAT_NO_AP_FOUND`` -- failed because no access point replied,
|
||||
* ``STAT_CONNECT_FAIL`` -- failed due to other problems,
|
||||
* ``STAT_GOT_IP`` -- connection susccessful.
|
||||
* ``STAT_GOT_IP`` -- connection successful.
|
||||
|
||||
.. method:: wlan.isconnected()
|
||||
|
||||
@@ -329,7 +329,7 @@ For example::
|
||||
|
||||
.. method:: wlan.ifconfig([(ip, subnet, gateway, dns)])
|
||||
|
||||
Get/set IP-level network interface paremeters: IP address, subnet mask,
|
||||
Get/set IP-level network interface parameters: IP address, subnet mask,
|
||||
gateway and DNS server. When called with no arguments, this method returns
|
||||
a 4-tuple with the above information. To set the above values, pass a
|
||||
4-tuple with the required information. For example::
|
||||
@@ -343,8 +343,8 @@ For example::
|
||||
with additional parameters beyond standard IP configuration (as dealt with by
|
||||
``wlan.ifconfig()``). These include network-specific and hardware-specific
|
||||
parameters. For setting parameters, keyword argument syntax should be used,
|
||||
multiple parameters can be set at once. For querying, paremeters name should
|
||||
be quoted as a string, and only one paramter can be queries at time::
|
||||
multiple parameters can be set at once. For querying, parameters name should
|
||||
be quoted as a string, and only one parameter can be queries at time::
|
||||
|
||||
# Set WiFi access point name (formally known as ESSID) and WiFi channel
|
||||
ap.config(essid='My AP', channel=11)
|
||||
@@ -397,7 +397,7 @@ For example::
|
||||
.. note::
|
||||
|
||||
The ``WLAN`` constructor is special in the sense that if no arguments besides the id are given,
|
||||
it will return the already exisiting ``WLAN`` instance without re-configuring it. This is
|
||||
it will return the already existing ``WLAN`` instance without re-configuring it. This is
|
||||
because ``WLAN`` is a system feature of the WiPy. If the already existing instance is not
|
||||
initialized it will do the same as the other constructors an will initialize it with default
|
||||
values.
|
||||
|
||||
@@ -13,7 +13,7 @@ class ADC -- analog to digital conversion
|
||||
adc = pyb.ADC(pin) # create an analog object from a pin
|
||||
val = adc.read() # read an analog value
|
||||
|
||||
adc = pyb.ADCAll(resolution) # creale an ADCAll object
|
||||
adc = pyb.ADCAll(resolution) # create an ADCAll object
|
||||
val = adc.read_channel(channel) # read the given channel
|
||||
val = adc.read_core_temp() # read MCU temperature
|
||||
val = adc.read_core_vbat() # read MCU VBAT
|
||||
|
||||
@@ -79,7 +79,7 @@ Methods
|
||||
.. method:: DAC.triangle(freq)
|
||||
|
||||
Generate a triangle wave. The value on the DAC output changes at
|
||||
the given frequency, and the frequence of the repeating triangle wave
|
||||
the given frequency, and the frequency of the repeating triangle wave
|
||||
itself is 2048 times smaller.
|
||||
|
||||
.. method:: DAC.write(value)
|
||||
|
||||
@@ -7,7 +7,7 @@ class ExtInt -- configure I/O pins to interrupt on external events
|
||||
There are a total of 22 interrupt lines. 16 of these can come from GPIO pins
|
||||
and the remaining 6 are from internal sources.
|
||||
|
||||
For lines 0 thru 15, a given line can map to the corresponding line from an
|
||||
For lines 0 through 15, a given line can map to the corresponding line from an
|
||||
arbitrary port. So line 0 can map to Px0 where x is A, B, C, ... and
|
||||
line 1 can map to Px1 where x is A, B, C, ... ::
|
||||
|
||||
@@ -27,7 +27,7 @@ explanation, along with various techniques for debouncing.
|
||||
Trying to register 2 callbacks onto the same pin will throw an exception.
|
||||
|
||||
If pin is passed as an integer, then it is assumed to map to one of the
|
||||
internal interrupt sources, and must be in the range 16 thru 22.
|
||||
internal interrupt sources, and must be in the range 16 through 22.
|
||||
|
||||
All other pin objects go through the pin mapper to come up with one of the
|
||||
gpio pins. ::
|
||||
|
||||
@@ -39,7 +39,7 @@ Printing the i2c object gives you information about its configuration.
|
||||
|
||||
You can specify a timeout (in ms)::
|
||||
|
||||
i2c.send(b'123', timeout=2000) # timout after 2 seconds
|
||||
i2c.send(b'123', timeout=2000) # timeout after 2 seconds
|
||||
|
||||
A master must specify the recipient's address::
|
||||
|
||||
|
||||
@@ -231,7 +231,7 @@ Constants
|
||||
class PinAF -- Pin Alternate Functions
|
||||
======================================
|
||||
|
||||
A Pin represents a physical pin on the microcprocessor. Each pin
|
||||
A Pin represents a physical pin on the microprocessor. Each pin
|
||||
can have a variety of functions (GPIO, I2C SDA, etc). Each PinAF
|
||||
object represents a particular function for a pin.
|
||||
|
||||
@@ -240,7 +240,7 @@ Constants
|
||||
x3 = pyb.Pin.board.X3
|
||||
x3_af = x3.af_list()
|
||||
|
||||
x3_af will now contain an array of PinAF objects which are availble on
|
||||
x3_af will now contain an array of PinAF objects which are available on
|
||||
pin X3.
|
||||
|
||||
For the pyboard, x3_af would contain:
|
||||
|
||||
@@ -73,7 +73,7 @@ Methods
|
||||
value, which is an integer in the range [-511 : 512]. With one
|
||||
argument it sets the RTC calibration.
|
||||
|
||||
The RTC Smooth Calibration mechanism addjusts the RTC clock rate by
|
||||
The RTC Smooth Calibration mechanism adjusts the RTC clock rate by
|
||||
adding or subtracting the given number of ticks from the 32768 Hz
|
||||
clock over a 32 second period (corresponding to 2^20 clock ticks.)
|
||||
Each tick added will speed up the clock by 1 part in 2^20, or 0.954
|
||||
|
||||
@@ -68,6 +68,7 @@ Methods
|
||||
- ``polarity`` can be 0 or 1, and is the level the idle clock line sits at.
|
||||
- ``phase`` can be 0 or 1 to sample data on the first or second clock edge
|
||||
respectively.
|
||||
- ``bits`` can be 8 or 16, and is the number of bits in each transferred word.
|
||||
- ``firstbit`` can be ``SPI.MSB`` or ``SPI.LSB``.
|
||||
- ``crc`` can be None for no CRC, or a polynomial specifier.
|
||||
|
||||
|
||||
@@ -78,7 +78,7 @@ Methods
|
||||
|
||||
Keyword arguments:
|
||||
|
||||
- ``freq`` --- specifies the periodic frequency of the timer. You migh also
|
||||
- ``freq`` --- specifies the periodic frequency of the timer. You might also
|
||||
view this as the frequency with which the timer goes through one complete cycle.
|
||||
|
||||
- ``prescaler`` [0-0xffff] - specifies the value to be loaded into the
|
||||
@@ -97,7 +97,7 @@ Methods
|
||||
|
||||
- ``Timer.UP`` - configures the timer to count from 0 to ARR (default)
|
||||
- ``Timer.DOWN`` - configures the timer to count from ARR down to 0.
|
||||
- ``Timer.CENTER`` - confgures the timer to count from 0 to ARR and
|
||||
- ``Timer.CENTER`` - configures the timer to count from 0 to ARR and
|
||||
then back down to 0.
|
||||
|
||||
- ``div`` can be one of 1, 2, or 4. Divides the timer clock to determine
|
||||
@@ -109,7 +109,7 @@ Methods
|
||||
transitions on complimentary channels (both channels will be inactive)
|
||||
for this time). ``deadtime`` may be an integer between 0 and 1008, with
|
||||
the following restrictions: 0-128 in steps of 1. 128-256 in steps of
|
||||
2, 256-512 in steps of 8, and 512-1008 in steps of 16. ``deadime``
|
||||
2, 256-512 in steps of 8, and 512-1008 in steps of 16. ``deadtime``
|
||||
measures ticks of ``source_freq`` divided by ``div`` clock ticks.
|
||||
``deadtime`` is only available on timers 1 and 8.
|
||||
|
||||
@@ -141,7 +141,7 @@ Methods
|
||||
If only a channel number is passed, then a previously initialized channel
|
||||
object is returned (or ``None`` if there is no previous channel).
|
||||
|
||||
Othwerwise, a TimerChannel object is initialized and returned.
|
||||
Otherwise, a TimerChannel object is initialized and returned.
|
||||
|
||||
Each channel can be configured to perform pwm, output compare, or
|
||||
input capture. All channels share the same underlying timer, which means
|
||||
@@ -183,7 +183,7 @@ Methods
|
||||
- ``polarity`` can be one of:
|
||||
|
||||
- ``Timer.HIGH`` - output is active high
|
||||
- ``Timer.LOW`` - output is acive low
|
||||
- ``Timer.LOW`` - output is active low
|
||||
|
||||
Optional keyword arguments for Timer.IC modes:
|
||||
|
||||
|
||||
39
docs/library/pyb.USB_HID.rst
Normal file
39
docs/library/pyb.USB_HID.rst
Normal file
@@ -0,0 +1,39 @@
|
||||
.. currentmodule:: pyb
|
||||
|
||||
class USB_HID -- USB Human Interface Device (HID)
|
||||
=================================================
|
||||
|
||||
The USB_HID class allows creation of an object representing the USB
|
||||
Human Interface Device (HID) interface. It can be used to emulate
|
||||
a peripheral such as a mouse or keyboard.
|
||||
|
||||
Before you can use this class, you need to use :meth:`pyb.usb_mode()` to set the USB mode to include the HID interface.
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. class:: pyb.USB_HID()
|
||||
|
||||
Create a new USB_HID object.
|
||||
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. method:: USB_HID.recv(data, \*, timeout=5000)
|
||||
|
||||
Receive data on the bus:
|
||||
|
||||
- ``data`` can be an integer, which is the number of bytes to receive,
|
||||
or a mutable buffer, which will be filled with received bytes.
|
||||
- ``timeout`` is the timeout in milliseconds to wait for the receive.
|
||||
|
||||
Return value: if ``data`` is an integer then a new buffer of the bytes received,
|
||||
otherwise the number of bytes read into ``data`` is returned.
|
||||
|
||||
.. method:: USB_HID.send(data)
|
||||
|
||||
Send data over the USB HID interface:
|
||||
|
||||
- ``data`` is the data to send (a tuple/list of integers, or a
|
||||
bytearray).
|
||||
@@ -46,7 +46,7 @@ Time related functions
|
||||
Returns the number of milliseconds which have elapsed since ``start``.
|
||||
|
||||
This function takes care of counter wrap, and always returns a positive
|
||||
number. This means it can be used to measure periods upto about 12.4 days.
|
||||
number. This means it can be used to measure periods up to about 12.4 days.
|
||||
|
||||
Example::
|
||||
|
||||
@@ -59,7 +59,7 @@ Time related functions
|
||||
Returns the number of microseconds which have elapsed since ``start``.
|
||||
|
||||
This function takes care of counter wrap, and always returns a positive
|
||||
number. This means it can be used to measure periods upto about 17.8 minutes.
|
||||
number. This means it can be used to measure periods up to about 17.8 minutes.
|
||||
|
||||
Example::
|
||||
|
||||
@@ -188,7 +188,7 @@ Miscellaneous functions
|
||||
Takes a 4-tuple (or list) and sends it to the USB host (the PC) to
|
||||
signal a HID mouse-motion event.
|
||||
|
||||
.. note:: This function is deprecated. Use pyb.USB_HID().send(...) instead.
|
||||
.. note:: This function is deprecated. Use :meth:`pyb.USB_HID.send()` instead.
|
||||
|
||||
.. function:: info([dump_alloc_table])
|
||||
|
||||
@@ -254,6 +254,33 @@ Miscellaneous functions
|
||||
|
||||
Returns a string of 12 bytes (96 bits), which is the unique ID of the MCU.
|
||||
|
||||
.. function:: usb_mode([modestr], vid=0xf055, pid=0x9801, hid=pyb.hid_mouse)
|
||||
|
||||
If called with no arguments, return the current USB mode as a string.
|
||||
|
||||
If called with ``modestr`` provided, attempts to set USB mode.
|
||||
This can only be done when called from ``boot.py`` before
|
||||
:meth:`pyb.main()` has been called. The following values of
|
||||
``modestr`` are understood:
|
||||
|
||||
- ``None``: disables USB
|
||||
- ``'VCP'``: enable with VCP (Virtual COM Port) interface
|
||||
- ``'VCP+MSC'``: enable with VCP and MSC (mass storage device class)
|
||||
- ``'VCP+HID'``: enable with VCP and HID (human interface device)
|
||||
|
||||
For backwards compatibility, ``'CDC'`` is understood to mean
|
||||
``'VCP'`` (and similarly for ``'CDC+MSC'`` and ``'CDC+HID'``).
|
||||
|
||||
The ``vid`` and ``pid`` parameters allow you to specify the VID
|
||||
(vendor id) and PID (product id).
|
||||
|
||||
If enabling HID mode, you may also specify the HID details by
|
||||
passing the ``hid`` keyword parameter. It takes a tuple of
|
||||
(subclass, protocol, max packet length, polling interval, report
|
||||
descriptor). By default it will set appropriate values for a USB
|
||||
mouse. There is also a ``pyb.hid_keyboard`` constant, which is an
|
||||
appropriate tuple for a USB keyboard.
|
||||
|
||||
Classes
|
||||
-------
|
||||
|
||||
@@ -277,4 +304,5 @@ Classes
|
||||
pyb.Switch.rst
|
||||
pyb.Timer.rst
|
||||
pyb.UART.rst
|
||||
pyb.USB_HID.rst
|
||||
pyb.USB_VCP.rst
|
||||
|
||||
@@ -17,7 +17,7 @@ Functions
|
||||
.. admonition:: Difference to CPython
|
||||
:class: attention
|
||||
|
||||
If additional argument, `sep` is supplied, it is used as a seperator
|
||||
If additional argument, `sep` is supplied, it is used as a separator
|
||||
between hexadecimal values.
|
||||
|
||||
.. function:: unhexlify(data)
|
||||
|
||||
@@ -13,10 +13,10 @@ Classes
|
||||
.. function:: namedtuple(name, fields)
|
||||
|
||||
This is factory function to create a new namedtuple type with a specific
|
||||
name and set of fields. A namedtyple is a subclass of tuple which allows
|
||||
name and set of fields. A namedtuple is a subclass of tuple which allows
|
||||
to access its fields not just by numeric index, but also with an attribute
|
||||
access syntax using symbolic field names. Fields is a sequence of strings
|
||||
specifying field names. For compatibily with CPython it can also be a
|
||||
specifying field names. For compatibility with CPython it can also be a
|
||||
a string with space-separated field named (but this is less efficient).
|
||||
Example of use::
|
||||
|
||||
|
||||
@@ -118,7 +118,7 @@ Module contents
|
||||
|
||||
.. data:: BIG_ENDIAN
|
||||
|
||||
Layour type for a big-endian packed structure.
|
||||
Layout type for a big-endian packed structure.
|
||||
|
||||
.. data:: NATIVE
|
||||
|
||||
@@ -184,7 +184,7 @@ Subscripting a pointer with other integer values but 0 are supported too,
|
||||
with the same semantics as in C.
|
||||
|
||||
Summing up, accessing structure fields generally follows C syntax,
|
||||
except for pointer derefence, when you need to use ``[0]`` operator
|
||||
except for pointer dereference, when you need to use ``[0]`` operator
|
||||
instead of ``*``.
|
||||
|
||||
Limitations
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
This module implements binary data hashing algorithms. Currently, it
|
||||
implements SHA256 algorithm. Choosing SHA256 was a deliberate choice,
|
||||
as a modern, cryptographically secure algorithm. This means that a
|
||||
single algorithm can cover both usecases of "any hash algorithm" and
|
||||
single algorithm can cover both use cases of "any hash algorithm" and
|
||||
security-related usage, and thus save space omitting legacy algorithms
|
||||
like MD5 or SHA1.
|
||||
|
||||
@@ -53,7 +53,7 @@ Constructors
|
||||
|
||||
Example::
|
||||
|
||||
hash = uhashlib.sha1('abcd1234', 1001) # lenght of the initial piece is multiple of 4 bytes
|
||||
hash = uhashlib.sha1('abcd1234', 1001) # length of the initial piece is multiple of 4 bytes
|
||||
hash.update('1234') # also multiple of 4 bytes
|
||||
...
|
||||
hash.update('12345') # last chunk may be of any length
|
||||
@@ -68,7 +68,7 @@ Methods
|
||||
|
||||
.. method:: hash.digest()
|
||||
|
||||
Return hash for all data passed thru hash, as a bytes object. After this
|
||||
Return hash for all data passed through hash, as a bytes object. After this
|
||||
method is called, more data cannot be fed into hash any longer.
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
@@ -12,7 +12,7 @@ Functions
|
||||
|
||||
.. function:: open(name, mode='r', **kwargs)
|
||||
|
||||
Open a file. Builtin ``open()`` function is alised to this function.
|
||||
Open a file. Builtin ``open()`` function is aliased to this function.
|
||||
All ports (which provide access to file system) are required to support
|
||||
`mode` parameter, but support for other arguments vary by port.
|
||||
|
||||
@@ -38,8 +38,9 @@ Classes
|
||||
opened with "b" modifier). Initial contents of file-like objects
|
||||
can be specified with `string` parameter (should be normal string
|
||||
for `StringIO` or bytes object for `BytesIO`). All the usual file
|
||||
methods like ``read()``, ``write()``, ``close()`` are available on
|
||||
these objects, and additionally, following method:
|
||||
methods like ``read()``, ``write()``, ``seek()``, ``flush()``,
|
||||
``close()`` are available on these objects, and additionally, a
|
||||
following method:
|
||||
|
||||
.. method:: getvalue()
|
||||
|
||||
|
||||
@@ -61,6 +61,29 @@ Functions
|
||||
|
||||
Get the status of a file or directory.
|
||||
|
||||
.. only:: port_unix or port_pyboard or port_esp8266
|
||||
|
||||
.. function:: statvfs(path)
|
||||
|
||||
Get the status of a fileystem.
|
||||
|
||||
Returns a tuple with the filesystem information in the following order:
|
||||
|
||||
* ``f_bsize`` -- file system block size
|
||||
* ``f_frsize`` -- fragment size
|
||||
* ``f_blocks`` -- size of fs in f_frsize units
|
||||
* ``f_bfree`` -- number of free blocks
|
||||
* ``f_bavail`` -- number of free blocks for unpriviliged users
|
||||
* ``f_files`` -- number of inodes
|
||||
* ``f_ffree`` -- number of free inodes
|
||||
* ``f_favail`` -- number of free inodes for unpriviliged users
|
||||
* ``f_flag`` -- mount flags
|
||||
* ``f_namemax`` -- maximum filename length
|
||||
|
||||
Parameters related to inodes: ``f_files``, ``f_ffree``, ``f_avail``
|
||||
and the ``f_flags`` parameter may return ``0`` as they can be unavailable
|
||||
in a port-specific implementation.
|
||||
|
||||
.. function:: sync()
|
||||
|
||||
Sync all filesystems.
|
||||
@@ -81,7 +104,7 @@ Functions
|
||||
|
||||
.. function:: unmount(path)
|
||||
|
||||
Unmounts a prevoulsy mounted block device from the given path.
|
||||
Unmounts a previously mounted block device from the given path.
|
||||
|
||||
.. function:: mkfs(block_device or path)
|
||||
|
||||
|
||||
@@ -117,7 +117,7 @@ Functions
|
||||
.. function:: time()
|
||||
|
||||
Returns the number of seconds, as an integer, since the Epoch, assuming that underlying
|
||||
RTC is set and maintained as decsribed above. If an RTC is not set, this function returns
|
||||
RTC is set and maintained as described above. If an RTC is not set, this function returns
|
||||
number of seconds since a port-specific reference point in time (for embedded boards without
|
||||
a battery-backed RTC, usually since power up or reset). If you want to develop portable
|
||||
MicroPython application, you should not rely on this function to provide higher than second
|
||||
|
||||
@@ -3,6 +3,12 @@
|
||||
Quick reference for the pyboard
|
||||
===============================
|
||||
|
||||
The below pinout is for PYBv1.0. You can also view pinouts for
|
||||
other versions of the pyboard:
|
||||
`PYBv1.1 <http://micropython.org/resources/pybv11-pinout.jpg>`__
|
||||
or `PYBLITEv1.0-AC <http://micropython.org/resources/pyblitev10ac-pinout.jpg>`__
|
||||
or `PYBLITEv1.0 <http://micropython.org/resources/pyblitev10-pinout.jpg>`__.
|
||||
|
||||
.. image:: http://micropython.org/resources/pybv10-pinout.jpg
|
||||
:alt: PYBv1.0 pinout
|
||||
:width: 700px
|
||||
@@ -14,14 +20,25 @@ See :mod:`pyb`. ::
|
||||
|
||||
import pyb
|
||||
|
||||
pyb.delay(50) # wait 50 milliseconds
|
||||
pyb.millis() # number of milliseconds since bootup
|
||||
pyb.repl_uart(pyb.UART(1, 9600)) # duplicate REPL on UART(1)
|
||||
pyb.wfi() # pause CPU, waiting for interrupt
|
||||
pyb.freq() # get CPU and bus frequencies
|
||||
pyb.freq(60000000) # set CPU freq to 60MHz
|
||||
pyb.stop() # stop CPU, waiting for external interrupt
|
||||
|
||||
Delay and timing
|
||||
----------------
|
||||
|
||||
Use the :mod:`time <utime>` module::
|
||||
|
||||
import time
|
||||
|
||||
time.sleep(1) # sleep for 1 second
|
||||
time.sleep_ms(500) # sleep for 500 milliseconds
|
||||
time.sleep_us(10) # sleep for 10 microseconds
|
||||
start = time.ticks_ms() # get value of millisecond counter
|
||||
delta = time.ticks_diff(start, time.ticks_ms()) # compute time difference
|
||||
|
||||
LEDs
|
||||
----
|
||||
|
||||
|
||||
@@ -95,7 +95,7 @@ We set up timer 2 as follows::
|
||||
|
||||
The prescaler is set at 83, which makes this timer count at 1 MHz.
|
||||
This is because the CPU clock, running at 168 MHz, is divided by
|
||||
2 and then by prescaler+1, giving a freqency of 168 MHz/2/(83+1)=1 MHz
|
||||
2 and then by prescaler+1, giving a frequency of 168 MHz/2/(83+1)=1 MHz
|
||||
for timer 2. The period is set to a large number so that the timer
|
||||
can count up to a large number before wrapping back around to zero.
|
||||
In this case it will take about 17 minutes before it cycles back to
|
||||
|
||||
@@ -13,23 +13,23 @@ will look something like this::
|
||||
|
||||
import pyb
|
||||
#pyb.main('main.py') # main script to run after this one
|
||||
#pyb.usb_mode('CDC+MSC') # act as a serial and a storage device
|
||||
#pyb.usb_mode('CDC+HID') # act as a serial device and a mouse
|
||||
#pyb.usb_mode('VCP+MSC') # act as a serial and a storage device
|
||||
#pyb.usb_mode('VCP+HID') # act as a serial device and a mouse
|
||||
|
||||
To enable the mouse mode, uncomment the last line of the file, to
|
||||
make it look like::
|
||||
|
||||
pyb.usb_mode('CDC+HID') # act as a serial device and a mouse
|
||||
pyb.usb_mode('VCP+HID') # act as a serial device and a mouse
|
||||
|
||||
If you already changed your ``boot.py`` file, then the minimum code it
|
||||
needs to work is::
|
||||
|
||||
import pyb
|
||||
pyb.usb_mode('CDC+HID')
|
||||
pyb.usb_mode('VCP+HID')
|
||||
|
||||
This tells the pyboard to configure itself as a CDC (serial) and HID
|
||||
(human interface device, in our case a mouse) USB device when it boots
|
||||
up.
|
||||
This tells the pyboard to configure itself as a VCP (Virtual COM Port,
|
||||
ie serial port) and HID (human interface device, in our case a mouse)
|
||||
USB device when it boots up.
|
||||
|
||||
Eject/unmount the pyboard drive and reset it using the RST switch.
|
||||
Your PC should now detect the pyboard as a mouse!
|
||||
@@ -41,7 +41,8 @@ To get the py-mouse to do anything we need to send mouse events to the PC.
|
||||
We will first do this manually using the REPL prompt. Connect to your
|
||||
pyboard using your serial program and type the following::
|
||||
|
||||
>>> pyb.hid((0, 10, 0, 0))
|
||||
>>> hid = pyb.USB_HID()
|
||||
>>> hid.send((0, 10, 0, 0))
|
||||
|
||||
Your mouse should move 10 pixels to the right! In the command above you
|
||||
are sending 4 pieces of information: button status, x, y and scroll. The
|
||||
@@ -52,7 +53,7 @@ Let's make the mouse oscillate left and right::
|
||||
>>> import math
|
||||
>>> def osc(n, d):
|
||||
... for i in range(n):
|
||||
... pyb.hid((0, int(20 * math.sin(i / 10)), 0, 0))
|
||||
... hid.send((0, int(20 * math.sin(i / 10)), 0, 0))
|
||||
... pyb.delay(d)
|
||||
...
|
||||
>>> osc(100, 50)
|
||||
@@ -61,7 +62,7 @@ The first argument to the function ``osc`` is the number of mouse events to send
|
||||
and the second argument is the delay (in milliseconds) between events. Try
|
||||
playing around with different numbers.
|
||||
|
||||
**Excercise: make the mouse go around in a circle.**
|
||||
**Exercise: make the mouse go around in a circle.**
|
||||
|
||||
Making a mouse with the accelerometer
|
||||
-------------------------------------
|
||||
@@ -85,14 +86,14 @@ the [safe mode tutorial](tut-reset), but we repeat the instructions here:
|
||||
3. The LEDs will then cycle green to orange to green+orange and back again.
|
||||
4. Keep holding down USR until *only the orange LED is lit*, and then let
|
||||
go of the USR switch.
|
||||
5. The orange LED should flash quickly 4 times, and then turn off.
|
||||
5. The orange LED should flash quickly 4 times, and then turn off.
|
||||
6. You are now in safe mode.
|
||||
|
||||
In safe mode, the ``boot.py`` and ``main.py`` files are not executed, and so
|
||||
the pyboard boots up with default settings. This means you now have access
|
||||
to the filesystem (the USB drive should appear), and you can edit ``main.py``.
|
||||
(Leave ``boot.py`` as-is, because we still want to go back to HID-mode after
|
||||
we finish editting ``main.py``.)
|
||||
we finish editing ``main.py``.)
|
||||
|
||||
In ``main.py`` put the following code::
|
||||
|
||||
@@ -100,9 +101,10 @@ In ``main.py`` put the following code::
|
||||
|
||||
switch = pyb.Switch()
|
||||
accel = pyb.Accel()
|
||||
hid = pyb.USB_HID()
|
||||
|
||||
while not switch():
|
||||
pyb.hid((0, accel.x(), accel.y(), 0))
|
||||
hid.send((0, accel.x(), accel.y(), 0))
|
||||
pyb.delay(20)
|
||||
|
||||
Save your file, eject/unmount your pyboard drive, and reset it using the RST
|
||||
@@ -112,7 +114,7 @@ the mouse around. Try it out, and see if you can make the mouse stand still!
|
||||
Press the USR switch to stop the mouse motion.
|
||||
|
||||
You'll note that the y-axis is inverted. That's easy to fix: just put a
|
||||
minus sign in front of the y-coordinate in the ``pyb.hid()`` line above.
|
||||
minus sign in front of the y-coordinate in the ``hid.send()`` line above.
|
||||
|
||||
Restoring your pyboard to normal
|
||||
--------------------------------
|
||||
@@ -121,9 +123,9 @@ If you leave your pyboard as-is, it'll behave as a mouse everytime you plug
|
||||
it in. You probably want to change it back to normal. To do this you need
|
||||
to first enter safe mode (see above), and then edit the ``boot.py`` file.
|
||||
In the ``boot.py`` file, comment out (put a # in front of) the line with the
|
||||
``CDC+HID`` setting, so it looks like::
|
||||
``VCP+HID`` setting, so it looks like::
|
||||
|
||||
#pyb.usb_mode('CDC+HID') # act as a serial device and a mouse
|
||||
#pyb.usb_mode('VCP+HID') # act as a serial device and a mouse
|
||||
|
||||
Save your file, eject/unmount the drive, and reset the pyboard. It is now
|
||||
back to normal operating mode.
|
||||
|
||||
@@ -129,7 +129,7 @@ Non-integer data types
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
These may be handled by means of arrays of the appropriate data type. For
|
||||
example, single precison floating point data may be processed as follows.
|
||||
example, single precision floating point data may be processed as follows.
|
||||
This code example takes an array of floats and replaces its contents with
|
||||
their squares.
|
||||
|
||||
@@ -172,7 +172,7 @@ thus:
|
||||
|
||||
The const() construct causes MicroPython to replace the variable name
|
||||
with its value at compile time. If constants are declared in an outer
|
||||
Python scope they can be shared between mutiple assembler functions and
|
||||
Python scope they can be shared between multiple assembler functions and
|
||||
with Python code.
|
||||
|
||||
Assembler code as class methods
|
||||
|
||||
@@ -23,7 +23,7 @@ specifiers:
|
||||
* ne Not equal
|
||||
* cs Carry set
|
||||
* cc Carry clear
|
||||
* mi Minus (negaive)
|
||||
* mi Minus (negative)
|
||||
* pl Plus (positive)
|
||||
* vs Overflow set
|
||||
* vc Overflow clear
|
||||
|
||||
456
docs/reference/constrained.rst
Normal file
456
docs/reference/constrained.rst
Normal file
@@ -0,0 +1,456 @@
|
||||
.. _constrained:
|
||||
|
||||
MicroPython on Microcontrollers
|
||||
===============================
|
||||
|
||||
MicroPython is designed to be capable of running on microcontrollers. These
|
||||
have hardware limitations which may be unfamiliar to programmers more familiar
|
||||
with conventional computers. In particular the amount of RAM and nonvolatile
|
||||
"disk" (flash memory) storage is limited. This tutorial offers ways to make
|
||||
the most of the limited resources. Because MicroPython runs on controllers
|
||||
based on a variety of architectures, the methods presented are generic: in some
|
||||
cases it will be necessary to obtain detailed information from platform specific
|
||||
documentation.
|
||||
|
||||
Flash Memory
|
||||
------------
|
||||
|
||||
On the Pyboard the simple way to address the limited capacity is to fit a micro
|
||||
SD card. In some cases this is impractical, either because the device does not
|
||||
have an SD card slot or for reasons of cost or power consumption; hence the
|
||||
on-chip flash must be used. The firmware including the MicroPython subsystem is
|
||||
stored in the onboard flash. The remaining capacity is available for use. For
|
||||
reasons connected with the physical architecture of the flash memory part of
|
||||
this capacity may be inaccessible as a filesystem. In such cases this space may
|
||||
be employed by incorporating user modules into a firmware build which is then
|
||||
flashed to the device.
|
||||
|
||||
There are two ways to achieve this: frozen modules and frozen bytecode. Frozen
|
||||
modules store the Python source with the firmware. Frozen bytecode uses the
|
||||
cross compiler to convert the source to bytecode which is then stored with the
|
||||
firmware. In either case the module may be accessed with an import statement:
|
||||
|
||||
.. code::
|
||||
|
||||
import mymodule
|
||||
|
||||
The procedure for producing frozen modules and bytecode is platform dependent;
|
||||
instructions for building the firmware can be found in the README files in the
|
||||
relevant part of the source tree.
|
||||
|
||||
In general terms the steps are as follows:
|
||||
|
||||
* Clone the MicroPython `repository <https://github.com/micropython/micropython>`_.
|
||||
* Acquire the (platform specific) toolchain to build the firmware.
|
||||
* Build the cross compiler.
|
||||
* Place the modules to be frozen in a specified directory (dependent on whether
|
||||
the module is to be frozen as source or as bytecode).
|
||||
* Build the firmware. A specific command may be required to build frozen
|
||||
code of either type - see the platform documentation.
|
||||
* Flash the firmware to the device.
|
||||
|
||||
RAM
|
||||
---
|
||||
|
||||
When reducing RAM usage there are two phases to consider: compilation and
|
||||
execution. In addition to memory consumption, there is also an issue known as
|
||||
heap fragmentation. In general terms it is best to minimise the repeated
|
||||
creation and destruction of objects. The reason for this is covered in the
|
||||
section covering the `heap`_.
|
||||
|
||||
Compilation Phase
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
When a module is imported, MicroPython compiles the code to bytecode which is
|
||||
then executed by the MicroPython virtual machine (VM). The bytecode is stored
|
||||
in RAM. The compiler itself requires RAM, but this becomes available for use
|
||||
when the compilation has completed.
|
||||
|
||||
If a number of modules have already been imported the situation can arise where
|
||||
there is insufficient RAM to run the compiler. In this case the import
|
||||
statement will produce a memory exception.
|
||||
|
||||
If a module instantiates global objects on import it will consume RAM at the
|
||||
time of import, which is then unavailable for the compiler to use on subsequent
|
||||
imports. In general it is best to avoid code which runs on import; a better
|
||||
approach is to have initialisation code which is run by the application after
|
||||
all modules have been imported. This maximises the RAM available to the
|
||||
compiler.
|
||||
|
||||
If RAM is still insufficient to compile all modules one solution is to
|
||||
precompile modules. MicroPython has a cross compiler capable of compiling Python
|
||||
modules to bytecode (see the README in the mpy-cross directory). The resulting
|
||||
bytecode file has a .mpy extension; it may be copied to the filesystem and
|
||||
imported in the usual way. Alternatively some or all modules may be implemented
|
||||
as frozen bytecode: on most platforms this saves even more RAM as the bytecode
|
||||
is run directly from flash rather than being stored in RAM.
|
||||
|
||||
Execution Phase
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
There are a number of coding techniques for reducing RAM usage.
|
||||
|
||||
**Constants**
|
||||
|
||||
MicroPython provides a ``const`` keyword which may be used as follows:
|
||||
|
||||
.. code::
|
||||
|
||||
from micropython import const
|
||||
ROWS = const(33)
|
||||
_COLS = const(0x10)
|
||||
a = ROWS
|
||||
b = _COLS
|
||||
|
||||
In both instances where the constant is assigned to a variable the compiler
|
||||
will avoid coding a lookup to the name of the constant by substituting its
|
||||
literal value. This saves bytecode and hence RAM. However the ``ROWS`` value
|
||||
will occupy at least two machine words, one each for the key and value in the
|
||||
globals dictionary. The presence in the dictionary is necessary because another
|
||||
module might import or use it. This RAM can be saved by prepending the name
|
||||
with an underscore as in ``_COLS``: this symbol is not visible outside the
|
||||
module so will not occupy RAM.
|
||||
|
||||
The argument to ``const()`` may be anything which, at compile time, evaluates
|
||||
to an integer e.g. ``0x100`` or ``1 << 8``. It can even include other const
|
||||
symbols that have already been defined, e.g. ``1 << BIT``.
|
||||
|
||||
**Constant data structures**
|
||||
|
||||
Where there is a substantial volume of constant data and the platform supports
|
||||
execution from Flash, RAM may be saved as follows. The data should be located in
|
||||
Python modules and frozen as bytecode. The data must be defined as ``bytes``
|
||||
objects. The compiler 'knows' that ``bytes`` objects are immutable and ensures
|
||||
that the objects remain in flash memory rather than being copied to RAM. The
|
||||
``ustruct`` module can assist in converting between ``bytes`` types and other
|
||||
Python built-in types.
|
||||
|
||||
When considering the implications of frozen bytecode, note that in Python
|
||||
strings, floats, bytes, integers and complex numbers are immutable. Accordingly
|
||||
these will be frozen into flash. Thus, in the line
|
||||
|
||||
.. code::
|
||||
|
||||
mystring = "The quick brown fox"
|
||||
|
||||
the actual string "The quick brown fox" will reside in flash. At runtime a
|
||||
reference to the string is assigned to the *variable* ``mystring``. The reference
|
||||
occupies a single machine word. In principle a long integer could be used to
|
||||
store constant data:
|
||||
|
||||
.. code::
|
||||
|
||||
bar = 0xDEADBEEF0000DEADBEEF
|
||||
|
||||
As in the string example, at runtime a reference to the arbitrarily large
|
||||
integer is assigned to the variable ``bar``. That reference occupies a
|
||||
single machine word.
|
||||
|
||||
It might be expected that tuples of integers could be employed for the purpose
|
||||
of storing constant data with minimal RAM use. With the current compiler this
|
||||
is ineffective (the code works, but RAM is not saved).
|
||||
|
||||
.. code::
|
||||
|
||||
foo = (1, 2, 3, 4, 5, 6, 100000)
|
||||
|
||||
At runtime the tuple will be located in RAM. This may be subject to future
|
||||
improvement.
|
||||
|
||||
**Needless object creation**
|
||||
|
||||
There are a number of situations where objects may unwittingly be created and
|
||||
destroyed. This can reduce the usability of RAM through fragmentation. The
|
||||
following sections discuss instances of this.
|
||||
|
||||
**String concatenation**
|
||||
|
||||
Consider the following code fragments which aim to produce constant strings:
|
||||
|
||||
.. code::
|
||||
|
||||
var = "foo" + "bar"
|
||||
var1 = "foo" "bar"
|
||||
var2 = """\
|
||||
foo\
|
||||
bar"""
|
||||
|
||||
Each produces the same outcome, however the first needlessly creates two string
|
||||
objects at runtime, allocates more RAM for concatenation before producing the
|
||||
third. The others perform the concatenation at compile time which is more
|
||||
efficient, reducing fragmentation.
|
||||
|
||||
Where strings must be dynamically created before being fed to a stream such as
|
||||
a file it will save RAM if this is done in a piecemeal fashion. Rather than
|
||||
creating a large string object, create a substring and feed it to the stream
|
||||
before dealing with the next.
|
||||
|
||||
The best way to create dynamic strings is by means of the string ``format``
|
||||
method:
|
||||
|
||||
.. code::
|
||||
|
||||
var = "Temperature {:5.2f} Pressure {:06d}\n".format(temp, press)
|
||||
|
||||
**Buffers**
|
||||
|
||||
When accessing devices such as instances of UART, I2C and SPI interfaces, using
|
||||
pre-allocated buffers avoids the creation of needless objects. Consider these
|
||||
two loops:
|
||||
|
||||
.. code::
|
||||
|
||||
while True:
|
||||
var = spi.read(100)
|
||||
# process data
|
||||
|
||||
buf = bytearray(100)
|
||||
while True:
|
||||
spi.readinto(buf)
|
||||
# process data in buf
|
||||
|
||||
The first creates a buffer on each pass whereas the second re-uses a pre-allocated
|
||||
buffer; this is both faster and more efficient in terms of memory fragmentation.
|
||||
|
||||
**Bytes are smaller than ints**
|
||||
|
||||
On most platforms an integer consumes four bytes. Consider the two calls to the
|
||||
function ``foo()``:
|
||||
|
||||
.. code::
|
||||
|
||||
def foo(bar):
|
||||
for x in bar:
|
||||
print(x)
|
||||
foo((1, 2, 0xff))
|
||||
foo(b'\1\2\xff')
|
||||
|
||||
In the first call a tuple of integers is created in RAM. The second efficiently
|
||||
creates a ``bytes`` object consuming the minimum amount of RAM. If the module
|
||||
were frozen as bytecode, the ``bytes`` object would reside in flash.
|
||||
|
||||
**Strings Versus Bytes**
|
||||
|
||||
Python3 introduced Unicode support. This introduced a distinction between a
|
||||
string and an array of bytes. MicroPython ensures that Unicode strings take no
|
||||
additional space so long as all characters in the string are ASCII (i.e. have
|
||||
a value < 126). If values in the full 8-bit range are required ``bytes`` and
|
||||
``bytearray`` objects can be used to ensure that no additional space will be
|
||||
required. Note that most string methods (e.g. ``strip()``) apply also to ``bytes``
|
||||
instances so the process of eliminating Unicode can be painless.
|
||||
|
||||
.. code::
|
||||
|
||||
s = 'the quick brown fox' # A string instance
|
||||
b = b'the quick brown fox' # a bytes instance
|
||||
|
||||
Where it is necessary to convert between strings and bytes the string ``encode``
|
||||
and the bytes ``decode`` methods can be used. Note that both strings and bytes
|
||||
are immutable. Any operation which takes as input such an object and produces
|
||||
another implies at least one RAM allocation to produce the result. In the
|
||||
second line below a new bytes object is allocated. This would also occur if ``foo``
|
||||
were a string.
|
||||
|
||||
.. code::
|
||||
|
||||
foo = b' empty whitespace'
|
||||
foo = foo.lstrip()
|
||||
|
||||
**Runtime compiler execution**
|
||||
|
||||
The Python keywords ``eval`` and ``exec`` invoke the compiler at runtime, which
|
||||
requires significant amounts of RAM. Note that the ``pickle`` library employs
|
||||
``exec``. It may be more RAM efficient to use the ``json`` library for object
|
||||
serialisation.
|
||||
|
||||
**Storing strings in flash**
|
||||
|
||||
Python strings are immutable hence have the potential to be stored in read only
|
||||
memory. The compiler can place in flash strings defined in Python code. As with
|
||||
frozen modules it is necessary to have a copy of the source tree on the PC and
|
||||
the toolchain to build the firmware. The procedure will work even if the
|
||||
modules have not been fully debugged, so long as they can be imported and run.
|
||||
|
||||
After importing the modules, execute:
|
||||
|
||||
.. code::
|
||||
|
||||
micropython.qstr_info(1)
|
||||
|
||||
Then copy and paste all the Q(xxx) lines into a text editor. Check for and
|
||||
remove lines which are obviously invalid. Open the file qstrdefsport.h which
|
||||
will be found in stmhal (or the equivalent directory for the architecture in
|
||||
use). Copy and paste the corrected lines at the end of the file. Save the file,
|
||||
rebuild and flash the firmware. The outcome can be checked by importing the
|
||||
modules and again issuing:
|
||||
|
||||
.. code::
|
||||
|
||||
micropython.qstr_info(1)
|
||||
|
||||
The Q(xxx) lines should be gone.
|
||||
|
||||
.. _heap:
|
||||
|
||||
The Heap
|
||||
--------
|
||||
|
||||
When a running program instantiates an object the necessary RAM is allocated
|
||||
from a fixed size pool known as the heap. When the object goes out of scope (in
|
||||
other words becomes inaccessible to code) the redundant object is known as
|
||||
"garbage". A process known as "garbage collection" (GC) reclaims that memory,
|
||||
returning it to the free heap. This process runs automatically, however it can
|
||||
be invoked directly by issuing ``gc.collect()``.
|
||||
|
||||
The discourse on this is somewhat involved. For a 'quick fix' issue the
|
||||
following periodically:
|
||||
|
||||
.. code::
|
||||
|
||||
gc.collect()
|
||||
gc.threshold(gc.mem_free() // 4 + gc.mem_alloc())
|
||||
|
||||
Fragmentation
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
Say a program creates an object ``foo``, then an object ``bar``. Subsequently
|
||||
``foo`` goes out of scope but ``bar`` remains. The RAM used by ``foo`` will be
|
||||
reclaimed by GC. However if ``bar`` was allocated to a higher address, the
|
||||
RAM reclaimed from ``foo`` will only be of use for objects no bigger than
|
||||
``foo``. In a complex or long running program the heap can become fragmented:
|
||||
despite there being a substantial amount of RAM available, there is insufficient
|
||||
contiguous space to allocate a particular object, and the program fails with a
|
||||
memory error.
|
||||
|
||||
The techniques outlined above aim to minimise this. Where large permanent buffers
|
||||
or other objects are required it is best to instantiate these early in the
|
||||
process of program execution before fragmentation can occur. Further improvements
|
||||
may be made by monitoring the state of the heap and by controlling GC; these are
|
||||
outlined below.
|
||||
|
||||
Reporting
|
||||
~~~~~~~~~
|
||||
|
||||
A number of library functions are available to report on memory allocation and
|
||||
to control GC. These are to be found in the ``gc`` and ``micropython`` modules.
|
||||
The following example may be pasted at the REPL (``ctrl e`` to enter paste mode,
|
||||
``ctrl d`` to run it).
|
||||
|
||||
.. code::
|
||||
|
||||
import gc
|
||||
import micropython
|
||||
gc.collect()
|
||||
micropython.mem_info()
|
||||
print('-----------------------------')
|
||||
print('Initial free: {} allocated: {}'.format(gc.mem_free(), gc.mem_alloc()))
|
||||
def func():
|
||||
a = bytearray(10000)
|
||||
gc.collect()
|
||||
print('Func definition: {} allocated: {}'.format(gc.mem_free(), gc.mem_alloc()))
|
||||
func()
|
||||
print('Func run free: {} allocated: {}'.format(gc.mem_free(), gc.mem_alloc()))
|
||||
gc.collect()
|
||||
print('Garbage collect free: {} allocated: {}'.format(gc.mem_free(), gc.mem_alloc()))
|
||||
print('-----------------------------')
|
||||
micropython.mem_info(1)
|
||||
|
||||
Methods employed above:
|
||||
|
||||
* ``gc.collect()`` Force a garbage collection. See footnote.
|
||||
* ``micropython.mem_info()`` Print a summary of RAM utilisation.
|
||||
* ``gc.mem_free()`` Return the free heap size in bytes.
|
||||
* ``gc.mem_alloc()`` Return the number of bytes currently allocated.
|
||||
* ``micropython.mem_info(1)`` Print a table of heap utilisation (detailed below).
|
||||
|
||||
The numbers produced are dependent on the platform, but it can be seen that
|
||||
declaring the function uses a small amount of RAM in the form of bytecode
|
||||
emitted by the compiler (the RAM used by the compiler has been reclaimed).
|
||||
Running the function uses over 10KiB, but on return ``a`` is garbage because it
|
||||
is out of scope and cannot be referenced. The final ``gc.collect()`` recovers
|
||||
that memory.
|
||||
|
||||
The final output produced by ``micropython.mem_info(1)`` will vary in detail but
|
||||
may be interpreted as follows:
|
||||
|
||||
====== =================
|
||||
Symbol Meaning
|
||||
====== =================
|
||||
. free block
|
||||
h head block
|
||||
= tail block
|
||||
m marked head block
|
||||
T tuple
|
||||
L list
|
||||
D dict
|
||||
F float
|
||||
B byte code
|
||||
M module
|
||||
====== =================
|
||||
|
||||
Each letter represents a single block of memory, a block being 16 bytes. So each
|
||||
line of the heap dump represents 0x400 bytes or 1KiB of RAM.
|
||||
|
||||
Control of Garbage Collection
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
A GC can be demanded at any time by issuing ``gc.collect()``. It is advantageous
|
||||
to do this at intervals, firstly to pre-empt fragmentation and secondly for
|
||||
performance. A GC can take several milliseconds but is quicker when there is
|
||||
little work to do (about 1ms on the Pyboard). An explicit call can minimise that
|
||||
delay while ensuring it occurs at points in the program when it is acceptable.
|
||||
|
||||
Automatic GC is provoked under the following circumstances. When an attempt at
|
||||
allocation fails, a GC is performed and the allocation re-tried. Only if this
|
||||
fails is an exception raised. Secondly an automatic GC will be triggered if the
|
||||
amount of free RAM falls below a threshold. This threshold can be adapted as
|
||||
execution progresses:
|
||||
|
||||
.. code::
|
||||
|
||||
gc.collect()
|
||||
gc.threshold(gc.mem_free() // 4 + gc.mem_alloc())
|
||||
|
||||
This will provoke a GC when more than 25% of the currently free heap becomes
|
||||
occupied.
|
||||
|
||||
In general modules should instantiate data objects at runtime using constructors
|
||||
or other initialisation functions. The reason is that if this occurs on
|
||||
initialisation the compiler may be starved of RAM when subsequent modules are
|
||||
imported. If modules do instantiate data on import then ``gc.collect()`` issued
|
||||
after the import will ameliorate the problem.
|
||||
|
||||
String Operations
|
||||
-----------------
|
||||
|
||||
MicroPython handles strings in an efficient manner and understanding this can
|
||||
help in designing applications to run on microcontrollers. When a module
|
||||
is compiled, strings which occur multiple times are stored once only, a process
|
||||
known as string interning. In MicroPython an interned string is known as a ``qstr``.
|
||||
In a module imported normally that single instance will be located in RAM, but
|
||||
as described above, in modules frozen as bytecode it will be located in flash.
|
||||
|
||||
String comparisons are also performed efficiently using hashing rather than
|
||||
character by character. The penalty for using strings rather than integers may
|
||||
hence be small both in terms of performance and RAM usage - a fact which may
|
||||
come as a surprise to C programmers.
|
||||
|
||||
Postscript
|
||||
----------
|
||||
|
||||
MicroPython passes, returns and (by default) copies objects by reference. A
|
||||
reference occupies a single machine word so these processes are efficient in
|
||||
RAM usage and speed.
|
||||
|
||||
Where variables are required whose size is neither a byte nor a machine word
|
||||
there are standard libraries which can assist in storing these efficiently and
|
||||
in performing conversions. See the ``array``, ``ustruct`` and ``uctypes``
|
||||
modules.
|
||||
|
||||
Footnote: gc.collect() return value
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
On Unix and Windows platforms the ``gc.collect()`` method returns an integer
|
||||
which signifies the number of distinct memory regions that were reclaimed in the
|
||||
collection (more precisely, the number of heads that were turned into frees). For
|
||||
efficiency reasons bare metal ports do not return this value.
|
||||
@@ -15,6 +15,7 @@ MicroPython are described in the sections here.
|
||||
repl.rst
|
||||
isr_rules.rst
|
||||
speed_python.rst
|
||||
constrained.rst
|
||||
|
||||
.. only:: port_pyboard
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ This summarises the points detailed below and lists the principal recommendation
|
||||
* Where an ISR returns multiple bytes use a pre-allocated ``bytearray``. If multiple integers are to be
|
||||
shared between an ISR and the main program consider an array (``array.array``).
|
||||
* Where data is shared between the main program and an ISR, consider disabling interrupts prior to accessing
|
||||
the data in the main program and re-enabling them immediately afterwards (see Critcal Sections).
|
||||
the data in the main program and re-enabling them immediately afterwards (see Critical Sections).
|
||||
* Allocate an emergency exception buffer (see below).
|
||||
|
||||
|
||||
@@ -110,6 +110,19 @@ the flag. The memory allocation occurs in the main program code when the object
|
||||
The MicroPython library I/O methods usually provide an option to use a pre-allocated buffer. For
|
||||
example ``pyb.i2c.recv()`` can accept a mutable buffer as its first argument: this enables its use in an ISR.
|
||||
|
||||
A means of creating an object without employing a class or globals is as follows:
|
||||
|
||||
.. code:: python
|
||||
|
||||
def set_volume(t, buf=bytearray(3)):
|
||||
buf[0] = 0xa5
|
||||
buf[1] = t >> 4
|
||||
buf[2] = 0x5a
|
||||
return buf
|
||||
|
||||
The compiler instantiates the default ``buf`` argument when the function is
|
||||
loaded for the first time (usually when the module it's in is imported).
|
||||
|
||||
Use of Python objects
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -300,3 +313,20 @@ that access to the critical variables is denied. A simple example of a mutex may
|
||||
but only for the duration of eight machine instructions: the benefit of this approach is that other interrupts are
|
||||
virtually unaffected.
|
||||
|
||||
Interrupts and the REPL
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Interrupt handlers, such as those associated with timers, can continue to run
|
||||
after a program terminates. This may produce unexpected results where you might
|
||||
have expected the object raising the callback to have gone out of scope. For
|
||||
example on the Pyboard:
|
||||
|
||||
.. code:: python
|
||||
|
||||
def bar():
|
||||
foo = pyb.Timer(2, freq=4, callback=lambda t: print('.', end=''))
|
||||
|
||||
bar()
|
||||
|
||||
This continues to run until the timer is explicitly disabled or the board is
|
||||
reset with ``ctrl D``.
|
||||
|
||||
@@ -50,7 +50,7 @@ Finally type ``print(i)``, press RETURN, press BACKSPACE and press RETURN again:
|
||||
>>>
|
||||
|
||||
Auto-indent won't be applied if the previous two lines were all spaces. This
|
||||
means that you can finish entering a compound statment by pressing RETURN
|
||||
means that you can finish entering a compound statement by pressing RETURN
|
||||
twice, and then a third press will finish and execute.
|
||||
|
||||
Auto-completion
|
||||
@@ -80,7 +80,7 @@ expansions:
|
||||
Interrupting a running program
|
||||
------------------------------
|
||||
|
||||
You can interupt a running program by pressing Ctrl-C. This will raise a KeyboardInterrupt
|
||||
You can interrupt a running program by pressing Ctrl-C. This will raise a KeyboardInterrupt
|
||||
which will bring you back to the REPL, providing your program doesn't intercept the
|
||||
KeyboardInterrupt exception.
|
||||
|
||||
@@ -184,8 +184,8 @@ variables no longer exist:
|
||||
The special variable _ (underscore)
|
||||
-----------------------------------
|
||||
|
||||
When you use the REPL, you may perfom computations and see the results.
|
||||
MicroPython stores the results of the previous statment in the variable _ (underscore).
|
||||
When you use the REPL, you may perform computations and see the results.
|
||||
MicroPython stores the results of the previous statement in the variable _ (underscore).
|
||||
So you can use the underscore to save the result in a variable. For example:
|
||||
|
||||
>>> 1 + 2 + 3 + 4 + 5
|
||||
|
||||
@@ -14,18 +14,18 @@ all divisions must be performed using '//' instead of '/'. Example::
|
||||
Before applying power
|
||||
---------------------
|
||||
|
||||
.. warning::
|
||||
.. warning::
|
||||
|
||||
The GPIO pins of the WiPy are NOT 5V tolerant, connecting them to voltages higer
|
||||
than 3.6V will cause irreparable damage to the board. ADC pins, when configured
|
||||
The GPIO pins of the WiPy are NOT 5V tolerant, connecting them to voltages higher
|
||||
than 3.6V will cause irreparable damage to the board. ADC pins, when configured
|
||||
in analog mode cannot withstand voltages above 1.8V. Keep these considerations in
|
||||
mind when wiring your electronics.
|
||||
|
||||
WLAN default behaviour
|
||||
----------------------
|
||||
|
||||
When the WiPy boots with the default factory configuration starts in Access Point
|
||||
mode with ``ssid`` that starts with: ``wipy-wlan`` and ``key: www.wipy.io``.
|
||||
When the WiPy boots with the default factory configuration starts in Access Point
|
||||
mode with ``ssid`` that starts with: ``wipy-wlan`` and ``key: www.wipy.io``.
|
||||
Connect to this network and the WiPy will be reachable at ``192.168.1.1``. In order
|
||||
to gain access to the interactive prompt, open a telnet session to that IP address on
|
||||
the default port (23). You will be asked for credentials:
|
||||
@@ -98,7 +98,7 @@ the WiPy by pressing the switch on the board, or by typing::
|
||||
>>> import machine
|
||||
>>> machine.reset()
|
||||
|
||||
Software updates can be found in: https://github.com/wipy/wipy/releases (**Binaries.zip**).
|
||||
Software updates can be found in: https://github.com/wipy/wipy/releases (**Binaries.zip**).
|
||||
It's always recommended to update to the latest software, but make sure to
|
||||
read the **release notes** before.
|
||||
|
||||
@@ -122,7 +122,7 @@ Boot modes and safe boot
|
||||
------------------------
|
||||
|
||||
If you power up normally, or press the reset button, the WiPy will boot
|
||||
into standard mode; the ``boot.py`` file will be executed first, then
|
||||
into standard mode; the ``boot.py`` file will be executed first, then
|
||||
``main.py`` will run.
|
||||
|
||||
You can override this boot sequence by pulling ``GP28`` **up** (connect
|
||||
@@ -178,4 +178,4 @@ Details on sleep modes
|
||||
configuration required.
|
||||
* ``machine.sleep()``: 950uA (in WLAN STA mode). Wake sources are ``Pin``, ``RTC``
|
||||
and ``WLAN``
|
||||
* ``machine.deepsleep()``: ~5uA. Wake sources are ``Pin`` and ``RTC``.
|
||||
* ``machine.deepsleep()``: ~350uA. Wake sources are ``Pin`` and ``RTC``.
|
||||
|
||||
@@ -51,11 +51,10 @@ See :ref:`machine.Timer <machine.Timer>` and :ref:`machine.Pin <machine.Pin>`. :
|
||||
|
||||
tim = Timer(0, mode=Timer.PERIODIC)
|
||||
tim_a = tim.channel(Timer.A, freq=1000)
|
||||
tim_a.time() # get the value in microseconds
|
||||
tim_a.freq(5) # 5 Hz
|
||||
|
||||
p_out = Pin('GP2', mode=Pin.OUT)
|
||||
tim_a.irq(handler=lambda t: p_out.toggle())
|
||||
tim_a.irq(trigger=Timer.TIMEOUT, handler=lambda t: p_out.toggle())
|
||||
|
||||
PWM (pulse width modulation)
|
||||
----------------------------
|
||||
@@ -135,10 +134,9 @@ Real time clock (RTC)
|
||||
|
||||
See :ref:`machine.RTC <machine.RTC>` ::
|
||||
|
||||
import machine
|
||||
from machine import RTC
|
||||
|
||||
rtc = machine.RTC() # init with default time and date
|
||||
rtc = RTC() # init with default time and date
|
||||
rtc = RTC(datetime=(2015, 8, 29, 9, 0, 0, 0, None)) # init with a specific time and date
|
||||
print(rtc.now())
|
||||
|
||||
@@ -205,7 +203,7 @@ See :ref:`network.Server <network.Server>` ::
|
||||
server = Server(login=('user', 'password'), timeout=60)
|
||||
server.timeout(300) # change the timeout
|
||||
server.timeout() # get the timeout
|
||||
server.isrunning() # check wether the server is running or not
|
||||
server.isrunning() # check whether the server is running or not
|
||||
|
||||
Heart beat LED
|
||||
--------------
|
||||
|
||||
@@ -17,7 +17,7 @@ Because the WiPy/expansion board does not have a housing it needs a bit of care:
|
||||
If you experience a lot of static electricity in your area (eg dry and cold
|
||||
climates), take extra care not to shock the WiPy. If your WiPy came
|
||||
in a ESD bag, then this bag is the best way to store and carry the
|
||||
WiPy as it will protect it agains static discharges.
|
||||
WiPy as it will protect it against static discharges.
|
||||
|
||||
As long as you take care of the hardware, you should be okay. It's almost
|
||||
impossible to break the software on the WiPy, so feel free to play around
|
||||
|
||||
@@ -84,6 +84,6 @@ STATIC mp_obj_t dht_readinto(mp_obj_t pin_in, mp_obj_t buf_in) {
|
||||
|
||||
timeout:
|
||||
mp_hal_quiet_timing_exit(irq_state);
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_ETIMEDOUT)));
|
||||
mp_raise_OSError(MP_ETIMEDOUT);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_2(dht_readinto_obj, dht_readinto);
|
||||
|
||||
@@ -4,31 +4,41 @@ Micro Python driver for SD cards using SPI bus.
|
||||
Requires an SPI bus and a CS pin. Provides readblocks and writeblocks
|
||||
methods so the device can be mounted as a filesystem.
|
||||
|
||||
Example usage:
|
||||
Example usage on pyboard:
|
||||
|
||||
import pyb, sdcard, os
|
||||
sd = sdcard.SDCard(pyb.SPI(1), pyb.Pin.board.X5)
|
||||
pyb.mount(sd, '/sd2')
|
||||
os.listdir('/')
|
||||
|
||||
Example usage on ESP8266:
|
||||
|
||||
import machine, sdcard, os
|
||||
sd = sdcard.SDCard(machine.SPI(0), machine.Pin(15))
|
||||
os.umount()
|
||||
os.VfsFat(sd, "")
|
||||
os.listdir()
|
||||
|
||||
"""
|
||||
|
||||
import pyb
|
||||
import time
|
||||
|
||||
|
||||
_CMD_TIMEOUT = const(100)
|
||||
|
||||
_R1_IDLE_STATE = const(1 << 0)
|
||||
#R1_ERASE_RESET = const(1 << 1)
|
||||
_R1_ILLEGAL_COMMAND = const(1 << 2)
|
||||
#R1_COM_CRC_ERROR = const(1 << 3)
|
||||
#R1_ERASE_SEQUENCE_ERROR = const(1 << 4)
|
||||
#R1_ADDRESS_ERROR = const(1 << 5)
|
||||
#R1_PARAMETER_ERROR = const(1 << 6)
|
||||
_TOKEN_CMD25 = const(0xfc)
|
||||
_TOKEN_STOP_TRAN = const(0xfd)
|
||||
_TOKEN_DATA = const(0xfe)
|
||||
|
||||
|
||||
class SDCard:
|
||||
CMD_TIMEOUT = const(100)
|
||||
|
||||
R1_IDLE_STATE = const(1 << 0)
|
||||
#R1_ERASE_RESET = const(1 << 1)
|
||||
R1_ILLEGAL_COMMAND = const(1 << 2)
|
||||
#R1_COM_CRC_ERROR = const(1 << 3)
|
||||
#R1_ERASE_SEQUENCE_ERROR = const(1 << 4)
|
||||
#R1_ADDRESS_ERROR = const(1 << 5)
|
||||
#R1_PARAMETER_ERROR = const(1 << 6)
|
||||
TOKEN_CMD25 = const(0xfc)
|
||||
TOKEN_STOP_TRAN = const(0xfd)
|
||||
TOKEN_DATA = const(0xfe)
|
||||
|
||||
def __init__(self, spi, cs):
|
||||
self.spi = spi
|
||||
self.cs = cs
|
||||
@@ -42,30 +52,39 @@ class SDCard:
|
||||
# initialise the card
|
||||
self.init_card()
|
||||
|
||||
def init_spi(self, baudrate):
|
||||
try:
|
||||
master = self.spi.MASTER
|
||||
except AttributeError:
|
||||
# on ESP8266
|
||||
self.spi.init(baudrate=baudrate, phase=0, polarity=0)
|
||||
else:
|
||||
# on pyboard
|
||||
self.spi.init(master, baudrate=baudrate, phase=0, polarity=0)
|
||||
|
||||
def init_card(self):
|
||||
# init CS pin
|
||||
self.cs.high()
|
||||
self.cs.init(self.cs.OUT_PP)
|
||||
self.cs.init(self.cs.OUT, value=1)
|
||||
|
||||
# init SPI bus; use low data rate for initialisation
|
||||
self.spi.init(self.spi.MASTER, baudrate=100000, phase=0, polarity=0)
|
||||
self.init_spi(100000)
|
||||
|
||||
# clock card at least 100 cycles with cs high
|
||||
for i in range(16):
|
||||
self.spi.send(0xff)
|
||||
self.spi.write(b'\xff')
|
||||
|
||||
# CMD0: init card; should return R1_IDLE_STATE (allow 5 attempts)
|
||||
# CMD0: init card; should return _R1_IDLE_STATE (allow 5 attempts)
|
||||
for _ in range(5):
|
||||
if self.cmd(0, 0, 0x95) == R1_IDLE_STATE:
|
||||
if self.cmd(0, 0, 0x95) == _R1_IDLE_STATE:
|
||||
break
|
||||
else:
|
||||
raise OSError("no SD card")
|
||||
|
||||
# CMD8: determine card version
|
||||
r = self.cmd(8, 0x01aa, 0x87, 4)
|
||||
if r == R1_IDLE_STATE:
|
||||
if r == _R1_IDLE_STATE:
|
||||
self.init_card_v2()
|
||||
elif r == (R1_IDLE_STATE | R1_ILLEGAL_COMMAND):
|
||||
elif r == (_R1_IDLE_STATE | _R1_ILLEGAL_COMMAND):
|
||||
self.init_card_v1()
|
||||
else:
|
||||
raise OSError("couldn't determine SD card version")
|
||||
@@ -86,10 +105,10 @@ class SDCard:
|
||||
raise OSError("can't set 512 block size")
|
||||
|
||||
# set to high data rate now that it's initialised
|
||||
self.spi.init(self.spi.MASTER, baudrate=1320000, phase=0, polarity=0)
|
||||
self.init_spi(1320000)
|
||||
|
||||
def init_card_v1(self):
|
||||
for i in range(CMD_TIMEOUT):
|
||||
for i in range(_CMD_TIMEOUT):
|
||||
self.cmd(55, 0, 0)
|
||||
if self.cmd(41, 0, 0) == 0:
|
||||
self.cdv = 512
|
||||
@@ -98,8 +117,8 @@ class SDCard:
|
||||
raise OSError("timeout waiting for v1 card")
|
||||
|
||||
def init_card_v2(self):
|
||||
for i in range(CMD_TIMEOUT):
|
||||
pyb.delay(50)
|
||||
for i in range(_CMD_TIMEOUT):
|
||||
time.sleep_ms(50)
|
||||
self.cmd(58, 0, 0, 4)
|
||||
self.cmd(55, 0, 0)
|
||||
if self.cmd(41, 0x40000000, 0) == 0:
|
||||
@@ -120,87 +139,87 @@ class SDCard:
|
||||
buf[3] = arg >> 8
|
||||
buf[4] = arg
|
||||
buf[5] = crc
|
||||
self.spi.send(buf)
|
||||
self.spi.write(buf)
|
||||
|
||||
# wait for the repsonse (response[7] == 0)
|
||||
for i in range(CMD_TIMEOUT):
|
||||
response = self.spi.send_recv(0xff)[0]
|
||||
for i in range(_CMD_TIMEOUT):
|
||||
response = self.spi.read(1, 0xff)[0]
|
||||
if not (response & 0x80):
|
||||
# this could be a big-endian integer that we are getting here
|
||||
for j in range(final):
|
||||
self.spi.send(0xff)
|
||||
self.spi.write(b'\xff')
|
||||
if release:
|
||||
self.cs.high()
|
||||
self.spi.send(0xff)
|
||||
self.spi.write(b'\xff')
|
||||
return response
|
||||
|
||||
# timeout
|
||||
self.cs.high()
|
||||
self.spi.send(0xff)
|
||||
self.spi.write(b'\xff')
|
||||
return -1
|
||||
|
||||
def cmd_nodata(self, cmd):
|
||||
self.spi.send(cmd)
|
||||
self.spi.send_recv(0xff) # ignore stuff byte
|
||||
for _ in range(CMD_TIMEOUT):
|
||||
if self.spi.send_recv(0xff)[0] == 0xff:
|
||||
self.spi.write(cmd)
|
||||
self.spi.read(1, 0xff) # ignore stuff byte
|
||||
for _ in range(_CMD_TIMEOUT):
|
||||
if self.spi.read(1, 0xff)[0] == 0xff:
|
||||
self.cs.high()
|
||||
self.spi.send(0xff)
|
||||
self.spi.write(b'\xff')
|
||||
return 0 # OK
|
||||
self.cs.high()
|
||||
self.spi.send(0xff)
|
||||
self.spi.write(b'\xff')
|
||||
return 1 # timeout
|
||||
|
||||
def readinto(self, buf):
|
||||
self.cs.low()
|
||||
|
||||
# read until start byte (0xff)
|
||||
while self.spi.send_recv(0xff)[0] != 0xfe:
|
||||
while self.spi.read(1, 0xff)[0] != 0xfe:
|
||||
pass
|
||||
|
||||
# read data
|
||||
mv = self.dummybuf_memoryview[:len(buf)]
|
||||
self.spi.send_recv(mv, recv=buf)
|
||||
self.spi.write_readinto(mv, buf)
|
||||
|
||||
# read checksum
|
||||
self.spi.send(0xff)
|
||||
self.spi.send(0xff)
|
||||
self.spi.write(b'\xff')
|
||||
self.spi.write(b'\xff')
|
||||
|
||||
self.cs.high()
|
||||
self.spi.send(0xff)
|
||||
self.spi.write(b'\xff')
|
||||
|
||||
def write(self, token, buf):
|
||||
self.cs.low()
|
||||
|
||||
# send: start of block, data, checksum
|
||||
self.spi.send(token)
|
||||
self.spi.send(buf)
|
||||
self.spi.send(0xff)
|
||||
self.spi.send(0xff)
|
||||
self.spi.read(1, token)
|
||||
self.spi.write(buf)
|
||||
self.spi.write(b'\xff')
|
||||
self.spi.write(b'\xff')
|
||||
|
||||
# check the response
|
||||
if (self.spi.send_recv(0xff)[0] & 0x1f) != 0x05:
|
||||
if (self.spi.read(1, 0xff)[0] & 0x1f) != 0x05:
|
||||
self.cs.high()
|
||||
self.spi.send(0xff)
|
||||
self.spi.write(b'\xff')
|
||||
return
|
||||
|
||||
# wait for write to finish
|
||||
while self.spi.send_recv(0xff)[0] == 0:
|
||||
while self.spi.read(1, 0xff)[0] == 0:
|
||||
pass
|
||||
|
||||
self.cs.high()
|
||||
self.spi.send(0xff)
|
||||
self.spi.write(b'\xff')
|
||||
|
||||
def write_token(self, token):
|
||||
self.cs.low()
|
||||
self.spi.send(token)
|
||||
self.spi.send(0xff)
|
||||
self.spi.read(1, token)
|
||||
self.spi.write(b'\xff')
|
||||
# wait for write to finish
|
||||
while self.spi.send_recv(0xff)[0] == 0:
|
||||
while self.spi.read(1, 0xff)[0] == 0x00:
|
||||
pass
|
||||
|
||||
self.cs.high()
|
||||
self.spi.send(0xff)
|
||||
self.spi.write(b'\xff')
|
||||
|
||||
def count(self):
|
||||
return self.sectors
|
||||
@@ -224,7 +243,7 @@ class SDCard:
|
||||
self.readinto(mv[offset : offset + 512])
|
||||
offset += 512
|
||||
nblocks -= 1
|
||||
return self.cmd_nodata(12)
|
||||
return self.cmd_nodata(b'\x0c') # cmd 12
|
||||
return 0
|
||||
|
||||
def writeblocks(self, block_num, buf):
|
||||
@@ -236,7 +255,7 @@ class SDCard:
|
||||
return 1
|
||||
|
||||
# send the data
|
||||
self.write(TOKEN_DATA, buf)
|
||||
self.write(_TOKEN_DATA, buf)
|
||||
else:
|
||||
# CMD25: set write address for first block
|
||||
if self.cmd(25, block_num * self.cdv, 0) != 0:
|
||||
@@ -245,8 +264,8 @@ class SDCard:
|
||||
offset = 0
|
||||
mv = memoryview(buf)
|
||||
while nblocks:
|
||||
self.write(TOKEN_CMD25, mv[offset : offset + 512])
|
||||
self.write(_TOKEN_CMD25, mv[offset : offset + 512])
|
||||
offset += 512
|
||||
nblocks -= 1
|
||||
self.write_token(TOKEN_STOP_TRAN)
|
||||
self.write_token(_TOKEN_STOP_TRAN)
|
||||
return 0
|
||||
|
||||
@@ -157,7 +157,7 @@ int8_t WIZCHIP_EXPORT(socket)(uint8_t sn, uint8_t protocol, uint16_t port, uint8
|
||||
setSn_PORT(sn,port);
|
||||
setSn_CR(sn,Sn_CR_OPEN);
|
||||
while(getSn_CR(sn));
|
||||
sock_io_mode |= ((flag & SF_IO_NONBLOCK) << sn);
|
||||
sock_io_mode |= ((flag & SF_IO_NONBLOCK) << sn);
|
||||
sock_is_sending &= ~(1<<sn);
|
||||
sock_remained_size[sn] = 0;
|
||||
sock_pack_info[sn] = 0;
|
||||
|
||||
@@ -4,18 +4,21 @@ include ../py/mkenv.mk
|
||||
QSTR_DEFS = qstrdefsport.h #$(BUILD)/pins_qstr.h
|
||||
|
||||
MICROPY_PY_USSL = 1
|
||||
MICROPY_SSL_AXTLS = 1
|
||||
MICROPY_PY_BTREE = 1
|
||||
|
||||
# include py core make definitions
|
||||
include ../py/py.mk
|
||||
|
||||
MPY_CROSS = ../mpy-cross/mpy-cross
|
||||
MPY_TOOL = ../tools/mpy-tool.py
|
||||
MAKE_FROZEN = ../tools/make-frozen.py
|
||||
|
||||
SCRIPTDIR = scripts
|
||||
FROZEN_DIR = scripts
|
||||
FROZEN_MPY_DIR = modules
|
||||
PORT ?= /dev/ttyACM0
|
||||
BAUD ?= 115200
|
||||
FLASH_MODE ?= qio
|
||||
FLASH_SIZE ?= 8m
|
||||
CROSS_COMPILE = xtensa-lx106-elf-
|
||||
ESP_SDK = $(shell $(CC) -print-sysroot)/usr
|
||||
|
||||
@@ -76,7 +79,9 @@ SRC_C = \
|
||||
modpybrtc.c \
|
||||
modpybadc.c \
|
||||
modpybuart.c \
|
||||
modmachinewdt.c \
|
||||
modpybspi.c \
|
||||
modpybhspi.c \
|
||||
modesp.c \
|
||||
modnetwork.c \
|
||||
modutime.c \
|
||||
@@ -87,6 +92,8 @@ SRC_C = \
|
||||
$(BUILD)/frozen.c \
|
||||
fatfs_port.c \
|
||||
axtls_helpers.c \
|
||||
hspi.c \
|
||||
$(SRC_MOD)
|
||||
|
||||
STM_SRC_C = $(addprefix stmhal/,\
|
||||
pybstdio.c \
|
||||
@@ -122,7 +129,7 @@ LIB_SRC_C = $(addprefix lib/,\
|
||||
timeutils/timeutils.c \
|
||||
utils/pyexec.c \
|
||||
utils/pyhelp.c \
|
||||
utils/printf.c \
|
||||
utils/interrupt_char.c \
|
||||
fatfs/ff.c \
|
||||
fatfs/option/ccsbcs.c \
|
||||
)
|
||||
@@ -134,7 +141,7 @@ DRIVERS_SRC_C = $(addprefix drivers/,\
|
||||
SRC_S = \
|
||||
gchelper.s \
|
||||
|
||||
FROZEN_MPY_PY_FILES := $(shell find $(FROZEN_MPY_DIR)/ -type f -name '*.py')
|
||||
FROZEN_MPY_PY_FILES := $(shell find -L $(FROZEN_MPY_DIR) -type f -name '*.py')
|
||||
FROZEN_MPY_MPY_FILES := $(addprefix $(BUILD)/,$(FROZEN_MPY_PY_FILES:.py=.mpy))
|
||||
|
||||
OBJ =
|
||||
@@ -153,22 +160,20 @@ SRC_QSTR += $(SRC_C) $(STM_SRC_C) $(EXTMOD_SRC_C) $(DRIVERS_SRC_C)
|
||||
# Append any auto-generated sources that are needed by sources listed in SRC_QSTR
|
||||
SRC_QSTR_AUTO_DEPS +=
|
||||
|
||||
all: $(BUILD)/firmware-combined.bin
|
||||
all: $(BUILD)/libaxtls.a $(BUILD)/firmware-combined.bin
|
||||
|
||||
CONFVARS_FILE = $(BUILD)/confvars
|
||||
|
||||
ifeq ($(wildcard $(CONFVARS_FILE)),)
|
||||
$(shell $(MKDIR) -p $(BUILD))
|
||||
$(shell echo $(SCRIPTDIR) $(UART_OS) > $(CONFVARS_FILE))
|
||||
else ifneq ($(shell cat $(CONFVARS_FILE)), $(SCRIPTDIR) $(UART_OS))
|
||||
$(shell echo $(SCRIPTDIR) $(UART_OS) > $(CONFVARS_FILE))
|
||||
$(shell echo $(FROZEN_DIR) $(UART_OS) > $(CONFVARS_FILE))
|
||||
else ifneq ($(shell cat $(CONFVARS_FILE)), $(FROZEN_DIR) $(UART_OS))
|
||||
$(shell echo $(FROZEN_DIR) $(UART_OS) > $(CONFVARS_FILE))
|
||||
endif
|
||||
|
||||
$(BUILD)/uart.o: $(CONFVARS_FILE)
|
||||
|
||||
$(BUILD)/frozen.c: $(wildcard $(SCRIPTDIR)/*) $(CONFVARS_FILE)
|
||||
$(ECHO) "Generating $@"
|
||||
$(Q)$(MAKE_FROZEN) $(SCRIPTDIR) > $@
|
||||
FROZEN_EXTRA_DEPS = $(CONFVARS_FILE)
|
||||
|
||||
# to build .mpy files from .py files
|
||||
$(BUILD)/$(FROZEN_MPY_DIR)/%.mpy: $(FROZEN_MPY_DIR)/%.py
|
||||
@@ -185,7 +190,7 @@ $(BUILD)/frozen_mpy.c: $(FROZEN_MPY_MPY_FILES) $(BUILD)/genhdr/qstrdefs.generate
|
||||
|
||||
deploy: $(BUILD)/firmware-combined.bin
|
||||
$(ECHO) "Writing $< to the board"
|
||||
$(Q)esptool.py --port $(PORT) --baud $(BAUD) write_flash --verify --flash_size=8m 0 $<
|
||||
$(Q)esptool.py --port $(PORT) --baud $(BAUD) write_flash --verify --flash_size=$(FLASH_SIZE) --flash_mode=$(FLASH_MODE) 0 $<
|
||||
#$(Q)esptool.py --port $(PORT) --baud $(BAUD) write_flash --flash_size=8m 0 $(BUILD)/firmware.elf-0x00000.bin 0x9000 $(BUILD)/firmware.elf-0x0[1-f]000.bin
|
||||
|
||||
reset:
|
||||
@@ -229,8 +234,11 @@ $(BUILD)/firmware.elf: $(OBJ)
|
||||
|
||||
include ../py/mkrules.mk
|
||||
|
||||
axtls:
|
||||
axtls: $(BUILD)/libaxtls.a
|
||||
|
||||
$(BUILD)/libaxtls.a:
|
||||
cd ../lib/axtls; cp config/upyconfig config/.config
|
||||
cd ../lib/axtls; make oldconfig -B
|
||||
cd ../lib/axtls; make clean
|
||||
cd ../lib/axtls; make all CC="$(CC)" LD="$(LD)" AR="$(AR)" CFLAGS_EXTRA="$(CFLAGS_XTENSA) -Dabort=abort_ -DRT_MAX_PLAIN_LENGTH=1024 -DRT_EXTRA=3072"
|
||||
cp ../lib/axtls/_stage/libaxtls.a $@
|
||||
|
||||
@@ -70,9 +70,10 @@ $ make deploy
|
||||
```
|
||||
This will use the `esptool.py` script to download the images. You must have
|
||||
your ESP module in the bootloader mode, and connected to a serial port on your PC.
|
||||
The default serial port is `/dev/ttyACM0`. To specify another, use, eg:
|
||||
The default serial port is `/dev/ttyACM0`, flash mode is `qio` and flash size is `8m`.
|
||||
To specify other values, use, eg:
|
||||
```bash
|
||||
$ make PORT=/dev/ttyUSB0 deploy
|
||||
$ make PORT=/dev/ttyUSB0 FLASH_MODE=qio FLASH_SIZE=8m deploy
|
||||
```
|
||||
|
||||
The image produced is `firmware-combined.bin`, to be flashed at 0x00000.
|
||||
|
||||
@@ -43,9 +43,6 @@ void *calloc(size_t nmemb, size_t size) {
|
||||
void *realloc(void *ptr, size_t size) {
|
||||
return gc_realloc(ptr, size, true);
|
||||
}
|
||||
void abort_(void) {
|
||||
printf("Aborted\n");
|
||||
}
|
||||
|
||||
#define PLATFORM_HTONL(_n) ((uint32_t)( (((_n) & 0xff) << 24) | (((_n) & 0xff00) << 8) | (((_n) >> 8) & 0xff00) | (((_n) >> 24) & 0xff) ))
|
||||
#undef htonl
|
||||
|
||||
@@ -20,6 +20,7 @@ PROVIDE ( SPI_read_status = 0x400043c8 );
|
||||
PROVIDE ( SPI_write_status = 0x40004400 );
|
||||
PROVIDE ( SPI_write_enable = 0x4000443c );
|
||||
PROVIDE ( Wait_SPI_Idle = 0x4000448c );
|
||||
PROVIDE ( Enable_QMode = 0x400044c0 );
|
||||
PROVIDE ( SPIEraseArea = 0x40004b44 );
|
||||
PROVIDE ( SPIEraseBlock = 0x400049b4 );
|
||||
PROVIDE ( SPIEraseChip = 0x40004984 );
|
||||
|
||||
@@ -5,7 +5,7 @@ MEMORY
|
||||
dport0_0_seg : org = 0x3ff00000, len = 0x10
|
||||
dram0_0_seg : org = 0x3ffe8000, len = 0x14000
|
||||
iram1_0_seg : org = 0x40100000, len = 0x8000
|
||||
irom0_0_seg : org = 0x40209000, len = 0x80000
|
||||
irom0_0_seg : org = 0x40209000, len = 0x87000
|
||||
}
|
||||
|
||||
/* define the top of RAM */
|
||||
@@ -121,6 +121,7 @@ SECTIONS
|
||||
|
||||
*lib/fatfs/*.o*(.literal*, .text*)
|
||||
*/libaxtls.a:(.literal*, .text*)
|
||||
*lib/berkeley-db-1.xx/*.o(.literal*, .text*)
|
||||
*lib/libm/*.o*(.literal*, .text*)
|
||||
*lib/mp-readline/*.o(.literal*, .text*)
|
||||
*lib/netutils/*.o*(.literal*, .text*)
|
||||
@@ -140,7 +141,10 @@ SECTIONS
|
||||
*modpybadc.o(.literal*, .text*)
|
||||
*modpybuart.o(.literal*, .text*)
|
||||
*modpybi2c.o(.literal*, .text*)
|
||||
*modmachinewdt.o(.literal*, .text*)
|
||||
*modpybspi.o(.literal*, .text*)
|
||||
*modpybhspi.o(.literal*, .text*)
|
||||
*hspi.o(.literal*, .text*)
|
||||
*modesp.o(.literal* .text*)
|
||||
*modnetwork.o(.literal* .text*)
|
||||
*moduos.o(.literal* .text*)
|
||||
|
||||
@@ -36,17 +36,13 @@
|
||||
#include "extmod/misc.h"
|
||||
#include "lib/utils/pyexec.h"
|
||||
|
||||
extern void ets_wdt_disable(void);
|
||||
extern void wdt_feed(void);
|
||||
extern void ets_delay_us();
|
||||
|
||||
STATIC byte input_buf_array[256];
|
||||
ringbuf_t input_buf = {input_buf_array, sizeof(input_buf_array)};
|
||||
void mp_hal_debug_tx_strn_cooked(void *env, const char *str, uint32_t len);
|
||||
const mp_print_t mp_debug_print = {NULL, mp_hal_debug_tx_strn_cooked};
|
||||
|
||||
void mp_hal_init(void) {
|
||||
ets_wdt_disable(); // it's a pain while developing
|
||||
//ets_wdt_disable(); // it's a pain while developing
|
||||
mp_hal_rtc_init();
|
||||
uart_init(UART_BIT_RATE_115200, UART_BIT_RATE_115200);
|
||||
}
|
||||
@@ -64,7 +60,14 @@ int mp_hal_stdin_rx_chr(void) {
|
||||
if (c != -1) {
|
||||
return c;
|
||||
}
|
||||
#if 0
|
||||
// Idles CPU but need more testing before enabling
|
||||
if (!ets_loop_iter()) {
|
||||
asm("waiti 0");
|
||||
}
|
||||
#else
|
||||
mp_hal_delay_us(1);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,7 +117,7 @@ void mp_hal_debug_tx_strn_cooked(void *env, const char *str, uint32_t len) {
|
||||
}
|
||||
|
||||
uint32_t mp_hal_ticks_ms(void) {
|
||||
return system_get_time() / 1000;
|
||||
return ((uint64_t)system_time_high_word << 32 | (uint64_t)system_get_time()) / 1000;
|
||||
}
|
||||
|
||||
uint32_t mp_hal_ticks_us(void) {
|
||||
@@ -125,14 +128,6 @@ void mp_hal_delay_ms(uint32_t delay) {
|
||||
mp_hal_delay_us(delay * 1000);
|
||||
}
|
||||
|
||||
void mp_hal_set_interrupt_char(int c) {
|
||||
if (c != -1) {
|
||||
mp_obj_exception_clear_traceback(MP_STATE_PORT(mp_kbd_exception));
|
||||
}
|
||||
extern int interrupt_char;
|
||||
interrupt_char = c;
|
||||
}
|
||||
|
||||
void ets_event_poll(void) {
|
||||
ets_loop_iter();
|
||||
if (MP_STATE_VM(mp_pending_exception) != NULL) {
|
||||
@@ -177,7 +172,7 @@ static int call_dupterm_read(void) {
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(MP_STATE_PORT(dupterm_arr_obj), &bufinfo, MP_BUFFER_READ);
|
||||
nlr_pop();
|
||||
if (*(byte*)bufinfo.buf == interrupt_char) {
|
||||
if (*(byte*)bufinfo.buf == mp_interrupt_char) {
|
||||
mp_keyboard_interrupt();
|
||||
return -2;
|
||||
}
|
||||
@@ -259,3 +254,8 @@ int ets_esf_free_bufs(int idx) {
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
|
||||
extern int mp_stream_errno;
|
||||
int *__errno() {
|
||||
return &mp_stream_errno;
|
||||
}
|
||||
|
||||
@@ -28,10 +28,10 @@
|
||||
#define _INCLUDED_MPHAL_H_
|
||||
|
||||
#include "py/ringbuf.h"
|
||||
#include "lib/utils/interrupt_char.h"
|
||||
#include "xtirq.h"
|
||||
|
||||
void mp_keyboard_interrupt(void);
|
||||
extern int interrupt_char;
|
||||
|
||||
struct _mp_print_t;
|
||||
// Structure for UART-only output via mp_printf()
|
||||
@@ -47,6 +47,12 @@ void mp_hal_init(void);
|
||||
void mp_hal_rtc_init(void);
|
||||
|
||||
uint32_t mp_hal_ticks_us(void);
|
||||
__attribute__((always_inline)) static inline uint32_t mp_hal_ticks_cpu(void) {
|
||||
uint32_t ccount;
|
||||
__asm__ __volatile__("rsr %0,ccount":"=a" (ccount));
|
||||
return ccount;
|
||||
}
|
||||
|
||||
void mp_hal_delay_us(uint32_t);
|
||||
void mp_hal_set_interrupt_char(int c);
|
||||
uint32_t mp_hal_get_cpu_freq(void);
|
||||
|
||||
@@ -24,6 +24,9 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "py/mpconfig.h"
|
||||
#if MICROPY_ESP8266_APA102
|
||||
|
||||
#include <stdio.h>
|
||||
#include "c_types.h"
|
||||
#include "eagle_soc.h"
|
||||
@@ -108,3 +111,5 @@ void esp_apa102_write(uint8_t clockPin, uint8_t dataPin, uint8_t *pixels, uint32
|
||||
_esp_apa102_append_additionial_cycles(clockPinMask, dataPinMask, numBytes);
|
||||
_esp_apa102_end_frame(clockPinMask, dataPinMask);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -5,20 +5,17 @@
|
||||
// ESP8266 work for the NeoPixelBus library: github.com/Makuna/NeoPixelBus
|
||||
// Needs to be a separate .c file to enforce ICACHE_RAM_ATTR execution.
|
||||
|
||||
#include "py/mpconfig.h"
|
||||
#if MICROPY_ESP8266_NEOPIXEL
|
||||
|
||||
#include "c_types.h"
|
||||
#include "eagle_soc.h"
|
||||
#include "user_interface.h"
|
||||
#include "espneopixel.h"
|
||||
#include "esp_mphal.h"
|
||||
|
||||
#define NEO_KHZ400 (1)
|
||||
|
||||
static uint32_t _getCycleCount(void) __attribute__((always_inline));
|
||||
static inline uint32_t _getCycleCount(void) {
|
||||
uint32_t ccount;
|
||||
__asm__ __volatile__("rsr %0,ccount":"=a" (ccount));
|
||||
return ccount;
|
||||
}
|
||||
|
||||
void /*ICACHE_RAM_ATTR*/ esp_neopixel_write(uint8_t pin, uint8_t *pixels, uint32_t numBytes, bool is800KHz) {
|
||||
|
||||
uint8_t *p, *end, pix, mask;
|
||||
@@ -47,12 +44,13 @@ void /*ICACHE_RAM_ATTR*/ esp_neopixel_write(uint8_t pin, uint8_t *pixels, uint32
|
||||
}
|
||||
#endif
|
||||
|
||||
uint32_t irq_state = mp_hal_quiet_timing_enter();
|
||||
for(t = time0;; t = time0) {
|
||||
if(pix & mask) t = time1; // Bit high duration
|
||||
while(((c = _getCycleCount()) - startTime) < period); // Wait for bit start
|
||||
while(((c = mp_hal_ticks_cpu()) - startTime) < period); // Wait for bit start
|
||||
GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, pinMask); // Set high
|
||||
startTime = c; // Save start time
|
||||
while(((c = _getCycleCount()) - startTime) < t); // Wait high duration
|
||||
while(((c = mp_hal_ticks_cpu()) - startTime) < t); // Wait high duration
|
||||
GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, pinMask); // Set low
|
||||
if(!(mask >>= 1)) { // Next bit/byte
|
||||
if(p >= end) break;
|
||||
@@ -60,5 +58,8 @@ void /*ICACHE_RAM_ATTR*/ esp_neopixel_write(uint8_t pin, uint8_t *pixels, uint32
|
||||
mask = 0x80;
|
||||
}
|
||||
}
|
||||
while((_getCycleCount() - startTime) < period); // Wait for last bit
|
||||
while((mp_hal_ticks_cpu() - startTime) < period); // Wait for last bit
|
||||
mp_hal_quiet_timing_exit(irq_state);
|
||||
}
|
||||
|
||||
#endif // MICROPY_ESP8266_NEOPIXEL
|
||||
|
||||
@@ -87,7 +87,7 @@ bool ets_post(uint8 prio, os_signal_t sig, os_param_t param) {
|
||||
if (emu_tasks[id].i_put == -1) {
|
||||
// queue is full
|
||||
printf("ets_post: task %d queue full\n", prio);
|
||||
return false;
|
||||
return 1;
|
||||
}
|
||||
q = &q[emu_tasks[id].i_put++];
|
||||
q->sig = sig;
|
||||
@@ -104,16 +104,28 @@ bool ets_post(uint8 prio, os_signal_t sig, os_param_t param) {
|
||||
|
||||
ets_intr_unlock();
|
||||
|
||||
return true;
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
int ets_loop_iter_disable = 0;
|
||||
|
||||
// to implement a 64-bit wide microsecond counter
|
||||
static uint32_t system_time_prev = 0;
|
||||
uint32_t system_time_high_word = 0;
|
||||
|
||||
bool ets_loop_iter(void) {
|
||||
if (ets_loop_iter_disable) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// handle overflow of system microsecond counter
|
||||
uint32_t system_time_cur = system_get_time();
|
||||
if (system_time_cur < system_time_prev) {
|
||||
system_time_high_word += 1; // record overflow of low 32-bits
|
||||
}
|
||||
system_time_prev = system_time_cur;
|
||||
|
||||
//static unsigned cnt;
|
||||
bool progress = false;
|
||||
for (volatile struct task_entry *t = emu_tasks; t < &emu_tasks[MP_ARRAY_SIZE(emu_tasks)]; t++) {
|
||||
|
||||
@@ -1,2 +1,4 @@
|
||||
extern int ets_loop_iter_disable;
|
||||
extern uint32_t system_time_high_word;
|
||||
|
||||
bool ets_loop_iter(void);
|
||||
|
||||
@@ -20,6 +20,16 @@ void ets_timer_arm_new(os_timer_t *tim, uint32_t millis, bool repeat, bool is_mi
|
||||
void ets_timer_setfn(os_timer_t *tim, ETSTimerFunc callback, void *cb_data);
|
||||
void ets_timer_disarm(os_timer_t *tim);
|
||||
|
||||
extern void ets_wdt_disable(void);
|
||||
extern void wdt_feed(void);
|
||||
|
||||
// Opaque structure
|
||||
typedef char MD5_CTX[64];
|
||||
|
||||
void MD5Init(MD5_CTX *context);
|
||||
void MD5Update(MD5_CTX *context, const void *data, unsigned int len);
|
||||
void MD5Final(unsigned char digest[16], MD5_CTX *context);
|
||||
|
||||
// These prototypes are for recent SDKs with "malloc tracking"
|
||||
void *pvPortMalloc(unsigned sz, const char *fname, int line);
|
||||
void vPortFree(void *p, const char *fname, int line);
|
||||
|
||||
331
esp8266/hspi.c
Normal file
331
esp8266/hspi.c
Normal file
@@ -0,0 +1,331 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015 David Ogilvy (MetalPhreak)
|
||||
* Modified 2016 by Radomir Dopieralski
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "hspi.h"
|
||||
|
||||
/*
|
||||
Wrapper to setup HSPI/SPI GPIO pins and default SPI clock
|
||||
spi_no - SPI (0) or HSPI (1)
|
||||
Not used in Micropython.
|
||||
*/
|
||||
void spi_init(uint8_t spi_no) {
|
||||
spi_init_gpio(spi_no, SPI_CLK_USE_DIV);
|
||||
spi_clock(spi_no, SPI_CLK_PREDIV, SPI_CLK_CNTDIV);
|
||||
spi_tx_byte_order(spi_no, SPI_BYTE_ORDER_HIGH_TO_LOW);
|
||||
spi_rx_byte_order(spi_no, SPI_BYTE_ORDER_HIGH_TO_LOW);
|
||||
|
||||
SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_CS_SETUP|SPI_CS_HOLD);
|
||||
CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_FLASH_MODE);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Configures SPI mode parameters for clock edge and clock polarity.
|
||||
spi_no - SPI (0) or HSPI (1)
|
||||
spi_cpha - (0) Data is valid on clock leading edge
|
||||
(1) Data is valid on clock trailing edge
|
||||
spi_cpol - (0) Clock is low when inactive
|
||||
(1) Clock is high when inactive
|
||||
For Micropython this version is different from original.
|
||||
*/
|
||||
void spi_mode(uint8_t spi_no, uint8_t spi_cpha, uint8_t spi_cpol) {
|
||||
if (spi_cpol) {
|
||||
SET_PERI_REG_MASK(SPI_PIN(HSPI), SPI_IDLE_EDGE);
|
||||
} else {
|
||||
CLEAR_PERI_REG_MASK(SPI_PIN(HSPI), SPI_IDLE_EDGE);
|
||||
}
|
||||
if (spi_cpha == spi_cpol) {
|
||||
// Mode 3 - MOSI is set on falling edge of clock
|
||||
// Mode 0 - MOSI is set on falling edge of clock
|
||||
CLEAR_PERI_REG_MASK(SPI_USER(HSPI), SPI_CK_OUT_EDGE);
|
||||
SET_PERI_REG_MASK(SPI_USER(HSPI), SPI_CK_I_EDGE);
|
||||
} else {
|
||||
// Mode 2 - MOSI is set on rising edge of clock
|
||||
// Mode 1 - MOSI is set on rising edge of clock
|
||||
SET_PERI_REG_MASK(SPI_USER(HSPI), SPI_CK_OUT_EDGE);
|
||||
CLEAR_PERI_REG_MASK(SPI_USER(HSPI), SPI_CK_I_EDGE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Initialise the GPIO pins for use as SPI pins.
|
||||
spi_no - SPI (0) or HSPI (1)
|
||||
sysclk_as_spiclk -
|
||||
SPI_CLK_80MHZ_NODIV (1) if using 80MHz for SPI clock.
|
||||
SPI_CLK_USE_DIV (0) if using divider for lower speed.
|
||||
*/
|
||||
void spi_init_gpio(uint8_t spi_no, uint8_t sysclk_as_spiclk) {
|
||||
uint32_t clock_div_flag = 0;
|
||||
if (sysclk_as_spiclk) {
|
||||
clock_div_flag = 0x0001;
|
||||
}
|
||||
if (spi_no == SPI) {
|
||||
// Set bit 8 if 80MHz sysclock required
|
||||
WRITE_PERI_REG(PERIPHS_IO_MUX, 0x005 | (clock_div_flag<<8));
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CLK_U, 1);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CMD_U, 1);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA0_U, 1);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA1_U, 1);
|
||||
} else if (spi_no == HSPI) {
|
||||
// Set bit 9 if 80MHz sysclock required
|
||||
WRITE_PERI_REG(PERIPHS_IO_MUX, 0x105 | (clock_div_flag<<9));
|
||||
// GPIO12 is HSPI MISO pin (Master Data In)
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDI_U, 2);
|
||||
// GPIO13 is HSPI MOSI pin (Master Data Out)
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, 2);
|
||||
// GPIO14 is HSPI CLK pin (Clock)
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTMS_U, 2);
|
||||
// GPIO15 is HSPI CS pin (Chip Select / Slave Select)
|
||||
// In Micropython, we are handling CS ourself in drivers.
|
||||
// PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, 2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Set up the control registers for the SPI clock
|
||||
spi_no - SPI (0) or HSPI (1)
|
||||
prediv - predivider value (actual division value)
|
||||
cntdiv - postdivider value (actual division value)
|
||||
Set either divider to 0 to disable all division (80MHz sysclock)
|
||||
*/
|
||||
void spi_clock(uint8_t spi_no, uint16_t prediv, uint8_t cntdiv) {
|
||||
if (prediv == 0 || cntdiv == 0) {
|
||||
WRITE_PERI_REG(SPI_CLOCK(spi_no), SPI_CLK_EQU_SYSCLK);
|
||||
} else {
|
||||
WRITE_PERI_REG(SPI_CLOCK(spi_no),
|
||||
(((prediv - 1) & SPI_CLKDIV_PRE) << SPI_CLKDIV_PRE_S) |
|
||||
(((cntdiv - 1) & SPI_CLKCNT_N) << SPI_CLKCNT_N_S) |
|
||||
(((cntdiv >> 1) & SPI_CLKCNT_H) << SPI_CLKCNT_H_S) |
|
||||
((0 & SPI_CLKCNT_L) << SPI_CLKCNT_L_S)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Setup the byte order for shifting data out of buffer
|
||||
spi_no - SPI (0) or HSPI (1)
|
||||
byte_order -
|
||||
SPI_BYTE_ORDER_HIGH_TO_LOW (1)
|
||||
Data is sent out starting with Bit31 and down to Bit0
|
||||
SPI_BYTE_ORDER_LOW_TO_HIGH (0)
|
||||
Data is sent out starting with the lowest BYTE, from MSB to LSB,
|
||||
followed by the second lowest BYTE, from MSB to LSB, followed by
|
||||
the second highest BYTE, from MSB to LSB, followed by the highest
|
||||
BYTE, from MSB to LSB 0xABCDEFGH would be sent as 0xGHEFCDAB.
|
||||
*/
|
||||
void spi_tx_byte_order(uint8_t spi_no, uint8_t byte_order) {
|
||||
if (byte_order) {
|
||||
SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_WR_BYTE_ORDER);
|
||||
} else {
|
||||
CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_WR_BYTE_ORDER);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Setup the byte order for shifting data into buffer
|
||||
spi_no - SPI (0) or HSPI (1)
|
||||
byte_order -
|
||||
SPI_BYTE_ORDER_HIGH_TO_LOW (1)
|
||||
Data is read in starting with Bit31 and down to Bit0
|
||||
SPI_BYTE_ORDER_LOW_TO_HIGH (0)
|
||||
Data is read in starting with the lowest BYTE, from MSB to LSB,
|
||||
followed by the second lowest BYTE, from MSB to LSB, followed by
|
||||
the second highest BYTE, from MSB to LSB, followed by the highest
|
||||
BYTE, from MSB to LSB 0xABCDEFGH would be read as 0xGHEFCDAB
|
||||
*/
|
||||
void spi_rx_byte_order(uint8_t spi_no, uint8_t byte_order) {
|
||||
if (byte_order) {
|
||||
SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_RD_BYTE_ORDER);
|
||||
} else {
|
||||
CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_RD_BYTE_ORDER);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
SPI transaction function
|
||||
spi_no - SPI (0) or HSPI (1)
|
||||
cmd_bits - actual number of bits to transmit
|
||||
cmd_data - command data
|
||||
addr_bits - actual number of bits to transmit
|
||||
addr_data - address data
|
||||
dout_bits - actual number of bits to transmit
|
||||
dout_data - output data
|
||||
din_bits - actual number of bits to receive
|
||||
Returns: read data - uint32_t containing read in data only if RX was set
|
||||
0 - something went wrong (or actual read data was 0)
|
||||
1 - data sent ok (or actual read data is 1)
|
||||
Note: all data is assumed to be stored in the lower bits of the data variables
|
||||
(for anything <32 bits).
|
||||
*/
|
||||
uint32_t spi_transaction(uint8_t spi_no, uint8_t cmd_bits, uint16_t cmd_data,
|
||||
uint32_t addr_bits, uint32_t addr_data,
|
||||
uint32_t dout_bits, uint32_t dout_data,
|
||||
uint32_t din_bits, uint32_t dummy_bits) {
|
||||
while (spi_busy(spi_no)) {}; // Wait for SPI to be ready
|
||||
|
||||
// Enable SPI Functions
|
||||
// Disable MOSI, MISO, ADDR, COMMAND, DUMMY in case previously set.
|
||||
CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MOSI | SPI_USR_MISO |
|
||||
SPI_USR_COMMAND | SPI_USR_ADDR | SPI_USR_DUMMY);
|
||||
|
||||
// Enable functions based on number of bits. 0 bits = disabled.
|
||||
// This is rather inefficient but allows for a very generic function.
|
||||
// CMD ADDR and MOSI are set below to save on an extra if statement.
|
||||
if (din_bits) {
|
||||
if (dout_bits) {
|
||||
SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_DOUTDIN);
|
||||
} else {
|
||||
SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MISO);
|
||||
}
|
||||
}
|
||||
if (dummy_bits) {
|
||||
SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_DUMMY);
|
||||
}
|
||||
|
||||
// Setup Bitlengths
|
||||
WRITE_PERI_REG(SPI_USER1(spi_no),
|
||||
// Number of bits in Address
|
||||
((addr_bits - 1) & SPI_USR_ADDR_BITLEN) << SPI_USR_ADDR_BITLEN_S |
|
||||
// Number of bits to Send
|
||||
((dout_bits - 1) & SPI_USR_MOSI_BITLEN) << SPI_USR_MOSI_BITLEN_S |
|
||||
// Number of bits to receive
|
||||
((din_bits - 1) & SPI_USR_MISO_BITLEN) << SPI_USR_MISO_BITLEN_S |
|
||||
// Number of Dummy bits to insert
|
||||
((dummy_bits - 1) & SPI_USR_DUMMY_CYCLELEN) << SPI_USR_DUMMY_CYCLELEN_S);
|
||||
|
||||
// Setup Command Data
|
||||
if (cmd_bits) {
|
||||
// Enable COMMAND function in SPI module
|
||||
SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_COMMAND);
|
||||
// Align command data to high bits
|
||||
uint16_t command = cmd_data << (16-cmd_bits);
|
||||
// Swap byte order
|
||||
command = ((command>>8)&0xff) | ((command<<8)&0xff00);
|
||||
WRITE_PERI_REG(SPI_USER2(spi_no), (
|
||||
(((cmd_bits - 1) & SPI_USR_COMMAND_BITLEN) << SPI_USR_COMMAND_BITLEN_S) |
|
||||
(command & SPI_USR_COMMAND_VALUE)
|
||||
));
|
||||
}
|
||||
|
||||
// Setup Address Data
|
||||
if (addr_bits) {
|
||||
// Enable ADDRess function in SPI module
|
||||
SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_ADDR);
|
||||
// Align address data to high bits
|
||||
WRITE_PERI_REG(SPI_ADDR(spi_no), addr_data << (32 - addr_bits));
|
||||
}
|
||||
|
||||
// Setup DOUT data
|
||||
if (dout_bits) {
|
||||
// Enable MOSI function in SPI module
|
||||
SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MOSI);
|
||||
// Copy data to W0
|
||||
if (READ_PERI_REG(SPI_USER(spi_no))&SPI_WR_BYTE_ORDER) {
|
||||
WRITE_PERI_REG(SPI_W0(spi_no), dout_data << (32 - dout_bits));
|
||||
} else {
|
||||
uint8_t dout_extra_bits = dout_bits%8;
|
||||
|
||||
if (dout_extra_bits) {
|
||||
// If your data isn't a byte multiple (8/16/24/32 bits) and you
|
||||
// don't have SPI_WR_BYTE_ORDER set, you need this to move the
|
||||
// non-8bit remainder to the MSBs. Not sure if there's even a use
|
||||
// case for this, but it's here if you need it... For example,
|
||||
// 0xDA4 12 bits without SPI_WR_BYTE_ORDER would usually be output
|
||||
// as if it were 0x0DA4, of which 0xA4, and then 0x0 would be
|
||||
// shifted out (first 8 bits of low byte, then 4 MSB bits of high
|
||||
// byte - ie reverse byte order).
|
||||
// The code below shifts it out as 0xA4 followed by 0xD as you
|
||||
// might require.
|
||||
WRITE_PERI_REG(SPI_W0(spi_no), (
|
||||
(0xFFFFFFFF << (dout_bits - dout_extra_bits) & dout_data)
|
||||
<< (8-dout_extra_bits) |
|
||||
((0xFFFFFFFF >> (32 - (dout_bits - dout_extra_bits)))
|
||||
& dout_data)
|
||||
));
|
||||
} else {
|
||||
WRITE_PERI_REG(SPI_W0(spi_no), dout_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Begin SPI Transaction
|
||||
SET_PERI_REG_MASK(SPI_CMD(spi_no), SPI_USR);
|
||||
|
||||
// Return DIN data
|
||||
if (din_bits) {
|
||||
while (spi_busy(spi_no)) {}; // Wait for SPI transaction to complete
|
||||
if (READ_PERI_REG(SPI_USER(spi_no))&SPI_RD_BYTE_ORDER) {
|
||||
// Assuming data in is written to MSB. TBC
|
||||
return READ_PERI_REG(SPI_W0(spi_no)) >> (32 - din_bits);
|
||||
} else {
|
||||
// Read in the same way as DOUT is sent. Note existing contents of
|
||||
// SPI_W0 remain unless overwritten!
|
||||
return READ_PERI_REG(SPI_W0(spi_no));
|
||||
}
|
||||
return 0; // Something went wrong
|
||||
}
|
||||
|
||||
// Transaction completed
|
||||
return 1; // Success
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Just do minimal work needed to send 8 bits.
|
||||
*/
|
||||
inline void spi_tx8fast(uint8_t spi_no, uint8_t dout_data) {
|
||||
while (spi_busy(spi_no)) {}; // Wait for SPI to be ready
|
||||
|
||||
// Enable SPI Functions
|
||||
// Disable MOSI, MISO, ADDR, COMMAND, DUMMY in case previously set.
|
||||
CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MOSI | SPI_USR_MISO |
|
||||
SPI_USR_COMMAND | SPI_USR_ADDR | SPI_USR_DUMMY);
|
||||
|
||||
// Setup Bitlengths
|
||||
WRITE_PERI_REG(SPI_USER1(spi_no),
|
||||
// Number of bits to Send
|
||||
((8 - 1) & SPI_USR_MOSI_BITLEN) << SPI_USR_MOSI_BITLEN_S |
|
||||
// Number of bits to receive
|
||||
((8 - 1) & SPI_USR_MISO_BITLEN) << SPI_USR_MISO_BITLEN_S);
|
||||
|
||||
|
||||
// Setup DOUT data
|
||||
// Enable MOSI function in SPI module
|
||||
SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MOSI);
|
||||
// Copy data to W0
|
||||
if (READ_PERI_REG(SPI_USER(spi_no)) & SPI_WR_BYTE_ORDER) {
|
||||
WRITE_PERI_REG(SPI_W0(spi_no), dout_data << (32 - 8));
|
||||
} else {
|
||||
WRITE_PERI_REG(SPI_W0(spi_no), dout_data);
|
||||
}
|
||||
|
||||
// Begin SPI Transaction
|
||||
SET_PERI_REG_MASK(SPI_CMD(spi_no), SPI_USR);
|
||||
}
|
||||
79
esp8266/hspi.h
Normal file
79
esp8266/hspi.h
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015 David Ogilvy (MetalPhreak)
|
||||
* Modified 2016 by Radomir Dopieralski
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef SPI_APP_H
|
||||
#define SPI_APP_H
|
||||
|
||||
#include "hspi_register.h"
|
||||
#include "ets_sys.h"
|
||||
#include "osapi.h"
|
||||
#include "os_type.h"
|
||||
|
||||
// Define SPI hardware modules
|
||||
#define SPI 0
|
||||
#define HSPI 1
|
||||
|
||||
#define SPI_CLK_USE_DIV 0
|
||||
#define SPI_CLK_80MHZ_NODIV 1
|
||||
|
||||
#define SPI_BYTE_ORDER_HIGH_TO_LOW 1
|
||||
#define SPI_BYTE_ORDER_LOW_TO_HIGH 0
|
||||
|
||||
#ifndef CPU_CLK_FREQ //Should already be defined in eagle_soc.h
|
||||
#define CPU_CLK_FREQ (80 * 1000000)
|
||||
#endif
|
||||
|
||||
// Define some default SPI clock settings
|
||||
#define SPI_CLK_PREDIV 10
|
||||
#define SPI_CLK_CNTDIV 2
|
||||
#define SPI_CLK_FREQ (CPU_CLK_FREQ / (SPI_CLK_PREDIV * SPI_CLK_CNTDIV))
|
||||
// 80 / 20 = 4 MHz
|
||||
|
||||
void spi_init(uint8_t spi_no);
|
||||
void spi_mode(uint8_t spi_no, uint8_t spi_cpha,uint8_t spi_cpol);
|
||||
void spi_init_gpio(uint8_t spi_no, uint8_t sysclk_as_spiclk);
|
||||
void spi_clock(uint8_t spi_no, uint16_t prediv, uint8_t cntdiv);
|
||||
void spi_tx_byte_order(uint8_t spi_no, uint8_t byte_order);
|
||||
void spi_rx_byte_order(uint8_t spi_no, uint8_t byte_order);
|
||||
uint32_t spi_transaction(uint8_t spi_no, uint8_t cmd_bits, uint16_t cmd_data,
|
||||
uint32_t addr_bits, uint32_t addr_data,
|
||||
uint32_t dout_bits, uint32_t dout_data,
|
||||
uint32_t din_bits, uint32_t dummy_bits);
|
||||
void spi_tx8fast(uint8_t spi_no, uint8_t dout_data);
|
||||
|
||||
// Expansion Macros
|
||||
#define spi_busy(spi_no) READ_PERI_REG(SPI_CMD(spi_no))&SPI_USR
|
||||
|
||||
#define spi_txd(spi_no, bits, data) spi_transaction(spi_no, 0, 0, 0, 0, bits, (uint32_t) data, 0, 0)
|
||||
#define spi_tx8(spi_no, data) spi_transaction(spi_no, 0, 0, 0, 0, 8, (uint32_t) data, 0, 0)
|
||||
#define spi_tx16(spi_no, data) spi_transaction(spi_no, 0, 0, 0, 0, 16, (uint32_t) data, 0, 0)
|
||||
#define spi_tx32(spi_no, data) spi_transaction(spi_no, 0, 0, 0, 0, 32, (uint32_t) data, 0, 0)
|
||||
|
||||
#define spi_rxd(spi_no, bits) spi_transaction(spi_no, 0, 0, 0, 0, 0, 0, bits, 0)
|
||||
#define spi_rx8(spi_no) spi_transaction(spi_no, 0, 0, 0, 0, 0, 0, 8, 0)
|
||||
#define spi_rx16(spi_no) spi_transaction(spi_no, 0, 0, 0, 0, 0, 0, 16, 0)
|
||||
#define spi_rx32(spi_no) spi_transaction(spi_no, 0, 0, 0, 0, 0, 0, 32, 0)
|
||||
|
||||
#endif
|
||||
278
esp8266/hspi_register.h
Normal file
278
esp8266/hspi_register.h
Normal file
@@ -0,0 +1,278 @@
|
||||
/*
|
||||
* Copyright (c) 2010 - 2011 Espressif System
|
||||
* Modified by David Ogilvy (MetalPhreak)
|
||||
* Based on original file included in SDK 1.0.0
|
||||
*
|
||||
* Missing defines from previous SDK versions have
|
||||
* been added and are noted with comments. The
|
||||
* names of these defines are likely to change.
|
||||
*/
|
||||
|
||||
#ifndef SPI_REGISTER_H_INCLUDED
|
||||
#define SPI_REGISTER_H_INCLUDED
|
||||
|
||||
#define REG_SPI_BASE(i) (0x60000200-i*0x100)
|
||||
|
||||
#define SPI_CMD(i) (REG_SPI_BASE(i) + 0x0)
|
||||
#define SPI_FLASH_READ (BIT(31)) //From previous SDK
|
||||
#define SPI_FLASH_WREN (BIT(30)) //From previous SDK
|
||||
#define SPI_FLASH_WRDI (BIT(29)) //From previous SDK
|
||||
#define SPI_FLASH_RDID (BIT(28)) //From previous SDK
|
||||
#define SPI_FLASH_RDSR (BIT(27)) //From previous SDK
|
||||
#define SPI_FLASH_WRSR (BIT(26)) //From previous SDK
|
||||
#define SPI_FLASH_PP (BIT(25)) //From previous SDK
|
||||
#define SPI_FLASH_SE (BIT(24)) //From previous SDK
|
||||
#define SPI_FLASH_BE (BIT(23)) //From previous SDK
|
||||
#define SPI_FLASH_CE (BIT(22)) //From previous SDK
|
||||
#define SPI_FLASH_DP (BIT(21)) //From previous SDK
|
||||
#define SPI_FLASH_RES (BIT(20)) //From previous SDK
|
||||
#define SPI_FLASH_HPM (BIT(19)) //From previous SDK
|
||||
#define SPI_USR (BIT(18))
|
||||
|
||||
#define SPI_ADDR(i) (REG_SPI_BASE(i) + 0x4)
|
||||
|
||||
#define SPI_CTRL(i) (REG_SPI_BASE(i) + 0x8)
|
||||
#define SPI_WR_BIT_ORDER (BIT(26))
|
||||
#define SPI_RD_BIT_ORDER (BIT(25))
|
||||
#define SPI_QIO_MODE (BIT(24))
|
||||
#define SPI_DIO_MODE (BIT(23))
|
||||
#define SPI_TWO_BYTE_STATUS_EN (BIT(22)) //From previous SDK
|
||||
#define SPI_WP_REG (BIT(21)) //From previous SDK
|
||||
#define SPI_QOUT_MODE (BIT(20))
|
||||
#define SPI_SHARE_BUS (BIT(19)) //From previous SDK
|
||||
#define SPI_HOLD_MODE (BIT(18)) //From previous SDK
|
||||
#define SPI_ENABLE_AHB (BIT(17)) //From previous SDK
|
||||
#define SPI_SST_AAI (BIT(16)) //From previous SDK
|
||||
#define SPI_RESANDRES (BIT(15)) //From previous SDK
|
||||
#define SPI_DOUT_MODE (BIT(14))
|
||||
#define SPI_FASTRD_MODE (BIT(13))
|
||||
|
||||
#define SPI_CTRL1(i) (REG_SPI_BASE (i) + 0xC) //From previous SDK. Removed _FLASH_ from name to match other registers.
|
||||
#define SPI_CS_HOLD_DELAY 0x0000000F //Espressif BBS
|
||||
#define SPI_CS_HOLD_DELAY_S 28 //Espressif BBS
|
||||
#define SPI_CS_HOLD_DELAY_RES 0x00000FFF //Espressif BBS
|
||||
#define SPI_CS_HOLD_DELAY_RES_S 16 //Espressif BBS
|
||||
#define SPI_BUS_TIMER_LIMIT 0x0000FFFF //From previous SDK
|
||||
#define SPI_BUS_TIMER_LIMIT_S 0 //From previous SDK
|
||||
|
||||
|
||||
#define SPI_RD_STATUS(i) (REG_SPI_BASE(i) + 0x10)
|
||||
#define SPI_STATUS_EXT 0x000000FF //From previous SDK
|
||||
#define SPI_STATUS_EXT_S 24 //From previous SDK
|
||||
#define SPI_WB_MODE 0x000000FF //From previous SDK
|
||||
#define SPI_WB_MODE_S 16 //From previous SDK
|
||||
#define SPI_FLASH_STATUS_PRO_FLAG (BIT(7)) //From previous SDK
|
||||
#define SPI_FLASH_TOP_BOT_PRO_FLAG (BIT(5)) //From previous SDK
|
||||
#define SPI_FLASH_BP2 (BIT(4)) //From previous SDK
|
||||
#define SPI_FLASH_BP1 (BIT(3)) //From previous SDK
|
||||
#define SPI_FLASH_BP0 (BIT(2)) //From previous SDK
|
||||
#define SPI_FLASH_WRENABLE_FLAG (BIT(1)) //From previous SDK
|
||||
#define SPI_FLASH_BUSY_FLAG (BIT(0)) //From previous SDK
|
||||
|
||||
#define SPI_CTRL2(i) (REG_SPI_BASE(i) + 0x14)
|
||||
#define SPI_CS_DELAY_NUM 0x0000000F
|
||||
#define SPI_CS_DELAY_NUM_S 28
|
||||
#define SPI_CS_DELAY_MODE 0x00000003
|
||||
#define SPI_CS_DELAY_MODE_S 26
|
||||
#define SPI_MOSI_DELAY_NUM 0x00000007
|
||||
#define SPI_MOSI_DELAY_NUM_S 23
|
||||
#define SPI_MOSI_DELAY_MODE 0x00000003 //mode 0 : posedge; data set at positive edge of clk
|
||||
//mode 1 : negedge + 1 cycle delay, only if freq<10MHz ; data set at negitive edge of clk
|
||||
//mode 2 : Do not use this mode.
|
||||
#define SPI_MOSI_DELAY_MODE_S 21
|
||||
#define SPI_MISO_DELAY_NUM 0x00000007
|
||||
#define SPI_MISO_DELAY_NUM_S 18
|
||||
#define SPI_MISO_DELAY_MODE 0x00000003
|
||||
#define SPI_MISO_DELAY_MODE_S 16
|
||||
#define SPI_CK_OUT_HIGH_MODE 0x0000000F
|
||||
#define SPI_CK_OUT_HIGH_MODE_S 12
|
||||
#define SPI_CK_OUT_LOW_MODE 0x0000000F
|
||||
#define SPI_CK_OUT_LOW_MODE_S 8
|
||||
#define SPI_HOLD_TIME 0x0000000F
|
||||
#define SPI_HOLD_TIME_S 4
|
||||
#define SPI_SETUP_TIME 0x0000000F
|
||||
#define SPI_SETUP_TIME_S 0
|
||||
|
||||
#define SPI_CLOCK(i) (REG_SPI_BASE(i) + 0x18)
|
||||
#define SPI_CLK_EQU_SYSCLK (BIT(31))
|
||||
#define SPI_CLKDIV_PRE 0x00001FFF
|
||||
#define SPI_CLKDIV_PRE_S 18
|
||||
#define SPI_CLKCNT_N 0x0000003F
|
||||
#define SPI_CLKCNT_N_S 12
|
||||
#define SPI_CLKCNT_H 0x0000003F
|
||||
#define SPI_CLKCNT_H_S 6
|
||||
#define SPI_CLKCNT_L 0x0000003F
|
||||
#define SPI_CLKCNT_L_S 0
|
||||
|
||||
#define SPI_USER(i) (REG_SPI_BASE(i) + 0x1C)
|
||||
#define SPI_USR_COMMAND (BIT(31))
|
||||
#define SPI_USR_ADDR (BIT(30))
|
||||
#define SPI_USR_DUMMY (BIT(29))
|
||||
#define SPI_USR_MISO (BIT(28))
|
||||
#define SPI_USR_MOSI (BIT(27))
|
||||
#define SPI_USR_DUMMY_IDLE (BIT(26)) //From previous SDK
|
||||
#define SPI_USR_MOSI_HIGHPART (BIT(25))
|
||||
#define SPI_USR_MISO_HIGHPART (BIT(24))
|
||||
#define SPI_USR_PREP_HOLD (BIT(23)) //From previous SDK
|
||||
#define SPI_USR_CMD_HOLD (BIT(22)) //From previous SDK
|
||||
#define SPI_USR_ADDR_HOLD (BIT(21)) //From previous SDK
|
||||
#define SPI_USR_DUMMY_HOLD (BIT(20)) //From previous SDK
|
||||
#define SPI_USR_DIN_HOLD (BIT(19)) //From previous SDK
|
||||
#define SPI_USR_DOUT_HOLD (BIT(18)) //From previous SDK
|
||||
#define SPI_USR_HOLD_POL (BIT(17)) //From previous SDK
|
||||
#define SPI_SIO (BIT(16))
|
||||
#define SPI_FWRITE_QIO (BIT(15))
|
||||
#define SPI_FWRITE_DIO (BIT(14))
|
||||
#define SPI_FWRITE_QUAD (BIT(13))
|
||||
#define SPI_FWRITE_DUAL (BIT(12))
|
||||
#define SPI_WR_BYTE_ORDER (BIT(11))
|
||||
#define SPI_RD_BYTE_ORDER (BIT(10))
|
||||
#define SPI_AHB_ENDIAN_MODE 0x00000003 //From previous SDK
|
||||
#define SPI_AHB_ENDIAN_MODE_S 8 //From previous SDK
|
||||
#define SPI_CK_OUT_EDGE (BIT(7))
|
||||
#define SPI_CK_I_EDGE (BIT(6))
|
||||
#define SPI_CS_SETUP (BIT(5))
|
||||
#define SPI_CS_HOLD (BIT(4))
|
||||
#define SPI_AHB_USR_COMMAND (BIT(3)) //From previous SDK
|
||||
#define SPI_FLASH_MODE (BIT(2))
|
||||
#define SPI_AHB_USR_COMMAND_4BYTE (BIT(1)) //From previous SDK
|
||||
#define SPI_DOUTDIN (BIT(0)) //From previous SDK
|
||||
|
||||
//AHB = http://en.wikipedia.org/wiki/Advanced_Microcontroller_Bus_Architecture ?
|
||||
|
||||
|
||||
#define SPI_USER1(i) (REG_SPI_BASE(i) + 0x20)
|
||||
#define SPI_USR_ADDR_BITLEN 0x0000003F
|
||||
#define SPI_USR_ADDR_BITLEN_S 26
|
||||
#define SPI_USR_MOSI_BITLEN 0x000001FF
|
||||
#define SPI_USR_MOSI_BITLEN_S 17
|
||||
#define SPI_USR_MISO_BITLEN 0x000001FF
|
||||
#define SPI_USR_MISO_BITLEN_S 8
|
||||
#define SPI_USR_DUMMY_CYCLELEN 0x000000FF
|
||||
#define SPI_USR_DUMMY_CYCLELEN_S 0
|
||||
|
||||
#define SPI_USER2(i) (REG_SPI_BASE(i) + 0x24)
|
||||
#define SPI_USR_COMMAND_BITLEN 0x0000000F
|
||||
#define SPI_USR_COMMAND_BITLEN_S 28
|
||||
#define SPI_USR_COMMAND_VALUE 0x0000FFFF
|
||||
#define SPI_USR_COMMAND_VALUE_S 0
|
||||
|
||||
#define SPI_WR_STATUS(i) (REG_SPI_BASE(i) + 0x28)
|
||||
//previously defined as SPI_FLASH_USER3. No further info available.
|
||||
|
||||
#define SPI_PIN(i) (REG_SPI_BASE(i) + 0x2C)
|
||||
#define SPI_IDLE_EDGE (BIT(29))
|
||||
#define SPI_CS2_DIS (BIT(2))
|
||||
#define SPI_CS1_DIS (BIT(1))
|
||||
#define SPI_CS0_DIS (BIT(0))
|
||||
|
||||
#define SPI_SLAVE(i) (REG_SPI_BASE(i) + 0x30)
|
||||
#define SPI_SYNC_RESET (BIT(31))
|
||||
#define SPI_SLAVE_MODE (BIT(30))
|
||||
#define SPI_SLV_WR_RD_BUF_EN (BIT(29))
|
||||
#define SPI_SLV_WR_RD_STA_EN (BIT(28))
|
||||
#define SPI_SLV_CMD_DEFINE (BIT(27))
|
||||
#define SPI_TRANS_CNT 0x0000000F
|
||||
#define SPI_TRANS_CNT_S 23
|
||||
#define SPI_SLV_LAST_STATE 0x00000007 //From previous SDK
|
||||
#define SPI_SLV_LAST_STATE_S 20 //From previous SDK
|
||||
#define SPI_SLV_LAST_COMMAND 0x00000007 //From previous SDK
|
||||
#define SPI_SLV_LAST_COMMAND_S 17 //From previous SDK
|
||||
#define SPI_CS_I_MODE 0x00000003 //From previous SDK
|
||||
#define SPI_CS_I_MODE_S 10 //From previous SDK
|
||||
#define SPI_TRANS_DONE_EN (BIT(9))
|
||||
#define SPI_SLV_WR_STA_DONE_EN (BIT(8))
|
||||
#define SPI_SLV_RD_STA_DONE_EN (BIT(7))
|
||||
#define SPI_SLV_WR_BUF_DONE_EN (BIT(6))
|
||||
#define SPI_SLV_RD_BUF_DONE_EN (BIT(5))
|
||||
#define SLV_SPI_INT_EN 0x0000001f
|
||||
#define SLV_SPI_INT_EN_S 5
|
||||
#define SPI_TRANS_DONE (BIT(4))
|
||||
#define SPI_SLV_WR_STA_DONE (BIT(3))
|
||||
#define SPI_SLV_RD_STA_DONE (BIT(2))
|
||||
#define SPI_SLV_WR_BUF_DONE (BIT(1))
|
||||
#define SPI_SLV_RD_BUF_DONE (BIT(0))
|
||||
|
||||
#define SPI_SLAVE1(i) (REG_SPI_BASE(i) + 0x34)
|
||||
#define SPI_SLV_STATUS_BITLEN 0x0000001F
|
||||
#define SPI_SLV_STATUS_BITLEN_S 27
|
||||
#define SPI_SLV_STATUS_FAST_EN (BIT(26)) //From previous SDK
|
||||
#define SPI_SLV_STATUS_READBACK (BIT(25)) //From previous SDK
|
||||
#define SPI_SLV_BUF_BITLEN 0x000001FF
|
||||
#define SPI_SLV_BUF_BITLEN_S 16
|
||||
#define SPI_SLV_RD_ADDR_BITLEN 0x0000003F
|
||||
#define SPI_SLV_RD_ADDR_BITLEN_S 10
|
||||
#define SPI_SLV_WR_ADDR_BITLEN 0x0000003F
|
||||
#define SPI_SLV_WR_ADDR_BITLEN_S 4
|
||||
#define SPI_SLV_WRSTA_DUMMY_EN (BIT(3))
|
||||
#define SPI_SLV_RDSTA_DUMMY_EN (BIT(2))
|
||||
#define SPI_SLV_WRBUF_DUMMY_EN (BIT(1))
|
||||
#define SPI_SLV_RDBUF_DUMMY_EN (BIT(0))
|
||||
|
||||
|
||||
|
||||
#define SPI_SLAVE2(i) (REG_SPI_BASE(i) + 0x38)
|
||||
#define SPI_SLV_WRBUF_DUMMY_CYCLELEN 0X000000FF
|
||||
#define SPI_SLV_WRBUF_DUMMY_CYCLELEN_S 24
|
||||
#define SPI_SLV_RDBUF_DUMMY_CYCLELEN 0X000000FF
|
||||
#define SPI_SLV_RDBUF_DUMMY_CYCLELEN_S 16
|
||||
#define SPI_SLV_WRSTR_DUMMY_CYCLELEN 0X000000FF
|
||||
#define SPI_SLV_WRSTR_DUMMY_CYCLELEN_S 8
|
||||
#define SPI_SLV_RDSTR_DUMMY_CYCLELEN 0x000000FF
|
||||
#define SPI_SLV_RDSTR_DUMMY_CYCLELEN_S 0
|
||||
|
||||
#define SPI_SLAVE3(i) (REG_SPI_BASE(i) + 0x3C)
|
||||
#define SPI_SLV_WRSTA_CMD_VALUE 0x000000FF
|
||||
#define SPI_SLV_WRSTA_CMD_VALUE_S 24
|
||||
#define SPI_SLV_RDSTA_CMD_VALUE 0x000000FF
|
||||
#define SPI_SLV_RDSTA_CMD_VALUE_S 16
|
||||
#define SPI_SLV_WRBUF_CMD_VALUE 0x000000FF
|
||||
#define SPI_SLV_WRBUF_CMD_VALUE_S 8
|
||||
#define SPI_SLV_RDBUF_CMD_VALUE 0x000000FF
|
||||
#define SPI_SLV_RDBUF_CMD_VALUE_S 0
|
||||
|
||||
//Previous SDKs referred to these following registers as SPI_C0 etc.
|
||||
|
||||
#define SPI_W0(i) (REG_SPI_BASE(i) +0x40)
|
||||
#define SPI_W1(i) (REG_SPI_BASE(i) +0x44)
|
||||
#define SPI_W2(i) (REG_SPI_BASE(i) +0x48)
|
||||
#define SPI_W3(i) (REG_SPI_BASE(i) +0x4C)
|
||||
#define SPI_W4(i) (REG_SPI_BASE(i) +0x50)
|
||||
#define SPI_W5(i) (REG_SPI_BASE(i) +0x54)
|
||||
#define SPI_W6(i) (REG_SPI_BASE(i) +0x58)
|
||||
#define SPI_W7(i) (REG_SPI_BASE(i) +0x5C)
|
||||
#define SPI_W8(i) (REG_SPI_BASE(i) +0x60)
|
||||
#define SPI_W9(i) (REG_SPI_BASE(i) +0x64)
|
||||
#define SPI_W10(i) (REG_SPI_BASE(i) +0x68)
|
||||
#define SPI_W11(i) (REG_SPI_BASE(i) +0x6C)
|
||||
#define SPI_W12(i) (REG_SPI_BASE(i) +0x70)
|
||||
#define SPI_W13(i) (REG_SPI_BASE(i) +0x74)
|
||||
#define SPI_W14(i) (REG_SPI_BASE(i) +0x78)
|
||||
#define SPI_W15(i) (REG_SPI_BASE(i) +0x7C)
|
||||
|
||||
// +0x80 to +0xBC could be SPI_W16 through SPI_W31?
|
||||
|
||||
// +0xC0 to +0xEC not currently defined.
|
||||
|
||||
#define SPI_EXT0(i) (REG_SPI_BASE(i) + 0xF0) //From previous SDK. Removed _FLASH_ from name to match other registers.
|
||||
#define SPI_T_PP_ENA (BIT(31)) //From previous SDK
|
||||
#define SPI_T_PP_SHIFT 0x0000000F //From previous SDK
|
||||
#define SPI_T_PP_SHIFT_S 16 //From previous SDK
|
||||
#define SPI_T_PP_TIME 0x00000FFF //From previous SDK
|
||||
#define SPI_T_PP_TIME_S 0 //From previous SDK
|
||||
|
||||
#define SPI_EXT1(i) (REG_SPI_BASE(i) + 0xF4) //From previous SDK. Removed _FLASH_ from name to match other registers.
|
||||
#define SPI_T_ERASE_ENA (BIT(31)) //From previous SDK
|
||||
#define SPI_T_ERASE_SHIFT 0x0000000F //From previous SDK
|
||||
#define SPI_T_ERASE_SHIFT_S 16 //From previous SDK
|
||||
#define SPI_T_ERASE_TIME 0x00000FFF //From previous SDK
|
||||
#define SPI_T_ERASE_TIME_S 0 //From previous SDK
|
||||
|
||||
#define SPI_EXT2(i) (REG_SPI_BASE(i) + 0xF8) //From previous SDK. Removed _FLASH_ from name to match other registers.
|
||||
#define SPI_ST 0x00000007 //From previous SDK
|
||||
#define SPI_ST_S 0 //From previous SDK
|
||||
|
||||
#define SPI_EXT3(i) (REG_SPI_BASE(i) + 0xFC)
|
||||
#define SPI_INT_HOLD_ENA 0x00000003
|
||||
#define SPI_INT_HOLD_ENA_S 0
|
||||
#endif // SPI_REGISTER_H_INCLUDED
|
||||
@@ -49,8 +49,8 @@ STATIC void mp_reset(void) {
|
||||
mp_init();
|
||||
mp_obj_list_init(mp_sys_path, 0);
|
||||
mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR_)); // current dir (or base dir of the script)
|
||||
mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_));
|
||||
mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_lib));
|
||||
mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_));
|
||||
mp_obj_list_init(mp_sys_argv, 0);
|
||||
#if MICROPY_VFS_FAT
|
||||
memset(MP_STATE_PORT(fs_user_mount), 0, sizeof(MP_STATE_PORT(fs_user_mount)));
|
||||
@@ -60,6 +60,7 @@ STATIC void mp_reset(void) {
|
||||
MP_STATE_PORT(dupterm_arr_obj) = MP_OBJ_NULL;
|
||||
pin_init0();
|
||||
readline_init0();
|
||||
dupterm_task_init();
|
||||
#if MICROPY_MODULE_FROZEN
|
||||
pyexec_frozen_module("_boot.py");
|
||||
pyexec_file("boot.py");
|
||||
@@ -85,7 +86,6 @@ void init_done(void) {
|
||||
#if MICROPY_REPL_EVENT_DRIVEN
|
||||
pyexec_event_repl_init();
|
||||
#endif
|
||||
dupterm_task_init();
|
||||
|
||||
#if !MICROPY_REPL_EVENT_DRIVEN
|
||||
soft_reset:
|
||||
@@ -141,10 +141,6 @@ mp_obj_t mp_builtin_open(uint n_args, const mp_obj_t *args, mp_map_t *kwargs) {
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_open_obj, 1, mp_builtin_open);
|
||||
|
||||
void mp_keyboard_interrupt(void) {
|
||||
MP_STATE_VM(mp_pending_exception) = MP_STATE_PORT(mp_kbd_exception);
|
||||
}
|
||||
|
||||
void nlr_jump_fail(void *val) {
|
||||
printf("NLR jump failed\n");
|
||||
for (;;) {
|
||||
|
||||
@@ -1,23 +1,40 @@
|
||||
import sys
|
||||
import struct
|
||||
import hashlib
|
||||
|
||||
SEGS_MAX_SIZE = 0x9000
|
||||
|
||||
assert len(sys.argv) == 4
|
||||
|
||||
md5 = hashlib.md5()
|
||||
|
||||
with open(sys.argv[3], 'wb') as fout:
|
||||
|
||||
with open(sys.argv[1], 'rb') as f:
|
||||
data_flash = f.read()
|
||||
fout.write(data_flash)
|
||||
# First 4 bytes include flash size, etc. which may be changed
|
||||
# by esptool.py, etc.
|
||||
md5.update(data_flash[4:])
|
||||
print('flash ', len(data_flash))
|
||||
|
||||
pad = b'\xff' * (SEGS_MAX_SIZE - len(data_flash))
|
||||
fout.write(pad)
|
||||
print('padding ', len(pad))
|
||||
|
||||
with open(sys.argv[2], 'rb') as f:
|
||||
data_rom = f.read()
|
||||
fout.write(data_rom)
|
||||
print('irom0text', len(data_rom))
|
||||
|
||||
pad = b'\xff' * (SEGS_MAX_SIZE - len(data_flash))
|
||||
assert len(pad) >= 4
|
||||
fout.write(pad[:-4])
|
||||
md5.update(pad[:-4])
|
||||
len_data = struct.pack("I", SEGS_MAX_SIZE + len(data_rom))
|
||||
fout.write(len_data)
|
||||
md5.update(len_data)
|
||||
print('padding ', len(pad))
|
||||
|
||||
fout.write(data_rom)
|
||||
md5.update(data_rom)
|
||||
print('irom0text', len(data_rom))
|
||||
|
||||
fout.write(md5.digest())
|
||||
|
||||
print('total ', SEGS_MAX_SIZE + len(data_rom))
|
||||
print('md5 ', md5.hexdigest())
|
||||
|
||||
@@ -583,7 +583,7 @@ STATIC mp_obj_t esp_flash_read(mp_obj_t offset_in, mp_obj_t len_or_buf_in) {
|
||||
if (alloc_buf) {
|
||||
m_del(byte, buf, len);
|
||||
}
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(res == SPI_FLASH_RESULT_TIMEOUT ? MP_ETIMEDOUT : MP_EIO)));
|
||||
mp_raise_OSError(res == SPI_FLASH_RESULT_TIMEOUT ? MP_ETIMEDOUT : MP_EIO);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(esp_flash_read_obj, esp_flash_read);
|
||||
|
||||
@@ -598,9 +598,7 @@ STATIC mp_obj_t esp_flash_write(mp_obj_t offset_in, const mp_obj_t buf_in) {
|
||||
if (res == SPI_FLASH_RESULT_OK) {
|
||||
return mp_const_none;
|
||||
}
|
||||
nlr_raise(mp_obj_new_exception_arg1(
|
||||
&mp_type_OSError,
|
||||
MP_OBJ_NEW_SMALL_INT(res == SPI_FLASH_RESULT_TIMEOUT ? MP_ETIMEDOUT : MP_EIO)));
|
||||
mp_raise_OSError(res == SPI_FLASH_RESULT_TIMEOUT ? MP_ETIMEDOUT : MP_EIO);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(esp_flash_write_obj, esp_flash_write);
|
||||
|
||||
@@ -610,9 +608,7 @@ STATIC mp_obj_t esp_flash_erase(mp_obj_t sector_in) {
|
||||
if (res == SPI_FLASH_RESULT_OK) {
|
||||
return mp_const_none;
|
||||
}
|
||||
nlr_raise(mp_obj_new_exception_arg1(
|
||||
&mp_type_OSError,
|
||||
MP_OBJ_NEW_SMALL_INT(res == SPI_FLASH_RESULT_TIMEOUT ? MP_ETIMEDOUT : MP_EIO)));
|
||||
mp_raise_OSError(res == SPI_FLASH_RESULT_TIMEOUT ? MP_ETIMEDOUT : MP_EIO);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_flash_erase_obj, esp_flash_erase);
|
||||
|
||||
@@ -633,6 +629,24 @@ STATIC mp_obj_t esp_flash_size(void) {
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(esp_flash_size_obj, esp_flash_size);
|
||||
|
||||
STATIC mp_obj_t esp_check_fw(void) {
|
||||
MD5_CTX ctx;
|
||||
uint32_t *sz_p = (uint32_t*)0x40208ffc;
|
||||
printf("size: %d\n", *sz_p);
|
||||
MD5Init(&ctx);
|
||||
MD5Update(&ctx, (char*)0x40200004, *sz_p - 4);
|
||||
unsigned char digest[16];
|
||||
MD5Final(digest, &ctx);
|
||||
printf("md5: ");
|
||||
for (int i = 0; i < 16; i++) {
|
||||
printf("%02x", digest[i]);
|
||||
}
|
||||
printf("\n");
|
||||
return mp_obj_new_bool(memcmp(digest, (void*)(0x40200000 + *sz_p), sizeof(digest)) == 0);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(esp_check_fw_obj, esp_check_fw);
|
||||
|
||||
|
||||
STATIC mp_obj_t esp_neopixel_write_(mp_obj_t pin, mp_obj_t buf, mp_obj_t is800k) {
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_READ);
|
||||
@@ -642,6 +656,7 @@ STATIC mp_obj_t esp_neopixel_write_(mp_obj_t pin, mp_obj_t buf, mp_obj_t is800k)
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_3(esp_neopixel_write_obj, esp_neopixel_write_);
|
||||
|
||||
#if MICROPY_ESP8266_APA102
|
||||
STATIC mp_obj_t esp_apa102_write_(mp_obj_t clockPin, mp_obj_t dataPin, mp_obj_t buf) {
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_READ);
|
||||
@@ -651,6 +666,7 @@ STATIC mp_obj_t esp_apa102_write_(mp_obj_t clockPin, mp_obj_t dataPin, mp_obj_t
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_3(esp_apa102_write_obj, esp_apa102_write_);
|
||||
#endif
|
||||
|
||||
STATIC mp_obj_t esp_freemem() {
|
||||
return MP_OBJ_NEW_SMALL_INT(system_get_free_heap_size());
|
||||
@@ -694,11 +710,16 @@ STATIC const mp_map_elem_t esp_module_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_socket), (mp_obj_t)&esp_socket_type },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_getaddrinfo), (mp_obj_t)&esp_getaddrinfo_obj },
|
||||
#endif
|
||||
#if MICROPY_ESP8266_NEOPIXEL
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_neopixel_write), (mp_obj_t)&esp_neopixel_write_obj },
|
||||
#endif
|
||||
#if MICROPY_ESP8266_APA102
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_apa102_write), (mp_obj_t)&esp_apa102_write_obj },
|
||||
#endif
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_dht_readinto), (mp_obj_t)&dht_readinto_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_freemem), (mp_obj_t)&esp_freemem_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_meminfo), (mp_obj_t)&esp_meminfo_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_check_fw), (mp_obj_t)&esp_check_fw_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_info), (mp_obj_t)&pyb_info_obj }, // TODO delete/rename/move elsewhere
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_malloc), (mp_obj_t)&esp_malloc_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_free), (mp_obj_t)&esp_free_obj },
|
||||
@@ -725,6 +746,5 @@ STATIC MP_DEFINE_CONST_DICT(esp_module_globals, esp_module_globals_table);
|
||||
|
||||
const mp_obj_module_t esp_module = {
|
||||
.base = { &mp_type_module },
|
||||
.name = MP_QSTR_esp,
|
||||
.globals = (mp_obj_dict_t*)&esp_module_globals,
|
||||
};
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "py/obj.h"
|
||||
#include "py/runtime.h"
|
||||
@@ -48,6 +49,8 @@
|
||||
//#define MACHINE_WAKE_SLEEP (0x02)
|
||||
#define MACHINE_WAKE_DEEPSLEEP (0x04)
|
||||
|
||||
extern const mp_obj_type_t esp_wdt_type;
|
||||
|
||||
STATIC mp_obj_t machine_freq(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
if (n_args == 0) {
|
||||
// get
|
||||
@@ -82,6 +85,20 @@ STATIC mp_obj_t machine_unique_id(void) {
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_unique_id_obj, machine_unique_id);
|
||||
|
||||
STATIC mp_obj_t machine_idle(void) {
|
||||
uint32_t t = mp_hal_ticks_cpu();
|
||||
asm("waiti 0");
|
||||
t = mp_hal_ticks_cpu() - t;
|
||||
return MP_OBJ_NEW_SMALL_INT(t);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_idle_obj, machine_idle);
|
||||
|
||||
STATIC mp_obj_t machine_sleep(void) {
|
||||
printf("Warning: not yet implemented\n");
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_sleep_obj, machine_sleep);
|
||||
|
||||
STATIC mp_obj_t machine_deepsleep(void) {
|
||||
// default to sleep forever
|
||||
uint32_t sleep_us = 0;
|
||||
@@ -222,6 +239,8 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&machine_reset_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_reset_cause), MP_ROM_PTR(&machine_reset_cause_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_unique_id), MP_ROM_PTR(&machine_unique_id_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_idle), MP_ROM_PTR(&machine_idle_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_sleep), MP_ROM_PTR(&machine_sleep_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_deepsleep), MP_ROM_PTR(&machine_deepsleep_obj) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_disable_irq), MP_ROM_PTR(&machine_disable_irq_obj) },
|
||||
@@ -231,27 +250,29 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = {
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_RTC), MP_ROM_PTR(&pyb_rtc_type) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_Timer), MP_ROM_PTR(&esp_timer_type) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_WDT), MP_ROM_PTR(&esp_wdt_type) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_Pin), MP_ROM_PTR(&pyb_pin_type) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_PWM), MP_ROM_PTR(&pyb_pwm_type) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_ADC), MP_ROM_PTR(&pyb_adc_type) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&pyb_uart_type) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&machine_i2c_type) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&pyb_spi_type) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&pyb_hspi_type) },
|
||||
|
||||
// wake abilities
|
||||
{ MP_ROM_QSTR(MP_QSTR_DEEPSLEEP), MP_ROM_INT(MACHINE_WAKE_DEEPSLEEP) },
|
||||
|
||||
// reset causes
|
||||
{ MP_ROM_QSTR(MP_QSTR_PWR_ON_RESET), MP_ROM_INT(REASON_EXT_SYS_RST) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_PWRON_RESET), MP_ROM_INT(REASON_DEFAULT_RST) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_HARD_RESET), MP_ROM_INT(REASON_EXT_SYS_RST) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_DEEPSLEEP_RESET), MP_ROM_INT(REASON_DEEP_SLEEP_AWAKE) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_WDT_RESET), MP_ROM_INT(REASON_WDT_RST) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_SOFT_RESET), MP_ROM_INT(REASON_SOFT_RESTART) },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(machine_module_globals, machine_module_globals_table);
|
||||
|
||||
const mp_obj_module_t mp_module_machine = {
|
||||
.base = { &mp_type_module },
|
||||
.name = MP_QSTR_umachine,
|
||||
.globals = (mp_obj_dict_t*)&machine_module_globals,
|
||||
};
|
||||
|
||||
|
||||
85
esp8266/modmachinewdt.c
Normal file
85
esp8266/modmachinewdt.c
Normal file
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2016 Paul Sokolovsky
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
//#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "py/nlr.h"
|
||||
#include "py/obj.h"
|
||||
#include "py/runtime.h"
|
||||
#include "user_interface.h"
|
||||
#include "etshal.h"
|
||||
|
||||
const mp_obj_type_t esp_wdt_type;
|
||||
|
||||
typedef struct _machine_wdt_obj_t {
|
||||
mp_obj_base_t base;
|
||||
} machine_wdt_obj_t;
|
||||
|
||||
STATIC machine_wdt_obj_t wdt_default = {{&esp_wdt_type}};
|
||||
|
||||
STATIC mp_obj_t machine_wdt_make_new(const mp_obj_type_t *type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
|
||||
mp_arg_check_num(n_args, n_kw, 0, 1, false);
|
||||
|
||||
mp_int_t id = 0;
|
||||
if (n_args > 0) {
|
||||
id = mp_obj_get_int(args[0]);
|
||||
}
|
||||
|
||||
switch (id) {
|
||||
case 0:
|
||||
return &wdt_default;
|
||||
default:
|
||||
mp_raise_ValueError("");
|
||||
}
|
||||
}
|
||||
|
||||
STATIC mp_obj_t machine_wdt_feed(mp_obj_t self_in) {
|
||||
(void)self_in;
|
||||
system_soft_wdt_feed();
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_wdt_feed_obj, machine_wdt_feed);
|
||||
|
||||
STATIC mp_obj_t machine_wdt_deinit(mp_obj_t self_in) {
|
||||
(void)self_in;
|
||||
ets_wdt_disable();
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_wdt_deinit_obj, machine_wdt_deinit);
|
||||
|
||||
STATIC const mp_map_elem_t machine_wdt_locals_dict_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_feed), (mp_obj_t)&machine_wdt_feed_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_deinit), (mp_obj_t)&machine_wdt_deinit_obj },
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(machine_wdt_locals_dict, machine_wdt_locals_dict_table);
|
||||
|
||||
const mp_obj_type_t esp_wdt_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_WDT,
|
||||
.make_new = machine_wdt_make_new,
|
||||
.locals_dict = (mp_obj_t)&machine_wdt_locals_dict,
|
||||
};
|
||||
@@ -130,17 +130,16 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_status_obj, esp_status);
|
||||
|
||||
STATIC mp_obj_t *esp_scan_list = NULL;
|
||||
|
||||
STATIC void esp_scan_cb(scaninfo *si, STATUS status) {
|
||||
STATIC void esp_scan_cb(void *result, STATUS status) {
|
||||
if (esp_scan_list == NULL) {
|
||||
// called unexpectedly
|
||||
return;
|
||||
}
|
||||
if (si->pbss && status == 0) {
|
||||
if (result && status == 0) {
|
||||
// we need to catch any memory errors
|
||||
nlr_buf_t nlr;
|
||||
if (nlr_push(&nlr) == 0) {
|
||||
struct bss_info *bs;
|
||||
STAILQ_FOREACH(bs, si->pbss, next) {
|
||||
for (struct bss_info *bs = result; bs; bs = STAILQ_NEXT(bs, next)) {
|
||||
mp_obj_tuple_t *t = mp_obj_new_tuple(6, NULL);
|
||||
#if 1
|
||||
// struct bss_info::ssid_len is not documented in SDK API Guide,
|
||||
@@ -485,6 +484,5 @@ STATIC MP_DEFINE_CONST_DICT(mp_module_network_globals, mp_module_network_globals
|
||||
|
||||
const mp_obj_module_t network_module = {
|
||||
.base = { &mp_type_module },
|
||||
.name = MP_QSTR_network,
|
||||
.globals = (mp_obj_dict_t*)&mp_module_network_globals,
|
||||
};
|
||||
|
||||
@@ -117,6 +117,5 @@ STATIC MP_DEFINE_CONST_DICT(onewire_module_globals, onewire_module_globals_table
|
||||
|
||||
const mp_obj_module_t onewire_module = {
|
||||
.base = { &mp_type_module },
|
||||
.name = MP_QSTR_onewire,
|
||||
.globals = (mp_obj_dict_t*)&onewire_module_globals,
|
||||
};
|
||||
|
||||
@@ -10,6 +10,8 @@ extern const mp_obj_type_t pyb_rtc_type;
|
||||
extern const mp_obj_type_t pyb_uart_type;
|
||||
extern const mp_obj_type_t pyb_i2c_type;
|
||||
extern const mp_obj_type_t pyb_spi_type;
|
||||
extern const mp_obj_type_t pyb_hspi_type;
|
||||
extern const mp_obj_type_t machine_spi_type;
|
||||
|
||||
MP_DECLARE_CONST_FUN_OBJ(pyb_info_obj);
|
||||
|
||||
|
||||
212
esp8266/modpybhspi.c
Normal file
212
esp8266/modpybhspi.c
Normal file
@@ -0,0 +1,212 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2016 Damien P. George
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ets_sys.h"
|
||||
#include "etshal.h"
|
||||
#include "ets_alt_task.h"
|
||||
|
||||
#include "py/runtime.h"
|
||||
#include "py/stream.h"
|
||||
#include "py/mphal.h"
|
||||
#include "extmod/machine_spi.h"
|
||||
|
||||
#include "hspi.h"
|
||||
|
||||
mp_obj_t pyb_spi_make_new(const mp_obj_type_t *type, size_t n_args,
|
||||
size_t n_kw, const mp_obj_t *args);
|
||||
|
||||
typedef struct _pyb_hspi_obj_t {
|
||||
mp_obj_base_t base;
|
||||
uint32_t baudrate;
|
||||
uint8_t polarity;
|
||||
uint8_t phase;
|
||||
} pyb_hspi_obj_t;
|
||||
|
||||
|
||||
STATIC void hspi_transfer(mp_obj_base_t *self_in, size_t len, const uint8_t *src, uint8_t *dest) {
|
||||
(void)self_in;
|
||||
|
||||
if (dest == NULL) {
|
||||
// fast case when we only need to write data
|
||||
size_t chunk_size = 1024;
|
||||
size_t count = len / chunk_size;
|
||||
size_t i = 0;
|
||||
for (size_t j = 0; j < count; ++j) {
|
||||
for (size_t k = 0; k < chunk_size; ++k) {
|
||||
spi_tx8fast(HSPI, src[i]);
|
||||
++i;
|
||||
}
|
||||
ets_loop_iter();
|
||||
}
|
||||
while (i < len) {
|
||||
spi_tx8fast(HSPI, src[i]);
|
||||
++i;
|
||||
}
|
||||
} else {
|
||||
// we need to read and write data
|
||||
|
||||
// Process data in chunks, let the pending tasks run in between
|
||||
size_t chunk_size = 1024; // TODO this should depend on baudrate
|
||||
size_t count = len / chunk_size;
|
||||
size_t i = 0;
|
||||
for (size_t j = 0; j < count; ++j) {
|
||||
for (size_t k = 0; k < chunk_size; ++k) {
|
||||
dest[i] = spi_transaction(HSPI, 0, 0, 0, 0, 8, src[i], 8, 0);
|
||||
++i;
|
||||
}
|
||||
ets_loop_iter();
|
||||
}
|
||||
while (i < len) {
|
||||
dest[i] = spi_transaction(HSPI, 0, 0, 0, 0, 8, src[i], 8, 0);
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
// MicroPython bindings for HSPI
|
||||
|
||||
STATIC void pyb_hspi_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
pyb_hspi_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
mp_printf(print, "HSPI(id=1, baudrate=%u, polarity=%u, phase=%u)",
|
||||
self->baudrate, self->polarity, self->phase);
|
||||
}
|
||||
|
||||
STATIC void pyb_hspi_init_helper(pyb_hspi_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_id, ARG_baudrate, ARG_polarity, ARG_phase };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_id, MP_ARG_INT, {.u_int = -1} },
|
||||
{ MP_QSTR_baudrate, MP_ARG_INT, {.u_int = -1} },
|
||||
{ MP_QSTR_polarity, MP_ARG_INT, {.u_int = -1} },
|
||||
{ MP_QSTR_phase, MP_ARG_INT, {.u_int = -1} },
|
||||
};
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args),
|
||||
allowed_args, args);
|
||||
|
||||
if (args[ARG_baudrate].u_int != -1) {
|
||||
self->baudrate = args[ARG_baudrate].u_int;
|
||||
}
|
||||
if (args[ARG_polarity].u_int != -1) {
|
||||
self->polarity = args[ARG_polarity].u_int;
|
||||
}
|
||||
if (args[ARG_phase].u_int != -1) {
|
||||
self->phase = args[ARG_phase].u_int;
|
||||
}
|
||||
if (self->baudrate == 80000000L) {
|
||||
// Special case for full speed.
|
||||
spi_init_gpio(HSPI, SPI_CLK_80MHZ_NODIV);
|
||||
spi_clock(HSPI, 0, 0);
|
||||
} else if (self->baudrate > 40000000L) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError,
|
||||
"impossible baudrate"));
|
||||
} else {
|
||||
uint32_t divider = 40000000L / self->baudrate;
|
||||
uint16_t prediv = MIN(divider, SPI_CLKDIV_PRE + 1);
|
||||
uint16_t cntdiv = (divider / prediv) * 2; // cntdiv has to be even
|
||||
if (cntdiv > SPI_CLKCNT_N + 1 || cntdiv == 0 || prediv == 0) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError,
|
||||
"impossible baudrate"));
|
||||
}
|
||||
self->baudrate = 80000000L / (prediv * cntdiv);
|
||||
spi_init_gpio(HSPI, SPI_CLK_USE_DIV);
|
||||
spi_clock(HSPI, prediv, cntdiv);
|
||||
}
|
||||
// TODO: Make the byte order configurable too (discuss param names)
|
||||
spi_tx_byte_order(HSPI, SPI_BYTE_ORDER_HIGH_TO_LOW);
|
||||
spi_rx_byte_order(HSPI, SPI_BYTE_ORDER_HIGH_TO_LOW);
|
||||
CLEAR_PERI_REG_MASK(SPI_USER(HSPI), SPI_FLASH_MODE | SPI_USR_MISO |
|
||||
SPI_USR_ADDR | SPI_USR_COMMAND | SPI_USR_DUMMY);
|
||||
// Clear Dual or Quad lines transmission mode
|
||||
CLEAR_PERI_REG_MASK(SPI_CTRL(HSPI), SPI_QIO_MODE | SPI_DIO_MODE |
|
||||
SPI_DOUT_MODE | SPI_QOUT_MODE);
|
||||
spi_mode(HSPI, self->phase, self->polarity);
|
||||
}
|
||||
|
||||
mp_obj_t pyb_hspi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||
mp_arg_check_num(n_args, n_kw, 0, 1, true);
|
||||
mp_int_t id = -1;
|
||||
if (n_args > 0) {
|
||||
id = mp_obj_get_int(args[0]);
|
||||
}
|
||||
|
||||
if (id == -1) {
|
||||
// Multiplex to bitbanging SPI
|
||||
if (n_args > 0) {
|
||||
args++;
|
||||
}
|
||||
return pyb_spi_make_new(type, 0, n_kw, args);
|
||||
}
|
||||
|
||||
if (id != 1) {
|
||||
// FlashROM is on SPI0, so far we don't support its usage
|
||||
mp_raise_ValueError("");
|
||||
}
|
||||
|
||||
pyb_hspi_obj_t *self = m_new_obj(pyb_hspi_obj_t);
|
||||
self->base.type = &pyb_hspi_type;
|
||||
// set defaults
|
||||
self->baudrate = 80000000L;
|
||||
self->polarity = 0;
|
||||
self->phase = 0;
|
||||
mp_map_t kw_args;
|
||||
mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
|
||||
pyb_hspi_init_helper(self, n_args, args, &kw_args);
|
||||
return MP_OBJ_FROM_PTR(self);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t pyb_hspi_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
|
||||
pyb_hspi_init_helper(args[0], n_args - 1, args + 1, kw_args);
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(pyb_hspi_init_obj, 1, pyb_hspi_init);
|
||||
|
||||
STATIC const mp_rom_map_elem_t pyb_hspi_locals_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&pyb_hspi_init_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_machine_spi_read_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_machine_spi_readinto_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_machine_spi_write_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_write_readinto), MP_ROM_PTR(&mp_machine_spi_write_readinto_obj) },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(pyb_hspi_locals_dict, pyb_hspi_locals_dict_table);
|
||||
|
||||
STATIC const mp_machine_spi_p_t pyb_hspi_p = {
|
||||
.transfer = hspi_transfer,
|
||||
};
|
||||
|
||||
const mp_obj_type_t pyb_hspi_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_HSPI,
|
||||
.print = pyb_hspi_print,
|
||||
.make_new = pyb_hspi_make_new,
|
||||
.protocol = &pyb_hspi_p,
|
||||
.locals_dict = (mp_obj_dict_t*)&pyb_hspi_locals_dict,
|
||||
};
|
||||
@@ -244,7 +244,11 @@ STATIC mp_obj_t pyb_pin_obj_init_helper(pyb_pin_obj_t *self, mp_uint_t n_args, c
|
||||
|
||||
// configure the GPIO as requested
|
||||
if (self->phys_port == 16) {
|
||||
// TODO: Set pull up/pull down
|
||||
// only pull-down seems to be supported by the hardware, and
|
||||
// we only expose pull-up behaviour in software
|
||||
if (pull != GPIO_PULL_NONE) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Pin(16) doesn't support pull"));
|
||||
}
|
||||
} else {
|
||||
PIN_FUNC_SELECT(self->periph, self->func);
|
||||
#if 0
|
||||
@@ -301,7 +305,7 @@ STATIC mp_obj_t pyb_pin_call(mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw,
|
||||
pyb_pin_obj_t *self = self_in;
|
||||
if (n_args == 0) {
|
||||
// get pin
|
||||
return MP_OBJ_NEW_SMALL_INT(GPIO_INPUT_GET(self->phys_port));
|
||||
return MP_OBJ_NEW_SMALL_INT(pin_get(self->phys_port));
|
||||
} else {
|
||||
// set pin
|
||||
pin_set(self->phys_port, mp_obj_is_true(args[0]));
|
||||
|
||||
@@ -212,13 +212,28 @@ STATIC mp_obj_t pyb_rtc_alarm(mp_obj_t self_in, mp_obj_t alarm_id, mp_obj_t time
|
||||
}
|
||||
|
||||
// set expiry time (in microseconds)
|
||||
pyb_rtc_alarm0_expiry = pyb_rtc_get_us_since_2000() + mp_obj_get_int(time_in) * 1000;
|
||||
pyb_rtc_alarm0_expiry = pyb_rtc_get_us_since_2000() + (uint64_t)mp_obj_get_int(time_in) * 1000;
|
||||
|
||||
return mp_const_none;
|
||||
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_3(pyb_rtc_alarm_obj, pyb_rtc_alarm);
|
||||
|
||||
STATIC mp_obj_t pyb_rtc_alarm_left(size_t n_args, const mp_obj_t *args) {
|
||||
// check we want alarm0
|
||||
if (n_args > 1 && mp_obj_get_int(args[1]) != 0) {
|
||||
mp_raise_ValueError("invalid alarm");
|
||||
}
|
||||
|
||||
uint64_t now = pyb_rtc_get_us_since_2000();
|
||||
if (pyb_rtc_alarm0_expiry <= now) {
|
||||
return MP_OBJ_NEW_SMALL_INT(0);
|
||||
} else {
|
||||
return mp_obj_new_int((pyb_rtc_alarm0_expiry - now) / 1000);
|
||||
}
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_rtc_alarm_left_obj, 1, 2, pyb_rtc_alarm_left);
|
||||
|
||||
STATIC mp_obj_t pyb_rtc_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_trigger, ARG_wake };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
@@ -244,6 +259,7 @@ STATIC const mp_map_elem_t pyb_rtc_locals_dict_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_datetime), (mp_obj_t)&pyb_rtc_datetime_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_memory), (mp_obj_t)&pyb_rtc_memory_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_alarm), (mp_obj_t)&pyb_rtc_alarm_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_alarm_left), (mp_obj_t)&pyb_rtc_alarm_left_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_irq), (mp_obj_t)&pyb_rtc_irq_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ALARM0), MP_OBJ_NEW_SMALL_INT(0) },
|
||||
};
|
||||
|
||||
@@ -28,71 +28,35 @@
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ets_sys.h"
|
||||
#include "etshal.h"
|
||||
#include "ets_alt_task.h"
|
||||
|
||||
#include "py/runtime.h"
|
||||
#include "py/stream.h"
|
||||
#include "py/mphal.h"
|
||||
|
||||
typedef struct _pyb_spi_obj_t {
|
||||
mp_obj_base_t base;
|
||||
uint32_t baudrate;
|
||||
uint8_t polarity;
|
||||
uint8_t phase;
|
||||
mp_hal_pin_obj_t sck;
|
||||
mp_hal_pin_obj_t mosi;
|
||||
mp_hal_pin_obj_t miso;
|
||||
} pyb_spi_obj_t;
|
||||
|
||||
STATIC void mp_hal_spi_transfer(pyb_spi_obj_t *self, size_t src_len, const uint8_t *src_buf, size_t dest_len, uint8_t *dest_buf) {
|
||||
// only MSB transfer is implemented
|
||||
uint32_t delay_half = 500000 / self->baudrate + 1;
|
||||
for (size_t i = 0; i < src_len || i < dest_len; ++i) {
|
||||
uint8_t data_out;
|
||||
if (src_len == 1) {
|
||||
data_out = src_buf[0];
|
||||
} else {
|
||||
data_out = src_buf[i];
|
||||
}
|
||||
uint8_t data_in = 0;
|
||||
for (int j = 0; j < 8; ++j, data_out <<= 1) {
|
||||
mp_hal_pin_write(self->mosi, (data_out >> 7) & 1);
|
||||
if (self->phase == 0) {
|
||||
ets_delay_us(delay_half);
|
||||
mp_hal_pin_write(self->sck, 1 - self->polarity);
|
||||
} else {
|
||||
mp_hal_pin_write(self->sck, 1 - self->polarity);
|
||||
ets_delay_us(delay_half);
|
||||
}
|
||||
data_in = (data_in << 1) | mp_hal_pin_read(self->miso);
|
||||
if (self->phase == 0) {
|
||||
ets_delay_us(delay_half);
|
||||
mp_hal_pin_write(self->sck, self->polarity);
|
||||
} else {
|
||||
mp_hal_pin_write(self->sck, self->polarity);
|
||||
ets_delay_us(delay_half);
|
||||
}
|
||||
}
|
||||
if (dest_len != 0) {
|
||||
dest_buf[i] = data_in;
|
||||
}
|
||||
// make sure pending tasks have a chance to run
|
||||
ets_loop_iter();
|
||||
}
|
||||
}
|
||||
#include "extmod/machine_spi.h"
|
||||
|
||||
/******************************************************************************/
|
||||
// MicroPython bindings for SPI
|
||||
|
||||
STATIC void pyb_spi_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
pyb_spi_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
mp_printf(print, "SPI(baudrate=%u, polarity=%u, phase=%u, sck=%u, mosi=%u, miso=%u)",
|
||||
self->baudrate, self->polarity, self->phase, self->sck, self->mosi, self->miso);
|
||||
STATIC uint32_t baudrate_from_delay_half(uint32_t delay_half) {
|
||||
return 500000 / delay_half;
|
||||
}
|
||||
|
||||
STATIC void pyb_spi_init_helper(pyb_spi_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
STATIC uint32_t baudrate_to_delay_half(uint32_t baudrate) {
|
||||
uint32_t delay_half = 500000 / baudrate;
|
||||
// round delay_half up so that: actual_baudrate <= requested_baudrate
|
||||
if (500000 % baudrate != 0) {
|
||||
delay_half += 1;
|
||||
}
|
||||
return delay_half;
|
||||
}
|
||||
|
||||
STATIC void pyb_spi_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
mp_machine_soft_spi_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
mp_printf(print, "SPI(baudrate=%u, polarity=%u, phase=%u, sck=%u, mosi=%u, miso=%u)",
|
||||
baudrate_from_delay_half(self->delay_half),
|
||||
self->polarity, self->phase, self->sck, self->mosi, self->miso);
|
||||
}
|
||||
|
||||
STATIC void pyb_spi_init_helper(mp_machine_soft_spi_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_baudrate, ARG_polarity, ARG_phase, ARG_sck, ARG_mosi, ARG_miso };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_baudrate, MP_ARG_INT, {.u_int = -1} },
|
||||
@@ -106,7 +70,7 @@ STATIC void pyb_spi_init_helper(pyb_spi_obj_t *self, size_t n_args, const mp_obj
|
||||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
if (args[ARG_baudrate].u_int != -1) {
|
||||
self->baudrate = args[ARG_baudrate].u_int;
|
||||
self->delay_half = baudrate_to_delay_half(args[ARG_baudrate].u_int);
|
||||
}
|
||||
if (args[ARG_polarity].u_int != -1) {
|
||||
self->polarity = args[ARG_polarity].u_int;
|
||||
@@ -131,12 +95,12 @@ STATIC void pyb_spi_init_helper(pyb_spi_obj_t *self, size_t n_args, const mp_obj
|
||||
mp_hal_pin_input(self->miso);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t pyb_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||
mp_obj_t pyb_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||
mp_arg_check_num(n_args, n_kw, 0, MP_OBJ_FUN_ARGS_MAX, true);
|
||||
pyb_spi_obj_t *self = m_new_obj(pyb_spi_obj_t);
|
||||
mp_machine_soft_spi_obj_t *self = m_new_obj(mp_machine_soft_spi_obj_t);
|
||||
self->base.type = &pyb_spi_type;
|
||||
// set defaults
|
||||
self->baudrate = 500000;
|
||||
self->delay_half = baudrate_to_delay_half(500000);
|
||||
self->polarity = 0;
|
||||
self->phase = 0;
|
||||
self->sck = 14;
|
||||
@@ -154,69 +118,25 @@ STATIC mp_obj_t pyb_spi_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_a
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(pyb_spi_init_obj, 1, pyb_spi_init);
|
||||
|
||||
STATIC mp_obj_t pyb_spi_read(size_t n_args, const mp_obj_t *args) {
|
||||
pyb_spi_obj_t *self = MP_OBJ_TO_PTR(args[0]);
|
||||
uint8_t write_byte = 0;
|
||||
if (n_args == 3) {
|
||||
write_byte = mp_obj_get_int(args[2]);
|
||||
}
|
||||
vstr_t vstr;
|
||||
vstr_init_len(&vstr, mp_obj_get_int(args[1]));
|
||||
mp_hal_spi_transfer(self, 1, &write_byte, vstr.len, (uint8_t*)vstr.buf);
|
||||
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_spi_read_obj, 2, 3, pyb_spi_read);
|
||||
|
||||
STATIC mp_obj_t pyb_spi_readinto(size_t n_args, const mp_obj_t *args) {
|
||||
pyb_spi_obj_t *self = MP_OBJ_TO_PTR(args[0]);
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_WRITE);
|
||||
uint8_t write_byte = 0;
|
||||
if (n_args == 3) {
|
||||
write_byte = mp_obj_get_int(args[2]);
|
||||
}
|
||||
mp_hal_spi_transfer(self, 1, &write_byte, bufinfo.len, (uint8_t*)bufinfo.buf);
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_spi_readinto_obj, 2, 3, pyb_spi_readinto);
|
||||
|
||||
STATIC mp_obj_t pyb_spi_write(mp_obj_t self_in, mp_obj_t wr_buf_in) {
|
||||
pyb_spi_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
mp_buffer_info_t src_buf;
|
||||
mp_get_buffer_raise(wr_buf_in, &src_buf, MP_BUFFER_READ);
|
||||
mp_hal_spi_transfer(self, src_buf.len, (const uint8_t*)src_buf.buf, 0, NULL);
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_2(pyb_spi_write_obj, pyb_spi_write);
|
||||
|
||||
STATIC mp_obj_t pyb_spi_write_readinto(mp_obj_t self_in, mp_obj_t wr_buf_in, mp_obj_t rd_buf_in) {
|
||||
pyb_spi_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
mp_buffer_info_t src_buf;
|
||||
mp_get_buffer_raise(wr_buf_in, &src_buf, MP_BUFFER_READ);
|
||||
mp_buffer_info_t dest_buf;
|
||||
mp_get_buffer_raise(rd_buf_in, &dest_buf, MP_BUFFER_WRITE);
|
||||
if (src_buf.len != dest_buf.len) {
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "buffers must be the same length"));
|
||||
}
|
||||
mp_hal_spi_transfer(self, src_buf.len, (const uint8_t*)src_buf.buf, dest_buf.len, (uint8_t*)dest_buf.buf);
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_3(pyb_spi_write_readinto_obj, pyb_spi_write_readinto);
|
||||
|
||||
STATIC const mp_rom_map_elem_t pyb_spi_locals_dict_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&pyb_spi_init_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&pyb_spi_read_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&pyb_spi_readinto_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&pyb_spi_write_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_write_readinto), MP_ROM_PTR(&pyb_spi_write_readinto_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_machine_spi_read_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_machine_spi_readinto_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_machine_spi_write_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_write_readinto), MP_ROM_PTR(&mp_machine_spi_write_readinto_obj) },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(pyb_spi_locals_dict, pyb_spi_locals_dict_table);
|
||||
|
||||
STATIC const mp_machine_spi_p_t pyb_spi_p = {
|
||||
.transfer = mp_machine_soft_spi_transfer,
|
||||
};
|
||||
|
||||
const mp_obj_type_t pyb_spi_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_SPI,
|
||||
.name = MP_QSTR_SoftSPI,
|
||||
.print = pyb_spi_print,
|
||||
.make_new = pyb_spi_make_new,
|
||||
.protocol = &pyb_spi_p,
|
||||
.locals_dict = (mp_obj_dict_t*)&pyb_spi_locals_dict,
|
||||
};
|
||||
|
||||
@@ -112,9 +112,11 @@ STATIC void pyb_uart_init_helper(pyb_uart_obj_t *self, size_t n_args, const mp_o
|
||||
if (args[ARG_parity].u_obj != MP_OBJ_NULL) {
|
||||
if (args[ARG_parity].u_obj == mp_const_none) {
|
||||
UartDev.parity = UART_NONE_BITS;
|
||||
UartDev.exist_parity = UART_STICK_PARITY_DIS;
|
||||
self->parity = 0;
|
||||
} else {
|
||||
mp_int_t parity = mp_obj_get_int(args[ARG_parity].u_obj);
|
||||
UartDev.exist_parity = UART_STICK_PARITY_EN;
|
||||
if (parity & 1) {
|
||||
UartDev.parity = UART_ODD_BITS;
|
||||
self->parity = 1;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import gc
|
||||
gc.threshold((gc.mem_free() + gc.mem_alloc()) // 4)
|
||||
import uos
|
||||
from flashbdev import bdev
|
||||
|
||||
|
||||
46
esp8266/modules/ds18x20.py
Normal file
46
esp8266/modules/ds18x20.py
Normal file
@@ -0,0 +1,46 @@
|
||||
# DS18x20 temperature sensor driver for MicroPython.
|
||||
# MIT license; Copyright (c) 2016 Damien P. George
|
||||
|
||||
_CONVERT = const(0x44)
|
||||
_RD_SCRATCH = const(0xbe)
|
||||
_WR_SCRATCH = const(0x4e)
|
||||
|
||||
class DS18X20:
|
||||
def __init__(self, onewire):
|
||||
self.ow = onewire
|
||||
self.buf = bytearray(9)
|
||||
|
||||
def scan(self):
|
||||
return [rom for rom in self.ow.scan() if rom[0] == 0x10 or rom[0] == 0x28]
|
||||
|
||||
def convert_temp(self):
|
||||
self.ow.reset(True)
|
||||
self.ow.writebyte(self.ow.SKIP_ROM)
|
||||
self.ow.writebyte(_CONVERT)
|
||||
|
||||
def read_scratch(self, rom):
|
||||
self.ow.reset(True)
|
||||
self.ow.select_rom(rom)
|
||||
self.ow.writebyte(_RD_SCRATCH)
|
||||
self.ow.readinto(self.buf)
|
||||
if self.ow.crc8(self.buf):
|
||||
raise Exception('CRC error')
|
||||
return self.buf
|
||||
|
||||
def write_scratch(self, rom, buf):
|
||||
self.ow.reset(True)
|
||||
self.ow.select_rom(rom)
|
||||
self.ow.writebyte(_WR_SCRATCH)
|
||||
self.ow.write(buf)
|
||||
|
||||
def read_temp(self, rom):
|
||||
buf = self.read_scratch(rom)
|
||||
if rom[0] == 0x10:
|
||||
if buf[1]:
|
||||
t = buf[0] >> 1 | 0x80
|
||||
t = -((~t + 1) & 0xff)
|
||||
else:
|
||||
t = buf[0] >> 1
|
||||
return t - 0.25 + (buf[7] - buf[6]) / buf[7]
|
||||
else:
|
||||
return (buf[1] << 8 | buf[0]) / 16
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user