Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
0f1973fb68
1
.gitattributes
vendored
1
.gitattributes
vendored
@ -7,6 +7,7 @@
|
||||
*.bat text eol=crlf
|
||||
|
||||
# These are binary so should never be modified by git.
|
||||
*.a binary
|
||||
*.png binary
|
||||
*.jpg binary
|
||||
*.dxf binary
|
||||
|
||||
1
.github/FUNDING.yml
vendored
Normal file
1
.github/FUNDING.yml
vendored
Normal file
@ -0,0 +1 @@
|
||||
github: micropython
|
||||
16
.github/workflows/code_formatting.yml
vendored
Normal file
16
.github/workflows/code_formatting.yml
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
name: Check code formatting
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-python@v1
|
||||
- name: Install packages
|
||||
run: source tools/ci.sh && ci_code_formatting_setup
|
||||
- name: Run code formatting
|
||||
run: source tools/ci.sh && ci_code_formatting_run
|
||||
- name: Check code formatting
|
||||
run: git diff --exit-code
|
||||
27
.github/workflows/code_size.yml
vendored
Normal file
27
.github/workflows/code_size.yml
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
name: Check code size
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
paths:
|
||||
- '.github/workflows/*.yml'
|
||||
- 'tools/**'
|
||||
- 'py/**'
|
||||
- 'extmod/**'
|
||||
- 'lib/**'
|
||||
- 'ports/bare-arm/**'
|
||||
- 'ports/minimal/**'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 100
|
||||
- name: Install packages
|
||||
run: source tools/ci.sh && ci_code_size_setup
|
||||
- name: Build
|
||||
run: source tools/ci.sh && ci_code_size_build
|
||||
- name: Compute code size difference
|
||||
run: tools/metrics.py diff --error-threshold 0 ~/size0 ~/size1
|
||||
14
.github/workflows/commit_formatting.yml
vendored
Normal file
14
.github/workflows/commit_formatting.yml
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
name: Check commit message formatting
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: '100'
|
||||
- uses: actions/setup-python@v1
|
||||
- name: Check commit message formatting
|
||||
run: source tools/ci.sh && ci_commit_formatting_run
|
||||
18
.github/workflows/docs.yml
vendored
Normal file
18
.github/workflows/docs.yml
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
name: Build docs
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- docs/**
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-python@v1
|
||||
- name: Install Python packages
|
||||
run: pip install Sphinx
|
||||
- name: Build docs
|
||||
run: make -C docs/ html
|
||||
23
.github/workflows/ports_cc3200.yml
vendored
Normal file
23
.github/workflows/ports_cc3200.yml
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
name: cc3200 port
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
paths:
|
||||
- '.github/workflows/*.yml'
|
||||
- 'tools/**'
|
||||
- 'py/**'
|
||||
- 'extmod/**'
|
||||
- 'lib/**'
|
||||
- 'drivers/**'
|
||||
- 'ports/cc3200/**'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install packages
|
||||
run: source tools/ci.sh && ci_cc3200_setup
|
||||
- name: Build
|
||||
run: source tools/ci.sh && ci_cc3200_build
|
||||
36
.github/workflows/ports_esp32.yml
vendored
Normal file
36
.github/workflows/ports_esp32.yml
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
name: esp32 port
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
paths:
|
||||
- '.github/workflows/*.yml'
|
||||
- 'tools/**'
|
||||
- 'py/**'
|
||||
- 'extmod/**'
|
||||
- 'lib/**'
|
||||
- 'drivers/**'
|
||||
- 'ports/esp32/**'
|
||||
|
||||
jobs:
|
||||
idf3_build:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install packages
|
||||
run: source tools/ci.sh && ci_esp32_idf3_setup && ci_esp32_idf3_path >> $GITHUB_PATH
|
||||
- name: Build
|
||||
env:
|
||||
IDF_PATH: ${{ github.workspace }}/esp-idf
|
||||
run: source tools/ci.sh && ci_esp32_idf3_build
|
||||
|
||||
idf4_build:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install packages
|
||||
run: source tools/ci.sh && ci_esp32_idf4_setup && ci_esp32_idf4_path >> $GITHUB_PATH
|
||||
- name: Build
|
||||
env:
|
||||
IDF_PATH: ${{ github.workspace }}/esp-idf
|
||||
run: source tools/ci.sh && ci_esp32_idf4_build
|
||||
23
.github/workflows/ports_esp8266.yml
vendored
Normal file
23
.github/workflows/ports_esp8266.yml
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
name: esp8266 port
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
paths:
|
||||
- '.github/workflows/*.yml'
|
||||
- 'tools/**'
|
||||
- 'py/**'
|
||||
- 'extmod/**'
|
||||
- 'lib/**'
|
||||
- 'drivers/**'
|
||||
- 'ports/esp8266/**'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install packages
|
||||
run: source tools/ci.sh && ci_esp8266_setup && ci_esp8266_path >> $GITHUB_PATH
|
||||
- name: Build
|
||||
run: source tools/ci.sh && ci_esp8266_build
|
||||
23
.github/workflows/ports_nrf.yml
vendored
Normal file
23
.github/workflows/ports_nrf.yml
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
name: nrf port
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
paths:
|
||||
- '.github/workflows/*.yml'
|
||||
- 'tools/**'
|
||||
- 'py/**'
|
||||
- 'extmod/**'
|
||||
- 'lib/**'
|
||||
- 'drivers/**'
|
||||
- 'ports/nrf/**'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install packages
|
||||
run: source tools/ci.sh && ci_nrf_setup
|
||||
- name: Build
|
||||
run: source tools/ci.sh && ci_nrf_build
|
||||
23
.github/workflows/ports_powerpc.yml
vendored
Normal file
23
.github/workflows/ports_powerpc.yml
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
name: powerpc port
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
paths:
|
||||
- '.github/workflows/*.yml'
|
||||
- 'tools/**'
|
||||
- 'py/**'
|
||||
- 'extmod/**'
|
||||
- 'lib/**'
|
||||
- 'drivers/**'
|
||||
- 'ports/powerpc/**'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install packages
|
||||
run: source tools/ci.sh && ci_powerpc_setup
|
||||
- name: Build
|
||||
run: source tools/ci.sh && ci_powerpc_build
|
||||
27
.github/workflows/ports_qemu-arm.yml
vendored
Normal file
27
.github/workflows/ports_qemu-arm.yml
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
name: qemu-arm port
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
paths:
|
||||
- '.github/workflows/*.yml'
|
||||
- 'tools/**'
|
||||
- 'py/**'
|
||||
- 'extmod/**'
|
||||
- 'lib/**'
|
||||
- 'drivers/**'
|
||||
- 'ports/qemu-arm/**'
|
||||
- 'tests/**'
|
||||
|
||||
jobs:
|
||||
build_and_test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install packages
|
||||
run: source tools/ci.sh && ci_qemu_arm_setup
|
||||
- name: Build and run test suite
|
||||
run: source tools/ci.sh && ci_qemu_arm_build
|
||||
- name: Print failures
|
||||
if: failure()
|
||||
run: grep --text "FAIL" ports/qemu-arm/build/console.out
|
||||
23
.github/workflows/ports_rp2.yml
vendored
Normal file
23
.github/workflows/ports_rp2.yml
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
name: rp2 port
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
paths:
|
||||
- '.github/workflows/*.yml'
|
||||
- 'tools/**'
|
||||
- 'py/**'
|
||||
- 'extmod/**'
|
||||
- 'lib/**'
|
||||
- 'drivers/**'
|
||||
- 'ports/rp2/**'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install packages
|
||||
run: source tools/ci.sh && ci_rp2_setup
|
||||
- name: Build
|
||||
run: source tools/ci.sh && ci_rp2_build
|
||||
23
.github/workflows/ports_samd.yml
vendored
Normal file
23
.github/workflows/ports_samd.yml
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
name: samd port
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
paths:
|
||||
- '.github/workflows/*.yml'
|
||||
- 'tools/**'
|
||||
- 'py/**'
|
||||
- 'extmod/**'
|
||||
- 'lib/**'
|
||||
- 'drivers/**'
|
||||
- 'ports/samd/**'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install packages
|
||||
run: source tools/ci.sh && ci_samd_setup
|
||||
- name: Build
|
||||
run: source tools/ci.sh && ci_samd_build
|
||||
32
.github/workflows/ports_stm32.yml
vendored
Normal file
32
.github/workflows/ports_stm32.yml
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
name: stm32 port
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
paths:
|
||||
- '.github/workflows/*.yml'
|
||||
- 'tools/**'
|
||||
- 'py/**'
|
||||
- 'extmod/**'
|
||||
- 'lib/**'
|
||||
- 'drivers/**'
|
||||
- 'ports/stm32/**'
|
||||
|
||||
jobs:
|
||||
build_pyb:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install packages
|
||||
run: source tools/ci.sh && ci_stm32_setup
|
||||
- name: Build
|
||||
run: source tools/ci.sh && ci_stm32_pyb_build
|
||||
|
||||
build_nucleo:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install packages
|
||||
run: source tools/ci.sh && ci_stm32_setup
|
||||
- name: Build
|
||||
run: source tools/ci.sh && ci_stm32_nucleo_build
|
||||
23
.github/workflows/ports_teensy.yml
vendored
Normal file
23
.github/workflows/ports_teensy.yml
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
name: teensy port
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
paths:
|
||||
- '.github/workflows/*.yml'
|
||||
- 'tools/**'
|
||||
- 'py/**'
|
||||
- 'extmod/**'
|
||||
- 'lib/**'
|
||||
- 'drivers/**'
|
||||
- 'ports/teensy/**'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install packages
|
||||
run: source tools/ci.sh && ci_teensy_setup
|
||||
- name: Build
|
||||
run: source tools/ci.sh && ci_teensy_build
|
||||
188
.github/workflows/ports_unix.yml
vendored
Normal file
188
.github/workflows/ports_unix.yml
vendored
Normal file
@ -0,0 +1,188 @@
|
||||
name: unix port
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
paths:
|
||||
- '.github/workflows/*.yml'
|
||||
- 'tools/**'
|
||||
- 'py/**'
|
||||
- 'extmod/**'
|
||||
- 'lib/**'
|
||||
- 'examples/**'
|
||||
- 'ports/unix/**'
|
||||
- 'tests/**'
|
||||
|
||||
jobs:
|
||||
minimal:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Build
|
||||
run: source tools/ci.sh && ci_unix_minimal_build
|
||||
- name: Run main test suite
|
||||
run: source tools/ci.sh && ci_unix_minimal_run_tests
|
||||
- name: Print failures
|
||||
if: failure()
|
||||
run: tests/run-tests --print-failures
|
||||
|
||||
reproducible:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Build with reproducible date
|
||||
run: source tools/ci.sh && ci_unix_minimal_build
|
||||
env:
|
||||
SOURCE_DATE_EPOCH: 1234567890
|
||||
- name: Check reproducible build date
|
||||
run: echo | ports/unix/micropython-minimal -i | grep 'on 2009-02-13;'
|
||||
|
||||
standard:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Build
|
||||
run: source tools/ci.sh && ci_unix_standard_build
|
||||
- name: Run main test suite
|
||||
run: source tools/ci.sh && ci_unix_standard_run_tests
|
||||
- name: Run performance benchmarks
|
||||
run: source tools/ci.sh && ci_unix_standard_run_perfbench
|
||||
- name: Print failures
|
||||
if: failure()
|
||||
run: tests/run-tests --print-failures
|
||||
|
||||
coverage:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install packages
|
||||
run: source tools/ci.sh && ci_unix_coverage_setup
|
||||
- name: Build
|
||||
run: source tools/ci.sh && ci_unix_coverage_build
|
||||
- name: Run main test suite
|
||||
run: source tools/ci.sh && ci_unix_coverage_run_tests
|
||||
- name: Build native mpy modules
|
||||
run: source tools/ci.sh && ci_native_mpy_modules_build
|
||||
- name: Test importing .mpy generated by mpy_ld.py
|
||||
run: source tools/ci.sh && ci_unix_coverage_run_native_mpy_tests
|
||||
- name: Run lcov coverage analysis
|
||||
run: |
|
||||
mkdir -p coverage
|
||||
lcov --rc lcov_branch_coverage=1 --directory ports/unix/build-coverage --capture --output-file coverage/lcov.info.all
|
||||
lcov --remove coverage/lcov.info.all '*/lib/*' '*/ports/unix/*' '*/utils/*' --output-file coverage/lcov.info
|
||||
- name: Send to coveralls
|
||||
uses: coverallsapp/github-action@master
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Print failures
|
||||
if: failure()
|
||||
run: tests/run-tests --print-failures
|
||||
|
||||
coverage_32bit:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install packages
|
||||
run: source tools/ci.sh && ci_unix_32bit_setup
|
||||
- name: Build
|
||||
run: source tools/ci.sh && ci_unix_coverage_32bit_build
|
||||
- name: Run main test suite
|
||||
run: source tools/ci.sh && ci_unix_coverage_32bit_run_tests
|
||||
- name: Build native mpy modules
|
||||
run: source tools/ci.sh && ci_native_mpy_modules_32bit_build
|
||||
- name: Test importing .mpy generated by mpy_ld.py
|
||||
run: source tools/ci.sh && ci_unix_coverage_32bit_run_native_mpy_tests
|
||||
- name: Print failures
|
||||
if: failure()
|
||||
run: tests/run-tests --print-failures
|
||||
|
||||
nanbox:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install packages
|
||||
run: source tools/ci.sh && ci_unix_32bit_setup
|
||||
- name: Build
|
||||
run: source tools/ci.sh && ci_unix_nanbox_build
|
||||
- name: Run main test suite
|
||||
run: source tools/ci.sh && ci_unix_nanbox_run_tests
|
||||
- name: Print failures
|
||||
if: failure()
|
||||
run: tests/run-tests --print-failures
|
||||
|
||||
float:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Build
|
||||
run: source tools/ci.sh && ci_unix_float_build
|
||||
- name: Run main test suite
|
||||
run: source tools/ci.sh && ci_unix_float_run_tests
|
||||
- name: Print failures
|
||||
if: failure()
|
||||
run: tests/run-tests --print-failures
|
||||
|
||||
stackless_clang:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install packages
|
||||
run: source tools/ci.sh && ci_unix_clang_setup
|
||||
- name: Build
|
||||
run: source tools/ci.sh && ci_unix_stackless_clang_build
|
||||
- name: Run main test suite
|
||||
run: source tools/ci.sh && ci_unix_stackless_clang_run_tests
|
||||
- name: Print failures
|
||||
if: failure()
|
||||
run: tests/run-tests --print-failures
|
||||
|
||||
float_clang:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install packages
|
||||
run: source tools/ci.sh && ci_unix_clang_setup
|
||||
- name: Build
|
||||
run: source tools/ci.sh && ci_unix_float_clang_build
|
||||
- name: Run main test suite
|
||||
run: source tools/ci.sh && ci_unix_float_clang_run_tests
|
||||
- name: Print failures
|
||||
if: failure()
|
||||
run: tests/run-tests --print-failures
|
||||
|
||||
settrace:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Build
|
||||
run: source tools/ci.sh && ci_unix_settrace_build
|
||||
- name: Run main test suite
|
||||
run: source tools/ci.sh && ci_unix_settrace_run_tests
|
||||
- name: Print failures
|
||||
if: failure()
|
||||
run: tests/run-tests --print-failures
|
||||
|
||||
settrace_stackless:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Build
|
||||
run: source tools/ci.sh && ci_unix_settrace_stackless_build
|
||||
- name: Run main test suite
|
||||
run: source tools/ci.sh && ci_unix_settrace_stackless_run_tests
|
||||
- name: Print failures
|
||||
if: failure()
|
||||
run: tests/run-tests --print-failures
|
||||
|
||||
macos:
|
||||
runs-on: macos-11.0
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-python@v1
|
||||
- name: Build
|
||||
run: source tools/ci.sh && ci_unix_macos_build
|
||||
- name: Run tests
|
||||
run: source tools/ci.sh && ci_unix_macos_run_tests
|
||||
- name: Print failures
|
||||
if: failure()
|
||||
run: tests/run-tests --print-failures
|
||||
23
.github/workflows/ports_windows.yml
vendored
Normal file
23
.github/workflows/ports_windows.yml
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
name: windows port
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
paths:
|
||||
- '.github/workflows/*.yml'
|
||||
- 'tools/**'
|
||||
- 'py/**'
|
||||
- 'extmod/**'
|
||||
- 'lib/**'
|
||||
- 'ports/unix/**'
|
||||
- 'ports/windows/**'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install packages
|
||||
run: source tools/ci.sh && ci_windows_setup
|
||||
- name: Build
|
||||
run: source tools/ci.sh && ci_windows_build
|
||||
24
.github/workflows/ports_zephyr.yml
vendored
Normal file
24
.github/workflows/ports_zephyr.yml
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
name: zephyr port
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
paths:
|
||||
- '.github/workflows/ports_zephyr.yml'
|
||||
- 'tools/**'
|
||||
- 'py/**'
|
||||
- 'extmod/**'
|
||||
- 'lib/**'
|
||||
- 'ports/zephyr/**'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install packages
|
||||
run: source tools/ci.sh && ci_zephyr_setup
|
||||
- name: Install Zephyr
|
||||
run: source tools/ci.sh && ci_zephyr_install
|
||||
- name: Build
|
||||
run: source tools/ci.sh && ci_zephyr_build
|
||||
6
.gitignore
vendored
6
.gitignore
vendored
@ -20,14 +20,14 @@
|
||||
######################
|
||||
*.swp
|
||||
|
||||
# Build directory
|
||||
# Build directories
|
||||
######################
|
||||
build/
|
||||
build-*/
|
||||
|
||||
# Test failure outputs
|
||||
######################
|
||||
tests/*.exp
|
||||
tests/*.out
|
||||
tests/results/*
|
||||
|
||||
# Python cache files
|
||||
######################
|
||||
|
||||
27
.gitmodules
vendored
27
.gitmodules
vendored
@ -15,3 +15,30 @@
|
||||
path = lib/stm32lib
|
||||
url = https://github.com/micropython/stm32lib
|
||||
branch = work-F4-1.13.1+F7-1.5.0+L4-1.3.0
|
||||
[submodule "lib/nrfx"]
|
||||
path = lib/nrfx
|
||||
url = https://github.com/NordicSemiconductor/nrfx.git
|
||||
[submodule "lib/mbedtls"]
|
||||
path = lib/mbedtls
|
||||
url = https://github.com/ARMmbed/mbedtls.git
|
||||
[submodule "lib/asf4"]
|
||||
path = lib/asf4
|
||||
url = https://github.com/adafruit/asf4
|
||||
[submodule "lib/tinyusb"]
|
||||
path = lib/tinyusb
|
||||
url = https://github.com/hathach/tinyusb
|
||||
[submodule "lib/mynewt-nimble"]
|
||||
path = lib/mynewt-nimble
|
||||
url = https://github.com/apache/mynewt-nimble.git
|
||||
[submodule "lib/btstack"]
|
||||
path = lib/btstack
|
||||
url = https://github.com/bluekitchen/btstack.git
|
||||
[submodule "lib/nxp_driver"]
|
||||
path = lib/nxp_driver
|
||||
url = https://github.com/hathach/nxp_driver.git
|
||||
[submodule "lib/libhydrogen"]
|
||||
path = lib/libhydrogen
|
||||
url = https://github.com/jedisct1/libhydrogen.git
|
||||
[submodule "lib/pico-sdk"]
|
||||
path = lib/pico-sdk
|
||||
url = https://github.com/raspberrypi/pico-sdk.git
|
||||
|
||||
77
.travis.yml
77
.travis.yml
@ -1,77 +0,0 @@
|
||||
sudo: required
|
||||
dist: trusty
|
||||
language: c
|
||||
compiler:
|
||||
- gcc
|
||||
cache:
|
||||
directories:
|
||||
- "${HOME}/persist"
|
||||
env:
|
||||
- MAKEOPTS="-j4"
|
||||
|
||||
before_script:
|
||||
# Extra CPython versions
|
||||
# - sudo add-apt-repository -y ppa:fkrull/deadsnakes
|
||||
# Extra gcc versions
|
||||
# - sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
|
||||
- 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 gcc-mingw-w64
|
||||
- sudo apt-get install -y --force-yes gcc-arm-none-eabi
|
||||
# For teensy build
|
||||
- sudo apt-get install realpath
|
||||
# For coverage testing (a specific urllib3 version is needed for requests and cpp-coveralls to work together)
|
||||
- sudo pip install -Iv urllib3==1.22
|
||||
- sudo pip install cpp-coveralls
|
||||
- gcc --version
|
||||
- arm-none-eabi-gcc --version
|
||||
- python3 --version
|
||||
|
||||
script:
|
||||
- make ${MAKEOPTS} -C mpy-cross
|
||||
- make ${MAKEOPTS} -C ports/minimal CROSS=1 build/firmware.bin
|
||||
- ls -l ports/minimal/build/firmware.bin
|
||||
- tools/check_code_size.sh
|
||||
- mkdir -p ${HOME}/persist
|
||||
# Save new firmware for reference, but only if building a main branch, not a pull request
|
||||
- 'if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then cp ports/minimal/build/firmware.bin ${HOME}/persist/; fi'
|
||||
- make ${MAKEOPTS} -C ports/unix deplibs
|
||||
- make ${MAKEOPTS} -C ports/unix
|
||||
- make ${MAKEOPTS} -C ports/unix nanbox
|
||||
- make ${MAKEOPTS} -C ports/bare-arm
|
||||
- make ${MAKEOPTS} -C ports/qemu-arm -f Makefile.test test
|
||||
- make ${MAKEOPTS} -C ports/stm32
|
||||
- make ${MAKEOPTS} -C ports/stm32 BOARD=PYBV11 MICROPY_PY_WIZNET5K=5200 MICROPY_PY_CC3K=1
|
||||
- make ${MAKEOPTS} -C ports/stm32 BOARD=STM32F769DISC
|
||||
- make ${MAKEOPTS} -C ports/stm32 BOARD=STM32L476DISC
|
||||
- make ${MAKEOPTS} -C ports/teensy
|
||||
- make ${MAKEOPTS} -C ports/cc3200 BTARGET=application BTYPE=release
|
||||
- make ${MAKEOPTS} -C ports/cc3200 BTARGET=bootloader BTYPE=release
|
||||
- make ${MAKEOPTS} -C ports/windows CROSS_COMPILE=i686-w64-mingw32-
|
||||
|
||||
# run tests without coverage info
|
||||
#- (cd tests && MICROPY_CPYTHON3=python3.4 ./run-tests)
|
||||
#- (cd tests && MICROPY_CPYTHON3=python3.4 ./run-tests --emit native)
|
||||
|
||||
# run tests with coverage info
|
||||
- make ${MAKEOPTS} -C ports/unix coverage
|
||||
- (cd tests && MICROPY_CPYTHON3=python3.4 MICROPY_MICROPYTHON=../ports/unix/micropython_coverage ./run-tests)
|
||||
- (cd tests && MICROPY_CPYTHON3=python3.4 MICROPY_MICROPYTHON=../ports/unix/micropython_coverage ./run-tests -d thread)
|
||||
- (cd tests && MICROPY_CPYTHON3=python3.4 MICROPY_MICROPYTHON=../ports/unix/micropython_coverage ./run-tests --emit native)
|
||||
- (cd tests && MICROPY_CPYTHON3=python3.4 MICROPY_MICROPYTHON=../ports/unix/micropython_coverage ./run-tests --via-mpy -d basics float)
|
||||
|
||||
# test when input script comes from stdin
|
||||
- cat tests/basics/0prelim.py | ports/unix/micropython_coverage | grep -q 'abc'
|
||||
|
||||
# run coveralls coverage analysis (try to, even if some builds/tests failed)
|
||||
- (cd ports/unix && coveralls --root ../.. --build-root . --gcov $(which gcov) --gcov-options '\-o build-coverage/' --include py --include extmod)
|
||||
|
||||
# run tests on stackless build
|
||||
- rm -rf ports/unix/build-coverage
|
||||
- make ${MAKEOPTS} -C ports/unix coverage CFLAGS_EXTRA="-DMICROPY_STACKLESS=1 -DMICROPY_STACKLESS_STRICT=1"
|
||||
- (cd tests && MICROPY_CPYTHON3=python3.4 MICROPY_MICROPYTHON=../ports/unix/micropython_coverage ./run-tests)
|
||||
|
||||
after_failure:
|
||||
- (cd tests && for exp in *.exp; do testbase=$(basename $exp .exp); echo -e "\nFAILURE $testbase"; diff -u $testbase.exp $testbase.out; done)
|
||||
- (grep "FAIL" ports/qemu-arm/build/console.out)
|
||||
@ -762,7 +762,6 @@ today. The names appear in order of pledging.
|
||||
1642 Udine
|
||||
1643 Simon Critchley
|
||||
1644 Sven Haiges, Germany
|
||||
1645 Yi Qing Sim
|
||||
1646 "silicium" ("silicium_one", if "silicium" is busy)
|
||||
1648 Andy O'Malia, @andyomalia
|
||||
1650 RedCamelApps.com
|
||||
|
||||
@ -11,7 +11,7 @@ It's also ok to drop file extensions.
|
||||
|
||||
Besides prefix, first line of a commit message should describe a
|
||||
change clearly and to the point, and be a grammatical sentence with
|
||||
final full stop. First line should fit within 78 characters. Examples
|
||||
final full stop. First line should fit within 72 characters. Examples
|
||||
of good first line of commit messages:
|
||||
|
||||
py/objstr: Add splitlines() method.
|
||||
@ -19,16 +19,20 @@ of good first line of commit messages:
|
||||
docs/machine: Fix typo in reset() description.
|
||||
ports: Switch to use lib/foo instead of duplicated code.
|
||||
|
||||
After the first line, add an empty line and in following lines describe
|
||||
a change in a detail, if needed. Any change beyond 5 lines would likely
|
||||
require such detailed description.
|
||||
After the first line add an empty line and in the following lines describe
|
||||
the change in a detail, if needed, with lines fitting within 75 characters
|
||||
(with an exception for long items like URLs which cannot be broken). Any
|
||||
change beyond 5 lines would likely require such detailed description.
|
||||
|
||||
To get good practical examples of good commits and their messages, browse
|
||||
the `git log` of the project.
|
||||
|
||||
MicroPython doesn't require explicit sign-off for patches ("Signed-off-by"
|
||||
lines and similar). Instead, the commit message, and your name and email
|
||||
address on it construes your sign-off of the following:
|
||||
When committing you are encouraged to sign-off your commit by adding
|
||||
"Signed-off-by" lines and similar, eg using "git commit -s". If you don't
|
||||
explicitly sign-off in this way then the commit message, which includes your
|
||||
name and email address in the "Author" line, implies your sign-off. In either
|
||||
case, of explicit or implicit sign-off, you are certifying and signing off
|
||||
against the following:
|
||||
|
||||
* That you wrote the change yourself, or took it from a project with
|
||||
a compatible license (in the latter case the commit message, and possibly
|
||||
@ -42,19 +46,35 @@ address on it construes your sign-off of the following:
|
||||
copyright for your changes (for smaller changes, the commit message
|
||||
conveys your copyright; if you make significant changes to a particular
|
||||
source module, you're welcome to add your name to the file header).
|
||||
* Your signature for all of the above, which is the 'Author' line in
|
||||
the commit message, and which should include your full real name and
|
||||
* Your contribution including commit message will be publicly and
|
||||
indefinitely available for anyone to access, including redistribution
|
||||
under the terms of the project's license.
|
||||
* Your signature for all of the above, which is the "Signed-off-by" line
|
||||
or the "Author" line in the commit message, includes your full real name and
|
||||
a valid and active email address by which you can be contacted in the
|
||||
foreseeable future.
|
||||
|
||||
Code auto-formatting
|
||||
====================
|
||||
|
||||
Both C and Python code are auto-formatted using the `tools/codeformat.py`
|
||||
script. This uses [uncrustify](https://github.com/uncrustify/uncrustify) to
|
||||
format C code and [black](https://github.com/psf/black) to format Python code.
|
||||
After making changes, and before committing, run this tool to reformat your
|
||||
changes to the correct style. Without arguments this tool will reformat all
|
||||
source code (and may take some time to run). Otherwise pass as arguments to
|
||||
the tool the files that changed and it will only reformat those.
|
||||
|
||||
Python code conventions
|
||||
=======================
|
||||
|
||||
Python code follows [PEP 8](http://legacy.python.org/dev/peps/pep-0008/).
|
||||
Python code follows [PEP 8](https://legacy.python.org/dev/peps/pep-0008/) and
|
||||
is auto-formatted using [black](https://github.com/psf/black) with a line-length
|
||||
of 99 characters.
|
||||
|
||||
Naming conventions:
|
||||
- Module names are short and all lowercase; eg pyb, stm.
|
||||
- Class names are CamelCase, with abreviations all uppercase; eg I2C, not
|
||||
- Class names are CamelCase, with abbreviations all uppercase; eg I2C, not
|
||||
I2c.
|
||||
- Function and method names are all lowercase with words separated by
|
||||
a single underscore as necessary to improve readability; eg mem_read.
|
||||
@ -64,7 +84,12 @@ Naming conventions:
|
||||
C code conventions
|
||||
==================
|
||||
|
||||
When writing new C code, please adhere to the following conventions.
|
||||
C code is auto-formatted using [uncrustify](https://github.com/uncrustify/uncrustify)
|
||||
and the corresponding configuration file `tools/uncrustify.cfg`, with a few
|
||||
minor fix-ups applied by `tools/codeformat.py`. When writing new C code please
|
||||
adhere to the existing style and use `tools/codeformat.py` to check any changes.
|
||||
The main conventions, and things not enforceable via the auto-formatter, are
|
||||
described below.
|
||||
|
||||
White space:
|
||||
- Expand tabs to 4 spaces.
|
||||
@ -125,7 +150,7 @@ Braces, spaces, names and comments:
|
||||
foo(x + TO_ADD, some_value - 1);
|
||||
}
|
||||
|
||||
for (int my_counter = 0; my_counter < x; my_counter++) {
|
||||
for (int my_counter = 0; my_counter < x; ++my_counter) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
53
CODEOFCONDUCT.md
Normal file
53
CODEOFCONDUCT.md
Normal file
@ -0,0 +1,53 @@
|
||||
MicroPython Code of Conduct
|
||||
===========================
|
||||
|
||||
The MicroPython community is made up of members from around the globe with a
|
||||
diverse set of skills, personalities, and experiences. It is through these
|
||||
differences that our community experiences great successes and continued growth.
|
||||
When you're working with members of the community, this Code of Conduct will
|
||||
help steer your interactions and keep MicroPython a positive, successful, and
|
||||
growing community.
|
||||
|
||||
Members of the MicroPython community are open, considerate, and respectful.
|
||||
Behaviours that reinforce these values contribute to a positive environment, and
|
||||
include: acknowledging time and effort, being respectful of differing viewpoints
|
||||
and experiences, gracefully accepting constructive criticism, and using
|
||||
welcoming and inclusive language.
|
||||
|
||||
Every member of our community has the right to have their identity respected.
|
||||
The MicroPython community is dedicated to providing a positive experience for
|
||||
everyone, regardless of age, gender identity and expression, sexual orientation,
|
||||
disability, physical appearance, body size, ethnicity, nationality, race, or
|
||||
religion (or lack thereof), education, or socio-economic status.
|
||||
|
||||
Unacceptable behaviour includes: harassment, trolling, deliberate intimidation,
|
||||
violent threats or language directed against another person; insults, put downs,
|
||||
or jokes that are based upon stereotypes, that are exclusionary, or that hold
|
||||
others up for ridicule; unwelcome sexual attention or advances; sustained
|
||||
disruption of community discussions; publishing others' private information
|
||||
without explicit permission; and other conduct that is inappropriate for a
|
||||
professional audience including people of many different backgrounds.
|
||||
|
||||
This code of conduct covers all online and offline presence related to the
|
||||
MicroPython project, including GitHub and the forum. If a participant engages
|
||||
in behaviour that violates this code of conduct, the MicroPython team may take
|
||||
action as they deem appropriate, including warning the offender or expulsion
|
||||
from the community. Community members asked to stop any inappropriate behaviour
|
||||
are expected to comply immediately.
|
||||
|
||||
Thank you for helping make this a welcoming, friendly community for everyone.
|
||||
|
||||
If you believe that someone is violating the code of conduct, or have any other
|
||||
concerns, please contact a member of the MicroPython team by emailing
|
||||
contact@micropython.org.
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
This Code of Conduct is licensed under the Creative Commons
|
||||
Attribution-ShareAlike 3.0 Unported License.
|
||||
|
||||
Attributions
|
||||
------------
|
||||
|
||||
Based on the Python code of conduct found at https://www.python.org/psf/conduct/
|
||||
@ -3,6 +3,6 @@ make sure that you are acquainted with Contributor Guidelines:
|
||||
|
||||
https://github.com/micropython/micropython/wiki/ContributorGuidelines
|
||||
|
||||
and Code Conventions:
|
||||
as well as the Code Conventions, which includes details of how to commit:
|
||||
|
||||
https://github.com/micropython/micropython/blob/master/CODECONVENTIONS.md
|
||||
|
||||
2
LICENSE
2
LICENSE
@ -1,6 +1,6 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013, 2014 Damien P. George
|
||||
Copyright (c) 2013-2021 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
|
||||
|
||||
48
README.md
48
README.md
@ -1,4 +1,4 @@
|
||||
[](https://travis-ci.org/micropython/micropython) [](https://coveralls.io/r/micropython/micropython?branch=master)
|
||||
[](https://github.com/micropython/micropython/actions?query=branch%3Amaster+event%3Apush) [](https://coveralls.io/r/micropython/micropython?branch=master)
|
||||
|
||||
The MicroPython project
|
||||
=======================
|
||||
@ -41,8 +41,7 @@ Major components in this repository:
|
||||
to port MicroPython to another microcontroller.
|
||||
- tests/ -- test framework and test scripts.
|
||||
- docs/ -- user documentation in Sphinx reStructuredText format. Rendered
|
||||
HTML documentation is available at http://docs.micropython.org (be sure
|
||||
to select needed board/port at the bottom left corner).
|
||||
HTML documentation is available at http://docs.micropython.org.
|
||||
|
||||
Additional components:
|
||||
- ports/bare-arm/ -- a bare minimum version of MicroPython for ARM MCUs. Used
|
||||
@ -51,7 +50,9 @@ Additional components:
|
||||
(preliminary but functional).
|
||||
- ports/pic16bit/ -- a version of MicroPython for 16-bit PIC microcontrollers.
|
||||
- ports/cc3200/ -- a version of MicroPython that runs on the CC3200 from TI.
|
||||
- ports/esp8266/ -- an experimental port for ESP8266 WiFi modules.
|
||||
- ports/esp8266/ -- a version of MicroPython that runs on Espressif's ESP8266 SoC.
|
||||
- ports/esp32/ -- a version of MicroPython that runs on Espressif's ESP32 SoC.
|
||||
- ports/nrf/ -- a version of MicroPython that runs on Nordic's nRF51 and nRF52 MCUs.
|
||||
- extmod/ -- additional (non-core) modules implemented in C.
|
||||
- tools/ -- various tools, including the pyboard.py module.
|
||||
- examples/ -- a few example Python scripts.
|
||||
@ -59,7 +60,20 @@ Additional components:
|
||||
The subdirectories above may include READMEs with additional info.
|
||||
|
||||
"make" is used to build the components, or "gmake" on BSD-based systems.
|
||||
You will also need bash, gcc, and Python (at least 2.7 or 3.3).
|
||||
You will also need bash, gcc, and Python 3.3+ available as the command `python3`
|
||||
(if your system only has Python 2.7 then invoke make with the additional option
|
||||
`PYTHON=python2`).
|
||||
|
||||
The MicroPython cross-compiler, mpy-cross
|
||||
-----------------------------------------
|
||||
|
||||
Most ports require the MicroPython cross-compiler to be built first. This
|
||||
program, called mpy-cross, is used to pre-compile Python scripts to .mpy
|
||||
files which can then be included (frozen) into the firmware/executable for
|
||||
a port. To build mpy-cross use:
|
||||
|
||||
$ cd mpy-cross
|
||||
$ make
|
||||
|
||||
The Unix version
|
||||
----------------
|
||||
@ -72,9 +86,8 @@ Alternatively, fallback implementation based on setjmp/longjmp can be used.
|
||||
|
||||
To build (see section below for required dependencies):
|
||||
|
||||
$ git submodule update --init
|
||||
$ cd ports/unix
|
||||
$ make axtls
|
||||
$ make submodules
|
||||
$ make
|
||||
|
||||
Then to give it a try:
|
||||
@ -86,7 +99,7 @@ Use `CTRL-D` (i.e. EOF) to exit the shell.
|
||||
Learn about command-line options (in particular, how to increase heap size
|
||||
which may be needed for larger applications):
|
||||
|
||||
$ ./micropython --help
|
||||
$ ./micropython -h
|
||||
|
||||
Run complete testsuite:
|
||||
|
||||
@ -114,13 +127,14 @@ Debian/Ubuntu/Mint derivative Linux distros, install `build-essential`
|
||||
Other dependencies can be built together with MicroPython. This may
|
||||
be required to enable extra features or capabilities, and in recent
|
||||
versions of MicroPython, these may be enabled by default. To build
|
||||
these additional dependencies, first fetch git submodules for them:
|
||||
these additional dependencies, in the port directory you're
|
||||
interested in (e.g. `ports/unix/`) first execute:
|
||||
|
||||
$ git submodule update --init
|
||||
$ make submodules
|
||||
|
||||
Use the same command to get the latest versions of dependencies, as
|
||||
they are updated from time to time. After that, in the port directory
|
||||
(e.g. `ports/unix/`), execute:
|
||||
This will fetch all the relevant git submodules (sub repositories) that
|
||||
the port needs. Use the same command to get the latest versions of
|
||||
submodules as they are updated from time to time. After that execute:
|
||||
|
||||
$ make deplibs
|
||||
|
||||
@ -130,11 +144,11 @@ options (like cross-compiling), the same set of options should be passed
|
||||
to `make deplibs`. To actually enable/disable use of dependencies, edit
|
||||
`ports/unix/mpconfigport.mk` file, which has inline descriptions of the options.
|
||||
For example, to build SSL module (required for `upip` tool described above,
|
||||
and so enabled by dfeault), `MICROPY_PY_USSL` should be set to 1.
|
||||
and so enabled by default), `MICROPY_PY_USSL` should be set to 1.
|
||||
|
||||
For some ports, building required dependences is transparent, and happens
|
||||
automatically. They still need to be fetched with the git submodule command
|
||||
above.
|
||||
automatically. But they still need to be fetched with the `make submodules`
|
||||
command.
|
||||
|
||||
The STM32 version
|
||||
-----------------
|
||||
@ -146,8 +160,8 @@ https://launchpad.net/gcc-arm-embedded
|
||||
|
||||
To build:
|
||||
|
||||
$ git submodule update --init
|
||||
$ cd ports/stm32
|
||||
$ make submodules
|
||||
$ make
|
||||
|
||||
You then need to get your board into DFU mode. On the pyboard, connect the
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
|
||||
# You can set these variables from the command line.
|
||||
PYTHON = python3
|
||||
SPHINXOPTS =
|
||||
SPHINXOPTS = -W --keep-going
|
||||
SPHINXBUILD = sphinx-build
|
||||
PAPER =
|
||||
BUILDDIR = build/$(MICROPY_PORT)
|
||||
|
||||
@ -21,18 +21,31 @@ preferably in a virtualenv:
|
||||
|
||||
In `micropython/docs`, build the docs:
|
||||
|
||||
make MICROPY_PORT=<port_name> html
|
||||
make html
|
||||
|
||||
Where `<port_name>` can be `unix`, `pyboard`, `wipy` or `esp8266`.
|
||||
You'll find the index page at `micropython/docs/build/html/index.html`.
|
||||
|
||||
You'll find the index page at `micropython/docs/build/<port_name>/html/index.html`.
|
||||
Having readthedocs.org build the documentation
|
||||
----------------------------------------------
|
||||
|
||||
If you would like to have docs for forks/branches hosted on GitHub, GitLab or
|
||||
BitBucket an alternative to building the docs locally is to sign up for a free
|
||||
https://readthedocs.org account. The rough steps to follow are:
|
||||
1. sign-up for an account, unless you already have one
|
||||
2. in your account settings: add GitHub as a connected service (assuming
|
||||
you have forked this repo on github)
|
||||
3. in your account projects: import your forked/cloned micropython repository
|
||||
into readthedocs
|
||||
4. in the project's versions: add the branches you are developing on or
|
||||
for which you'd like readthedocs to auto-generate docs whenever you
|
||||
push a change
|
||||
|
||||
PDF manual generation
|
||||
---------------------
|
||||
|
||||
This can be achieved with:
|
||||
|
||||
make MICROPY_PORT=<port_name> latexpdf
|
||||
make latexpdf
|
||||
|
||||
but require rather complete install of LaTeX with various extensions. On
|
||||
Debian/Ubuntu, try (500MB+ download):
|
||||
|
||||
63
docs/conf.py
63
docs/conf.py
@ -21,42 +21,21 @@ import os
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
sys.path.insert(0, os.path.abspath('.'))
|
||||
|
||||
# Work out the port to generate the docs for
|
||||
from collections import OrderedDict
|
||||
micropy_port = os.getenv('MICROPY_PORT') or 'pyboard'
|
||||
tags.add('port_' + micropy_port)
|
||||
ports = OrderedDict((
|
||||
('unix', 'unix'),
|
||||
('pyboard', 'the pyboard'),
|
||||
('wipy', 'the WiPy'),
|
||||
('esp8266', 'the ESP8266'),
|
||||
))
|
||||
|
||||
# The members of the html_context dict are available inside topindex.html
|
||||
micropy_version = os.getenv('MICROPY_VERSION') or 'latest'
|
||||
micropy_all_versions = (os.getenv('MICROPY_ALL_VERSIONS') or 'latest').split(',')
|
||||
url_pattern = '%s/en/%%s/%%s' % (os.getenv('MICROPY_URL_PREFIX') or '/',)
|
||||
url_pattern = '%s/en/%%s' % (os.getenv('MICROPY_URL_PREFIX') or '/',)
|
||||
html_context = {
|
||||
'port':micropy_port,
|
||||
'port_name':ports[micropy_port],
|
||||
'port_version':micropy_version,
|
||||
'all_ports':[
|
||||
(port_id, url_pattern % (micropy_version, port_id))
|
||||
for port_id, port_name in ports.items()
|
||||
],
|
||||
'cur_version':micropy_version,
|
||||
'all_versions':[
|
||||
(ver, url_pattern % (ver, micropy_port))
|
||||
for ver in micropy_all_versions
|
||||
(ver, url_pattern % ver) for ver in micropy_all_versions
|
||||
],
|
||||
'downloads':[
|
||||
('PDF', url_pattern % (micropy_version, 'micropython-%s.pdf' % micropy_port)),
|
||||
('PDF', url_pattern % micropy_version + '/micropython-docs.pdf'),
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
# Specify a custom master document based on the port name
|
||||
master_doc = micropy_port + '_' + 'index'
|
||||
|
||||
# -- General configuration ------------------------------------------------
|
||||
|
||||
# If your documentation needs a minimal Sphinx version, state it here.
|
||||
@ -71,9 +50,6 @@ extensions = [
|
||||
'sphinx.ext.intersphinx',
|
||||
'sphinx.ext.todo',
|
||||
'sphinx.ext.coverage',
|
||||
'sphinx_selective_exclude.modindex_exclude',
|
||||
'sphinx_selective_exclude.eager_only',
|
||||
'sphinx_selective_exclude.search_auto_exclude',
|
||||
]
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
@ -86,11 +62,11 @@ source_suffix = '.rst'
|
||||
#source_encoding = 'utf-8-sig'
|
||||
|
||||
# The master toctree document.
|
||||
#master_doc = 'index'
|
||||
master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = 'MicroPython'
|
||||
copyright = '2014-2018, Damien P. George, Paul Sokolovsky, and contributors'
|
||||
copyright = '2014-2021, Damien P. George, Paul Sokolovsky, and contributors'
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
@ -98,7 +74,7 @@ copyright = '2014-2018, Damien P. George, Paul Sokolovsky, and contributors'
|
||||
#
|
||||
# We don't follow "The short X.Y version" vs "The full version, including alpha/beta/rc tags"
|
||||
# breakdown, so use the same version identifier for both to avoid confusion.
|
||||
version = release = '1.9.4'
|
||||
version = release = '1.13'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
@ -183,7 +159,7 @@ else:
|
||||
# The name of an image file (within the static path) to use as favicon of the
|
||||
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
|
||||
# pixels large.
|
||||
html_favicon = 'favicon.ico'
|
||||
html_favicon = 'static/favicon.ico'
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
@ -322,25 +298,4 @@ texinfo_documents = [
|
||||
|
||||
|
||||
# Example configuration for intersphinx: refer to the Python standard library.
|
||||
intersphinx_mapping = {'python': ('http://docs.python.org/3.5', None)}
|
||||
|
||||
# Append the other ports' specific folders/files to the exclude pattern
|
||||
exclude_patterns.extend([port + '*' for port in ports if port != micropy_port])
|
||||
|
||||
modules_port_specific = {
|
||||
'pyboard': ['pyb'],
|
||||
'wipy': ['wipy'],
|
||||
'esp8266': ['esp'],
|
||||
}
|
||||
|
||||
modindex_exclude = []
|
||||
|
||||
for p, l in modules_port_specific.items():
|
||||
if p != micropy_port:
|
||||
modindex_exclude += l
|
||||
|
||||
# Exclude extra modules per port
|
||||
modindex_exclude += {
|
||||
'esp8266': ['cmath', 'select'],
|
||||
'wipy': ['cmath'],
|
||||
}.get(micropy_port, [])
|
||||
intersphinx_mapping = {'python': ('https://docs.python.org/3.5', None)}
|
||||
|
||||
172
docs/develop/cmodules.rst
Normal file
172
docs/develop/cmodules.rst
Normal file
@ -0,0 +1,172 @@
|
||||
.. _cmodules:
|
||||
|
||||
MicroPython external C modules
|
||||
==============================
|
||||
|
||||
When developing modules for use with MicroPython you may find you run into
|
||||
limitations with the Python environment, often due to an inability to access
|
||||
certain hardware resources or Python speed limitations.
|
||||
|
||||
If your limitations can't be resolved with suggestions in :ref:`speed_python`,
|
||||
writing some or all of your module in C (and/or C++ if implemented for your port)
|
||||
is a viable option.
|
||||
|
||||
If your module is designed to access or work with commonly available
|
||||
hardware or libraries please consider implementing it inside the MicroPython
|
||||
source tree alongside similar modules and submitting it as a pull request.
|
||||
If however you're targeting obscure or proprietary systems it may make
|
||||
more sense to keep this external to the main MicroPython repository.
|
||||
|
||||
This chapter describes how to compile such external modules into the
|
||||
MicroPython executable or firmware image.
|
||||
|
||||
An alternative approach is to use :ref:`natmod` which allows writing custom C
|
||||
code that is placed in a .mpy file, which can be imported dynamically in to
|
||||
a running MicroPython system without the need to recompile the main firmware.
|
||||
|
||||
|
||||
Structure of an external C module
|
||||
---------------------------------
|
||||
|
||||
A MicroPython user C module is a directory with the following files:
|
||||
|
||||
* ``*.c`` / ``*.cpp`` / ``*.h`` source code files for your module.
|
||||
|
||||
These will typically include the low level functionality being implemented and
|
||||
the MicroPython binding functions to expose the functions and module(s).
|
||||
|
||||
Currently the best reference for writing these functions/modules is
|
||||
to find similar modules within the MicroPython tree and use them as examples.
|
||||
|
||||
* ``micropython.mk`` contains the Makefile fragment for this module.
|
||||
|
||||
``$(USERMOD_DIR)`` is available in ``micropython.mk`` as the path to your
|
||||
module directory. As it's redefined for each c module, is should be expanded
|
||||
in your ``micropython.mk`` to a local make variable,
|
||||
eg ``EXAMPLE_MOD_DIR := $(USERMOD_DIR)``
|
||||
|
||||
Your ``micropython.mk`` must add your modules source files relative to your
|
||||
expanded copy of ``$(USERMOD_DIR)`` to ``SRC_USERMOD``, eg
|
||||
``SRC_USERMOD += $(EXAMPLE_MOD_DIR)/example.c``
|
||||
|
||||
If you have custom compiler options (like ``-I`` to add directories to search
|
||||
for header files), these should be added to ``CFLAGS_USERMOD`` for C code
|
||||
and to ``CXXFLAGS_USERMOD`` for C++ code.
|
||||
|
||||
See below for full usage example.
|
||||
|
||||
|
||||
Basic example
|
||||
-------------
|
||||
|
||||
This simple module named ``cexample`` provides a single function
|
||||
``cexample.add_ints(a, b)`` which adds the two integer args together and returns
|
||||
the result. It can be found in the MicroPython source tree
|
||||
`in the examples directory <https://github.com/micropython/micropython/tree/master/examples/usercmodule/cexample>`_
|
||||
and has a source file and a Makefile fragment with content as descibed above::
|
||||
|
||||
micropython/
|
||||
└──examples/
|
||||
└──usercmodule/
|
||||
└──cexample/
|
||||
├── examplemodule.c
|
||||
└── micropython.mk
|
||||
|
||||
Refer to the comments in these 2 files for additional explanation.
|
||||
Next to the ``cexample`` module there's also ``cppexample`` which
|
||||
works in the same way but shows one way of mixing C and C++ code
|
||||
in MicroPython.
|
||||
|
||||
|
||||
Compiling the cmodule into MicroPython
|
||||
--------------------------------------
|
||||
|
||||
To build such a module, compile MicroPython (see `getting started
|
||||
<https://github.com/micropython/micropython/wiki/Getting-Started>`_),
|
||||
applying 2 modifications:
|
||||
|
||||
- an extra ``make`` flag named ``USER_C_MODULES`` set to the directory
|
||||
containing all modules you want included (not to the module itself).
|
||||
For building the example modules which come with MicroPython,
|
||||
set ``USER_C_MODULES`` to the ``examples/usercmodule`` directory.
|
||||
For your own projects it's more convenient to keep custom code out of
|
||||
the main source tree so a typical project directory structure will look
|
||||
like this::
|
||||
|
||||
my_project/
|
||||
├── modules/
|
||||
│ └──example1/
|
||||
│ ├──example1.c
|
||||
│ └──micropython.mk
|
||||
│ └──example2/
|
||||
│ ├──example2.c
|
||||
│ └──micropython.mk
|
||||
└── micropython/
|
||||
├──ports/
|
||||
... ├──stm32/
|
||||
...
|
||||
|
||||
|
||||
with ``USER_C_MODULES`` set to the ``my_project/modules`` directory.
|
||||
|
||||
- all modules found in this directory will be compiled, but only those
|
||||
which are explicitly enabled will be availabe for importing. Enabling a
|
||||
module is done by setting the preprocessor define from its module
|
||||
registration to 1. For example if the source code defines the module with
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
MP_REGISTER_MODULE(MP_QSTR_cexample, example_user_cmodule, MODULE_CEXAMPLE_ENABLED);
|
||||
|
||||
|
||||
then ``MODULE_CEXAMPLE_ENABLED`` has to be set to 1 to make the module available.
|
||||
This can be done by adding ``CFLAGS_EXTRA=-DMODULE_CEXAMPLE_ENABLED=1`` to
|
||||
the ``make`` command, or editing ``mpconfigport.h`` or ``mpconfigboard.h``
|
||||
to add
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#define MODULE_CEXAMPLE_ENABLED (1)
|
||||
|
||||
|
||||
Note that the exact method depends on the port as they have different
|
||||
structures. If not done correctly it will compile but importing will
|
||||
fail to find the module.
|
||||
|
||||
To sum up, here's how the ``cexample`` module from the ``examples/usercmodule``
|
||||
directory can be built for the unix port:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
cd micropython/ports/unix
|
||||
make USER_C_MODULES=../../examples/usercmodule CFLAGS_EXTRA=-DMODULE_CEXAMPLE_ENABLED=1 all
|
||||
|
||||
The build output will show the modules found::
|
||||
|
||||
...
|
||||
Including User C Module from ../../examples/usercmodule/cexample
|
||||
Including User C Module from ../../examples/usercmodule/cppexample
|
||||
...
|
||||
|
||||
|
||||
Or for your own project with a directory structure as shown above,
|
||||
including both modules and building the stm32 port for example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
cd my_project/micropython/ports/stm32
|
||||
make USER_C_MODULES=../../../modules \
|
||||
CFLAGS_EXTRA="-DMODULE_EXAMPLE1_ENABLED=1 -DMODULE_EXAMPLE2_ENABLED=1" all
|
||||
|
||||
|
||||
Module usage in MicroPython
|
||||
---------------------------
|
||||
|
||||
Once built into your copy of MicroPython, the module
|
||||
can now be accessed in Python just like any other builtin module, e.g.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import cexample
|
||||
print(cexample.add_ints(1, 3))
|
||||
# should display 4
|
||||
317
docs/develop/compiler.rst
Normal file
317
docs/develop/compiler.rst
Normal file
@ -0,0 +1,317 @@
|
||||
.. _compiler:
|
||||
|
||||
The Compiler
|
||||
============
|
||||
|
||||
The compilation process in MicroPython involves the following steps:
|
||||
|
||||
* The lexer converts the stream of text that makes up a MicroPython program into tokens.
|
||||
* The parser then converts the tokens into an abstract syntax (parse tree).
|
||||
* Then bytecode or native code is emitted based on the parse tree.
|
||||
|
||||
For purposes of this discussion we are going to add a simple language feature ``add1``
|
||||
that can be use in Python as:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
>>> add1 3
|
||||
4
|
||||
>>>
|
||||
|
||||
The ``add1`` statement takes an integer as argument and adds ``1`` to it.
|
||||
|
||||
Adding a grammar rule
|
||||
----------------------
|
||||
|
||||
MicroPython's grammar is based on the `CPython grammar <https://docs.python.org/3.5/reference/grammar.html>`_
|
||||
and is defined in `py/grammar.h <https://github.com/micropython/micropython/blob/master/py/grammar.h>`_.
|
||||
This grammar is what is used to parse MicroPython source files.
|
||||
|
||||
There are two macros you need to know to define a grammar rule: ``DEF_RULE`` and ``DEF_RULE_NC``.
|
||||
``DEF_RULE`` allows you to define a rule with an associated compile function,
|
||||
while ``DEF_RULE_NC`` has no compile (NC) function for it.
|
||||
|
||||
A simple grammar definition with a compile function for our new ``add1`` statement
|
||||
looks like the following:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
DEF_RULE(add1_stmt, c(add1_stmt), and(2), tok(KW_ADD1), rule(testlist))
|
||||
|
||||
The second argument ``c(add1_stmt)`` is the corresponding compile function that should be implemented
|
||||
in ``py/compile.c`` to turn this rule into executable code.
|
||||
|
||||
The third required argument can be ``or`` or ``and``. This specifies the number of nodes associated
|
||||
with a statement. For example, in this case, our ``add1`` statement is similar to ADD1 in assembly
|
||||
language. It takes one numeric argument. Therefore, the ``add1_stmt`` has two nodes associated with it.
|
||||
One node is for the statement itself, i.e the literal ``add1`` corresponding to ``KW_ADD1``,
|
||||
and the other for its argument, a ``testlist`` rule which is the top-level expression rule.
|
||||
|
||||
.. note::
|
||||
The ``add1`` rule here is just an example and not part of the standard
|
||||
MicroPython grammar.
|
||||
|
||||
The fourth argument in this example is the token associated with the rule, ``KW_ADD1``. This token should be
|
||||
defined in the lexer by editing ``py/lexer.h``.
|
||||
|
||||
Defining the same rule without a compile function is achieved by using the ``DEF_RULE_NC`` macro
|
||||
and omitting the compile function argument:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
DEF_RULE_NC(add1_stmt, and(2), tok(KW_ADD1), rule(testlist))
|
||||
|
||||
The remaining arguments take on the same meaning. A rule without a compile function must
|
||||
be handled explicitly by all rules that may have this rule as a node. Such NC-rules are usually
|
||||
used to express sub-parts of a complicated grammar structure that cannot be expressed in a
|
||||
single rule.
|
||||
|
||||
.. note::
|
||||
The macros ``DEF_RULE`` and ``DEF_RULE_NC`` take other arguments. For an in-depth understanding of
|
||||
supported parameters, see `py/grammar.h <https://github.com/micropython/micropython/blob/master/py/grammar.h>`_.
|
||||
|
||||
Adding a lexical token
|
||||
----------------------
|
||||
|
||||
Every rule defined in the grammar should have a token associated with it that is defined in ``py/lexer.h``.
|
||||
Add this token by editing the ``_mp_token_kind_t`` enum:
|
||||
|
||||
.. code-block:: c
|
||||
:emphasize-lines: 12
|
||||
|
||||
typedef enum _mp_token_kind_t {
|
||||
...
|
||||
MP_TOKEN_KW_OR,
|
||||
MP_TOKEN_KW_PASS,
|
||||
MP_TOKEN_KW_RAISE,
|
||||
MP_TOKEN_KW_RETURN,
|
||||
MP_TOKEN_KW_TRY,
|
||||
MP_TOKEN_KW_WHILE,
|
||||
MP_TOKEN_KW_WITH,
|
||||
MP_TOKEN_KW_YIELD,
|
||||
MP_TOKEN_KW_ADD1,
|
||||
...
|
||||
} mp_token_kind_t;
|
||||
|
||||
Then also edit ``py/lexer.c`` to add the new keyword literal text:
|
||||
|
||||
.. code-block:: c
|
||||
:emphasize-lines: 12
|
||||
|
||||
STATIC const char *const tok_kw[] = {
|
||||
...
|
||||
"or",
|
||||
"pass",
|
||||
"raise",
|
||||
"return",
|
||||
"try",
|
||||
"while",
|
||||
"with",
|
||||
"yield",
|
||||
"add1",
|
||||
...
|
||||
};
|
||||
|
||||
Notice the keyword is named depending on what you want it to be. For consistency, maintain the
|
||||
naming standard accordingly.
|
||||
|
||||
.. note::
|
||||
The order of these keywords in ``py/lexer.c`` must match the order of tokens in the enum
|
||||
defined in ``py/lexer.h``.
|
||||
|
||||
Parsing
|
||||
-------
|
||||
|
||||
In the parsing stage the parser takes the tokens produced by the lexer and converts them to an abstract syntax tree (AST) or
|
||||
*parse tree*. The implementation for the parser is defined in `py/parse.c <https://github.com/micropython/micropython/blob/master/py/parse.c>`_.
|
||||
|
||||
The parser also maintains a table of constants for use in different aspects of parsing, similar to what a
|
||||
`symbol table <https://steemit.com/programming/@drifter1/writing-a-simple-compiler-on-my-own-symbol-table-basic-structure>`_
|
||||
does.
|
||||
|
||||
Several optimizations like `constant folding <http://compileroptimizations.com/category/constant_folding.htm>`_
|
||||
on integers for most operations e.g. logical, binary, unary, etc, and optimizing enhancements on parenthesis
|
||||
around expressions are performed during this phase, along with some optimizations on strings.
|
||||
|
||||
It's worth noting that *docstrings* are discarded and not accessible to the compiler.
|
||||
Even optimizations like `string interning <https://en.wikipedia.org/wiki/String_interning>`_ are
|
||||
not applied to *docstrings*.
|
||||
|
||||
Compiler passes
|
||||
---------------
|
||||
|
||||
Like many compilers, MicroPython compiles all code to MicroPython bytecode or native code. The functionality
|
||||
that achieves this is implemented in `py/compile.c <https://github.com/micropython/micropython/blob/master/py/compile.c>`_.
|
||||
The most relevant method you should know about is this:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
mp_obj_t mp_compile(mp_parse_tree_t *parse_tree, qstr source_file, bool is_repl) {
|
||||
// Compile the input parse_tree to a raw-code structure.
|
||||
mp_raw_code_t *rc = mp_compile_to_raw_code(parse_tree, source_file, is_repl);
|
||||
// Create and return a function object that executes the outer module.
|
||||
return mp_make_function_from_raw_code(rc, MP_OBJ_NULL, MP_OBJ_NULL);
|
||||
}
|
||||
|
||||
The compiler compiles the code in four passes: scope, stack size, code size and emit.
|
||||
Each pass runs the same C code over the same AST data structure, with different things
|
||||
being computed each time based on the results of the previous pass.
|
||||
|
||||
First pass
|
||||
~~~~~~~~~~
|
||||
|
||||
In the first pass, the compiler learns about the known identifiers (variables) and
|
||||
their scope, being global, local, closed over, etc. In the same pass the emitter
|
||||
(bytecode or native code) also computes the number of labels needed for the emitted
|
||||
code.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
// Compile pass 1.
|
||||
comp->emit = emit_bc;
|
||||
comp->emit_method_table = &emit_bc_method_table;
|
||||
|
||||
uint max_num_labels = 0;
|
||||
for (scope_t *s = comp->scope_head; s != NULL && comp->compile_error == MP_OBJ_NULL; s = s->next) {
|
||||
if (s->emit_options == MP_EMIT_OPT_ASM) {
|
||||
compile_scope_inline_asm(comp, s, MP_PASS_SCOPE);
|
||||
} else {
|
||||
compile_scope(comp, s, MP_PASS_SCOPE);
|
||||
|
||||
// Check if any implicitly declared variables should be closed over.
|
||||
for (size_t i = 0; i < s->id_info_len; ++i) {
|
||||
id_info_t *id = &s->id_info[i];
|
||||
if (id->kind == ID_INFO_KIND_GLOBAL_IMPLICIT) {
|
||||
scope_check_to_close_over(s, id);
|
||||
}
|
||||
}
|
||||
}
|
||||
...
|
||||
}
|
||||
|
||||
Second and third passes
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The second and third passes involve computing the Python stack size and code size
|
||||
for the bytecode or native code. After the third pass the code size cannot change,
|
||||
otherwise jump labels will be incorrect.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
for (scope_t *s = comp->scope_head; s != NULL && comp->compile_error == MP_OBJ_NULL; s = s->next) {
|
||||
...
|
||||
|
||||
// Pass 2: Compute the Python stack size.
|
||||
compile_scope(comp, s, MP_PASS_STACK_SIZE);
|
||||
|
||||
// Pass 3: Compute the code size.
|
||||
if (comp->compile_error == MP_OBJ_NULL) {
|
||||
compile_scope(comp, s, MP_PASS_CODE_SIZE);
|
||||
}
|
||||
|
||||
...
|
||||
}
|
||||
|
||||
Just before pass two there is a selection for the type of code to be emitted, which can
|
||||
either be native or bytecode.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
// Choose the emitter type.
|
||||
switch (s->emit_options) {
|
||||
case MP_EMIT_OPT_NATIVE_PYTHON:
|
||||
case MP_EMIT_OPT_VIPER:
|
||||
if (emit_native == NULL) {
|
||||
emit_native = NATIVE_EMITTER(new)(&comp->compile_error, &comp->next_label, max_num_labels);
|
||||
}
|
||||
comp->emit_method_table = NATIVE_EMITTER_TABLE;
|
||||
comp->emit = emit_native;
|
||||
break;
|
||||
|
||||
default:
|
||||
comp->emit = emit_bc;
|
||||
comp->emit_method_table = &emit_bc_method_table;
|
||||
break;
|
||||
}
|
||||
|
||||
The bytecode option is the default but something unique to note for the native
|
||||
code option is that there is another option via ``VIPER``. See the
|
||||
:ref:`Emitting native code <emitting_native_code>` section for more details on
|
||||
viper annotations.
|
||||
|
||||
There is also support for *inline assembly code*, where assembly instructions are
|
||||
written as Python function calls but are emitted directly as the corresponding
|
||||
machine code. This assembler has only three passes (scope, code size, emit)
|
||||
and uses a different implementation, not the ``compile_scope`` function.
|
||||
See the `inline assembler tutorial <https://docs.micropython.org/en/latest/pyboard/tutorial/assembler.html#pyboard-tutorial-assembler>`_
|
||||
for more details.
|
||||
|
||||
Fourth pass
|
||||
~~~~~~~~~~~
|
||||
|
||||
The fourth pass emits the final code that can be executed, either bytecode in
|
||||
the virtual machine, or native code directly by the CPU.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
for (scope_t *s = comp->scope_head; s != NULL && comp->compile_error == MP_OBJ_NULL; s = s->next) {
|
||||
...
|
||||
|
||||
// Pass 4: Emit the compiled bytecode or native code.
|
||||
if (comp->compile_error == MP_OBJ_NULL) {
|
||||
compile_scope(comp, s, MP_PASS_EMIT);
|
||||
}
|
||||
}
|
||||
|
||||
Emitting bytecode
|
||||
-----------------
|
||||
|
||||
Statements in Python code usually correspond to emitted bytecode, for example ``a + b``
|
||||
generates "push a" then "push b" then "binary op add". Some statements do not emit
|
||||
anything but instead affect other things like the scope of variables, for example
|
||||
``global a``.
|
||||
|
||||
The implementation of a function that emits bytecode looks similar to this:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
void mp_emit_bc_unary_op(emit_t *emit, mp_unary_op_t op) {
|
||||
emit_write_bytecode_byte(emit, 0, MP_BC_UNARY_OP_MULTI + op);
|
||||
}
|
||||
|
||||
We use the unary operator expressions for an example here but the implementation
|
||||
details are similar for other statements/expressions. The method ``emit_write_bytecode_byte()``
|
||||
is a wrapper around the main function ``emit_get_cur_to_write_bytecode()`` that all
|
||||
functions must call to emit bytecode.
|
||||
|
||||
.. _emitting_native_code:
|
||||
|
||||
Emitting native code
|
||||
---------------------
|
||||
|
||||
Similar to how bytecode is generated, there should be a corresponding function in ``py/emitnative.c`` for each
|
||||
code statement:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
STATIC void emit_native_unary_op(emit_t *emit, mp_unary_op_t op) {
|
||||
vtype_kind_t vtype;
|
||||
emit_pre_pop_reg(emit, &vtype, REG_ARG_2);
|
||||
if (vtype == VTYPE_PYOBJ) {
|
||||
emit_call_with_imm_arg(emit, MP_F_UNARY_OP, op, REG_ARG_1);
|
||||
emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
|
||||
} else {
|
||||
adjust_stack(emit, 1);
|
||||
EMIT_NATIVE_VIPER_TYPE_ERROR(emit,
|
||||
MP_ERROR_TEXT("unary op %q not implemented"), mp_unary_op_method_name[op]);
|
||||
}
|
||||
}
|
||||
|
||||
The difference here is that we have to handle *viper typing*. Viper annotations allow
|
||||
us to handle more than one type of variable. By default all variables are Python objects,
|
||||
but with viper a variable can also be declared as a machine-typed variable like a native
|
||||
integer or pointer. Viper can be thought of as a superset of Python, where normal Python
|
||||
objects are handled as usual, while native machine variables are handled in an optimised
|
||||
way by using direct machine instructions for the operations. Viper typing may break
|
||||
Python equivalence because, for example, integers become native integers and can overflow
|
||||
(unlike Python integers which extend automatically to arbitrary precision).
|
||||
19
docs/develop/extendingmicropython.rst
Normal file
19
docs/develop/extendingmicropython.rst
Normal file
@ -0,0 +1,19 @@
|
||||
.. _extendingmicropython:
|
||||
|
||||
Extending MicroPython in C
|
||||
==========================
|
||||
|
||||
This chapter describes options for implementing additional functionality in C, but from code
|
||||
written outside of the main MicroPython repository. The first approach is useful for building
|
||||
your own custom firmware with some project-specific additional modules or functions that can
|
||||
be accessed from Python. The second approach is for building modules that can be loaded at runtime.
|
||||
|
||||
Please see the :ref:`library section <internals_library>` for more information on building core modules that
|
||||
live in the main MicroPython repository.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 3
|
||||
|
||||
cmodules.rst
|
||||
natmod.rst
|
||||
|
||||
324
docs/develop/gettingstarted.rst
Normal file
324
docs/develop/gettingstarted.rst
Normal file
@ -0,0 +1,324 @@
|
||||
.. _gettingstarted:
|
||||
|
||||
Getting Started
|
||||
===============
|
||||
|
||||
This guide covers a step-by-step process on setting up version control, obtaining and building
|
||||
a copy of the source code for a port, building the documentation, running tests, and a description of the
|
||||
directory structure of the MicroPython code base.
|
||||
|
||||
Source control with git
|
||||
-----------------------
|
||||
|
||||
MicroPython is hosted on `GitHub <https://github.com/micropython/micropython>`_ and uses
|
||||
`Git <https://git-scm.com>`_ for source control. The workflow is such that
|
||||
code is pulled and pushed to and from the main repository. Install the respective version
|
||||
of Git for your operating system to follow through the rest of the steps.
|
||||
|
||||
.. note::
|
||||
For a reference on the installation instructions, please refer to
|
||||
the `Git installation instructions <https://git-scm.com/book/en/v2/Getting-Started-Installing-Git>`_.
|
||||
Learn about the basic git commands in this `Git Handbook <https://guides.github.com/introduction/git-handbook/>`_
|
||||
or any other sources on the internet.
|
||||
|
||||
Get the code
|
||||
------------
|
||||
|
||||
It is recommended that you maintain a fork of the MicroPython repository for your development purposes.
|
||||
The process of obtaining the source code includes the following:
|
||||
|
||||
#. Fork the repository https://github.com/micropython/micropython
|
||||
#. You will now have a fork at <https://github.com/<your-user-name>/micropython>.
|
||||
#. Clone the forked repository using the following command:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ git clone https://github.com/<your-user-name>/micropython
|
||||
|
||||
Then, `configure the remote repositories <https://git-scm.com/book/en/v2/Git-Basics-Working-with-Remotes>`_ to be able to
|
||||
collaborate on the MicroPython project.
|
||||
|
||||
Configure remote upstream:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ cd micropython
|
||||
$ git remote add upstream https://github.com/micropython/micropython
|
||||
|
||||
It is common to configure ``upstream`` and ``origin`` on a forked repository
|
||||
to assist with sharing code changes. You can maintain your own mapping but
|
||||
it is recommended that ``origin`` maps to your fork and ``upstream`` to the main
|
||||
MicroPython repository.
|
||||
|
||||
After the above configuration, your setup should be similar to this:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ git remote -v
|
||||
origin https://github.com/<your-user-name>/micropython (fetch)
|
||||
origin https://github.com/<your-user-name>/micropython (push)
|
||||
upstream https://github.com/micropython/micropython (fetch)
|
||||
upstream https://github.com/micropython/micropython (push)
|
||||
|
||||
You should now have a copy of the source code. By default, you are pointing
|
||||
to the master branch. To prepare for further development, it is recommended
|
||||
to work on a development branch.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ git checkout -b dev-branch
|
||||
|
||||
You can give it any name. You will have to compile MicroPython whenever you change
|
||||
to a different branch.
|
||||
|
||||
Compile and build the code
|
||||
--------------------------
|
||||
|
||||
When compiling MicroPython, you compile a specific :term:`port`, usually
|
||||
targeting a specific :ref:`board <glossary>`. Start by installing the required dependencies.
|
||||
Then build the MicroPython cross-compiler before you can successfully compile and build.
|
||||
This applies specifically when using Linux to compile.
|
||||
The Windows instructions are provided in a later section.
|
||||
|
||||
.. _required_dependencies:
|
||||
|
||||
Required dependencies
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Install the required dependencies for Linux:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ sudo apt-get install build-essential libffi-dev git pkg-config
|
||||
|
||||
For the stm32 port, the ARM cross-compiler is required:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ sudo apt-get install arm-none-eabi-gcc arm-none-eabi-binutils arm-none-eabi-newlib
|
||||
|
||||
See the `ARM GCC
|
||||
toolchain <https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm>`_
|
||||
for the latest details.
|
||||
|
||||
Python is also required. Python 2 is supported for now, but we recommend using Python 3.
|
||||
Check that you have Python available on your system:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ python3
|
||||
Python 3.5.0 (default, Jul 17 2020, 14:04:10)
|
||||
[GCC 5.4.0 20160609] on linux
|
||||
Type "help", "copyright", "credits" or "license" for more information.
|
||||
>>>
|
||||
|
||||
All supported ports have different dependency requirements, see their respective
|
||||
`readme files <https://github.com/micropython/micropython/tree/master/ports>`_.
|
||||
|
||||
Building the MicroPython cross-compiler
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Almost all ports require building ``mpy-cross`` first to perform pre-compilation
|
||||
of Python code that will be included in the port firmware:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ cd mpy-cross
|
||||
$ make
|
||||
|
||||
.. note::
|
||||
Note that, ``mpy-cross`` must be built for the host architecture
|
||||
and not the target architecture.
|
||||
|
||||
If it built successfully, you should see a message similar to this:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
LINK mpy-cross
|
||||
text data bss dec hex filename
|
||||
279328 776 880 280984 44998 mpy-cross
|
||||
|
||||
.. note::
|
||||
|
||||
Use ``make -C mpy-cross`` to build the cross-compiler in one statement
|
||||
without moving to the ``mpy-cross`` directory otherwise, you will need
|
||||
to do ``cd ..`` for the next steps.
|
||||
|
||||
Building the Unix port of MicroPython
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The Unix port is a version of MicroPython that runs on Linux, macOS, and other Unix-like operating systems.
|
||||
It's extremely useful for developing MicroPython as it avoids having to deploy your code to a device to test it.
|
||||
In many ways, it works a lot like CPython's python binary.
|
||||
|
||||
To build for the Unix port, make sure all Linux related dependencies are installed as detailed in the
|
||||
required dependencies section. See the :ref:`required_dependencies`
|
||||
to make sure that all dependencies are installed for this port. Also, make sure you have a working
|
||||
environment for ``gcc`` and ``GNU make``. Ubuntu 20.04 has been used for the example
|
||||
below but other unixes ought to work with little modification:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ gcc --version
|
||||
gcc (Ubuntu 9.3.0-10ubuntu2) 9.3.0
|
||||
Copyright (C) 2019 Free Software Foundation, Inc.
|
||||
This is free software; see the source for copying conditions. There is NO
|
||||
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.then build:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ cd ports/unix
|
||||
$ make submodules
|
||||
$ make
|
||||
|
||||
If MicroPython built correctly, you should see the following:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
LINK micropython
|
||||
text data bss dec hex filename
|
||||
412033 5680 2496 420209 66971 micropython
|
||||
|
||||
Now run it:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ ./micropython
|
||||
MicroPython v1.13-38-gc67012d-dirty on 2020-09-13; linux version
|
||||
Use Ctrl-D to exit, Ctrl-E for paste mode
|
||||
>>> print("hello world")
|
||||
hello world
|
||||
>>>
|
||||
|
||||
Building the Windows port
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The Windows port includes a Visual Studio project file micropython.vcxproj that you can use to build micropython.exe.
|
||||
It can be opened in Visual Studio or built from the command line using msbuild. Alternatively, it can be built using mingw,
|
||||
either in Windows with Cygwin, or on Linux.
|
||||
See `windows port documentation <https://github.com/micropython/micropython/tree/master/ports/windows>`_ for more information.
|
||||
|
||||
Building the STM32 port
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Like the Unix port, you need to install some required dependencies
|
||||
as detailed in the :ref:`required_dependencies` section, then build:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ cd ports/stm32
|
||||
$ make submodules
|
||||
$ make
|
||||
|
||||
Please refer to the `stm32 documentation <https://github.com/micropython/micropython/tree/master/ports/stm32>`_
|
||||
for more details on flashing the firmware.
|
||||
|
||||
.. note::
|
||||
See the :ref:`required_dependencies` to make sure that all dependencies are installed for this port.
|
||||
The cross-compiler is needed. ``arm-none-eabi-gcc`` should also be in the $PATH or specified manually
|
||||
via CROSS_COMPILE, either by setting the environment variable or in the ``make`` command line arguments.
|
||||
|
||||
You can also specify which board to use:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ cd ports/stm32
|
||||
$ make submodules
|
||||
$ make BOARD=<board>
|
||||
|
||||
See `ports/stm32/boards <https://github.com/micropython/micropython/tree/master/ports/stm32/boards>`_
|
||||
for the available boards. e.g. "PYBV11" or "NUCLEO_WB55".
|
||||
|
||||
Building the documentation
|
||||
--------------------------
|
||||
|
||||
MicroPython documentation is created using ``Sphinx``. If you have already
|
||||
installed Python, then install ``Sphinx`` using ``pip``. It is recommended
|
||||
that you use a virtual environment:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ python3 -m venv env
|
||||
$ source env/bin/activate
|
||||
$ pip install sphinx
|
||||
|
||||
Navigate to the ``docs`` directory:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ cd docs
|
||||
|
||||
Build the docs:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ make html
|
||||
|
||||
Open ``docs/build/html/index.html`` in your browser to view the docs locally. Refer to the
|
||||
documentation on `importing your documentation
|
||||
<https://docs.readthedocs.io/en/stable/intro/import-guide.html>`_ to use Read the Docs.
|
||||
|
||||
Running the tests
|
||||
-----------------
|
||||
|
||||
To run all tests in the test suite on the Unix port use:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ cd ports/unix
|
||||
$ make test
|
||||
|
||||
To run a selection of tests on a board/device connected over USB use:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ cd tests
|
||||
$ ./run-tests --target minimal --device /dev/ttyACM0
|
||||
|
||||
See also :ref:`writingtests`.
|
||||
|
||||
Folder structure
|
||||
----------------
|
||||
|
||||
There are a couple of directories to take note of in terms of where certain implementation details
|
||||
are. The following is a break down of the top-level folders in the source code.
|
||||
|
||||
py
|
||||
|
||||
Contains the compiler, runtime, and core library implementation.
|
||||
|
||||
mpy-cross
|
||||
|
||||
Has the MicroPython cross-compiler which pre-compiles the Python scripts to bytecode.
|
||||
|
||||
ports
|
||||
|
||||
Code for all the versions of MicroPython for the supported ports.
|
||||
|
||||
lib
|
||||
|
||||
Low-level C libraries used by any port which are mostly 3rd-party libraries.
|
||||
|
||||
drivers
|
||||
|
||||
Has drivers for specific hardware and intended to work across multiple ports.
|
||||
|
||||
extmod
|
||||
|
||||
Contains a C implementation of more non-core modules.
|
||||
|
||||
docs
|
||||
|
||||
Has the standard documentation found at https://docs.micropython.org/.
|
||||
|
||||
tests
|
||||
|
||||
An implementation of the test suite.
|
||||
|
||||
tools
|
||||
|
||||
Contains helper tools including the ``upip`` and the ``pyboard.py`` module.
|
||||
|
||||
examples
|
||||
|
||||
Example code for building MicroPython as a library as well as native modules.
|
||||
BIN
docs/develop/img/bitmap.png
Normal file
BIN
docs/develop/img/bitmap.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.2 KiB |
BIN
docs/develop/img/collision.png
Normal file
BIN
docs/develop/img/collision.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.4 KiB |
BIN
docs/develop/img/linprob.png
Normal file
BIN
docs/develop/img/linprob.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.6 KiB |
27
docs/develop/index.rst
Normal file
27
docs/develop/index.rst
Normal file
@ -0,0 +1,27 @@
|
||||
MicroPython Internals
|
||||
=====================
|
||||
|
||||
This chapter covers a tour of MicroPython from the perspective of a developer, contributing
|
||||
to MicroPython. It acts as a comprehensive resource on the implementation details of MicroPython
|
||||
for both novice and expert contributors.
|
||||
|
||||
Development around MicroPython usually involves modifying the core runtime, porting or
|
||||
maintaining a new library. This guide describes at great depth, the implementation
|
||||
details of MicroPython including a getting started guide, compiler internals, porting
|
||||
MicroPython to a new platform and implementing a core MicroPython library.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 3
|
||||
|
||||
gettingstarted.rst
|
||||
writingtests.rst
|
||||
compiler.rst
|
||||
memorymgt.rst
|
||||
library.rst
|
||||
optimizations.rst
|
||||
qstr.rst
|
||||
maps.rst
|
||||
publiccapi.rst
|
||||
extendingmicropython.rst
|
||||
porting.rst
|
||||
|
||||
86
docs/develop/library.rst
Normal file
86
docs/develop/library.rst
Normal file
@ -0,0 +1,86 @@
|
||||
.. _internals_library:
|
||||
|
||||
Implementing a Module
|
||||
=====================
|
||||
|
||||
This chapter details how to implement a core module in MicroPython.
|
||||
MicroPython modules can be one of the following:
|
||||
|
||||
- Built-in module: A general module that is be part of the MicroPython repository.
|
||||
- User module: A module that is useful for your specific project that you maintain
|
||||
in your own repository or private codebase.
|
||||
- Dynamic module: A module that can be deployed and imported at runtime to your device.
|
||||
|
||||
A module in MicroPython can be implemented in one of the following locations:
|
||||
|
||||
- py/: A core library that mirrors core CPython functionality.
|
||||
- extmod/: A CPython or MicroPython-specific module that is shared across multiple ports.
|
||||
- ports/<port>/: A port-specific module.
|
||||
|
||||
.. note::
|
||||
This chapter describes modules implemented in ``py/`` or core modules.
|
||||
See :ref:`extendingmicropython` for details on implementing an external module.
|
||||
For details on port-specific modules, see :ref:`porting_to_a_board`.
|
||||
|
||||
Implementing a core module
|
||||
--------------------------
|
||||
|
||||
Like CPython, MicroPython has core builtin modules that can be accessed through import statements.
|
||||
An example is the ``gc`` module discussed in :ref:`memorymanagement`.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
>>> import gc
|
||||
>>> gc.enable()
|
||||
>>>
|
||||
|
||||
MicroPython has several other builtin standard/core modules like ``io``, ``uarray`` etc.
|
||||
Adding a new core module involves several modifications.
|
||||
|
||||
First, create the ``C`` file in the ``py/`` directory. In this example we are adding a
|
||||
hypothetical new module ``subsystem`` in the file ``modsubsystem.c``:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#include "py/builtin.h"
|
||||
#include "py/runtime.h"
|
||||
|
||||
#if MICROPY_PY_SUBSYSTEM
|
||||
|
||||
// info()
|
||||
STATIC mp_obj_t py_subsystem_info(void) {
|
||||
return MP_OBJ_NEW_SMALL_INT(42);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_0(subsystem_info_obj, py_subsystem_info);
|
||||
|
||||
STATIC const mp_rom_map_elem_t mp_module_subsystem_globals_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_subsystem) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_info), MP_ROM_PTR(&subsystem_info_obj) },
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(mp_module_subsystem_globals, mp_module_subsystem_globals_table);
|
||||
|
||||
const mp_obj_module_t mp_module_subsystem = {
|
||||
.base = { &mp_type_module },
|
||||
.globals = (mp_obj_dict_t *)&mp_module_subsystem_globals,
|
||||
};
|
||||
|
||||
MP_REGISTER_MODULE(MP_QSTR_subsystem, mp_module_subsystem, MICROPY_PY_SUBSYSTEM);
|
||||
|
||||
#endif
|
||||
|
||||
The implementation includes a definition of all functions related to the module and adds the
|
||||
functions to the module's global table in ``mp_module_subsystem_globals_table``. It also
|
||||
creates the module object with ``mp_module_subsystem``. The module is then registered with
|
||||
the wider system via the ``MP_REGISTER_MODULE`` macro.
|
||||
|
||||
After building and running the modified MicroPython, the module should now be importable:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
>>> import subsystem
|
||||
>>> subsystem.info()
|
||||
42
|
||||
>>>
|
||||
|
||||
Our ``info()`` function currently returns just a single number but can be extended
|
||||
to do anything. Similarly, more functions can be added to this new module.
|
||||
63
docs/develop/maps.rst
Normal file
63
docs/develop/maps.rst
Normal file
@ -0,0 +1,63 @@
|
||||
.. _maps:
|
||||
|
||||
Maps and Dictionaries
|
||||
=====================
|
||||
|
||||
MicroPython dictionaries and maps use techniques called open addressing and linear probing.
|
||||
This chapter details both of these methods.
|
||||
|
||||
Open addressing
|
||||
---------------
|
||||
|
||||
`Open addressing <https://en.wikipedia.org/wiki/Open_addressing>`_ is used to resolve collisions.
|
||||
Collisions are very common occurrences and happen when two items happen to hash to the same
|
||||
slot or location. For example, given a hash setup as this:
|
||||
|
||||
.. image:: img/collision.png
|
||||
|
||||
If there is a request to fill slot ``0`` with ``70``, since the slot ``0`` is not empty, open addressing
|
||||
finds the next available slot in the dictionary to service this request. This sequential search for an alternate
|
||||
location is called *probing*. There are several sequence probing algorithms but MicroPython uses
|
||||
linear probing that is described in the next section.
|
||||
|
||||
Linear probing
|
||||
--------------
|
||||
|
||||
Linear probing is one of the methods for finding an available address or slot in a dictionary. In MicroPython,
|
||||
it is used with open addressing. To service the request described above, unlike other probing algorithms,
|
||||
linear probing assumes a fixed interval of ``1`` between probes. The request will therefore be serviced by
|
||||
placing the item in the next free slot which is slot ``4`` in our example:
|
||||
|
||||
.. image:: img/linprob.png
|
||||
|
||||
The same methods i.e open addressing and linear probing are used to search for an item in a dictionary.
|
||||
Assume we want to search for the data item ``33``. The computed hash value will be 2. Looking at slot 2
|
||||
reveals ``33``, at this point, we return ``True``. Searching for ``70`` is quite different as there was a
|
||||
collision at the time of insertion. Therefore computing the hash value is ``0`` which is currently
|
||||
holding ``44``. Instead of simply returning ``False``, we perform a sequential search starting at point
|
||||
``1`` until the item ``70`` is found or we encounter a free slot. This is the general way of performing
|
||||
look-ups in hashes:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
// not yet found, keep searching in this table
|
||||
pos = (pos + 1) % set->alloc;
|
||||
|
||||
if (pos == start_pos) {
|
||||
// search got back to starting position, so index is not in table
|
||||
if (lookup_kind & MP_MAP_LOOKUP_ADD_IF_NOT_FOUND) {
|
||||
if (avail_slot != NULL) {
|
||||
// there was an available slot, so use that
|
||||
set->used++;
|
||||
*avail_slot = index;
|
||||
return index;
|
||||
} else {
|
||||
// not enough room in table, rehash it
|
||||
mp_set_rehash(set);
|
||||
// restart the search for the new element
|
||||
start_pos = pos = hash % set->alloc;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return MP_OBJ_NULL;
|
||||
}
|
||||
141
docs/develop/memorymgt.rst
Normal file
141
docs/develop/memorymgt.rst
Normal file
@ -0,0 +1,141 @@
|
||||
.. _memorymanagement:
|
||||
|
||||
Memory Management
|
||||
=================
|
||||
|
||||
Unlike programming languages such as C/C++, MicroPython hides memory management
|
||||
details from the developer by supporting automatic memory management.
|
||||
Automatic memory management is a technique used by operating systems or applications to automatically manage
|
||||
the allocation and deallocation of memory. This eliminates challenges such as forgetting to
|
||||
free the memory allocated to an object. Automatic memory management also avoids the critical issue of using memory
|
||||
that is already released. Automatic memory management takes many forms, one of them being
|
||||
garbage collection (GC).
|
||||
|
||||
The garbage collector usually has two responsibilities;
|
||||
|
||||
#. Allocate new objects in available memory.
|
||||
#. Free unused memory.
|
||||
|
||||
There are many GC algorithms but MicroPython uses the
|
||||
`Mark and Sweep <https://en.wikipedia.org/wiki/Tracing_garbage_collection#Basic_algorithm>`_
|
||||
policy for managing memory. This algorithm has a mark phase that traverses the heap marking all
|
||||
live objects while the sweep phase goes through the heap reclaiming all unmarked objects.
|
||||
|
||||
Garbage collection functionality in MicroPython is available through the ``gc`` built-in
|
||||
module:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
>>> x = 5
|
||||
>>> x
|
||||
5
|
||||
>>> import gc
|
||||
>>> gc.enable()
|
||||
>>> gc.mem_alloc()
|
||||
1312
|
||||
>>> gc.mem_free()
|
||||
2071392
|
||||
>>> gc.collect()
|
||||
19
|
||||
>>> gc.disable()
|
||||
>>>
|
||||
|
||||
Even when ``gc.disable()`` is invoked, collection can be triggered with ``gc.collect()``.
|
||||
|
||||
The object model
|
||||
----------------
|
||||
|
||||
All MicroPython objects are referred to by the ``mp_obj_t`` data type.
|
||||
This is usually word-sized (i.e. the same size as a pointer on the target architecture),
|
||||
and can be typically 32-bit (STM32, nRF, ESP32, Unix x86) or 64-bit (Unix x64).
|
||||
It can also be greater than a word-size for certain object representations, for
|
||||
example ``OBJ_REPR_D`` has a 64-bit sized ``mp_obj_t`` on a 32-bit architecture.
|
||||
|
||||
An ``mp_obj_t`` represents a MicroPython object, for example an integer, float, type, dict or
|
||||
class instance. Some objects, like booleans and small integers, have their value stored directly
|
||||
in the ``mp_obj_t`` value and do not require additional memory. Other objects have their value
|
||||
store elsewhere in memory (for example on the garbage-collected heap) and their ``mp_obj_t`` contains
|
||||
a pointer to that memory. A portion of ``mp_obj_t`` is the tag which tells what type of object it is.
|
||||
|
||||
See ``py/mpconfig.h`` for the specific details of the available representations.
|
||||
|
||||
**Pointer tagging**
|
||||
|
||||
Because pointers are word-aligned, when they are stored in an ``mp_obj_t`` the
|
||||
lower bits of this object handle will be zero. For example on a 32-bit architecture
|
||||
the lower 2 bits will be zero:
|
||||
|
||||
``********|********|********|******00``
|
||||
|
||||
These bits are reserved for purposes of storing a tag. The tag stores extra information as
|
||||
opposed to introducing a new field to store that information in the object, which may be
|
||||
inefficient. In MicroPython the tag tells if we are dealing with a small integer, interned
|
||||
(small) string or a concrete object, and different semantics apply to each of these.
|
||||
|
||||
For small integers the mapping is this:
|
||||
|
||||
``********|********|********|*******1``
|
||||
|
||||
Where the asterisks hold the actual integer value. For an interned string or an immediate
|
||||
object (e.g. ``True``) the layout of the ``mp_obj_t`` value is, respectively:
|
||||
|
||||
``********|********|********|*****010``
|
||||
|
||||
``********|********|********|*****110``
|
||||
|
||||
While a concrete object that is none of the above takes the form:
|
||||
|
||||
``********|********|********|******00``
|
||||
|
||||
The stars here correspond to the address of the concrete object in memory.
|
||||
|
||||
Allocation of objects
|
||||
----------------------
|
||||
|
||||
The value of a small integer is stored directly in the ``mp_obj_t`` and will be
|
||||
allocated in-place, not on the heap or elsewhere. As such, creation of small
|
||||
integers does not affect the heap. Similarly for interned strings that already have
|
||||
their textual data stored elsewhere, and immediate values like ``None``, ``False``
|
||||
and ``True``.
|
||||
|
||||
Everything else which is a concrete object is allocated on the heap and its object structure is such that
|
||||
a field is reserved in the object header to store the type of the object.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
+++++++++++
|
||||
+ +
|
||||
+ type + object header
|
||||
+ +
|
||||
+++++++++++
|
||||
+ + object items
|
||||
+ +
|
||||
+ +
|
||||
+++++++++++
|
||||
|
||||
The heap's smallest unit of allocation is a block, which is four machine words in
|
||||
size (16 bytes on a 32-bit machine, 32 bytes on a 64-bit machine).
|
||||
Another structure also allocated on the heap tracks the allocation of
|
||||
objects in each block. This structure is called a *bitmap*.
|
||||
|
||||
.. image:: img/bitmap.png
|
||||
|
||||
The bitmap tracks whether a block is "free" or "in use" and use two bits to track this state
|
||||
for each block.
|
||||
|
||||
The mark-sweep garbage collector manages the objects allocated on the heap, and also
|
||||
utilises the bitmap to mark objects that are still in use.
|
||||
See `py/gc.c <https://github.com/micropython/micropython/blob/master/py/gc.c>`_
|
||||
for the full implementation of these details.
|
||||
|
||||
**Allocation: heap layout**
|
||||
|
||||
The heap is arranged such that it consists of blocks in pools. A block
|
||||
can have different properties:
|
||||
|
||||
- *ATB(allocation table byte):* If set, then the block is a normal block
|
||||
- *FREE:* Free block
|
||||
- *HEAD:* Head of a chain of blocks
|
||||
- *TAIL:* In the tail of a chain of blocks
|
||||
- *MARK :* Marked head block
|
||||
- *FTB(finaliser table byte):* If set, then the block has a finaliser
|
||||
224
docs/develop/natmod.rst
Normal file
224
docs/develop/natmod.rst
Normal file
@ -0,0 +1,224 @@
|
||||
.. _natmod:
|
||||
|
||||
Native machine code in .mpy files
|
||||
=================================
|
||||
|
||||
This section describes how to build and work with .mpy files that contain native
|
||||
machine code from a language other than Python. This allows you to
|
||||
write code in a language like C, compile and link it into a .mpy file, and then
|
||||
import this file like a normal Python module. This can be used for implementing
|
||||
functionality which is performance critical, or for including an existing
|
||||
library written in another language.
|
||||
|
||||
One of the main advantages of using native .mpy files is that native machine code
|
||||
can be imported by a script dynamically, without the need to rebuild the main
|
||||
MicroPython firmware. This is in contrast to :ref:`cmodules` which also allows
|
||||
defining custom modules in C but they must be compiled into the main firmware image.
|
||||
|
||||
The focus here is on using C to build native modules, but in principle any
|
||||
language which can be compiled to stand-alone machine code can be put into a
|
||||
.mpy file.
|
||||
|
||||
A native .mpy module is built using the ``mpy_ld.py`` tool, which is found in the
|
||||
``tools/`` directory of the project. This tool takes a set of object files
|
||||
(.o files) and links them together to create a native .mpy files. It requires
|
||||
CPython 3 and the library pyelftools v0.25 or greater.
|
||||
|
||||
Supported features and limitations
|
||||
----------------------------------
|
||||
|
||||
A .mpy file can contain MicroPython bytecode and/or native machine code. If it
|
||||
contains native machine code then the .mpy file has a specific architecture
|
||||
associated with it. Current supported architectures are (these are the valid
|
||||
options for the ``ARCH`` variable, see below):
|
||||
|
||||
* ``x86`` (32 bit)
|
||||
* ``x64`` (64 bit x86)
|
||||
* ``armv7m`` (ARM Thumb 2, eg Cortex-M3)
|
||||
* ``armv7emsp`` (ARM Thumb 2, single precision float, eg Cortex-M4F, Cortex-M7)
|
||||
* ``armv7emdp`` (ARM Thumb 2, double precision float, eg Cortex-M7)
|
||||
* ``xtensa`` (non-windowed, eg ESP8266)
|
||||
* ``xtensawin`` (windowed with window size 8, eg ESP32)
|
||||
|
||||
When compiling and linking the native .mpy file the architecture must be chosen
|
||||
and the corresponding file can only be imported on that architecture. For more
|
||||
details about .mpy files see :ref:`mpy_files`.
|
||||
|
||||
Native code must be compiled as position independent code (PIC) and use a global
|
||||
offset table (GOT), although the details of this varies from architecture to
|
||||
architecture. When importing .mpy files with native code the import machinery
|
||||
is able to do some basic relocation of the native code. This includes
|
||||
relocating text, rodata and BSS sections.
|
||||
|
||||
Supported features of the linker and dynamic loader are:
|
||||
|
||||
* executable code (text)
|
||||
* read-only data (rodata), including strings and constant data (arrays, structs, etc)
|
||||
* zeroed data (BSS)
|
||||
* pointers in text to text, rodata and BSS
|
||||
* pointers in rodata to text, rodata and BSS
|
||||
|
||||
The known limitations are:
|
||||
|
||||
* data sections are not supported; workaround: use BSS data and initialise the
|
||||
data values explicitly
|
||||
|
||||
* static BSS variables are not supported; workaround: use global BSS variables
|
||||
|
||||
So, if your C code has writable data, make sure the data is defined globally,
|
||||
without an initialiser, and only written to within functions.
|
||||
|
||||
Linker limitation: the native module is not linked against the symbol table of the
|
||||
full MicroPython firmware. Rather, it is linked against an explicit table of exported
|
||||
symbols found in ``mp_fun_table`` (in ``py/nativeglue.h``), that is fixed at firmware
|
||||
build time. It is thus not possible to simply call some arbitrary HAL/OS/RTOS/system
|
||||
function, for example.
|
||||
|
||||
New symbols can be added to the end of the table and the firmware rebuilt.
|
||||
The symbols also need to be added to ``tools/mpy_ld.py``'s ``fun_table`` dict in the
|
||||
same location. This allows ``mpy_ld.py`` to be able to pick the new symbols up and
|
||||
provide relocations for them when the mpy is imported. Finally, if the symbol is a
|
||||
function, a macro or stub should be added to ``py/dynruntime.h`` to make it easy to
|
||||
call the function.
|
||||
|
||||
Defining a native module
|
||||
------------------------
|
||||
|
||||
A native .mpy module is defined by a set of files that are used to build the .mpy.
|
||||
The filesystem layout consists of two main parts, the source files and the Makefile:
|
||||
|
||||
* In the simplest case only a single C source file is required, which contains all
|
||||
the code that will be compiled into the .mpy module. This C source code must
|
||||
include the ``py/dynruntime.h`` file to access the MicroPython dynamic API, and
|
||||
must at least define a function called ``mpy_init``. This function will be the
|
||||
entry point of the module, called when the module is imported.
|
||||
|
||||
The module can be split into multiple C source files if desired. Parts of the
|
||||
module can also be implemented in Python. All source files should be listed in
|
||||
the Makefile, by adding them to the ``SRC`` variable (see below). This includes
|
||||
both C source files as well as any Python files which will be included in the
|
||||
resulting .mpy file.
|
||||
|
||||
* The ``Makefile`` contains the build configuration for the module and list the
|
||||
source files used to build the .mpy module. It should define ``MPY_DIR`` as the
|
||||
location of the MicroPython repository (to find header files, the relevant Makefile
|
||||
fragment, and the ``mpy_ld.py`` tool), ``MOD`` as the name of the module, ``SRC``
|
||||
as the list of source files, optionally specify the machine architecture via ``ARCH``,
|
||||
and then include ``py/dynruntime.mk``.
|
||||
|
||||
Minimal example
|
||||
---------------
|
||||
|
||||
This section provides a fully working example of a simple module named ``factorial``.
|
||||
This module provides a single function ``factorial.factorial(x)`` which computes the
|
||||
factorial of the input and returns the result.
|
||||
|
||||
Directory layout::
|
||||
|
||||
factorial/
|
||||
├── factorial.c
|
||||
└── Makefile
|
||||
|
||||
The file ``factorial.c`` contains:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
// Include the header file to get access to the MicroPython API
|
||||
#include "py/dynruntime.h"
|
||||
|
||||
// Helper function to compute factorial
|
||||
STATIC mp_int_t factorial_helper(mp_int_t x) {
|
||||
if (x == 0) {
|
||||
return 1;
|
||||
}
|
||||
return x * factorial_helper(x - 1);
|
||||
}
|
||||
|
||||
// This is the function which will be called from Python, as factorial(x)
|
||||
STATIC mp_obj_t factorial(mp_obj_t x_obj) {
|
||||
// Extract the integer from the MicroPython input object
|
||||
mp_int_t x = mp_obj_get_int(x_obj);
|
||||
// Calculate the factorial
|
||||
mp_int_t result = factorial_helper(x);
|
||||
// Convert the result to a MicroPython integer object and return it
|
||||
return mp_obj_new_int(result);
|
||||
}
|
||||
// Define a Python reference to the function above
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(factorial_obj, factorial);
|
||||
|
||||
// This is the entry point and is called when the module is imported
|
||||
mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) {
|
||||
// This must be first, it sets up the globals dict and other things
|
||||
MP_DYNRUNTIME_INIT_ENTRY
|
||||
|
||||
// Make the function available in the module's namespace
|
||||
mp_store_global(MP_QSTR_factorial, MP_OBJ_FROM_PTR(&factorial_obj));
|
||||
|
||||
// This must be last, it restores the globals dict
|
||||
MP_DYNRUNTIME_INIT_EXIT
|
||||
}
|
||||
|
||||
The file ``Makefile`` contains:
|
||||
|
||||
.. code-block:: make
|
||||
|
||||
# Location of top-level MicroPython directory
|
||||
MPY_DIR = ../../..
|
||||
|
||||
# Name of module
|
||||
MOD = factorial
|
||||
|
||||
# Source files (.c or .py)
|
||||
SRC = factorial.c
|
||||
|
||||
# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin)
|
||||
ARCH = x64
|
||||
|
||||
# Include to get the rules for compiling and linking the module
|
||||
include $(MPY_DIR)/py/dynruntime.mk
|
||||
|
||||
Compiling the module
|
||||
--------------------
|
||||
|
||||
The prerequisite tools needed to build a native .mpy file are:
|
||||
|
||||
* The MicroPython repository (at least the ``py/`` and ``tools/`` directories).
|
||||
* CPython 3, and the library pyelftools (eg ``pip install 'pyelftools>=0.25'``).
|
||||
* GNU make.
|
||||
* A C compiler for the target architecture (if C source is used).
|
||||
* Optionally ``mpy-cross``, built from the MicroPython repository (if .py source is used).
|
||||
|
||||
Be sure to select the correct ``ARCH`` for the target you are going to run on.
|
||||
Then build with::
|
||||
|
||||
$ make
|
||||
|
||||
Without modifying the Makefile you can specify the target architecture via::
|
||||
|
||||
$ make ARCH=armv7m
|
||||
|
||||
Module usage in MicroPython
|
||||
---------------------------
|
||||
|
||||
Once the module is built there should be a file called ``factorial.mpy``. Copy
|
||||
this so it is accessible on the filesystem of your MicroPython system and can be
|
||||
found in the import path. The module can now be accessed in Python just like any
|
||||
other module, for example::
|
||||
|
||||
import factorial
|
||||
print(factorial.factorial(10))
|
||||
# should display 3628800
|
||||
|
||||
Further examples
|
||||
----------------
|
||||
|
||||
See ``examples/natmod/`` for further examples which show many of the available
|
||||
features of native .mpy modules. Such features include:
|
||||
|
||||
* using multiple C source files
|
||||
* including Python code alongside C code
|
||||
* rodata and BSS data
|
||||
* memory allocation
|
||||
* use of floating point
|
||||
* exception handling
|
||||
* including external C libraries
|
||||
72
docs/develop/optimizations.rst
Normal file
72
docs/develop/optimizations.rst
Normal file
@ -0,0 +1,72 @@
|
||||
.. _optimizations:
|
||||
|
||||
Optimizations
|
||||
=============
|
||||
|
||||
MicroPython uses several optimizations to save RAM but also ensure the efficient
|
||||
execution of programs. This chapter discusses some of these optimizations.
|
||||
|
||||
.. note::
|
||||
:ref:`qstr` and :ref:`maps` details other optimizations on strings and
|
||||
dictionaries.
|
||||
|
||||
Frozen bytecode
|
||||
---------------
|
||||
|
||||
When MicroPython loads Python code from the filesystem, it first has to parse the file into
|
||||
a temporary in-memory representation, and then generate bytecode for execution, both of which
|
||||
are stored in the heap (in RAM). This can lead to significant amounts of memory being used.
|
||||
The MicroPython cross compiler can be used to generate
|
||||
a ``.mpy`` file, containing the pre-compiled bytecode for a Python module. This will still
|
||||
be loaded into RAM, but it avoids the additional overhead of the parsing stage.
|
||||
|
||||
As a further optimisation, the pre-compiled bytecode from a ``.mpy`` file can be "frozen"
|
||||
into the firmware image as part of the main firmware compilation process, which means that
|
||||
the bytecode will be executed from ROM. This can lead to a significant memory saving, and
|
||||
reduce heap fragmentation.
|
||||
|
||||
Variables
|
||||
---------
|
||||
|
||||
MicroPython processes local and global variables differently. Global variables
|
||||
are stored and looked up from a global dictionary that is allocated on the heap
|
||||
(note that each module has its own separate dict, so separate namespace).
|
||||
Local variables on the other hand are are stored on the Python value stack, which may
|
||||
live on the C stack or on the heap. They are accessed directly by their offset
|
||||
within the Python stack, which is more efficient than a global lookup in a dict.
|
||||
|
||||
The length of global variable names also affects how much RAM is used as identifiers
|
||||
are stored in RAM. The shorter the identifier, the less memory is used.
|
||||
|
||||
The other aspect is that ``const`` variables that start with an underscore are treated as
|
||||
proper constants and are not allocated or added in a dictionary, hence saving some memory.
|
||||
These variables use ``const()`` from the MicroPython library. Therefore:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from micropython import const
|
||||
|
||||
X = const(1)
|
||||
_Y = const(2)
|
||||
foo(X, _Y)
|
||||
|
||||
Compiles to:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
X = 1
|
||||
foo(1, 2)
|
||||
|
||||
Allocation of memory
|
||||
--------------------
|
||||
|
||||
Most of the common MicroPython constructs are not allocated on the heap.
|
||||
However the following are:
|
||||
|
||||
- Dynamic data structures like lists, mappings, etc;
|
||||
- Functions, classes and object instances;
|
||||
- imports; and
|
||||
- First-time assignment of global variables (to create the slot in the global dict).
|
||||
|
||||
For a detailed discussion on a more user-centric perspective on optimization,
|
||||
see `Maximising MicroPython speed <https://docs.micropython.org/en/latest/reference/speed_python.html>`_
|
||||
310
docs/develop/porting.rst
Normal file
310
docs/develop/porting.rst
Normal file
@ -0,0 +1,310 @@
|
||||
.. _porting_to_a_board:
|
||||
|
||||
Porting MicroPython
|
||||
===================
|
||||
|
||||
The MicroPython project contains several ports to different microcontroller families and
|
||||
architectures. The project repository has a `ports <https://github.com/micropython/micropython/tree/master/ports>`_
|
||||
directory containing a subdirectory for each supported port.
|
||||
|
||||
A port will typically contain definitions for multiple "boards", each of which is a specific piece of
|
||||
hardware that that port can run on, e.g. a development kit or device.
|
||||
|
||||
The `minimal port <https://github.com/micropython/micropython/tree/master/ports/minimal>`_ is
|
||||
available as a simplified reference implementation of a MicroPython port. It can run on both the
|
||||
host system and an STM32F4xx MCU.
|
||||
|
||||
In general, starting a port requires:
|
||||
|
||||
- Setting up the toolchain (configuring Makefiles, etc).
|
||||
- Implementing boot configuration and CPU initialization.
|
||||
- Initialising basic drivers required for development and debugging (e.g. GPIO, UART).
|
||||
- Performing the board-specific configurations.
|
||||
- Implementing the port-specific modules.
|
||||
|
||||
Minimal MicroPython firmware
|
||||
----------------------------
|
||||
|
||||
The best way to start porting MicroPython to a new board is by integrating a minimal
|
||||
MicroPython interpreter. For this walkthrough, create a subdirectory for the new
|
||||
port in the ``ports`` directory:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ cd ports
|
||||
$ mkdir example_port
|
||||
|
||||
The basic MicroPython firmware is implemented in the main port file, e.g ``main.c``:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#include "py/compile.h"
|
||||
#include "py/gc.h"
|
||||
#include "py/mperrno.h"
|
||||
#include "py/stackctrl.h"
|
||||
#include "lib/utils/gchelper.h"
|
||||
#include "lib/utils/pyexec.h"
|
||||
|
||||
// Allocate memory for the MicroPython GC heap.
|
||||
static char heap[4096];
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
// Initialise the MicroPython runtime.
|
||||
mp_stack_ctrl_init();
|
||||
gc_init(heap, heap + sizeof(heap));
|
||||
mp_init();
|
||||
mp_obj_list_init(MP_OBJ_TO_PTR(mp_sys_path), 0);
|
||||
mp_obj_list_init(MP_OBJ_TO_PTR(mp_sys_argv), 0);
|
||||
|
||||
// Start a normal REPL; will exit when ctrl-D is entered on a blank line.
|
||||
pyexec_friendly_repl();
|
||||
|
||||
// Deinitialise the runtime.
|
||||
gc_sweep_all();
|
||||
mp_deinit();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Handle uncaught exceptions (should never be reached in a correct C implementation).
|
||||
void nlr_jump_fail(void *val) {
|
||||
for (;;) {
|
||||
}
|
||||
}
|
||||
|
||||
// Do a garbage collection cycle.
|
||||
void gc_collect(void) {
|
||||
gc_collect_start();
|
||||
gc_helper_collect_regs_and_stack();
|
||||
gc_collect_end();
|
||||
}
|
||||
|
||||
// There is no filesystem so stat'ing returns nothing.
|
||||
mp_import_stat_t mp_import_stat(const char *path) {
|
||||
return MP_IMPORT_STAT_NO_EXIST;
|
||||
}
|
||||
|
||||
// There is no filesystem so opening a file raises an exception.
|
||||
mp_lexer_t *mp_lexer_new_from_file(const char *filename) {
|
||||
mp_raise_OSError(MP_ENOENT);
|
||||
}
|
||||
|
||||
We also need a Makefile at this point for the port:
|
||||
|
||||
.. code-block:: Makefile
|
||||
|
||||
# Include the core environment definitions; this will set $(TOP).
|
||||
include ../../py/mkenv.mk
|
||||
|
||||
# Include py core make definitions.
|
||||
include $(TOP)/py/py.mk
|
||||
|
||||
# Set CFLAGS and libraries.
|
||||
CFLAGS = -I. -I$(BUILD) -I$(TOP)
|
||||
LIBS = -lm
|
||||
|
||||
# Define the required source files.
|
||||
SRC_C = \
|
||||
main.c \
|
||||
mphalport.c \
|
||||
lib/mp-readline/readline.c \
|
||||
lib/utils/gchelper_generic.c \
|
||||
lib/utils/pyexec.c \
|
||||
lib/utils/stdout_helpers.c \
|
||||
|
||||
# Define the required object files.
|
||||
OBJ = $(PY_CORE_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o))
|
||||
|
||||
# Define the top-level target, the main firmware.
|
||||
all: $(BUILD)/firmware.elf
|
||||
|
||||
# Define how to build the firmware.
|
||||
$(BUILD)/firmware.elf: $(OBJ)
|
||||
$(ECHO) "LINK $@"
|
||||
$(Q)$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||
$(Q)$(SIZE) $@
|
||||
|
||||
# Include remaining core make rules.
|
||||
include $(TOP)/py/mkrules.mk
|
||||
|
||||
Remember to use proper tabs to indent the Makefile.
|
||||
|
||||
MicroPython Configurations
|
||||
--------------------------
|
||||
|
||||
After integrating the minimal code above, the next step is to create the MicroPython
|
||||
configuration files for the port. The compile-time configurations are specified in
|
||||
``mpconfigport.h`` and additional hardware-abstraction functions, such as time keeping,
|
||||
in ``mphalport.h``.
|
||||
|
||||
The following is an example of an ``mpconfigport.h`` file:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// Python internal features.
|
||||
#define MICROPY_ENABLE_GC (1)
|
||||
#define MICROPY_HELPER_REPL (1)
|
||||
#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_TERSE)
|
||||
#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT)
|
||||
|
||||
// Fine control over Python builtins, classes, modules, etc.
|
||||
#define MICROPY_PY_ASYNC_AWAIT (0)
|
||||
#define MICROPY_PY_BUILTINS_SET (0)
|
||||
#define MICROPY_PY_ATTRTUPLE (0)
|
||||
#define MICROPY_PY_COLLECTIONS (0)
|
||||
#define MICROPY_PY_MATH (0)
|
||||
#define MICROPY_PY_IO (0)
|
||||
#define MICROPY_PY_STRUCT (0)
|
||||
|
||||
// Type definitions for the specific machine.
|
||||
|
||||
typedef intptr_t mp_int_t; // must be pointer size
|
||||
typedef uintptr_t mp_uint_t; // must be pointer size
|
||||
typedef long mp_off_t;
|
||||
|
||||
// We need to provide a declaration/definition of alloca().
|
||||
#include <alloca.h>
|
||||
|
||||
// Define the port's name and hardware.
|
||||
#define MICROPY_HW_BOARD_NAME "example-board"
|
||||
#define MICROPY_HW_MCU_NAME "unknown-cpu"
|
||||
|
||||
#define MP_STATE_PORT MP_STATE_VM
|
||||
|
||||
#define MICROPY_PORT_ROOT_POINTERS \
|
||||
const char *readline_hist[8];
|
||||
|
||||
This configuration file contains machine-specific configurations including aspects like if different
|
||||
MicroPython features should be enabled e.g. ``#define MICROPY_ENABLE_GC (1)``. Making this Setting
|
||||
``(0)`` disables the feature.
|
||||
|
||||
Other configurations include type definitions, root pointers, board name, microcontroller name
|
||||
etc.
|
||||
|
||||
Similarly, an minimal example ``mphalport.h`` file looks like this:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
static inline void mp_hal_set_interrupt_char(char c) {}
|
||||
|
||||
Support for standard input/output
|
||||
---------------------------------
|
||||
|
||||
MicroPython requires at least a way to output characters, and to have a REPL it also
|
||||
requires a way to input characters. Functions for this can be implemented in the file
|
||||
``mphalport.c``, for example:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#include <unistd.h>
|
||||
#include "py/mpconfig.h"
|
||||
|
||||
// Receive single character, blocking until one is available.
|
||||
int mp_hal_stdin_rx_chr(void) {
|
||||
unsigned char c = 0;
|
||||
int r = read(STDIN_FILENO, &c, 1);
|
||||
(void)r;
|
||||
return c;
|
||||
}
|
||||
|
||||
// Send the string of given length.
|
||||
void mp_hal_stdout_tx_strn(const char *str, mp_uint_t len) {
|
||||
int r = write(STDOUT_FILENO, str, len);
|
||||
(void)r;
|
||||
}
|
||||
|
||||
These input and output functions have to be modified depending on the
|
||||
specific board API. This example uses the standard input/output stream.
|
||||
|
||||
Building and running
|
||||
--------------------
|
||||
|
||||
At this stage the directory of the new port should contain::
|
||||
|
||||
ports/example_port/
|
||||
├── main.c
|
||||
├── Makefile
|
||||
├── mpconfigport.h
|
||||
├── mphalport.c
|
||||
└── mphalport.h
|
||||
|
||||
The port can now be built by running ``make`` (or otherwise, depending on your system).
|
||||
|
||||
If you are using the default compiler settings in the Makefile given above then this
|
||||
will create an executable called ``build/firmware.elf`` which can be executed directly.
|
||||
To get a functional REPL you may need to first configure the terminal to raw mode:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ stty raw opost -echo
|
||||
$ ./build/firmware.elf
|
||||
|
||||
That should give a MicroPython REPL. You can then run commands like:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
MicroPython v1.13 on 2021-01-01; example-board with unknown-cpu
|
||||
>>> import usys
|
||||
>>> usys.implementation
|
||||
('micropython', (1, 13, 0))
|
||||
>>>
|
||||
|
||||
Use Ctrl-D to exit, and then run ``reset`` to reset the terminal.
|
||||
|
||||
Adding a module to the port
|
||||
---------------------------
|
||||
|
||||
To add a custom module like ``myport``, first add the module definition in a file
|
||||
``modmyport.c``:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#include "py/runtime.h"
|
||||
|
||||
STATIC mp_obj_t myport_info(void) {
|
||||
mp_printf(&mp_plat_print, "info about my port\n");
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(myport_info_obj, myport_info);
|
||||
|
||||
STATIC const mp_rom_map_elem_t myport_module_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_myport) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_info), MP_ROM_PTR(&myport_info_obj) },
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(myport_module_globals, myport_module_globals_table);
|
||||
|
||||
const mp_obj_module_t myport_module = {
|
||||
.base = { &mp_type_module },
|
||||
.globals = (mp_obj_dict_t *)&myport_module_globals,
|
||||
};
|
||||
|
||||
MP_REGISTER_MODULE(MP_QSTR_myport, myport_module, 1);
|
||||
|
||||
Note: the "1" as the third argument in ``MP_REGISTER_MODULE`` enables this new module
|
||||
unconditionally. To allow it to be conditionally enabled, replace the "1" by
|
||||
``MICROPY_PY_MYPORT`` and then add ``#define MICROPY_PY_MYPORT (1)`` in ``mpconfigport.h``
|
||||
accordingly.
|
||||
|
||||
You will also need to edit the Makefile to add ``modmyport.c`` to the ``SRC_C`` list, and
|
||||
a new line adding the same file to ``SRC_QSTR`` (so qstrs are searched for in this new file),
|
||||
like this:
|
||||
|
||||
.. code-block:: Makefile
|
||||
|
||||
SRC_C = \
|
||||
main.c \
|
||||
modmyport.c \
|
||||
mphalport.c \
|
||||
...
|
||||
|
||||
SRC_QSTR += modport.c
|
||||
|
||||
If all went correctly then, after rebuilding, you should be able to import the new module:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
>>> import myport
|
||||
>>> myport.info()
|
||||
info about my port
|
||||
>>>
|
||||
25
docs/develop/publiccapi.rst
Normal file
25
docs/develop/publiccapi.rst
Normal file
@ -0,0 +1,25 @@
|
||||
.. _publiccapi:
|
||||
|
||||
The public C API
|
||||
================
|
||||
|
||||
The public C-API comprises functions defined in all C header files in the ``py/``
|
||||
directory. Most of the important core runtime C APIs are exposed in ``runtime.h`` and
|
||||
``obj.h``.
|
||||
|
||||
The following is an example of public API functions from ``obj.h``:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
mp_obj_t mp_obj_new_list(size_t n, mp_obj_t *items);
|
||||
mp_obj_t mp_obj_list_append(mp_obj_t self_in, mp_obj_t arg);
|
||||
mp_obj_t mp_obj_list_remove(mp_obj_t self_in, mp_obj_t value);
|
||||
void mp_obj_list_get(mp_obj_t self_in, size_t *len, mp_obj_t **items);
|
||||
|
||||
At its core, any functions and macros in header files make up the public
|
||||
API and can be used to access very low-level details of MicroPython. Static
|
||||
inline functions in header files are fine too, such functions will be
|
||||
inlined in the code when used.
|
||||
|
||||
Header files in the ``ports`` directory are only exposed to the functionality
|
||||
specific to a given port.
|
||||
115
docs/develop/qstr.rst
Normal file
115
docs/develop/qstr.rst
Normal file
@ -0,0 +1,115 @@
|
||||
.. _qstr:
|
||||
|
||||
MicroPython string interning
|
||||
============================
|
||||
|
||||
MicroPython uses `string interning`_ to save both RAM and ROM. This avoids
|
||||
having to store duplicate copies of the same string. Primarily, this applies to
|
||||
identifiers in your code, as something like a function or variable name is very
|
||||
likely to appear in multiple places in the code. In MicroPython an interned
|
||||
string is called a QSTR (uniQue STRing).
|
||||
|
||||
A QSTR value (with type ``qstr``) is a index into a linked list of QSTR pools.
|
||||
QSTRs store their length and a hash of their contents for fast comparison during
|
||||
the de-duplication process. All bytecode operations that work with strings use
|
||||
a QSTR argument.
|
||||
|
||||
Compile-time QSTR generation
|
||||
----------------------------
|
||||
|
||||
In the MicroPython C code, any strings that should be interned in the final
|
||||
firmware are written as ``MP_QSTR_Foo``. At compile time this will evaluate to
|
||||
a ``qstr`` value that points to the index of ``"Foo"`` in the QSTR pool.
|
||||
|
||||
A multi-step process in the ``Makefile`` makes this work. In summary this
|
||||
process has three parts:
|
||||
|
||||
1. Find all ``MP_QSTR_Foo`` tokens in the code.
|
||||
|
||||
2. Generate a static QSTR pool containing all the string data (including lengths
|
||||
and hashes).
|
||||
|
||||
3. Replace all ``MP_QSTR_Foo`` (via the preprocessor) with their corresponding
|
||||
index.
|
||||
|
||||
``MP_QSTR_Foo`` tokens are searched for in two sources:
|
||||
|
||||
1. All files referenced in ``$(SRC_QSTR)``. This is all C code (i.e. ``py``,
|
||||
``extmod``, ``ports/stm32``) but not including third-party code such as
|
||||
``lib``.
|
||||
|
||||
2. Additional ``$(QSTR_GLOBAL_DEPENDENCIES)`` (which includes ``mpconfig*.h``).
|
||||
|
||||
*Note:* ``frozen_mpy.c`` (generated by mpy-tool.py) has its own QSTR generation
|
||||
and pool.
|
||||
|
||||
Some additional strings that can't be expressed using the ``MP_QSTR_Foo`` syntax
|
||||
(e.g. they contain non-alphanumeric characters) are explicitly provided in
|
||||
``qstrdefs.h`` and ``qstrdefsport.h`` via the ``$(QSTR_DEFS)`` variable.
|
||||
|
||||
Processing happens in the following stages:
|
||||
|
||||
1. ``qstr.i.last`` is the concatenation of putting every single input file
|
||||
through the C pre-processor. This means that any conditionally disabled code
|
||||
will be removed, and macros expanded. This means we don't add strings to the
|
||||
pool that won't be used in the final firmware. Because at this stage (thanks
|
||||
to the ``NO_QSTR`` macro added by ``QSTR_GEN_CFLAGS``) there is no
|
||||
definition for ``MP_QSTR_Foo`` it passes through this stage unaffected. This
|
||||
file also includes comments from the preprocessor that include line number
|
||||
information. Note that this step only uses files that have changed, which
|
||||
means that ``qstr.i.last`` will only contain data from files that have
|
||||
changed since the last compile.
|
||||
|
||||
2. ``qstr.split`` is an empty file created after running ``makeqstrdefs.py split``
|
||||
on qstr.i.last. It's just used as a dependency to indicate that the step ran.
|
||||
This script outputs one file per input C file, ``genhdr/qstr/...file.c.qstr``,
|
||||
which contains only the matched QSTRs. Each QSTR is printed as ``Q(Foo)``.
|
||||
This step is necessary to combine the existing files with the new data
|
||||
generated from the incremental update in ``qstr.i.last``.
|
||||
|
||||
3. ``qstrdefs.collected.h`` is the output of concatenating ``genhdr/qstr/*``
|
||||
using ``makeqstrdefs.py cat``. This is now the full set of ``MP_QSTR_Foo``'s
|
||||
found in the code, now formatted as ``Q(Foo)``, one-per-line, with duplicates.
|
||||
This file is only updated if the set of qstrs has changed. A hash of the QSTR
|
||||
data is written to another file (``qstrdefs.collected.h.hash``) which allows
|
||||
it to track changes across builds.
|
||||
|
||||
4. Generate an enumeration, each entry of which maps a ``MP_QSTR_Foo`` to it's corresponding index.
|
||||
It concatenates ``qstrdefs.collected.h`` with ``qstrdefs*.h``, then it transforms
|
||||
each line from ``Q(Foo)`` to ``"Q(Foo)"`` so they pass through the preprocessor
|
||||
unchanged. Then the preprocessor is used to deal with any conditional
|
||||
compilation in ``qstrdefs*.h``. Then the transformation is undone back to
|
||||
``Q(Foo)``, and saved as ``qstrdefs.preprocessed.h``.
|
||||
|
||||
5. ``qstrdefs.generated.h`` is the output of ``makeqstrdata.py``. For each
|
||||
``Q(Foo)`` in qstrdefs.preprocessed.h (plus some extra hard-coded ones), it outputs
|
||||
``QDEF(MP_QSTR_Foo, (const byte*)"hash" "Foo")``.
|
||||
|
||||
Then in the main compile, two things happen with ``qstrdefs.generated.h``:
|
||||
|
||||
1. In qstr.h, each QDEF becomes an entry in an enum, which makes ``MP_QSTR_Foo``
|
||||
available to code and equal to the index of that string in the QSTR table.
|
||||
|
||||
2. In qstr.c, the actual QSTR data table is generated as elements of the
|
||||
``mp_qstr_const_pool->qstrs``.
|
||||
|
||||
.. _`string interning`: https://en.wikipedia.org/wiki/String_interning
|
||||
|
||||
Run-time QSTR generation
|
||||
------------------------
|
||||
|
||||
Additional QSTR pools can be created at runtime so that strings can be added to
|
||||
them. For example, the code::
|
||||
|
||||
foo[x] = 3
|
||||
|
||||
Will need to create a QSTR for the value of ``x`` so it can be used by the
|
||||
"load attr" bytecode.
|
||||
|
||||
Also, when compiling Python code, identifiers and literals need to have QSTRs
|
||||
created. Note: only literals shorter than 10 characters become QSTRs. This is
|
||||
because a regular string on the heap always takes up a minimum of 16 bytes (one
|
||||
GC block), whereas QSTRs allow them to be packed more efficiently into the pool.
|
||||
|
||||
QSTR pools (and the underlying "chunks" that store the string data) are allocated
|
||||
on-demand on the heap with a minimum size.
|
||||
70
docs/develop/writingtests.rst
Normal file
70
docs/develop/writingtests.rst
Normal file
@ -0,0 +1,70 @@
|
||||
.. _writingtests:
|
||||
|
||||
Writing tests
|
||||
=============
|
||||
|
||||
Tests in MicroPython are located at the path ``tests/``. The following is a listing of
|
||||
key directories and the run-tests runner script:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
.
|
||||
├── basics
|
||||
├── extmod
|
||||
├── float
|
||||
├── micropython
|
||||
├── run-tests
|
||||
...
|
||||
|
||||
There are subfolders maintained to categorize the tests. Add a test by creating a new file in one of the
|
||||
existing folders or in a new folder. It's also possible to make custom tests outside this tests folder,
|
||||
which would be recommended for a custom port.
|
||||
|
||||
For example, add the following code in a file ``print.py`` in the ``tests/unix/`` subdirectory:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def print_one():
|
||||
print(1)
|
||||
|
||||
print_one()
|
||||
|
||||
If you run your tests, this test should appear in the test output:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ cd ports/unix
|
||||
$ make tests
|
||||
skip unix/extra_coverage.py
|
||||
pass unix/ffi_callback.py
|
||||
pass unix/ffi_float.py
|
||||
pass unix/ffi_float2.py
|
||||
pass unix/print.py
|
||||
pass unix/time.py
|
||||
pass unix/time2.py
|
||||
|
||||
Tests are run by comparing the output from the test target against the output from CPython.
|
||||
So any test should use print statements to indicate test results.
|
||||
|
||||
For tests that can't be compared to CPython (i.e. micropython-specific functionality),
|
||||
you can provide a ``.py.exp`` file which will be used as the truth for comparison.
|
||||
|
||||
The other way to run tests, which is useful when running on targets other than the Unix port, is:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ cd tests
|
||||
$ ./run-tests
|
||||
|
||||
Then to run on a board:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ ./run-tests --target minimal --device /dev/ttyACM0
|
||||
|
||||
And to run only a certain set of tests (eg a directory):
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ ./run-tests -d basics
|
||||
$ ./run-tests float/builtin*.py
|
||||
@ -4,6 +4,7 @@ MicroPython differences from CPython
|
||||
====================================
|
||||
|
||||
The operations listed in this section produce conflicting results in MicroPython when compared to standard Python.
|
||||
MicroPython implements Python 3.4 and some select features of Python 3.5.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
64
docs/esp32/general.rst
Normal file
64
docs/esp32/general.rst
Normal file
@ -0,0 +1,64 @@
|
||||
.. _esp32_general:
|
||||
|
||||
General information about the ESP32 port
|
||||
========================================
|
||||
|
||||
The ESP32 is a popular WiFi and Bluetooth enabled System-on-Chip (SoC) by
|
||||
Espressif Systems.
|
||||
|
||||
Multitude of boards
|
||||
-------------------
|
||||
|
||||
There is a multitude of modules and boards from different sources which carry
|
||||
the ESP32 chip. MicroPython tries to provide a generic port which would run on
|
||||
as many boards/modules as possible, but there may be limitations. Espressif
|
||||
development boards are taken as reference for the port (for example, testing is
|
||||
performed on them). For any board you are using please make sure you have a
|
||||
datasheet, schematics and other reference materials so you can look up any
|
||||
board-specific functions.
|
||||
|
||||
To make a generic ESP32 port and support as many boards as possible the
|
||||
following design and implementation decision were made:
|
||||
|
||||
* GPIO pin numbering is based on ESP32 chip numbering. Please have the manual/pin
|
||||
diagram of your board at hand to find correspondence between your board pins and
|
||||
actual ESP32 pins.
|
||||
* All pins are supported by MicroPython but not all are usable on any given board.
|
||||
For example pins that are connected to external SPI flash should not be used,
|
||||
and a board may only expose a certain selection of pins.
|
||||
|
||||
|
||||
Technical specifications and SoC datasheets
|
||||
-------------------------------------------
|
||||
|
||||
The datasheets and other reference material for ESP32 chip are available
|
||||
from the vendor site: https://www.espressif.com/en/support/download/documents?keys=esp32 .
|
||||
They are the primary reference for the chip technical specifications, capabilities,
|
||||
operating modes, internal functioning, etc.
|
||||
|
||||
For your convenience, some of technical specifications are provided below:
|
||||
|
||||
* Architecture: Xtensa Dual-Core 32-bit LX6
|
||||
* CPU frequency: up to 240MHz
|
||||
* Total RAM available: 528KB (part of it reserved for system)
|
||||
* BootROM: 448KB
|
||||
* Internal FlashROM: none
|
||||
* External FlashROM: code and data, via SPI Flash; usual size 4MB
|
||||
* GPIO: 34 (GPIOs are multiplexed with other functions, including
|
||||
external FlashROM, UART, etc.)
|
||||
* UART: 3 RX/TX UART (no hardware handshaking), one TX-only UART
|
||||
* SPI: 4 SPI interfaces (one used for FlashROM)
|
||||
* I2C: 2 I2C (bitbang implementation available on any pins)
|
||||
* I2S: 2
|
||||
* ADC: 12-bit SAR ADC up to 18 channels
|
||||
* DAC: 2 8-bit DACs
|
||||
* RMT: 8 channels allowing accurate pulse transmit/receive
|
||||
* Programming: using BootROM bootloader from UART - due to external FlashROM
|
||||
and always-available BootROM bootloader, the ESP32 is not brickable
|
||||
|
||||
For more information see the ESP32 datasheet: https://www.espressif.com/sites/default/files/documentation/esp32_datasheet_en.pdf
|
||||
|
||||
MicroPython is implemented on top of the ESP-IDF, Espressif's development
|
||||
framework for the ESP32. This is a FreeRTOS based system. See the
|
||||
`ESP-IDF Programming Guide <https://docs.espressif.com/projects/esp-idf/en/latest/index.html>`_
|
||||
for details.
|
||||
BIN
docs/esp32/img/esp32.jpg
Normal file
BIN
docs/esp32/img/esp32.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 84 KiB |
539
docs/esp32/quickref.rst
Normal file
539
docs/esp32/quickref.rst
Normal file
@ -0,0 +1,539 @@
|
||||
.. _esp32_quickref:
|
||||
|
||||
Quick reference for the ESP32
|
||||
=============================
|
||||
|
||||
.. image:: img/esp32.jpg
|
||||
:alt: ESP32 board
|
||||
:width: 640px
|
||||
|
||||
The Espressif ESP32 Development Board (image attribution: Adafruit).
|
||||
|
||||
Below is a quick reference for ESP32-based boards. If it is your first time
|
||||
working with this board it may be useful to get an overview of the microcontroller:
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
general.rst
|
||||
tutorial/intro.rst
|
||||
|
||||
Installing MicroPython
|
||||
----------------------
|
||||
|
||||
See the corresponding section of tutorial: :ref:`esp32_intro`. It also includes
|
||||
a troubleshooting subsection.
|
||||
|
||||
General board control
|
||||
---------------------
|
||||
|
||||
The MicroPython REPL is on UART0 (GPIO1=TX, GPIO3=RX) at baudrate 115200.
|
||||
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 :mod:`machine` module::
|
||||
|
||||
import machine
|
||||
|
||||
machine.freq() # get the current frequency of the CPU
|
||||
machine.freq(240000000) # set the CPU frequency to 240 MHz
|
||||
|
||||
The :mod:`esp` module::
|
||||
|
||||
import esp
|
||||
|
||||
esp.osdebug(None) # turn off vendor O/S debugging messages
|
||||
esp.osdebug(0) # redirect vendor O/S debugging messages to UART(0)
|
||||
|
||||
# low level methods to interact with flash storage
|
||||
esp.flash_size()
|
||||
esp.flash_user_start()
|
||||
esp.flash_erase(sector_no)
|
||||
esp.flash_write(byte_offset, buffer)
|
||||
esp.flash_read(byte_offset, buffer)
|
||||
|
||||
The :mod:`esp32` module::
|
||||
|
||||
import esp32
|
||||
|
||||
esp32.hall_sensor() # read the internal hall sensor
|
||||
esp32.raw_temperature() # read the internal temperature of the MCU, in Farenheit
|
||||
esp32.ULP() # access to the Ultra-Low-Power Co-processor
|
||||
|
||||
Note that the temperature sensor in the ESP32 will typically read higher than
|
||||
ambient due to the IC getting warm while it runs. This effect can be minimised
|
||||
by reading the temperature sensor immediately after waking up from sleep.
|
||||
|
||||
Networking
|
||||
----------
|
||||
|
||||
The :mod:`network` module::
|
||||
|
||||
import network
|
||||
|
||||
wlan = network.WLAN(network.STA_IF) # create station interface
|
||||
wlan.active(True) # activate the interface
|
||||
wlan.scan() # scan for access points
|
||||
wlan.isconnected() # check if the station is connected to an AP
|
||||
wlan.connect('essid', 'password') # connect to an AP
|
||||
wlan.config('mac') # get the interface's MAC address
|
||||
wlan.ifconfig() # get the interface's IP/netmask/gw/DNS addresses
|
||||
|
||||
ap = network.WLAN(network.AP_IF) # create access-point interface
|
||||
ap.config(essid='ESP-AP') # set the ESSID of the access point
|
||||
ap.config(max_clients=10) # set how many clients can connect to the network
|
||||
ap.active(True) # activate the interface
|
||||
|
||||
A useful function for connecting to your local WiFi network is::
|
||||
|
||||
def do_connect():
|
||||
import network
|
||||
wlan = network.WLAN(network.STA_IF)
|
||||
wlan.active(True)
|
||||
if not wlan.isconnected():
|
||||
print('connecting to network...')
|
||||
wlan.connect('essid', 'password')
|
||||
while not wlan.isconnected():
|
||||
pass
|
||||
print('network config:', wlan.ifconfig())
|
||||
|
||||
Once the network is established the :mod:`socket <usocket>` module can be used
|
||||
to create and use TCP/UDP sockets as usual, and the ``urequests`` module for
|
||||
convenient HTTP requests.
|
||||
|
||||
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 millisecond counter
|
||||
delta = time.ticks_diff(time.ticks_ms(), start) # compute time difference
|
||||
|
||||
Timers
|
||||
------
|
||||
|
||||
The ESP32 port has four hardware timers. Use the :ref:`machine.Timer <machine.Timer>` class
|
||||
with a timer ID from 0 to 3 (inclusive)::
|
||||
|
||||
from machine import Timer
|
||||
|
||||
tim0 = Timer(0)
|
||||
tim0.init(period=5000, mode=Timer.ONE_SHOT, callback=lambda t:print(0))
|
||||
|
||||
tim1 = Timer(1)
|
||||
tim1.init(period=2000, mode=Timer.PERIODIC, callback=lambda t:print(1))
|
||||
|
||||
The period is in milliseconds.
|
||||
|
||||
Virtual timers are not currently supported on this port.
|
||||
|
||||
.. _Pins_and_GPIO:
|
||||
|
||||
Pins and GPIO
|
||||
-------------
|
||||
|
||||
Use the :ref:`machine.Pin <machine.Pin>` class::
|
||||
|
||||
from machine import Pin
|
||||
|
||||
p0 = Pin(0, Pin.OUT) # create output pin on GPIO0
|
||||
p0.on() # set pin to "on" (high) level
|
||||
p0.off() # set pin to "off" (low) level
|
||||
p0.value(1) # set pin to on/high
|
||||
|
||||
p2 = Pin(2, Pin.IN) # create input pin on GPIO2
|
||||
print(p2.value()) # get value, 0 or 1
|
||||
|
||||
p4 = Pin(4, Pin.IN, Pin.PULL_UP) # enable internal pull-up resistor
|
||||
p5 = Pin(5, Pin.OUT, value=1) # set pin high on creation
|
||||
|
||||
Available Pins are from the following ranges (inclusive): 0-19, 21-23, 25-27, 32-39.
|
||||
These correspond to the actual GPIO pin numbers of ESP32 chip. Note that many
|
||||
end-user boards use their own adhoc pin numbering (marked e.g. D0, D1, ...).
|
||||
For mapping between board logical pins and physical chip pins consult your board
|
||||
documentation.
|
||||
|
||||
Notes:
|
||||
|
||||
* Pins 1 and 3 are REPL UART TX and RX respectively
|
||||
|
||||
* Pins 6, 7, 8, 11, 16, and 17 are used for connecting the embedded flash,
|
||||
and are not recommended for other uses
|
||||
|
||||
* Pins 34-39 are input only, and also do not have internal pull-up resistors
|
||||
|
||||
* The pull value of some pins can be set to ``Pin.PULL_HOLD`` to reduce power
|
||||
consumption during deepsleep.
|
||||
|
||||
PWM (pulse width modulation)
|
||||
----------------------------
|
||||
|
||||
PWM can be enabled on all output-enabled pins. The base frequency can
|
||||
range from 1Hz to 40MHz but there is a tradeoff; as the base frequency
|
||||
*increases* the duty resolution *decreases*. See
|
||||
`LED Control <https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/peripherals/ledc.html>`_
|
||||
for more details.
|
||||
Currently the duty cycle has to be in the range of 0-1023.
|
||||
|
||||
Use the ``machine.PWM`` class::
|
||||
|
||||
from machine import Pin, PWM
|
||||
|
||||
pwm0 = PWM(Pin(0)) # create PWM object from a pin
|
||||
pwm0.freq() # get current frequency
|
||||
pwm0.freq(1000) # set frequency
|
||||
pwm0.duty() # get current duty cycle
|
||||
pwm0.duty(200) # set duty cycle
|
||||
pwm0.deinit() # turn off PWM on the pin
|
||||
|
||||
pwm2 = PWM(Pin(2), freq=20000, duty=512) # create and configure in one go
|
||||
|
||||
ADC (analog to digital conversion)
|
||||
----------------------------------
|
||||
|
||||
On the ESP32 ADC functionality is available on Pins 32-39. Note that, when
|
||||
using the default configuration, input voltages on the ADC pin must be between
|
||||
0.0v and 1.0v (anything above 1.0v will just read as 4095). Attenuation must
|
||||
be applied in order to increase this usable voltage range.
|
||||
|
||||
Use the :ref:`machine.ADC <machine.ADC>` class::
|
||||
|
||||
from machine import ADC
|
||||
|
||||
adc = ADC(Pin(32)) # create ADC object on ADC pin
|
||||
adc.read() # read value, 0-4095 across voltage range 0.0v - 1.0v
|
||||
|
||||
adc.atten(ADC.ATTN_11DB) # set 11dB input attenuation (voltage range roughly 0.0v - 3.6v)
|
||||
adc.width(ADC.WIDTH_9BIT) # set 9 bit return values (returned range 0-511)
|
||||
adc.read() # read value using the newly configured attenuation and width
|
||||
|
||||
ESP32 specific ADC class method reference:
|
||||
|
||||
.. method:: ADC.atten(attenuation)
|
||||
|
||||
This method allows for the setting of the amount of attenuation on the
|
||||
input of the ADC. This allows for a wider possible input voltage range,
|
||||
at the cost of accuracy (the same number of bits now represents a wider
|
||||
range). The possible attenuation options are:
|
||||
|
||||
- ``ADC.ATTN_0DB``: 0dB attenuation, gives a maximum input voltage
|
||||
of 1.00v - this is the default configuration
|
||||
- ``ADC.ATTN_2_5DB``: 2.5dB attenuation, gives a maximum input voltage
|
||||
of approximately 1.34v
|
||||
- ``ADC.ATTN_6DB``: 6dB attenuation, gives a maximum input voltage
|
||||
of approximately 2.00v
|
||||
- ``ADC.ATTN_11DB``: 11dB attenuation, gives a maximum input voltage
|
||||
of approximately 3.6v
|
||||
|
||||
.. Warning::
|
||||
Despite 11dB attenuation allowing for up to a 3.6v range, note that the
|
||||
absolute maximum voltage rating for the input pins is 3.6v, and so going
|
||||
near this boundary may be damaging to the IC!
|
||||
|
||||
.. method:: ADC.width(width)
|
||||
|
||||
This method allows for the setting of the number of bits to be utilised
|
||||
and returned during ADC reads. Possible width options are:
|
||||
|
||||
- ``ADC.WIDTH_9BIT``: 9 bit data
|
||||
- ``ADC.WIDTH_10BIT``: 10 bit data
|
||||
- ``ADC.WIDTH_11BIT``: 11 bit data
|
||||
- ``ADC.WIDTH_12BIT``: 12 bit data - this is the default configuration
|
||||
|
||||
Software SPI bus
|
||||
----------------
|
||||
|
||||
Software SPI (using bit-banging) works on all pins, and is accessed via the
|
||||
:ref:`machine.SoftSPI <machine.SoftSPI>` class::
|
||||
|
||||
from machine import Pin, SoftSPI
|
||||
|
||||
# construct a SoftSPI 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 = SoftSPI(baudrate=100000, polarity=1, phase=0, sck=Pin(0), mosi=Pin(2), miso=Pin(4))
|
||||
|
||||
spi.init(baudrate=200000) # set the baudrate
|
||||
|
||||
spi.read(10) # read 10 bytes on MISO
|
||||
spi.read(10, 0xff) # read 10 bytes while outputting 0xff on MOSI
|
||||
|
||||
buf = bytearray(50) # create a buffer
|
||||
spi.readinto(buf) # read into the given buffer (reads 50 bytes in this case)
|
||||
spi.readinto(buf, 0xff) # read into the given buffer and output 0xff on MOSI
|
||||
|
||||
spi.write(b'12345') # write 5 bytes on MOSI
|
||||
|
||||
buf = bytearray(4) # create a buffer
|
||||
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
|
||||
|
||||
.. Warning::
|
||||
Currently *all* of ``sck``, ``mosi`` and ``miso`` *must* be specified when
|
||||
initialising Software SPI.
|
||||
|
||||
Hardware SPI bus
|
||||
----------------
|
||||
|
||||
There are two hardware SPI channels that allow faster transmission
|
||||
rates (up to 80Mhz). These may be used on any IO pins that support the
|
||||
required direction and are otherwise unused (see :ref:`Pins_and_GPIO`)
|
||||
but if they are not configured to their default pins then they need to
|
||||
pass through an extra layer of GPIO multiplexing, which can impact
|
||||
their reliability at high speeds. Hardware SPI channels are limited
|
||||
to 40MHz when used on pins other than the default ones listed below.
|
||||
|
||||
===== =========== ============
|
||||
\ HSPI (id=1) VSPI (id=2)
|
||||
===== =========== ============
|
||||
sck 14 18
|
||||
mosi 13 23
|
||||
miso 12 19
|
||||
===== =========== ============
|
||||
|
||||
Hardware SPI is accessed via the :ref:`machine.SPI <machine.SPI>` class and
|
||||
has the same methods as software SPI above::
|
||||
|
||||
from machine import Pin, SPI
|
||||
|
||||
hspi = SPI(1, 10000000, sck=Pin(14), mosi=Pin(13), miso=Pin(12))
|
||||
vspi = SPI(2, baudrate=80000000, polarity=0, phase=0, bits=8, firstbit=0, sck=Pin(18), mosi=Pin(23), miso=Pin(19))
|
||||
|
||||
Software I2C bus
|
||||
----------------
|
||||
|
||||
Software I2C (using bit-banging) works on all output-capable pins, and is
|
||||
accessed via the :ref:`machine.SoftI2C <machine.SoftI2C>` class::
|
||||
|
||||
from machine import Pin, SoftI2C
|
||||
|
||||
i2c = SoftI2C(scl=Pin(5), sda=Pin(4), freq=100000)
|
||||
|
||||
i2c.scan() # scan for devices
|
||||
|
||||
i2c.readfrom(0x3a, 4) # read 4 bytes from device with address 0x3a
|
||||
i2c.writeto(0x3a, '12') # write '12' to device with address 0x3a
|
||||
|
||||
buf = bytearray(10) # create a buffer with 10 bytes
|
||||
i2c.writeto(0x3a, buf) # write the given buffer to the slave
|
||||
|
||||
Hardware I2C bus
|
||||
----------------
|
||||
|
||||
There are two hardware I2C peripherals with identifiers 0 and 1. Any available
|
||||
output-capable pins can be used for SCL and SDA but the defaults are given
|
||||
below.
|
||||
|
||||
===== =========== ============
|
||||
\ I2C(0) I2C(1)
|
||||
===== =========== ============
|
||||
scl 18 25
|
||||
sda 19 26
|
||||
===== =========== ============
|
||||
|
||||
The driver is accessed via the :ref:`machine.I2C <machine.I2C>` class and
|
||||
has the same methods as software I2C above::
|
||||
|
||||
from machine import Pin, I2C
|
||||
|
||||
i2c = I2C(0)
|
||||
i2c = I2C(1, scl=Pin(5), sda=Pin(4), freq=400000)
|
||||
|
||||
Real time clock (RTC)
|
||||
---------------------
|
||||
|
||||
See :ref:`machine.RTC <machine.RTC>` ::
|
||||
|
||||
from machine import RTC
|
||||
|
||||
rtc = RTC()
|
||||
rtc.datetime((2017, 8, 23, 1, 12, 48, 0, 0)) # set a specific date and time
|
||||
rtc.datetime() # get date and time
|
||||
|
||||
Deep-sleep mode
|
||||
---------------
|
||||
|
||||
The following code can be used to sleep, wake and check the reset cause::
|
||||
|
||||
import machine
|
||||
|
||||
# check if the device woke from a deep sleep
|
||||
if machine.reset_cause() == machine.DEEPSLEEP_RESET:
|
||||
print('woke from a deep sleep')
|
||||
|
||||
# put the device to sleep for 10 seconds
|
||||
machine.deepsleep(10000)
|
||||
|
||||
Notes:
|
||||
|
||||
* Calling ``deepsleep()`` without an argument will put the device to sleep
|
||||
indefinitely
|
||||
* A software reset does not change the reset cause
|
||||
* There may be some leakage current flowing through enabled internal pullups.
|
||||
To further reduce power consumption it is possible to disable the internal pullups::
|
||||
|
||||
p1 = Pin(4, Pin.IN, Pin.PULL_HOLD)
|
||||
|
||||
After leaving deepsleep it may be necessary to un-hold the pin explicitly (e.g. if
|
||||
it is an output pin) via::
|
||||
|
||||
p1 = Pin(4, Pin.OUT, None)
|
||||
|
||||
RMT
|
||||
---
|
||||
|
||||
The RMT is ESP32-specific and allows generation of accurate digital pulses with
|
||||
12.5ns resolution. See :ref:`esp32.RMT <esp32.RMT>` for details. Usage is::
|
||||
|
||||
import esp32
|
||||
from machine import Pin
|
||||
|
||||
r = esp32.RMT(0, pin=Pin(18), clock_div=8)
|
||||
r # RMT(channel=0, pin=18, source_freq=80000000, clock_div=8)
|
||||
# The channel resolution is 100ns (1/(source_freq/clock_div)).
|
||||
r.write_pulses((1, 20, 2, 40), start=0) # Send 0 for 100ns, 1 for 2000ns, 0 for 200ns, 1 for 4000ns
|
||||
|
||||
OneWire driver
|
||||
--------------
|
||||
|
||||
The OneWire driver is implemented in software and works on all pins::
|
||||
|
||||
from machine import Pin
|
||||
import onewire
|
||||
|
||||
ow = onewire.OneWire(Pin(12)) # create a OneWire bus on GPIO12
|
||||
ow.scan() # return a list of devices on the bus
|
||||
ow.reset() # reset the bus
|
||||
ow.readbyte() # read a byte
|
||||
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 DS18S20 and DS18B20 devices::
|
||||
|
||||
import time, ds18x20
|
||||
ds = ds18x20.DS18X20(ow)
|
||||
roms = ds.scan()
|
||||
ds.convert_temp()
|
||||
time.sleep_ms(750)
|
||||
for rom in roms:
|
||||
print(ds.read_temp(rom))
|
||||
|
||||
Be sure to put a 4.7k pull-up resistor on the data line. Note that
|
||||
the ``convert_temp()`` method must be called each time you want to
|
||||
sample the temperature.
|
||||
|
||||
NeoPixel driver
|
||||
---------------
|
||||
|
||||
Use the ``neopixel`` module::
|
||||
|
||||
from machine import Pin
|
||||
from neopixel import NeoPixel
|
||||
|
||||
pin = Pin(0, Pin.OUT) # set GPIO0 to output to drive NeoPixels
|
||||
np = NeoPixel(pin, 8) # create NeoPixel driver on GPIO0 for 8 pixels
|
||||
np[0] = (255, 255, 255) # set the first pixel to white
|
||||
np.write() # write data to all pixels
|
||||
r, g, b = np[0] # get first pixel colour
|
||||
|
||||
For low-level driving of a NeoPixel::
|
||||
|
||||
import esp
|
||||
esp.neopixel_write(pin, grb_buf, is800khz)
|
||||
|
||||
.. Warning::
|
||||
By default ``NeoPixel`` is configured to control the more popular *800kHz*
|
||||
units. It is possible to use alternative timing to control other (typically
|
||||
400kHz) devices by passing ``timing=0`` when constructing the
|
||||
``NeoPixel`` object.
|
||||
|
||||
|
||||
Capacitive touch
|
||||
----------------
|
||||
|
||||
Use the ``TouchPad`` class in the ``machine`` module::
|
||||
|
||||
from machine import TouchPad, Pin
|
||||
|
||||
t = TouchPad(Pin(14))
|
||||
t.read() # Returns a smaller number when touched
|
||||
|
||||
``TouchPad.read`` returns a value relative to the capacitive variation. Small numbers (typically in
|
||||
the *tens*) are common when a pin is touched, larger numbers (above *one thousand*) when
|
||||
no touch is present. However the values are *relative* and can vary depending on the board
|
||||
and surrounding composition so some calibration may be required.
|
||||
|
||||
There are ten capacitive touch-enabled pins that can be used on the ESP32: 0, 2, 4, 12, 13
|
||||
14, 15, 27, 32, 33. Trying to assign to any other pins will result in a ``ValueError``.
|
||||
|
||||
Note that TouchPads can be used to wake an ESP32 from sleep::
|
||||
|
||||
import machine
|
||||
from machine import TouchPad, Pin
|
||||
import esp32
|
||||
|
||||
t = TouchPad(Pin(14))
|
||||
t.config(500) # configure the threshold at which the pin is considered touched
|
||||
esp32.wake_on_touch(True)
|
||||
machine.lightsleep() # put the MCU to sleep until a touchpad is touched
|
||||
|
||||
For more details on touchpads refer to `Espressif Touch Sensor
|
||||
<https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/peripherals/touch_pad.html>`_.
|
||||
|
||||
|
||||
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)
|
||||
----------------------------------------
|
||||
|
||||
WebREPL (REPL over WebSockets, accessible via a web browser) is an
|
||||
experimental feature available in ESP32 port. Download web client
|
||||
from https://github.com/micropython/webrepl (hosted version available
|
||||
at http://micropython.org/webrepl), and configure it by executing::
|
||||
|
||||
import webrepl_setup
|
||||
|
||||
and following on-screen instructions. After reboot, it will be available
|
||||
for connection. If you disabled automatic start-up on boot, you may
|
||||
run configured daemon on demand using::
|
||||
|
||||
import webrepl
|
||||
webrepl.start()
|
||||
|
||||
# or, start with a specific password
|
||||
webrepl.start(password='mypass')
|
||||
|
||||
The WebREPL daemon listens on all active interfaces, which can be STA or
|
||||
AP. This allows you to connect to the ESP32 via a router (the STA
|
||||
interface) or directly when connected to its access point.
|
||||
|
||||
In addition to terminal/command prompt access, WebREPL also has provision
|
||||
for file transfer (both upload and download). The web client has buttons for
|
||||
the corresponding functions, or you can use the command-line client
|
||||
``webrepl_cli.py`` from the repository above.
|
||||
|
||||
See the MicroPython forum for other community-supported alternatives
|
||||
to transfer files to an ESP32 board.
|
||||
139
docs/esp32/tutorial/intro.rst
Normal file
139
docs/esp32/tutorial/intro.rst
Normal file
@ -0,0 +1,139 @@
|
||||
.. _esp32_intro:
|
||||
|
||||
Getting started with MicroPython on the ESP32
|
||||
=============================================
|
||||
|
||||
Using MicroPython is a great way to get the most of your ESP32 board. And
|
||||
vice versa, the ESP32 chip is a great platform for using MicroPython. This
|
||||
tutorial will guide you through setting up MicroPython, getting a prompt, using
|
||||
WebREPL, connecting to the network and communicating with the Internet, using
|
||||
the hardware peripherals, and controlling some external components.
|
||||
|
||||
Let's get started!
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
The first thing you need is a board with an ESP32 chip. The MicroPython
|
||||
software supports the ESP32 chip itself and any board should work. The main
|
||||
characteristic of a board is how the GPIO pins are connected to the outside
|
||||
world, and whether it includes a built-in USB-serial convertor to make the
|
||||
UART available to your PC.
|
||||
|
||||
Names of pins will be given in this tutorial using the chip names (eg GPIO2)
|
||||
and it should be straightforward to find which pin this corresponds to on your
|
||||
particular board.
|
||||
|
||||
Powering the board
|
||||
------------------
|
||||
|
||||
If your board has a USB connector on it then most likely it is powered through
|
||||
this when connected to your PC. Otherwise you will need to power it directly.
|
||||
Please refer to the documentation for your board for further details.
|
||||
|
||||
Getting the firmware
|
||||
--------------------
|
||||
|
||||
The first thing you need to do is download the most recent MicroPython firmware
|
||||
.bin file to load onto your ESP32 device. You can download it from the
|
||||
`MicroPython downloads page <https://micropython.org/download#esp32>`_.
|
||||
From here, you have 3 main choices:
|
||||
|
||||
* Stable firmware builds
|
||||
* Daily firmware builds
|
||||
* Daily firmware builds with SPIRAM support
|
||||
|
||||
If you are just starting with MicroPython, the best bet is to go for the Stable
|
||||
firmware builds. If you are an advanced, experienced MicroPython ESP32 user
|
||||
who would like to follow development closely and help with testing new
|
||||
features, there are daily builds. If your board has SPIRAM support you can
|
||||
use either the standard firmware or the firmware with SPIRAM support, and in
|
||||
the latter case you will have access to more RAM for Python objects.
|
||||
|
||||
Deploying the firmware
|
||||
----------------------
|
||||
|
||||
Once you have the MicroPython firmware you need to load it onto your ESP32 device.
|
||||
There are two main steps to do this: first you need to put your device in
|
||||
bootloader mode, and second you need to copy across the firmware. The exact
|
||||
procedure for these steps is highly dependent on the particular board and you will
|
||||
need to refer to its documentation for details.
|
||||
|
||||
Fortunately, most boards have a USB connector, a USB-serial convertor, and the DTR
|
||||
and RTS pins wired in a special way then deploying the firmware should be easy as
|
||||
all steps can be done automatically. Boards that have such features
|
||||
include the Adafruit Feather HUZZAH32, M5Stack, Wemos LOLIN32, and TinyPICO
|
||||
boards, along with the Espressif DevKitC, PICO-KIT, WROVER-KIT dev-kits.
|
||||
|
||||
For best results it is recommended to first erase the entire flash of your
|
||||
device before putting on new MicroPython firmware.
|
||||
|
||||
Currently we only support esptool.py to copy across the firmware. You can find
|
||||
this tool here: `<https://github.com/espressif/esptool/>`__, or install it
|
||||
using pip::
|
||||
|
||||
pip install esptool
|
||||
|
||||
Versions starting with 1.3 support both Python 2.7 and Python 3.4 (or newer).
|
||||
An older version (at least 1.2.1 is needed) works fine but will require Python
|
||||
2.7.
|
||||
|
||||
Using esptool.py you can erase the flash with the command::
|
||||
|
||||
esptool.py --port /dev/ttyUSB0 erase_flash
|
||||
|
||||
And then deploy the new firmware using::
|
||||
|
||||
esptool.py --chip esp32 --port /dev/ttyUSB0 write_flash -z 0x1000 esp32-20180511-v1.9.4.bin
|
||||
|
||||
Notes:
|
||||
|
||||
* You might need to change the "port" setting to something else relevant for your
|
||||
PC
|
||||
* You may need to reduce the baudrate if you get errors when flashing
|
||||
(eg down to 115200 by adding ``--baud 115200`` into the command)
|
||||
* For some boards with a particular FlashROM configuration you may need to
|
||||
change the flash mode (eg by adding ``-fm dio`` into the command)
|
||||
* The filename of the firmware should match the file that you have
|
||||
|
||||
If the above commands run without error then MicroPython should be installed on
|
||||
your board!
|
||||
|
||||
Serial prompt
|
||||
-------------
|
||||
|
||||
Once you have the firmware on the device you can access the REPL (Python prompt)
|
||||
over UART0 (GPIO1=TX, GPIO3=RX), which might be connected to a USB-serial
|
||||
convertor, depending on your board. The baudrate is 115200.
|
||||
|
||||
From here you can now follow the ESP8266 tutorial, because these two Espressif chips
|
||||
are very similar when it comes to using MicroPython on them. The ESP8266 tutorial
|
||||
is found at :ref:`esp8266_tutorial` (but skip the Introduction section).
|
||||
|
||||
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. The most reliable and convenient power
|
||||
source is a USB port.
|
||||
|
||||
* 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.
|
||||
|
||||
* To catch incorrect flash content (e.g. from a defective sector on a chip),
|
||||
add ``--verify`` switch to the commands above.
|
||||
|
||||
* If you still experience problems with flashing the firmware please
|
||||
refer to esptool.py project page, https://github.com/espressif/esptool
|
||||
for additional documentation and a bug tracker where you can report problems.
|
||||
|
||||
* If you are able to flash the firmware but the ``--verify`` option returns
|
||||
errors even after multiple retries the you may have a defective FlashROM chip.
|
||||
@ -1,3 +1,5 @@
|
||||
.. _esp8266_general:
|
||||
|
||||
General information about the ESP8266 port
|
||||
==========================================
|
||||
|
||||
@ -138,7 +140,7 @@ The above may also happen after an application terminates and quits to the REPL
|
||||
for any reason including an exception. Subsequent arrival of data provokes the
|
||||
failure with the above error message repeatedly issued. So, sockets should be
|
||||
closed in any case, regardless whether an application terminates successfully
|
||||
or by an exeption, for example using try/finally::
|
||||
or by an exception, for example using try/finally::
|
||||
|
||||
sock = socket(...)
|
||||
try:
|
||||
@ -156,7 +158,7 @@ also has some known issues/limitations:
|
||||
|
||||
1. No support for Diffie-Hellman (DH) key exchange and Elliptic-curve
|
||||
cryptography (ECC). This means it can't work with sites which force
|
||||
the use of these features (it works ok with classic RSA certifactes).
|
||||
the use of these features (it works ok with classic RSA certificates).
|
||||
2. Half-duplex communication nature. axTLS uses a single buffer for both
|
||||
sending and receiving, which leads to considerable memory saving and
|
||||
works well with protocols like HTTP. But there may be problems with
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
.. _quickref:
|
||||
.. _esp8266_quickref:
|
||||
|
||||
Quick reference for the ESP8266
|
||||
===============================
|
||||
@ -9,6 +9,15 @@ Quick reference for the ESP8266
|
||||
|
||||
The Adafruit Feather HUZZAH board (image attribution: Adafruit).
|
||||
|
||||
Below is a quick reference for ESP8266-based boards. If it is your first time
|
||||
working with this board please consider reading the following sections first:
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
general.rst
|
||||
tutorial/index.rst
|
||||
|
||||
Installing MicroPython
|
||||
----------------------
|
||||
|
||||
@ -129,6 +138,45 @@ Also note that Pin(16) is a special pin (used for wakeup from deepsleep
|
||||
mode) and may be not available for use with higher-level classes like
|
||||
``Neopixel``.
|
||||
|
||||
UART (serial bus)
|
||||
-----------------
|
||||
|
||||
See :ref:`machine.UART <machine.UART>`. ::
|
||||
|
||||
from machine import UART
|
||||
uart = UART(0, baudrate=9600)
|
||||
uart.write('hello')
|
||||
uart.read(5) # read up to 5 bytes
|
||||
|
||||
Two UARTs are available. UART0 is on Pins 1 (TX) and 3 (RX). UART0 is
|
||||
bidirectional, and by default is used for the REPL. UART1 is on Pins 2
|
||||
(TX) and 8 (RX) however Pin 8 is used to connect the flash chip, so
|
||||
UART1 is TX only.
|
||||
|
||||
When UART0 is attached to the REPL, all incoming chars on UART(0) go
|
||||
straight to stdin so uart.read() will always return None. Use
|
||||
sys.stdin.read() if it's needed to read characters from the UART(0)
|
||||
while it's also used for the REPL (or detach, read, then reattach).
|
||||
When detached the UART(0) can be used for other purposes.
|
||||
|
||||
If there are no objects in any of the dupterm slots when the REPL is
|
||||
started (on hard or soft reset) then UART(0) is automatically attached.
|
||||
Without this, the only way to recover a board without a REPL would be to
|
||||
completely erase and reflash (which would install the default boot.py which
|
||||
attaches the REPL).
|
||||
|
||||
To detach the REPL from UART0, use::
|
||||
|
||||
import uos
|
||||
uos.dupterm(None, 1)
|
||||
|
||||
The REPL is attached by default. If you have detached it, to reattach
|
||||
it use::
|
||||
|
||||
import uos, machine
|
||||
uart = machine.UART(0, 115200)
|
||||
uos.dupterm(uart, 1)
|
||||
|
||||
PWM (pulse width modulation)
|
||||
----------------------------
|
||||
|
||||
@ -166,20 +214,20 @@ Software SPI bus
|
||||
----------------
|
||||
|
||||
There are two SPI drivers. One is implemented in software (bit-banging)
|
||||
and works on all pins, and is accessed via the :ref:`machine.SPI <machine.SPI>`
|
||||
and works on all pins, and is accessed via the :ref:`machine.SoftSPI <machine.SoftSPI>`
|
||||
class::
|
||||
|
||||
from machine import Pin, SPI
|
||||
from machine import Pin, SoftSPI
|
||||
|
||||
# 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(-1, baudrate=100000, polarity=1, phase=0, sck=Pin(0), mosi=Pin(2), miso=Pin(4))
|
||||
spi = SoftSPI(baudrate=100000, polarity=1, phase=0, sck=Pin(0), mosi=Pin(2), miso=Pin(4))
|
||||
|
||||
spi.init(baudrate=200000) # set the baudrate
|
||||
|
||||
spi.read(10) # read 10 bytes on MISO
|
||||
spi.read(10, 0xff) # read 10 bytes while outputing 0xff on MOSI
|
||||
spi.read(10, 0xff) # read 10 bytes while outputting 0xff on MOSI
|
||||
|
||||
buf = bytearray(50) # create a buffer
|
||||
spi.readinto(buf) # read into the given buffer (reads 50 bytes in this case)
|
||||
@ -210,7 +258,8 @@ I2C bus
|
||||
-------
|
||||
|
||||
The I2C driver is implemented in software and works on all pins,
|
||||
and is accessed via the :ref:`machine.I2C <machine.I2C>` class::
|
||||
and is accessed via the :ref:`machine.I2C <machine.I2C>` class (which is an
|
||||
alias of :ref:`machine.SoftI2C <machine.SoftI2C>`)::
|
||||
|
||||
from machine import Pin, I2C
|
||||
|
||||
@ -234,6 +283,16 @@ See :ref:`machine.RTC <machine.RTC>` ::
|
||||
rtc.datetime((2017, 8, 23, 1, 12, 48, 0, 0)) # set a specific date and time
|
||||
rtc.datetime() # get date and time
|
||||
|
||||
# synchronize with ntp
|
||||
# need to be connected to wifi
|
||||
import ntptime
|
||||
ntptime.settime() # set the rtc datetime from the remote server
|
||||
rtc.datetime() # get the date and time in UTC
|
||||
|
||||
.. note:: Not all methods are implemented: `RTC.now()`, `RTC.irq(handler=*) <RTC.irq>`
|
||||
(using a custom handler), `RTC.init()` and `RTC.deinit()` are
|
||||
currently not supported.
|
||||
|
||||
Deep-sleep mode
|
||||
---------------
|
||||
|
||||
@ -305,6 +364,13 @@ For low-level driving of a NeoPixel::
|
||||
import esp
|
||||
esp.neopixel_write(pin, grb_buf, is800khz)
|
||||
|
||||
.. Warning::
|
||||
By default ``NeoPixel`` is configured to control the more popular *800kHz*
|
||||
units. It is possible to use alternative timing to control other (typically
|
||||
400kHz) devices by passing ``timing=0`` when constructing the
|
||||
``NeoPixel`` object.
|
||||
|
||||
|
||||
APA102 driver
|
||||
-------------
|
||||
|
||||
|
||||
91
docs/esp8266/tutorial/apa102.rst
Normal file
91
docs/esp8266/tutorial/apa102.rst
Normal file
@ -0,0 +1,91 @@
|
||||
Controlling APA102 LEDs
|
||||
=======================
|
||||
|
||||
APA102 LEDs, also known as DotStar LEDs, are individually addressable
|
||||
full-colour RGB LEDs, generally in a string formation. They differ from
|
||||
NeoPixels in that they require two pins to control - both a Clock and Data pin.
|
||||
They can operate at a much higher data and PWM frequencies than NeoPixels and
|
||||
are more suitable for persistence-of-vision effects.
|
||||
|
||||
To create an APA102 object do the following::
|
||||
|
||||
>>> import machine, apa102
|
||||
>>> strip = apa102.APA102(machine.Pin(5), machine.Pin(4), 60)
|
||||
|
||||
This configures an 60 pixel APA102 strip with clock on GPIO5 and data on GPIO4.
|
||||
You can adjust the pin numbers and the number of pixels to suit your needs.
|
||||
|
||||
The RGB colour data, as well as a brightness level, is sent to the APA102 in a
|
||||
certain order. Usually this is ``(Red, Green, Blue, Brightness)``.
|
||||
If you are using one of the newer APA102C LEDs the green and blue are swapped,
|
||||
so the order is ``(Red, Blue, Green, Brightness)``.
|
||||
The APA102 has more of a square lens while the APA102C has more of a round one.
|
||||
If you are using a APA102C strip and would prefer to provide colours in RGB
|
||||
order instead of RBG, you can customise the tuple colour order like so::
|
||||
|
||||
>>> strip.ORDER = (0, 2, 1, 3)
|
||||
|
||||
To set the colour of pixels use::
|
||||
|
||||
>>> strip[0] = (255, 255, 255, 31) # set to white, full brightness
|
||||
>>> strip[1] = (255, 0, 0, 31) # set to red, full brightness
|
||||
>>> strip[2] = (0, 255, 0, 15) # set to green, half brightness
|
||||
>>> strip[3] = (0, 0, 255, 7) # set to blue, quarter brightness
|
||||
|
||||
Use the ``write()`` method to output the colours to the LEDs::
|
||||
|
||||
>>> strip.write()
|
||||
|
||||
Demonstration::
|
||||
|
||||
import time
|
||||
import machine, apa102
|
||||
|
||||
# 1M strip with 60 LEDs
|
||||
strip = apa102.APA102(machine.Pin(5), machine.Pin(4), 60)
|
||||
|
||||
brightness = 1 # 0 is off, 1 is dim, 31 is max
|
||||
|
||||
# Helper for converting 0-255 offset to a colour tuple
|
||||
def wheel(offset, brightness):
|
||||
# The colours are a transition r - g - b - back to r
|
||||
offset = 255 - offset
|
||||
if offset < 85:
|
||||
return (255 - offset * 3, 0, offset * 3, brightness)
|
||||
if offset < 170:
|
||||
offset -= 85
|
||||
return (0, offset * 3, 255 - offset * 3, brightness)
|
||||
offset -= 170
|
||||
return (offset * 3, 255 - offset * 3, 0, brightness)
|
||||
|
||||
# Demo 1: RGB RGB RGB
|
||||
red = 0xff0000
|
||||
green = red >> 8
|
||||
blue = red >> 16
|
||||
for i in range(strip.n):
|
||||
colour = red >> (i % 3) * 8
|
||||
strip[i] = ((colour & red) >> 16, (colour & green) >> 8, (colour & blue), brightness)
|
||||
strip.write()
|
||||
|
||||
# Demo 2: Show all colours of the rainbow
|
||||
for i in range(strip.n):
|
||||
strip[i] = wheel((i * 256 // strip.n) % 255, brightness)
|
||||
strip.write()
|
||||
|
||||
# Demo 3: Fade all pixels together through rainbow colours, offset each pixel
|
||||
for r in range(5):
|
||||
for n in range(256):
|
||||
for i in range(strip.n):
|
||||
strip[i] = wheel(((i * 256 // strip.n) + n) & 255, brightness)
|
||||
strip.write()
|
||||
time.sleep_ms(25)
|
||||
|
||||
# Demo 4: Same colour, different brightness levels
|
||||
for b in range(31,-1,-1):
|
||||
strip[0] = (255, 153, 0, b)
|
||||
strip.write()
|
||||
time.sleep_ms(250)
|
||||
|
||||
# End: Turn off all the LEDs
|
||||
strip.fill((0, 0, 0, 0))
|
||||
strip.write()
|
||||
@ -1,4 +1,4 @@
|
||||
.. _tutorial-index:
|
||||
.. _esp8266_tutorial:
|
||||
|
||||
MicroPython tutorial for ESP8266
|
||||
================================
|
||||
@ -29,5 +29,6 @@ to `<https://www.python.org>`__.
|
||||
powerctrl.rst
|
||||
onewire.rst
|
||||
neopixel.rst
|
||||
apa102.rst
|
||||
dht.rst
|
||||
nextsteps.rst
|
||||
|
||||
@ -44,7 +44,7 @@ Now that we are connected we can download and display the data::
|
||||
... data = s.recv(500)
|
||||
... print(str(data, 'utf8'), end='')
|
||||
...
|
||||
|
||||
|
||||
When this loop executes it should start showing the animation (use ctrl-C to
|
||||
interrupt it).
|
||||
|
||||
@ -61,6 +61,7 @@ of the request you need to specify the page to retrieve.
|
||||
Let's define a function that can download and print a URL::
|
||||
|
||||
def http_get(url):
|
||||
import socket
|
||||
_, _, host, path = url.split('/', 3)
|
||||
addr = socket.getaddrinfo(host, 80)[0][-1]
|
||||
s = socket.socket()
|
||||
@ -74,8 +75,7 @@ Let's define a function that can download and print a URL::
|
||||
break
|
||||
s.close()
|
||||
|
||||
Make sure that you import the socket module before running this function. Then
|
||||
you can try::
|
||||
Then you can try::
|
||||
|
||||
>>> http_get('http://micropython.org/ks/test.html')
|
||||
|
||||
@ -118,5 +118,6 @@ that contains a table with the state of all the GPIO pins::
|
||||
break
|
||||
rows = ['<tr><td>%s</td><td>%d</td></tr>' % (str(p), p.value()) for p in pins]
|
||||
response = html % '\n'.join(rows)
|
||||
cl.send('HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n')
|
||||
cl.send(response)
|
||||
cl.close()
|
||||
|
||||
@ -1,12 +0,0 @@
|
||||
MicroPython documentation and references
|
||||
========================================
|
||||
|
||||
.. toctree::
|
||||
|
||||
esp8266/quickref.rst
|
||||
esp8266/general.rst
|
||||
esp8266/tutorial/index.rst
|
||||
library/index.rst
|
||||
reference/index.rst
|
||||
genrst/index.rst
|
||||
license.rst
|
||||
@ -3,10 +3,13 @@ MicroPython documentation and references
|
||||
|
||||
.. toctree::
|
||||
|
||||
pyboard/quickref.rst
|
||||
pyboard/general.rst
|
||||
pyboard/tutorial/index.rst
|
||||
library/index.rst
|
||||
reference/index.rst
|
||||
genrst/index.rst
|
||||
develop/index.rst
|
||||
license.rst
|
||||
pyboard/quickref.rst
|
||||
esp8266/quickref.rst
|
||||
esp32/quickref.rst
|
||||
wipy/quickref.rst
|
||||
unix/quickref.rst
|
||||
@ -76,7 +76,7 @@ Example::
|
||||
Functions
|
||||
---------
|
||||
|
||||
.. function:: open(stream, \*, flags=0, pagesize=0, cachesize=0, minkeypage=0)
|
||||
.. function:: open(stream, *, flags=0, pagesize=0, cachesize=0, minkeypage=0)
|
||||
|
||||
Open a database from a random-access `stream` (like an open file). All
|
||||
other parameters are optional and keyword-only, and allow to tweak advanced
|
||||
@ -116,9 +116,9 @@ Methods
|
||||
Flush any data in cache to the underlying stream.
|
||||
|
||||
.. method:: btree.__getitem__(key)
|
||||
btree.get(key, default=None)
|
||||
btree.get(key, default=None, /)
|
||||
btree.__setitem__(key, val)
|
||||
btree.__detitem__(key)
|
||||
btree.__delitem__(key)
|
||||
btree.__contains__(key)
|
||||
|
||||
Standard dictionary methods.
|
||||
|
||||
@ -1,10 +1,12 @@
|
||||
:mod:`esp` --- functions related to the ESP8266
|
||||
===============================================
|
||||
:mod:`esp` --- functions related to the ESP8266 and ESP32
|
||||
=========================================================
|
||||
|
||||
.. module:: esp
|
||||
:synopsis: functions related to the ESP8266
|
||||
:synopsis: functions related to the ESP8266 and ESP32
|
||||
|
||||
The ``esp`` module contains specific functions related to the ESP8266 module.
|
||||
The ``esp`` module contains specific functions related to both the ESP8266 and
|
||||
ESP32 modules. Some functions are only available on one or the other of these
|
||||
ports.
|
||||
|
||||
|
||||
Functions
|
||||
@ -12,6 +14,8 @@ Functions
|
||||
|
||||
.. function:: sleep_type([sleep_type])
|
||||
|
||||
**Note**: ESP8266 only
|
||||
|
||||
Get or set the sleep type.
|
||||
|
||||
If the *sleep_type* parameter is provided, sets the sleep type to its
|
||||
@ -27,7 +31,9 @@ Functions
|
||||
|
||||
The system enters the set sleep mode automatically when possible.
|
||||
|
||||
.. function:: deepsleep(time=0)
|
||||
.. function:: deepsleep(time_us=0, /)
|
||||
|
||||
**Note**: ESP8266 only - use `machine.deepsleep()` on ESP32
|
||||
|
||||
Enter deep sleep.
|
||||
|
||||
@ -38,8 +44,18 @@ Functions
|
||||
|
||||
.. function:: flash_id()
|
||||
|
||||
**Note**: ESP8266 only
|
||||
|
||||
Read the device ID of the flash memory.
|
||||
|
||||
.. function:: flash_size()
|
||||
|
||||
Read the total size of the flash memory.
|
||||
|
||||
.. function:: flash_user_start()
|
||||
|
||||
Read the memory offset at which the user flash space begins.
|
||||
|
||||
.. function:: flash_read(byte_offset, length_or_buffer)
|
||||
|
||||
.. function:: flash_write(byte_offset, bytes)
|
||||
@ -48,6 +64,8 @@ Functions
|
||||
|
||||
.. function:: set_native_code_location(start, length)
|
||||
|
||||
**Note**: ESP8266 only
|
||||
|
||||
Set the location that native code will be placed for execution after it is
|
||||
compiled. Native code is emitted when the ``@micropython.native``,
|
||||
``@micropython.viper`` and ``@micropython.asm_xtensa`` decorators are applied
|
||||
|
||||
271
docs/library/esp32.rst
Normal file
271
docs/library/esp32.rst
Normal file
@ -0,0 +1,271 @@
|
||||
.. currentmodule:: esp32
|
||||
|
||||
:mod:`esp32` --- functionality specific to the ESP32
|
||||
====================================================
|
||||
|
||||
.. module:: esp32
|
||||
:synopsis: functionality specific to the ESP32
|
||||
|
||||
The ``esp32`` module contains functions and classes specifically aimed at
|
||||
controlling ESP32 modules.
|
||||
|
||||
|
||||
Functions
|
||||
---------
|
||||
|
||||
.. function:: wake_on_touch(wake)
|
||||
|
||||
Configure whether or not a touch will wake the device from sleep.
|
||||
*wake* should be a boolean value.
|
||||
|
||||
.. function:: wake_on_ext0(pin, level)
|
||||
|
||||
Configure how EXT0 wakes the device from sleep. *pin* can be ``None``
|
||||
or a valid Pin object. *level* should be ``esp32.WAKEUP_ALL_LOW`` or
|
||||
``esp32.WAKEUP_ANY_HIGH``.
|
||||
|
||||
.. function:: wake_on_ext1(pins, level)
|
||||
|
||||
Configure how EXT1 wakes the device from sleep. *pins* can be ``None``
|
||||
or a tuple/list of valid Pin objects. *level* should be ``esp32.WAKEUP_ALL_LOW``
|
||||
or ``esp32.WAKEUP_ANY_HIGH``.
|
||||
|
||||
.. function:: raw_temperature()
|
||||
|
||||
Read the raw value of the internal temperature sensor, returning an integer.
|
||||
|
||||
.. function:: hall_sensor()
|
||||
|
||||
Read the raw value of the internal Hall sensor, returning an integer.
|
||||
|
||||
.. function:: idf_heap_info(capabilities)
|
||||
|
||||
Returns information about the ESP-IDF heap memory regions. One of them contains
|
||||
the MicroPython heap and the others are used by ESP-IDF, e.g., for network
|
||||
buffers and other data. This data is useful to get a sense of how much memory
|
||||
is available to ESP-IDF and the networking stack in particular. It may shed
|
||||
some light on situations where ESP-IDF operations fail due to allocation failures.
|
||||
The information returned is *not* useful to troubleshoot Python allocation failures,
|
||||
use `micropython.mem_info()` instead.
|
||||
|
||||
The capabilities parameter corresponds to ESP-IDF's ``MALLOC_CAP_XXX`` values but the
|
||||
two most useful ones are predefined as `esp32.HEAP_DATA` for data heap regions and
|
||||
`esp32.HEAP_EXEC` for executable regions as used by the native code emitter.
|
||||
|
||||
The return value is a list of 4-tuples, where each 4-tuple corresponds to one heap
|
||||
and contains: the total bytes, the free bytes, the largest free block, and
|
||||
the minimum free seen over time.
|
||||
|
||||
Example after booting::
|
||||
|
||||
>>> import esp32; esp32.idf_heap_info(esp32.HEAP_DATA)
|
||||
[(240, 0, 0, 0), (7288, 0, 0, 0), (16648, 4, 4, 4), (79912, 35712, 35512, 35108),
|
||||
(15072, 15036, 15036, 15036), (113840, 0, 0, 0)]
|
||||
|
||||
Flash partitions
|
||||
----------------
|
||||
|
||||
This class gives access to the partitions in the device's flash memory and includes
|
||||
methods to enable over-the-air (OTA) updates.
|
||||
|
||||
.. class:: Partition(id)
|
||||
|
||||
Create an object representing a partition. *id* can be a string which is the label
|
||||
of the partition to retrieve, or one of the constants: ``BOOT`` or ``RUNNING``.
|
||||
|
||||
.. classmethod:: Partition.find(type=TYPE_APP, subtype=0xff, label=None)
|
||||
|
||||
Find a partition specified by *type*, *subtype* and *label*. Returns a
|
||||
(possibly empty) list of Partition objects. Note: ``subtype=0xff`` matches any subtype
|
||||
and ``label=None`` matches any label.
|
||||
|
||||
.. method:: Partition.info()
|
||||
|
||||
Returns a 6-tuple ``(type, subtype, addr, size, label, encrypted)``.
|
||||
|
||||
.. method:: Partition.readblocks(block_num, buf)
|
||||
Partition.readblocks(block_num, buf, offset)
|
||||
.. method:: Partition.writeblocks(block_num, buf)
|
||||
Partition.writeblocks(block_num, buf, offset)
|
||||
.. method:: Partition.ioctl(cmd, arg)
|
||||
|
||||
These methods implement the simple and :ref:`extended
|
||||
<block-device-interface>` block protocol defined by
|
||||
:class:`uos.AbstractBlockDev`.
|
||||
|
||||
.. method:: Partition.set_boot()
|
||||
|
||||
Sets the partition as the boot partition.
|
||||
|
||||
.. method:: Partition.get_next_update()
|
||||
|
||||
Gets the next update partition after this one, and returns a new Partition object.
|
||||
Typical usage is ``Partition(Partition.RUNNING).get_next_update()``
|
||||
which returns the next partition to update given the current running one.
|
||||
|
||||
.. classmethod:: Partition.mark_app_valid_cancel_rollback()
|
||||
|
||||
Signals that the current boot is considered successful.
|
||||
Calling ``mark_app_valid_cancel_rollback`` is required on the first boot of a new
|
||||
partition to avoid an automatic rollback at the next boot.
|
||||
This uses the ESP-IDF "app rollback" feature with "CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE"
|
||||
and an ``OSError(-261)`` is raised if called on firmware that doesn't have the
|
||||
feature enabled.
|
||||
It is OK to call ``mark_app_valid_cancel_rollback`` on every boot and it is not
|
||||
necessary when booting firmare that was loaded using esptool.
|
||||
|
||||
Constants
|
||||
~~~~~~~~~
|
||||
|
||||
.. data:: Partition.BOOT
|
||||
Partition.RUNNING
|
||||
|
||||
Used in the `Partition` constructor to fetch various partitions: ``BOOT`` is the
|
||||
partition that will be booted at the next reset and ``RUNNING`` is the currently
|
||||
running partition.
|
||||
|
||||
.. data:: Partition.TYPE_APP
|
||||
Partition.TYPE_DATA
|
||||
|
||||
Used in `Partition.find` to specify the partition type: ``APP`` is for bootable
|
||||
firmware partitions (typically labelled ``factory``, ``ota_0``, ``ota_1``), and
|
||||
``DATA`` is for other partitions, e.g. ``nvs``, ``otadata``, ``phy_init``, ``vfs``.
|
||||
|
||||
.. data:: HEAP_DATA
|
||||
HEAP_EXEC
|
||||
|
||||
Used in `idf_heap_info`.
|
||||
|
||||
.. _esp32.RMT:
|
||||
|
||||
RMT
|
||||
---
|
||||
|
||||
The RMT (Remote Control) module, specific to the ESP32, was originally designed
|
||||
to send and receive infrared remote control signals. However, due to a flexible
|
||||
design and very accurate (as low as 12.5ns) pulse generation, it can also be
|
||||
used to transmit or receive many other types of digital signals::
|
||||
|
||||
import esp32
|
||||
from machine import Pin
|
||||
|
||||
r = esp32.RMT(0, pin=Pin(18), clock_div=8)
|
||||
r # RMT(channel=0, pin=18, source_freq=80000000, clock_div=8)
|
||||
|
||||
# To use carrier frequency
|
||||
r = esp32.RMT(0, pin=Pin(18), clock_div=8, carrier_freq=38000)
|
||||
r # RMT(channel=0, pin=18, source_freq=80000000, clock_div=8, carrier_freq=38000, carrier_duty_percent=50)
|
||||
|
||||
# The channel resolution is 100ns (1/(source_freq/clock_div)).
|
||||
r.write_pulses((1, 20, 2, 40), start=0) # Send 0 for 100ns, 1 for 2000ns, 0 for 200ns, 1 for 4000ns
|
||||
|
||||
The input to the RMT module is an 80MHz clock (in the future it may be able to
|
||||
configure the input clock but, for now, it's fixed). ``clock_div`` *divides*
|
||||
the clock input which determines the resolution of the RMT channel. The
|
||||
numbers specificed in ``write_pulses`` are multiplied by the resolution to
|
||||
define the pulses.
|
||||
|
||||
``clock_div`` is an 8-bit divider (0-255) and each pulse can be defined by
|
||||
multiplying the resolution by a 15-bit (0-32,768) number. There are eight
|
||||
channels (0-7) and each can have a different clock divider.
|
||||
|
||||
To enable the carrier frequency feature of the esp32 hardware, specify the
|
||||
``carrier_freq`` as something like 38000, a typical IR carrier frequency.
|
||||
|
||||
So, in the example above, the 80MHz clock is divided by 8. Thus the
|
||||
resolution is (1/(80Mhz/8)) 100ns. Since the ``start`` level is 0 and toggles
|
||||
with each number, the bitstream is ``0101`` with durations of [100ns, 2000ns,
|
||||
100ns, 4000ns].
|
||||
|
||||
For more details see Espressif's `ESP-IDF RMT documentation.
|
||||
<https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/peripherals/rmt.html>`_.
|
||||
|
||||
.. Warning::
|
||||
The current MicroPython RMT implementation lacks some features, most notably
|
||||
receiving pulses. RMT should be considered a
|
||||
*beta feature* and the interface may change in the future.
|
||||
|
||||
|
||||
.. class:: RMT(channel, *, pin=None, clock_div=8, carrier_freq=0, carrier_duty_percent=50)
|
||||
|
||||
This class provides access to one of the eight RMT channels. *channel* is
|
||||
required and identifies which RMT channel (0-7) will be configured. *pin*,
|
||||
also required, configures which Pin is bound to the RMT channel. *clock_div*
|
||||
is an 8-bit clock divider that divides the source clock (80MHz) to the RMT
|
||||
channel allowing the resolution to be specified. *carrier_freq* is used to
|
||||
enable the carrier feature and specify its frequency, default value is ``0``
|
||||
(not enabled). To enable, specify a positive integer. *carrier_duty_percent*
|
||||
defaults to 50.
|
||||
|
||||
.. method:: RMT.source_freq()
|
||||
|
||||
Returns the source clock frequency. Currently the source clock is not
|
||||
configurable so this will always return 80MHz.
|
||||
|
||||
.. method:: RMT.clock_div()
|
||||
|
||||
Return the clock divider. Note that the channel resolution is
|
||||
``1 / (source_freq / clock_div)``.
|
||||
|
||||
.. method:: RMT.wait_done(timeout=0)
|
||||
|
||||
Returns ``True`` if the channel is currently transmitting a stream of pulses
|
||||
started with a call to `RMT.write_pulses`.
|
||||
|
||||
If *timeout* (defined in ticks of ``source_freq / clock_div``) is specified
|
||||
the method will wait for *timeout* or until transmission is complete,
|
||||
returning ``False`` if the channel continues to transmit. If looping is
|
||||
enabled with `RMT.loop` and a stream has started, then this method will
|
||||
always (wait and) return ``False``.
|
||||
|
||||
.. method:: RMT.loop(enable_loop)
|
||||
|
||||
Configure looping on the channel. *enable_loop* is bool, set to ``True`` to
|
||||
enable looping on the *next* call to `RMT.write_pulses`. If called with
|
||||
``False`` while a looping stream is currently being transmitted then the
|
||||
current set of pulses will be completed before transmission stops.
|
||||
|
||||
.. method:: RMT.write_pulses(pulses, start)
|
||||
|
||||
Begin sending *pulses*, a list or tuple defining the stream of pulses. The
|
||||
length of each pulse is defined by a number to be multiplied by the channel
|
||||
resolution ``(1 / (source_freq / clock_div))``. *start* defines whether the
|
||||
stream starts at 0 or 1.
|
||||
|
||||
If transmission of a stream is currently in progress then this method will
|
||||
block until transmission of that stream has ended before beginning sending
|
||||
*pulses*.
|
||||
|
||||
If looping is enabled with `RMT.loop`, the stream of pulses will be repeated
|
||||
indefinitely. Further calls to `RMT.write_pulses` will end the previous
|
||||
stream - blocking until the last set of pulses has been transmitted -
|
||||
before starting the next stream.
|
||||
|
||||
|
||||
Ultra-Low-Power co-processor
|
||||
----------------------------
|
||||
|
||||
.. class:: ULP()
|
||||
|
||||
This class provides access to the Ultra-Low-Power co-processor.
|
||||
|
||||
.. method:: ULP.set_wakeup_period(period_index, period_us)
|
||||
|
||||
Set the wake-up period.
|
||||
|
||||
.. method:: ULP.load_binary(load_addr, program_binary)
|
||||
|
||||
Load a *program_binary* into the ULP at the given *load_addr*.
|
||||
|
||||
.. method:: ULP.run(entry_point)
|
||||
|
||||
Start the ULP running at the given *entry_point*.
|
||||
|
||||
|
||||
Constants
|
||||
---------
|
||||
|
||||
.. data:: esp32.WAKEUP_ALL_LOW
|
||||
esp32.WAKEUP_ANY_HIGH
|
||||
|
||||
Selects the wake level for pins.
|
||||
@ -1,4 +1,4 @@
|
||||
:mod:`framebuf` --- Frame buffer manipulation
|
||||
:mod:`framebuf` --- frame buffer manipulation
|
||||
=============================================
|
||||
|
||||
.. module:: framebuf
|
||||
@ -19,7 +19,7 @@ For example::
|
||||
import framebuf
|
||||
|
||||
# FrameBuffer needs 2 bytes for every RGB565 pixel
|
||||
fbuf = FrameBuffer(bytearray(10 * 100 * 2), 10, 100, framebuf.RGB565)
|
||||
fbuf = framebuf.FrameBuffer(bytearray(10 * 100 * 2), 10, 100, framebuf.RGB565)
|
||||
|
||||
fbuf.fill(0)
|
||||
fbuf.text('MicroPython!', 0, 0, 0xffff)
|
||||
@ -28,7 +28,7 @@ For example::
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. class:: FrameBuffer(buffer, width, height, format, stride=width)
|
||||
.. class:: FrameBuffer(buffer, width, height, format, stride=width, /)
|
||||
|
||||
Construct a FrameBuffer object. The parameters are:
|
||||
|
||||
@ -130,7 +130,7 @@ Constants
|
||||
|
||||
Monochrome (1-bit) color format
|
||||
This defines a mapping where the bits in a byte are horizontally mapped.
|
||||
Each byte occupies 8 horizontal pixels with bit 0 being the leftmost.
|
||||
Each byte occupies 8 horizontal pixels with bit 7 being the leftmost.
|
||||
Subsequent bytes appear at successive horizontal locations until the
|
||||
rightmost edge is reached. Further bytes are rendered on the next row, one
|
||||
pixel lower.
|
||||
@ -139,7 +139,7 @@ Constants
|
||||
|
||||
Monochrome (1-bit) color format
|
||||
This defines a mapping where the bits in a byte are horizontally mapped.
|
||||
Each byte occupies 8 horizontal pixels with bit 7 being the leftmost.
|
||||
Each byte occupies 8 horizontal pixels with bit 0 being the leftmost.
|
||||
Subsequent bytes appear at successive horizontal locations until the
|
||||
rightmost edge is reached. Further bytes are rendered on the next row, one
|
||||
pixel lower.
|
||||
|
||||
@ -23,7 +23,7 @@ into MicroPython. There are a few categories of such modules:
|
||||
* Modules which implement a subset of Python functionality, with a provision
|
||||
for extension by the user (via Python code).
|
||||
* Modules which implement MicroPython extensions to the Python standard libraries.
|
||||
* Modules specific to a particular `MicroPython port` and thus not portable.
|
||||
* Modules specific to a particular :term:`MicroPython port` and thus not portable.
|
||||
|
||||
Note about the availability of the modules and their contents: This documentation
|
||||
in general aspires to describe all modules and functions/classes which are
|
||||
@ -38,7 +38,12 @@ in a module (or even the entire module) described in this documentation **may be
|
||||
unavailable** in a particular build of MicroPython on a particular system. The
|
||||
best place to find general information of the availability/non-availability
|
||||
of a particular feature is the "General Information" section which contains
|
||||
information pertaining to a specific `MicroPython port`.
|
||||
information pertaining to a specific :term:`MicroPython port`.
|
||||
|
||||
On some ports you are able to discover the available, built-in libraries that
|
||||
can be imported by entering the following at the REPL::
|
||||
|
||||
help('modules')
|
||||
|
||||
Beyond the built-in libraries described in this documentation, many more
|
||||
modules from the Python standard library, as well as further MicroPython
|
||||
@ -65,104 +70,32 @@ For example, ``import json`` will first search for a file ``json.py`` (or packag
|
||||
directory ``json``) and load that module if it is found. If nothing is found,
|
||||
it will fallback to loading the built-in ``ujson`` module.
|
||||
|
||||
.. only:: port_unix
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
builtins.rst
|
||||
array.rst
|
||||
cmath.rst
|
||||
gc.rst
|
||||
math.rst
|
||||
sys.rst
|
||||
ubinascii.rst
|
||||
ucollections.rst
|
||||
uerrno.rst
|
||||
uhashlib.rst
|
||||
uheapq.rst
|
||||
uio.rst
|
||||
ujson.rst
|
||||
uos.rst
|
||||
ure.rst
|
||||
uselect.rst
|
||||
usocket.rst
|
||||
ussl.rst
|
||||
ustruct.rst
|
||||
utime.rst
|
||||
uzlib.rst
|
||||
_thread.rst
|
||||
|
||||
.. only:: port_pyboard
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
builtins.rst
|
||||
array.rst
|
||||
cmath.rst
|
||||
gc.rst
|
||||
math.rst
|
||||
sys.rst
|
||||
ubinascii.rst
|
||||
ucollections.rst
|
||||
uerrno.rst
|
||||
uhashlib.rst
|
||||
uheapq.rst
|
||||
uio.rst
|
||||
ujson.rst
|
||||
uos.rst
|
||||
ure.rst
|
||||
uselect.rst
|
||||
usocket.rst
|
||||
ustruct.rst
|
||||
utime.rst
|
||||
uzlib.rst
|
||||
_thread.rst
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
builtins.rst
|
||||
array.rst
|
||||
gc.rst
|
||||
sys.rst
|
||||
ubinascii.rst
|
||||
ujson.rst
|
||||
uos.rst
|
||||
ure.rst
|
||||
uselect.rst
|
||||
usocket.rst
|
||||
ussl.rst
|
||||
utime.rst
|
||||
|
||||
.. only:: port_esp8266
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
builtins.rst
|
||||
array.rst
|
||||
gc.rst
|
||||
math.rst
|
||||
sys.rst
|
||||
ubinascii.rst
|
||||
ucollections.rst
|
||||
uerrno.rst
|
||||
uhashlib.rst
|
||||
uheapq.rst
|
||||
uio.rst
|
||||
ujson.rst
|
||||
uos.rst
|
||||
ure.rst
|
||||
uselect.rst
|
||||
usocket.rst
|
||||
ussl.rst
|
||||
ustruct.rst
|
||||
utime.rst
|
||||
uzlib.rst
|
||||
builtins.rst
|
||||
cmath.rst
|
||||
gc.rst
|
||||
math.rst
|
||||
uarray.rst
|
||||
uasyncio.rst
|
||||
ubinascii.rst
|
||||
ucollections.rst
|
||||
uerrno.rst
|
||||
uhashlib.rst
|
||||
uheapq.rst
|
||||
uio.rst
|
||||
ujson.rst
|
||||
uos.rst
|
||||
ure.rst
|
||||
uselect.rst
|
||||
usocket.rst
|
||||
ussl.rst
|
||||
ustruct.rst
|
||||
usys.rst
|
||||
utime.rst
|
||||
uzlib.rst
|
||||
_thread.rst
|
||||
|
||||
|
||||
MicroPython-specific libraries
|
||||
@ -179,43 +112,56 @@ the following libraries.
|
||||
machine.rst
|
||||
micropython.rst
|
||||
network.rst
|
||||
ubluetooth.rst
|
||||
ucryptolib.rst
|
||||
uctypes.rst
|
||||
|
||||
|
||||
.. only:: port_pyboard
|
||||
Port-specific libraries
|
||||
-----------------------
|
||||
|
||||
Libraries specific to the pyboard
|
||||
---------------------------------
|
||||
In some cases the following port/board-specific libraries have functions or
|
||||
classes similar to those in the :mod:`machine` library. Where this occurs, the
|
||||
entry in the port specific library exposes hardware functionality unique to
|
||||
that platform.
|
||||
|
||||
The following libraries are specific to the pyboard.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
pyb.rst
|
||||
lcd160cr.rst
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
Libraries specific to the WiPy
|
||||
---------------------------------
|
||||
|
||||
The following libraries are specific to the WiPy.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
wipy.rst
|
||||
To write portable code use functions and classes from the :mod:`machine` module.
|
||||
To access platform-specific hardware use the appropriate library, e.g.
|
||||
:mod:`pyb` in the case of the Pyboard.
|
||||
|
||||
|
||||
.. only:: port_esp8266
|
||||
Libraries specific to the pyboard
|
||||
---------------------------------
|
||||
|
||||
Libraries specific to the ESP8266
|
||||
---------------------------------
|
||||
The following libraries are specific to the pyboard.
|
||||
|
||||
The following libraries are specific to the ESP8266.
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
pyb.rst
|
||||
lcd160cr.rst
|
||||
|
||||
esp.rst
|
||||
|
||||
Libraries specific to the WiPy
|
||||
------------------------------
|
||||
|
||||
The following libraries and classes are specific to the WiPy.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
wipy.rst
|
||||
machine.ADCWiPy.rst
|
||||
machine.TimerWiPy.rst
|
||||
|
||||
|
||||
Libraries specific to the ESP8266 and ESP32
|
||||
-------------------------------------------
|
||||
|
||||
The following libraries are specific to the ESP8266 and ESP32.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
esp.rst
|
||||
esp32.rst
|
||||
|
||||
@ -37,7 +37,7 @@ For example::
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. class:: LCD160CR(connect=None, \*, pwr=None, i2c=None, spi=None, i2c_addr=98)
|
||||
.. class:: LCD160CR(connect=None, *, pwr=None, i2c=None, spi=None, i2c_addr=98)
|
||||
|
||||
Construct an LCD160CR object. The parameters are:
|
||||
|
||||
@ -340,7 +340,7 @@ Advanced commands
|
||||
.. method:: LCD160CR.set_scroll_win_param(win, param, value)
|
||||
|
||||
Set a single parameter of a scrolling window region:
|
||||
|
||||
|
||||
- *win* is the window id, 0..8.
|
||||
- *param* is the parameter number to configure, 0..7, and corresponds
|
||||
to the parameters in the `set_scroll_win` method.
|
||||
|
||||
@ -4,71 +4,32 @@
|
||||
class ADC -- analog to digital conversion
|
||||
=========================================
|
||||
|
||||
Usage::
|
||||
The ADC class provides an interface to analog-to-digital convertors, and
|
||||
represents a single endpoint that can sample a continuous voltage and
|
||||
convert it to a discretised value.
|
||||
|
||||
Example usage::
|
||||
|
||||
import machine
|
||||
|
||||
adc = machine.ADC() # create an ADC object
|
||||
apin = adc.channel(pin='GP3') # create an analog pin on GP3
|
||||
val = apin() # read an analog value
|
||||
adc = machine.ADC(pin) # create an ADC object acting on a pin
|
||||
val = adc.read_u16() # read a raw analog value in the range 0-65535
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. class:: ADC(id=0, \*, bits=12)
|
||||
.. class:: ADC(id)
|
||||
|
||||
Create an ADC object associated with the given pin.
|
||||
This allows you to then read analog values on that pin.
|
||||
For more info check the `pinout and alternate functions
|
||||
table. <https://raw.githubusercontent.com/wipy/wipy/master/docs/PinOUT.png>`_
|
||||
|
||||
.. warning::
|
||||
|
||||
ADC pin input range is 0-1.4V (being 1.8V the absolute maximum that it
|
||||
can withstand). When GP2, GP3, GP4 or GP5 are remapped to the
|
||||
ADC block, 1.8 V is the maximum. If these pins are used in digital mode,
|
||||
then the maximum allowed input is 3.6V.
|
||||
Access the ADC associated with a source identified by *id*. This
|
||||
*id* may be an integer (usually specifying a channel number), a
|
||||
:ref:`Pin <machine.Pin>` object, or other value supported by the
|
||||
underlying machine.
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. method:: ADC.channel(id, \*, pin)
|
||||
.. method:: ADC.read_u16()
|
||||
|
||||
Create an analog pin. If only channel ID is given, the correct pin will
|
||||
be selected. Alternatively, only the pin can be passed and the correct
|
||||
channel will be selected. Examples::
|
||||
|
||||
# all of these are equivalent and enable ADC channel 1 on GP3
|
||||
apin = adc.channel(1)
|
||||
apin = adc.channel(pin='GP3')
|
||||
apin = adc.channel(id=1, pin='GP3')
|
||||
|
||||
.. method:: ADC.init()
|
||||
|
||||
Enable the ADC block.
|
||||
|
||||
.. method:: ADC.deinit()
|
||||
|
||||
Disable the ADC block.
|
||||
|
||||
class ADCChannel --- read analog values from internal or external sources
|
||||
=========================================================================
|
||||
|
||||
ADC channels can be connected to internal points of the MCU or to GPIO pins.
|
||||
ADC channels are created using the ADC.channel method.
|
||||
|
||||
.. method:: adcchannel()
|
||||
|
||||
Fast method to read the channel value.
|
||||
|
||||
.. method:: adcchannel.value()
|
||||
|
||||
Read the channel value.
|
||||
|
||||
.. method:: adcchannel.init()
|
||||
|
||||
Re-init (and effectively enable) the ADC channel.
|
||||
|
||||
.. method:: adcchannel.deinit()
|
||||
|
||||
Disable the ADC channel.
|
||||
Take an analog reading and return an integer in the range 0-65535.
|
||||
The return value represents the raw reading taken by the ADC, scaled
|
||||
such that the minimum value is 0 and the maximum value is 65535.
|
||||
|
||||
81
docs/library/machine.ADCWiPy.rst
Normal file
81
docs/library/machine.ADCWiPy.rst
Normal file
@ -0,0 +1,81 @@
|
||||
.. currentmodule:: machine
|
||||
.. _machine.ADCWiPy:
|
||||
|
||||
class ADCWiPy -- analog to digital conversion
|
||||
=============================================
|
||||
|
||||
.. note::
|
||||
|
||||
This class is a non-standard ADC implementation for the WiPy.
|
||||
It is available simply as ``machine.ADC`` on the WiPy but is named in the
|
||||
documentation below as ``machine.ADCWiPy`` to distinguish it from the
|
||||
more general :ref:`machine.ADC <machine.ADC>` class.
|
||||
|
||||
Usage::
|
||||
|
||||
import machine
|
||||
|
||||
adc = machine.ADC() # create an ADC object
|
||||
apin = adc.channel(pin='GP3') # create an analog pin on GP3
|
||||
val = apin() # read an analog value
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. class:: ADCWiPy(id=0, *, bits=12)
|
||||
|
||||
Create an ADC object associated with the given pin.
|
||||
This allows you to then read analog values on that pin.
|
||||
For more info check the `pinout and alternate functions
|
||||
table. <https://raw.githubusercontent.com/wipy/wipy/master/docs/PinOUT.png>`_
|
||||
|
||||
.. warning::
|
||||
|
||||
ADC pin input range is 0-1.4V (being 1.8V the absolute maximum that it
|
||||
can withstand). When GP2, GP3, GP4 or GP5 are remapped to the
|
||||
ADC block, 1.8 V is the maximum. If these pins are used in digital mode,
|
||||
then the maximum allowed input is 3.6V.
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. method:: ADCWiPy.channel(id, *, pin)
|
||||
|
||||
Create an analog pin. If only channel ID is given, the correct pin will
|
||||
be selected. Alternatively, only the pin can be passed and the correct
|
||||
channel will be selected. Examples::
|
||||
|
||||
# all of these are equivalent and enable ADC channel 1 on GP3
|
||||
apin = adc.channel(1)
|
||||
apin = adc.channel(pin='GP3')
|
||||
apin = adc.channel(id=1, pin='GP3')
|
||||
|
||||
.. method:: ADCWiPy.init()
|
||||
|
||||
Enable the ADC block.
|
||||
|
||||
.. method:: ADCWiPy.deinit()
|
||||
|
||||
Disable the ADC block.
|
||||
|
||||
class ADCChannel --- read analog values from internal or external sources
|
||||
=========================================================================
|
||||
|
||||
ADC channels can be connected to internal points of the MCU or to GPIO pins.
|
||||
ADC channels are created using the ADC.channel method.
|
||||
|
||||
.. method:: adcchannel()
|
||||
|
||||
Fast method to read the channel value.
|
||||
|
||||
.. method:: adcchannel.value()
|
||||
|
||||
Read the channel value.
|
||||
|
||||
.. method:: adcchannel.init()
|
||||
|
||||
Re-init (and effectively enable) the ADC channel.
|
||||
|
||||
.. method:: adcchannel.deinit()
|
||||
|
||||
Disable the ADC channel.
|
||||
@ -12,6 +12,14 @@ when created, or initialised later on.
|
||||
|
||||
Printing the I2C object gives you information about its configuration.
|
||||
|
||||
Both hardware and software I2C implementations exist via the
|
||||
:ref:`machine.I2C <machine.I2C>` and `machine.SoftI2C` classes. Hardware I2C uses
|
||||
underlying hardware support of the system to perform the reads/writes and is
|
||||
usually efficient and fast but may have restrictions on which pins can be used.
|
||||
Software I2C is implemented by bit-banging and can be used on any pin but is not
|
||||
as efficient. These classes have the same methods available and differ primarily
|
||||
in the way they are constructed.
|
||||
|
||||
Example usage::
|
||||
|
||||
from machine import I2C
|
||||
@ -33,26 +41,38 @@ Example usage::
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. class:: I2C(id=-1, \*, scl, sda, freq=400000)
|
||||
.. class:: I2C(id, *, scl, sda, freq=400000)
|
||||
|
||||
Construct and return a new I2C object using the following parameters:
|
||||
|
||||
- *id* identifies a particular I2C peripheral. The default
|
||||
value of -1 selects a software implementation of I2C which can
|
||||
work (in most cases) with arbitrary pins for SCL and SDA.
|
||||
If *id* is -1 then *scl* and *sda* must be specified. Other
|
||||
allowed values for *id* depend on the particular port/board,
|
||||
and specifying *scl* and *sda* may or may not be required or
|
||||
allowed in this case.
|
||||
- *id* identifies a particular I2C peripheral. Allowed values for
|
||||
depend on the particular port/board
|
||||
- *scl* should be a pin object specifying the pin to use for SCL.
|
||||
- *sda* should be a pin object specifying the pin to use for SDA.
|
||||
- *freq* should be an integer which sets the maximum frequency
|
||||
for SCL.
|
||||
|
||||
Note that some ports/boards will have default values of *scl* and *sda*
|
||||
that can be changed in this constructor. Others will have fixed values
|
||||
of *scl* and *sda* that cannot be changed.
|
||||
|
||||
.. _machine.SoftI2C:
|
||||
.. class:: SoftI2C(scl, sda, *, freq=400000, timeout=255)
|
||||
|
||||
Construct a new software I2C object. The parameters are:
|
||||
|
||||
- *scl* should be a pin object specifying the pin to use for SCL.
|
||||
- *sda* should be a pin object specifying the pin to use for SDA.
|
||||
- *freq* should be an integer which sets the maximum frequency
|
||||
for SCL.
|
||||
- *timeout* is the maximum time in microseconds to wait for clock
|
||||
stretching (SCL held low by another device on the bus), after
|
||||
which an ``OSError(ETIMEDOUT)`` exception is raised.
|
||||
|
||||
General Methods
|
||||
---------------
|
||||
|
||||
.. method:: I2C.init(scl, sda, \*, freq=400000)
|
||||
.. method:: I2C.init(scl, sda, *, freq=400000)
|
||||
|
||||
Initialise the I2C bus with the given arguments:
|
||||
|
||||
@ -79,19 +99,17 @@ The following methods implement the primitive I2C master bus operations and can
|
||||
be combined to make any I2C transaction. They are provided if you need more
|
||||
control over the bus, otherwise the standard methods (see below) can be used.
|
||||
|
||||
These methods are only available on the `machine.SoftI2C` class.
|
||||
|
||||
.. method:: I2C.start()
|
||||
|
||||
Generate a START condition on the bus (SDA transitions to low while SCL is high).
|
||||
|
||||
Availability: ESP8266.
|
||||
|
||||
.. method:: I2C.stop()
|
||||
|
||||
Generate a STOP condition on the bus (SDA transitions to high while SCL is high).
|
||||
|
||||
Availability: ESP8266.
|
||||
|
||||
.. method:: I2C.readinto(buf, nack=True)
|
||||
.. method:: I2C.readinto(buf, nack=True, /)
|
||||
|
||||
Reads bytes from the bus and stores them into *buf*. The number of bytes
|
||||
read is the length of *buf*. An ACK will be sent on the bus after
|
||||
@ -99,29 +117,25 @@ control over the bus, otherwise the standard methods (see below) can be used.
|
||||
is true then a NACK will be sent, otherwise an ACK will be sent (and in this
|
||||
case the slave assumes more bytes are going to be read in a later call).
|
||||
|
||||
Availability: ESP8266.
|
||||
|
||||
.. method:: I2C.write(buf)
|
||||
|
||||
Write the bytes from *buf* to the bus. Checks that an ACK is received
|
||||
after each byte and stops transmitting the remaining bytes if a NACK is
|
||||
received. The function returns the number of ACKs that were received.
|
||||
|
||||
Availability: ESP8266.
|
||||
|
||||
Standard bus operations
|
||||
-----------------------
|
||||
|
||||
The following methods implement the standard I2C master read and write
|
||||
operations that target a given slave device.
|
||||
|
||||
.. method:: I2C.readfrom(addr, nbytes, stop=True)
|
||||
.. method:: I2C.readfrom(addr, nbytes, stop=True, /)
|
||||
|
||||
Read *nbytes* from the slave specified by *addr*.
|
||||
If *stop* is true then a STOP condition is generated at the end of the transfer.
|
||||
Returns a `bytes` object with the data read.
|
||||
|
||||
.. method:: I2C.readfrom_into(addr, buf, stop=True)
|
||||
.. method:: I2C.readfrom_into(addr, buf, stop=True, /)
|
||||
|
||||
Read into *buf* from the slave specified by *addr*.
|
||||
The number of bytes read will be the length of *buf*.
|
||||
@ -129,7 +143,7 @@ operations that target a given slave device.
|
||||
|
||||
The method returns ``None``.
|
||||
|
||||
.. method:: I2C.writeto(addr, buf, stop=True)
|
||||
.. method:: I2C.writeto(addr, buf, stop=True, /)
|
||||
|
||||
Write the bytes from *buf* to the slave specified by *addr*. If a
|
||||
NACK is received following the write of a byte from *buf* then the
|
||||
@ -137,6 +151,20 @@ operations that target a given slave device.
|
||||
generated at the end of the transfer, even if a NACK is received.
|
||||
The function returns the number of ACKs that were received.
|
||||
|
||||
.. method:: I2C.writevto(addr, vector, stop=True, /)
|
||||
|
||||
Write the bytes contained in *vector* to the slave specified by *addr*.
|
||||
*vector* should be a tuple or list of objects with the buffer protocol.
|
||||
The *addr* is sent once and then the bytes from each object in *vector*
|
||||
are written out sequentially. The objects in *vector* may be zero bytes
|
||||
in length in which case they don't contribute to the output.
|
||||
|
||||
If a NACK is received following the write of a byte from one of the
|
||||
objects in *vector* then the remaining bytes, and any remaining objects,
|
||||
are not sent. If *stop* is true then a STOP condition is generated at
|
||||
the end of the transfer, even if a NACK is received. The function
|
||||
returns the number of ACKs that were received.
|
||||
|
||||
Memory operations
|
||||
-----------------
|
||||
|
||||
@ -145,14 +173,14 @@ from and written to. In this case there are two addresses associated with an
|
||||
I2C transaction: the slave address and the memory address. The following
|
||||
methods are convenience functions to communicate with such devices.
|
||||
|
||||
.. method:: I2C.readfrom_mem(addr, memaddr, nbytes, \*, addrsize=8)
|
||||
.. method:: I2C.readfrom_mem(addr, memaddr, nbytes, *, addrsize=8)
|
||||
|
||||
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.
|
||||
Returns a `bytes` object with the data read.
|
||||
|
||||
.. method:: I2C.readfrom_mem_into(addr, memaddr, buf, \*, addrsize=8)
|
||||
.. method:: I2C.readfrom_mem_into(addr, memaddr, buf, *, addrsize=8)
|
||||
|
||||
Read into *buf* from the slave specified by *addr* starting from the
|
||||
memory address specified by *memaddr*. The number of bytes read is the
|
||||
@ -162,7 +190,7 @@ methods are convenience functions to communicate with such devices.
|
||||
|
||||
The method returns ``None``.
|
||||
|
||||
.. method:: I2C.writeto_mem(addr, memaddr, buf, \*, addrsize=8)
|
||||
.. method:: I2C.writeto_mem(addr, memaddr, buf, *, addrsize=8)
|
||||
|
||||
Write *buf* to the slave specified by *addr* starting from the
|
||||
memory address specified by *memaddr*.
|
||||
|
||||
@ -42,7 +42,7 @@ Usage Model::
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. class:: Pin(id, mode=-1, pull=-1, \*, value, drive, alt)
|
||||
.. class:: Pin(id, mode=-1, pull=-1, *, value, drive, alt)
|
||||
|
||||
Access the pin peripheral (GPIO pin) associated with the given ``id``. If
|
||||
additional arguments are given in the constructor then they are used to initialise
|
||||
@ -106,7 +106,7 @@ Constructors
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. method:: Pin.init(mode=-1, pull=-1, \*, value, drive, alt)
|
||||
.. method:: Pin.init(mode=-1, pull=-1, *, value, drive, alt)
|
||||
|
||||
Re-initialise the pin using the given parameters. Only those arguments that
|
||||
are specified will be set. The rest of the pin peripheral state will remain
|
||||
@ -179,7 +179,7 @@ Methods
|
||||
|
||||
Availability: WiPy.
|
||||
|
||||
.. method:: Pin.irq(handler=None, trigger=(Pin.IRQ_FALLING | Pin.IRQ_RISING), \*, priority=1, wake=None)
|
||||
.. method:: Pin.irq(handler=None, trigger=(Pin.IRQ_FALLING | Pin.IRQ_RISING), *, priority=1, wake=None, hard=False)
|
||||
|
||||
Configure an interrupt handler to be called when the trigger source of the
|
||||
pin is active. If the pin mode is ``Pin.IN`` then the trigger source is
|
||||
@ -191,7 +191,8 @@ Methods
|
||||
The arguments are:
|
||||
|
||||
- ``handler`` is an optional function to be called when the interrupt
|
||||
triggers.
|
||||
triggers. The handler must take exactly one argument which is the
|
||||
``Pin`` instance.
|
||||
|
||||
- ``trigger`` configures the event which can generate an interrupt.
|
||||
Possible values are:
|
||||
@ -212,6 +213,11 @@ Methods
|
||||
These values can also be OR'ed together to make a pin generate interrupts in
|
||||
more than one power mode.
|
||||
|
||||
- ``hard`` if true a hardware interrupt is used. This reduces the delay
|
||||
between the pin change and the handler being called. Hard interrupt
|
||||
handlers may not allocate memory; see :ref:`isr_rules`.
|
||||
Not all ports support this argument.
|
||||
|
||||
This method returns a callback object.
|
||||
|
||||
Constants
|
||||
@ -230,6 +236,7 @@ not all constants are available on all ports.
|
||||
|
||||
.. data:: Pin.PULL_UP
|
||||
Pin.PULL_DOWN
|
||||
Pin.PULL_HOLD
|
||||
|
||||
Selects whether there is a pull up/down resistor. Use the value
|
||||
``None`` for no pull.
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
class RTC -- real time clock
|
||||
============================
|
||||
|
||||
The RTC is and independent clock that keeps track of the date
|
||||
The RTC is an independent clock that keeps track of the date
|
||||
and time.
|
||||
|
||||
Example usage::
|
||||
@ -27,7 +27,7 @@ Methods
|
||||
.. method:: RTC.init(datetime)
|
||||
|
||||
Initialise the RTC. Datetime is a tuple of the form:
|
||||
|
||||
|
||||
``(year, month, day[, hour[, minute[, second[, microsecond[, tzinfo]]]]])``
|
||||
|
||||
.. method:: RTC.now()
|
||||
@ -38,7 +38,7 @@ Methods
|
||||
|
||||
Resets the RTC to the time of January 1, 2015 and starts running it again.
|
||||
|
||||
.. method:: RTC.alarm(id, time, \*, repeat=False)
|
||||
.. method:: RTC.alarm(id, time, *, repeat=False)
|
||||
|
||||
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
|
||||
@ -52,7 +52,7 @@ Methods
|
||||
|
||||
Cancel a running alarm.
|
||||
|
||||
.. method:: RTC.irq(\*, trigger, handler=None, wake=machine.IDLE)
|
||||
.. method:: RTC.irq(*, trigger, handler=None, wake=machine.IDLE)
|
||||
|
||||
Create an irq object triggered by a real time clock alarm.
|
||||
|
||||
|
||||
@ -1,8 +1,13 @@
|
||||
.. currentmodule:: machine
|
||||
.. _machine.SD:
|
||||
|
||||
class SD -- secure digital memory card
|
||||
======================================
|
||||
class SD -- secure digital memory card (cc3200 port only)
|
||||
=========================================================
|
||||
|
||||
.. warning::
|
||||
|
||||
This is a non-standard class and is only available on the cc3200 port.
|
||||
|
||||
|
||||
The SD card class allows to configure and enable the memory card
|
||||
module of the WiPy and automatically mount it as ``/sd`` as part
|
||||
|
||||
124
docs/library/machine.SDCard.rst
Normal file
124
docs/library/machine.SDCard.rst
Normal file
@ -0,0 +1,124 @@
|
||||
.. currentmodule:: machine
|
||||
.. _machine.SDCard:
|
||||
|
||||
class SDCard -- secure digital memory card
|
||||
==========================================
|
||||
|
||||
SD cards are one of the most common small form factor removable storage media.
|
||||
SD cards come in a variety of sizes and physical form factors. MMC cards are
|
||||
similar removable storage devices while eMMC devices are electrically similar
|
||||
storage devices designed to be embedded into other systems. All three form
|
||||
share a common protocol for communication with their host system and high-level
|
||||
support looks the same for them all. As such in MicroPython they are implemented
|
||||
in a single class called :class:`machine.SDCard` .
|
||||
|
||||
Both SD and MMC interfaces support being accessed with a variety of bus widths.
|
||||
When being accessed with a 1-bit wide interface they can be accessed using the
|
||||
SPI protocol. Different MicroPython hardware platforms support different widths
|
||||
and pin configurations but for most platforms there is a standard configuration
|
||||
for any given hardware. In general constructing an ``SDCard`` object with without
|
||||
passing any parameters will initialise the interface to the default card slot
|
||||
for the current hardware. The arguments listed below represent the common
|
||||
arguments that might need to be set in order to use either a non-standard slot
|
||||
or a non-standard pin assignment. The exact subset of arguments supported will
|
||||
vary from platform to platform.
|
||||
|
||||
.. class:: SDCard(slot=1, width=1, cd=None, wp=None, sck=None, miso=None, mosi=None, cs=None, freq=20000000)
|
||||
|
||||
This class provides access to SD or MMC storage cards using either
|
||||
a dedicated SD/MMC interface hardware or through an SPI channel.
|
||||
The class implements the block protocol defined by :class:`uos.AbstractBlockDev`.
|
||||
This allows the mounting of an SD card to be as simple as::
|
||||
|
||||
uos.mount(machine.SDCard(), "/sd")
|
||||
|
||||
The constructor takes the following parameters:
|
||||
|
||||
- *slot* selects which of the available interfaces to use. Leaving this
|
||||
unset will select the default interface.
|
||||
|
||||
- *width* selects the bus width for the SD/MMC interface.
|
||||
|
||||
- *cd* can be used to specify a card-detect pin.
|
||||
|
||||
- *wp* can be used to specify a write-protect pin.
|
||||
|
||||
- *sck* can be used to specify an SPI clock pin.
|
||||
|
||||
- *miso* can be used to specify an SPI miso pin.
|
||||
|
||||
- *mosi* can be used to specify an SPI mosi pin.
|
||||
|
||||
- *cs* can be used to specify an SPI chip select pin.
|
||||
|
||||
- *freq* selects the SD/MMC interface frequency in Hz (only supported on the ESP32).
|
||||
|
||||
Implementation-specific details
|
||||
-------------------------------
|
||||
|
||||
Different implementations of the ``SDCard`` class on different hardware support
|
||||
varying subsets of the options above.
|
||||
|
||||
PyBoard
|
||||
```````
|
||||
|
||||
The standard PyBoard has just one slot. No arguments are necessary or supported.
|
||||
|
||||
ESP32
|
||||
`````
|
||||
|
||||
The ESP32 provides two channels of SD/MMC hardware and also supports
|
||||
access to SD Cards through either of the two SPI ports that are
|
||||
generally available to the user. As a result the *slot* argument can
|
||||
take a value between 0 and 3, inclusive. Slots 0 and 1 use the
|
||||
built-in SD/MMC hardware while slots 2 and 3 use the SPI ports. Slot 0
|
||||
supports 1, 4 or 8-bit wide access while slot 1 supports 1 or 4-bit
|
||||
access; the SPI slots only support 1-bit access.
|
||||
|
||||
.. note:: Slot 0 is used to communicate with on-board flash memory
|
||||
on most ESP32 modules and so will be unavailable to the
|
||||
user.
|
||||
|
||||
.. note:: Most ESP32 modules that provide an SD card slot using the
|
||||
dedicated hardware only wire up 1 data pin, so the default
|
||||
value for *width* is 1.
|
||||
|
||||
The pins used by the dedicated SD/MMC hardware are fixed. The pins
|
||||
used by the SPI hardware can be reassigned.
|
||||
|
||||
.. note:: If any of the SPI signals are remapped then all of the SPI
|
||||
signals will pass through a GPIO multiplexer unit which
|
||||
can limit the performance of high frequency signals. Since
|
||||
the normal operating speed for SD cards is 40MHz this can
|
||||
cause problems on some cards.
|
||||
|
||||
The default (and preferred) pin assignment are as follows:
|
||||
|
||||
====== ====== ====== ====== ======
|
||||
Slot 0 1 2 3
|
||||
------ ------ ------ ------ ------
|
||||
Signal Pin Pin Pin Pin
|
||||
====== ====== ====== ====== ======
|
||||
sck 6 14 18 14
|
||||
cmd 11 15
|
||||
cs 5 15
|
||||
miso 19 12
|
||||
mosi 23 13
|
||||
D0 7 2
|
||||
D1 8 4
|
||||
D2 9 12
|
||||
D3 10 13
|
||||
D4 16
|
||||
D5 17
|
||||
D6 5
|
||||
D7 18
|
||||
====== ====== ====== ====== ======
|
||||
|
||||
cc3200
|
||||
``````
|
||||
|
||||
You can set the pins used for SPI access by passing a tuple as the
|
||||
*pins* argument.
|
||||
|
||||
*Note:* The current cc3200 SD card implementation names the this class
|
||||
:class:`machine.SD` rather than :class:`machine.SDCard` .
|
||||
@ -11,25 +11,39 @@ SS (Slave Select), to select a particular device on a bus with which
|
||||
communication takes place. Management of an SS signal should happen in
|
||||
user code (via machine.Pin class).
|
||||
|
||||
Both hardware and software SPI implementations exist via the
|
||||
:ref:`machine.SPI <machine.SPI>` and `machine.SoftSPI` classes. Hardware SPI uses underlying
|
||||
hardware support of the system to perform the reads/writes and is usually
|
||||
efficient and fast but may have restrictions on which pins can be used.
|
||||
Software SPI is implemented by bit-banging and can be used on any pin but
|
||||
is not as efficient. These classes have the same methods available and
|
||||
differ primarily in the way they are constructed.
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. class:: SPI(id, ...)
|
||||
|
||||
Construct an SPI object on the given bus, ``id``. Values of ``id`` depend
|
||||
Construct an SPI object on the given bus, *id*. Values of *id* depend
|
||||
on a particular port and its hardware. Values 0, 1, etc. are commonly used
|
||||
to select hardware SPI block #0, #1, etc. Value -1 can be used for
|
||||
bitbanging (software) implementation of SPI (if supported by a port).
|
||||
to select hardware SPI block #0, #1, etc.
|
||||
|
||||
With no additional parameters, the SPI object is created but not
|
||||
initialised (it has the settings from the last initialisation of
|
||||
the bus, if any). If extra arguments are given, the bus is initialised.
|
||||
See ``init`` for parameters of initialisation.
|
||||
|
||||
.. _machine.SoftSPI:
|
||||
.. class:: SoftSPI(baudrate=500000, *, polarity=0, phase=0, bits=8, firstbit=MSB, sck=None, mosi=None, miso=None)
|
||||
|
||||
Construct a new software SPI object. Additional parameters must be
|
||||
given, usually at least *sck*, *mosi* and *miso*, and these are used
|
||||
to initialise the bus. See `SPI.init` for a description of the parameters.
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. method:: SPI.init(baudrate=1000000, \*, polarity=0, phase=0, bits=8, firstbit=SPI.MSB, sck=None, mosi=None, miso=None, pins=(SCK, MOSI, MISO))
|
||||
.. method:: SPI.init(baudrate=1000000, *, polarity=0, phase=0, bits=8, firstbit=SPI.MSB, sck=None, mosi=None, miso=None, pins=(SCK, MOSI, MISO))
|
||||
|
||||
Initialise the SPI bus with the given parameters:
|
||||
|
||||
@ -47,6 +61,10 @@ Methods
|
||||
- ``pins`` - WiPy port doesn't ``sck``, ``mosi``, ``miso`` arguments, and instead allows to
|
||||
specify them as a tuple of ``pins`` parameter.
|
||||
|
||||
In the case of hardware SPI the actual clock frequency may be lower than the
|
||||
requested baudrate. This is dependant on the platform hardware. The actual
|
||||
rate may be determined by printing the SPI object.
|
||||
|
||||
.. method:: SPI.deinit()
|
||||
|
||||
Turn off the SPI bus.
|
||||
|
||||
@ -55,7 +55,7 @@ Following is the guide when Signal vs Pin should be used:
|
||||
* Use Pin: If you implement a higher-level protocol or bus to communicate
|
||||
with more complex devices.
|
||||
|
||||
The split between Pin and Signal come from the usecases above and the
|
||||
The split between Pin and Signal come from the use cases above and the
|
||||
architecture of MicroPython: Pin offers the lowest overhead, which may
|
||||
be important when bit-banging protocols. But Signal adds additional
|
||||
flexibility on top of Pin, at the cost of minor overhead (much smaller
|
||||
@ -75,7 +75,7 @@ Constructors
|
||||
------------
|
||||
|
||||
.. class:: Signal(pin_obj, invert=False)
|
||||
Signal(pin_arguments..., \*, invert=False)
|
||||
Signal(pin_arguments..., *, invert=False)
|
||||
|
||||
Create a Signal object. There're two ways to create it:
|
||||
|
||||
|
||||
@ -21,6 +21,9 @@ Timer callbacks.
|
||||
:func:`micropython.alloc_emergency_exception_buf` for how to get around this
|
||||
limitation.
|
||||
|
||||
If you are using a WiPy board please refer to :ref:`machine.TimerWiPy <machine.TimerWiPy>`
|
||||
instead of this class.
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
@ -28,133 +31,36 @@ Constructors
|
||||
|
||||
Construct a new timer object of the given id. Id of -1 constructs a
|
||||
virtual timer (if supported by a board).
|
||||
|
||||
See ``init`` for parameters of initialisation.
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. only:: port_wipy
|
||||
.. method:: Timer.init(*, mode=Timer.PERIODIC, period=-1, callback=None)
|
||||
|
||||
.. method:: Timer.init(mode, \*, width=16)
|
||||
Initialise the timer. Example::
|
||||
|
||||
Initialise the timer. Example::
|
||||
tim.init(period=100) # periodic with 100ms period
|
||||
tim.init(mode=Timer.ONE_SHOT, period=1000) # one shot firing after 1000ms
|
||||
|
||||
tim.init(Timer.PERIODIC) # periodic 16-bit timer
|
||||
tim.init(Timer.ONE_SHOT, width=32) # one shot 32-bit timer
|
||||
Keyword arguments:
|
||||
|
||||
Keyword arguments:
|
||||
|
||||
- ``mode`` can be one of:
|
||||
|
||||
- ``Timer.ONE_SHOT`` - The timer runs once until the configured
|
||||
period of the channel expires.
|
||||
- ``Timer.PERIODIC`` - The timer runs periodically at the configured
|
||||
frequency of the channel.
|
||||
- ``Timer.PWM`` - Output a PWM signal on a pin.
|
||||
- ``mode`` can be one of:
|
||||
|
||||
- ``width`` must be either 16 or 32 (bits). For really low frequencies < 5Hz
|
||||
(or large periods), 32-bit timers should be used. 32-bit mode is only available
|
||||
for ``ONE_SHOT`` AND ``PERIODIC`` modes.
|
||||
- ``Timer.ONE_SHOT`` - The timer runs once until the configured
|
||||
period of the channel expires.
|
||||
- ``Timer.PERIODIC`` - The timer runs periodically at the configured
|
||||
frequency of the channel.
|
||||
|
||||
.. method:: Timer.deinit()
|
||||
|
||||
Deinitialises the timer. Stops the timer, and disables the timer peripheral.
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
.. method:: Timer.channel(channel, \**, freq, period, polarity=Timer.POSITIVE, duty_cycle=0)
|
||||
|
||||
If only a channel identifier passed, then a previously initialized channel
|
||||
object is returned (or ``None`` if there is no previous channel).
|
||||
|
||||
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.
|
||||
|
||||
- ``channel`` if the width of the timer is 16-bit, then must be either ``TIMER.A``, ``TIMER.B``.
|
||||
If the width is 32-bit then it **must be** ``TIMER.A | TIMER.B``.
|
||||
|
||||
Keyword only arguments:
|
||||
|
||||
- ``freq`` sets the frequency in Hz.
|
||||
- ``period`` sets the period in microseconds.
|
||||
|
||||
.. note::
|
||||
|
||||
Either ``freq`` or ``period`` must be given, never both.
|
||||
|
||||
- ``polarity`` this is applicable for ``PWM``, and defines the polarity of the duty cycle
|
||||
- ``duty_cycle`` only applicable to ``PWM``. It's a percentage (0.00-100.00). Since the WiPy
|
||||
doesn't support floating point numbers the duty cycle must be specified in the range 0-10000,
|
||||
where 10000 would represent 100.00, 5050 represents 50.50, and so on.
|
||||
|
||||
.. note::
|
||||
|
||||
When the channel is in PWM mode, the corresponding pin is assigned automatically, therefore
|
||||
there's no need to assign the alternate function of the pin via the ``Pin`` class. The pins which
|
||||
support PWM functionality are the following:
|
||||
|
||||
- ``GP24`` on Timer 0 channel A.
|
||||
- ``GP25`` on Timer 1 channel A.
|
||||
- ``GP9`` on Timer 2 channel B.
|
||||
- ``GP10`` on Timer 3 channel A.
|
||||
- ``GP11`` on Timer 3 channel B.
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
class TimerChannel --- setup a channel for a timer
|
||||
==================================================
|
||||
|
||||
Timer channels are used to generate/capture a signal using a timer.
|
||||
|
||||
TimerChannel objects are created using the Timer.channel() method.
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. method:: timerchannel.irq(\*, trigger, priority=1, handler=None)
|
||||
|
||||
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
|
||||
with the configured frequency or period.
|
||||
- If mode is ``Timer.ONE_SHOT`` the callback is executed once when
|
||||
the configured timer expires.
|
||||
- If mode is ``Timer.PWM`` the callback is executed when reaching the duty
|
||||
cycle value.
|
||||
|
||||
The accepted params are:
|
||||
|
||||
- ``priority`` level of the interrupt. Can take values in the range 1-7.
|
||||
Higher values represent higher priorities.
|
||||
- ``handler`` is an optional function to be called when the interrupt is triggered.
|
||||
- ``trigger`` must be ``Timer.TIMEOUT`` when the operating mode is either ``Timer.PERIODIC`` or
|
||||
``Timer.ONE_SHOT``. In the case that mode is ``Timer.PWM`` then trigger must be equal to
|
||||
``Timer.MATCH``.
|
||||
|
||||
Returns a callback object.
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
.. method:: timerchannel.freq([value])
|
||||
|
||||
Get or set the timer channel frequency (in Hz).
|
||||
|
||||
.. method:: timerchannel.period([value])
|
||||
|
||||
Get or set the timer channel period (in microseconds).
|
||||
|
||||
.. method:: timerchannel.duty_cycle([value])
|
||||
|
||||
Get or set the duty cycle of the PWM signal. It's a percentage (0.00-100.00). Since the WiPy
|
||||
doesn't support floating point numbers the duty cycle must be specified in the range 0-10000,
|
||||
where 10000 would represent 100.00, 5050 represents 50.50, and so on.
|
||||
|
||||
Constants
|
||||
---------
|
||||
|
||||
.. data:: Timer.ONE_SHOT
|
||||
.. data:: Timer.PERIODIC
|
||||
Timer.PERIODIC
|
||||
|
||||
Timer operating mode.
|
||||
|
||||
159
docs/library/machine.TimerWiPy.rst
Normal file
159
docs/library/machine.TimerWiPy.rst
Normal file
@ -0,0 +1,159 @@
|
||||
.. currentmodule:: machine
|
||||
.. _machine.TimerWiPy:
|
||||
|
||||
class TimerWiPy -- control hardware timers
|
||||
==========================================
|
||||
|
||||
.. note::
|
||||
|
||||
This class is a non-standard Timer implementation for the WiPy.
|
||||
It is available simply as ``machine.Timer`` on the WiPy but is named in the
|
||||
documentation below as ``machine.TimerWiPy`` to distinguish it from the
|
||||
more general :ref:`machine.Timer <machine.Timer>` class.
|
||||
|
||||
Hardware timers deal with timing of periods and events. Timers are perhaps
|
||||
the most flexible and heterogeneous kind of hardware in MCUs and SoCs,
|
||||
differently greatly from a model to a model. MicroPython's Timer class
|
||||
defines a baseline operation of executing a callback with a given period
|
||||
(or once after some delay), and allow specific boards to define more
|
||||
non-standard behavior (which thus won't be portable to other boards).
|
||||
|
||||
See discussion of :ref:`important constraints <machine_callbacks>` on
|
||||
Timer callbacks.
|
||||
|
||||
.. note::
|
||||
|
||||
Memory can't be allocated inside irq handlers (an interrupt) and so
|
||||
exceptions raised within a handler don't give much information. See
|
||||
:func:`micropython.alloc_emergency_exception_buf` for how to get around this
|
||||
limitation.
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. class:: TimerWiPy(id, ...)
|
||||
|
||||
Construct a new timer object of the given id. Id of -1 constructs a
|
||||
virtual timer (if supported by a board).
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. method:: TimerWiPy.init(mode, *, width=16)
|
||||
|
||||
Initialise the timer. Example::
|
||||
|
||||
tim.init(Timer.PERIODIC) # periodic 16-bit timer
|
||||
tim.init(Timer.ONE_SHOT, width=32) # one shot 32-bit timer
|
||||
|
||||
Keyword arguments:
|
||||
|
||||
- ``mode`` can be one of:
|
||||
|
||||
- ``TimerWiPy.ONE_SHOT`` - The timer runs once until the configured
|
||||
period of the channel expires.
|
||||
- ``TimerWiPy.PERIODIC`` - The timer runs periodically at the configured
|
||||
frequency of the channel.
|
||||
- ``TimerWiPy.PWM`` - Output a PWM signal on a pin.
|
||||
|
||||
- ``width`` must be either 16 or 32 (bits). For really low frequencies < 5Hz
|
||||
(or large periods), 32-bit timers should be used. 32-bit mode is only available
|
||||
for ``ONE_SHOT`` AND ``PERIODIC`` modes.
|
||||
|
||||
.. method:: TimerWiPy.deinit()
|
||||
|
||||
Deinitialises the timer. Stops the timer, and disables the timer peripheral.
|
||||
|
||||
.. method:: TimerWiPy.channel(channel, **, freq, period, polarity=TimerWiPy.POSITIVE, duty_cycle=0)
|
||||
|
||||
If only a channel identifier passed, then a previously initialized channel
|
||||
object is returned (or ``None`` if there is no previous channel).
|
||||
|
||||
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.
|
||||
|
||||
- ``channel`` if the width of the timer is 16-bit, then must be either ``TIMER.A``, ``TIMER.B``.
|
||||
If the width is 32-bit then it **must be** ``TIMER.A | TIMER.B``.
|
||||
|
||||
Keyword only arguments:
|
||||
|
||||
- ``freq`` sets the frequency in Hz.
|
||||
- ``period`` sets the period in microseconds.
|
||||
|
||||
.. note::
|
||||
|
||||
Either ``freq`` or ``period`` must be given, never both.
|
||||
|
||||
- ``polarity`` this is applicable for ``PWM``, and defines the polarity of the duty cycle
|
||||
- ``duty_cycle`` only applicable to ``PWM``. It's a percentage (0.00-100.00). Since the WiPy
|
||||
doesn't support floating point numbers the duty cycle must be specified in the range 0-10000,
|
||||
where 10000 would represent 100.00, 5050 represents 50.50, and so on.
|
||||
|
||||
.. note::
|
||||
|
||||
When the channel is in PWM mode, the corresponding pin is assigned automatically, therefore
|
||||
there's no need to assign the alternate function of the pin via the ``Pin`` class. The pins which
|
||||
support PWM functionality are the following:
|
||||
|
||||
- ``GP24`` on Timer 0 channel A.
|
||||
- ``GP25`` on Timer 1 channel A.
|
||||
- ``GP9`` on Timer 2 channel B.
|
||||
- ``GP10`` on Timer 3 channel A.
|
||||
- ``GP11`` on Timer 3 channel B.
|
||||
|
||||
class TimerChannel --- setup a channel for a timer
|
||||
==================================================
|
||||
|
||||
Timer channels are used to generate/capture a signal using a timer.
|
||||
|
||||
TimerChannel objects are created using the Timer.channel() method.
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. method:: timerchannel.irq(*, trigger, priority=1, handler=None)
|
||||
|
||||
The behavior of this callback is heavily dependent on the operating
|
||||
mode of the timer channel:
|
||||
|
||||
- If mode is ``TimerWiPy.PERIODIC`` the callback is executed periodically
|
||||
with the configured frequency or period.
|
||||
- If mode is ``TimerWiPy.ONE_SHOT`` the callback is executed once when
|
||||
the configured timer expires.
|
||||
- If mode is ``TimerWiPy.PWM`` the callback is executed when reaching the duty
|
||||
cycle value.
|
||||
|
||||
The accepted params are:
|
||||
|
||||
- ``priority`` level of the interrupt. Can take values in the range 1-7.
|
||||
Higher values represent higher priorities.
|
||||
- ``handler`` is an optional function to be called when the interrupt is triggered.
|
||||
- ``trigger`` must be ``TimerWiPy.TIMEOUT`` when the operating mode is either ``TimerWiPy.PERIODIC`` or
|
||||
``TimerWiPy.ONE_SHOT``. In the case that mode is ``TimerWiPy.PWM`` then trigger must be equal to
|
||||
``TimerWiPy.MATCH``.
|
||||
|
||||
Returns a callback object.
|
||||
|
||||
.. method:: timerchannel.freq([value])
|
||||
|
||||
Get or set the timer channel frequency (in Hz).
|
||||
|
||||
.. method:: timerchannel.period([value])
|
||||
|
||||
Get or set the timer channel period (in microseconds).
|
||||
|
||||
.. method:: timerchannel.duty_cycle([value])
|
||||
|
||||
Get or set the duty cycle of the PWM signal. It's a percentage (0.00-100.00). Since the WiPy
|
||||
doesn't support floating point numbers the duty cycle must be specified in the range 0-10000,
|
||||
where 10000 would represent 100.00, 5050 represents 50.50, and so on.
|
||||
|
||||
Constants
|
||||
---------
|
||||
|
||||
.. data:: TimerWiPy.ONE_SHOT
|
||||
.. data:: TimerWiPy.PERIODIC
|
||||
|
||||
Timer operating mode.
|
||||
@ -43,21 +43,32 @@ Constructors
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. only:: port_wipy
|
||||
.. method:: UART.init(baudrate=9600, bits=8, parity=None, stop=1, *, ...)
|
||||
|
||||
.. method:: UART.init(baudrate=9600, bits=8, parity=None, stop=1, \*, pins=(TX, RX, RTS, CTS))
|
||||
|
||||
Initialise the UART bus with the given parameters:
|
||||
|
||||
- ``baudrate`` is the clock rate.
|
||||
- ``bits`` is the number of bits per character, 7, 8 or 9.
|
||||
- ``parity`` is the parity, ``None``, 0 (even) or 1 (odd).
|
||||
- ``stop`` is the number of stop bits, 1 or 2.
|
||||
- ``pins`` is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order).
|
||||
Any of the pins can be None if one wants the UART to operate with limited functionality.
|
||||
If the RTS pin is given the the RX pin must be given as well. The same applies to CTS.
|
||||
When no pins are given, then the default set of TX and RX pins is taken, and hardware
|
||||
flow control will be disabled. If pins=None, no pin assignment will be made.
|
||||
Initialise the UART bus with the given parameters:
|
||||
|
||||
- *baudrate* is the clock rate.
|
||||
- *bits* is the number of bits per character, 7, 8 or 9.
|
||||
- *parity* is the parity, ``None``, 0 (even) or 1 (odd).
|
||||
- *stop* is the number of stop bits, 1 or 2.
|
||||
|
||||
Additional keyword-only parameters that may be supported by a port are:
|
||||
|
||||
- *tx* specifies the TX pin to use.
|
||||
- *rx* specifies the RX pin to use.
|
||||
- *txbuf* specifies the length in characters of the TX buffer.
|
||||
- *rxbuf* specifies the length in characters of the RX buffer.
|
||||
- *timeout* specifies the time to wait for the first character (in ms).
|
||||
- *timeout_char* specifies the time to wait between characters (in ms).
|
||||
- *invert* specifies which lines to invert.
|
||||
|
||||
On the WiPy only the following keyword-only parameter is supported:
|
||||
|
||||
- *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order).
|
||||
Any of the pins can be None if one wants the UART to operate with limited functionality.
|
||||
If the RTS pin is given the the RX pin must be given as well. The same applies to CTS.
|
||||
When no pins are given, then the default set of TX and RX pins is taken, and hardware
|
||||
flow control will be disabled. If *pins* is ``None``, no pin assignment will be made.
|
||||
|
||||
.. method:: UART.deinit()
|
||||
|
||||
@ -79,7 +90,8 @@ Methods
|
||||
.. method:: UART.read([nbytes])
|
||||
|
||||
Read characters. If ``nbytes`` is specified then read at most that many bytes,
|
||||
otherwise read as much data as possible.
|
||||
otherwise read as much data as possible. It may return sooner if a timeout
|
||||
is reached. The timeout is configurable in the constructor.
|
||||
|
||||
Return value: a bytes object containing the bytes read in. Returns ``None``
|
||||
on timeout.
|
||||
@ -87,14 +99,16 @@ Methods
|
||||
.. method:: UART.readinto(buf[, nbytes])
|
||||
|
||||
Read bytes into the ``buf``. If ``nbytes`` is specified then read at most
|
||||
that many bytes. Otherwise, read at most ``len(buf)`` bytes.
|
||||
that many bytes. Otherwise, read at most ``len(buf)`` bytes. It may return sooner if a timeout
|
||||
is reached. The timeout is configurable in the constructor.
|
||||
|
||||
Return value: number of bytes read and stored into ``buf`` or ``None`` on
|
||||
timeout.
|
||||
|
||||
.. method:: UART.readline()
|
||||
|
||||
Read a line, ending in a newline character.
|
||||
Read a line, ending in a newline character. It may return sooner if a timeout
|
||||
is reached. The timeout is configurable in the constructor.
|
||||
|
||||
Return value: the line read or ``None`` on timeout.
|
||||
|
||||
@ -109,34 +123,36 @@ Methods
|
||||
Send a break condition on the bus. This drives the bus low for a duration
|
||||
longer than required for a normal transmission of a character.
|
||||
|
||||
.. only:: port_wipy
|
||||
.. method:: UART.irq(trigger, priority=1, handler=None, wake=machine.IDLE)
|
||||
|
||||
.. method:: UART.irq(trigger, priority=1, handler=None, wake=machine.IDLE)
|
||||
Create a callback to be triggered when data is received on the UART.
|
||||
|
||||
Create a callback to be triggered when data is received on the UART.
|
||||
- *trigger* can only be ``UART.RX_ANY``
|
||||
- *priority* level of the interrupt. Can take values in the range 1-7.
|
||||
Higher values represent higher priorities.
|
||||
- *handler* an optional function to be called when new characters arrive.
|
||||
- *wake* can only be ``machine.IDLE``.
|
||||
|
||||
- ``trigger`` can only be ``UART.RX_ANY``
|
||||
- ``priority`` level of the interrupt. Can take values in the range 1-7.
|
||||
Higher values represent higher priorities.
|
||||
- ``handler`` an optional function to be called when new characters arrive.
|
||||
- ``wake`` can only be ``machine.IDLE``.
|
||||
.. note::
|
||||
|
||||
.. note::
|
||||
The handler will be called whenever any of the following two conditions are met:
|
||||
|
||||
The handler will be called whenever any of the following two conditions are met:
|
||||
- 8 new characters have been received.
|
||||
- At least 1 new character is waiting in the Rx buffer and the Rx line has been
|
||||
silent for the duration of 1 complete frame.
|
||||
|
||||
- 8 new characters have been received.
|
||||
- At least 1 new character is waiting in the Rx buffer and the Rx line has been
|
||||
silent for the duration of 1 complete frame.
|
||||
This means that when the handler function is called there will be between 1 to 8
|
||||
characters waiting.
|
||||
|
||||
This means that when the handler function is called there will be between 1 to 8
|
||||
characters waiting.
|
||||
Returns an irq object.
|
||||
|
||||
Returns an irq object.
|
||||
Availability: WiPy.
|
||||
|
||||
Constants
|
||||
---------
|
||||
Constants
|
||||
---------
|
||||
|
||||
.. data:: UART.RX_ANY
|
||||
.. data:: UART.RX_ANY
|
||||
|
||||
IRQ trigger sources
|
||||
IRQ trigger sources
|
||||
|
||||
Availability: WiPy.
|
||||
|
||||
@ -15,16 +15,18 @@ Example usage::
|
||||
wdt = WDT(timeout=2000) # enable it with a timeout of 2s
|
||||
wdt.feed()
|
||||
|
||||
Availability of this class: pyboard, WiPy.
|
||||
Availability of this class: pyboard, WiPy, esp8266, esp32.
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. class:: WDT(id=0, timeout=5000)
|
||||
|
||||
Create a WDT object and start it. The timeout must be given in seconds and
|
||||
the minimum value that is accepted is 1 second. Once it is running the timeout
|
||||
cannot be changed and the WDT cannot be stopped either.
|
||||
Create a WDT object and start it. The timeout must be given in milliseconds.
|
||||
Once it is running the timeout cannot be changed and the WDT cannot be stopped either.
|
||||
|
||||
Notes: On the esp32 the minimum timeout is 1 second. On the esp8266 a timeout
|
||||
cannot be specified, it is determined by the underlying system.
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
@ -27,6 +27,12 @@ Reset related functions
|
||||
Resets the device in a manner similar to pushing the external RESET
|
||||
button.
|
||||
|
||||
.. function:: soft_reset()
|
||||
|
||||
Performs a soft reset of the interpreter, deleting all Python objects and
|
||||
resetting the Python heap. It tries to retain the method by which the user
|
||||
is connected to the MicroPython REPL (eg serial, USB, Wifi).
|
||||
|
||||
.. function:: reset_cause()
|
||||
|
||||
Get the reset cause. See :ref:`constants <machine_constants>` for the possible return values.
|
||||
@ -63,32 +69,41 @@ Power related functions
|
||||
|
||||
.. function:: sleep()
|
||||
|
||||
Stops the CPU and disables all peripherals except for WLAN. Execution is resumed from
|
||||
the point where the sleep was requested. For wake up to actually happen, wake sources
|
||||
should be configured first.
|
||||
.. note:: This function is deprecated, use `lightsleep()` instead with no arguments.
|
||||
|
||||
.. function:: deepsleep()
|
||||
.. function:: lightsleep([time_ms])
|
||||
deepsleep([time_ms])
|
||||
|
||||
Stops the CPU and all peripherals (including networking interfaces, if any). Execution
|
||||
is resumed from the main script, just as with a reset. The reset cause can be checked
|
||||
to know that we are coming from `machine.DEEPSLEEP`. For wake up to actually happen,
|
||||
wake sources should be configured first, like `Pin` change or `RTC` timeout.
|
||||
Stops execution in an attempt to enter a low power state.
|
||||
|
||||
.. only:: port_wipy
|
||||
If *time_ms* is specified then this will be the maximum time in milliseconds that
|
||||
the sleep will last for. Otherwise the sleep can last indefinitely.
|
||||
|
||||
.. function:: wake_reason()
|
||||
With or without a timeout, execution may resume at any time if there are events
|
||||
that require processing. Such events, or wake sources, should be configured before
|
||||
sleeping, like `Pin` change or `RTC` timeout.
|
||||
|
||||
Get the wake reason. See :ref:`constants <machine_constants>` for the possible return values.
|
||||
The precise behaviour and power-saving capabilities of lightsleep and deepsleep is
|
||||
highly dependent on the underlying hardware, but the general properties are:
|
||||
|
||||
* A lightsleep has full RAM and state retention. Upon wake execution is resumed
|
||||
from the point where the sleep was requested, with all subsystems operational.
|
||||
|
||||
* A deepsleep may not retain RAM or any other state of the system (for example
|
||||
peripherals or network interfaces). Upon wake execution is resumed from the main
|
||||
script, similar to a hard or power-on reset. The `reset_cause()` function will
|
||||
return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake
|
||||
from other resets.
|
||||
|
||||
.. function:: wake_reason()
|
||||
|
||||
Get the wake reason. See :ref:`constants <machine_constants>` for the possible return values.
|
||||
|
||||
Availability: ESP32, WiPy.
|
||||
|
||||
Miscellaneous functions
|
||||
-----------------------
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
.. function:: rng()
|
||||
|
||||
Return a 24-bit software generated random number.
|
||||
|
||||
.. function:: unique_id()
|
||||
|
||||
Returns a byte string with a unique identifier of a board/SoC. It will vary
|
||||
@ -96,7 +111,7 @@ Miscellaneous functions
|
||||
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.
|
||||
|
||||
.. function:: time_pulse_us(pin, pulse_level, timeout_us=1000000)
|
||||
.. function:: time_pulse_us(pin, pulse_level, timeout_us=1000000, /)
|
||||
|
||||
Time a pulse on the given *pin*, and return the duration of the pulse in
|
||||
microseconds. The *pulse_level* argument should be 0 to time a low pulse
|
||||
@ -112,6 +127,12 @@ Miscellaneous functions
|
||||
above. The timeout is the same for both cases and given by *timeout_us* (which
|
||||
is in microseconds).
|
||||
|
||||
.. function:: rng()
|
||||
|
||||
Return a 24-bit software generated random number.
|
||||
|
||||
Availability: WiPy.
|
||||
|
||||
.. _machine_constants:
|
||||
|
||||
Constants
|
||||
@ -140,31 +161,17 @@ Constants
|
||||
Classes
|
||||
-------
|
||||
|
||||
.. only:: not port_wipy
|
||||
|
||||
.. toctree::
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
machine.Pin.rst
|
||||
machine.Signal.rst
|
||||
machine.UART.rst
|
||||
machine.SPI.rst
|
||||
machine.I2C.rst
|
||||
machine.RTC.rst
|
||||
machine.Timer.rst
|
||||
machine.WDT.rst
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
machine.Pin.rst
|
||||
machine.UART.rst
|
||||
machine.SPI.rst
|
||||
machine.I2C.rst
|
||||
machine.RTC.rst
|
||||
machine.Timer.rst
|
||||
machine.WDT.rst
|
||||
machine.ADC.rst
|
||||
machine.UART.rst
|
||||
machine.SPI.rst
|
||||
machine.I2C.rst
|
||||
machine.RTC.rst
|
||||
machine.Timer.rst
|
||||
machine.WDT.rst
|
||||
machine.SD.rst
|
||||
machine.SDCard.rst
|
||||
|
||||
@ -82,14 +82,26 @@ Functions
|
||||
|
||||
.. function:: heap_lock()
|
||||
.. function:: heap_unlock()
|
||||
.. function:: heap_locked()
|
||||
|
||||
Lock or unlock the heap. When locked no memory allocation can occur and a
|
||||
`MemoryError` will be raised if any heap allocation is attempted.
|
||||
`heap_locked()` returns a true value if the heap is currently locked.
|
||||
|
||||
These functions can be nested, ie `heap_lock()` can be called multiple times
|
||||
in a row and the lock-depth will increase, and then `heap_unlock()` must be
|
||||
called the same number of times to make the heap available again.
|
||||
|
||||
Both `heap_unlock()` and `heap_locked()` return the current lock depth
|
||||
(after unlocking for the former) as a non-negative integer, with 0 meaning
|
||||
the heap is not locked.
|
||||
|
||||
If the REPL becomes active with the heap locked then it will be forcefully
|
||||
unlocked.
|
||||
|
||||
Note: `heap_locked()` is not enabled on most ports by default,
|
||||
requires ``MICROPY_PY_MICROPYTHON_HEAP_LOCKED``.
|
||||
|
||||
.. function:: kbd_intr(chr)
|
||||
|
||||
Set the character that will raise a `KeyboardInterrupt` exception. By
|
||||
@ -133,5 +145,5 @@ Functions
|
||||
:ref:`reference documentation <isr_rules>` under "Creation of Python
|
||||
objects".
|
||||
|
||||
There is a finite stack to hold the scheduled functions and `schedule()`
|
||||
will raise a `RuntimeError` if the stack is full.
|
||||
There is a finite queue to hold the scheduled functions and `schedule()`
|
||||
will raise a `RuntimeError` if the queue is full.
|
||||
|
||||
89
docs/library/network.CC3K.rst
Normal file
89
docs/library/network.CC3K.rst
Normal file
@ -0,0 +1,89 @@
|
||||
.. currentmodule:: network
|
||||
.. _network.CC3K:
|
||||
|
||||
class CC3K -- control CC3000 WiFi modules
|
||||
=========================================
|
||||
|
||||
This class provides a driver for CC3000 WiFi modules. Example usage::
|
||||
|
||||
import network
|
||||
nic = network.CC3K(pyb.SPI(2), pyb.Pin.board.Y5, pyb.Pin.board.Y4, pyb.Pin.board.Y3)
|
||||
nic.connect('your-ssid', 'your-password')
|
||||
while not nic.isconnected():
|
||||
pyb.delay(50)
|
||||
print(nic.ifconfig())
|
||||
|
||||
# now use socket as usual
|
||||
...
|
||||
|
||||
For this example to work the CC3000 module must have the following connections:
|
||||
|
||||
- MOSI connected to Y8
|
||||
- MISO connected to Y7
|
||||
- CLK connected to Y6
|
||||
- CS connected to Y5
|
||||
- VBEN connected to Y4
|
||||
- IRQ connected to Y3
|
||||
|
||||
It is possible to use other SPI busses and other pins for CS, VBEN and IRQ.
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. class:: CC3K(spi, pin_cs, pin_en, pin_irq)
|
||||
|
||||
Create a CC3K driver object, initialise the CC3000 module using the given SPI bus
|
||||
and pins, and return the CC3K object.
|
||||
|
||||
Arguments are:
|
||||
|
||||
- *spi* is an :ref:`SPI object <pyb.SPI>` which is the SPI bus that the CC3000 is
|
||||
connected to (the MOSI, MISO and CLK pins).
|
||||
- *pin_cs* is a :ref:`Pin object <pyb.Pin>` which is connected to the CC3000 CS pin.
|
||||
- *pin_en* is a :ref:`Pin object <pyb.Pin>` which is connected to the CC3000 VBEN pin.
|
||||
- *pin_irq* is a :ref:`Pin object <pyb.Pin>` which is connected to the CC3000 IRQ pin.
|
||||
|
||||
All of these objects will be initialised by the driver, so there is no need to
|
||||
initialise them yourself. For example, you can use::
|
||||
|
||||
nic = network.CC3K(pyb.SPI(2), pyb.Pin.board.Y5, pyb.Pin.board.Y4, pyb.Pin.board.Y3)
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. method:: CC3K.connect(ssid, key=None, *, security=WPA2, bssid=None)
|
||||
|
||||
Connect to a WiFi access point using the given SSID, and other security
|
||||
parameters.
|
||||
|
||||
.. method:: CC3K.disconnect()
|
||||
|
||||
Disconnect from the WiFi access point.
|
||||
|
||||
.. method:: CC3K.isconnected()
|
||||
|
||||
Returns True if connected to a WiFi access point and has a valid IP address,
|
||||
False otherwise.
|
||||
|
||||
.. method:: CC3K.ifconfig()
|
||||
|
||||
Returns a 7-tuple with (ip, subnet mask, gateway, DNS server, DHCP server,
|
||||
MAC address, SSID).
|
||||
|
||||
.. method:: CC3K.patch_version()
|
||||
|
||||
Return the version of the patch program (firmware) on the CC3000.
|
||||
|
||||
.. method:: CC3K.patch_program('pgm')
|
||||
|
||||
Upload the current firmware to the CC3000. You must pass 'pgm' as the first
|
||||
argument in order for the upload to proceed.
|
||||
|
||||
Constants
|
||||
---------
|
||||
|
||||
.. data:: CC3K.WEP
|
||||
.. data:: CC3K.WPA
|
||||
.. data:: CC3K.WPA2
|
||||
|
||||
security type to use
|
||||
71
docs/library/network.WIZNET5K.rst
Normal file
71
docs/library/network.WIZNET5K.rst
Normal file
@ -0,0 +1,71 @@
|
||||
.. currentmodule:: network
|
||||
.. _network.WIZNET5K:
|
||||
|
||||
class WIZNET5K -- control WIZnet5x00 Ethernet modules
|
||||
=====================================================
|
||||
|
||||
This class allows you to control WIZnet5x00 Ethernet adaptors based on
|
||||
the W5200 and W5500 chipsets. The particular chipset that is supported
|
||||
by the firmware is selected at compile-time via the MICROPY_PY_WIZNET5K
|
||||
option.
|
||||
|
||||
Example usage::
|
||||
|
||||
import network
|
||||
nic = network.WIZNET5K(pyb.SPI(1), pyb.Pin.board.X5, pyb.Pin.board.X4)
|
||||
print(nic.ifconfig())
|
||||
|
||||
# now use socket as usual
|
||||
...
|
||||
|
||||
For this example to work the WIZnet5x00 module must have the following connections:
|
||||
|
||||
- MOSI connected to X8
|
||||
- MISO connected to X7
|
||||
- SCLK connected to X6
|
||||
- nSS connected to X5
|
||||
- nRESET connected to X4
|
||||
|
||||
It is possible to use other SPI busses and other pins for nSS and nRESET.
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. class:: WIZNET5K(spi, pin_cs, pin_rst)
|
||||
|
||||
Create a WIZNET5K driver object, initialise the WIZnet5x00 module using the given
|
||||
SPI bus and pins, and return the WIZNET5K object.
|
||||
|
||||
Arguments are:
|
||||
|
||||
- *spi* is an :ref:`SPI object <pyb.SPI>` which is the SPI bus that the WIZnet5x00 is
|
||||
connected to (the MOSI, MISO and SCLK pins).
|
||||
- *pin_cs* is a :ref:`Pin object <pyb.Pin>` which is connected to the WIZnet5x00 nSS pin.
|
||||
- *pin_rst* is a :ref:`Pin object <pyb.Pin>` which is connected to the WIZnet5x00 nRESET pin.
|
||||
|
||||
All of these objects will be initialised by the driver, so there is no need to
|
||||
initialise them yourself. For example, you can use::
|
||||
|
||||
nic = network.WIZNET5K(pyb.SPI(1), pyb.Pin.board.X5, pyb.Pin.board.X4)
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. method:: WIZNET5K.isconnected()
|
||||
|
||||
Returns ``True`` if the physical Ethernet link is connected and up.
|
||||
Returns ``False`` otherwise.
|
||||
|
||||
.. method:: WIZNET5K.ifconfig([(ip, subnet, gateway, dns)])
|
||||
|
||||
Get/set IP address, subnet mask, gateway and DNS.
|
||||
|
||||
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::
|
||||
|
||||
nic.ifconfig(('192.168.0.4', '255.255.255.0', '192.168.0.1', '8.8.8.8'))
|
||||
|
||||
.. method:: WIZNET5K.regs()
|
||||
|
||||
Dump the WIZnet5x00 registers. Useful for debugging.
|
||||
132
docs/library/network.WLAN.rst
Normal file
132
docs/library/network.WLAN.rst
Normal file
@ -0,0 +1,132 @@
|
||||
.. currentmodule:: network
|
||||
.. _network.WLAN:
|
||||
|
||||
class WLAN -- control built-in WiFi interfaces
|
||||
==============================================
|
||||
|
||||
This class provides a driver for WiFi network processors. Example usage::
|
||||
|
||||
import network
|
||||
# enable station interface and connect to WiFi access point
|
||||
nic = network.WLAN(network.STA_IF)
|
||||
nic.active(True)
|
||||
nic.connect('your-ssid', 'your-password')
|
||||
# now use sockets as usual
|
||||
|
||||
Constructors
|
||||
------------
|
||||
.. class:: WLAN(interface_id)
|
||||
|
||||
Create a WLAN network interface object. Supported interfaces are
|
||||
``network.STA_IF`` (station aka client, connects to upstream WiFi access
|
||||
points) and ``network.AP_IF`` (access point, allows other WiFi clients to
|
||||
connect). Availability of the methods below depends on interface type.
|
||||
For example, only STA interface may `WLAN.connect()` to an access point.
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. method:: WLAN.active([is_active])
|
||||
|
||||
Activate ("up") or deactivate ("down") network interface, if boolean
|
||||
argument is passed. Otherwise, query current state if no argument is
|
||||
provided. Most other methods require active interface.
|
||||
|
||||
.. method:: WLAN.connect(ssid=None, password=None, *, bssid=None)
|
||||
|
||||
Connect to the specified wireless network, using the specified password.
|
||||
If *bssid* is given then the connection will be restricted to the
|
||||
access-point with that MAC address (the *ssid* must also be specified
|
||||
in this case).
|
||||
|
||||
.. method:: WLAN.disconnect()
|
||||
|
||||
Disconnect from the currently connected wireless network.
|
||||
|
||||
.. method:: WLAN.scan()
|
||||
|
||||
Scan for the available wireless networks.
|
||||
|
||||
Scanning is only possible on STA interface. Returns list of tuples with
|
||||
the information about WiFi access points:
|
||||
|
||||
(ssid, bssid, channel, RSSI, authmode, hidden)
|
||||
|
||||
*bssid* is hardware address of an access point, in binary form, returned as
|
||||
bytes object. You can use `ubinascii.hexlify()` to convert it to ASCII form.
|
||||
|
||||
There are five values for authmode:
|
||||
|
||||
* 0 -- open
|
||||
* 1 -- WEP
|
||||
* 2 -- WPA-PSK
|
||||
* 3 -- WPA2-PSK
|
||||
* 4 -- WPA/WPA2-PSK
|
||||
|
||||
and two for hidden:
|
||||
|
||||
* 0 -- visible
|
||||
* 1 -- hidden
|
||||
|
||||
.. method:: WLAN.status([param])
|
||||
|
||||
Return the current status of the wireless connection.
|
||||
|
||||
When called with no argument the return value describes the network link status.
|
||||
The possible statuses are defined as constants:
|
||||
|
||||
* ``STAT_IDLE`` -- no connection and no activity,
|
||||
* ``STAT_CONNECTING`` -- connecting in progress,
|
||||
* ``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 successful.
|
||||
|
||||
When called with one argument *param* should be a string naming the status
|
||||
parameter to retrieve. Supported parameters in WiFI STA mode are: ``'rssi'``.
|
||||
|
||||
.. method:: WLAN.isconnected()
|
||||
|
||||
In case of STA mode, returns ``True`` if connected to a WiFi access
|
||||
point and has a valid IP address. In AP mode returns ``True`` when a
|
||||
station is connected. Returns ``False`` otherwise.
|
||||
|
||||
.. method:: WLAN.ifconfig([(ip, subnet, gateway, dns)])
|
||||
|
||||
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::
|
||||
|
||||
nic.ifconfig(('192.168.0.4', '255.255.255.0', '192.168.0.1', '8.8.8.8'))
|
||||
|
||||
.. method:: WLAN.config('param')
|
||||
WLAN.config(param=value, ...)
|
||||
|
||||
Get or set general network interface parameters. These methods allow to work
|
||||
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, 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)
|
||||
# Query params one by one
|
||||
print(ap.config('essid'))
|
||||
print(ap.config('channel'))
|
||||
|
||||
Following are commonly supported parameters (availability of a specific parameter
|
||||
depends on network technology type, driver, and :term:`MicroPython port`).
|
||||
|
||||
============= ===========
|
||||
Parameter Description
|
||||
============= ===========
|
||||
mac MAC address (bytes)
|
||||
essid WiFi access point name (string)
|
||||
channel WiFi channel (integer)
|
||||
hidden Whether ESSID is hidden (boolean)
|
||||
authmode Authentication mode supported (enumeration, see module constants)
|
||||
password Access password (string)
|
||||
dhcp_hostname The DHCP hostname to use
|
||||
============= ===========
|
||||
161
docs/library/network.WLANWiPy.rst
Normal file
161
docs/library/network.WLANWiPy.rst
Normal file
@ -0,0 +1,161 @@
|
||||
.. currentmodule:: network
|
||||
.. _network.WLANWiPy:
|
||||
|
||||
class WLANWiPy -- WiPy specific WiFi control
|
||||
============================================
|
||||
|
||||
.. note::
|
||||
|
||||
This class is a non-standard WLAN implementation for the WiPy.
|
||||
It is available simply as ``network.WLAN`` on the WiPy but is named in the
|
||||
documentation below as ``network.WLANWiPy`` to distinguish it from the
|
||||
more general :ref:`network.WLAN <network.WLAN>` class.
|
||||
|
||||
This class provides a driver for the WiFi network processor in the WiPy. Example usage::
|
||||
|
||||
import network
|
||||
import time
|
||||
# setup as a station
|
||||
wlan = network.WLAN(mode=WLAN.STA)
|
||||
wlan.connect('your-ssid', auth=(WLAN.WPA2, 'your-key'))
|
||||
while not wlan.isconnected():
|
||||
time.sleep_ms(50)
|
||||
print(wlan.ifconfig())
|
||||
|
||||
# now use socket as usual
|
||||
...
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. class:: WLANWiPy(id=0, ...)
|
||||
|
||||
Create a WLAN object, and optionally configure it. See `init()` for params of configuration.
|
||||
|
||||
.. note::
|
||||
|
||||
The ``WLAN`` constructor is special in the sense that if no arguments besides the id are given,
|
||||
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.
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. method:: WLANWiPy.init(mode, *, ssid, auth, channel, antenna)
|
||||
|
||||
Set or get the WiFi network processor configuration.
|
||||
|
||||
Arguments are:
|
||||
|
||||
- *mode* can be either ``WLAN.STA`` or ``WLAN.AP``.
|
||||
- *ssid* is a string with the ssid name. Only needed when mode is ``WLAN.AP``.
|
||||
- *auth* is a tuple with (sec, key). Security can be ``None``, ``WLAN.WEP``,
|
||||
``WLAN.WPA`` or ``WLAN.WPA2``. The key is a string with the network password.
|
||||
If ``sec`` is ``WLAN.WEP`` the key must be a string representing hexadecimal
|
||||
values (e.g. 'ABC1DE45BF'). Only needed when mode is ``WLAN.AP``.
|
||||
- *channel* a number in the range 1-11. Only needed when mode is ``WLAN.AP``.
|
||||
- *antenna* selects between the internal and the external antenna. Can be either
|
||||
``WLAN.INT_ANT`` or ``WLAN.EXT_ANT``.
|
||||
|
||||
For example, you can do::
|
||||
|
||||
# create and configure as an access point
|
||||
wlan.init(mode=WLAN.AP, ssid='wipy-wlan', auth=(WLAN.WPA2,'www.wipy.io'), channel=7, antenna=WLAN.INT_ANT)
|
||||
|
||||
or::
|
||||
|
||||
# configure as an station
|
||||
wlan.init(mode=WLAN.STA)
|
||||
|
||||
.. method:: WLANWiPy.connect(ssid, *, auth=None, bssid=None, timeout=None)
|
||||
|
||||
Connect to a WiFi access point using the given SSID, and other security
|
||||
parameters.
|
||||
|
||||
- *auth* is a tuple with (sec, key). Security can be ``None``, ``WLAN.WEP``,
|
||||
``WLAN.WPA`` or ``WLAN.WPA2``. The key is a string with the network password.
|
||||
If ``sec`` is ``WLAN.WEP`` the key must be a string representing hexadecimal
|
||||
values (e.g. 'ABC1DE45BF').
|
||||
- *bssid* is the MAC address of the AP to connect to. Useful when there are several
|
||||
APs with the same ssid.
|
||||
- *timeout* is the maximum time in milliseconds to wait for the connection to succeed.
|
||||
|
||||
.. method:: WLANWiPy.scan()
|
||||
|
||||
Performs a network scan and returns a list of named tuples with (ssid, bssid, sec, channel, rssi).
|
||||
Note that channel is always ``None`` since this info is not provided by the WiPy.
|
||||
|
||||
.. method:: WLANWiPy.disconnect()
|
||||
|
||||
Disconnect from the WiFi access point.
|
||||
|
||||
.. method:: WLANWiPy.isconnected()
|
||||
|
||||
In case of STA mode, returns ``True`` if connected to a WiFi access point and has a valid IP address.
|
||||
In AP mode returns ``True`` when a station is connected, ``False`` otherwise.
|
||||
|
||||
.. method:: WLANWiPy.ifconfig(if_id=0, config=['dhcp' or configtuple])
|
||||
|
||||
With no parameters given returns a 4-tuple of *(ip, subnet_mask, gateway, DNS_server)*.
|
||||
|
||||
if ``'dhcp'`` is passed as a parameter then the DHCP client is enabled and the IP params
|
||||
are negotiated with the AP.
|
||||
|
||||
If the 4-tuple config is given then a static IP is configured. For instance::
|
||||
|
||||
wlan.ifconfig(config=('192.168.0.4', '255.255.255.0', '192.168.0.1', '8.8.8.8'))
|
||||
|
||||
.. method:: WLANWiPy.mode([mode])
|
||||
|
||||
Get or set the WLAN mode.
|
||||
|
||||
.. method:: WLANWiPy.ssid([ssid])
|
||||
|
||||
Get or set the SSID when in AP mode.
|
||||
|
||||
.. method:: WLANWiPy.auth([auth])
|
||||
|
||||
Get or set the authentication type when in AP mode.
|
||||
|
||||
.. method:: WLANWiPy.channel([channel])
|
||||
|
||||
Get or set the channel (only applicable in AP mode).
|
||||
|
||||
.. method:: WLANWiPy.antenna([antenna])
|
||||
|
||||
Get or set the antenna type (external or internal).
|
||||
|
||||
.. method:: WLANWiPy.mac([mac_addr])
|
||||
|
||||
Get or set a 6-byte long bytes object with the MAC address.
|
||||
|
||||
.. method:: WLANWiPy.irq(*, handler, wake)
|
||||
|
||||
Create a callback to be triggered when a WLAN event occurs during ``machine.SLEEP``
|
||||
mode. Events are triggered by socket activity or by WLAN connection/disconnection.
|
||||
|
||||
- *handler* is the function that gets called when the IRQ is triggered.
|
||||
- *wake* must be ``machine.SLEEP``.
|
||||
|
||||
Returns an IRQ object.
|
||||
|
||||
Constants
|
||||
---------
|
||||
|
||||
.. data:: WLANWiPy.STA
|
||||
.. data:: WLANWiPy.AP
|
||||
|
||||
selects the WLAN mode
|
||||
|
||||
.. data:: WLANWiPy.WEP
|
||||
.. data:: WLANWiPy.WPA
|
||||
.. data:: WLANWiPy.WPA2
|
||||
|
||||
selects the network security
|
||||
|
||||
.. data:: WLANWiPy.INT_ANT
|
||||
.. data:: WLANWiPy.EXT_ANT
|
||||
|
||||
selects the antenna type
|
||||
@ -39,7 +39,7 @@ Common network adapter interface
|
||||
================================
|
||||
|
||||
This section describes an (implied) abstract base class for all network
|
||||
interface classes implemented by `MicroPython ports <MicroPython port>`
|
||||
interface classes implemented by :term:`MicroPython ports <MicroPython port>`
|
||||
for different hardware. This means that MicroPython does not actually
|
||||
provide ``AbstractNIC`` class, but any actual NIC class, as described
|
||||
in the following sections, implements methods as described here.
|
||||
@ -50,7 +50,7 @@ Instantiate a network interface object. Parameters are network interface
|
||||
dependent. If there are more than one interface of the same type, the first
|
||||
parameter should be `id`.
|
||||
|
||||
.. method:: active([is_active])
|
||||
.. method:: AbstractNIC.active([is_active])
|
||||
|
||||
Activate ("up") or deactivate ("down") the network interface, if
|
||||
a boolean argument is passed. Otherwise, query current state if
|
||||
@ -58,7 +58,7 @@ parameter should be `id`.
|
||||
interface (behavior of calling them on inactive interface is
|
||||
undefined).
|
||||
|
||||
.. method:: connect([service_id, key=None, \*, ...])
|
||||
.. method:: AbstractNIC.connect([service_id, key=None, *, ...])
|
||||
|
||||
Connect the interface to a network. This method is optional, and
|
||||
available only for interfaces which are not "always connected".
|
||||
@ -68,21 +68,21 @@ parameter should be `id`.
|
||||
(password) required to access said service. There can be further
|
||||
arbitrary keyword-only parameters, depending on the networking medium
|
||||
type and/or particular device. Parameters can be used to: a)
|
||||
specify alternative service identifer types; b) provide additional
|
||||
specify alternative service identifier types; b) provide additional
|
||||
connection parameters. For various medium types, there are different
|
||||
sets of predefined/recommended parameters, among them:
|
||||
|
||||
* WiFi: *bssid* keyword to connect to a specific BSSID (MAC address)
|
||||
|
||||
.. method:: disconnect()
|
||||
.. method:: AbstractNIC.disconnect()
|
||||
|
||||
Disconnect from network.
|
||||
|
||||
.. method:: isconnected()
|
||||
.. method:: AbstractNIC.isconnected()
|
||||
|
||||
Returns ``True`` if connected to network, otherwise returns ``False``.
|
||||
|
||||
.. method:: scan(\*, ...)
|
||||
.. method:: AbstractNIC.scan(*, ...)
|
||||
|
||||
Scan for the available network services/connections. Returns a
|
||||
list of tuples with discovered service parameters. For various
|
||||
@ -98,7 +98,7 @@ parameter should be `id`.
|
||||
duration and other parameters. Where possible, parameter names
|
||||
should match those in connect().
|
||||
|
||||
.. method:: status([param])
|
||||
.. method:: AbstractNIC.status([param])
|
||||
|
||||
Query dynamic status information of the interface. When called with no
|
||||
argument the return value describes the network link status. Otherwise
|
||||
@ -113,7 +113,7 @@ parameter should be `id`.
|
||||
connected to the AP. The list contains tuples of the form
|
||||
(MAC, RSSI).
|
||||
|
||||
.. method:: ifconfig([(ip, subnet, gateway, dns)])
|
||||
.. method:: AbstractNIC.ifconfig([(ip, subnet, gateway, dns)])
|
||||
|
||||
Get/set IP-level network interface parameters: IP address, subnet mask,
|
||||
gateway and DNS server. When called with no arguments, this method returns
|
||||
@ -122,8 +122,8 @@ parameter should be `id`.
|
||||
|
||||
nic.ifconfig(('192.168.0.4', '255.255.255.0', '192.168.0.1', '8.8.8.8'))
|
||||
|
||||
.. method:: config('param')
|
||||
config(param=value, ...)
|
||||
.. method:: AbstractNIC.config('param')
|
||||
AbstractNIC.config(param=value, ...)
|
||||
|
||||
Get or set general network interface parameters. These methods allow to work
|
||||
with additional parameters beyond standard IP configuration (as dealt with by
|
||||
@ -139,465 +139,35 @@ parameter should be `id`.
|
||||
print(ap.config('essid'))
|
||||
print(ap.config('channel'))
|
||||
|
||||
.. only:: port_pyboard
|
||||
Specific network class implementations
|
||||
======================================
|
||||
|
||||
class CC3K
|
||||
==========
|
||||
|
||||
This class provides a driver for CC3000 WiFi modules. Example usage::
|
||||
|
||||
import network
|
||||
nic = network.CC3K(pyb.SPI(2), pyb.Pin.board.Y5, pyb.Pin.board.Y4, pyb.Pin.board.Y3)
|
||||
nic.connect('your-ssid', 'your-password')
|
||||
while not nic.isconnected():
|
||||
pyb.delay(50)
|
||||
print(nic.ifconfig())
|
||||
|
||||
# now use socket as usual
|
||||
...
|
||||
|
||||
For this example to work the CC3000 module must have the following connections:
|
||||
|
||||
- MOSI connected to Y8
|
||||
- MISO connected to Y7
|
||||
- CLK connected to Y6
|
||||
- CS connected to Y5
|
||||
- VBEN connected to Y4
|
||||
- IRQ connected to Y3
|
||||
|
||||
It is possible to use other SPI busses and other pins for CS, VBEN and IRQ.
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. class:: CC3K(spi, pin_cs, pin_en, pin_irq)
|
||||
|
||||
Create a CC3K driver object, initialise the CC3000 module using the given SPI bus
|
||||
and pins, and return the CC3K object.
|
||||
|
||||
Arguments are:
|
||||
|
||||
- *spi* is an :ref:`SPI object <pyb.SPI>` which is the SPI bus that the CC3000 is
|
||||
connected to (the MOSI, MISO and CLK pins).
|
||||
- *pin_cs* is a :ref:`Pin object <pyb.Pin>` which is connected to the CC3000 CS pin.
|
||||
- *pin_en* is a :ref:`Pin object <pyb.Pin>` which is connected to the CC3000 VBEN pin.
|
||||
- *pin_irq* is a :ref:`Pin object <pyb.Pin>` which is connected to the CC3000 IRQ pin.
|
||||
|
||||
All of these objects will be initialised by the driver, so there is no need to
|
||||
initialise them yourself. For example, you can use::
|
||||
|
||||
nic = network.CC3K(pyb.SPI(2), pyb.Pin.board.Y5, pyb.Pin.board.Y4, pyb.Pin.board.Y3)
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. method:: cc3k.connect(ssid, key=None, \*, security=WPA2, bssid=None)
|
||||
|
||||
Connect to a WiFi access point using the given SSID, and other security
|
||||
parameters.
|
||||
|
||||
.. method:: cc3k.disconnect()
|
||||
|
||||
Disconnect from the WiFi access point.
|
||||
|
||||
.. method:: cc3k.isconnected()
|
||||
|
||||
Returns True if connected to a WiFi access point and has a valid IP address,
|
||||
False otherwise.
|
||||
|
||||
.. method:: cc3k.ifconfig()
|
||||
|
||||
Returns a 7-tuple with (ip, subnet mask, gateway, DNS server, DHCP server,
|
||||
MAC address, SSID).
|
||||
|
||||
.. method:: cc3k.patch_version()
|
||||
|
||||
Return the version of the patch program (firmware) on the CC3000.
|
||||
|
||||
.. method:: cc3k.patch_program('pgm')
|
||||
|
||||
Upload the current firmware to the CC3000. You must pass 'pgm' as the first
|
||||
argument in order for the upload to proceed.
|
||||
|
||||
Constants
|
||||
---------
|
||||
|
||||
.. data:: CC3K.WEP
|
||||
.. data:: CC3K.WPA
|
||||
.. data:: CC3K.WPA2
|
||||
|
||||
security type to use
|
||||
|
||||
class WIZNET5K
|
||||
==============
|
||||
|
||||
This class allows you to control WIZnet5x00 Ethernet adaptors based on
|
||||
the W5200 and W5500 chipsets. The particular chipset that is supported
|
||||
by the firmware is selected at compile-time via the MICROPY_PY_WIZNET5K
|
||||
option.
|
||||
|
||||
Example usage::
|
||||
|
||||
import network
|
||||
nic = network.WIZNET5K(pyb.SPI(1), pyb.Pin.board.X5, pyb.Pin.board.X4)
|
||||
print(nic.ifconfig())
|
||||
|
||||
# now use socket as usual
|
||||
...
|
||||
|
||||
For this example to work the WIZnet5x00 module must have the following connections:
|
||||
|
||||
- MOSI connected to X8
|
||||
- MISO connected to X7
|
||||
- SCLK connected to X6
|
||||
- nSS connected to X5
|
||||
- nRESET connected to X4
|
||||
|
||||
It is possible to use other SPI busses and other pins for nSS and nRESET.
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. class:: WIZNET5K(spi, pin_cs, pin_rst)
|
||||
|
||||
Create a WIZNET5K driver object, initialise the WIZnet5x00 module using the given
|
||||
SPI bus and pins, and return the WIZNET5K object.
|
||||
|
||||
Arguments are:
|
||||
|
||||
- *spi* is an :ref:`SPI object <pyb.SPI>` which is the SPI bus that the WIZnet5x00 is
|
||||
connected to (the MOSI, MISO and SCLK pins).
|
||||
- *pin_cs* is a :ref:`Pin object <pyb.Pin>` which is connected to the WIZnet5x00 nSS pin.
|
||||
- *pin_rst* is a :ref:`Pin object <pyb.Pin>` which is connected to the WIZnet5x00 nRESET pin.
|
||||
|
||||
All of these objects will be initialised by the driver, so there is no need to
|
||||
initialise them yourself. For example, you can use::
|
||||
|
||||
nic = network.WIZNET5K(pyb.SPI(1), pyb.Pin.board.X5, pyb.Pin.board.X4)
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. method:: wiznet5k.isconnected()
|
||||
The following concrete classes implement the AbstractNIC interface and
|
||||
provide a way to control networking interfaces of various kinds.
|
||||
|
||||
Returns ``True`` if the physical Ethernet link is connected and up.
|
||||
Returns ``False`` otherwise.
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
.. method:: wiznet5k.ifconfig([(ip, subnet, gateway, dns)])
|
||||
|
||||
Get/set IP address, subnet mask, gateway and DNS.
|
||||
|
||||
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::
|
||||
|
||||
nic.ifconfig(('192.168.0.4', '255.255.255.0', '192.168.0.1', '8.8.8.8'))
|
||||
|
||||
.. method:: wiznet5k.regs()
|
||||
|
||||
Dump the WIZnet5x00 registers. Useful for debugging.
|
||||
network.WLAN.rst
|
||||
network.WLANWiPy.rst
|
||||
network.CC3K.rst
|
||||
network.WIZNET5K.rst
|
||||
|
||||
.. _network.WLAN:
|
||||
Network functions
|
||||
=================
|
||||
|
||||
.. only:: port_esp8266
|
||||
The following are functions available in the network module.
|
||||
|
||||
Functions
|
||||
=========
|
||||
.. function:: phy_mode([mode])
|
||||
|
||||
.. function:: phy_mode([mode])
|
||||
Get or set the PHY mode.
|
||||
|
||||
Get or set the PHY mode.
|
||||
If the *mode* parameter is provided, sets the mode to its value. If
|
||||
the function is called without parameters, returns the current mode.
|
||||
|
||||
If the *mode* parameter is provided, sets the mode to its value. If
|
||||
the function is called without parameters, returns the current mode.
|
||||
The possible modes are defined as constants:
|
||||
* ``MODE_11B`` -- IEEE 802.11b,
|
||||
* ``MODE_11G`` -- IEEE 802.11g,
|
||||
* ``MODE_11N`` -- IEEE 802.11n.
|
||||
|
||||
The possible modes are defined as constants:
|
||||
* ``MODE_11B`` -- IEEE 802.11b,
|
||||
* ``MODE_11G`` -- IEEE 802.11g,
|
||||
* ``MODE_11N`` -- IEEE 802.11n.
|
||||
|
||||
class WLAN
|
||||
==========
|
||||
|
||||
This class provides a driver for WiFi network processor in the ESP8266. Example usage::
|
||||
|
||||
import network
|
||||
# enable station interface and connect to WiFi access point
|
||||
nic = network.WLAN(network.STA_IF)
|
||||
nic.active(True)
|
||||
nic.connect('your-ssid', 'your-password')
|
||||
# now use sockets as usual
|
||||
|
||||
Constructors
|
||||
------------
|
||||
.. class:: WLAN(interface_id)
|
||||
|
||||
Create a WLAN network interface object. Supported interfaces are
|
||||
``network.STA_IF`` (station aka client, connects to upstream WiFi access
|
||||
points) and ``network.AP_IF`` (access point, allows other WiFi clients to
|
||||
connect). Availability of the methods below depends on interface type.
|
||||
For example, only STA interface may `connect()` to an access point.
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. method:: wlan.active([is_active])
|
||||
|
||||
Activate ("up") or deactivate ("down") network interface, if boolean
|
||||
argument is passed. Otherwise, query current state if no argument is
|
||||
provided. Most other methods require active interface.
|
||||
|
||||
.. method:: wlan.connect(ssid=None, password=None, \*, bssid=None)
|
||||
|
||||
Connect to the specified wireless network, using the specified password.
|
||||
If *bssid* is given then the connection will be restricted to the
|
||||
access-point with that MAC address (the *ssid* must also be specified
|
||||
in this case).
|
||||
|
||||
.. method:: wlan.disconnect()
|
||||
|
||||
Disconnect from the currently connected wireless network.
|
||||
|
||||
.. method:: wlan.scan()
|
||||
|
||||
Scan for the available wireless networks.
|
||||
|
||||
Scanning is only possible on STA interface. Returns list of tuples with
|
||||
the information about WiFi access points:
|
||||
|
||||
(ssid, bssid, channel, RSSI, authmode, hidden)
|
||||
|
||||
*bssid* is hardware address of an access point, in binary form, returned as
|
||||
bytes object. You can use `ubinascii.hexlify()` to convert it to ASCII form.
|
||||
|
||||
There are five values for authmode:
|
||||
|
||||
* 0 -- open
|
||||
* 1 -- WEP
|
||||
* 2 -- WPA-PSK
|
||||
* 3 -- WPA2-PSK
|
||||
* 4 -- WPA/WPA2-PSK
|
||||
|
||||
and two for hidden:
|
||||
|
||||
* 0 -- visible
|
||||
* 1 -- hidden
|
||||
|
||||
.. method:: wlan.status([param])
|
||||
|
||||
Return the current status of the wireless connection.
|
||||
|
||||
When called with no argument the return value describes the network link status.
|
||||
The possible statuses are defined as constants:
|
||||
|
||||
* ``STAT_IDLE`` -- no connection and no activity,
|
||||
* ``STAT_CONNECTING`` -- connecting in progress,
|
||||
* ``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 successful.
|
||||
|
||||
When called with one argument *param* should be a string naming the status
|
||||
parameter to retrieve. Supported parameters in WiFI STA mode are: ``'rssi'``.
|
||||
|
||||
.. method:: wlan.isconnected()
|
||||
|
||||
In case of STA mode, returns ``True`` if connected to a WiFi access
|
||||
point and has a valid IP address. In AP mode returns ``True`` when a
|
||||
station is connected. Returns ``False`` otherwise.
|
||||
|
||||
.. method:: wlan.ifconfig([(ip, subnet, gateway, dns)])
|
||||
|
||||
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::
|
||||
|
||||
nic.ifconfig(('192.168.0.4', '255.255.255.0', '192.168.0.1', '8.8.8.8'))
|
||||
|
||||
.. method:: wlan.config('param')
|
||||
.. method:: wlan.config(param=value, ...)
|
||||
|
||||
Get or set general network interface parameters. These methods allow to work
|
||||
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, 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)
|
||||
# Query params one by one
|
||||
print(ap.config('essid'))
|
||||
print(ap.config('channel'))
|
||||
|
||||
Following are commonly supported parameters (availability of a specific parameter
|
||||
depends on network technology type, driver, and `MicroPython port`).
|
||||
|
||||
============= ===========
|
||||
Parameter Description
|
||||
============= ===========
|
||||
mac MAC address (bytes)
|
||||
essid WiFi access point name (string)
|
||||
channel WiFi channel (integer)
|
||||
hidden Whether ESSID is hidden (boolean)
|
||||
authmode Authentication mode supported (enumeration, see module constants)
|
||||
password Access password (string)
|
||||
dhcp_hostname The DHCP hostname to use
|
||||
============= ===========
|
||||
|
||||
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
class WLAN
|
||||
==========
|
||||
|
||||
This class provides a driver for the WiFi network processor in the WiPy. Example usage::
|
||||
|
||||
import network
|
||||
import time
|
||||
# setup as a station
|
||||
wlan = network.WLAN(mode=WLAN.STA)
|
||||
wlan.connect('your-ssid', auth=(WLAN.WPA2, 'your-key'))
|
||||
while not wlan.isconnected():
|
||||
time.sleep_ms(50)
|
||||
print(wlan.ifconfig())
|
||||
|
||||
# now use socket as usual
|
||||
...
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. class:: WLAN(id=0, ...)
|
||||
|
||||
Create a WLAN object, and optionally configure it. See `init()` for params of configuration.
|
||||
|
||||
.. note::
|
||||
|
||||
The ``WLAN`` constructor is special in the sense that if no arguments besides the id are given,
|
||||
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.
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. method:: wlan.init(mode, \*, ssid, auth, channel, antenna)
|
||||
|
||||
Set or get the WiFi network processor configuration.
|
||||
|
||||
Arguments are:
|
||||
|
||||
- *mode* can be either ``WLAN.STA`` or ``WLAN.AP``.
|
||||
- *ssid* is a string with the ssid name. Only needed when mode is ``WLAN.AP``.
|
||||
- *auth* is a tuple with (sec, key). Security can be ``None``, ``WLAN.WEP``,
|
||||
``WLAN.WPA`` or ``WLAN.WPA2``. The key is a string with the network password.
|
||||
If ``sec`` is ``WLAN.WEP`` the key must be a string representing hexadecimal
|
||||
values (e.g. 'ABC1DE45BF'). Only needed when mode is ``WLAN.AP``.
|
||||
- *channel* a number in the range 1-11. Only needed when mode is ``WLAN.AP``.
|
||||
- *antenna* selects between the internal and the external antenna. Can be either
|
||||
``WLAN.INT_ANT`` or ``WLAN.EXT_ANT``.
|
||||
|
||||
For example, you can do::
|
||||
|
||||
# create and configure as an access point
|
||||
wlan.init(mode=WLAN.AP, ssid='wipy-wlan', auth=(WLAN.WPA2,'www.wipy.io'), channel=7, antenna=WLAN.INT_ANT)
|
||||
|
||||
or::
|
||||
|
||||
# configure as an station
|
||||
wlan.init(mode=WLAN.STA)
|
||||
|
||||
.. method:: wlan.connect(ssid, \*, auth=None, bssid=None, timeout=None)
|
||||
|
||||
Connect to a WiFi access point using the given SSID, and other security
|
||||
parameters.
|
||||
|
||||
- *auth* is a tuple with (sec, key). Security can be ``None``, ``WLAN.WEP``,
|
||||
``WLAN.WPA`` or ``WLAN.WPA2``. The key is a string with the network password.
|
||||
If ``sec`` is ``WLAN.WEP`` the key must be a string representing hexadecimal
|
||||
values (e.g. 'ABC1DE45BF').
|
||||
- *bssid* is the MAC address of the AP to connect to. Useful when there are several
|
||||
APs with the same ssid.
|
||||
- *timeout* is the maximum time in milliseconds to wait for the connection to succeed.
|
||||
|
||||
.. method:: wlan.scan()
|
||||
|
||||
Performs a network scan and returns a list of named tuples with (ssid, bssid, sec, channel, rssi).
|
||||
Note that channel is always ``None`` since this info is not provided by the WiPy.
|
||||
|
||||
.. method:: wlan.disconnect()
|
||||
|
||||
Disconnect from the WiFi access point.
|
||||
|
||||
.. method:: wlan.isconnected()
|
||||
|
||||
In case of STA mode, returns ``True`` if connected to a WiFi access point and has a valid IP address.
|
||||
In AP mode returns ``True`` when a station is connected, ``False`` otherwise.
|
||||
|
||||
.. method:: wlan.ifconfig(if_id=0, config=['dhcp' or configtuple])
|
||||
|
||||
With no parameters given returns a 4-tuple of *(ip, subnet_mask, gateway, DNS_server)*.
|
||||
|
||||
if ``'dhcp'`` is passed as a parameter then the DHCP client is enabled and the IP params
|
||||
are negotiated with the AP.
|
||||
|
||||
If the 4-tuple config is given then a static IP is configured. For instance::
|
||||
|
||||
wlan.ifconfig(config=('192.168.0.4', '255.255.255.0', '192.168.0.1', '8.8.8.8'))
|
||||
|
||||
.. method:: wlan.mode([mode])
|
||||
|
||||
Get or set the WLAN mode.
|
||||
|
||||
.. method:: wlan.ssid([ssid])
|
||||
|
||||
Get or set the SSID when in AP mode.
|
||||
|
||||
.. method:: wlan.auth([auth])
|
||||
|
||||
Get or set the authentication type when in AP mode.
|
||||
|
||||
.. method:: wlan.channel([channel])
|
||||
|
||||
Get or set the channel (only applicable in AP mode).
|
||||
|
||||
.. method:: wlan.antenna([antenna])
|
||||
|
||||
Get or set the antenna type (external or internal).
|
||||
|
||||
.. method:: wlan.mac([mac_addr])
|
||||
|
||||
Get or set a 6-byte long bytes object with the MAC address.
|
||||
|
||||
.. method:: wlan.irq(\*, handler, wake)
|
||||
|
||||
Create a callback to be triggered when a WLAN event occurs during ``machine.SLEEP``
|
||||
mode. Events are triggered by socket activity or by WLAN connection/disconnection.
|
||||
|
||||
- *handler* is the function that gets called when the IRQ is triggered.
|
||||
- *wake* must be ``machine.SLEEP``.
|
||||
|
||||
Returns an IRQ object.
|
||||
|
||||
Constants
|
||||
---------
|
||||
|
||||
.. data:: WLAN.STA
|
||||
.. data:: WLAN.AP
|
||||
|
||||
selects the WLAN mode
|
||||
|
||||
.. data:: WLAN.WEP
|
||||
.. data:: WLAN.WPA
|
||||
.. data:: WLAN.WPA2
|
||||
|
||||
selects the network security
|
||||
|
||||
.. data:: WLAN.INT_ANT
|
||||
.. data:: WLAN.EXT_ANT
|
||||
|
||||
selects the antenna type
|
||||
Availability: ESP8266.
|
||||
|
||||
@ -4,173 +4,164 @@
|
||||
class ADC -- analog to digital conversion
|
||||
=========================================
|
||||
|
||||
.. only:: port_pyboard
|
||||
Usage::
|
||||
|
||||
Usage::
|
||||
import pyb
|
||||
|
||||
adc = pyb.ADC(pin) # create an analog object from a pin
|
||||
val = adc.read() # read an analog value
|
||||
|
||||
adc = pyb.ADCAll(resolution) # create an ADCAll object
|
||||
adc = pyb.ADCAll(resolution, mask) # create an ADCAll object for selected analog channels
|
||||
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
|
||||
val = adc.read_core_vref() # read MCU VREF
|
||||
val = adc.read_vref() # read MCU supply voltage
|
||||
|
||||
import pyb
|
||||
|
||||
adc = pyb.ADC(pin) # create an analog object from a pin
|
||||
val = adc.read() # read an analog value
|
||||
|
||||
adc = pyb.ADCAll(resolution) # create an ADCAll object
|
||||
adc = pyb.ADCAll(resolution, mask) # create an ADCAll object for selected analog channels
|
||||
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
|
||||
val = adc.read_core_vref() # read MCU VREF
|
||||
val = adc.read_vref() # read MCU supply voltage
|
||||
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. class:: pyb.ADC(pin)
|
||||
|
||||
.. only:: port_pyboard
|
||||
|
||||
.. class:: pyb.ADC(pin)
|
||||
|
||||
Create an ADC object associated with the given pin.
|
||||
This allows you to then read analog values on that pin.
|
||||
Create an ADC object associated with the given pin.
|
||||
This allows you to then read analog values on that pin.
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. only:: port_pyboard
|
||||
.. method:: ADC.read()
|
||||
|
||||
.. method:: ADC.read()
|
||||
Read the value on the analog pin and return it. The returned value
|
||||
will be between 0 and 4095.
|
||||
|
||||
Read the value on the analog pin and return it. The returned value
|
||||
will be between 0 and 4095.
|
||||
.. method:: ADC.read_timed(buf, timer)
|
||||
|
||||
.. method:: ADC.read_timed(buf, timer)
|
||||
|
||||
Read analog values into ``buf`` at a rate set by the ``timer`` object.
|
||||
Read analog values into ``buf`` at a rate set by the ``timer`` object.
|
||||
|
||||
``buf`` can be bytearray or array.array for example. The ADC values have
|
||||
12-bit resolution and are stored directly into ``buf`` if its element size is
|
||||
16 bits or greater. If ``buf`` has only 8-bit elements (eg a bytearray) then
|
||||
the sample resolution will be reduced to 8 bits.
|
||||
``buf`` can be bytearray or array.array for example. The ADC values have
|
||||
12-bit resolution and are stored directly into ``buf`` if its element size is
|
||||
16 bits or greater. If ``buf`` has only 8-bit elements (eg a bytearray) then
|
||||
the sample resolution will be reduced to 8 bits.
|
||||
|
||||
``timer`` should be a Timer object, and a sample is read each time the timer
|
||||
triggers. The timer must already be initialised and running at the desired
|
||||
sampling frequency.
|
||||
``timer`` should be a Timer object, and a sample is read each time the timer
|
||||
triggers. The timer must already be initialised and running at the desired
|
||||
sampling frequency.
|
||||
|
||||
To support previous behaviour of this function, ``timer`` can also be an
|
||||
integer which specifies the frequency (in Hz) to sample at. In this case
|
||||
Timer(6) will be automatically configured to run at the given frequency.
|
||||
To support previous behaviour of this function, ``timer`` can also be an
|
||||
integer which specifies the frequency (in Hz) to sample at. In this case
|
||||
Timer(6) will be automatically configured to run at the given frequency.
|
||||
|
||||
Example using a Timer object (preferred way)::
|
||||
Example using a Timer object (preferred way)::
|
||||
|
||||
adc = pyb.ADC(pyb.Pin.board.X19) # create an ADC on pin X19
|
||||
tim = pyb.Timer(6, freq=10) # create a timer running at 10Hz
|
||||
buf = bytearray(100) # creat a buffer to store the samples
|
||||
adc.read_timed(buf, tim) # sample 100 values, taking 10s
|
||||
adc = pyb.ADC(pyb.Pin.board.X19) # create an ADC on pin X19
|
||||
tim = pyb.Timer(6, freq=10) # create a timer running at 10Hz
|
||||
buf = bytearray(100) # creat a buffer to store the samples
|
||||
adc.read_timed(buf, tim) # sample 100 values, taking 10s
|
||||
|
||||
Example using an integer for the frequency::
|
||||
Example using an integer for the frequency::
|
||||
|
||||
adc = pyb.ADC(pyb.Pin.board.X19) # create an ADC on pin X19
|
||||
buf = bytearray(100) # create a buffer of 100 bytes
|
||||
adc.read_timed(buf, 10) # read analog values into buf at 10Hz
|
||||
# this will take 10 seconds to finish
|
||||
for val in buf: # loop over all values
|
||||
print(val) # print the value out
|
||||
adc = pyb.ADC(pyb.Pin.board.X19) # create an ADC on pin X19
|
||||
buf = bytearray(100) # create a buffer of 100 bytes
|
||||
adc.read_timed(buf, 10) # read analog values into buf at 10Hz
|
||||
# this will take 10 seconds to finish
|
||||
for val in buf: # loop over all values
|
||||
print(val) # print the value out
|
||||
|
||||
This function does not allocate any heap memory. It has blocking behaviour:
|
||||
it does not return to the calling program until the buffer is full.
|
||||
This function does not allocate any heap memory. It has blocking behaviour:
|
||||
it does not return to the calling program until the buffer is full.
|
||||
|
||||
.. method:: ADC.read_timed_multi((adcx, adcy, ...), (bufx, bufy, ...), timer)
|
||||
.. method:: ADC.read_timed_multi((adcx, adcy, ...), (bufx, bufy, ...), timer)
|
||||
|
||||
This is a static method. It can be used to extract relative timing or
|
||||
phase data from multiple ADC's.
|
||||
This is a static method. It can be used to extract relative timing or
|
||||
phase data from multiple ADC's.
|
||||
|
||||
It reads analog values from multiple ADC's into buffers at a rate set by
|
||||
the *timer* object. Each time the timer triggers a sample is rapidly
|
||||
read from each ADC in turn.
|
||||
It reads analog values from multiple ADC's into buffers at a rate set by
|
||||
the *timer* object. Each time the timer triggers a sample is rapidly
|
||||
read from each ADC in turn.
|
||||
|
||||
ADC and buffer instances are passed in tuples with each ADC having an
|
||||
associated buffer. All buffers must be of the same type and length and
|
||||
the number of buffers must equal the number of ADC's.
|
||||
ADC and buffer instances are passed in tuples with each ADC having an
|
||||
associated buffer. All buffers must be of the same type and length and
|
||||
the number of buffers must equal the number of ADC's.
|
||||
|
||||
Buffers can be ``bytearray`` or ``array.array`` for example. The ADC values
|
||||
have 12-bit resolution and are stored directly into the buffer if its element
|
||||
size is 16 bits or greater. If buffers have only 8-bit elements (eg a
|
||||
``bytearray``) then the sample resolution will be reduced to 8 bits.
|
||||
Buffers can be ``bytearray`` or ``array.array`` for example. The ADC values
|
||||
have 12-bit resolution and are stored directly into the buffer if its element
|
||||
size is 16 bits or greater. If buffers have only 8-bit elements (eg a
|
||||
``bytearray``) then the sample resolution will be reduced to 8 bits.
|
||||
|
||||
*timer* must be a Timer object. The timer must already be initialised
|
||||
and running at the desired sampling frequency.
|
||||
*timer* must be a Timer object. The timer must already be initialised
|
||||
and running at the desired sampling frequency.
|
||||
|
||||
Example reading 3 ADC's::
|
||||
Example reading 3 ADC's::
|
||||
|
||||
adc0 = pyb.ADC(pyb.Pin.board.X1) # Create ADC's
|
||||
adc1 = pyb.ADC(pyb.Pin.board.X2)
|
||||
adc2 = pyb.ADC(pyb.Pin.board.X3)
|
||||
tim = pyb.Timer(8, freq=100) # Create timer
|
||||
rx0 = array.array('H', (0 for i in range(100))) # ADC buffers of
|
||||
rx1 = array.array('H', (0 for i in range(100))) # 100 16-bit words
|
||||
rx2 = array.array('H', (0 for i in range(100)))
|
||||
# read analog values into buffers at 100Hz (takes one second)
|
||||
pyb.ADC.read_timed_multi((adc0, adc1, adc2), (rx0, rx1, rx2), tim)
|
||||
for n in range(len(rx0)):
|
||||
print(rx0[n], rx1[n], rx2[n])
|
||||
adc0 = pyb.ADC(pyb.Pin.board.X1) # Create ADC's
|
||||
adc1 = pyb.ADC(pyb.Pin.board.X2)
|
||||
adc2 = pyb.ADC(pyb.Pin.board.X3)
|
||||
tim = pyb.Timer(8, freq=100) # Create timer
|
||||
rx0 = array.array('H', (0 for i in range(100))) # ADC buffers of
|
||||
rx1 = array.array('H', (0 for i in range(100))) # 100 16-bit words
|
||||
rx2 = array.array('H', (0 for i in range(100)))
|
||||
# read analog values into buffers at 100Hz (takes one second)
|
||||
pyb.ADC.read_timed_multi((adc0, adc1, adc2), (rx0, rx1, rx2), tim)
|
||||
for n in range(len(rx0)):
|
||||
print(rx0[n], rx1[n], rx2[n])
|
||||
|
||||
This function does not allocate any heap memory. It has blocking behaviour:
|
||||
it does not return to the calling program until the buffers are full.
|
||||
This function does not allocate any heap memory. It has blocking behaviour:
|
||||
it does not return to the calling program until the buffers are full.
|
||||
|
||||
The function returns ``True`` if all samples were acquired with correct
|
||||
timing. At high sample rates the time taken to acquire a set of samples
|
||||
can exceed the timer period. In this case the function returns ``False``,
|
||||
indicating a loss of precision in the sample interval. In extreme cases
|
||||
samples may be missed.
|
||||
The function returns ``True`` if all samples were acquired with correct
|
||||
timing. At high sample rates the time taken to acquire a set of samples
|
||||
can exceed the timer period. In this case the function returns ``False``,
|
||||
indicating a loss of precision in the sample interval. In extreme cases
|
||||
samples may be missed.
|
||||
|
||||
The maximum rate depends on factors including the data width and the
|
||||
number of ADC's being read. In testing two ADC's were sampled at a timer
|
||||
rate of 210kHz without overrun. Samples were missed at 215kHz. For three
|
||||
ADC's the limit is around 140kHz, and for four it is around 110kHz.
|
||||
At high sample rates disabling interrupts for the duration can reduce the
|
||||
risk of sporadic data loss.
|
||||
The maximum rate depends on factors including the data width and the
|
||||
number of ADC's being read. In testing two ADC's were sampled at a timer
|
||||
rate of 210kHz without overrun. Samples were missed at 215kHz. For three
|
||||
ADC's the limit is around 140kHz, and for four it is around 110kHz.
|
||||
At high sample rates disabling interrupts for the duration can reduce the
|
||||
risk of sporadic data loss.
|
||||
|
||||
The ADCAll Object
|
||||
-----------------
|
||||
|
||||
.. only:: port_pyboard
|
||||
Instantiating this changes all masked ADC pins to analog inputs. The preprocessed MCU temperature,
|
||||
VREF and VBAT data can be accessed on ADC channels 16, 17 and 18 respectively.
|
||||
Appropriate scaling is handled according to reference voltage used (usually 3.3V).
|
||||
The temperature sensor on the chip is factory calibrated and allows to read the die temperature
|
||||
to +/- 1 degree centigrade. Although this sounds pretty accurate, don't forget that the MCU's internal
|
||||
temperature is measured. Depending on processing loads and I/O subsystems active the die temperature
|
||||
may easily be tens of degrees above ambient temperature. On the other hand a pyboard woken up after a
|
||||
long standby period will show correct ambient temperature within limits mentioned above.
|
||||
|
||||
Instantiating this changes all masked ADC pins to analog inputs. The preprocessed MCU temperature,
|
||||
VREF and VBAT data can be accessed on ADC channels 16, 17 and 18 respectively.
|
||||
Appropriate scaling is handled according to reference voltage used (usually 3.3V).
|
||||
The temperature sensor on the chip is factory calibrated and allows to read the die temperature
|
||||
to +/- 1 degree centigrade. Although this sounds pretty accurate, don't forget that the MCU's internal
|
||||
temperature is measured. Depending on processing loads and I/O subsystems active the die temperature
|
||||
may easily be tens of degrees above ambient temperature. On the other hand a pyboard woken up after a
|
||||
long standby period will show correct ambient temperature within limits mentioned above.
|
||||
The ``ADCAll`` ``read_core_vbat()``, ``read_vref()`` and ``read_core_vref()`` methods read
|
||||
the backup battery voltage, reference voltage and the (1.21V nominal) reference voltage using the
|
||||
actual supply as a reference. All results are floating point numbers giving direct voltage values.
|
||||
|
||||
The ``ADCAll`` ``read_core_vbat()``, ``read_vref()`` and ``read_core_vref()`` methods read
|
||||
the backup battery voltage, reference voltage and the (1.21V nominal) reference voltage using the
|
||||
actual supply as a reference. All results are floating point numbers giving direct voltage values.
|
||||
``read_core_vbat()`` returns the voltage of the backup battery. This voltage is also adjusted according
|
||||
to the actual supply voltage. To avoid analog input overload the battery voltage is measured
|
||||
via a voltage divider and scaled according to the divider value. To prevent excessive loads
|
||||
to the backup battery, the voltage divider is only active during ADC conversion.
|
||||
|
||||
``read_core_vbat()`` returns the voltage of the backup battery. This voltage is also adjusted according
|
||||
to the actual supply voltage. To avoid analog input overload the battery voltage is measured
|
||||
via a voltage divider and scaled according to the divider value. To prevent excessive loads
|
||||
to the backup battery, the voltage divider is only active during ADC conversion.
|
||||
``read_vref()`` is evaluated by measuring the internal voltage reference and backscale it using
|
||||
factory calibration value of the internal voltage reference. In most cases the reading would be close
|
||||
to 3.3V. If the pyboard is operated from a battery, the supply voltage may drop to values below 3.3V.
|
||||
The pyboard will still operate fine as long as the operating conditions are met. With proper settings
|
||||
of MCU clock, flash access speed and programming mode it is possible to run the pyboard down to
|
||||
2 V and still get useful ADC conversion.
|
||||
|
||||
``read_vref()`` is evaluated by measuring the internal voltage reference and backscale it using
|
||||
factory calibration value of the internal voltage reference. In most cases the reading would be close
|
||||
to 3.3V. If the pyboard is operated from a battery, the supply voltage may drop to values below 3.3V.
|
||||
The pyboard will still operate fine as long as the operating conditions are met. With proper settings
|
||||
of MCU clock, flash access speed and programming mode it is possible to run the pyboard down to
|
||||
2 V and still get useful ADC conversion.
|
||||
It is very important to make sure analog input voltages never exceed actual supply voltage.
|
||||
|
||||
It is very important to make sure analog input voltages never exceed actual supply voltage.
|
||||
Other analog input channels (0..15) will return unscaled integer values according to the selected
|
||||
precision.
|
||||
|
||||
Other analog input channels (0..15) will return unscaled integer values according to the selected
|
||||
precision.
|
||||
To avoid unwanted activation of analog inputs (channel 0..15) a second parameter can be specified.
|
||||
This parameter is a binary pattern where each requested analog input has the corresponding bit set.
|
||||
The default value is 0xffffffff which means all analog inputs are active. If just the internal
|
||||
channels (16..18) are required, the mask value should be 0x70000.
|
||||
|
||||
To avoid unwanted activation of analog inputs (channel 0..15) a second parameter can be specified.
|
||||
This parameter is a binary pattern where each requested analog input has the corresponding bit set.
|
||||
The default value is 0xffffffff which means all analog inputs are active. If just the internal
|
||||
channels (16..18) are required, the mask value should be 0x70000.
|
||||
|
||||
Example::
|
||||
Example::
|
||||
|
||||
adcall = pyb.ADCAll(12, 0x70000) # 12 bit resolution, internal channels
|
||||
temp = adcall.read_core_temp()
|
||||
adcall = pyb.ADCAll(12, 0x70000) # 12 bit resolution, internal channels
|
||||
temp = adcall.read_core_temp()
|
||||
|
||||
@ -19,7 +19,7 @@ Constructors
|
||||
.. class:: pyb.Accel()
|
||||
|
||||
Create and return an accelerometer object.
|
||||
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
|
||||
@ -49,7 +49,7 @@ Class Methods
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. method:: CAN.init(mode, extframe=False, prescaler=100, \*, sjw=1, bs1=6, bs2=8, auto_restart=False)
|
||||
.. method:: CAN.init(mode, extframe=False, prescaler=100, *, sjw=1, bs1=6, bs2=8, auto_restart=False, baudrate=0, sample_point=75)
|
||||
|
||||
Initialise the CAN bus with the given parameters:
|
||||
|
||||
@ -67,6 +67,11 @@ Methods
|
||||
- *auto_restart* sets whether the controller will automatically try and restart
|
||||
communications after entering the bus-off state; if this is disabled then
|
||||
:meth:`~CAN.restart()` can be used to leave the bus-off state
|
||||
- *baudrate* if a baudrate other than 0 is provided, this function will try to automatically
|
||||
calculate a CAN bit-timing (overriding *prescaler*, *bs1* and *bs2*) that satisfies both
|
||||
the baudrate and the desired *sample_point*.
|
||||
- *sample_point* given in a percentage of the bit time, the *sample_point* specifies the position
|
||||
of the last bit sample with respect to the whole bit time. The default *sample_point* is 75%.
|
||||
|
||||
The time quanta tq is the basic unit of time for the CAN bus. tq is the CAN
|
||||
prescaler value divided by PCLK1 (the frequency of internal peripheral bus 1);
|
||||
@ -92,7 +97,7 @@ Methods
|
||||
|
||||
Force a software restart of the CAN controller without resetting its
|
||||
configuration.
|
||||
|
||||
|
||||
If the controller enters the bus-off state then it will no longer participate
|
||||
in bus activity. If the controller is not configured to automatically restart
|
||||
(see :meth:`~CAN.init()`) then this method can be used to trigger a restart,
|
||||
@ -135,7 +140,7 @@ Methods
|
||||
- number of pending RX messages on fifo 0
|
||||
- number of pending RX messages on fifo 1
|
||||
|
||||
.. method:: CAN.setfilter(bank, mode, fifo, params, \*, rtr)
|
||||
.. method:: CAN.setfilter(bank, mode, fifo, params, *, rtr)
|
||||
|
||||
Configure a filter bank:
|
||||
|
||||
@ -187,7 +192,7 @@ Methods
|
||||
|
||||
Return ``True`` if any message waiting on the FIFO, else ``False``.
|
||||
|
||||
.. method:: CAN.recv(fifo, list=None, \*, timeout=5000)
|
||||
.. method:: CAN.recv(fifo, list=None, *, timeout=5000)
|
||||
|
||||
Receive data on the bus:
|
||||
|
||||
@ -220,7 +225,7 @@ Methods
|
||||
# No heap memory is allocated in the following call
|
||||
can.recv(0, lst)
|
||||
|
||||
.. method:: CAN.send(data, id, \*, timeout=0, rtr=False)
|
||||
.. method:: CAN.send(data, id, *, timeout=0, rtr=False)
|
||||
|
||||
Send a message on the bus:
|
||||
|
||||
|
||||
@ -49,7 +49,7 @@ To output a continuous sine-wave at 12-bit resolution::
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. class:: pyb.DAC(port, bits=8, \*, buffering=None)
|
||||
.. class:: pyb.DAC(port, bits=8, *, buffering=None)
|
||||
|
||||
Construct a new DAC object.
|
||||
|
||||
@ -76,10 +76,10 @@ Constructors
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. method:: DAC.init(bits=8, \*, buffering=None)
|
||||
.. method:: DAC.init(bits=8, *, buffering=None)
|
||||
|
||||
Reinitialise the DAC. *bits* can be 8 or 12. *buffering* can be
|
||||
``None``, ``False`` or ``True`; see above constructor for the meaning
|
||||
``None``, ``False`` or ``True``; see above constructor for the meaning
|
||||
of this parameter.
|
||||
|
||||
.. method:: DAC.deinit()
|
||||
@ -93,9 +93,9 @@ Methods
|
||||
|
||||
.. method:: DAC.triangle(freq)
|
||||
|
||||
Generate a triangle wave. The value on the DAC output changes at
|
||||
the given frequency, and the frequency of the repeating triangle wave
|
||||
itself is 2048 times smaller.
|
||||
Generate a triangle wave. The value on the DAC output changes at the given
|
||||
frequency and ramps through the full 12-bit range (up and down). Therefore
|
||||
the frequency of the repeating triangle wave itself is 8192 times smaller.
|
||||
|
||||
.. method:: DAC.write(value)
|
||||
|
||||
@ -103,7 +103,7 @@ Methods
|
||||
value is 2\*\*``bits``-1, where ``bits`` is set when creating the DAC
|
||||
object or by using the ``init`` method.
|
||||
|
||||
.. method:: DAC.write_timed(data, freq, \*, mode=DAC.NORMAL)
|
||||
.. method:: DAC.write_timed(data, freq, *, mode=DAC.NORMAL)
|
||||
|
||||
Initiates a burst of RAM to DAC using a DMA transfer.
|
||||
The input data is treated as an array of bytes in 8-bit mode, and
|
||||
|
||||
@ -54,7 +54,7 @@ Constructors
|
||||
.. class:: pyb.ExtInt(pin, mode, pull, callback)
|
||||
|
||||
Create an ExtInt object:
|
||||
|
||||
|
||||
- ``pin`` is the pin on which to enable the interrupt (can be a pin object or any valid pin name).
|
||||
- ``mode`` can be one of:
|
||||
- ``ExtInt.IRQ_RISING`` - trigger on a rising edge;
|
||||
|
||||
53
docs/library/pyb.Flash.rst
Normal file
53
docs/library/pyb.Flash.rst
Normal file
@ -0,0 +1,53 @@
|
||||
.. currentmodule:: pyb
|
||||
.. _pyb.Flash:
|
||||
|
||||
class Flash -- access to built-in flash storage
|
||||
===============================================
|
||||
|
||||
The Flash class allows direct access to the primary flash device on the pyboard.
|
||||
|
||||
In most cases, to store persistent data on the device, you'll want to use a
|
||||
higher-level abstraction, for example the filesystem via Python's standard file
|
||||
API, but this interface is useful to :ref:`customise the filesystem
|
||||
configuration <filesystem>` or implement a low-level storage system for your
|
||||
application.
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. class:: pyb.Flash()
|
||||
|
||||
Create and return a block device that represents the flash device presented
|
||||
to the USB mass storage interface.
|
||||
|
||||
It includes a virtual partition table at the start, and the actual flash
|
||||
starts at block ``0x100``.
|
||||
|
||||
This constructor is deprecated and will be removed in a future version of MicroPython.
|
||||
|
||||
.. class:: pyb.Flash(*, start=-1, len=-1)
|
||||
:noindex:
|
||||
|
||||
Create and return a block device that accesses the flash at the specified offset. The length defaults to the remaining size of the device.
|
||||
|
||||
The *start* and *len* offsets are in bytes, and must be a multiple of the block size (typically 512 for internal flash).
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. method:: Flash.readblocks(block_num, buf)
|
||||
Flash.readblocks(block_num, buf, offset)
|
||||
.. method:: Flash.writeblocks(block_num, buf)
|
||||
Flash.writeblocks(block_num, buf, offset)
|
||||
.. method:: Flash.ioctl(cmd, arg)
|
||||
|
||||
These methods implement the simple and :ref:`extended
|
||||
<block-device-interface>` block protocol defined by
|
||||
:class:`uos.AbstractBlockDev`.
|
||||
|
||||
Hardware Note
|
||||
-------------
|
||||
|
||||
On boards with external spiflash (e.g. Pyboard D), the MicroPython firmware will
|
||||
be configured to use that as the primary flash storage. On all other boards, the
|
||||
internal flash inside the :term:`MCU` will be used.
|
||||
@ -10,78 +10,72 @@ level it consists of 2 wires: SCL and SDA, the clock and data lines respectively
|
||||
I2C objects are created attached to a specific bus. They can be initialised
|
||||
when created, or initialised later on.
|
||||
|
||||
.. only:: port_pyboard
|
||||
Example::
|
||||
|
||||
Example::
|
||||
from pyb import I2C
|
||||
|
||||
from pyb import I2C
|
||||
|
||||
i2c = I2C(1) # create on bus 1
|
||||
i2c = I2C(1, I2C.MASTER) # create and init as a master
|
||||
i2c.init(I2C.MASTER, baudrate=20000) # init as a master
|
||||
i2c.init(I2C.SLAVE, addr=0x42) # init as a slave with given address
|
||||
i2c.deinit() # turn off the peripheral
|
||||
i2c = I2C(1) # create on bus 1
|
||||
i2c = I2C(1, I2C.MASTER) # create and init as a master
|
||||
i2c.init(I2C.MASTER, baudrate=20000) # init as a master
|
||||
i2c.init(I2C.SLAVE, addr=0x42) # init as a slave with given address
|
||||
i2c.deinit() # turn off the peripheral
|
||||
|
||||
Printing the i2c object gives you information about its configuration.
|
||||
|
||||
.. only:: port_pyboard
|
||||
The basic methods are send and recv::
|
||||
|
||||
The basic methods are send and recv::
|
||||
i2c.send('abc') # send 3 bytes
|
||||
i2c.send(0x42) # send a single byte, given by the number
|
||||
data = i2c.recv(3) # receive 3 bytes
|
||||
|
||||
i2c.send('abc') # send 3 bytes
|
||||
i2c.send(0x42) # send a single byte, given by the number
|
||||
data = i2c.recv(3) # receive 3 bytes
|
||||
|
||||
To receive inplace, first create a bytearray::
|
||||
To receive inplace, first create a bytearray::
|
||||
|
||||
data = bytearray(3) # create a buffer
|
||||
i2c.recv(data) # receive 3 bytes, writing them into data
|
||||
data = bytearray(3) # create a buffer
|
||||
i2c.recv(data) # receive 3 bytes, writing them into data
|
||||
|
||||
You can specify a timeout (in ms)::
|
||||
You can specify a timeout (in ms)::
|
||||
|
||||
i2c.send(b'123', timeout=2000) # timeout after 2 seconds
|
||||
i2c.send(b'123', timeout=2000) # timeout after 2 seconds
|
||||
|
||||
A master must specify the recipient's address::
|
||||
A master must specify the recipient's address::
|
||||
|
||||
i2c.init(I2C.MASTER)
|
||||
i2c.send('123', 0x42) # send 3 bytes to slave with address 0x42
|
||||
i2c.send(b'456', addr=0x42) # keyword for address
|
||||
i2c.init(I2C.MASTER)
|
||||
i2c.send('123', 0x42) # send 3 bytes to slave with address 0x42
|
||||
i2c.send(b'456', addr=0x42) # keyword for address
|
||||
|
||||
Master also has other methods::
|
||||
Master also has other methods::
|
||||
|
||||
i2c.is_ready(0x42) # check if slave 0x42 is ready
|
||||
i2c.scan() # scan for slaves on the bus, returning
|
||||
# a list of valid addresses
|
||||
i2c.mem_read(3, 0x42, 2) # read 3 bytes from memory of slave 0x42,
|
||||
# starting at address 2 in the slave
|
||||
i2c.mem_write('abc', 0x42, 2, timeout=1000) # write 'abc' (3 bytes) to memory of slave 0x42
|
||||
# starting at address 2 in the slave, timeout after 1 second
|
||||
i2c.is_ready(0x42) # check if slave 0x42 is ready
|
||||
i2c.scan() # scan for slaves on the bus, returning
|
||||
# a list of valid addresses
|
||||
i2c.mem_read(3, 0x42, 2) # read 3 bytes from memory of slave 0x42,
|
||||
# starting at address 2 in the slave
|
||||
i2c.mem_write('abc', 0x42, 2, timeout=1000) # write 'abc' (3 bytes) to memory of slave 0x42
|
||||
# starting at address 2 in the slave, timeout after 1 second
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. only:: port_pyboard
|
||||
.. class:: pyb.I2C(bus, ...)
|
||||
|
||||
.. class:: pyb.I2C(bus, ...)
|
||||
Construct an I2C object on the given bus. ``bus`` can be 1 or 2, 'X' or
|
||||
'Y'. With no additional parameters, the I2C object is created but not
|
||||
initialised (it has the settings from the last initialisation of
|
||||
the bus, if any). If extra arguments are given, the bus is initialised.
|
||||
See ``init`` for parameters of initialisation.
|
||||
|
||||
Construct an I2C object on the given bus. ``bus`` can be 1 or 2, 'X' or
|
||||
'Y'. With no additional parameters, the I2C object is created but not
|
||||
initialised (it has the settings from the last initialisation of
|
||||
the bus, if any). If extra arguments are given, the bus is initialised.
|
||||
See ``init`` for parameters of initialisation.
|
||||
The physical pins of the I2C busses on Pyboards V1.0 and V1.1 are:
|
||||
|
||||
The physical pins of the I2C busses on Pyboards V1.0 and V1.1 are:
|
||||
- ``I2C(1)`` is on the X position: ``(SCL, SDA) = (X9, X10) = (PB6, PB7)``
|
||||
- ``I2C(2)`` is on the Y position: ``(SCL, SDA) = (Y9, Y10) = (PB10, PB11)``
|
||||
|
||||
- ``I2C(1)`` is on the X position: ``(SCL, SDA) = (X9, X10) = (PB6, PB7)``
|
||||
- ``I2C(2)`` is on the Y position: ``(SCL, SDA) = (Y9, Y10) = (PB10, PB11)``
|
||||
|
||||
On the Pyboard Lite:
|
||||
|
||||
- ``I2C(1)`` is on the X position: ``(SCL, SDA) = (X9, X10) = (PB6, PB7)``
|
||||
- ``I2C(3)`` is on the Y position: ``(SCL, SDA) = (Y9, Y10) = (PA8, PB8)``
|
||||
|
||||
Calling the constructor with 'X' or 'Y' enables portability between Pyboard
|
||||
types.
|
||||
On the Pyboard Lite:
|
||||
|
||||
- ``I2C(1)`` is on the X position: ``(SCL, SDA) = (X9, X10) = (PB6, PB7)``
|
||||
- ``I2C(3)`` is on the Y position: ``(SCL, SDA) = (Y9, Y10) = (PA8, PB8)``
|
||||
|
||||
Calling the constructor with 'X' or 'Y' enables portability between Pyboard
|
||||
types.
|
||||
|
||||
Methods
|
||||
-------
|
||||
@ -90,71 +84,69 @@ Methods
|
||||
|
||||
Turn off the I2C bus.
|
||||
|
||||
.. only:: port_pyboard
|
||||
.. method:: I2C.init(mode, *, addr=0x12, baudrate=400000, gencall=False, dma=False)
|
||||
|
||||
.. method:: I2C.init(mode, \*, addr=0x12, baudrate=400000, gencall=False, dma=False)
|
||||
Initialise the I2C bus with the given parameters:
|
||||
|
||||
Initialise the I2C bus with the given parameters:
|
||||
- ``mode`` must be either ``I2C.MASTER`` or ``I2C.SLAVE``
|
||||
- ``addr`` is the 7-bit address (only sensible for a slave)
|
||||
- ``baudrate`` is the SCL clock rate (only sensible for a master)
|
||||
- ``gencall`` is whether to support general call mode
|
||||
- ``dma`` is whether to allow the use of DMA for the I2C transfers (note
|
||||
that DMA transfers have more precise timing but currently do not handle bus
|
||||
errors properly)
|
||||
|
||||
- ``mode`` must be either ``I2C.MASTER`` or ``I2C.SLAVE``
|
||||
- ``addr`` is the 7-bit address (only sensible for a slave)
|
||||
- ``baudrate`` is the SCL clock rate (only sensible for a master)
|
||||
- ``gencall`` is whether to support general call mode
|
||||
- ``dma`` is whether to allow the use of DMA for the I2C transfers (note
|
||||
that DMA transfers have more precise timing but currently do not handle bus
|
||||
errors properly)
|
||||
.. method:: I2C.is_ready(addr)
|
||||
|
||||
.. method:: I2C.is_ready(addr)
|
||||
Check if an I2C device responds to the given address. Only valid when in master mode.
|
||||
|
||||
Check if an I2C device responds to the given address. Only valid when in master mode.
|
||||
.. method:: I2C.mem_read(data, addr, memaddr, *, timeout=5000, addr_size=8)
|
||||
|
||||
.. method:: I2C.mem_read(data, addr, memaddr, \*, timeout=5000, addr_size=8)
|
||||
Read from the memory of an I2C device:
|
||||
|
||||
Read from the memory of an I2C device:
|
||||
- ``data`` can be an integer (number of bytes to read) or a buffer to read into
|
||||
- ``addr`` is the I2C device address
|
||||
- ``memaddr`` is the memory location within the I2C device
|
||||
- ``timeout`` is the timeout in milliseconds to wait for the read
|
||||
- ``addr_size`` selects width of memaddr: 8 or 16 bits
|
||||
|
||||
- ``data`` can be an integer (number of bytes to read) or a buffer to read into
|
||||
- ``addr`` is the I2C device address
|
||||
- ``memaddr`` is the memory location within the I2C device
|
||||
- ``timeout`` is the timeout in milliseconds to wait for the read
|
||||
- ``addr_size`` selects width of memaddr: 8 or 16 bits
|
||||
Returns the read data.
|
||||
This is only valid in master mode.
|
||||
|
||||
Returns the read data.
|
||||
This is only valid in master mode.
|
||||
.. method:: I2C.mem_write(data, addr, memaddr, *, timeout=5000, addr_size=8)
|
||||
|
||||
.. method:: I2C.mem_write(data, addr, memaddr, \*, timeout=5000, addr_size=8)
|
||||
Write to the memory of an I2C device:
|
||||
|
||||
Write to the memory of an I2C device:
|
||||
- ``data`` can be an integer or a buffer to write from
|
||||
- ``addr`` is the I2C device address
|
||||
- ``memaddr`` is the memory location within the I2C device
|
||||
- ``timeout`` is the timeout in milliseconds to wait for the write
|
||||
- ``addr_size`` selects width of memaddr: 8 or 16 bits
|
||||
|
||||
- ``data`` can be an integer or a buffer to write from
|
||||
- ``addr`` is the I2C device address
|
||||
- ``memaddr`` is the memory location within the I2C device
|
||||
- ``timeout`` is the timeout in milliseconds to wait for the write
|
||||
- ``addr_size`` selects width of memaddr: 8 or 16 bits
|
||||
Returns ``None``.
|
||||
This is only valid in master mode.
|
||||
|
||||
Returns ``None``.
|
||||
This is only valid in master mode.
|
||||
.. method:: I2C.recv(recv, addr=0x00, *, timeout=5000)
|
||||
|
||||
.. method:: I2C.recv(recv, addr=0x00, \*, timeout=5000)
|
||||
Receive data on the bus:
|
||||
|
||||
Receive data on the bus:
|
||||
- ``recv`` can be an integer, which is the number of bytes to receive,
|
||||
or a mutable buffer, which will be filled with received bytes
|
||||
- ``addr`` is the address to receive from (only required in master mode)
|
||||
- ``timeout`` is the timeout in milliseconds to wait for the receive
|
||||
|
||||
- ``recv`` can be an integer, which is the number of bytes to receive,
|
||||
or a mutable buffer, which will be filled with received bytes
|
||||
- ``addr`` is the address to receive from (only required in master mode)
|
||||
- ``timeout`` is the timeout in milliseconds to wait for the receive
|
||||
|
||||
Return value: if ``recv`` is an integer then a new buffer of the bytes received,
|
||||
otherwise the same buffer that was passed in to ``recv``.
|
||||
Return value: if ``recv`` is an integer then a new buffer of the bytes received,
|
||||
otherwise the same buffer that was passed in to ``recv``.
|
||||
|
||||
.. method:: I2C.send(send, addr=0x00, \*, timeout=5000)
|
||||
.. method:: I2C.send(send, addr=0x00, *, timeout=5000)
|
||||
|
||||
Send data on the bus:
|
||||
Send data on the bus:
|
||||
|
||||
- ``send`` is the data to send (an integer to send, or a buffer object)
|
||||
- ``addr`` is the address to send to (only required in master mode)
|
||||
- ``timeout`` is the timeout in milliseconds to wait for the send
|
||||
- ``send`` is the data to send (an integer to send, or a buffer object)
|
||||
- ``addr`` is the address to send to (only required in master mode)
|
||||
- ``timeout`` is the timeout in milliseconds to wait for the send
|
||||
|
||||
Return value: ``None``.
|
||||
Return value: ``None``.
|
||||
|
||||
.. method:: I2C.scan()
|
||||
|
||||
@ -168,8 +160,6 @@ Constants
|
||||
|
||||
for initialising the bus to master mode
|
||||
|
||||
.. only:: port_pyboard
|
||||
.. data:: I2C.SLAVE
|
||||
|
||||
.. data:: I2C.SLAVE
|
||||
|
||||
for initialising the bus to slave mode
|
||||
for initialising the bus to slave mode
|
||||
|
||||
@ -63,13 +63,13 @@ Methods
|
||||
.. method:: LCD.fill(colour)
|
||||
|
||||
Fill the screen with the given colour (0 or 1 for white or black).
|
||||
|
||||
|
||||
This method writes to the hidden buffer. Use ``show()`` to show the buffer.
|
||||
|
||||
.. method:: LCD.get(x, y)
|
||||
|
||||
Get the pixel at the position ``(x, y)``. Returns 0 or 1.
|
||||
|
||||
|
||||
This method reads from the visible buffer.
|
||||
|
||||
.. method:: LCD.light(value)
|
||||
@ -79,7 +79,7 @@ Methods
|
||||
.. method:: LCD.pixel(x, y, colour)
|
||||
|
||||
Set the pixel at ``(x, y)`` to the given colour (0 or 1).
|
||||
|
||||
|
||||
This method writes to the hidden buffer. Use ``show()`` to show the buffer.
|
||||
|
||||
.. method:: LCD.show()
|
||||
@ -89,7 +89,7 @@ Methods
|
||||
.. method:: LCD.text(str, x, y, colour)
|
||||
|
||||
Draw the given text to the position ``(x, y)`` using the given colour (0 or 1).
|
||||
|
||||
|
||||
This method writes to the hidden buffer. Use ``show()`` to show the buffer.
|
||||
|
||||
.. method:: LCD.write(str)
|
||||
|
||||
@ -13,7 +13,7 @@ Constructors
|
||||
.. class:: pyb.LED(id)
|
||||
|
||||
Create an LED object associated with the given LED:
|
||||
|
||||
|
||||
- ``id`` is the LED number, 1-4.
|
||||
|
||||
|
||||
|
||||
@ -10,68 +10,66 @@ digital logic level. For analog control of a pin, see the ADC class.
|
||||
|
||||
Usage Model:
|
||||
|
||||
.. only:: port_pyboard
|
||||
All Board Pins are predefined as pyb.Pin.board.Name::
|
||||
|
||||
All Board Pins are predefined as pyb.Pin.board.Name::
|
||||
|
||||
x1_pin = pyb.Pin.board.X1
|
||||
|
||||
g = pyb.Pin(pyb.Pin.board.X1, pyb.Pin.IN)
|
||||
|
||||
CPU pins which correspond to the board pins are available
|
||||
as ``pyb.cpu.Name``. For the CPU pins, the names are the port letter
|
||||
followed by the pin number. On the PYBv1.0, ``pyb.Pin.board.X1`` and
|
||||
``pyb.Pin.cpu.A0`` are the same pin.
|
||||
|
||||
You can also use strings::
|
||||
|
||||
g = pyb.Pin('X1', pyb.Pin.OUT_PP)
|
||||
|
||||
Users can add their own names::
|
||||
|
||||
MyMapperDict = { 'LeftMotorDir' : pyb.Pin.cpu.C12 }
|
||||
pyb.Pin.dict(MyMapperDict)
|
||||
g = pyb.Pin("LeftMotorDir", pyb.Pin.OUT_OD)
|
||||
|
||||
and can query mappings::
|
||||
|
||||
pin = pyb.Pin("LeftMotorDir")
|
||||
|
||||
Users can also add their own mapping function::
|
||||
|
||||
def MyMapper(pin_name):
|
||||
if pin_name == "LeftMotorDir":
|
||||
return pyb.Pin.cpu.A0
|
||||
|
||||
pyb.Pin.mapper(MyMapper)
|
||||
|
||||
So, if you were to call: ``pyb.Pin("LeftMotorDir", pyb.Pin.OUT_PP)``
|
||||
then ``"LeftMotorDir"`` is passed directly to the mapper function.
|
||||
|
||||
To summarise, the following order determines how things get mapped into
|
||||
an ordinal pin number:
|
||||
|
||||
1. Directly specify a pin object
|
||||
2. User supplied mapping function
|
||||
3. User supplied mapping (object must be usable as a dictionary key)
|
||||
4. Supply a string which matches a board pin
|
||||
5. Supply a string which matches a CPU port/pin
|
||||
|
||||
You can set ``pyb.Pin.debug(True)`` to get some debug information about
|
||||
how a particular object gets mapped to a pin.
|
||||
|
||||
When a pin has the ``Pin.PULL_UP`` or ``Pin.PULL_DOWN`` pull-mode enabled,
|
||||
that pin has an effective 40k Ohm resistor pulling it to 3V3 or GND
|
||||
respectively (except pin Y5 which has 11k Ohm resistors).
|
||||
x1_pin = pyb.Pin.board.X1
|
||||
|
||||
Now every time a falling edge is seen on the gpio pin, the callback will be
|
||||
executed. Caution: mechanical push buttons have "bounce" and pushing or
|
||||
releasing a switch will often generate multiple edges.
|
||||
See: http://www.eng.utah.edu/~cs5780/debouncing.pdf for a detailed
|
||||
explanation, along with various techniques for debouncing.
|
||||
g = pyb.Pin(pyb.Pin.board.X1, pyb.Pin.IN)
|
||||
|
||||
All pin objects go through the pin mapper to come up with one of the
|
||||
gpio pins.
|
||||
CPU pins which correspond to the board pins are available
|
||||
as ``pyb.Pin.cpu.Name``. For the CPU pins, the names are the port letter
|
||||
followed by the pin number. On the PYBv1.0, ``pyb.Pin.board.X1`` and
|
||||
``pyb.Pin.cpu.A0`` are the same pin.
|
||||
|
||||
You can also use strings::
|
||||
|
||||
g = pyb.Pin('X1', pyb.Pin.OUT_PP)
|
||||
|
||||
Users can add their own names::
|
||||
|
||||
MyMapperDict = { 'LeftMotorDir' : pyb.Pin.cpu.C12 }
|
||||
pyb.Pin.dict(MyMapperDict)
|
||||
g = pyb.Pin("LeftMotorDir", pyb.Pin.OUT_OD)
|
||||
|
||||
and can query mappings::
|
||||
|
||||
pin = pyb.Pin("LeftMotorDir")
|
||||
|
||||
Users can also add their own mapping function::
|
||||
|
||||
def MyMapper(pin_name):
|
||||
if pin_name == "LeftMotorDir":
|
||||
return pyb.Pin.cpu.A0
|
||||
|
||||
pyb.Pin.mapper(MyMapper)
|
||||
|
||||
So, if you were to call: ``pyb.Pin("LeftMotorDir", pyb.Pin.OUT_PP)``
|
||||
then ``"LeftMotorDir"`` is passed directly to the mapper function.
|
||||
|
||||
To summarise, the following order determines how things get mapped into
|
||||
an ordinal pin number:
|
||||
|
||||
1. Directly specify a pin object
|
||||
2. User supplied mapping function
|
||||
3. User supplied mapping (object must be usable as a dictionary key)
|
||||
4. Supply a string which matches a board pin
|
||||
5. Supply a string which matches a CPU port/pin
|
||||
|
||||
You can set ``pyb.Pin.debug(True)`` to get some debug information about
|
||||
how a particular object gets mapped to a pin.
|
||||
|
||||
When a pin has the ``Pin.PULL_UP`` or ``Pin.PULL_DOWN`` pull-mode enabled,
|
||||
that pin has an effective 40k Ohm resistor pulling it to 3V3 or GND
|
||||
respectively (except pin Y5 which has 11k Ohm resistors).
|
||||
|
||||
Now every time a falling edge is seen on the gpio pin, the callback will be
|
||||
executed. Caution: mechanical push buttons have "bounce" and pushing or
|
||||
releasing a switch will often generate multiple edges.
|
||||
See: http://www.eng.utah.edu/~cs5780/debouncing.pdf for a detailed
|
||||
explanation, along with various techniques for debouncing.
|
||||
|
||||
All pin objects go through the pin mapper to come up with one of the
|
||||
gpio pins.
|
||||
|
||||
Constructors
|
||||
------------
|
||||
@ -81,52 +79,48 @@ Constructors
|
||||
Create a new Pin object associated with the id. If additional arguments are given,
|
||||
they are used to initialise the pin. See :meth:`pin.init`.
|
||||
|
||||
.. only:: port_pyboard
|
||||
Class methods
|
||||
-------------
|
||||
|
||||
Class methods
|
||||
-------------
|
||||
.. classmethod:: Pin.debug([state])
|
||||
|
||||
.. classmethod:: Pin.debug([state])
|
||||
|
||||
Get or set the debugging state (``True`` or ``False`` for on or off).
|
||||
|
||||
.. classmethod:: Pin.dict([dict])
|
||||
|
||||
Get or set the pin mapper dictionary.
|
||||
|
||||
.. classmethod:: Pin.mapper([fun])
|
||||
|
||||
Get or set the pin mapper function.
|
||||
Get or set the debugging state (``True`` or ``False`` for on or off).
|
||||
|
||||
.. classmethod:: Pin.dict([dict])
|
||||
|
||||
Get or set the pin mapper dictionary.
|
||||
|
||||
.. classmethod:: Pin.mapper([fun])
|
||||
|
||||
Get or set the pin mapper function.
|
||||
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. only:: port_pyboard
|
||||
.. method:: Pin.init(mode, pull=Pin.PULL_NONE, af=-1)
|
||||
|
||||
.. method:: Pin.init(mode, pull=Pin.PULL_NONE, af=-1)
|
||||
|
||||
Initialise the pin:
|
||||
|
||||
- ``mode`` can be one of:
|
||||
Initialise the pin:
|
||||
|
||||
- ``Pin.IN`` - configure the pin for input;
|
||||
- ``Pin.OUT_PP`` - configure the pin for output, with push-pull control;
|
||||
- ``Pin.OUT_OD`` - configure the pin for output, with open-drain control;
|
||||
- ``Pin.AF_PP`` - configure the pin for alternate function, pull-pull;
|
||||
- ``Pin.AF_OD`` - configure the pin for alternate function, open-drain;
|
||||
- ``Pin.ANALOG`` - configure the pin for analog.
|
||||
- ``mode`` can be one of:
|
||||
|
||||
- ``pull`` can be one of:
|
||||
- ``Pin.IN`` - configure the pin for input;
|
||||
- ``Pin.OUT_PP`` - configure the pin for output, with push-pull control;
|
||||
- ``Pin.OUT_OD`` - configure the pin for output, with open-drain control;
|
||||
- ``Pin.AF_PP`` - configure the pin for alternate function, pull-pull;
|
||||
- ``Pin.AF_OD`` - configure the pin for alternate function, open-drain;
|
||||
- ``Pin.ANALOG`` - configure the pin for analog.
|
||||
|
||||
- ``Pin.PULL_NONE`` - no pull up or down resistors;
|
||||
- ``Pin.PULL_UP`` - enable the pull-up resistor;
|
||||
- ``Pin.PULL_DOWN`` - enable the pull-down resistor.
|
||||
- ``pull`` can be one of:
|
||||
|
||||
- when mode is ``Pin.AF_PP`` or ``Pin.AF_OD``, then af can be the index or name
|
||||
of one of the alternate functions associated with a pin.
|
||||
|
||||
Returns: ``None``.
|
||||
- ``Pin.PULL_NONE`` - no pull up or down resistors;
|
||||
- ``Pin.PULL_UP`` - enable the pull-up resistor;
|
||||
- ``Pin.PULL_DOWN`` - enable the pull-down resistor.
|
||||
|
||||
- when mode is ``Pin.AF_PP`` or ``Pin.AF_OD``, then af can be the index or name
|
||||
of one of the alternate functions associated with a pin.
|
||||
|
||||
Returns: ``None``.
|
||||
|
||||
.. method:: Pin.value([value])
|
||||
|
||||
@ -137,47 +131,45 @@ Methods
|
||||
anything that converts to a boolean. If it converts to ``True``, the pin
|
||||
is set high, otherwise it is set low.
|
||||
|
||||
.. only:: port_pyboard
|
||||
.. method:: Pin.__str__()
|
||||
|
||||
.. method:: Pin.__str__()
|
||||
|
||||
Return a string describing the pin object.
|
||||
|
||||
.. method:: Pin.af()
|
||||
|
||||
Returns the currently configured alternate-function of the pin. The
|
||||
integer returned will match one of the allowed constants for the af
|
||||
argument to the init function.
|
||||
Return a string describing the pin object.
|
||||
|
||||
.. method:: Pin.af_list()
|
||||
.. method:: Pin.af()
|
||||
|
||||
Returns an array of alternate functions available for this pin.
|
||||
|
||||
.. method:: Pin.gpio()
|
||||
|
||||
Returns the base address of the GPIO block associated with this pin.
|
||||
|
||||
.. method:: Pin.mode()
|
||||
|
||||
Returns the currently configured mode of the pin. The integer returned
|
||||
will match one of the allowed constants for the mode argument to the init
|
||||
function.
|
||||
|
||||
.. method:: Pin.name()
|
||||
Returns the currently configured alternate-function of the pin. The
|
||||
integer returned will match one of the allowed constants for the af
|
||||
argument to the init function.
|
||||
|
||||
Get the pin name.
|
||||
.. method:: Pin.af_list()
|
||||
|
||||
.. method:: Pin.names()
|
||||
|
||||
Returns the cpu and board names for this pin.
|
||||
|
||||
.. method:: Pin.pin()
|
||||
|
||||
Get the pin number.
|
||||
|
||||
.. method:: Pin.port()
|
||||
|
||||
Get the pin port.
|
||||
Returns an array of alternate functions available for this pin.
|
||||
|
||||
.. method:: Pin.gpio()
|
||||
|
||||
Returns the base address of the GPIO block associated with this pin.
|
||||
|
||||
.. method:: Pin.mode()
|
||||
|
||||
Returns the currently configured mode of the pin. The integer returned
|
||||
will match one of the allowed constants for the mode argument to the init
|
||||
function.
|
||||
|
||||
.. method:: Pin.name()
|
||||
|
||||
Get the pin name.
|
||||
|
||||
.. method:: Pin.names()
|
||||
|
||||
Returns the cpu and board names for this pin.
|
||||
|
||||
.. method:: Pin.pin()
|
||||
|
||||
Get the pin number.
|
||||
|
||||
.. method:: Pin.port()
|
||||
|
||||
Get the pin port.
|
||||
|
||||
.. method:: Pin.pull()
|
||||
|
||||
@ -188,93 +180,89 @@ Methods
|
||||
Constants
|
||||
---------
|
||||
|
||||
.. only:: port_pyboard
|
||||
.. data:: Pin.AF_OD
|
||||
|
||||
.. data:: Pin.AF_OD
|
||||
|
||||
initialise the pin to alternate-function mode with an open-drain drive
|
||||
|
||||
.. data:: Pin.AF_PP
|
||||
|
||||
initialise the pin to alternate-function mode with a push-pull drive
|
||||
|
||||
.. data:: Pin.ANALOG
|
||||
|
||||
initialise the pin to analog mode
|
||||
|
||||
.. data:: Pin.IN
|
||||
|
||||
initialise the pin to input mode
|
||||
|
||||
.. data:: Pin.OUT_OD
|
||||
|
||||
initialise the pin to output mode with an open-drain drive
|
||||
|
||||
.. data:: Pin.OUT_PP
|
||||
|
||||
initialise the pin to output mode with a push-pull drive
|
||||
|
||||
.. data:: Pin.PULL_DOWN
|
||||
|
||||
enable the pull-down resistor on the pin
|
||||
|
||||
.. data:: Pin.PULL_NONE
|
||||
|
||||
don't enable any pull up or down resistors on the pin
|
||||
|
||||
.. data:: Pin.PULL_UP
|
||||
|
||||
enable the pull-up resistor on the pin
|
||||
initialise the pin to alternate-function mode with an open-drain drive
|
||||
|
||||
.. only:: port_pyboard
|
||||
.. data:: Pin.AF_PP
|
||||
|
||||
class PinAF -- Pin Alternate Functions
|
||||
======================================
|
||||
|
||||
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.
|
||||
|
||||
Usage Model::
|
||||
|
||||
x3 = pyb.Pin.board.X3
|
||||
x3_af = x3.af_list()
|
||||
|
||||
x3_af will now contain an array of PinAF objects which are available on
|
||||
pin X3.
|
||||
|
||||
For the pyboard, x3_af would contain:
|
||||
[Pin.AF1_TIM2, Pin.AF2_TIM5, Pin.AF3_TIM9, Pin.AF7_USART2]
|
||||
|
||||
Normally, each peripheral would configure the af automatically, but sometimes
|
||||
the same function is available on multiple pins, and having more control
|
||||
is desired.
|
||||
|
||||
To configure X3 to expose TIM2_CH3, you could use::
|
||||
|
||||
pin = pyb.Pin(pyb.Pin.board.X3, mode=pyb.Pin.AF_PP, af=pyb.Pin.AF1_TIM2)
|
||||
|
||||
or::
|
||||
|
||||
pin = pyb.Pin(pyb.Pin.board.X3, mode=pyb.Pin.AF_PP, af=1)
|
||||
initialise the pin to alternate-function mode with a push-pull drive
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. method:: pinaf.__str__()
|
||||
|
||||
Return a string describing the alternate function.
|
||||
|
||||
.. method:: pinaf.index()
|
||||
|
||||
Return the alternate function index.
|
||||
|
||||
.. method:: pinaf.name()
|
||||
|
||||
Return the name of the alternate function.
|
||||
|
||||
.. method:: pinaf.reg()
|
||||
|
||||
Return the base register associated with the peripheral assigned to this
|
||||
alternate function. For example, if the alternate function were TIM2_CH3
|
||||
this would return stm.TIM2
|
||||
.. data:: Pin.ANALOG
|
||||
|
||||
initialise the pin to analog mode
|
||||
|
||||
.. data:: Pin.IN
|
||||
|
||||
initialise the pin to input mode
|
||||
|
||||
.. data:: Pin.OUT_OD
|
||||
|
||||
initialise the pin to output mode with an open-drain drive
|
||||
|
||||
.. data:: Pin.OUT_PP
|
||||
|
||||
initialise the pin to output mode with a push-pull drive
|
||||
|
||||
.. data:: Pin.PULL_DOWN
|
||||
|
||||
enable the pull-down resistor on the pin
|
||||
|
||||
.. data:: Pin.PULL_NONE
|
||||
|
||||
don't enable any pull up or down resistors on the pin
|
||||
|
||||
.. data:: Pin.PULL_UP
|
||||
|
||||
enable the pull-up resistor on the pin
|
||||
|
||||
class PinAF -- Pin Alternate Functions
|
||||
======================================
|
||||
|
||||
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.
|
||||
|
||||
Usage Model::
|
||||
|
||||
x3 = pyb.Pin.board.X3
|
||||
x3_af = x3.af_list()
|
||||
|
||||
x3_af will now contain an array of PinAF objects which are available on
|
||||
pin X3.
|
||||
|
||||
For the pyboard, x3_af would contain:
|
||||
[Pin.AF1_TIM2, Pin.AF2_TIM5, Pin.AF3_TIM9, Pin.AF7_USART2]
|
||||
|
||||
Normally, each peripheral would configure the af automatically, but sometimes
|
||||
the same function is available on multiple pins, and having more control
|
||||
is desired.
|
||||
|
||||
To configure X3 to expose TIM2_CH3, you could use::
|
||||
|
||||
pin = pyb.Pin(pyb.Pin.board.X3, mode=pyb.Pin.AF_PP, af=pyb.Pin.AF1_TIM2)
|
||||
|
||||
or::
|
||||
|
||||
pin = pyb.Pin(pyb.Pin.board.X3, mode=pyb.Pin.AF_PP, af=1)
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. method:: pinaf.__str__()
|
||||
|
||||
Return a string describing the alternate function.
|
||||
|
||||
.. method:: pinaf.index()
|
||||
|
||||
Return the alternate function index.
|
||||
|
||||
.. method:: pinaf.name()
|
||||
|
||||
Return the name of the alternate function.
|
||||
|
||||
.. method:: pinaf.reg()
|
||||
|
||||
Return the base register associated with the peripheral assigned to this
|
||||
alternate function. For example, if the alternate function were TIM2_CH3
|
||||
this would return stm.TIM2
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
class RTC -- real time clock
|
||||
============================
|
||||
|
||||
The RTC is and independent clock that keeps track of the date
|
||||
The RTC is an independent clock that keeps track of the date
|
||||
and time.
|
||||
|
||||
Example usage::
|
||||
@ -28,56 +28,51 @@ Methods
|
||||
.. method:: RTC.datetime([datetimetuple])
|
||||
|
||||
Get or set the date and time of the RTC.
|
||||
|
||||
|
||||
With no arguments, this method returns an 8-tuple with the current
|
||||
date and time. With 1 argument (being an 8-tuple) it sets the date
|
||||
and time (and ``subseconds`` is reset to 255).
|
||||
|
||||
.. only:: port_pyboard
|
||||
|
||||
The 8-tuple has the following format:
|
||||
|
||||
(year, month, day, weekday, hours, minutes, seconds, subseconds)
|
||||
|
||||
``weekday`` is 1-7 for Monday through Sunday.
|
||||
|
||||
``subseconds`` counts down from 255 to 0
|
||||
|
||||
.. only:: port_pyboard
|
||||
The 8-tuple has the following format:
|
||||
|
||||
.. method:: RTC.wakeup(timeout, callback=None)
|
||||
|
||||
Set the RTC wakeup timer to trigger repeatedly at every ``timeout``
|
||||
milliseconds. This trigger can wake the pyboard from both the sleep
|
||||
states: :meth:`pyb.stop` and :meth:`pyb.standby`.
|
||||
|
||||
If ``timeout`` is ``None`` then the wakeup timer is disabled.
|
||||
|
||||
If ``callback`` is given then it is executed at every trigger of the
|
||||
wakeup timer. ``callback`` must take exactly one argument.
|
||||
|
||||
.. method:: RTC.info()
|
||||
|
||||
Get information about the startup time and reset source.
|
||||
|
||||
- The lower 0xffff are the number of milliseconds the RTC took to
|
||||
start up.
|
||||
- Bit 0x10000 is set if a power-on reset occurred.
|
||||
- Bit 0x20000 is set if an external reset occurred
|
||||
|
||||
.. method:: RTC.calibration(cal)
|
||||
|
||||
Get or set RTC calibration.
|
||||
|
||||
With no arguments, ``calibration()`` returns the current calibration
|
||||
value, which is an integer in the range [-511 : 512]. With one
|
||||
argument it sets the RTC calibration.
|
||||
|
||||
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
|
||||
ppm; likewise the RTC clock it slowed by negative values. The
|
||||
usable calibration range is:
|
||||
(-511 * 0.954) ~= -487.5 ppm up to (512 * 0.954) ~= 488.5 ppm
|
||||
(year, month, day, weekday, hours, minutes, seconds, subseconds)
|
||||
|
||||
``weekday`` is 1-7 for Monday through Sunday.
|
||||
|
||||
``subseconds`` counts down from 255 to 0
|
||||
|
||||
.. method:: RTC.wakeup(timeout, callback=None)
|
||||
|
||||
Set the RTC wakeup timer to trigger repeatedly at every ``timeout``
|
||||
milliseconds. This trigger can wake the pyboard from both the sleep
|
||||
states: :meth:`pyb.stop` and :meth:`pyb.standby`.
|
||||
|
||||
If ``timeout`` is ``None`` then the wakeup timer is disabled.
|
||||
|
||||
If ``callback`` is given then it is executed at every trigger of the
|
||||
wakeup timer. ``callback`` must take exactly one argument.
|
||||
|
||||
.. method:: RTC.info()
|
||||
|
||||
Get information about the startup time and reset source.
|
||||
|
||||
- The lower 0xffff are the number of milliseconds the RTC took to
|
||||
start up.
|
||||
- Bit 0x10000 is set if a power-on reset occurred.
|
||||
- Bit 0x20000 is set if an external reset occurred
|
||||
|
||||
.. method:: RTC.calibration(cal)
|
||||
|
||||
Get or set RTC calibration.
|
||||
|
||||
With no arguments, ``calibration()`` returns the current calibration
|
||||
value, which is an integer in the range [-511 : 512]. With one
|
||||
argument it sets the RTC calibration.
|
||||
|
||||
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
|
||||
ppm; likewise the RTC clock it slowed by negative values. The
|
||||
usable calibration range is:
|
||||
(-511 * 0.954) ~= -487.5 ppm up to (512 * 0.954) ~= 488.5 ppm
|
||||
|
||||
@ -7,46 +7,42 @@ class SPI -- a master-driven serial protocol
|
||||
SPI is a serial protocol that is driven by a master. At the physical level
|
||||
there are 3 lines: SCK, MOSI, MISO.
|
||||
|
||||
.. only:: port_pyboard
|
||||
See usage model of I2C; SPI is very similar. Main difference is
|
||||
parameters to init the SPI bus::
|
||||
|
||||
See usage model of I2C; SPI is very similar. Main difference is
|
||||
parameters to init the SPI bus::
|
||||
from pyb import SPI
|
||||
spi = SPI(1, SPI.MASTER, baudrate=600000, polarity=1, phase=0, crc=0x7)
|
||||
|
||||
from pyb import SPI
|
||||
spi = SPI(1, SPI.MASTER, baudrate=600000, polarity=1, phase=0, crc=0x7)
|
||||
Only required parameter is mode, SPI.MASTER or SPI.SLAVE. 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. Crc can be
|
||||
None for no CRC, or a polynomial specifier.
|
||||
|
||||
Only required parameter is mode, SPI.MASTER or SPI.SLAVE. 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. Crc can be
|
||||
None for no CRC, or a polynomial specifier.
|
||||
Additional methods for SPI::
|
||||
|
||||
Additional methods for SPI::
|
||||
|
||||
data = spi.send_recv(b'1234') # send 4 bytes and receive 4 bytes
|
||||
buf = bytearray(4)
|
||||
spi.send_recv(b'1234', buf) # send 4 bytes and receive 4 into buf
|
||||
spi.send_recv(buf, buf) # send/recv 4 bytes from/to buf
|
||||
data = spi.send_recv(b'1234') # send 4 bytes and receive 4 bytes
|
||||
buf = bytearray(4)
|
||||
spi.send_recv(b'1234', buf) # send 4 bytes and receive 4 into buf
|
||||
spi.send_recv(buf, buf) # send/recv 4 bytes from/to buf
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. only:: port_pyboard
|
||||
.. class:: pyb.SPI(bus, ...)
|
||||
|
||||
.. class:: pyb.SPI(bus, ...)
|
||||
Construct an SPI object on the given bus. ``bus`` can be 1 or 2, or
|
||||
'X' or 'Y'. With no additional parameters, the SPI object is created but
|
||||
not initialised (it has the settings from the last initialisation of
|
||||
the bus, if any). If extra arguments are given, the bus is initialised.
|
||||
See ``init`` for parameters of initialisation.
|
||||
|
||||
Construct an SPI object on the given bus. ``bus`` can be 1 or 2, or
|
||||
'X' or 'Y'. With no additional parameters, the SPI object is created but
|
||||
not initialised (it has the settings from the last initialisation of
|
||||
the bus, if any). If extra arguments are given, the bus is initialised.
|
||||
See ``init`` for parameters of initialisation.
|
||||
The physical pins of the SPI busses are:
|
||||
|
||||
The physical pins of the SPI busses are:
|
||||
- ``SPI(1)`` is on the X position: ``(NSS, SCK, MISO, MOSI) = (X5, X6, X7, X8) = (PA4, PA5, PA6, PA7)``
|
||||
- ``SPI(2)`` is on the Y position: ``(NSS, SCK, MISO, MOSI) = (Y5, Y6, Y7, Y8) = (PB12, PB13, PB14, PB15)``
|
||||
|
||||
- ``SPI(1)`` is on the X position: ``(NSS, SCK, MISO, MOSI) = (X5, X6, X7, X8) = (PA4, PA5, PA6, PA7)``
|
||||
- ``SPI(2)`` is on the Y position: ``(NSS, SCK, MISO, MOSI) = (Y5, Y6, Y7, Y8) = (PB12, PB13, PB14, PB15)``
|
||||
|
||||
At the moment, the NSS pin is not used by the SPI driver and is free
|
||||
for other use.
|
||||
At the moment, the NSS pin is not used by the SPI driver and is free
|
||||
for other use.
|
||||
|
||||
Methods
|
||||
-------
|
||||
@ -55,78 +51,73 @@ Methods
|
||||
|
||||
Turn off the SPI bus.
|
||||
|
||||
.. only:: port_pyboard
|
||||
.. method:: SPI.init(mode, baudrate=328125, *, prescaler, polarity=1, phase=0, bits=8, firstbit=SPI.MSB, ti=False, crc=None)
|
||||
|
||||
.. method:: SPI.init(mode, baudrate=328125, \*, prescaler, polarity=1, phase=0, bits=8, firstbit=SPI.MSB, ti=False, crc=None)
|
||||
Initialise the SPI bus with the given parameters:
|
||||
|
||||
Initialise the SPI bus with the given parameters:
|
||||
- ``mode`` must be either ``SPI.MASTER`` or ``SPI.SLAVE``.
|
||||
- ``baudrate`` is the SCK clock rate (only sensible for a master).
|
||||
- ``prescaler`` is the prescaler to use to derive SCK from the APB bus frequency;
|
||||
use of ``prescaler`` overrides ``baudrate``.
|
||||
- ``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``.
|
||||
- ``ti`` True indicates Texas Instruments, as opposed to Motorola, signal conventions.
|
||||
- ``crc`` can be None for no CRC, or a polynomial specifier.
|
||||
|
||||
- ``mode`` must be either ``SPI.MASTER`` or ``SPI.SLAVE``.
|
||||
- ``baudrate`` is the SCK clock rate (only sensible for a master).
|
||||
- ``prescaler`` is the prescaler to use to derive SCK from the APB bus frequency;
|
||||
use of ``prescaler`` overrides ``baudrate``.
|
||||
- ``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.
|
||||
Note that the SPI clock frequency will not always be the requested baudrate.
|
||||
The hardware only supports baudrates that are the APB bus frequency
|
||||
(see :meth:`pyb.freq`) divided by a prescaler, which can be 2, 4, 8, 16, 32,
|
||||
64, 128 or 256. SPI(1) is on AHB2, and SPI(2) is on AHB1. For precise
|
||||
control over the SPI clock frequency, specify ``prescaler`` instead of
|
||||
``baudrate``.
|
||||
|
||||
Note that the SPI clock frequency will not always be the requested baudrate.
|
||||
The hardware only supports baudrates that are the APB bus frequency
|
||||
(see :meth:`pyb.freq`) divided by a prescaler, which can be 2, 4, 8, 16, 32,
|
||||
64, 128 or 256. SPI(1) is on AHB2, and SPI(2) is on AHB1. For precise
|
||||
control over the SPI clock frequency, specify ``prescaler`` instead of
|
||||
``baudrate``.
|
||||
Printing the SPI object will show you the computed baudrate and the chosen
|
||||
prescaler.
|
||||
|
||||
Printing the SPI object will show you the computed baudrate and the chosen
|
||||
prescaler.
|
||||
.. method:: SPI.recv(recv, *, timeout=5000)
|
||||
|
||||
.. only:: port_pyboard
|
||||
Receive data on the bus:
|
||||
|
||||
.. method:: SPI.recv(recv, \*, timeout=5000)
|
||||
|
||||
Receive data on the bus:
|
||||
- ``recv`` 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.
|
||||
|
||||
- ``recv`` 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 ``recv`` is an integer then a new buffer of the bytes received,
|
||||
otherwise the same buffer that was passed in to ``recv``.
|
||||
|
||||
Return value: if ``recv`` is an integer then a new buffer of the bytes received,
|
||||
otherwise the same buffer that was passed in to ``recv``.
|
||||
|
||||
.. method:: SPI.send(send, \*, timeout=5000)
|
||||
.. method:: SPI.send(send, *, timeout=5000)
|
||||
|
||||
Send data on the bus:
|
||||
Send data on the bus:
|
||||
|
||||
- ``send`` is the data to send (an integer to send, or a buffer object).
|
||||
- ``timeout`` is the timeout in milliseconds to wait for the send.
|
||||
- ``send`` is the data to send (an integer to send, or a buffer object).
|
||||
- ``timeout`` is the timeout in milliseconds to wait for the send.
|
||||
|
||||
Return value: ``None``.
|
||||
Return value: ``None``.
|
||||
|
||||
.. method:: SPI.send_recv(send, recv=None, \*, timeout=5000)
|
||||
|
||||
Send and receive data on the bus at the same time:
|
||||
.. method:: SPI.send_recv(send, recv=None, *, timeout=5000)
|
||||
|
||||
- ``send`` is the data to send (an integer to send, or a buffer object).
|
||||
- ``recv`` is a mutable buffer which will be filled with received bytes.
|
||||
It can be the same as ``send``, or omitted. If omitted, a new buffer will
|
||||
be created.
|
||||
- ``timeout`` is the timeout in milliseconds to wait for the receive.
|
||||
Send and receive data on the bus at the same time:
|
||||
|
||||
Return value: the buffer with the received bytes.
|
||||
- ``send`` is the data to send (an integer to send, or a buffer object).
|
||||
- ``recv`` is a mutable buffer which will be filled with received bytes.
|
||||
It can be the same as ``send``, or omitted. If omitted, a new buffer will
|
||||
be created.
|
||||
- ``timeout`` is the timeout in milliseconds to wait for the receive.
|
||||
|
||||
Return value: the buffer with the received bytes.
|
||||
|
||||
Constants
|
||||
---------
|
||||
|
||||
.. only:: port_pyboard
|
||||
.. data:: SPI.MASTER
|
||||
.. data:: SPI.SLAVE
|
||||
|
||||
.. data:: SPI.MASTER
|
||||
.. data:: SPI.SLAVE
|
||||
|
||||
for initialising the SPI bus to master or slave mode
|
||||
|
||||
.. data:: SPI.LSB
|
||||
.. data:: SPI.MSB
|
||||
|
||||
set the first bit to be the least or most significant bit
|
||||
for initialising the SPI bus to master or slave mode
|
||||
|
||||
.. data:: SPI.LSB
|
||||
.. data:: SPI.MSB
|
||||
|
||||
set the first bit to be the least or most significant bit
|
||||
|
||||
@ -4,47 +4,45 @@
|
||||
class Timer -- control internal timers
|
||||
======================================
|
||||
|
||||
.. only:: port_pyboard
|
||||
Timers can be used for a great variety of tasks. At the moment, only
|
||||
the simplest case is implemented: that of calling a function periodically.
|
||||
|
||||
Timers can be used for a great variety of tasks. At the moment, only
|
||||
the simplest case is implemented: that of calling a function periodically.
|
||||
|
||||
Each timer consists of a counter that counts up at a certain rate. The rate
|
||||
at which it counts is the peripheral clock frequency (in Hz) divided by the
|
||||
timer prescaler. When the counter reaches the timer period it triggers an
|
||||
event, and the counter resets back to zero. By using the callback method,
|
||||
the timer event can call a Python function.
|
||||
|
||||
Example usage to toggle an LED at a fixed frequency::
|
||||
|
||||
tim = pyb.Timer(4) # create a timer object using timer 4
|
||||
tim.init(freq=2) # trigger at 2Hz
|
||||
tim.callback(lambda t:pyb.LED(1).toggle())
|
||||
|
||||
Example using named function for the callback::
|
||||
|
||||
def tick(timer): # we will receive the timer object when being called
|
||||
print(timer.counter()) # show current timer's counter value
|
||||
tim = pyb.Timer(4, freq=1) # create a timer object using timer 4 - trigger at 1Hz
|
||||
tim.callback(tick) # set the callback to our tick function
|
||||
|
||||
Further examples::
|
||||
|
||||
tim = pyb.Timer(4, freq=100) # freq in Hz
|
||||
tim = pyb.Timer(4, prescaler=0, period=99)
|
||||
tim.counter() # get counter (can also set)
|
||||
tim.prescaler(2) # set prescaler (can also get)
|
||||
tim.period(199) # set period (can also get)
|
||||
tim.callback(lambda t: ...) # set callback for update interrupt (t=tim instance)
|
||||
tim.callback(None) # clear callback
|
||||
|
||||
*Note:* Timer(2) and Timer(3) are used for PWM to set the intensity of LED(3)
|
||||
and LED(4) respectively. But these timers are only configured for PWM if
|
||||
the intensity of the relevant LED is set to a value between 1 and 254. If
|
||||
the intensity feature of the LEDs is not used then these timers are free for
|
||||
general purpose use. Similarly, Timer(5) controls the servo driver, and
|
||||
Timer(6) is used for timed ADC/DAC reading/writing. It is recommended to
|
||||
use the other timers in your programs.
|
||||
Each timer consists of a counter that counts up at a certain rate. The rate
|
||||
at which it counts is the peripheral clock frequency (in Hz) divided by the
|
||||
timer prescaler. When the counter reaches the timer period it triggers an
|
||||
event, and the counter resets back to zero. By using the callback method,
|
||||
the timer event can call a Python function.
|
||||
|
||||
Example usage to toggle an LED at a fixed frequency::
|
||||
|
||||
tim = pyb.Timer(4) # create a timer object using timer 4
|
||||
tim.init(freq=2) # trigger at 2Hz
|
||||
tim.callback(lambda t:pyb.LED(1).toggle())
|
||||
|
||||
Example using named function for the callback::
|
||||
|
||||
def tick(timer): # we will receive the timer object when being called
|
||||
print(timer.counter()) # show current timer's counter value
|
||||
tim = pyb.Timer(4, freq=1) # create a timer object using timer 4 - trigger at 1Hz
|
||||
tim.callback(tick) # set the callback to our tick function
|
||||
|
||||
Further examples::
|
||||
|
||||
tim = pyb.Timer(4, freq=100) # freq in Hz
|
||||
tim = pyb.Timer(4, prescaler=0, period=99)
|
||||
tim.counter() # get counter (can also set)
|
||||
tim.prescaler(2) # set prescaler (can also get)
|
||||
tim.period(199) # set period (can also get)
|
||||
tim.callback(lambda t: ...) # set callback for update interrupt (t=tim instance)
|
||||
tim.callback(None) # clear callback
|
||||
|
||||
*Note:* Timer(2) and Timer(3) are used for PWM to set the intensity of LED(3)
|
||||
and LED(4) respectively. But these timers are only configured for PWM if
|
||||
the intensity of the relevant LED is set to a value between 1 and 254. If
|
||||
the intensity feature of the LEDs is not used then these timers are free for
|
||||
general purpose use. Similarly, Timer(5) controls the servo driver, and
|
||||
Timer(6) is used for timed ADC/DAC reading/writing. It is recommended to
|
||||
use the other timers in your programs.
|
||||
|
||||
*Note:* Memory can't be allocated during a callback (an interrupt) and so
|
||||
exceptions raised within a callback don't give much information. See
|
||||
@ -57,184 +55,168 @@ Constructors
|
||||
|
||||
.. class:: pyb.Timer(id, ...)
|
||||
|
||||
.. only:: port_pyboard
|
||||
|
||||
Construct a new timer object of the given id. If additional
|
||||
arguments are given, then the timer is initialised by ``init(...)``.
|
||||
``id`` can be 1 to 14.
|
||||
Construct a new timer object of the given id. If additional
|
||||
arguments are given, then the timer is initialised by ``init(...)``.
|
||||
``id`` can be 1 to 14.
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. only:: port_pyboard
|
||||
.. method:: Timer.init(*, freq, prescaler, period, mode=Timer.UP, div=1, callback=None, deadtime=0)
|
||||
|
||||
.. method:: Timer.init(\*, freq, prescaler, period)
|
||||
|
||||
Initialise the timer. Initialisation must be either by frequency (in Hz)
|
||||
or by prescaler and period::
|
||||
|
||||
tim.init(freq=100) # set the timer to trigger at 100Hz
|
||||
tim.init(prescaler=83, period=999) # set the prescaler and period directly
|
||||
|
||||
Keyword arguments:
|
||||
|
||||
- ``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
|
||||
timer's Prescaler Register (PSC). The timer clock source is divided by
|
||||
(``prescaler + 1``) to arrive at the timer clock. Timers 2-7 and 12-14
|
||||
have a clock source of 84 MHz (pyb.freq()[2] \* 2), and Timers 1, and 8-11
|
||||
have a clock source of 168 MHz (pyb.freq()[3] \* 2).
|
||||
|
||||
- ``period`` [0-0xffff] for timers 1, 3, 4, and 6-15. [0-0x3fffffff] for timers 2 & 5.
|
||||
Specifies the value to be loaded into the timer's AutoReload
|
||||
Register (ARR). This determines the period of the timer (i.e. when the
|
||||
counter cycles). The timer counter will roll-over after ``period + 1``
|
||||
timer clock cycles.
|
||||
|
||||
- ``mode`` can be one of:
|
||||
|
||||
- ``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`` - 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
|
||||
the sampling clock used by the digital filters.
|
||||
|
||||
- ``callback`` - as per Timer.callback()
|
||||
|
||||
- ``deadtime`` - specifies the amount of "dead" or inactive time between
|
||||
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. ``deadtime``
|
||||
measures ticks of ``source_freq`` divided by ``div`` clock ticks.
|
||||
``deadtime`` is only available on timers 1 and 8.
|
||||
|
||||
You must either specify freq or both of period and prescaler.
|
||||
Initialise the timer. Initialisation must be either by frequency (in Hz)
|
||||
or by prescaler and period::
|
||||
|
||||
tim.init(freq=100) # set the timer to trigger at 100Hz
|
||||
tim.init(prescaler=83, period=999) # set the prescaler and period directly
|
||||
|
||||
Keyword arguments:
|
||||
|
||||
- ``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
|
||||
timer's Prescaler Register (PSC). The timer clock source is divided by
|
||||
(``prescaler + 1``) to arrive at the timer clock. Timers 2-7 and 12-14
|
||||
have a clock source of 84 MHz (pyb.freq()[2] \* 2), and Timers 1, and 8-11
|
||||
have a clock source of 168 MHz (pyb.freq()[3] \* 2).
|
||||
|
||||
- ``period`` [0-0xffff] for timers 1, 3, 4, and 6-15. [0-0x3fffffff] for timers 2 & 5.
|
||||
Specifies the value to be loaded into the timer's AutoReload
|
||||
Register (ARR). This determines the period of the timer (i.e. when the
|
||||
counter cycles). The timer counter will roll-over after ``period + 1``
|
||||
timer clock cycles.
|
||||
|
||||
- ``mode`` can be one of:
|
||||
|
||||
- ``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`` - 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
|
||||
the sampling clock used by the digital filters.
|
||||
|
||||
- ``callback`` - as per Timer.callback()
|
||||
|
||||
- ``deadtime`` - specifies the amount of "dead" or inactive time between
|
||||
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. ``deadtime``
|
||||
measures ticks of ``source_freq`` divided by ``div`` clock ticks.
|
||||
``deadtime`` is only available on timers 1 and 8.
|
||||
|
||||
You must either specify freq or both of period and prescaler.
|
||||
|
||||
.. method:: Timer.deinit()
|
||||
|
||||
Deinitialises the timer.
|
||||
|
||||
.. only:: port_pyboard
|
||||
|
||||
Disables the callback (and the associated irq).
|
||||
Disables the callback (and the associated irq).
|
||||
|
||||
Disables any channel callbacks (and the associated irq).
|
||||
Stops the timer, and disables the timer peripheral.
|
||||
|
||||
.. only:: port_pyboard
|
||||
.. method:: Timer.callback(fun)
|
||||
|
||||
.. method:: Timer.callback(fun)
|
||||
|
||||
Set the function to be called when the timer triggers.
|
||||
``fun`` is passed 1 argument, the timer object.
|
||||
If ``fun`` is ``None`` then the callback will be disabled.
|
||||
Set the function to be called when the timer triggers.
|
||||
``fun`` is passed 1 argument, the timer object.
|
||||
If ``fun`` is ``None`` then the callback will be disabled.
|
||||
|
||||
.. only:: port_pyboard
|
||||
.. method:: Timer.channel(channel, mode, ...)
|
||||
|
||||
.. method:: Timer.channel(channel, mode, ...)
|
||||
|
||||
If only a channel number is passed, then a previously initialized channel
|
||||
object is returned (or ``None`` if there is no previous channel).
|
||||
|
||||
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
|
||||
that they share the same timer clock.
|
||||
|
||||
Keyword arguments:
|
||||
|
||||
- ``mode`` can be one of:
|
||||
|
||||
- ``Timer.PWM`` --- configure the timer in PWM mode (active high).
|
||||
- ``Timer.PWM_INVERTED`` --- configure the timer in PWM mode (active low).
|
||||
- ``Timer.OC_TIMING`` --- indicates that no pin is driven.
|
||||
- ``Timer.OC_ACTIVE`` --- the pin will be made active when a compare match occurs (active is determined by polarity)
|
||||
- ``Timer.OC_INACTIVE`` --- the pin will be made inactive when a compare match occurs.
|
||||
- ``Timer.OC_TOGGLE`` --- the pin will be toggled when an compare match occurs.
|
||||
- ``Timer.OC_FORCED_ACTIVE`` --- the pin is forced active (compare match is ignored).
|
||||
- ``Timer.OC_FORCED_INACTIVE`` --- the pin is forced inactive (compare match is ignored).
|
||||
- ``Timer.IC`` --- configure the timer in Input Capture mode.
|
||||
- ``Timer.ENC_A`` --- configure the timer in Encoder mode. The counter only changes when CH1 changes.
|
||||
- ``Timer.ENC_B`` --- configure the timer in Encoder mode. The counter only changes when CH2 changes.
|
||||
- ``Timer.ENC_AB`` --- configure the timer in Encoder mode. The counter changes when CH1 or CH2 changes.
|
||||
|
||||
- ``callback`` - as per TimerChannel.callback()
|
||||
|
||||
- ``pin`` None (the default) or a Pin object. If specified (and not None)
|
||||
this will cause the alternate function of the the indicated pin
|
||||
to be configured for this timer channel. An error will be raised if
|
||||
the pin doesn't support any alternate functions for this timer channel.
|
||||
|
||||
Keyword arguments for Timer.PWM modes:
|
||||
|
||||
- ``pulse_width`` - determines the initial pulse width value to use.
|
||||
- ``pulse_width_percent`` - determines the initial pulse width percentage to use.
|
||||
|
||||
Keyword arguments for Timer.OC modes:
|
||||
|
||||
- ``compare`` - determines the initial value of the compare register.
|
||||
|
||||
- ``polarity`` can be one of:
|
||||
|
||||
- ``Timer.HIGH`` - output is active high
|
||||
- ``Timer.LOW`` - output is active low
|
||||
|
||||
Optional keyword arguments for Timer.IC modes:
|
||||
|
||||
- ``polarity`` can be one of:
|
||||
|
||||
- ``Timer.RISING`` - captures on rising edge.
|
||||
- ``Timer.FALLING`` - captures on falling edge.
|
||||
- ``Timer.BOTH`` - captures on both edges.
|
||||
|
||||
Note that capture only works on the primary channel, and not on the
|
||||
complimentary channels.
|
||||
|
||||
Notes for Timer.ENC modes:
|
||||
|
||||
- Requires 2 pins, so one or both pins will need to be configured to use
|
||||
the appropriate timer AF using the Pin API.
|
||||
- Read the encoder value using the timer.counter() method.
|
||||
- Only works on CH1 and CH2 (and not on CH1N or CH2N)
|
||||
- The channel number is ignored when setting the encoder mode.
|
||||
|
||||
PWM Example::
|
||||
|
||||
timer = pyb.Timer(2, freq=1000)
|
||||
ch2 = timer.channel(2, pyb.Timer.PWM, pin=pyb.Pin.board.X2, pulse_width=8000)
|
||||
ch3 = timer.channel(3, pyb.Timer.PWM, pin=pyb.Pin.board.X3, pulse_width=16000)
|
||||
If only a channel number is passed, then a previously initialized channel
|
||||
object is returned (or ``None`` if there is no previous channel).
|
||||
|
||||
.. only:: port_pyboard
|
||||
Otherwise, a TimerChannel object is initialized and returned.
|
||||
|
||||
.. method:: Timer.counter([value])
|
||||
Each channel can be configured to perform pwm, output compare, or
|
||||
input capture. All channels share the same underlying timer, which means
|
||||
that they share the same timer clock.
|
||||
|
||||
Get or set the timer counter.
|
||||
Keyword arguments:
|
||||
|
||||
.. only:: port_pyboard
|
||||
- ``mode`` can be one of:
|
||||
|
||||
.. method:: Timer.freq([value])
|
||||
|
||||
Get or set the frequency for the timer (changes prescaler and period if set).
|
||||
- ``Timer.PWM`` --- configure the timer in PWM mode (active high).
|
||||
- ``Timer.PWM_INVERTED`` --- configure the timer in PWM mode (active low).
|
||||
- ``Timer.OC_TIMING`` --- indicates that no pin is driven.
|
||||
- ``Timer.OC_ACTIVE`` --- the pin will be made active when a compare match occurs (active is determined by polarity)
|
||||
- ``Timer.OC_INACTIVE`` --- the pin will be made inactive when a compare match occurs.
|
||||
- ``Timer.OC_TOGGLE`` --- the pin will be toggled when an compare match occurs.
|
||||
- ``Timer.OC_FORCED_ACTIVE`` --- the pin is forced active (compare match is ignored).
|
||||
- ``Timer.OC_FORCED_INACTIVE`` --- the pin is forced inactive (compare match is ignored).
|
||||
- ``Timer.IC`` --- configure the timer in Input Capture mode.
|
||||
- ``Timer.ENC_A`` --- configure the timer in Encoder mode. The counter only changes when CH1 changes.
|
||||
- ``Timer.ENC_B`` --- configure the timer in Encoder mode. The counter only changes when CH2 changes.
|
||||
- ``Timer.ENC_AB`` --- configure the timer in Encoder mode. The counter changes when CH1 or CH2 changes.
|
||||
|
||||
.. only:: port_pyboard
|
||||
- ``callback`` - as per TimerChannel.callback()
|
||||
|
||||
.. method:: Timer.period([value])
|
||||
|
||||
Get or set the period of the timer.
|
||||
|
||||
.. method:: Timer.prescaler([value])
|
||||
|
||||
Get or set the prescaler for the timer.
|
||||
|
||||
.. method:: Timer.source_freq()
|
||||
|
||||
Get the frequency of the source of the timer.
|
||||
- ``pin`` None (the default) or a Pin object. If specified (and not None)
|
||||
this will cause the alternate function of the the indicated pin
|
||||
to be configured for this timer channel. An error will be raised if
|
||||
the pin doesn't support any alternate functions for this timer channel.
|
||||
|
||||
Keyword arguments for Timer.PWM modes:
|
||||
|
||||
- ``pulse_width`` - determines the initial pulse width value to use.
|
||||
- ``pulse_width_percent`` - determines the initial pulse width percentage to use.
|
||||
|
||||
Keyword arguments for Timer.OC modes:
|
||||
|
||||
- ``compare`` - determines the initial value of the compare register.
|
||||
|
||||
- ``polarity`` can be one of:
|
||||
|
||||
- ``Timer.HIGH`` - output is active high
|
||||
- ``Timer.LOW`` - output is active low
|
||||
|
||||
Optional keyword arguments for Timer.IC modes:
|
||||
|
||||
- ``polarity`` can be one of:
|
||||
|
||||
- ``Timer.RISING`` - captures on rising edge.
|
||||
- ``Timer.FALLING`` - captures on falling edge.
|
||||
- ``Timer.BOTH`` - captures on both edges.
|
||||
|
||||
Note that capture only works on the primary channel, and not on the
|
||||
complimentary channels.
|
||||
|
||||
Notes for Timer.ENC modes:
|
||||
|
||||
- Requires 2 pins, so one or both pins will need to be configured to use
|
||||
the appropriate timer AF using the Pin API.
|
||||
- Read the encoder value using the timer.counter() method.
|
||||
- Only works on CH1 and CH2 (and not on CH1N or CH2N)
|
||||
- The channel number is ignored when setting the encoder mode.
|
||||
|
||||
PWM Example::
|
||||
|
||||
timer = pyb.Timer(2, freq=1000)
|
||||
ch2 = timer.channel(2, pyb.Timer.PWM, pin=pyb.Pin.board.X2, pulse_width=8000)
|
||||
ch3 = timer.channel(3, pyb.Timer.PWM, pin=pyb.Pin.board.X3, pulse_width=16000)
|
||||
|
||||
.. method:: Timer.counter([value])
|
||||
|
||||
Get or set the timer counter.
|
||||
|
||||
.. method:: Timer.freq([value])
|
||||
|
||||
Get or set the frequency for the timer (changes prescaler and period if set).
|
||||
|
||||
.. method:: Timer.period([value])
|
||||
|
||||
Get or set the period of the timer.
|
||||
|
||||
.. method:: Timer.prescaler([value])
|
||||
|
||||
Get or set the prescaler for the timer.
|
||||
|
||||
.. method:: Timer.source_freq()
|
||||
|
||||
Get the frequency of the source of the timer.
|
||||
|
||||
class TimerChannel --- setup a channel for a timer
|
||||
==================================================
|
||||
@ -246,41 +228,37 @@ TimerChannel objects are created using the Timer.channel() method.
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. only:: port_pyboard
|
||||
.. method:: timerchannel.callback(fun)
|
||||
|
||||
.. method:: timerchannel.callback(fun)
|
||||
Set the function to be called when the timer channel triggers.
|
||||
``fun`` is passed 1 argument, the timer object.
|
||||
If ``fun`` is ``None`` then the callback will be disabled.
|
||||
|
||||
Set the function to be called when the timer channel triggers.
|
||||
``fun`` is passed 1 argument, the timer object.
|
||||
If ``fun`` is ``None`` then the callback will be disabled.
|
||||
.. method:: timerchannel.capture([value])
|
||||
|
||||
.. only:: port_pyboard
|
||||
Get or set the capture value associated with a channel.
|
||||
capture, compare, and pulse_width are all aliases for the same function.
|
||||
capture is the logical name to use when the channel is in input capture mode.
|
||||
|
||||
.. method:: timerchannel.capture([value])
|
||||
|
||||
Get or set the capture value associated with a channel.
|
||||
capture, compare, and pulse_width are all aliases for the same function.
|
||||
capture is the logical name to use when the channel is in input capture mode.
|
||||
|
||||
.. method:: timerchannel.compare([value])
|
||||
|
||||
Get or set the compare value associated with a channel.
|
||||
capture, compare, and pulse_width are all aliases for the same function.
|
||||
compare is the logical name to use when the channel is in output compare mode.
|
||||
|
||||
.. method:: timerchannel.pulse_width([value])
|
||||
|
||||
Get or set the pulse width value associated with a channel.
|
||||
capture, compare, and pulse_width are all aliases for the same function.
|
||||
pulse_width is the logical name to use when the channel is in PWM mode.
|
||||
|
||||
In edge aligned mode, a pulse_width of ``period + 1`` corresponds to a duty cycle of 100%
|
||||
In center aligned mode, a pulse width of ``period`` corresponds to a duty cycle of 100%
|
||||
|
||||
.. method:: timerchannel.pulse_width_percent([value])
|
||||
|
||||
Get or set the pulse width percentage associated with a channel. The value
|
||||
is a number between 0 and 100 and sets the percentage of the timer period
|
||||
for which the pulse is active. The value can be an integer or
|
||||
floating-point number for more accuracy. For example, a value of 25 gives
|
||||
a duty cycle of 25%.
|
||||
.. method:: timerchannel.compare([value])
|
||||
|
||||
Get or set the compare value associated with a channel.
|
||||
capture, compare, and pulse_width are all aliases for the same function.
|
||||
compare is the logical name to use when the channel is in output compare mode.
|
||||
|
||||
.. method:: timerchannel.pulse_width([value])
|
||||
|
||||
Get or set the pulse width value associated with a channel.
|
||||
capture, compare, and pulse_width are all aliases for the same function.
|
||||
pulse_width is the logical name to use when the channel is in PWM mode.
|
||||
|
||||
In edge aligned mode, a pulse_width of ``period + 1`` corresponds to a duty cycle of 100%
|
||||
In center aligned mode, a pulse width of ``period`` corresponds to a duty cycle of 100%
|
||||
|
||||
.. method:: timerchannel.pulse_width_percent([value])
|
||||
|
||||
Get or set the pulse width percentage associated with a channel. The value
|
||||
is a number between 0 and 100 and sets the percentage of the timer period
|
||||
for which the pulse is active. The value can be an integer or
|
||||
floating-point number for more accuracy. For example, a value of 25 gives
|
||||
a duty cycle of 25%.
|
||||
|
||||
@ -16,12 +16,10 @@ UART objects can be created and initialised using::
|
||||
uart = UART(1, 9600) # init with given baudrate
|
||||
uart.init(9600, bits=8, parity=None, stop=1) # init with given parameters
|
||||
|
||||
.. only:: port_pyboard
|
||||
Bits can be 7, 8 or 9. Parity can be None, 0 (even) or 1 (odd). Stop can be 1 or 2.
|
||||
|
||||
Bits can be 7, 8 or 9. Parity can be None, 0 (even) or 1 (odd). Stop can be 1 or 2.
|
||||
|
||||
*Note:* with parity=None, only 8 and 9 bits are supported. With parity enabled,
|
||||
only 7 and 8 bits are supported.
|
||||
*Note:* with parity=None, only 8 and 9 bits are supported. With parity enabled,
|
||||
only 7 and 8 bits are supported.
|
||||
|
||||
A UART object acts like a `stream` object and reading and writing is done
|
||||
using the standard stream methods::
|
||||
@ -32,84 +30,91 @@ using the standard stream methods::
|
||||
uart.readinto(buf) # read and store into the given buffer
|
||||
uart.write('abc') # write the 3 characters
|
||||
|
||||
.. only:: port_pyboard
|
||||
Individual characters can be read/written using::
|
||||
|
||||
Individual characters can be read/written using::
|
||||
uart.readchar() # read 1 character and returns it as an integer
|
||||
uart.writechar(42) # write 1 character
|
||||
|
||||
uart.readchar() # read 1 character and returns it as an integer
|
||||
uart.writechar(42) # write 1 character
|
||||
To check if there is anything to be read, use::
|
||||
|
||||
To check if there is anything to be read, use::
|
||||
|
||||
uart.any() # returns the number of characters waiting
|
||||
uart.any() # returns the number of characters waiting
|
||||
|
||||
|
||||
*Note:* The stream functions ``read``, ``write``, etc. are new in MicroPython v1.3.4.
|
||||
Earlier versions use ``uart.send`` and ``uart.recv``.
|
||||
*Note:* The stream functions ``read``, ``write``, etc. are new in MicroPython v1.3.4.
|
||||
Earlier versions use ``uart.send`` and ``uart.recv``.
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. only:: port_pyboard
|
||||
.. class:: pyb.UART(bus, ...)
|
||||
|
||||
.. class:: pyb.UART(bus, ...)
|
||||
|
||||
Construct a UART object on the given bus. ``bus`` can be 1-6, or 'XA', 'XB', 'YA', or 'YB'.
|
||||
With no additional parameters, the UART object is created but not
|
||||
initialised (it has the settings from the last initialisation of
|
||||
the bus, if any). If extra arguments are given, the bus is initialised.
|
||||
See ``init`` for parameters of initialisation.
|
||||
Construct a UART object on the given bus.
|
||||
For Pyboard ``bus`` can be 1-4, 6, 'XA', 'XB', 'YA', or 'YB'.
|
||||
For Pyboard Lite ``bus`` can be 1, 2, 6, 'XB', or 'YA'.
|
||||
For Pyboard D ``bus`` can be 1-4, 'XA', 'YA' or 'YB'.
|
||||
With no additional parameters, the UART object is created but not
|
||||
initialised (it has the settings from the last initialisation of
|
||||
the bus, if any). If extra arguments are given, the bus is initialised.
|
||||
See ``init`` for parameters of initialisation.
|
||||
|
||||
The physical pins of the UART busses are:
|
||||
|
||||
- ``UART(4)`` is on ``XA``: ``(TX, RX) = (X1, X2) = (PA0, PA1)``
|
||||
- ``UART(1)`` is on ``XB``: ``(TX, RX) = (X9, X10) = (PB6, PB7)``
|
||||
- ``UART(6)`` is on ``YA``: ``(TX, RX) = (Y1, Y2) = (PC6, PC7)``
|
||||
- ``UART(3)`` is on ``YB``: ``(TX, RX) = (Y9, Y10) = (PB10, PB11)``
|
||||
- ``UART(2)`` is on: ``(TX, RX) = (X3, X4) = (PA2, PA3)``
|
||||
The physical pins of the UART busses on Pyboard are:
|
||||
|
||||
The Pyboard Lite supports UART(1), UART(2) and UART(6) only. Pins are as above except:
|
||||
- ``UART(4)`` is on ``XA``: ``(TX, RX) = (X1, X2) = (PA0, PA1)``
|
||||
- ``UART(1)`` is on ``XB``: ``(TX, RX) = (X9, X10) = (PB6, PB7)``
|
||||
- ``UART(6)`` is on ``YA``: ``(TX, RX) = (Y1, Y2) = (PC6, PC7)``
|
||||
- ``UART(3)`` is on ``YB``: ``(TX, RX) = (Y9, Y10) = (PB10, PB11)``
|
||||
- ``UART(2)`` is on: ``(TX, RX) = (X3, X4) = (PA2, PA3)``
|
||||
|
||||
- ``UART(2)`` is on: ``(TX, RX) = (X1, X2) = (PA2, PA3)``
|
||||
The Pyboard Lite supports UART(1), UART(2) and UART(6) only, pins are:
|
||||
|
||||
- ``UART(1)`` is on ``XB``: ``(TX, RX) = (X9, X10) = (PB6, PB7)``
|
||||
- ``UART(6)`` is on ``YA``: ``(TX, RX) = (Y1, Y2) = (PC6, PC7)``
|
||||
- ``UART(2)`` is on: ``(TX, RX) = (X1, X2) = (PA2, PA3)``
|
||||
|
||||
The Pyboard D supports UART(1), UART(2), UART(3) and UART(4) only, pins are:
|
||||
|
||||
- ``UART(4)`` is on ``XA``: ``(TX, RX) = (X1, X2) = (PA0, PA1)``
|
||||
- ``UART(1)`` is on ``YA``: ``(TX, RX) = (Y1, Y2) = (PA9, PA10)``
|
||||
- ``UART(3)`` is on ``YB``: ``(TX, RX) = (Y9, Y10) = (PB10, PB11)``
|
||||
- ``UART(2)`` is on: ``(TX, RX) = (X3, X4) = (PA2, PA3)``
|
||||
|
||||
*Note:* Pyboard D has ``UART(1)`` on ``YA``, unlike Pyboard and Pyboard Lite that both
|
||||
have ``UART(1)`` on ``XB`` and ``UART(6)`` on ``YA``.
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. only:: port_pyboard
|
||||
.. method:: UART.init(baudrate, bits=8, parity=None, stop=1, *, timeout=0, flow=0, timeout_char=0, read_buf_len=64)
|
||||
|
||||
.. method:: UART.init(baudrate, bits=8, parity=None, stop=1, \*, timeout=1000, flow=0, timeout_char=0, read_buf_len=64)
|
||||
|
||||
Initialise the UART bus with the given parameters:
|
||||
|
||||
- ``baudrate`` is the clock rate.
|
||||
- ``bits`` is the number of bits per character, 7, 8 or 9.
|
||||
- ``parity`` is the parity, ``None``, 0 (even) or 1 (odd).
|
||||
- ``stop`` is the number of stop bits, 1 or 2.
|
||||
- ``flow`` sets the flow control type. Can be 0, ``UART.RTS``, ``UART.CTS``
|
||||
or ``UART.RTS | UART.CTS``.
|
||||
- ``timeout`` is the timeout in milliseconds to wait for writing/reading the first character.
|
||||
- ``timeout_char`` is the timeout in milliseconds to wait between characters while writing or reading.
|
||||
- ``read_buf_len`` is the character length of the read buffer (0 to disable).
|
||||
|
||||
This method will raise an exception if the baudrate could not be set within
|
||||
5% of the desired value. The minimum baudrate is dictated by the frequency
|
||||
of the bus that the UART is on; UART(1) and UART(6) are APB2, the rest are on
|
||||
APB1. The default bus frequencies give a minimum baudrate of 1300 for
|
||||
UART(1) and UART(6) and 650 for the others. Use :func:`pyb.freq <pyb.freq>`
|
||||
to reduce the bus frequencies to get lower baudrates.
|
||||
|
||||
*Note:* with parity=None, only 8 and 9 bits are supported. With parity enabled,
|
||||
only 7 and 8 bits are supported.
|
||||
Initialise the UART bus with the given parameters:
|
||||
|
||||
- ``baudrate`` is the clock rate.
|
||||
- ``bits`` is the number of bits per character, 7, 8 or 9.
|
||||
- ``parity`` is the parity, ``None``, 0 (even) or 1 (odd).
|
||||
- ``stop`` is the number of stop bits, 1 or 2.
|
||||
- ``flow`` sets the flow control type. Can be 0, ``UART.RTS``, ``UART.CTS``
|
||||
or ``UART.RTS | UART.CTS``.
|
||||
- ``timeout`` is the timeout in milliseconds to wait for writing/reading the first character.
|
||||
- ``timeout_char`` is the timeout in milliseconds to wait between characters while writing or reading.
|
||||
- ``read_buf_len`` is the character length of the read buffer (0 to disable).
|
||||
|
||||
This method will raise an exception if the baudrate could not be set within
|
||||
5% of the desired value. The minimum baudrate is dictated by the frequency
|
||||
of the bus that the UART is on; UART(1) and UART(6) are APB2, the rest are on
|
||||
APB1. The default bus frequencies give a minimum baudrate of 1300 for
|
||||
UART(1) and UART(6) and 650 for the others. Use :func:`pyb.freq <pyb.freq>`
|
||||
to reduce the bus frequencies to get lower baudrates.
|
||||
|
||||
*Note:* with parity=None, only 8 and 9 bits are supported. With parity enabled,
|
||||
only 7 and 8 bits are supported.
|
||||
|
||||
.. method:: UART.deinit()
|
||||
|
||||
Turn off the UART bus.
|
||||
|
||||
.. only:: port_pyboard
|
||||
.. method:: UART.any()
|
||||
|
||||
.. method:: UART.any()
|
||||
|
||||
Returns the number of bytes waiting (may be 0).
|
||||
Returns the number of bytes waiting (may be 0).
|
||||
|
||||
.. method:: UART.read([nbytes])
|
||||
|
||||
@ -120,13 +125,11 @@ Methods
|
||||
If ``nbytes`` is not given then the method reads as much data as possible. It
|
||||
returns after the timeout has elapsed.
|
||||
|
||||
.. only:: port_pyboard
|
||||
*Note:* for 9 bit characters each character takes two bytes, ``nbytes`` must
|
||||
be even, and the number of characters is ``nbytes/2``.
|
||||
|
||||
*Note:* for 9 bit characters each character takes two bytes, ``nbytes`` must
|
||||
be even, and the number of characters is ``nbytes/2``.
|
||||
|
||||
Return value: a bytes object containing the bytes read in. Returns ``None``
|
||||
on timeout.
|
||||
Return value: a bytes object containing the bytes read in. Returns ``None``
|
||||
on timeout.
|
||||
|
||||
.. method:: UART.readchar()
|
||||
|
||||
@ -152,22 +155,18 @@ Methods
|
||||
|
||||
.. method:: UART.write(buf)
|
||||
|
||||
.. only:: port_pyboard
|
||||
Write the buffer of bytes to the bus. If characters are 7 or 8 bits wide
|
||||
then each byte is one character. If characters are 9 bits wide then two
|
||||
bytes are used for each character (little endian), and ``buf`` must contain
|
||||
an even number of bytes.
|
||||
|
||||
Write the buffer of bytes to the bus. If characters are 7 or 8 bits wide
|
||||
then each byte is one character. If characters are 9 bits wide then two
|
||||
bytes are used for each character (little endian), and ``buf`` must contain
|
||||
an even number of bytes.
|
||||
Return value: number of bytes written. If a timeout occurs and no bytes
|
||||
were written returns ``None``.
|
||||
|
||||
Return value: number of bytes written. If a timeout occurs and no bytes
|
||||
were written returns ``None``.
|
||||
.. method:: UART.writechar(char)
|
||||
|
||||
.. only:: port_pyboard
|
||||
|
||||
.. method:: UART.writechar(char)
|
||||
|
||||
Write a single character on the bus. ``char`` is an integer to write.
|
||||
Return value: ``None``. See note below if CTS flow control is used.
|
||||
Write a single character on the bus. ``char`` is an integer to write.
|
||||
Return value: ``None``. See note below if CTS flow control is used.
|
||||
|
||||
.. method:: UART.sendbreak()
|
||||
|
||||
@ -178,68 +177,64 @@ Methods
|
||||
Constants
|
||||
---------
|
||||
|
||||
.. only:: port_pyboard
|
||||
.. data:: UART.RTS
|
||||
UART.CTS
|
||||
|
||||
.. data:: UART.RTS
|
||||
.. data:: UART.CTS
|
||||
|
||||
to select the flow control type.
|
||||
to select the flow control type.
|
||||
|
||||
Flow Control
|
||||
------------
|
||||
|
||||
.. only:: port_pyboard
|
||||
On Pyboards V1 and V1.1 ``UART(2)`` and ``UART(3)`` support RTS/CTS hardware flow control
|
||||
using the following pins:
|
||||
|
||||
On Pyboards V1 and V1.1 ``UART(2)`` and ``UART(3)`` support RTS/CTS hardware flow control
|
||||
using the following pins:
|
||||
- ``UART(2)`` is on: ``(TX, RX, nRTS, nCTS) = (X3, X4, X2, X1) = (PA2, PA3, PA1, PA0)``
|
||||
- ``UART(3)`` is on :``(TX, RX, nRTS, nCTS) = (Y9, Y10, Y7, Y6) = (PB10, PB11, PB14, PB13)``
|
||||
|
||||
- ``UART(2)`` is on: ``(TX, RX, nRTS, nCTS) = (X3, X4, X2, X1) = (PA2, PA3, PA1, PA0)``
|
||||
- ``UART(3)`` is on :``(TX, RX, nRTS, nCTS) = (Y9, Y10, Y7, Y6) = (PB10, PB11, PB14, PB13)``
|
||||
On the Pyboard Lite only ``UART(2)`` supports flow control on these pins:
|
||||
|
||||
On the Pyboard Lite only ``UART(2)`` supports flow control on these pins:
|
||||
``(TX, RX, nRTS, nCTS) = (X1, X2, X4, X3) = (PA2, PA3, PA1, PA0)``
|
||||
|
||||
``(TX, RX, nRTS, nCTS) = (X1, X2, X4, X3) = (PA2, PA3, PA1, PA0)``
|
||||
In the following paragraphs the term "target" refers to the device connected to
|
||||
the UART.
|
||||
|
||||
In the following paragraphs the term "target" refers to the device connected to
|
||||
the UART.
|
||||
When the UART's ``init()`` method is called with ``flow`` set to one or both of
|
||||
``UART.RTS`` and ``UART.CTS`` the relevant flow control pins are configured.
|
||||
``nRTS`` is an active low output, ``nCTS`` is an active low input with pullup
|
||||
enabled. To achieve flow control the Pyboard's ``nCTS`` signal should be connected
|
||||
to the target's ``nRTS`` and the Pyboard's ``nRTS`` to the target's ``nCTS``.
|
||||
|
||||
When the UART's ``init()`` method is called with ``flow`` set to one or both of
|
||||
``UART.RTS`` and ``UART.CTS`` the relevant flow control pins are configured.
|
||||
``nRTS`` is an active low output, ``nCTS`` is an active low input with pullup
|
||||
enabled. To achieve flow control the Pyboard's ``nCTS`` signal should be connected
|
||||
to the target's ``nRTS`` and the Pyboard's ``nRTS`` to the target's ``nCTS``.
|
||||
CTS: target controls Pyboard transmitter
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
CTS: target controls Pyboard transmitter
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
If CTS flow control is enabled the write behaviour is as follows:
|
||||
|
||||
If CTS flow control is enabled the write behaviour is as follows:
|
||||
If the Pyboard's ``UART.write(buf)`` method is called, transmission will stall for
|
||||
any periods when ``nCTS`` is ``False``. This will result in a timeout if the entire
|
||||
buffer was not transmitted in the timeout period. The method returns the number of
|
||||
bytes written, enabling the user to write the remainder of the data if required. In
|
||||
the event of a timeout, a character will remain in the UART pending ``nCTS``. The
|
||||
number of bytes composing this character will be included in the return value.
|
||||
|
||||
If the Pyboard's ``UART.write(buf)`` method is called, transmission will stall for
|
||||
any periods when ``nCTS`` is ``False``. This will result in a timeout if the entire
|
||||
buffer was not transmitted in the timeout period. The method returns the number of
|
||||
bytes written, enabling the user to write the remainder of the data if required. In
|
||||
the event of a timeout, a character will remain in the UART pending ``nCTS``. The
|
||||
number of bytes composing this character will be included in the return value.
|
||||
|
||||
If ``UART.writechar()`` is called when ``nCTS`` is ``False`` the method will time
|
||||
out unless the target asserts ``nCTS`` in time. If it times out ``OSError 116``
|
||||
will be raised. The character will be transmitted as soon as the target asserts ``nCTS``.
|
||||
If ``UART.writechar()`` is called when ``nCTS`` is ``False`` the method will time
|
||||
out unless the target asserts ``nCTS`` in time. If it times out ``OSError 116``
|
||||
will be raised. The character will be transmitted as soon as the target asserts ``nCTS``.
|
||||
|
||||
RTS: Pyboard controls target's transmitter
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
RTS: Pyboard controls target's transmitter
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
If RTS flow control is enabled, behaviour is as follows:
|
||||
|
||||
If buffered input is used (``read_buf_len`` > 0), incoming characters are buffered.
|
||||
If the buffer becomes full, the next character to arrive will cause ``nRTS`` to go
|
||||
``False``: the target should cease transmission. ``nRTS`` will go ``True`` when
|
||||
characters are read from the buffer.
|
||||
|
||||
Note that the ``any()`` method returns the number of bytes in the buffer. Assume a
|
||||
buffer length of ``N`` bytes. If the buffer becomes full, and another character arrives,
|
||||
``nRTS`` will be set False, and ``any()`` will return the count ``N``. When
|
||||
characters are read the additional character will be placed in the buffer and will
|
||||
be included in the result of a subsequent ``any()`` call.
|
||||
|
||||
If buffered input is not used (``read_buf_len`` == 0) the arrival of a character will
|
||||
cause ``nRTS`` to go ``False`` until the character is read.
|
||||
If RTS flow control is enabled, behaviour is as follows:
|
||||
|
||||
If buffered input is used (``read_buf_len`` > 0), incoming characters are buffered.
|
||||
If the buffer becomes full, the next character to arrive will cause ``nRTS`` to go
|
||||
``False``: the target should cease transmission. ``nRTS`` will go ``True`` when
|
||||
characters are read from the buffer.
|
||||
|
||||
Note that the ``any()`` method returns the number of bytes in the buffer. Assume a
|
||||
buffer length of ``N`` bytes. If the buffer becomes full, and another character arrives,
|
||||
``nRTS`` will be set False, and ``any()`` will return the count ``N``. When
|
||||
characters are read the additional character will be placed in the buffer and will
|
||||
be included in the result of a subsequent ``any()`` call.
|
||||
|
||||
If buffered input is not used (``read_buf_len`` == 0) the arrival of a character will
|
||||
cause ``nRTS`` to go ``False`` until the character is read.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user