diff options
author | Damien George <damien.p.george@gmail.com> | 2017-08-13 21:24:32 +1000 |
---|---|---|
committer | Damien George <damien.p.george@gmail.com> | 2017-08-13 21:24:32 +1000 |
commit | b084ab966e2d4d18c9b2be8317541313f0e2586f (patch) | |
tree | ee073405e02d4d23c1bdb1e85b0c5a9842e0010b /docs/esp8266/tutorial | |
parent | 72912c753a31301efb7d6b2f35dd1e3e64b98cd4 (diff) | |
parent | 2c2fc070ecca654b0e9a80e1d9a342d46c6f0cdb (diff) | |
download | micropython-b084ab966e2d4d18c9b2be8317541313f0e2586f.tar.gz micropython-b084ab966e2d4d18c9b2be8317541313f0e2586f.zip |
Merge tag 'v1.8' into parse-bytecode
First general release of ESP8266 port, and support for frozen bytecode
This release marks the first general release of official ESP8266 support
within the MicroPython code base. The ESP8266 port has many improvements
and additions, including: websocket and webrepl modules, deep-sleep mode,
reading on UART, enhanced I2C support, enhanced network configuration,
full sequence of start-up scripts (built-in _boot.py, boot.py and
main.py), improved filesystem support with automatic flash-size detection
as well as documentation and a tutorial.
Known issues with ESP8266 port are:
- Basic SSL support is available but it works only with relatively short
data lengths (a few kilobytes).
- WebREPL over SSL is not supported.
- Only 5 or so WebREPL sessions in succession can be started (including
file transfer sessions), after that the board requires a hard reset.
- File transfer over WebREPL has issues with large files (above a few
tens of kilobytes).
- By design, only one concurrent WebREPL connection is supported.
- Soft reset doesn't reset the network stack.
In addition to ESP8266 support, this release brings frozen bytecode
which allows to compile bytecode offline and link it into the firmware,
completely eliminating the need for compilation (and the associated
RAM usage) at runtime. Basic async/await syntax is now supported, and
qstrs are now auto-generated in the build system.
A detailed list of changes is given below.
README:
- explicitly point to required dependencies section
- promote "docs" and "tests" to "major components"
- mention support "async" keyword from Python 3.5
ACKNOWLEDGEMENTS:
- add list of 842 backers from the ESP8266 campaign
py core:
- modbuiltins: add comment about setting "_" special var
- add async/await/async for/async with syntax
- fix constant folding and inline-asm to work with new async grammar
- emitglue: move typedef of mp_raw_code_t from .c to .h file
- emitglue: make mp_raw_code_t* arguments constant pointers
- makeqstrdata: factor out some code to functions that can be reused
- add ability to have frozen persistent bytecode from .mpy files
- makeqstrdata: add more names for escaped chars and esc non-printable
- simplify "and" action within parser by making ident-rules explicit
- makeqstrdata: fix rendering of qstrs that have non-printable ASCII
- makeqstrdata: add special case to handle \n qstr
- declare help, input, open builtins in core
- map: change hash-table allocation policy to be less aggressive
- makeqstrdefs: add script to automate extraction of qstr from sources
- frozenmod: pass the source name of the frozen module to the lexer
- rework QSTR extraction to work in simple and obvious way
- divide "split" and "cat" phases of qstr extraction for better efficiency
- fix bug passing a string as a keyword arg in a dict
- move call_function_*_protected() functions to py/ for reuse
- makeqstrdefs.py: windows compatibility
- obj.h: when constructing a small-int cast to mp_uint_t for bit-shift
- emitnative: use MP_OBJ_NEW_SMALL_INT instead of manual bit shifting
- vm: "yield from" didn't handle MP_OBJ_STOP_ITERATION optimization
- modio: rename module name to "uio" for consistency with other modules
- modcollections: rename module name have "u" prefix for consistency
extmod:
- add initial framebuf module
- add generic machine.I2C class, with bit-bang I2C
- machine_i2c: fix I2C reading by sending ack/nack at end of byte
- machine_i2c: implement I2C memory reading/writing
- moduos_dupterm: don't swallow exceptions in dupterm's read()/write()
- modlwip: lwip_tcp_receive(): Properly handle EOF for non-blocking sock
- modlwip: more debug messages for various edge conditions
- fsusermount: in mount/mkfs, deregister VFS object on error
- modlwip: lwip_tcp_send(): full error handling
- modlwip: lwip_tcp_receive(): full error handling
- modlwip: add ability to run callback on "recv" and "accept" events
- machine_i2c: allow mp_hal_pin_obj_t to be any type, not a ptr
- modlwip: protect recv/accept Python callback against exceptions
- modlwip: workaround esp8266 sendto issue where 1 is returned
- modlwip: add print_pcbs() debug function
- modwebsocket: handle CLOSE control frame
- modussl: throw Python exceptions in case of errors
- modussl: support server-side SSL sockets
- modussl: SSL_OK from ssl_read() means "no user data so far"
- modwebrepl: module to handle WebREPL protocol
- modwebrepl: initial implementation of "get file" operation
- modwebrepl: keep reading data when there's something to read
- modwebrepl: GET_FILE: Send length-prefix chunk with one write()
- modwebrepl: add rate-limiting workaround for broken network drivers
- modwebrepl: set debugging by default to off
- modwebrepl: add support for password
- modlwip: implement sendall() method for TCP sockets
- fix typo of macro that detects if float is enabled
lib:
- utils/printf: rework overriding printer of DEBUG_printf()
- utils/pyexec: condition-out GC calls from pyexec
- utils/pyhelp: extract implementation of help(obj) to a library function
- axtls: update to the latest upstream, fix reported MacOSX build issue
drivers:
- add SSD1306 OLED driver, with I2C and SPI interfaces
tools:
- mpy-tool.py: new tool to work with .mpy files; currently it can freeze them
- mpy-tool.py: add support for Python 2.7
tests:
- add 6 tests for async await/for/with
- add .exp files for async tests, so they can run with Python 3.4
- fix dict1.py so it doesn't rely on the order of dict elems
- extmod: move split-on-empty-match tests to a separate test file
- add testcase for yielding from a stopped generator
- run-bench-tests: process tests in alphabetical order
- update for _io/_collections module having been renamed
minimal port:
- add example of frozen persistent bytecode (.mpy file)
- disable async/await syntax
unix port:
- build with MICROPY_PY_UHASHLIB_SHA1 if already building with axTLS
- make sure build dir exists before accessing it for freezing upip
- Makefile: make install more compatible (BSD, etc.)
windows port:
- msvc: implement automatic qstr generation using makeqstrdefs
stmhal port:
- implement basic C-level pin HAL
- use new generic I2C object in machine module
- enable framebuf module
- properly handle RTS/CTS flow control for buf/unbuf transfers
- add Makefile option FROZEN_MPY_DIR to support frozen bytecode
- for frozen bytecode generation, add dependency of qstr file
- l4: add CMSIS files to support STM32L476
- l4: add basic STM32L4xx HAL files
- l4: adapt UART HAL to avoid 64-bit integer division
- update HALCOMMITS due to change to hal
- l4: add board definition files for STM32L476DISC
- l4: add line to Makefile for building L4 series
- l4: modify adc.c to add support for STM32L4 series
- l4: modify uart.c to support L4 MCU
- l4: modify usbd_conf.c to support L4 MCU
- l4: modify rtc.c to support L4 MCU
- l4: modify timer.c to support L4 MCU
- fix machine.unique_id() function to work for all MCUs
- l4: modify mphalport to support L4 MCU
- l4: modify flash.c and storage.c to support L4 MCU
- l4: add support for external interrupts/events
- accel: raise an exception if the accel couldn't be initialised
- use pyhelp_print_obj function
- change i2c.scan() method to scan addresses 0x08-0x77
- fix typo of macro that detects if float is enabled
cc3200 port:
- use pyhelp_print_obj function
- change i2c.scan() method to scan addresses 0x08-0x77
- disable async/await syntax
esp8266 port:
- enable websocket module
- modnetwork: .config(): Check interface whose config is requested
- modnetwork: .config(): Add "authmode" param
- modnetwork: .config(): Add "password" param (W/O)
- add Python modules for initial configuration
- scripts/inisetup.py: set WPA/WPA2 AP mode with a predefined password
- protect modpyb.h header file from multiple inclusions
- implement basic C-level pin HAL
- switch from using custom I2C driver to generic extmod one
- enable framebuf module
- in callback helpers, pop nlr_buf on successful call
- esp_mphal: don't swallow exceptions in dupterm's read()/write()
- esp_mphal: call_dupterm_read(): Fix order of deactivating on EOF
- remove pin_id field from C pin object
- add dummy entries for non-existing pins to simplify pin logic
- add hard IRQ callbacks for pin change on GPIO0-15
- separate 1-wire timing funcs from Python module to save iRAM
- switch integer arith routines to BootROM
- scripts/port_diag.py: module to collect diagnostic info
- enable input() builtin
- scripts/_boot: mount block device on "" instead of "/"
- moduos: add uos.mkdir function
- modmachine: add reset_cause() function
- adapt port to use new auto-qstr generation
- moduos: add dupterm_notify() function
- esp_mphal: protect dupterm_task_handler() from recursive exec
- README.md: update feature list for current state of affairs
- modesp: allow esp.deepsleep to take 2nd arg for RF wake opt
- scripts/flashbdev: use all available space in 1MB FlashROM for FS
- modesp: add flash_size() function
- scripts: don't try to create filesystem on 512KB devices or less
- modnetwork: .config(): Add "channel" param
- scripts/flashbdev: disable debug output/checks
- scripts/_boot: print notice when initial setup is executed
- scripts/flashbdev: correct bootloader flash size to match real size
- modnetwork: .config(): Add "hidden ESSID" param
- implement basic deep-sleep capabilities
- add uart_rx_wait and uart_rx_char functions
- implement UART.read functionality
- uart: remove obsolete UART rx buffering code
- esp_mphal: remove mp_hal_feed_watchdog
- convert mp_hal_pin_obj_t from pin ptr to simple integer
- allow GPIO16 to be used as a pin in the uPy pin HAL
- change software SPI driver to use general pin HAL
- scripts/websocket_helper: module encapsulating handshake sequences
- scripts/websocket_helper: disable debug output
- scripts/webrepl: webREPL based on C-level websocket object
- scripts/webrepl: convert to persistent daemon
- scripts/webrepl: don't start on import
- scripts/webrepl: allow to override port
- scripts/webrepl: print connection address
- scripts/webrepl: print client address for incoming connections
- scripts/flashbdev: use all available Flash for filesystem
- scripts/webrepl: add "ws://" to "daemon started at" message
- Makefile: add target to build axTLS
- esp8266.ld: put axTLS to FlashROM
- Makefile: override abort() when building axtls
- axtls_helpers: helper/wrapper functions for axTLS
- tests/onewire.py: don't run test on import
- Makefile: support linking with axTLS built from source
- Makefile: enable "ussl" module; axTLS should be built first using "make axtls"
- move pyb.info() function to esp module and remove pyb module
- move onewire.py, neopixel.py drivers from tests/ to scripts/
- scripts/onewire.py: simplify and improve 1-wire driver
- scripts/neopixel.py: remove test function from neopixel driver
- set suitable values for axtls's RT_MAX_PLAIN_LENGTH & RT_EXTRA
- README: add recently required step of 'make axtls'
- modnetwork: make WLAN.ifconfig() read/write
- help: implement help() builtin
- help: add cheatsheet for basic WiFi configuration
- enable WebREPL file transfer rate limiting
- enable webrepl module
- scripts: move all of initial setup to inisetup module
- scripts/inisetup: create default boot.py in filesystem
- scripts/webrepl: connection ack prompt is now printed by modwebrepl
- scripts/webrepl: switch to using _webrepl object wrapper
- scripts/webrepl: add "first connection" mode to setup password
- README: mention WebREPL
- Makefile: be sure to pass cross-compiling AR when building axtls
- scripts/webrepl_setup: reject too short passwords
- change platform name from ESP8266 to esp8266
- modnetwork: remove deprecated wifi_mode()
- esp_mphal: add ets_esf_free_bufs(), etc. functions
- modesp: add esf_free_bufs() debugging function
- modesp: add malloc() and free() functions
- scripts/inisetup: enable WebREPL auto-start on boot
- modnetwork: remove .mac() method, move to .config("mac")
- scripts/inisetup: update for nic.mac() method being gone
- scripts/neopixel.py: swap red and green in pixel accessor
- modpybpin: use enum+array instead of struct for parsing args
- modpybpin: use None instead of PULL_NONE for no-pull config
- modpybpin: make pin.irq() methods take keyword args
- tutorial: mention that esptool is available via pip
- scripts/ntptime: add simple NTP client
docs:
- esp: enumerate flash access functions
- machine: start to update for esp8266 port
- speed_python: clarify/generalize "Buffers" subsection
- speed_python: generalize "Floating point" subsection
- speed_python: add many more details on memoryviews
- machine: reset_cause() has been implemented for esp8266
- topindex.html: esp8266: Enable quickref/general on the main page
- esp8266/general: start "General information" for esp8266
- esp8266: add info about using deep-sleep mode to quickref
- esp8266/tutorial: add tutorial placeholder page
- ustruct: there's no complete "struct" module, only "ustruct" subset
- esp8266: include usocket module reference
- library/usocket: add link to CPython's socket module
- usocket: socket-specific exceptions are for WiPy only
- usocket: socket.IPPROTO_SEC is WiPy-specific
- usocket: describe address format once at the beginning
- network: esp8266: scan(): add note that bssid is bytes object
- library: group MicroPython-specific modules under separate heading
- library/index: move WiPy "micro-libraries" under corresponding heading
- library/index: esp8266 has the same set of stdlibs as pyboard/unix
- module "time" is actually "utime"
- library/index: make single section for "micro-ified" modules
- library/index: order sections from the most to least standard modules
- Makefile: default BUILDDIR based on MICROPY_PORT
- library: "os" module is actually "uos"
- fix uos and utime heading underlines to be the correct length
- library/utime: add more time functions for unix and esp8266 ports
- utime: describe time() peculiarities in MicroPython
- utime: describe sleep() peculiarities in MicroPython
- library: consistently use admonitions for CPython differences
- ubinascii: clean up grammar
- network: esp8266: Add wlan.ifconfig() method
- network: esp8266: Describe wlan.config() method
- make the short port names in the port/version sidebar lowercase
- esp8266: update quickref to reflect changes to 1-wire and NeoPixel
- library/utime: elaborate on epochs and calendar time maintenance
- esp8266/quickref: add info about WebREPL
- ustruct: document pack_into(), unpack_from()
- sys: document sys.modules
- ustruct: fix argument formatting
- sys: remove port-specific details from description of stdin/out/err
- sys: clarify description of sys.exit()
- sys: clean up print_exception() description
- sys: describe sys.implementation
- sys: describe sys.maxsize
- sys: describe sys.platform is port-neutral manner
- add _collections module reference
- add _io module reference
- _io and _collections were renamed to have standard "u" prefix
- library/machine.I2C: update to reflect ESP8266 implementation
- esp8266/general: webREPL is described in quickref for now
- esp8266/general: add more points to "Multitude of boards" section
- esp8266/general: fix list formatting
- esp8266/general: add techspec section
- esp8266/general: add "Boot process" section
- esp8266_contents: reference general and tutorial docs
- network: esp8266: MAC address is set via .config() method
- esp8266: add ESP8266 tutorial
- machine: generalize docs from just WiPy to other ports
- machine: move WiPy-specific hardware details to its general reference
- machine: more generic description of sleep's, WiPy details to its genref
- machine: idle() description generalization
- library/machine.Pin: update pin docs to reflect ESP8266 support
- esp8266/tutorial: update pins tutorial to reflect changes in API
examples:
- http_server_ssl.py: add HTTPS server example
Diffstat (limited to 'docs/esp8266/tutorial')
-rw-r--r-- | docs/esp8266/tutorial/adc.rst | 19 | ||||
-rw-r--r-- | docs/esp8266/tutorial/filesystem.rst | 70 | ||||
-rw-r--r-- | docs/esp8266/tutorial/index.rst | 32 | ||||
-rw-r--r-- | docs/esp8266/tutorial/intro.rst | 102 | ||||
-rw-r--r-- | docs/esp8266/tutorial/neopixel.rst | 70 | ||||
-rw-r--r-- | docs/esp8266/tutorial/network_basics.rst | 81 | ||||
-rw-r--r-- | docs/esp8266/tutorial/network_tcp.rst | 121 | ||||
-rw-r--r-- | docs/esp8266/tutorial/nextsteps.rst | 12 | ||||
-rw-r--r-- | docs/esp8266/tutorial/onewire.rst | 37 | ||||
-rw-r--r-- | docs/esp8266/tutorial/pins.rst | 75 | ||||
-rw-r--r-- | docs/esp8266/tutorial/powerctrl.rst | 61 | ||||
-rw-r--r-- | docs/esp8266/tutorial/pwm.rst | 87 | ||||
-rw-r--r-- | docs/esp8266/tutorial/repl.rst | 207 |
13 files changed, 974 insertions, 0 deletions
diff --git a/docs/esp8266/tutorial/adc.rst b/docs/esp8266/tutorial/adc.rst new file mode 100644 index 0000000000..fa6fdaba73 --- /dev/null +++ b/docs/esp8266/tutorial/adc.rst @@ -0,0 +1,19 @@ +Analog to Digital Conversion +============================ + +The ESP8266 has a single pin (separate to the GPIO pins) which can be used to +read analog voltages and convert them to a digital value. You can construct +such an ADC pin object using:: + + >>> import machine + >>> adc = machine.ADC(0) + +Then read its value with:: + + >>> adc.read() + 58 + +The values returned from the ``read()`` function are between 0 (for 0.0 volts) +and 1024 (for 1.0 volts). Please note that this input can only tolerate a +maximum of 1.0 volts and you must use a voltage divider circuit to measure +larger voltages. diff --git a/docs/esp8266/tutorial/filesystem.rst b/docs/esp8266/tutorial/filesystem.rst new file mode 100644 index 0000000000..9033a8576f --- /dev/null +++ b/docs/esp8266/tutorial/filesystem.rst @@ -0,0 +1,70 @@ +The internal filesystem +======================= + +If your devices has 1Mbyte or more of storage then it will be set up (upon first +boot) to contain a filesystem. This filesystem uses the FAT format and is +stored in the flash after the MicroPython firmware. + +Creating and reading files +-------------------------- + +MicroPython on the ESP8266 supports the standard way of accessing files in +Python, using the built-in ``open()`` function. + +To create a file try:: + + >>> f = open('data.txt', 'w') + >>> f.write('some data') + 9 + >>> f.close() + +The "9" is the number of bytes that were written with the ``write()`` method. +Then you can read back the contents of this new file using:: + + >>> f = open('data.txt') + >>> f.read() + 'some data' + >>> f.close() + +Note that the default mode when opening a file is to open it in read-only mode, +and as a text file. Specify ``'wb'`` as the second argument to ``open()`` to +open for writing in binary mode, and ``'rb'`` to open for reading in binary +mode. + +Listing file and more +--------------------- + +The os module can be used for further control over the filesystem. First +import the module:: + + >>> import os + +Then try listing the contents of the filesystem:: + + >>> os.listdir() + ['boot.py', 'port_config.py', 'data.txt'] + +You can make directories:: + + >>> os.mkdir('dir') + +And remove entries:: + + >>> os.remove('data.txt') + +Start up scripts +---------------- + +There are two files that are treated specially by the ESP8266 when it starts up: +boot.py and main.py. The boot.py script is executed first (if it exists) and +then once it completes the main.py script is executed. You can create these +files yourself and populate them with the code that you want to run when the +device starts up. + +Accessing the filesystem via WebREPL +------------------------------------ + +You can access the filesystem over WebREPL using the provided command-line +tool. This tool is found at `<https://github.com/micropython/webrepl>`__ +and is called webrepl_cli.py. Please refer to that program for information +on how to use it. diff --git a/docs/esp8266/tutorial/index.rst b/docs/esp8266/tutorial/index.rst new file mode 100644 index 0000000000..1a00afd853 --- /dev/null +++ b/docs/esp8266/tutorial/index.rst @@ -0,0 +1,32 @@ +.. _tutorial-index: + +MicroPython tutorial for ESP8266 +================================ + +This tutorial is intended to get you started using MicroPython on the ESP8266 +system-on-a-chip. If it is your first time it is recommended to follow the +tutorial through in the order below. Otherwise the sections are mostly self +contained, so feel free to skip to those that interest you. + +The tutorial does not assume that you know Python, but it also does not attempt +to explain any of the details of the Python language. Instead it provides you +with commands that are ready to run, and hopes that you will gain a bit of +Python knowledge along the way. To learn more about Python itself please refer +to `<https://www.python.org>`__. + +.. toctree:: + :maxdepth: 1 + :numbered: + + intro.rst + repl.rst + filesystem.rst + network_basics.rst + network_tcp.rst + pins.rst + pwm.rst + adc.rst + powerctrl.rst + onewire.rst + neopixel.rst + nextsteps.rst diff --git a/docs/esp8266/tutorial/intro.rst b/docs/esp8266/tutorial/intro.rst new file mode 100644 index 0000000000..a2c5d1838e --- /dev/null +++ b/docs/esp8266/tutorial/intro.rst @@ -0,0 +1,102 @@ +Introduction to MicroPython on the ESP8266 +========================================== + +Using MicroPython is a great way to get the most of your ESP8266 board. And +vice versa, the ESP8266 chip is a great platform for using MicroPython. This +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 ESP8266 chip. The MicroPython +software supports the ESP8266 chip itself and any board should work. The main +characteristic of a board is how much flash it has, 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. + +The minimum requirement for flash size is 512k. A board with this amount of +flash will not have room for a filesystem, but otherwise is fully functional. +If your board has 1Mbyte or more of flash then it will support a filesystem. + +Names of pins will be given in this tutorial using the chip names (eg GPIO0) +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. + +Deploying the firmware +---------------------- + +The very first thing you need to do is put the MicroPython firmware (compiled +code) on your ESP8266 device. There are two main steps to do this: first you +need to put your device in boot-loader 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. + +If you have a board that has a USB connector, a USB-serial convertor, and has +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 HUZZAH and NodeMCU boards. + +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/themadinventor/esptool/>`__, or install it +using pip:: + + pip install esptool + +It requires Python 2.7, so you may need to use ``pip2`` instead of ``pip`` in +the command above. Any other +flashing program should work, so feel free to try them out, or refer to the +documentation for your board to see its recommendations. + +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 --port /dev/ttyUSB0 --baud 460800 write_flash --flash_size=8m 0 esp8266-2016-05-03-v1.8.bin + +You might need to change the "port" setting to something else relevant for your +PC. You may also need to reduce the baudrate if you get errors when flashing +(eg down to 115200). The filename of the firmware should also match the file +that you have. + +If you have a NodeMCU board, you may need to use the following command to deploy +the firmware (note the "-fm dio" option):: + + esptool.py --port /dev/ttyUSB0 --baud 460800 write_flash --flash_size=8m -fm dio 0 esp8266-2016-05-03-v1.8.bin + +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. The next part of +the tutorial will discuss the prompt in more detail. + +WiFi +---- + +After a fresh install and boot the device configures itself as a WiFi access +point (AP) that you can connect to. The ESSID is of the form MicroPython-xxxxxx +where the x's are replaced with part of the MAC address of your device (so will +be the same everytime, and most likely different for all ESP8266 chips). The +password for the WiFi is micropythoN (note the upper-case N). Its IP address +will be 192.168.4.1 once you connect to its network. WiFi configuration will +be discussed in more detail later in the tutorial. diff --git a/docs/esp8266/tutorial/neopixel.rst b/docs/esp8266/tutorial/neopixel.rst new file mode 100644 index 0000000000..245aed6d46 --- /dev/null +++ b/docs/esp8266/tutorial/neopixel.rst @@ -0,0 +1,70 @@ +Controlling NeoPixels +===================== + +NeoPixels, also known as WS2812 LEDs, are full-colour LEDs that are connected in +serial, are individually addressable, and can have their red, green and blue +components set between 0 and 255. They require precise timing to control them +and there is a special neopixel module to do just this. + +To create a NeoPixel object do the following:: + + >>> import machine, neopixel + >>> np = neopixel.NeoPixel(machine.Pin(4), 8) + +This configures a NeoPixel strip on GPIO4 with 8 pixels. You can adjust the +"4" (pin number) and the "8" (number of pixel) to suit your set up. + +To set the colour of pixels use:: + + >>> np[0] = (255, 0, 0) # set to red, full brightness + >>> np[1] = (0, 128, 0) # set to green, half brightness + >>> np[2] = (0, 0, 64) # set to blue, quarter brightness + +Then use the ``write()`` method to output the colours to the LEDs:: + + >>> np.write() + +The following demo function makes a fancy show on the LEDs:: + + import time + + def demo(np): + n = np.n + + # cycle + for i in range(4 * n): + for j in range(n): + np[j] = (0, 0, 0) + np[i % n] = (255, 255, 255) + np.write() + time.sleep_ms(25) + + # bounce + for i in range(4 * n): + for j in range(n): + np[j] = (0, 0, 128) + if (i // n) % 2 == 0: + np[i % n] = (0, 0, 0) + else: + np[n - 1 - (i % n)] = (0, 0, 0) + np.write() + time.sleep_ms(60) + + # fade in/out + for i in range(0, 4 * 256, 8): + for j in range(n): + if (i // 256) % 2 == 0: + val = i & 0xff + else: + val = 255 - (i & 0xff) + np[j] = (val, 0, 0) + np.write() + + # clear + for i in range(n): + np[i] = (0, 0, 0) + np.write() + +Execute it using:: + + >>> demo(np) diff --git a/docs/esp8266/tutorial/network_basics.rst b/docs/esp8266/tutorial/network_basics.rst new file mode 100644 index 0000000000..02a7054858 --- /dev/null +++ b/docs/esp8266/tutorial/network_basics.rst @@ -0,0 +1,81 @@ +Network basics +============== + +The network module is used to configure the WiFi connection. There are two WiFi +interfaces, one for the station (when the ESP8266 connects to a router) and one +for the access point (for other devices to connect to the ESP8266). Create +instances of these objects using:: + + >>> import network + >>> sta_if = network.WLAN(network.STA_IF) + >>> ap_if = network.WLAN(network.AP_IF) + +You can check if the interfaces are active by:: + + >>> sta_if.active() + False + >>> ap_if.active() + True + +You can also check the network settings of the interface by:: + + >>> ap.ifconfig() + ('192.168.4.1', '255.255.255.0', '192.168.4.1', '8.8.8.8') + +The returned values are: IP address, netmask, gateway, DNS. + +Configuration of the WiFi +------------------------- + +Upon a fresh install the ESP8266 is configured in access point mode, so the +AP_IF interface is active and the STA_IF interface is inactive. You can +configure the module to connect to your own network using the STA_IF interface. + +First activate the station interface:: + + >>> sta_if.active(True) + +Then connect to your WiFi network:: + + >>> sta_if.connect('<your ESSID>', '<your password>') + +To check if the connection is established use:: + + >>> sta_if.isconnected() + +Once established you can check the IP address:: + + >>> sta_if.ifconfig() + ('192.168.0.2', '255.255.255.0', '192.168.0.1', '8.8.8.8') + +You can then disable the access-point interface if you no longer need it:: + + >>> ap_if.active(False) + +Here is a function you can run (or put in your boot.py file) to automatically +connect to your WiFi network:: + + def do_connect(): + import network + sta_if = network.WLAN(network.STA_IF) + if not sta_if.isconnected(): + print('connecting to network...') + sta_if.active(True) + sta_if.connect('<essid>', '<password>') + while not network.isconnected(): + pass + print('network config:', sta_if.ifconfig()) + +Sockets +------- + +Once the WiFi is set up the way to access the network is by using sockets. +A socket represents an endpoint on a network device, and when two sockets are +connected together communication can proceed. +Internet protocols are built on top of sockets, such as email (SMTP), the web +(HTTP), telnet, ssh, among many others. Each of these protocols is assigned +a specific port, which is just an integer. Given an IP address and a port +number you can connect to a remote device and start talking with it. + +The next part of the tutorial discusses how to use sockets to do some common +and useful network tasks. diff --git a/docs/esp8266/tutorial/network_tcp.rst b/docs/esp8266/tutorial/network_tcp.rst new file mode 100644 index 0000000000..0a1cca4457 --- /dev/null +++ b/docs/esp8266/tutorial/network_tcp.rst @@ -0,0 +1,121 @@ +Network - TCP sockets +===================== + +The building block of most of the internet is the TCP socket. These sockets +provide a reliable stream of bytes between the connected network devices. +This part of the tutorial will show how to use TCP sockets in a few different +cases. + +Star Wars Asciimation +--------------------- + +The simplest thing to do is to download data from the internet. In this case +we will use the Star Wars Asciimation service provided by the blinkenlights.nl +website. It uses the telnet protocol on port 23 to stream data to anyone that +connects. It's very simple to use because it doesn't require you to +authenticate (give a username or password), you can just start downloading data +straight away. + +The first thing to do is make sure we have the socket module available:: + + >>> import socket + +Then get the IP address of the server:: + + >>> addr_info = socket.getaddrinfo("towel.blinkenlights.nl", 23) + +The ``getaddrinfo`` function actually returns a list of addresses, and each +address has more information than we need. We want to get just the first valid +address, and then just the IP address and port of the server. To do this use:: + + >>> addr = addr_info[0][-1] + +If you type ``addr_info`` and ``addr`` at the prompt you will see exactly what +information they hold. + +Using the IP address we can make a socket and connect to the server:: + + >>> s = socket.socket() + >>> s.connect(addr[0][-1]) + +Now that we are connected we can download and display the data:: + + >>> while True: + ... 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). + +You should also be able to run this same code on your PC using normal Python if +you want to try it out there. + +HTTP GET request +---------------- + +The next example shows how to download a webpage. HTTP uses port 80 and you +first need to send a "GET" request before you can download anything. As part +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): + _, _, host, path = url.split('/', 3) + addr = socket.getaddrinfo(host, 80)[0][-1] + s = socket.socket() + s.connect(addr) + s.send(bytes('GET /%s HTTP/1.0\r\nHost: %s\r\n\r\n' % (path, host), 'utf8')) + while True: + data = s.recv(100) + if data: + print(str(data, 'utf8'), end='') + else: + break + +Make sure that you import the socket module before running this function. Then +you can try:: + + >>> http_get('http://micropython.org/ks/test.html') + +This should retrieve the webpage and print the HTML to the console. + +Simple HTTP server +------------------ + +The following code creates an simple HTTP server which serves a single webpage +that contains a table with the state of all the GPIO pins:: + + import machine + pins = [machine.Pin(i, machine.Pin.IN) for i in (0, 2, 4, 5, 12, 13, 14, 15)] + + html = """<!DOCTYPE html> + <html> + <head> <title>ESP8266 Pins</title> </head> + <body> <h1>ESP8266 Pins</h1> + <table border="1"> <tr><th>Pin</th><th>Value</th></tr> %s </table> + </body> + </html> + """ + + import socket + addr = socket.getaddrinfo('0.0.0.0', 80)[0][-1] + + s = socket.socket() + s.bind(addr) + s.listen(1) + + print('listening on', addr) + + while True: + cl, addr = s.accept() + print('client connected from', addr) + cl_file = cl.makefile('rwb', 0) + while True: + line = cl_file.readline() + if not line or line == b'\r\n': + 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(response) + cl.close() diff --git a/docs/esp8266/tutorial/nextsteps.rst b/docs/esp8266/tutorial/nextsteps.rst new file mode 100644 index 0000000000..318bd7ddf8 --- /dev/null +++ b/docs/esp8266/tutorial/nextsteps.rst @@ -0,0 +1,12 @@ +Next steps +========== + +That brings us to the end of the tutorial! Hopefully by now you have a good +feel for the capabilities of MicroPython on the ESP8266 and understand how to +control both the WiFi and IO aspects of the chip. + +There are many features that were not covered in this tutorial. The best way +to learn about them is to read the full documentation of the modules, and to +experiment! + +Good luck creating your Internet of Things devices! diff --git a/docs/esp8266/tutorial/onewire.rst b/docs/esp8266/tutorial/onewire.rst new file mode 100644 index 0000000000..c90044b7a8 --- /dev/null +++ b/docs/esp8266/tutorial/onewire.rst @@ -0,0 +1,37 @@ +Controlling 1-wire devices +========================== + +The 1-wire bus is a serial bus that uses just a single wire for communication +(in addition to wires for ground and power). The DS18B20 temperature sensor +is a very popular 1-wire device, and here we show how to use the onewire module +to read from such a device. + +For the following code to work you need to have at least one DS18B20 temperature +sensor with its data line connected to GPIO12. You must also power the sensors +and connect a 4.7k Ohm resistor between the data pin and the power pin. :: + + import time + import machine + import onewire + + # the device is on GPIO12 + dat = machine.Pin(12) + + # create the onewire object + ds = onewire.DS18B20(onewire.OneWire(dat)) + + # scan for devices on the bus + roms = ds.scan() + print('found devices:', roms) + + # loop 10 times and print all temperatures + for i in range(10): + print('temperatures:', end=' ') + ds.convert_temp() + time.sleep_ms(750) + for rom in roms: + print(ds.read_temp(rom), end=' ') + print() + +Note that you must execute the ``convert_temp()`` function to initiate a +temperature reading, then wait at least 750ms before reading the value. diff --git a/docs/esp8266/tutorial/pins.rst b/docs/esp8266/tutorial/pins.rst new file mode 100644 index 0000000000..639267d2ee --- /dev/null +++ b/docs/esp8266/tutorial/pins.rst @@ -0,0 +1,75 @@ +GPIO Pins +========= + +The way to connect your board to the external world, and control other +components, is through the GPIO pins. Not all pins are available to use, +in most cases only pins 0, 2, 4, 5, 12, 13, 14, 15, and 16 can be used. + +The pins are available in the machine module, so make sure you import that +first. Then you can create a pin using:: + + >>> pin = machine.Pin(0) + +Here, the "0" is the pin that you want to access. Usually you want to +configure the pin to be input or output, and you do this when constructing +it. To make an input pin use:: + + >>> pin = machine.Pin(0, machine.Pin.OUT, machine.Pin.PULL_UP) + +You can either use PULL_UP or None for the input pull-mode. If it's +not specified then it defaults to None, which is no pull resistor. +You can read the value on the pin using:: + + >>> pin.value() + 0 + +The pin on your board may return 0 or 1 here, depending on what it's connected +to. To make an output pin use:: + + >>> pin = machine.Pin(0, machine.Pin.OUT) + +Then set its value using:: + + >>> pin.value(0) + >>> pin.value(1) + +Or:: + + >>> pin.low() + >>> pin.high() + +External interrupts +------------------- + +All pins except number 16 can be configured to trigger a hard interrupt if their +input changes. You can set code (a callback function) to be executed on the +trigger. + +Let's first define a callback function, which must take a single argument, +being the pin that triggered the function. We will make the function just print +the pin:: + + >>> def callback(p): + ... print('pin change', p) + +Next we will create two pins and configure them as inputs:: + + >>> from machine import Pin + >>> p0 = Pin(0, Pin.IN) + >>> p2 = Pin(2, Pin.IN) + +An finally we need to tell the pins when to trigger, and the function to call +when they detect an event:: + + >>> p0.irq(trigger=Pin.IRQ_FALLING, handler=callback) + >>> p2.irq(trigger=Pin.IRQ_RISING | Pin.IRQ_FALLING, handler=callback) + +We set pin 0 to trigger only on a falling edge of the input (when it goes from +high to low), and set pin 2 to trigger on both a rising and falling edge. After +entering this code you can apply high and low voltages to pins 0 and 2 to see +the interrupt being executed. + +A hard interrupt will trigger as soon as the event occurs and will interrupt any +running code, including Python code. As such your callback functions are +limited in what they can do (they cannot allocate memory, for example) and +should be as short and simple as possible. diff --git a/docs/esp8266/tutorial/powerctrl.rst b/docs/esp8266/tutorial/powerctrl.rst new file mode 100644 index 0000000000..9e44339c86 --- /dev/null +++ b/docs/esp8266/tutorial/powerctrl.rst @@ -0,0 +1,61 @@ +Power control +============= + +The ESP8266 provides the ability to change the CPU frequency on the fly, and +enter a deep-sleep state. Both can be used to manage power consumption. + +Changing the CPU frequency +-------------------------- + +The machine module has a function to get and set the CPU frequency. To get the +current frequency use:: + + >>> import machine + >>> machine.freq() + 80000000 + +By default the CPU runs at 80MHz. It can be change to 160MHz if you need more +processing power, at the expense of current consumption:: + + >>> machine.freq(160000000) + >>> machine.freq() + 160000000 + +You can change to the higher frequency just while your code does the heavy +processing and then change back when its finished. + +Deep-sleep mode +--------------- + +The deep-sleep mode will shut down the ESP8266 and all its peripherals, +including the WiFi (but not including the real-time-clock, which is used to wake +the chip). This drastically reduces current consumption and is a good way to +make devices that can run for a while on a battery. + +To be able to use the deep-sleep feature you must connect GPIO16 to the reset +pin (RST on the Adafruit Feather HUZZAH board). Then the following code can be +used to sleep and wake the device:: + + import machine + + # configure RTC.ALARM0 to be able to wake the device + rtc = machine.RTC() + rtc.irq(trigger=rtc.ALARM0, wake=machine.DEEPSLEEP) + + # set RTC.ALARM0 to fire after 10 seconds (waking the device) + rtc.alarm(rtc.ALARM0, 10000) + + # put the device to sleep + machine.deepsleep() + +Note that when the chip wakes from a deep-sleep it is completely reset, +including all of the memory. The boot scripts will run as usual and you can +put code in them to check the reset cause to perhaps do something different if +the device just woke from a deep-sleep. For example, to print the reset cause +you can use:: + + if machine.reset_cause() == machine.DEEPSLEEP_RESET: + print('woke from a deep sleep') + else: + print('power on or hard reset') + diff --git a/docs/esp8266/tutorial/pwm.rst b/docs/esp8266/tutorial/pwm.rst new file mode 100644 index 0000000000..8de509427c --- /dev/null +++ b/docs/esp8266/tutorial/pwm.rst @@ -0,0 +1,87 @@ +Pulse Width Modulation +====================== + +Pulse width modulation (PWM) is a way to get an artificial analog output on a +digital pin. It achieves this by rapidly toggling the pin from low to high. +There are two parameters associated with this: the frequency of the toggling, +and the duty cycle. The duty cycle is defined to be how long the pin is high +compared with the length of a single period (low plus high time). Maximum +duty cycle is when the pin is high all of the time, and minimum is when it is +low all of the time. + +On the ESP8266 the pins 0, 2, 4, 5, 12, 13, 14 and 15 all support PWM. The +limitation is that they must all be at the same frequency, and the frequency +must be between 1Hz and 1kHz. + +To use PWM on a pin you must first create the pin object, for example:: + + >>> import machine + >>> p12 = machine.Pin(12) + +Then create the PWM object using:: + + >>> pwm12 = machine.PWM(p12) + +You can set the frequency and duty cycle using:: + + >>> pwm12.freq(500) + >>> pwm12.duty(512) + +Note that the duty cycle is between 0 (all off) and 1023 (all on), with 512 +being a 50% duty. If you print the PWM object then it will tell you its current +configuration:: + + >>> pwm12 + PWM(12, freq=500, duty=512) + +You can also call the ``freq()`` and ``duty()`` methods with no arguments to +get their current values. + +The pin will continue to be in PWM mode until you deinitialise it using:: + + >>> pwm12.deinit() + +Fading an LED +------------- + +Let's use the PWM feature to fade an LED. Assuming your board has an LED +connected to pin 2 (ESP-12 modules do) we can create an LED-PWM object using:: + + >>> led = machine.PWM(machine.Pin(2), freq=1000) + +Notice that we can set the frequency in the PWM constructor. + +For the next part we will use timing and some math, so import these modules:: + + >>> import time, math + +Then create a function to pulse the LED:: + + >>> def pulse(l, t): + ... for i in range(20): + ... l.duty(int(math.sin(i / 10 * math.pi) * 500 + 500)) + ... time.sleep_ms(t) + +You can try this function out using:: + + >>> pulse(led, 50) + +For a nice effect you can pulse many times in a row:: + + >>> for i in range(10): + ... pulse(led, 20) + +Remember you can use ctrl-C to interrupt the code. + +Control a hobby servo +--------------------- + +Hobby servo motors can be controlled using PWM. They require a frequency of +50Hz and then a duty between about 40 and 115, with 77 being the centre value. +If you connect a servo to the power and ground pins, and then the signal line +to pin 12 (other pins will work just as well), you can control the motor using:: + + >>> servo = machine.PWM(machine.Pin(12), freq=50) + >>> servo.duty(40) + >>> servo.duty(115) + >>> servo.duty(77) diff --git a/docs/esp8266/tutorial/repl.rst b/docs/esp8266/tutorial/repl.rst new file mode 100644 index 0000000000..078f31357c --- /dev/null +++ b/docs/esp8266/tutorial/repl.rst @@ -0,0 +1,207 @@ +Getting a MicroPython REPL prompt +================================= + +REPL stands for Read Evaluate Print Loop, and is the name given to the +interactive MicroPython prompt that you can access on the ESP8266. Using the +REPL is by far the easiest way to test out your code and run commands. + +There are two ways to access the REPL: either via a wired connection through the +UART serial port, or via WiFi. + +REPL over the serial port +------------------------- + +The REPL is always available on the UART0 serial peripheral, which is connected +to the pins GPIO1 for TX and GPIO3 for RX. The baudrate of the REPL is 115200. +If your board has a USB-serial convertor on it then you should be able to access +the REPL directly from your PC. Otherwise you will need to have a way of +communicating with the UART. + +To access the prompt over USB-serial you need to use a terminal emulator program. +On Windows TeraTerm is a good choice, on Mac you can use the built-in screen +program, and Linux has picocom and minicom. Of course, there are many other +terminal programs that will work, so pick your favourite! + +For example, on Linux you can try running:: + + picocom /dev/ttyUSB0 + +Once you have made the connection over the serial port you can test if it is +working by hitting enter a few times. You should see the Python REPL prompt, +indicated by ``>>>``. + +WebREPL - a prompt over WiFi +---------------------------- + +WebREPL allows you to use the Python prompt over WiFi, connecting through a +browser. The latest versions of Firefox and Chrome are supported. + +For your convinience, WebREPL client is hosted at +`<http://micropython.org/webrepl>`__ . Alternatively, you can install it +locally from the the GitHub repository +`<https://github.com/micropython/webrepl>`__ . + +To use WebREPL connect your computer to the ESP8266's access point +(MicroPython-xxxxxx, see the previous section about this). If you have +already reconfigured your ESP8266 to connect to a router then you can +skip this part. + +Once you are on the same network as the ESP8266 you click the "Connect" button +(if you are connecting via a router then you may need to change the IP address, +by default the IP address is correct when connected to the ESP8266's access +point). If the connection succeeds then you should see a welcome message. + +On the first connection you need to set a password. Make sure that the +terminal widget is selected by clicking on it, and then follow prompts to +type in your password twice (they should match each other). Then ESP8266 +will then reboot with the password applied (the WiFi will go down but come +back up again). Note that some modules may have troubles rebooting +automatically and need reset button press or power cycle (do this if +you don't see ESP8266 access point appearing in a minute or so). + +You should then click the "Connect" button again, and enter your password +to connect. If you type in the correct password you should get a prompt +looking like ``>>>``. You can now start typing Python commands! + +Using the REPL +-------------- + +Once you have a prompt you can start experimenting! Anything you type at the +prompt will be executed after you press the Enter key. MicroPython will run +the code that you enter and print the result (if there is one). If there is an +error with the text that you enter then an error message is printed. + +Try typing the following at the prompt:: + + >>> print('hello esp8266!') + hello esp8266! + +Note that you shouldn't type the ``>>>`` arrows, they are there to indicate that +you should type the text after it at the prompt. And then the line following is +what the device should respond with. In the end, once you have entered the text +``print("hello esp8266!")`` and pressed the Enter key, the output on your screen +should look exactly like it does above. + +If you already know some python you can now try some basic commands here. For +example:: + + >>> 1 + 2 + 3 + >>> 1 / 2 + 0.5 + >>> 12**34 + 4922235242952026704037113243122008064 + +If your board has an LED attached to GPIO2 (the ESP-12 modules do) then you can +turn it on and off using the following code:: + + >>> import machine + >>> pin = machine.Pin(2, machine.Pin.OUT) + >>> pin.high() + >>> pin.low() + +Note that ``high`` might turn the LED off and ``low`` might turn it on (or vice +versa), depending on how the LED is wired on your board. + +Line editing +~~~~~~~~~~~~ + +You can edit the current line that you are entering using the left and right +arrow keys to move the cursor, as well as the delete and backspace keys. Also, +pressing Home or ctrl-A moves the cursor to the start of the line, and pressing +End or ctrl-E moves to the end of the line. + +Input history +~~~~~~~~~~~~~ + +The REPL remembers a certain number of previous lines of text that you entered +(up to 8 on the ESP8266). To recall previous lines use the up and down arrow +keys. + +Tab completion +~~~~~~~~~~~~~~ + +Pressing the Tab key will do an auto-completion of the current word that you are +entering. This can be very useful to find out functions and methods that a +module or object has. Try it out by typing "ma" and then pressing Tab. It +should complete to "machine" (assuming you imported machine in the above +example). Then type "." and press Tab again to see a list of all the functions +that the machine module has. + +Line continuation and auto-indent +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Certain things that you type will need "continuing", that is, will need more +lines of text to make a proper Python statement. In this case the prompt will +change to ``...`` and the cursor will auto-indent the correct amount so you can +start typing the next line straight away. Try this by defining the following +function:: + + >>> def toggle(p): + ... p.value(not p.value()) + ... + ... + ... + >>> + +In the above, you needed to press the Enter key three times in a row to finish +the compound statement (that's the three lines with just dots on them). The +other way to finish a compound statement is to press backspace to get to the +start of the line, then press the Enter key. (If you did something wrong and +want to escape the continuation mode then press ctrl-C; all lines will be +ignored.) + +The function you just defined allows you to toggle a pin. The pin object you +created earlier should still exist (recreate it if it doesn't) and you can +toggle the LED using:: + + >>> toggle(pin) + +Let's now toggle the LED in a loop (if you don't have an LED then you can just +print some text instead of calling toggle, to see the effect):: + + >>> import time + >>> while True: + ... toggle(pin) + ... time.sleep_ms(500) + ... + ... + ... + >>> + +This will toggle the LED at 1Hz (half a second on, half a second off). To stop +the toggling press ctrl-C, which will raise a KeyboardInterrupt exception and +break out of the loop. + +The time module provides some useful functions for making delays and doing +timing. Use tab completion to find out what they are and play around with them! + +Paste mode +~~~~~~~~~~ + +Pressing ctrl-E will enter a special paste mode. This allows you to copy and +paste a chunk of text into the REPL. If you press ctrl-E you will see the +paste-mode prompt:: + + paste mode; Ctrl-C to cancel, Ctrl-D to finish + === + +You can then paste (or type) your text in. Note that none of the special keys +or commands work in paste mode (eg Tab or backspace), they are just accepted +as-is. Press ctrl-D to finish entering the text and execute it. + +Other control commands +~~~~~~~~~~~~~~~~~~~~~~ + +There are four other control commands: + +* Ctrl-A on a blank line will enter raw REPL mode. This is like a permanent + paste mode, except that characters are not echoed back. + +* Ctrl-B on a blank like goes to normal REPL mode. + +* Ctrl-C cancels any input, or interrupts the currently running code. + +* Ctrl-D on a blank line will do a soft reset. + +Note that ctrl-A and ctrl-D do not work with WebREPL. |