mirror of
https://github.com/micropython/micropython.git
synced 2025-12-24 13:50:12 +01:00
Compare commits
160 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fe08e3a54f | ||
|
|
8fd8bb36b3 | ||
|
|
3b24e83731 | ||
|
|
bb489066e8 | ||
|
|
109b363ddc | ||
|
|
075ca64521 | ||
|
|
be2879ce89 | ||
|
|
ee0058d174 | ||
|
|
1f2daf4304 | ||
|
|
1c7f9b16f0 | ||
|
|
ceb169008d | ||
|
|
04db848dc7 | ||
|
|
4b630c452d | ||
|
|
719dca2515 | ||
|
|
d67ea6b29f | ||
|
|
7ff585333e | ||
|
|
9a507c67ad | ||
|
|
9d7ef05caf | ||
|
|
e693e52442 | ||
|
|
9d0192de4a | ||
|
|
f09f8097d5 | ||
|
|
d19e4f0ba4 | ||
|
|
f961456b29 | ||
|
|
22521ea9e2 | ||
|
|
04353cc85e | ||
|
|
183edefddd | ||
|
|
aedb859177 | ||
|
|
7e359c648b | ||
|
|
aaef1851a7 | ||
|
|
60401d461a | ||
|
|
b106532b32 | ||
|
|
8e6e9eaea5 | ||
|
|
acea9352a9 | ||
|
|
9058a7031f | ||
|
|
a787467569 | ||
|
|
4078336d38 | ||
|
|
2f96b1982a | ||
|
|
bedab235f9 | ||
|
|
83158e0e7f | ||
|
|
d8066e999d | ||
|
|
504420c51d | ||
|
|
2c040edef8 | ||
|
|
9c72c71c05 | ||
|
|
f4c50f1cfc | ||
|
|
ae70e98ed4 | ||
|
|
8faf2dc75b | ||
|
|
36ae417c9f | ||
|
|
2e0cd20a1d | ||
|
|
65f6324573 | ||
|
|
d8137178bb | ||
|
|
39a380b621 | ||
|
|
e0f5df579b | ||
|
|
8ee153f234 | ||
|
|
fd379db286 | ||
|
|
096d1e4512 | ||
|
|
949c5c9180 | ||
|
|
7799410950 | ||
|
|
2ca7b05552 | ||
|
|
f8e9ef5cd0 | ||
|
|
020386b61c | ||
|
|
c3000b6f69 | ||
|
|
6ec6f51326 | ||
|
|
4542643025 | ||
|
|
fca3308cc3 | ||
|
|
e19dfe1c32 | ||
|
|
affcbe4139 | ||
|
|
6a515b95a8 | ||
|
|
c13be69a8e | ||
|
|
035a0a2b6e | ||
|
|
e813541e3f | ||
|
|
4bf3f2d3c0 | ||
|
|
556c8a9a4f | ||
|
|
4300c7dba2 | ||
|
|
74d0df7324 | ||
|
|
d7e3b36a09 | ||
|
|
fcce1483fa | ||
|
|
2430dfac31 | ||
|
|
fe29cc192d | ||
|
|
41eb705477 | ||
|
|
2ec835f572 | ||
|
|
59a41e8fcd | ||
|
|
d6442407f5 | ||
|
|
b5c43be135 | ||
|
|
b8f9ac5411 | ||
|
|
21f43ba9b0 | ||
|
|
3c9c3687d6 | ||
|
|
408b74d74c | ||
|
|
fdfcee7b1e | ||
|
|
64f2b213bb | ||
|
|
91fc075a33 | ||
|
|
3aa7dd23c9 | ||
|
|
fccbe9aa4d | ||
|
|
0334058fa4 | ||
|
|
6206f431cf | ||
|
|
46a1102852 | ||
|
|
1b586f3a73 | ||
|
|
53ca6ae1f3 | ||
|
|
95b352064e | ||
|
|
24652228af | ||
|
|
845b5a2a58 | ||
|
|
7381b7ac71 | ||
|
|
0e87bc7be6 | ||
|
|
01d64914c5 | ||
|
|
366239b8b9 | ||
|
|
02041bf2e0 | ||
|
|
216b6a494e | ||
|
|
b948de36fb | ||
|
|
4fb5ff86ee | ||
|
|
9f5f156b9d | ||
|
|
7e12a601b8 | ||
|
|
2a8d7ee0f8 | ||
|
|
fd38799049 | ||
|
|
fa391eed9d | ||
|
|
37ab061f4d | ||
|
|
aaa8867d4a | ||
|
|
062bd81814 | ||
|
|
f4d55c91fe | ||
|
|
326ff54649 | ||
|
|
90a36942b4 | ||
|
|
1ea4b77a9a | ||
|
|
0496de26d3 | ||
|
|
f22be4ebd9 | ||
|
|
34f26ea862 | ||
|
|
9e0a3d46b6 | ||
|
|
90b1cc5103 | ||
|
|
58e0f4ac50 | ||
|
|
e5635f4ab3 | ||
|
|
2065373f67 | ||
|
|
a81539db25 | ||
|
|
2f4e8511cd | ||
|
|
4c02e54298 | ||
|
|
5f3c3ec5e6 | ||
|
|
c4489a0543 | ||
|
|
0eba162ab5 | ||
|
|
f3ca8623f7 | ||
|
|
77020281ae | ||
|
|
f1a9923308 | ||
|
|
2a8a564fbd | ||
|
|
0d28a3edb9 | ||
|
|
ff736d6f6f | ||
|
|
d88d3b0b3a | ||
|
|
b6bdb0dbda | ||
|
|
ed6a5b78ad | ||
|
|
d5de1bf853 | ||
|
|
eb9a3ec654 | ||
|
|
6143f63560 | ||
|
|
37a2015cc5 | ||
|
|
958e273336 | ||
|
|
c92e6a45eb | ||
|
|
0a7e4fa5ce | ||
|
|
8192310dad | ||
|
|
ef369249cb | ||
|
|
a7261ae059 | ||
|
|
635ef16432 | ||
|
|
57fa14b5be | ||
|
|
dbdcb58d64 | ||
|
|
81d64ab939 | ||
|
|
c0a79cc919 | ||
|
|
7e18d3b6ff | ||
|
|
9d5e5c08ab |
7
.gitmodules
vendored
Normal file
7
.gitmodules
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
[submodule "lib/axtls"]
|
||||
path = lib/axtls
|
||||
url = https://github.com/pfalcon/axtls
|
||||
branch = micropython
|
||||
[submodule "lib/libffi"]
|
||||
path = lib/libffi
|
||||
url = https://github.com/atgreen/libffi
|
||||
@@ -15,6 +15,7 @@ before_script:
|
||||
|
||||
script:
|
||||
- make -C minimal test
|
||||
- make -C unix deplibs CC=gcc-4.7
|
||||
- make -C unix CC=gcc-4.7
|
||||
- make -C bare-arm
|
||||
- make -C qemu-arm test
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
The Micro Python project was proudly and successfully crowdfunded
|
||||
The MicroPython project was proudly and successfully crowdfunded
|
||||
via a Kickstarter campaign which ended on 13th December 2013. The
|
||||
project was supported by 1923 very generous backers, who pledged
|
||||
for a total of 2320 pyboards.
|
||||
|
||||
@@ -41,12 +41,12 @@ Names:
|
||||
- Use CAPS_WITH_UNDERSCORE for enums and macros.
|
||||
- When defining a type use underscore_case and put '_t' after it.
|
||||
|
||||
Integer types: Micro Python runs on 16, 32, and 64 bit machines, so it's
|
||||
Integer types: MicroPython runs on 16, 32, and 64 bit machines, so it's
|
||||
important to use the correctly-sized (and signed) integer types. The
|
||||
general guidelines are:
|
||||
- For most cases use mp_int_t for signed and mp_uint_t for unsigned
|
||||
integer values. These are guaranteed to be machine-word sized and
|
||||
therefore big enough to hold the value from a Micro Python small-int
|
||||
therefore big enough to hold the value from a MicroPython small-int
|
||||
object.
|
||||
- Use size_t for things that count bytes / sizes of objects.
|
||||
- You can use int/uint, but remember that they may be 16-bits wide.
|
||||
|
||||
57
README.md
57
README.md
@@ -8,19 +8,19 @@
|
||||
[istats-issue-img]: http://issuestats.com/github/micropython/micropython/badge/issue
|
||||
[istats-issue-repo]: http://issuestats.com/github/micropython/micropython
|
||||
|
||||
The Micro Python project
|
||||
========================
|
||||
The MicroPython project
|
||||
=======================
|
||||
<p align="center">
|
||||
<img src="https://raw.githubusercontent.com/micropython/micropython/master/logo/upython-with-micro.jpg" alt="MicroPython Logo"/>
|
||||
</p>
|
||||
|
||||
This is the Micro Python project, which aims to put an implementation
|
||||
This is the MicroPython project, which aims to put an implementation
|
||||
of Python 3.x on microcontrollers and small embedded systems.
|
||||
|
||||
WARNING: this project is in beta stage and is subject to changes of the
|
||||
code-base, including project-wide name changes and API changes.
|
||||
|
||||
Micro Python implements the entire Python 3.4 syntax (including exceptions,
|
||||
MicroPython implements the entire Python 3.4 syntax (including exceptions,
|
||||
"with", "yield from", etc.). The following core datatypes are provided:
|
||||
str (including basic Unicode support), bytes, bytearray, tuple, list, dict,
|
||||
set, frozenset, array.array, collections.namedtuple, classes and instances.
|
||||
@@ -33,19 +33,19 @@ Python board, the officially supported reference electronic circuit board.
|
||||
Major components in this repository:
|
||||
- py/ -- the core Python implementation, including compiler, runtime, and
|
||||
core library.
|
||||
- unix/ -- a version of Micro Python that runs on Unix.
|
||||
- stmhal/ -- a version of Micro Python that runs on the Micro Python board
|
||||
- unix/ -- a version of MicroPython that runs on Unix.
|
||||
- stmhal/ -- a version of MicroPython that runs on the MicroPython board
|
||||
with an STM32F405RG (using ST's Cube HAL drivers).
|
||||
- minimal/ -- a minimal Micro Python port. Start with this if you want
|
||||
to port Micro Python to another microcontroller.
|
||||
- minimal/ -- a minimal MicroPython port. Start with this if you want
|
||||
to port MicroPython to another microcontroller.
|
||||
|
||||
Additional components:
|
||||
- bare-arm/ -- a bare minimum version of Micro Python for ARM MCUs. Used
|
||||
- bare-arm/ -- a bare minimum version of MicroPython for ARM MCUs. Used
|
||||
mostly to control code size.
|
||||
- teensy/ -- a version of Micro Python that runs on the Teensy 3.1
|
||||
- teensy/ -- a version of MicroPython that runs on the Teensy 3.1
|
||||
(preliminary but functional).
|
||||
- pic16bit/ -- a version of Micro Python for 16-bit PIC microcontrollers.
|
||||
- cc3200/ -- a version of Micro Python that runs on the CC3200 from TI.
|
||||
- pic16bit/ -- a version of MicroPython for 16-bit PIC microcontrollers.
|
||||
- cc3200/ -- a version of MicroPython that runs on the CC3200 from TI.
|
||||
- esp8266/ -- an experimental port for ESP8266 WiFi modules.
|
||||
- tests/ -- test framework and test scripts.
|
||||
- tools/ -- various tools, including the pyboard.py module.
|
||||
@@ -74,6 +74,7 @@ Then to give it a try:
|
||||
$ ./micropython
|
||||
>>> list(5 * x + y for x in range(10) for y in [4, 2, 1])
|
||||
|
||||
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):
|
||||
|
||||
@@ -93,9 +94,35 @@ Browse available modules on
|
||||
Standard library modules come from
|
||||
[micropython-lib](https://github.com/micropython/micropython-lib) project.
|
||||
|
||||
(*) Debian/Ubuntu/Mint derivative Linux distros will require build-essentials,
|
||||
libffi-dev and pkg-config packages installed. If you have problems with some
|
||||
dependencies, they can be disabled in unix/mpconfigport.mk .
|
||||
External dependencies
|
||||
---------------------
|
||||
|
||||
Building Unix version requires some dependencies installed. For
|
||||
Debian/Ubuntu/Mint derivative Linux distros, install `build-essentials`
|
||||
(includes toolchain and make), `libffi-dev`, and `pkg-config` packages.
|
||||
|
||||
Other dependencies can be built together with MicroPython. Oftentimes,
|
||||
you need to do this to enable extra features or capabilities. To build
|
||||
these additional dependencies, first fetch git submodules for them:
|
||||
|
||||
$ git submodule update --init
|
||||
|
||||
Use this same command to get the latest versions of dependencies, as
|
||||
they are updated from time to time. After that, in `unix/` dir, execute:
|
||||
|
||||
$ make deplibs
|
||||
|
||||
This will build all available dependencies (regardless whether they
|
||||
are used or not). If you intend to build MicroPython with additional
|
||||
options (like cross-compiling), the same set of options should be passed
|
||||
to `make deplibs`. To actually enabled use of dependencies, edit
|
||||
`unix/mpconfigport.mk` file, which has inline descriptions of the options.
|
||||
For example, to build SSL module (required for `upip` tool described above),
|
||||
set `MICROPY_PY_USSL` to 1.
|
||||
|
||||
In `unix/mpconfigport.mk`, you can also disable some dependencies enabled
|
||||
by default, like FFI support, which requires libffi development files to
|
||||
be installed.
|
||||
|
||||
The STM version
|
||||
---------------
|
||||
|
||||
@@ -8,7 +8,7 @@ include ../py/py.mk
|
||||
|
||||
CROSS_COMPILE = arm-none-eabi-
|
||||
|
||||
INC = -I.
|
||||
INC += -I.
|
||||
INC += -I..
|
||||
INC += -I$(BUILD)
|
||||
|
||||
|
||||
@@ -16,8 +16,8 @@ void do_str(const char *src, mp_parse_input_kind_t input_kind) {
|
||||
nlr_buf_t nlr;
|
||||
if (nlr_push(&nlr) == 0) {
|
||||
qstr source_name = lex->source_name;
|
||||
mp_parse_node_t pn = mp_parse(lex, input_kind);
|
||||
mp_obj_t module_fun = mp_compile(pn, source_name, MP_EMIT_OPT_NONE, true);
|
||||
mp_parse_tree_t parse_tree = mp_parse(lex, input_kind);
|
||||
mp_obj_t module_fun = mp_compile(&parse_tree, source_name, MP_EMIT_OPT_NONE, true);
|
||||
mp_call_function_0(module_fun);
|
||||
nlr_pop();
|
||||
} else {
|
||||
|
||||
@@ -57,6 +57,9 @@ typedef void *machine_ptr_t; // must be of pointer size
|
||||
typedef const void *machine_const_ptr_t; // must be of pointer size
|
||||
typedef long mp_off_t;
|
||||
|
||||
// dummy print
|
||||
#define MP_PLAT_PRINT_STRN(str, len) (void)0
|
||||
|
||||
// extra built in names to add to the global namespace
|
||||
extern const struct _mp_obj_fun_builtin_t mp_builtin_open_obj;
|
||||
#define MICROPY_PORT_BUILTINS \
|
||||
|
||||
@@ -83,7 +83,7 @@
|
||||
#define configUSE_TICK_HOOK 1
|
||||
#define configCPU_CLOCK_HZ ( ( unsigned long ) 80000000 )
|
||||
#define configTICK_RATE_HZ ( ( TickType_t ) 1000 )
|
||||
#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 64 )
|
||||
#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 72 )
|
||||
#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 16384 ) )
|
||||
#define configMAX_TASK_NAME_LEN ( 8 )
|
||||
#define configUSE_TRACE_FACILITY 0
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Build Instructions for the CC3200
|
||||
|
||||
Currently the CC3200 port of Micro Python builds under Linux and OSX **but not under Windows**.
|
||||
Currently the CC3200 port of MicroPython builds under Linux and OSX **but not under Windows**.
|
||||
|
||||
The tool chain required for the build can be found at <https://launchpad.net/gcc-arm-embedded>.
|
||||
|
||||
@@ -25,7 +25,7 @@ make BTARGET=bootloader BTYPE=release BOARD=LAUNCHXL
|
||||
```
|
||||
|
||||
## Regarding old revisions of the CC3200-LAUNCHXL
|
||||
First silicon (pre-release) revisions of the CC3200 had issues with the ram blocks, and Micro Python cannot run
|
||||
First silicon (pre-release) revisions of the CC3200 had issues with the ram blocks, and MicroPython cannot run
|
||||
there. Make sure to use a **v4.1 (or higer) LAUNCHXL board** when trying this port, otherwise it won't work.
|
||||
|
||||
## Flashing the CC3200
|
||||
@@ -53,8 +53,6 @@ If `WIPY_IP`, `WIPY_USER` or `WIPY_PWD` are omitted the default values (the ones
|
||||
|
||||
Once the software is running, you have two options to access the MicroPython REPL:
|
||||
|
||||
- Through the UART.
|
||||
**Connect to PORT 22, baud rate = 115200, parity = none, stop bits = 1**
|
||||
- Through telnet.
|
||||
* Connect to the network created by the board (as boots up in AP mode), **ssid = "wipy-wlan", key = "www.wipy.io"**.
|
||||
* You can also reinitialize the WLAN in station mode and connect to another AP, or in AP mode but with a
|
||||
|
||||
@@ -78,21 +78,21 @@ APP_MISC_SRC_C = $(addprefix misc/,\
|
||||
antenna.c \
|
||||
FreeRTOSHooks.c \
|
||||
help.c \
|
||||
mpcallback.c \
|
||||
mpirq.c \
|
||||
mperror.c \
|
||||
mpexception.c \
|
||||
mpsystick.c \
|
||||
)
|
||||
|
||||
APP_MODS_SRC_C = $(addprefix mods/,\
|
||||
modmachine.c \
|
||||
modnetwork.c \
|
||||
moduhashlib.c \
|
||||
modubinascii.c \
|
||||
modpyb.c \
|
||||
moduos.c \
|
||||
modusocket.c \
|
||||
modussl.c \
|
||||
modutime.c \
|
||||
modwipy.c \
|
||||
modwlan.c \
|
||||
pybadc.c \
|
||||
pybpin.c \
|
||||
|
||||
@@ -52,16 +52,18 @@
|
||||
#define PIN(p_pin_name, p_port, p_bit, p_pin_num, p_af_list, p_num_afs) \
|
||||
{ \
|
||||
{ &pin_type }, \
|
||||
.name = MP_QSTR_ ## p_pin_name, \
|
||||
.port = PORT_A ## p_port, \
|
||||
.af_list = (p_af_list), \
|
||||
.pull = PIN_TYPE_STD, \
|
||||
.bit = (p_bit), \
|
||||
.pin_num = (p_pin_num), \
|
||||
.af = PIN_MODE_0, \
|
||||
.strength = PIN_STRENGTH_4MA, \
|
||||
.mode = GPIO_DIR_MODE_IN, \
|
||||
.num_afs = (p_num_afs), \
|
||||
.value = 0, \
|
||||
.used = false, \
|
||||
.name = MP_QSTR_ ## p_pin_name, \
|
||||
.port = PORT_A ## p_port, \
|
||||
.af_list = (p_af_list), \
|
||||
.pull = PIN_TYPE_STD, \
|
||||
.bit = (p_bit), \
|
||||
.pin_num = (p_pin_num), \
|
||||
.af = PIN_MODE_0, \
|
||||
.strength = PIN_STRENGTH_4MA, \
|
||||
.mode = GPIO_DIR_MODE_IN, \
|
||||
.num_afs = (p_num_afs), \
|
||||
.value = 0, \
|
||||
.used = false, \
|
||||
.irq_trigger = 0, \
|
||||
.irq_flags = 0, \
|
||||
}
|
||||
|
||||
@@ -31,12 +31,16 @@
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
#include "py/mpstate.h"
|
||||
#include MICROPY_HAL_H
|
||||
#include "py/runtime.h"
|
||||
#include "py/objstr.h"
|
||||
#include "inc/hw_types.h"
|
||||
#include "inc/hw_ints.h"
|
||||
#include "inc/hw_nvic.h"
|
||||
#include "hw_memmap.h"
|
||||
#include "py/mpstate.h"
|
||||
#include MICROPY_HAL_H
|
||||
#include "rom_map.h"
|
||||
#include "interrupt.h"
|
||||
#include "systick.h"
|
||||
@@ -47,6 +51,7 @@
|
||||
#include "pybuart.h"
|
||||
#include "utils.h"
|
||||
#include "irq.h"
|
||||
#include "moduos.h"
|
||||
|
||||
#ifdef USE_FREERTOS
|
||||
#include "FreeRTOS.h"
|
||||
@@ -67,11 +72,6 @@ static void hal_TickInit (void);
|
||||
******************************************************************************/
|
||||
static volatile uint32_t HAL_tickCount;
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PUBLIC DATA
|
||||
******************************************************************************/
|
||||
struct _pyb_uart_obj_t *pyb_stdio_uart;
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE IMPORTED DATA
|
||||
******************************************************************************/
|
||||
@@ -141,34 +141,57 @@ void mp_hal_stdout_tx_str(const char *str) {
|
||||
}
|
||||
|
||||
void mp_hal_stdout_tx_strn(const char *str, uint32_t len) {
|
||||
// send stdout to UART
|
||||
if (pyb_stdio_uart != NULL) {
|
||||
uart_tx_strn(pyb_stdio_uart, str, len);
|
||||
if (MP_STATE_PORT(os_term_dup_obj)) {
|
||||
if (MP_OBJ_IS_TYPE(MP_STATE_PORT(os_term_dup_obj)->stream_o, &pyb_uart_type)) {
|
||||
uart_tx_strn(MP_STATE_PORT(os_term_dup_obj)->stream_o, str, len);
|
||||
} else {
|
||||
MP_STATE_PORT(os_term_dup_obj)->write[2] = mp_obj_new_str_of_type(&mp_type_str, (const byte *)str, len);
|
||||
mp_call_method_n_kw(1, 0, MP_STATE_PORT(os_term_dup_obj)->write);
|
||||
}
|
||||
}
|
||||
// and also to telnet
|
||||
if (telnet_is_active()) {
|
||||
telnet_tx_strn(str, len);
|
||||
}
|
||||
telnet_tx_strn(str, len);
|
||||
}
|
||||
|
||||
void mp_hal_stdout_tx_strn_cooked(const char *str, uint32_t len) {
|
||||
// send stdout to UART
|
||||
if (pyb_stdio_uart != NULL) {
|
||||
uart_tx_strn_cooked(pyb_stdio_uart, str, len);
|
||||
void mp_hal_stdout_tx_strn_cooked (const char *str, uint32_t len) {
|
||||
int32_t nslen = 0;
|
||||
const char *_str = str;
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (str[i] == '\n') {
|
||||
mp_hal_stdout_tx_strn(_str, nslen);
|
||||
mp_hal_stdout_tx_strn("\r\n", 2);
|
||||
_str += nslen + 1;
|
||||
nslen = 0;
|
||||
} else {
|
||||
nslen++;
|
||||
}
|
||||
}
|
||||
// and also to telnet
|
||||
if (telnet_is_active()) {
|
||||
telnet_tx_strn_cooked(str, len);
|
||||
if (_str < str + len) {
|
||||
mp_hal_stdout_tx_strn(_str, nslen);
|
||||
}
|
||||
}
|
||||
|
||||
int mp_hal_stdin_rx_chr(void) {
|
||||
for ( ;; ) {
|
||||
// read telnet first
|
||||
if (telnet_rx_any()) {
|
||||
return telnet_rx_char();
|
||||
}
|
||||
else if (pyb_stdio_uart != NULL && uart_rx_any(pyb_stdio_uart)) {
|
||||
return uart_rx_char(pyb_stdio_uart);
|
||||
} else if (MP_STATE_PORT(os_term_dup_obj)) { // then the stdio_dup
|
||||
if (MP_OBJ_IS_TYPE(MP_STATE_PORT(os_term_dup_obj)->stream_o, &pyb_uart_type)) {
|
||||
if (uart_rx_any(MP_STATE_PORT(os_term_dup_obj)->stream_o)) {
|
||||
return uart_rx_char(MP_STATE_PORT(os_term_dup_obj)->stream_o);
|
||||
}
|
||||
} else {
|
||||
MP_STATE_PORT(os_term_dup_obj)->read[2] = mp_obj_new_int(1);
|
||||
mp_obj_t data = mp_call_method_n_kw(1, 0, MP_STATE_PORT(os_term_dup_obj)->read);
|
||||
// data len is > 0
|
||||
if (mp_obj_is_true(data)) {
|
||||
mp_buffer_info_t bufinfo;
|
||||
mp_get_buffer_raise(data, &bufinfo, MP_BUFFER_READ);
|
||||
return ((int *)(bufinfo.buf))[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
HAL_Delay(1);
|
||||
}
|
||||
|
||||
@@ -55,11 +55,6 @@
|
||||
" isb \n"); \
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PUBLIC DATA
|
||||
******************************************************************************/
|
||||
extern struct _pyb_uart_obj_t *pyb_stdio_uart;
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PUBLIC FUNCTIONS
|
||||
******************************************************************************/
|
||||
|
||||
@@ -112,17 +112,17 @@
|
||||
// following wrapper can be used to convert the value from cycles to
|
||||
// millisecond:
|
||||
//
|
||||
// CYCLES_U16MS(cycles) ((cycles *1000)/ 1024),
|
||||
// CYCLES_U16MS(cycles) ((cycles * 1000) / 1024),
|
||||
//
|
||||
// Similarly, before setting the value, it must be first converted (from ms to
|
||||
// cycles).
|
||||
//
|
||||
// U16MS_CYCLES(msec) ((msec *1024)/1000)
|
||||
// U16MS_CYCLES(msec) ((msec * 1024) / 1000)
|
||||
//
|
||||
// Note: There is a precision loss of 1 ms with the above scheme.
|
||||
//
|
||||
//
|
||||
#define SCC_U64MSEC_GET() (MAP_PRCMSlowClkCtrGet() >> 5)
|
||||
#define SCC_U64MSEC_GET() (RTCFastDomainCounterGet() >> 5)
|
||||
#define SCC_U64MSEC_MATCH_SET(u64Msec) (MAP_PRCMSlowClkCtrMatchSet(u64Msec << 5))
|
||||
#define SCC_U64MSEC_MATCH_GET() (MAP_PRCMSlowClkCtrMatchGet() >> 5)
|
||||
|
||||
@@ -208,6 +208,39 @@ static void RTCU32SecRegWrite(unsigned long u32Msec)
|
||||
MAP_PRCMHIBRegWrite(RTC_SECS_U32_REG_ADDR, u32Msec);
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
// Fast function to get the most accurate RTC counter value
|
||||
//*****************************************************************************
|
||||
static unsigned long long RTCFastDomainCounterGet (void) {
|
||||
|
||||
#define BRK_IF_RTC_CTRS_ALIGN(c2, c1) if (c2 - c1 <= 1) { \
|
||||
itr++; \
|
||||
break; \
|
||||
}
|
||||
|
||||
unsigned long long rtc_count1, rtc_count2, rtc_count3;
|
||||
unsigned int itr;
|
||||
|
||||
do {
|
||||
rtc_count1 = PRCMSlowClkCtrFastGet();
|
||||
rtc_count2 = PRCMSlowClkCtrFastGet();
|
||||
rtc_count3 = PRCMSlowClkCtrFastGet();
|
||||
itr = 0;
|
||||
|
||||
BRK_IF_RTC_CTRS_ALIGN(rtc_count2, rtc_count1);
|
||||
BRK_IF_RTC_CTRS_ALIGN(rtc_count3, rtc_count2);
|
||||
BRK_IF_RTC_CTRS_ALIGN(rtc_count3, rtc_count1);
|
||||
|
||||
// Consistent values in two consecutive reads implies a correct
|
||||
// value of the counter. Do note, the counter does not give the
|
||||
// calendar time but a hardware that ticks upwards continuously.
|
||||
// The 48-bit counter operates at 32,768 HZ.
|
||||
|
||||
} while (true);
|
||||
|
||||
return (1 == itr) ? rtc_count2 : rtc_count3;
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
// Macros
|
||||
//*****************************************************************************
|
||||
@@ -1245,6 +1278,35 @@ unsigned long long PRCMSlowClkCtrGet(void)
|
||||
return ullRTCVal;
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
//! Gets the current value of the internal slow clock counter
|
||||
//!
|
||||
//! This function is similar to \sa PRCMSlowClkCtrGet() but reads the counter
|
||||
//! value from a relatively faster interface using an auto-latch mechainsm.
|
||||
//!
|
||||
//! \note Due to the nature of implemetation of auto latching, when using this
|
||||
//! API, the recommendation is to read the value thrice and identify the right
|
||||
//! value (as 2 out the 3 read values will always be correct and with a max. of
|
||||
//! 1 LSB change)
|
||||
//!
|
||||
//! \return 64-bit current counter vlaue.
|
||||
//
|
||||
//*****************************************************************************
|
||||
unsigned long long PRCMSlowClkCtrFastGet(void)
|
||||
{
|
||||
unsigned long long ullRTCVal;
|
||||
|
||||
//
|
||||
// Read as 2 32-bit values
|
||||
//
|
||||
ullRTCVal = HWREG(HIB1P2_BASE + HIB1P2_O_HIB_RTC_TIMER_MSW_1P2);
|
||||
ullRTCVal = ullRTCVal << 32;
|
||||
ullRTCVal |= HWREG(HIB1P2_BASE + HIB1P2_O_HIB_RTC_TIMER_LSW_1P2);
|
||||
|
||||
return ullRTCVal;
|
||||
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
|
||||
@@ -247,6 +247,7 @@ extern void PRCMHibernateWakeupSourceDisable(unsigned long ulHIBWakupSrc);
|
||||
extern void PRCMHibernateIntervalSet(unsigned long long ullTicks);
|
||||
|
||||
extern unsigned long long PRCMSlowClkCtrGet(void);
|
||||
extern unsigned long long PRCMSlowClkCtrFastGet(void);
|
||||
extern void PRCMSlowClkCtrMatchSet(unsigned long long ullTicks);
|
||||
extern unsigned long long PRCMSlowClkCtrMatchGet(void);
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
#include "py/mpconfig.h"
|
||||
#include "py/obj.h"
|
||||
|
||||
STATIC const char help_text[] = "Welcome to Micro Python!\n"
|
||||
STATIC const char help_text[] = "Welcome to MicroPython!\n"
|
||||
"For online help please visit http://micropython.org/help/.\n"
|
||||
"For further help on a specific object, type help(obj)\n";
|
||||
|
||||
|
||||
@@ -149,17 +149,13 @@ void mperror_heartbeat_switch_off (void) {
|
||||
void mperror_heartbeat_signal (void) {
|
||||
if (mperror_heart_beat.do_disable) {
|
||||
mperror_heart_beat.do_disable = false;
|
||||
mperror_heartbeat_switch_off();
|
||||
mperror_heart_beat.enabled = false;
|
||||
}
|
||||
else if (mperror_heart_beat.enabled) {
|
||||
} else if (mperror_heart_beat.enabled) {
|
||||
if (!mperror_heart_beat.beating) {
|
||||
if ((mperror_heart_beat.on_time = HAL_GetTick()) - mperror_heart_beat.off_time > MPERROR_HEARTBEAT_OFF_MS) {
|
||||
MAP_GPIOPinWrite(MICROPY_SYS_LED_PORT, MICROPY_SYS_LED_PORT_PIN, MICROPY_SYS_LED_PORT_PIN);
|
||||
mperror_heart_beat.beating = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
if ((mperror_heart_beat.off_time = HAL_GetTick()) - mperror_heart_beat.on_time > MPERROR_HEARTBEAT_ON_MS) {
|
||||
MAP_GPIOPinWrite(MICROPY_SYS_LED_PORT, MICROPY_SYS_LED_PORT_PIN, 0);
|
||||
mperror_heart_beat.beating = false;
|
||||
@@ -199,48 +195,17 @@ void nlr_jump_fail(void *val) {
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef BOOTLOADER
|
||||
/******************************************************************************/
|
||||
// Micro Python bindings
|
||||
|
||||
/// \classmethod \constructor()
|
||||
///
|
||||
/// Return the heart beat object
|
||||
STATIC mp_obj_t pyb_heartbeat_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
|
||||
// check arguments
|
||||
mp_arg_check_num(n_args, n_kw, 0, 0, false);
|
||||
|
||||
// return constant object
|
||||
return (mp_obj_t)&pyb_heartbeat_obj;
|
||||
void mperror_enable_heartbeat (bool enable) {
|
||||
if (enable) {
|
||||
mperror_heart_beat.enabled = true;
|
||||
mperror_heart_beat.do_disable = false;
|
||||
mperror_heartbeat_switch_off();
|
||||
} else {
|
||||
mperror_heart_beat.do_disable = true;
|
||||
mperror_heart_beat.enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// \function enable()
|
||||
/// Enables the heartbeat signal
|
||||
STATIC mp_obj_t pyb_enable_heartbeat(mp_obj_t self) {
|
||||
mperror_heart_beat.enabled = true;
|
||||
return mp_const_none;
|
||||
bool mperror_is_heartbeat_enabled (void) {
|
||||
return mperror_heart_beat.enabled;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_enable_heartbeat_obj, pyb_enable_heartbeat);
|
||||
|
||||
/// \function disable()
|
||||
/// Disables the heartbeat signal
|
||||
STATIC mp_obj_t pyb_disable_heartbeat(mp_obj_t self) {
|
||||
mperror_heart_beat.do_disable = true;
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_disable_heartbeat_obj, pyb_disable_heartbeat);
|
||||
|
||||
STATIC const mp_map_elem_t pyb_heartbeat_locals_dict_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_enable), (mp_obj_t)&pyb_enable_heartbeat_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_disable), (mp_obj_t)&pyb_disable_heartbeat_obj },
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(pyb_heartbeat_locals_dict, pyb_heartbeat_locals_dict_table);
|
||||
|
||||
const mp_obj_type_t pyb_heartbeat_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_HeartBeat,
|
||||
.make_new = pyb_heartbeat_make_new,
|
||||
.locals_dict = (mp_obj_t)&pyb_heartbeat_locals_dict,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -40,5 +40,7 @@ void mperror_deinit_sfe_pin (void);
|
||||
void mperror_signal_error (void);
|
||||
void mperror_heartbeat_switch_off (void);
|
||||
void mperror_heartbeat_signal (void);
|
||||
void mperror_enable_heartbeat (bool enable);
|
||||
bool mperror_is_heartbeat_enabled (void);
|
||||
|
||||
#endif // MPERROR_H_
|
||||
|
||||
@@ -34,46 +34,51 @@
|
||||
#include "inc/hw_types.h"
|
||||
#include "interrupt.h"
|
||||
#include "pybsleep.h"
|
||||
#include "mpcallback.h"
|
||||
#include "mpexception.h"
|
||||
#include "mperror.h"
|
||||
#include "mpirq.h"
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PUBLIC DATA
|
||||
DECLARE PUBLIC DATA
|
||||
******************************************************************************/
|
||||
const mp_arg_t mpcallback_init_args[] = {
|
||||
{ MP_QSTR_mode, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
|
||||
const mp_arg_t mp_irq_init_args[] = {
|
||||
{ MP_QSTR_trigger, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||
{ MP_QSTR_priority, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} }, // the lowest priority
|
||||
{ MP_QSTR_handler, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||
{ MP_QSTR_priority, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} },
|
||||
{ MP_QSTR_value, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||
{ MP_QSTR_wake_from, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = PYB_PWR_MODE_ACTIVE} },
|
||||
{ MP_QSTR_wake, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||
};
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE DATA
|
||||
******************************************************************************/
|
||||
STATIC uint8_t mp_irq_priorities[] = { INT_PRIORITY_LVL_7, INT_PRIORITY_LVL_6, INT_PRIORITY_LVL_5, INT_PRIORITY_LVL_4,
|
||||
INT_PRIORITY_LVL_3, INT_PRIORITY_LVL_2, INT_PRIORITY_LVL_1 };
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PUBLIC FUNCTIONS
|
||||
******************************************************************************/
|
||||
void mpcallback_init0 (void) {
|
||||
void mp_irq_init0 (void) {
|
||||
// initialize the callback objects list
|
||||
mp_obj_list_init(&MP_STATE_PORT(mpcallback_obj_list), 0);
|
||||
mp_obj_list_init(&MP_STATE_PORT(mp_irq_obj_list), 0);
|
||||
}
|
||||
|
||||
mp_obj_t mpcallback_new (mp_obj_t parent, mp_obj_t handler, const mp_cb_methods_t *methods, bool enable) {
|
||||
mpcallback_obj_t *self = m_new_obj(mpcallback_obj_t);
|
||||
self->base.type = &pyb_callback_type;
|
||||
mp_obj_t mp_irq_new (mp_obj_t parent, mp_obj_t handler, const mp_irq_methods_t *methods) {
|
||||
mp_irq_obj_t *self = m_new_obj(mp_irq_obj_t);
|
||||
self->base.type = &mp_irq_type;
|
||||
self->handler = handler;
|
||||
self->parent = parent;
|
||||
self->methods = (mp_cb_methods_t *)methods;
|
||||
self->isenabled = enable;
|
||||
self->methods = (mp_irq_methods_t *)methods;
|
||||
self->isenabled = true;
|
||||
// remove it in case it was already registered
|
||||
mpcallback_remove(parent);
|
||||
mp_obj_list_append(&MP_STATE_PORT(mpcallback_obj_list), self);
|
||||
mp_irq_remove(parent);
|
||||
mp_obj_list_append(&MP_STATE_PORT(mp_irq_obj_list), self);
|
||||
return self;
|
||||
}
|
||||
|
||||
mpcallback_obj_t *mpcallback_find (mp_obj_t parent) {
|
||||
for (mp_uint_t i = 0; i < MP_STATE_PORT(mpcallback_obj_list).len; i++) {
|
||||
mpcallback_obj_t *callback_obj = ((mpcallback_obj_t *)(MP_STATE_PORT(mpcallback_obj_list).items[i]));
|
||||
mp_irq_obj_t *mp_irq_find (mp_obj_t parent) {
|
||||
for (mp_uint_t i = 0; i < MP_STATE_PORT(mp_irq_obj_list).len; i++) {
|
||||
mp_irq_obj_t *callback_obj = ((mp_irq_obj_t *)(MP_STATE_PORT(mp_irq_obj_list).items[i]));
|
||||
if (callback_obj->parent == parent) {
|
||||
return callback_obj;
|
||||
}
|
||||
@@ -81,58 +86,40 @@ mpcallback_obj_t *mpcallback_find (mp_obj_t parent) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void mpcallback_wake_all (void) {
|
||||
void mp_irq_wake_all (void) {
|
||||
// re-enable all active callback objects one by one
|
||||
for (mp_uint_t i = 0; i < MP_STATE_PORT(mpcallback_obj_list).len; i++) {
|
||||
mpcallback_obj_t *callback_obj = ((mpcallback_obj_t *)(MP_STATE_PORT(mpcallback_obj_list).items[i]));
|
||||
for (mp_uint_t i = 0; i < MP_STATE_PORT(mp_irq_obj_list).len; i++) {
|
||||
mp_irq_obj_t *callback_obj = ((mp_irq_obj_t *)(MP_STATE_PORT(mp_irq_obj_list).items[i]));
|
||||
if (callback_obj->isenabled) {
|
||||
callback_obj->methods->enable(callback_obj->parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void mpcallback_disable_all (void) {
|
||||
void mp_irq_disable_all (void) {
|
||||
// re-enable all active callback objects one by one
|
||||
for (mp_uint_t i = 0; i < MP_STATE_PORT(mpcallback_obj_list).len; i++) {
|
||||
mpcallback_obj_t *callback_obj = ((mpcallback_obj_t *)(MP_STATE_PORT(mpcallback_obj_list).items[i]));
|
||||
for (mp_uint_t i = 0; i < MP_STATE_PORT(mp_irq_obj_list).len; i++) {
|
||||
mp_irq_obj_t *callback_obj = ((mp_irq_obj_t *)(MP_STATE_PORT(mp_irq_obj_list).items[i]));
|
||||
callback_obj->methods->disable(callback_obj->parent);
|
||||
}
|
||||
}
|
||||
|
||||
void mpcallback_remove (const mp_obj_t parent) {
|
||||
mpcallback_obj_t *callback_obj;
|
||||
if ((callback_obj = mpcallback_find(parent))) {
|
||||
mp_obj_list_remove(&MP_STATE_PORT(mpcallback_obj_list), callback_obj);
|
||||
void mp_irq_remove (const mp_obj_t parent) {
|
||||
mp_irq_obj_t *callback_obj;
|
||||
if ((callback_obj = mp_irq_find(parent))) {
|
||||
mp_obj_list_remove(&MP_STATE_PORT(mp_irq_obj_list), callback_obj);
|
||||
}
|
||||
}
|
||||
|
||||
uint mpcallback_translate_priority (uint priority) {
|
||||
if (priority < 1 || priority > 7) {
|
||||
uint mp_irq_translate_priority (uint priority) {
|
||||
if (priority < 1 || priority > MP_ARRAY_SIZE(mp_irq_priorities)) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
|
||||
}
|
||||
|
||||
switch (priority) {
|
||||
case 1:
|
||||
return INT_PRIORITY_LVL_7;
|
||||
case 2:
|
||||
return INT_PRIORITY_LVL_6;
|
||||
case 3:
|
||||
return INT_PRIORITY_LVL_5;
|
||||
case 4:
|
||||
return INT_PRIORITY_LVL_4;
|
||||
case 5:
|
||||
return INT_PRIORITY_LVL_3;
|
||||
case 6:
|
||||
return INT_PRIORITY_LVL_2;
|
||||
case 7:
|
||||
return INT_PRIORITY_LVL_1;
|
||||
default:
|
||||
return INT_PRIORITY_LVL_7;
|
||||
}
|
||||
return mp_irq_priorities[priority - 1];
|
||||
}
|
||||
|
||||
void mpcallback_handler (mp_obj_t self_in) {
|
||||
mpcallback_obj_t *self = self_in;
|
||||
void mp_irq_handler (mp_obj_t self_in) {
|
||||
mp_irq_obj_t *self = self_in;
|
||||
if (self && self->handler != mp_const_none) {
|
||||
// when executing code within a handler we must lock the GC to prevent
|
||||
// any memory allocations.
|
||||
@@ -159,59 +146,57 @@ void mpcallback_handler (mp_obj_t self_in) {
|
||||
/******************************************************************************/
|
||||
// Micro Python bindings
|
||||
|
||||
/// \method init()
|
||||
/// Initializes the interrupt callback. With no parameters passed, everything will default
|
||||
/// to the values assigned to mpcallback_init_args[].
|
||||
STATIC mp_obj_t callback_init(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
mpcallback_obj_t *self = pos_args[0];
|
||||
STATIC mp_obj_t mp_irq_init (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
mp_irq_obj_t *self = pos_args[0];
|
||||
// this is a bit of a hack, but it let us reuse the callback_create method from our parent
|
||||
((mp_obj_t *)pos_args)[0] = self->parent;
|
||||
self->methods->init (n_args, pos_args, kw_args);
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(callback_init_obj, 1, callback_init);
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(mp_irq_init_obj, 1, mp_irq_init);
|
||||
|
||||
/// \method enable()
|
||||
/// Enables the interrupt callback
|
||||
STATIC mp_obj_t callback_enable (mp_obj_t self_in) {
|
||||
mpcallback_obj_t *self = self_in;
|
||||
STATIC mp_obj_t mp_irq_enable (mp_obj_t self_in) {
|
||||
mp_irq_obj_t *self = self_in;
|
||||
self->methods->enable(self->parent);
|
||||
self->isenabled = true;
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(callback_enable_obj, callback_enable);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_irq_enable_obj, mp_irq_enable);
|
||||
|
||||
/// \method disable()
|
||||
/// Disables the interrupt callback
|
||||
STATIC mp_obj_t callback_disable (mp_obj_t self_in) {
|
||||
mpcallback_obj_t *self = self_in;
|
||||
STATIC mp_obj_t mp_irq_disable (mp_obj_t self_in) {
|
||||
mp_irq_obj_t *self = self_in;
|
||||
self->methods->disable(self->parent);
|
||||
self->isenabled = false;
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(callback_disable_obj, callback_disable);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_irq_disable_obj, mp_irq_disable);
|
||||
|
||||
/// \method \call()
|
||||
/// Triggers the interrupt callback
|
||||
STATIC mp_obj_t callback_call(mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
|
||||
STATIC mp_obj_t mp_irq_flags (mp_obj_t self_in) {
|
||||
mp_irq_obj_t *self = self_in;
|
||||
return mp_obj_new_int(self->methods->flags(self->parent));
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_irq_flags_obj, mp_irq_flags);
|
||||
|
||||
STATIC mp_obj_t mp_irq_call (mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
|
||||
mp_arg_check_num(n_args, n_kw, 0, 0, false);
|
||||
mpcallback_handler (self_in);
|
||||
mp_irq_handler (self_in);
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
STATIC const mp_map_elem_t callback_locals_dict_table[] = {
|
||||
STATIC const mp_map_elem_t mp_irq_locals_dict_table[] = {
|
||||
// instance methods
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)&callback_init_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_enable), (mp_obj_t)&callback_enable_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_disable), (mp_obj_t)&callback_disable_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)&mp_irq_init_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_enable), (mp_obj_t)&mp_irq_enable_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_disable), (mp_obj_t)&mp_irq_disable_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_flags), (mp_obj_t)&mp_irq_flags_obj },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(callback_locals_dict, callback_locals_dict_table);
|
||||
STATIC MP_DEFINE_CONST_DICT(mp_irq_locals_dict, mp_irq_locals_dict_table);
|
||||
|
||||
const mp_obj_type_t pyb_callback_type = {
|
||||
const mp_obj_type_t mp_irq_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_callback,
|
||||
.call = callback_call,
|
||||
.locals_dict = (mp_obj_t)&callback_locals_dict,
|
||||
.name = MP_QSTR_irq,
|
||||
.call = mp_irq_call,
|
||||
.locals_dict = (mp_obj_t)&mp_irq_locals_dict,
|
||||
};
|
||||
|
||||
@@ -24,50 +24,52 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef MPCALLBACK_H_
|
||||
#define MPCALLBACK_H_
|
||||
#ifndef MPIRQ_H_
|
||||
#define MPIRQ_H_
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE CONSTANTS
|
||||
******************************************************************************/
|
||||
#define mpcallback_INIT_NUM_ARGS 5
|
||||
#define mp_irq_INIT_NUM_ARGS 4
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE TYPES
|
||||
******************************************************************************/
|
||||
typedef void (*mp_cb_method_t) (mp_obj_t self);
|
||||
typedef mp_obj_t (*mp_cb_init_t) (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
typedef mp_obj_t (*mp_irq_init_t) (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
typedef void (*mp_irq_void_method_t) (mp_obj_t self);
|
||||
typedef int (*mp_irq_int_method_t) (mp_obj_t self);
|
||||
|
||||
typedef struct {
|
||||
mp_cb_init_t init;
|
||||
mp_cb_method_t enable;
|
||||
mp_cb_method_t disable;
|
||||
} mp_cb_methods_t;
|
||||
mp_irq_init_t init;
|
||||
mp_irq_void_method_t enable;
|
||||
mp_irq_void_method_t disable;
|
||||
mp_irq_int_method_t flags;
|
||||
} mp_irq_methods_t;
|
||||
|
||||
typedef struct {
|
||||
mp_obj_base_t base;
|
||||
mp_obj_t parent;
|
||||
mp_obj_t handler;
|
||||
mp_cb_methods_t *methods;
|
||||
mp_irq_methods_t *methods;
|
||||
bool isenabled;
|
||||
} mpcallback_obj_t;
|
||||
} mp_irq_obj_t;
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE EXPORTED DATA
|
||||
******************************************************************************/
|
||||
extern const mp_arg_t mpcallback_init_args[];
|
||||
extern const mp_obj_type_t pyb_callback_type;
|
||||
extern const mp_arg_t mp_irq_init_args[];
|
||||
extern const mp_obj_type_t mp_irq_type;
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PUBLIC FUNCTIONS
|
||||
******************************************************************************/
|
||||
void mpcallback_init0 (void);
|
||||
mp_obj_t mpcallback_new (mp_obj_t parent, mp_obj_t handler, const mp_cb_methods_t *methods, bool enable);
|
||||
mpcallback_obj_t *mpcallback_find (mp_obj_t parent);
|
||||
void mpcallback_wake_all (void);
|
||||
void mpcallback_disable_all (void);
|
||||
void mpcallback_remove (const mp_obj_t parent);
|
||||
void mpcallback_handler (mp_obj_t self_in);
|
||||
uint mpcallback_translate_priority (uint priority);
|
||||
void mp_irq_init0 (void);
|
||||
mp_obj_t mp_irq_new (mp_obj_t parent, mp_obj_t handler, const mp_irq_methods_t *methods);
|
||||
mp_irq_obj_t *mp_irq_find (mp_obj_t parent);
|
||||
void mp_irq_wake_all (void);
|
||||
void mp_irq_disable_all (void);
|
||||
void mp_irq_remove (const mp_obj_t parent);
|
||||
void mp_irq_handler (mp_obj_t self_in);
|
||||
uint mp_irq_translate_priority (uint priority);
|
||||
|
||||
#endif /* MPCALLBACK_H_ */
|
||||
#endif /* MPIRQ_H_ */
|
||||
@@ -58,32 +58,14 @@ void sys_tick_wait_at_least(uint32_t start_tick, uint32_t delay_ms) {
|
||||
|
||||
// The SysTick timer counts down at HAL_FCPU_HZ, so we can use that knowledge
|
||||
// to grab a microsecond counter.
|
||||
//
|
||||
// We assume that HAL_GetTick returns milliseconds.
|
||||
uint32_t sys_tick_get_microseconds(void) {
|
||||
mp_uint_t irq_state = disable_irq();
|
||||
uint32_t counter = SysTickValueGet();
|
||||
uint32_t milliseconds = HAL_GetTick();
|
||||
uint32_t status = (HWREG(NVIC_ST_CTRL));
|
||||
enable_irq(irq_state);
|
||||
|
||||
// It's still possible for the countflag bit to get set if the counter was
|
||||
// reloaded between reading VAL and reading CTRL. With interrupts disabled
|
||||
// it definitely takes less than 50 HCLK cycles between reading VAL and
|
||||
// reading CTRL, so the test (counter > 50) is to cover the case where VAL
|
||||
// is +ve and very close to zero, and the COUNTFLAG bit is also set.
|
||||
if ((status & NVIC_ST_CTRL_COUNT) && counter > 50) {
|
||||
// This means that the HW reloaded VAL between the time we read VAL and the
|
||||
// time we read CTRL, which implies that there is an interrupt pending
|
||||
// to increment the tick counter.
|
||||
milliseconds++;
|
||||
}
|
||||
uint32_t load = (HWREG(NVIC_ST_RELOAD));
|
||||
uint32_t load = SysTickPeriodGet();
|
||||
counter = load - counter; // Convert from decrementing to incrementing
|
||||
|
||||
// ((load + 1) / 1000) is the number of counts per microsecond.
|
||||
//
|
||||
// counter / ((load + 1) / 1000) scales from the systick clock to microseconds
|
||||
// and is the same thing as (counter * 1000) / (load + 1)
|
||||
return milliseconds * 1000 + (counter * 1000) / (load + 1);
|
||||
return (milliseconds * 1000) + ((counter * 1000) / load);
|
||||
}
|
||||
|
||||
@@ -40,18 +40,13 @@
|
||||
#include "rom_map.h"
|
||||
#include "prcm.h"
|
||||
#include "pyexec.h"
|
||||
#include "ff.h"
|
||||
#include "diskio.h"
|
||||
#include "sflash_diskio.h"
|
||||
#include "pybuart.h"
|
||||
#include "pybpin.h"
|
||||
#include "pybrtc.h"
|
||||
#include "mpsystick.h"
|
||||
#include "simplelink.h"
|
||||
#include "modnetwork.h"
|
||||
#include "modwlan.h"
|
||||
#include "moduos.h"
|
||||
#include "telnet.h"
|
||||
#include "FreeRTOS.h"
|
||||
#include "portable.h"
|
||||
#include "task.h"
|
||||
@@ -66,8 +61,6 @@
|
||||
#include "pybtimer.h"
|
||||
#include "utils.h"
|
||||
#include "gccollect.h"
|
||||
#include "mperror.h"
|
||||
#include "genhdr/mpversion.h"
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
@@ -77,26 +70,23 @@ extern OsiTaskHandle xSimpleLinkSpawnTaskHndl;
|
||||
#endif
|
||||
|
||||
|
||||
/// \module pyb - functions related to the pyboard
|
||||
/// \module machine - functions related to the SoC
|
||||
///
|
||||
/// The `pyb` module contains specific functions related to the pyboard.
|
||||
|
||||
/// \function reset()
|
||||
/// Resets the pyboard in a manner similar to pushing the external
|
||||
/// reset button.
|
||||
STATIC mp_obj_t pyb_reset(void) {
|
||||
/******************************************************************************/
|
||||
// Micro Python bindings;
|
||||
|
||||
STATIC mp_obj_t machine_reset(void) {
|
||||
// disable wlan
|
||||
wlan_stop(SL_STOP_TIMEOUT_LONG);
|
||||
// reset the cpu and it's peripherals
|
||||
MAP_PRCMMCUReset(true);
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(pyb_reset_obj, pyb_reset);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_reset_obj, machine_reset);
|
||||
|
||||
#ifdef DEBUG
|
||||
/// \function info([dump_alloc_table])
|
||||
/// Print out some run time info which is helpful during development.
|
||||
STATIC mp_obj_t pyb_info(uint n_args, const mp_obj_t *args) {
|
||||
STATIC mp_obj_t machine_info(uint n_args, const mp_obj_t *args) {
|
||||
// FreeRTOS info
|
||||
{
|
||||
printf("---------------------------------------------\n");
|
||||
@@ -119,69 +109,82 @@ STATIC mp_obj_t pyb_info(uint n_args, const mp_obj_t *args) {
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_info_obj, 0, 1, pyb_info);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_info_obj, 0, 1, machine_info);
|
||||
#endif
|
||||
|
||||
/// \function freq()
|
||||
/// Returns the CPU frequency: (F_CPU).
|
||||
STATIC mp_obj_t pyb_freq(void) {
|
||||
STATIC mp_obj_t machine_freq(void) {
|
||||
mp_obj_t tuple[1] = {
|
||||
mp_obj_new_int(HAL_FCPU_HZ),
|
||||
};
|
||||
return mp_obj_new_tuple(1, tuple);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(pyb_freq_obj, pyb_freq);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_freq_obj, machine_freq);
|
||||
|
||||
/// \function unique_id()
|
||||
/// Returns a string of 6 bytes (48 bits), which is the unique ID for the MCU.
|
||||
STATIC mp_obj_t pyb_unique_id(void) {
|
||||
STATIC mp_obj_t machine_unique_id(void) {
|
||||
uint8_t mac[SL_BSSID_LENGTH];
|
||||
wlan_get_mac (mac);
|
||||
return mp_obj_new_bytes(mac, SL_BSSID_LENGTH);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(pyb_unique_id_obj, pyb_unique_id);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_unique_id_obj, machine_unique_id);
|
||||
|
||||
/// \function repl_uart(uart)
|
||||
/// Get or set the UART object that the REPL is repeated on.
|
||||
STATIC mp_obj_t pyb_repl_uart(uint n_args, const mp_obj_t *args) {
|
||||
if (n_args == 0) {
|
||||
if (pyb_stdio_uart == NULL) {
|
||||
return mp_const_none;
|
||||
} else {
|
||||
return pyb_stdio_uart;
|
||||
}
|
||||
STATIC mp_obj_t machine_main(mp_obj_t main) {
|
||||
if (MP_OBJ_IS_STR(main)) {
|
||||
MP_STATE_PORT(machine_config_main) = main;
|
||||
} else {
|
||||
if (args[0] == mp_const_none) {
|
||||
pyb_stdio_uart = NULL;
|
||||
} else if (mp_obj_get_type(args[0]) == &pyb_uart_type) {
|
||||
pyb_stdio_uart = args[0];
|
||||
} else {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, mpexception_num_type_invalid_arguments));
|
||||
}
|
||||
return mp_const_none;
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_repl_uart_obj, 0, 1, pyb_repl_uart);
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(machine_main_obj, machine_main);
|
||||
|
||||
MP_DECLARE_CONST_FUN_OBJ(pyb_main_obj); // defined in main.c
|
||||
STATIC mp_obj_t machine_idle(void) {
|
||||
__WFI();
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_idle_obj, machine_idle);
|
||||
|
||||
STATIC const mp_map_elem_t pyb_module_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_pyb) },
|
||||
STATIC mp_obj_t machine_sleep (void) {
|
||||
pyb_sleep_sleep();
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_sleep_obj, machine_sleep);
|
||||
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_reset), (mp_obj_t)&pyb_reset_obj },
|
||||
STATIC mp_obj_t machine_deepsleep (void) {
|
||||
pyb_sleep_deepsleep();
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_deepsleep_obj, machine_deepsleep);
|
||||
|
||||
STATIC mp_obj_t machine_reset_cause (void) {
|
||||
return mp_obj_new_int(pyb_sleep_get_reset_cause());
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_reset_cause_obj, machine_reset_cause);
|
||||
|
||||
STATIC mp_obj_t machine_wake_reason (void) {
|
||||
return mp_obj_new_int(pyb_sleep_get_wake_reason());
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_wake_reason_obj, machine_wake_reason);
|
||||
|
||||
STATIC const mp_map_elem_t machine_module_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_machine) },
|
||||
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_reset), (mp_obj_t)&machine_reset_obj },
|
||||
#ifdef DEBUG
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_info), (mp_obj_t)&pyb_info_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_info), (mp_obj_t)&machine_info_obj },
|
||||
#endif
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_freq), (mp_obj_t)&pyb_freq_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_unique_id), (mp_obj_t)&pyb_unique_id_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_repl_uart), (mp_obj_t)&pyb_repl_uart_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_freq), (mp_obj_t)&machine_freq_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_unique_id), (mp_obj_t)&machine_unique_id_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_main), (mp_obj_t)&machine_main_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_rng), (mp_obj_t)&machine_rng_get_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_idle), (mp_obj_t)&machine_idle_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_sleep), (mp_obj_t)&machine_sleep_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_deepsleep), (mp_obj_t)&machine_deepsleep_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_reset_cause), (mp_obj_t)&machine_reset_cause_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_wake_reason), (mp_obj_t)&machine_wake_reason_obj },
|
||||
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_disable_irq), (mp_obj_t)&pyb_disable_irq_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_enable_irq), (mp_obj_t)&pyb_enable_irq_obj },
|
||||
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_main), (mp_obj_t)&pyb_main_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_rng), (mp_obj_t)&pyb_rng_get_obj },
|
||||
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_RTC), (mp_obj_t)&pyb_rtc_type },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_Pin), (mp_obj_t)&pin_type },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ADC), (mp_obj_t)&pyb_adc_type },
|
||||
@@ -190,15 +193,26 @@ STATIC const mp_map_elem_t pyb_module_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_UART), (mp_obj_t)&pyb_uart_type },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_Timer), (mp_obj_t)&pyb_timer_type },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_WDT), (mp_obj_t)&pyb_wdt_type },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_Sleep), (mp_obj_t)&pyb_sleep_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_HeartBeat), (mp_obj_t)&pyb_heartbeat_type },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_SD), (mp_obj_t)&pyb_sd_type },
|
||||
|
||||
// class constants
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_IDLE), MP_OBJ_NEW_SMALL_INT(PYB_PWR_MODE_ACTIVE) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_SLEEP), MP_OBJ_NEW_SMALL_INT(PYB_PWR_MODE_LPDS) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_DEEPSLEEP), MP_OBJ_NEW_SMALL_INT(PYB_PWR_MODE_HIBERNATE) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_POWER_ON), MP_OBJ_NEW_SMALL_INT(PYB_SLP_PWRON_RESET) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_HARD_RESET), MP_OBJ_NEW_SMALL_INT(PYB_SLP_HARD_RESET) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_WDT_RESET), MP_OBJ_NEW_SMALL_INT(PYB_SLP_WDT_RESET) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_DEEPSLEEP_RESET), MP_OBJ_NEW_SMALL_INT(PYB_SLP_HIB_RESET) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_SOFT_RESET), MP_OBJ_NEW_SMALL_INT(PYB_SLP_SOFT_RESET) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_WLAN_WAKE), MP_OBJ_NEW_SMALL_INT(PYB_SLP_WAKED_BY_WLAN) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_PIN_WAKE), MP_OBJ_NEW_SMALL_INT(PYB_SLP_WAKED_BY_GPIO) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_RTC_WAKE), MP_OBJ_NEW_SMALL_INT(PYB_SLP_WAKED_BY_RTC) },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(pyb_module_globals, pyb_module_globals_table);
|
||||
STATIC MP_DEFINE_CONST_DICT(machine_module_globals, machine_module_globals_table);
|
||||
|
||||
const mp_obj_module_t pyb_module = {
|
||||
const mp_obj_module_t machine_module = {
|
||||
.base = { &mp_type_module },
|
||||
.name = MP_QSTR_pyb,
|
||||
.globals = (mp_obj_dict_t*)&pyb_module_globals,
|
||||
.name = MP_QSTR_machine,
|
||||
.globals = (mp_obj_dict_t*)&machine_module_globals,
|
||||
};
|
||||
@@ -29,12 +29,28 @@
|
||||
|
||||
#include "py/mpstate.h"
|
||||
#include MICROPY_HAL_H
|
||||
#include "py/obj.h"
|
||||
#include "py/nlr.h"
|
||||
#include "py/runtime.h"
|
||||
#include "modnetwork.h"
|
||||
#include "mpexception.h"
|
||||
#include "serverstask.h"
|
||||
#include "simplelink.h"
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE TYPES
|
||||
******************************************************************************/
|
||||
typedef struct {
|
||||
mp_obj_base_t base;
|
||||
} network_server_obj_t;
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE DATA
|
||||
******************************************************************************/
|
||||
STATIC network_server_obj_t network_server_obj;
|
||||
STATIC const mp_obj_type_t network_server_type;
|
||||
|
||||
/// \module network - network configuration
|
||||
///
|
||||
/// This module provides network drivers and server configuration.
|
||||
@@ -43,48 +59,93 @@ void mod_network_init0(void) {
|
||||
}
|
||||
|
||||
#if (MICROPY_PORT_HAS_TELNET || MICROPY_PORT_HAS_FTP)
|
||||
STATIC mp_obj_t network_server_running(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
if (n_args > 0) {
|
||||
// set
|
||||
if (mp_obj_is_true(args[0])) {
|
||||
servers_start();
|
||||
} else {
|
||||
servers_stop();
|
||||
}
|
||||
return mp_const_none;
|
||||
} else {
|
||||
// get
|
||||
return MP_BOOL(servers_are_enabled());
|
||||
STATIC mp_obj_t network_server_init_helper(mp_obj_t self, const mp_arg_val_t *args) {
|
||||
const char *user = SERVERS_DEF_USER;
|
||||
const char *pass = SERVERS_DEF_PASS;
|
||||
if (args[0].u_obj != MP_OBJ_NULL) {
|
||||
mp_obj_t *login;
|
||||
mp_obj_get_array_fixed_n(args[0].u_obj, 2, &login);
|
||||
user = mp_obj_str_get_str(login[0]);
|
||||
pass = mp_obj_str_get_str(login[1]);
|
||||
}
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(network_server_running_obj, 0, 1, network_server_running);
|
||||
|
||||
STATIC mp_obj_t network_server_login(mp_obj_t user, mp_obj_t pass) {
|
||||
const char *_user = mp_obj_str_get_str(user);
|
||||
const char *_pass = mp_obj_str_get_str(pass);
|
||||
if (strlen(user) > SERVERS_USER_PASS_LEN_MAX || strlen(pass) > SERVERS_USER_PASS_LEN_MAX) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
|
||||
uint32_t timeout = SERVERS_DEF_TIMEOUT_MS / 1000;
|
||||
if (args[1].u_obj != MP_OBJ_NULL) {
|
||||
timeout = mp_obj_get_int(args[1].u_obj);
|
||||
}
|
||||
servers_set_login ((char *)_user, (char *)_pass);
|
||||
|
||||
// configure the new login
|
||||
servers_set_login ((char *)user, (char *)pass);
|
||||
|
||||
// configure the timeout
|
||||
servers_set_timeout(timeout * 1000);
|
||||
|
||||
// start the servers
|
||||
servers_start();
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(network_server_login_obj, network_server_login);
|
||||
|
||||
STATIC const mp_arg_t network_server_args[] = {
|
||||
{ MP_QSTR_id, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
|
||||
{ MP_QSTR_login, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
|
||||
{ MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
|
||||
};
|
||||
STATIC mp_obj_t network_server_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *all_args) {
|
||||
// parse args
|
||||
mp_map_t kw_args;
|
||||
mp_map_init_fixed_table(&kw_args, n_kw, all_args + n_args);
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(network_server_args)];
|
||||
mp_arg_parse_all(n_args, all_args, &kw_args, MP_ARRAY_SIZE(args), network_server_args, args);
|
||||
|
||||
// check the server id
|
||||
if (args[0].u_obj != MP_OBJ_NULL) {
|
||||
if (mp_obj_get_int(args[0].u_obj) != 0) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable));
|
||||
}
|
||||
}
|
||||
|
||||
// setup the object and initialize it
|
||||
network_server_obj_t *self = &network_server_obj;
|
||||
self->base.type = &network_server_type;
|
||||
network_server_init_helper(self, &args[1]);
|
||||
|
||||
return (mp_obj_t)self;
|
||||
}
|
||||
|
||||
STATIC mp_obj_t network_server_init(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
// parse args
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(network_server_args) - 1];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), &network_server_args[1], args);
|
||||
return network_server_init_helper(pos_args[0], args);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(network_server_init_obj, 1, network_server_init);
|
||||
|
||||
// timeout value given in seconds
|
||||
STATIC mp_obj_t network_server_timeout(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
if (n_args > 0) {
|
||||
uint32_t _timeout = mp_obj_get_int(args[0]);
|
||||
if (!servers_set_timeout(_timeout * 1000)) {
|
||||
// timeout is too low
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
|
||||
}
|
||||
if (n_args > 1) {
|
||||
uint32_t timeout = mp_obj_get_int(args[1]);
|
||||
servers_set_timeout(timeout * 1000);
|
||||
return mp_const_none;
|
||||
} else {
|
||||
// get
|
||||
return mp_obj_new_int(servers_get_timeout() / 1000);
|
||||
}
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(network_server_timeout_obj, 0, 1, network_server_timeout);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(network_server_timeout_obj, 1, 2, network_server_timeout);
|
||||
|
||||
STATIC mp_obj_t network_server_running(mp_obj_t self_in) {
|
||||
// get
|
||||
return mp_obj_new_bool(servers_are_enabled());
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(network_server_running_obj, network_server_running);
|
||||
|
||||
STATIC mp_obj_t network_server_deinit(mp_obj_t self_in) {
|
||||
// simply stop the servers
|
||||
servers_stop();
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(network_server_deinit_obj, network_server_deinit);
|
||||
#endif
|
||||
|
||||
STATIC const mp_map_elem_t mp_module_network_globals_table[] = {
|
||||
@@ -92,9 +153,7 @@ STATIC const mp_map_elem_t mp_module_network_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_WLAN), (mp_obj_t)&mod_network_nic_type_wlan },
|
||||
|
||||
#if (MICROPY_PORT_HAS_TELNET || MICROPY_PORT_HAS_FTP)
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_server_running), (mp_obj_t)&network_server_running_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_server_login), (mp_obj_t)&network_server_login_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_server_timeout), (mp_obj_t)&network_server_timeout_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_server), (mp_obj_t)&network_server_type },
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -105,3 +164,21 @@ const mp_obj_module_t mp_module_network = {
|
||||
.name = MP_QSTR_network,
|
||||
.globals = (mp_obj_dict_t*)&mp_module_network_globals,
|
||||
};
|
||||
|
||||
#if (MICROPY_PORT_HAS_TELNET || MICROPY_PORT_HAS_FTP)
|
||||
STATIC const mp_map_elem_t network_server_locals_dict_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)&network_server_init_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_deinit), (mp_obj_t)&network_server_deinit_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_timeout), (mp_obj_t)&network_server_timeout_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_isrunning), (mp_obj_t)&network_server_running_obj },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(network_server_locals_dict, network_server_locals_dict_table);
|
||||
|
||||
STATIC const mp_obj_type_t network_server_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_server,
|
||||
.make_new = network_server_make_new,
|
||||
.locals_dict = (mp_obj_t)&network_server_locals_dict,
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
#include "py/objstr.h"
|
||||
#include "py/runtime.h"
|
||||
#include "genhdr/mpversion.h"
|
||||
#include "ff.h"
|
||||
#include "moduos.h"
|
||||
#include "diskio.h"
|
||||
#include "sflash_diskio.h"
|
||||
#include "file.h"
|
||||
@@ -42,8 +42,8 @@
|
||||
#include "mpexception.h"
|
||||
#include "version.h"
|
||||
#include "timeutils.h"
|
||||
#include "moduos.h"
|
||||
#include "pybsd.h"
|
||||
#include "pybuart.h"
|
||||
|
||||
/// \module os - basic "operating system" services
|
||||
///
|
||||
@@ -60,6 +60,7 @@
|
||||
DECLARE PRIVATE DATA
|
||||
******************************************************************************/
|
||||
STATIC uint32_t os_num_mounted_devices;
|
||||
STATIC os_term_dup_obj_t os_term_dup_obj;
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PUBLIC FUNCTIONS
|
||||
@@ -536,6 +537,31 @@ STATIC mp_obj_t os_mkfs(mp_obj_t device) {
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_mkfs_obj, os_mkfs);
|
||||
|
||||
STATIC mp_obj_t os_dupterm(uint n_args, const mp_obj_t *args) {
|
||||
if (n_args == 0) {
|
||||
if (MP_STATE_PORT(os_term_dup_obj) == MP_OBJ_NULL) {
|
||||
return mp_const_none;
|
||||
} else {
|
||||
return MP_STATE_PORT(os_term_dup_obj)->stream_o;
|
||||
}
|
||||
} else {
|
||||
mp_obj_t stream_o = args[0];
|
||||
if (stream_o == mp_const_none) {
|
||||
MP_STATE_PORT(os_term_dup_obj) = MP_OBJ_NULL;
|
||||
} else {
|
||||
if (!MP_OBJ_IS_TYPE(stream_o, &pyb_uart_type)) {
|
||||
// must be a stream-like object providing at least read and write methods
|
||||
mp_load_method(stream_o, MP_QSTR_read, os_term_dup_obj.read);
|
||||
mp_load_method(stream_o, MP_QSTR_write, os_term_dup_obj.write);
|
||||
}
|
||||
os_term_dup_obj.stream_o = stream_o;
|
||||
MP_STATE_PORT(os_term_dup_obj) = &os_term_dup_obj;
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(os_dupterm_obj, 0, 1, os_dupterm);
|
||||
|
||||
STATIC const mp_map_elem_t os_module_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_uos) },
|
||||
|
||||
@@ -551,9 +577,12 @@ STATIC const mp_map_elem_t os_module_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_unlink), (mp_obj_t)&os_remove_obj }, // unlink aliases to remove
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_sync), (mp_obj_t)&os_sync_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_urandom), (mp_obj_t)&os_urandom_obj },
|
||||
|
||||
// MicroPython additions
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_mount), (mp_obj_t)&os_mount_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_unmount), (mp_obj_t)&os_unmount_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_mkfs), (mp_obj_t)&os_mkfs_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_dupterm), (mp_obj_t)&os_dupterm_obj },
|
||||
|
||||
/// \constant sep - separation character used in paths
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_sep), MP_OBJ_NEW_QSTR(MP_QSTR__slash_) },
|
||||
|
||||
@@ -28,6 +28,11 @@
|
||||
#ifndef MODUOS_H_
|
||||
#define MODUOS_H_
|
||||
|
||||
#include "ff.h"
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PUBLIC TYPES
|
||||
******************************************************************************/
|
||||
typedef struct _os_fs_mount_t {
|
||||
mp_obj_t device;
|
||||
const char *path;
|
||||
@@ -40,6 +45,15 @@ typedef struct _os_fs_mount_t {
|
||||
uint8_t vol;
|
||||
} os_fs_mount_t;
|
||||
|
||||
typedef struct _os_term_dup_obj_t {
|
||||
mp_obj_t stream_o;
|
||||
mp_obj_t read[3];
|
||||
mp_obj_t write[3];
|
||||
} os_term_dup_obj_t;
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PUBLIC FUNCTIONS
|
||||
******************************************************************************/
|
||||
void moduos_init0 (void);
|
||||
os_fs_mount_t *osmount_find_by_path (const char *path);
|
||||
os_fs_mount_t *osmount_find_by_volume (uint8_t vol);
|
||||
|
||||
@@ -185,17 +185,23 @@ STATIC mp_obj_t socket_bind(mp_obj_t self_in, mp_obj_t addr_in) {
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_bind_obj, socket_bind);
|
||||
|
||||
// method socket.listen(backlog)
|
||||
STATIC mp_obj_t socket_listen(mp_obj_t self_in, mp_obj_t backlog) {
|
||||
mod_network_socket_obj_t *self = self_in;
|
||||
// method socket.listen([backlog])
|
||||
STATIC mp_obj_t socket_listen(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
mod_network_socket_obj_t *self = args[0];
|
||||
|
||||
int32_t backlog = 0;
|
||||
if (n_args > 1) {
|
||||
backlog = mp_obj_get_int(args[1]);
|
||||
backlog = (backlog < 0) ? 0 : backlog;
|
||||
}
|
||||
|
||||
int _errno;
|
||||
if (wlan_socket_listen(self, mp_obj_get_int(backlog), &_errno) != 0) {
|
||||
if (wlan_socket_listen(self, backlog, &_errno) != 0) {
|
||||
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(-_errno)));
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_listen_obj, socket_listen);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_listen_obj, 1, 2, socket_listen);
|
||||
|
||||
// method socket.accept()
|
||||
STATIC mp_obj_t socket_accept(mp_obj_t self_in) {
|
||||
@@ -391,6 +397,21 @@ STATIC mp_obj_t socket_setblocking(mp_obj_t self_in, mp_obj_t blocking) {
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_setblocking_obj, socket_setblocking);
|
||||
|
||||
STATIC mp_obj_t socket_makefile(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
// TODO: CPython explicitly says that closing the returned object doesn't
|
||||
// close the original socket (Python2 at all says that fd is dup()ed). But
|
||||
// we save on the bloat.
|
||||
mod_network_socket_obj_t *self = args[0];
|
||||
if (n_args > 1) {
|
||||
const char *mode = mp_obj_str_get_str(args[1]);
|
||||
if (strcmp(mode, "rb") && strcmp(mode, "wb")) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_makefile_obj, 1, 6, socket_makefile);
|
||||
|
||||
STATIC const mp_map_elem_t socket_locals_dict_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___del__), (mp_obj_t)&socket_close_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_close), (mp_obj_t)&socket_close_obj },
|
||||
@@ -406,7 +427,7 @@ STATIC const mp_map_elem_t socket_locals_dict_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_setsockopt), (mp_obj_t)&socket_setsockopt_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_settimeout), (mp_obj_t)&socket_settimeout_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_setblocking), (mp_obj_t)&socket_setblocking_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_makefile), (mp_obj_t)&mp_identity_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_makefile), (mp_obj_t)&socket_makefile_obj },
|
||||
|
||||
// stream methods
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_read), (mp_obj_t)&mp_stream_read_obj },
|
||||
@@ -504,16 +525,13 @@ STATIC const mp_map_elem_t mp_module_usocket_globals_table[] = {
|
||||
|
||||
// class constants
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_AF_INET), MP_OBJ_NEW_SMALL_INT(AF_INET) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_AF_INET6), MP_OBJ_NEW_SMALL_INT(AF_INET6) },
|
||||
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_SOCK_STREAM), MP_OBJ_NEW_SMALL_INT(SOCK_STREAM) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_SOCK_DGRAM), MP_OBJ_NEW_SMALL_INT(SOCK_DGRAM) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_SOCK_RAW), MP_OBJ_NEW_SMALL_INT(SOCK_RAW) },
|
||||
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_IPPROTO_SEC), MP_OBJ_NEW_SMALL_INT(SL_SEC_SOCKET) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_IPPROTO_TCP), MP_OBJ_NEW_SMALL_INT(IPPROTO_TCP) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_IPPROTO_UDP), MP_OBJ_NEW_SMALL_INT(IPPROTO_UDP) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_IPPROTO_RAW), MP_OBJ_NEW_SMALL_INT(IPPROTO_RAW) },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(mp_module_usocket_globals, mp_module_usocket_globals_table);
|
||||
|
||||
@@ -61,7 +61,7 @@ STATIC const mp_obj_type_t ssl_socket_type;
|
||||
/******************************************************************************/
|
||||
// Micro Python bindings; SSL class
|
||||
|
||||
// ssl socket inherits from normal socket, so we take its
|
||||
// ssl sockets inherit from normal socket, so we take its
|
||||
// locals and stream methods
|
||||
STATIC const mp_obj_type_t ssl_socket_type = {
|
||||
{ &mp_type_type },
|
||||
@@ -91,7 +91,7 @@ STATIC mp_obj_t mod_ssl_wrap_socket(mp_uint_t n_args, const mp_obj_t *pos_args,
|
||||
goto arg_error;
|
||||
}
|
||||
|
||||
// retrieve the file paths (with an 6 byte offset because to strip the '/flash' prefix)
|
||||
// retrieve the file paths (with an 6 byte offset in order to strip it from the '/flash' prefix)
|
||||
const char *keyfile = (args[1].u_obj == mp_const_none) ? NULL : &(mp_obj_str_get_str(args[1].u_obj)[6]);
|
||||
const char *certfile = (args[2].u_obj == mp_const_none) ? NULL : &(mp_obj_str_get_str(args[2].u_obj)[6]);
|
||||
const char *cafile = (args[5].u_obj == mp_const_none || args[4].u_int != SSL_CERT_REQUIRED) ?
|
||||
@@ -116,7 +116,7 @@ STATIC mp_obj_t mod_ssl_wrap_socket(mp_uint_t n_args, const mp_obj_t *pos_args,
|
||||
|
||||
// create the ssl socket
|
||||
mp_obj_ssl_socket_t *ssl_sock = m_new_obj(mp_obj_ssl_socket_t);
|
||||
// ssl socket inherits all properties from the original socket
|
||||
// ssl sockets inherit all properties from the original socket
|
||||
memcpy (&ssl_sock->sock_base, &((mod_network_socket_obj_t *)args[0].u_obj)->sock_base, sizeof(mod_network_socket_base_t));
|
||||
ssl_sock->base.type = &ssl_socket_type;
|
||||
ssl_sock->sock_base.cert_req = (args[4].u_int == SSL_CERT_REQUIRED) ? true : false;
|
||||
@@ -130,7 +130,7 @@ socket_error:
|
||||
arg_error:
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_ssl_wrap_socket_obj, 1, mod_ssl_wrap_socket);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_ssl_wrap_socket_obj, 0, mod_ssl_wrap_socket);
|
||||
|
||||
STATIC const mp_map_elem_t mp_module_ussl_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_ussl) },
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include MICROPY_HAL_H
|
||||
#include "py/nlr.h"
|
||||
#include "py/obj.h"
|
||||
#include "py/smallint.h"
|
||||
#include "timeutils.h"
|
||||
#include "inc/hw_types.h"
|
||||
#include "inc/hw_ints.h"
|
||||
@@ -56,7 +57,7 @@
|
||||
/// Convert a time expressed in seconds since Jan 1, 2000 into an 8-tuple which
|
||||
/// contains: (year, month, mday, hour, minute, second, weekday, yearday)
|
||||
/// If secs is not provided or None, then the current time from the RTC is used.
|
||||
/// year includes the century (for example 2014)
|
||||
/// year includes the century (for example 2015)
|
||||
/// month is 1-12
|
||||
/// mday is 1-31
|
||||
/// hour is 0-23
|
||||
@@ -67,14 +68,9 @@
|
||||
STATIC mp_obj_t time_localtime(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
if (n_args == 0 || args[0] == mp_const_none) {
|
||||
timeutils_struct_time_t tm;
|
||||
uint32_t seconds;
|
||||
uint16_t mseconds;
|
||||
|
||||
// get the seconds and the milliseconds from the RTC
|
||||
MAP_PRCMRTCGet(&seconds, &mseconds);
|
||||
mseconds = RTC_CYCLES_U16MS(mseconds);
|
||||
timeutils_seconds_since_2000_to_struct_time(seconds, &tm);
|
||||
|
||||
// get the seconds from the RTC
|
||||
timeutils_seconds_since_2000_to_struct_time(pyb_rtc_get_seconds(), &tm);
|
||||
mp_obj_t tuple[8] = {
|
||||
mp_obj_new_int(tm.tm_year),
|
||||
mp_obj_new_int(tm.tm_mon),
|
||||
@@ -154,36 +150,28 @@ STATIC mp_obj_t time_sleep_us (mp_obj_t usec_in) {
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(time_sleep_us_obj, time_sleep_us);
|
||||
|
||||
STATIC mp_obj_t time_ticks_ms(void) {
|
||||
// We want to "cast" the 32 bit unsigned into a small-int. This means
|
||||
// copying the MSB down 1 bit (extending the sign down), which is
|
||||
// equivalent to just using the MP_OBJ_NEW_SMALL_INT macro.
|
||||
return MP_OBJ_NEW_SMALL_INT(HAL_GetTick());
|
||||
// We want to "cast" the 32 bit unsigned into a 30-bit small-int
|
||||
return MP_OBJ_NEW_SMALL_INT(HAL_GetTick() & MP_SMALL_INT_POSITIVE_MASK);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(time_ticks_ms_obj, time_ticks_ms);
|
||||
|
||||
STATIC mp_obj_t time_ticks_us(void) {
|
||||
// We want to "cast" the 32 bit unsigned into a small-int. This means
|
||||
// copying the MSB down 1 bit (extending the sign down), which is
|
||||
// equivalent to just using the MP_OBJ_NEW_SMALL_INT macro.
|
||||
return MP_OBJ_NEW_SMALL_INT(sys_tick_get_microseconds());
|
||||
// We want to "cast" the 32 bit unsigned into a 30-bit small-int
|
||||
return MP_OBJ_NEW_SMALL_INT(sys_tick_get_microseconds() & MP_SMALL_INT_POSITIVE_MASK);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(time_ticks_us_obj, time_ticks_us);
|
||||
|
||||
STATIC mp_obj_t time_ticks_cpu(void) {
|
||||
// We want to "cast" the 32 bit unsigned into a small-int. This means
|
||||
// copying the MSB down 1 bit (extending the sign down), which is
|
||||
// equivalent to just using the MP_OBJ_NEW_SMALL_INT macro.
|
||||
return MP_OBJ_NEW_SMALL_INT(SysTickValueGet());
|
||||
// We want to "cast" the 32 bit unsigned into a 30-bit small-int
|
||||
return MP_OBJ_NEW_SMALL_INT((SysTickPeriodGet() - SysTickValueGet()) & MP_SMALL_INT_POSITIVE_MASK);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(time_ticks_cpu_obj, time_ticks_cpu);
|
||||
|
||||
STATIC mp_obj_t time_ticks_diff(mp_obj_t t0, mp_obj_t t1) {
|
||||
// We want to "cast" the 32 bit unsigned into a small-int. This means
|
||||
// copying the MSB down 1 bit (extending the sign down), which is
|
||||
// equivalent to just using the MP_OBJ_NEW_SMALL_INT macro.
|
||||
// We want to "cast" the 32 bit unsigned into a 30-bit small-int
|
||||
uint32_t start = mp_obj_get_int(t0);
|
||||
uint32_t end = mp_obj_get_int(t1);
|
||||
return MP_OBJ_NEW_SMALL_INT((end > start) ? (end - start) : (start - end));
|
||||
return MP_OBJ_NEW_SMALL_INT((end - start) & MP_SMALL_INT_POSITIVE_MASK);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(time_ticks_diff_obj, time_ticks_diff);
|
||||
|
||||
@@ -194,6 +182,8 @@ STATIC const mp_map_elem_t time_module_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_mktime), (mp_obj_t)&time_mktime_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_time), (mp_obj_t)&time_time_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_sleep), (mp_obj_t)&time_sleep_obj },
|
||||
|
||||
// MicroPython additions
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_sleep_ms), (mp_obj_t)&time_sleep_ms_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_sleep_us), (mp_obj_t)&time_sleep_us_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ticks_ms), (mp_obj_t)&time_ticks_ms_obj },
|
||||
|
||||
32
cc3200/mods/modwipy.c
Normal file
32
cc3200/mods/modwipy.c
Normal file
@@ -0,0 +1,32 @@
|
||||
#include "py/mpconfig.h"
|
||||
#include MICROPY_HAL_H
|
||||
#include "py/obj.h"
|
||||
#include "py/runtime.h"
|
||||
#include "mperror.h"
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
// Micro Python bindings
|
||||
|
||||
STATIC mp_obj_t mod_wipy_heartbeat (mp_uint_t n_args, const mp_obj_t *args) {
|
||||
if (n_args) {
|
||||
mperror_enable_heartbeat (mp_obj_is_true(args[0]));
|
||||
return mp_const_none;
|
||||
} else {
|
||||
return mp_obj_new_bool(mperror_is_heartbeat_enabled());
|
||||
}
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_wipy_heartbeat_obj, 0, 1, mod_wipy_heartbeat);
|
||||
|
||||
STATIC const mp_map_elem_t wipy_module_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_wipy) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_heartbeat), (mp_obj_t)&mod_wipy_heartbeat_obj },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(wipy_module_globals, wipy_module_globals_table);
|
||||
|
||||
const mp_obj_module_t wipy_module = {
|
||||
.base = { &mp_type_module },
|
||||
.name = MP_QSTR_wipy,
|
||||
.globals = (mp_obj_dict_t*)&wipy_module_globals,
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
@@ -35,6 +35,10 @@
|
||||
#define SL_STOP_TIMEOUT 35
|
||||
#define SL_STOP_TIMEOUT_LONG 575
|
||||
|
||||
#define MODWLAN_WIFI_EVENT_ANY 0x01
|
||||
|
||||
#define MODWLAN_SSID_LEN_MAX 32
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE TYPES
|
||||
******************************************************************************/
|
||||
@@ -45,6 +49,34 @@ typedef enum {
|
||||
MODWLAN_ERROR_UNKNOWN = -3,
|
||||
} modwlan_Status_t;
|
||||
|
||||
typedef struct _wlan_obj_t {
|
||||
mp_obj_base_t base;
|
||||
mp_obj_t irq_obj;
|
||||
uint32_t status;
|
||||
|
||||
uint32_t ip;
|
||||
|
||||
int8_t mode;
|
||||
uint8_t auth;
|
||||
uint8_t channel;
|
||||
uint8_t antenna;
|
||||
|
||||
// my own ssid, key and mac
|
||||
uint8_t ssid[(MODWLAN_SSID_LEN_MAX + 1)];
|
||||
uint8_t key[65];
|
||||
uint8_t mac[SL_MAC_ADDR_LEN];
|
||||
|
||||
// the sssid (or name) and mac of the other device
|
||||
uint8_t ssid_o[33];
|
||||
uint8_t bssid[6];
|
||||
uint8_t irq_flags;
|
||||
bool irq_enabled;
|
||||
|
||||
#if (MICROPY_PORT_HAS_TELNET || MICROPY_PORT_HAS_FTP)
|
||||
bool servers_enabled;
|
||||
#endif
|
||||
} wlan_obj_t;
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PUBLIC DATA
|
||||
******************************************************************************/
|
||||
@@ -54,12 +86,11 @@ extern _SlLockObj_t wlan_LockObj;
|
||||
DECLARE PUBLIC FUNCTIONS
|
||||
******************************************************************************/
|
||||
extern void wlan_pre_init (void);
|
||||
extern void wlan_sl_enable (int8_t mode, const char *ssid, uint8_t ssid_len, uint8_t sec,
|
||||
const char *key, uint8_t key_len, uint8_t channel, bool append_mac);
|
||||
extern void wlan_sl_init (int8_t mode, const char *ssid, uint8_t ssid_len, uint8_t auth, const char *key, uint8_t key_len,
|
||||
uint8_t channel, uint8_t antenna, bool add_mac);
|
||||
extern void wlan_first_start (void);
|
||||
extern void wlan_update(void);
|
||||
extern void wlan_stop (uint32_t timeout);
|
||||
extern void wlan_start (void);
|
||||
extern void wlan_get_mac (uint8_t *macAddress);
|
||||
extern void wlan_get_ip (uint32_t *ip);
|
||||
extern bool wlan_is_connected (void);
|
||||
|
||||
@@ -164,7 +164,7 @@ STATIC mp_obj_t adc_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw,
|
||||
|
||||
// initialize and register with the sleep module
|
||||
pyb_adc_init(self);
|
||||
pybsleep_add ((const mp_obj_t)self, (WakeUpCB_t)pyb_adc_init);
|
||||
pyb_sleep_add ((const mp_obj_t)self, (WakeUpCB_t)pyb_adc_init);
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -188,14 +188,14 @@ STATIC mp_obj_t adc_deinit(mp_obj_t self_in) {
|
||||
MAP_ADCDisable(ADC_BASE);
|
||||
self->enabled = false;
|
||||
// unregister it with the sleep module
|
||||
pybsleep_remove ((const mp_obj_t)self);
|
||||
pyb_sleep_remove ((const mp_obj_t)self);
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_deinit_obj, adc_deinit);
|
||||
|
||||
STATIC mp_obj_t adc_channel(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
STATIC const mp_arg_t pyb_adc_channel_args[] = {
|
||||
{ MP_QSTR_id, MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||
{ MP_QSTR_id, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
|
||||
{ MP_QSTR_pin, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||
};
|
||||
|
||||
@@ -204,12 +204,11 @@ STATIC mp_obj_t adc_channel(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), pyb_adc_channel_args, args);
|
||||
|
||||
uint ch_id;
|
||||
if (args[0].u_obj != mp_const_none) {
|
||||
if (args[0].u_obj != MP_OBJ_NULL) {
|
||||
ch_id = mp_obj_get_int(args[0].u_obj);
|
||||
if (ch_id >= PYB_ADC_NUM_CHANNELS) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_os_resource_not_avaliable));
|
||||
}
|
||||
else if (args[1].u_obj != mp_const_none) {
|
||||
} else if (args[1].u_obj != mp_const_none) {
|
||||
uint pin_ch_id = pin_find_peripheral_type (args[1].u_obj, PIN_FN_ADC, 0);
|
||||
if (ch_id != pin_ch_id) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
|
||||
@@ -224,7 +223,7 @@ STATIC mp_obj_t adc_channel(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t
|
||||
self->base.type = &pyb_adc_channel_type;
|
||||
pyb_adc_channel_init (self);
|
||||
// register it with the sleep module
|
||||
pybsleep_add ((const mp_obj_t)self, (WakeUpCB_t)pyb_adc_channel_init);
|
||||
pyb_sleep_add ((const mp_obj_t)self, (WakeUpCB_t)pyb_adc_channel_init);
|
||||
return self;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(adc_channel_obj, 1, adc_channel);
|
||||
@@ -267,7 +266,7 @@ STATIC mp_obj_t adc_channel_deinit(mp_obj_t self_in) {
|
||||
|
||||
MAP_ADCChannelDisable(ADC_BASE, self->channel);
|
||||
// unregister it with the sleep module
|
||||
pybsleep_remove ((const mp_obj_t)self);
|
||||
pyb_sleep_remove ((const mp_obj_t)self);
|
||||
self->enabled = false;
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
@@ -292,24 +292,20 @@ STATIC mp_obj_t pyb_i2c_init_helper(pyb_i2c_obj_t *self, const mp_arg_val_t *arg
|
||||
mp_obj_t pins_o = args[2].u_obj;
|
||||
if (pins_o != mp_const_none) {
|
||||
mp_obj_t *pins;
|
||||
mp_uint_t n_pins = 2;
|
||||
if (pins_o == MP_OBJ_NULL) {
|
||||
// use the default pins
|
||||
pins = (mp_obj_t *)pyb_i2c_def_pin;
|
||||
} else {
|
||||
mp_obj_get_array(pins_o, &n_pins, &pins);
|
||||
if (n_pins != 2) {
|
||||
goto invalid_args;
|
||||
}
|
||||
mp_obj_get_array_fixed_n(pins_o, 2, &pins);
|
||||
}
|
||||
pin_assign_pins_af (pins, n_pins, PIN_TYPE_STD_PU, PIN_FN_I2C, 0);
|
||||
pin_assign_pins_af (pins, 2, PIN_TYPE_STD_PU, PIN_FN_I2C, 0);
|
||||
}
|
||||
|
||||
// init the I2C bus
|
||||
i2c_init(self);
|
||||
|
||||
// register it with the sleep module
|
||||
pybsleep_add ((const mp_obj_t)self, (WakeUpCB_t)i2c_init);
|
||||
pyb_sleep_add ((const mp_obj_t)self, (WakeUpCB_t)i2c_init);
|
||||
|
||||
return mp_const_none;
|
||||
|
||||
@@ -320,8 +316,8 @@ invalid_args:
|
||||
STATIC const mp_arg_t pyb_i2c_init_args[] = {
|
||||
{ MP_QSTR_id, MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_mode, MP_ARG_INT, {.u_int = PYBI2C_MASTER} },
|
||||
{ MP_QSTR_baudrate, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 100000} },
|
||||
{ MP_QSTR_pins, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
|
||||
{ MP_QSTR_baudrate, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 100000} },
|
||||
{ MP_QSTR_pins, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
|
||||
};
|
||||
STATIC mp_obj_t pyb_i2c_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *all_args) {
|
||||
// parse args
|
||||
@@ -360,7 +356,7 @@ STATIC mp_obj_t pyb_i2c_deinit(mp_obj_t self_in) {
|
||||
// invalidate the baudrate
|
||||
pyb_i2c_obj.baudrate = 0;
|
||||
// unregister it with the sleep module
|
||||
pybsleep_remove ((const mp_obj_t)self_in);
|
||||
pyb_sleep_remove ((const mp_obj_t)self_in);
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_i2c_deinit_obj, pyb_i2c_deinit);
|
||||
@@ -414,7 +410,7 @@ STATIC mp_obj_t pyb_i2c_readfrom_into(mp_uint_t n_args, const mp_obj_t *pos_args
|
||||
// return the number of bytes received
|
||||
return mp_obj_new_int(vstr.len);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_readfrom_into_obj, 3, pyb_i2c_readfrom_into);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_readfrom_into_obj, 1, pyb_i2c_readfrom_into);
|
||||
|
||||
STATIC mp_obj_t pyb_i2c_writeto(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
STATIC const mp_arg_t pyb_i2c_writeto_args[] = {
|
||||
@@ -442,7 +438,7 @@ STATIC mp_obj_t pyb_i2c_writeto(mp_uint_t n_args, const mp_obj_t *pos_args, mp_m
|
||||
// return the number of bytes written
|
||||
return mp_obj_new_int(bufinfo.len);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_writeto_obj, 3, pyb_i2c_writeto);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_writeto_obj, 1, pyb_i2c_writeto);
|
||||
|
||||
STATIC mp_obj_t pyb_i2c_readfrom_mem(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
STATIC const mp_arg_t pyb_i2c_readfrom_mem_args[] = {
|
||||
@@ -460,7 +456,7 @@ STATIC mp_obj_t pyb_i2c_readfrom_mem(mp_uint_t n_args, const mp_obj_t *pos_args,
|
||||
pyb_i2c_readmem_into (args, &vstr);
|
||||
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_readfrom_mem_obj, 4, pyb_i2c_readfrom_mem);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_readfrom_mem_obj, 1, pyb_i2c_readfrom_mem);
|
||||
|
||||
STATIC const mp_arg_t pyb_i2c_readfrom_mem_into_args[] = {
|
||||
{ MP_QSTR_addr, MP_ARG_REQUIRED | MP_ARG_INT, },
|
||||
@@ -479,7 +475,7 @@ STATIC mp_obj_t pyb_i2c_readfrom_mem_into(mp_uint_t n_args, const mp_obj_t *pos_
|
||||
pyb_i2c_readmem_into (args, &vstr);
|
||||
return mp_obj_new_int(vstr.len);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_readfrom_mem_into_obj, 4, pyb_i2c_readfrom_mem_into);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_readfrom_mem_into_obj, 1, pyb_i2c_readfrom_mem_into);
|
||||
|
||||
STATIC mp_obj_t pyb_i2c_writeto_mem(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
// parse args
|
||||
@@ -507,7 +503,7 @@ STATIC mp_obj_t pyb_i2c_writeto_mem(mp_uint_t n_args, const mp_obj_t *pos_args,
|
||||
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed));
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_writeto_mem_obj, 4, pyb_i2c_writeto_mem);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_writeto_mem_obj, 1, pyb_i2c_writeto_mem);
|
||||
|
||||
STATIC const mp_map_elem_t pyb_i2c_locals_dict_table[] = {
|
||||
// instance methods
|
||||
|
||||
@@ -45,9 +45,9 @@
|
||||
#include "gpio.h"
|
||||
#include "interrupt.h"
|
||||
#include "pybpin.h"
|
||||
#include "mpirq.h"
|
||||
#include "pins.h"
|
||||
#include "pybsleep.h"
|
||||
#include "mpcallback.h"
|
||||
#include "mpexception.h"
|
||||
#include "mperror.h"
|
||||
|
||||
@@ -66,8 +66,8 @@ STATIC void pin_free_af_from_pins (uint8_t fn, uint8_t unit, uint8_t type);
|
||||
STATIC void pin_deassign (pin_obj_t* pin);
|
||||
STATIC void pin_obj_configure (const pin_obj_t *self);
|
||||
STATIC void pin_get_hibernate_pin_and_idx (const pin_obj_t *self, uint *wake_pin, uint *idx);
|
||||
STATIC void pin_extint_enable (mp_obj_t self_in);
|
||||
STATIC void pin_extint_disable (mp_obj_t self_in);
|
||||
STATIC void pin_irq_enable (mp_obj_t self_in);
|
||||
STATIC void pin_irq_disable (mp_obj_t self_in);
|
||||
STATIC void pin_extint_register(pin_obj_t *self, uint32_t intmode, uint32_t priority);
|
||||
STATIC void pin_validate_mode (uint mode);
|
||||
STATIC void pin_validate_pull (uint pull);
|
||||
@@ -88,6 +88,11 @@ DEFINE CONSTANTS
|
||||
#define GPIO_DIR_MODE_ALT 0x00000002 // Pin is NOT controlled by the PGIO module
|
||||
#define GPIO_DIR_MODE_ALT_OD 0x00000003 // Pin is NOT controlled by the PGIO module and is in open drain mode
|
||||
|
||||
#define PYB_PIN_FALLING_EDGE 0x01
|
||||
#define PYB_PIN_RISING_EDGE 0x02
|
||||
#define PYB_PIN_LOW_LEVEL 0x04
|
||||
#define PYB_PIN_HIGH_LEVEL 0x08
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE TYPES
|
||||
******************************************************************************/
|
||||
@@ -100,7 +105,7 @@ typedef struct {
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE DATA
|
||||
******************************************************************************/
|
||||
STATIC const mp_cb_methods_t pin_cb_methods;
|
||||
STATIC const mp_irq_methods_t pin_irq_methods;
|
||||
STATIC pybpin_wake_pin_t pybpin_wake_pin[PYBPIN_NUM_WAKE_PINS] =
|
||||
{ {.active = false, .lpds = PYBPIN_WAKES_NOT, .hib = PYBPIN_WAKES_NOT},
|
||||
{.active = false, .lpds = PYBPIN_WAKES_NOT, .hib = PYBPIN_WAKES_NOT},
|
||||
@@ -161,7 +166,7 @@ void pin_config (pin_obj_t *self, int af, uint mode, uint pull, int value, uint
|
||||
pin_obj_configure ((const pin_obj_t *)self);
|
||||
|
||||
// register it with the sleep module
|
||||
pybsleep_add ((const mp_obj_t)self, (WakeUpCB_t)pin_obj_configure);
|
||||
pyb_sleep_add ((const mp_obj_t)self, (WakeUpCB_t)pin_obj_configure);
|
||||
}
|
||||
|
||||
void pin_assign_pins_af (mp_obj_t *pins, uint32_t n_pins, uint32_t pull, uint32_t fn, uint32_t unit) {
|
||||
@@ -334,7 +339,7 @@ STATIC void pin_get_hibernate_pin_and_idx (const pin_obj_t *self, uint *hib_pin,
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void pin_extint_enable (mp_obj_t self_in) {
|
||||
STATIC void pin_irq_enable (mp_obj_t self_in) {
|
||||
const pin_obj_t *self = self_in;
|
||||
uint hib_pin, idx;
|
||||
|
||||
@@ -366,7 +371,7 @@ STATIC void pin_extint_enable (mp_obj_t self_in) {
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void pin_extint_disable (mp_obj_t self_in) {
|
||||
STATIC void pin_irq_disable (mp_obj_t self_in) {
|
||||
const pin_obj_t *self = self_in;
|
||||
uint hib_pin, idx;
|
||||
|
||||
@@ -385,6 +390,11 @@ STATIC void pin_extint_disable (mp_obj_t self_in) {
|
||||
MAP_GPIOIntDisable(self->port, self->bit);
|
||||
}
|
||||
|
||||
STATIC int pin_irq_flags (mp_obj_t self_in) {
|
||||
const pin_obj_t *self = self_in;
|
||||
return self->irq_flags;
|
||||
}
|
||||
|
||||
STATIC void pin_extint_register(pin_obj_t *self, uint32_t intmode, uint32_t priority) {
|
||||
void *handler;
|
||||
uint32_t intnum;
|
||||
@@ -467,14 +477,22 @@ STATIC void EXTI_Handler(uint port) {
|
||||
uint32_t bits = MAP_GPIOIntStatus(port, true);
|
||||
MAP_GPIOIntClear(port, bits);
|
||||
|
||||
// might be that we have more than one Pin interrupt pending
|
||||
// might be that we have more than one pin interrupt pending
|
||||
// therefore we must loop through all of the 8 possible bits
|
||||
for (int i = 0; i < 8; i++) {
|
||||
uint32_t bit = (1 << i);
|
||||
if (bit & bits) {
|
||||
pin_obj_t *self = (pin_obj_t *)pin_find_pin_by_port_bit(&pin_board_pins_locals_dict, port, bit);
|
||||
mp_obj_t _callback = mpcallback_find(self);
|
||||
mpcallback_handler(_callback);
|
||||
if (self->irq_trigger == (PYB_PIN_FALLING_EDGE | PYB_PIN_RISING_EDGE)) {
|
||||
// read the pin value (hoping that the pin level has remained stable)
|
||||
self->irq_flags = MAP_GPIOPinRead(self->port, self->bit) ? PYB_PIN_RISING_EDGE : PYB_PIN_FALLING_EDGE;
|
||||
} else {
|
||||
// same as the triggers
|
||||
self->irq_flags = self->irq_trigger;
|
||||
}
|
||||
mp_irq_handler(mp_irq_find(self));
|
||||
// always clear the flags after leaving the user handler
|
||||
self->irq_flags = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -484,7 +502,7 @@ STATIC void EXTI_Handler(uint port) {
|
||||
// Micro Python bindings
|
||||
|
||||
STATIC const mp_arg_t pin_init_args[] = {
|
||||
{ MP_QSTR_mode, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_mode, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
|
||||
{ MP_QSTR_pull, MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||
{ MP_QSTR_value, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
|
||||
{ MP_QSTR_drive, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = PIN_STRENGTH_4MA} },
|
||||
@@ -498,8 +516,14 @@ STATIC mp_obj_t pin_obj_init_helper(pin_obj_t *self, mp_uint_t n_args, const mp_
|
||||
mp_arg_parse_all(n_args, pos_args, kw_args, pin_INIT_NUM_ARGS, pin_init_args, args);
|
||||
|
||||
// get the io mode
|
||||
uint mode = args[0].u_int;
|
||||
pin_validate_mode(mode);
|
||||
uint mode;
|
||||
// default is input
|
||||
if (args[0].u_obj == MP_OBJ_NULL) {
|
||||
mode = GPIO_DIR_MODE_IN;
|
||||
} else {
|
||||
mode = mp_obj_get_int(args[0].u_obj);
|
||||
pin_validate_mode (mode);
|
||||
}
|
||||
|
||||
// get the pull type
|
||||
uint pull;
|
||||
@@ -609,12 +633,9 @@ STATIC mp_obj_t pin_make_new(mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw,
|
||||
// Run an argument through the mapper and return the result.
|
||||
pin_obj_t *pin = (pin_obj_t *)pin_find(args[0]);
|
||||
|
||||
if (n_args > 1 || n_kw > 0) {
|
||||
// pin af given, so configure it
|
||||
mp_map_t kw_args;
|
||||
mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
|
||||
pin_obj_init_helper(pin, n_args - 1, args + 1, &kw_args);
|
||||
}
|
||||
mp_map_t kw_args;
|
||||
mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
|
||||
pin_obj_init_helper(pin, n_args - 1, args + 1, &kw_args);
|
||||
|
||||
return (mp_obj_t)pin;
|
||||
}
|
||||
@@ -726,136 +747,147 @@ STATIC mp_obj_t pin_alt_list(mp_obj_t self_in) {
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_alt_list_obj, pin_alt_list);
|
||||
|
||||
STATIC mp_obj_t pin_callback (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
mp_arg_val_t args[mpcallback_INIT_NUM_ARGS];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, mpcallback_INIT_NUM_ARGS, mpcallback_init_args, args);
|
||||
|
||||
/// \method irq(trigger, priority, handler, wake)
|
||||
STATIC mp_obj_t pin_irq (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
mp_arg_val_t args[mp_irq_INIT_NUM_ARGS];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, mp_irq_INIT_NUM_ARGS, mp_irq_init_args, args);
|
||||
pin_obj_t *self = pos_args[0];
|
||||
// check if any parameters were passed
|
||||
mp_obj_t _callback = mpcallback_find(self);
|
||||
if (kw_args->used > 0) {
|
||||
// convert the priority to the correct value
|
||||
uint priority = mpcallback_translate_priority (args[2].u_int);
|
||||
// verify the interrupt mode
|
||||
uint intmode = args[0].u_int;
|
||||
if (intmode == (GPIO_FALLING_EDGE | GPIO_RISING_EDGE)) {
|
||||
intmode = GPIO_BOTH_EDGES;
|
||||
}
|
||||
else if (intmode != GPIO_FALLING_EDGE && intmode != GPIO_RISING_EDGE &&
|
||||
intmode != GPIO_LOW_LEVEL && intmode != GPIO_HIGH_LEVEL) {
|
||||
|
||||
// convert the priority to the correct value
|
||||
uint priority = mp_irq_translate_priority (args[1].u_int);
|
||||
|
||||
// verify and translate the interrupt mode
|
||||
uint mp_trigger = mp_obj_get_int(args[0].u_obj);
|
||||
uint trigger;
|
||||
if (mp_trigger == (PYB_PIN_FALLING_EDGE | PYB_PIN_RISING_EDGE)) {
|
||||
trigger = GPIO_BOTH_EDGES;
|
||||
} else {
|
||||
switch (mp_trigger) {
|
||||
case PYB_PIN_FALLING_EDGE:
|
||||
trigger = GPIO_FALLING_EDGE;
|
||||
break;
|
||||
case PYB_PIN_RISING_EDGE:
|
||||
trigger = GPIO_RISING_EDGE;
|
||||
break;
|
||||
case PYB_PIN_LOW_LEVEL:
|
||||
trigger = GPIO_LOW_LEVEL;
|
||||
break;
|
||||
case PYB_PIN_HIGH_LEVEL:
|
||||
trigger = GPIO_HIGH_LEVEL;
|
||||
break;
|
||||
default:
|
||||
goto invalid_args;
|
||||
}
|
||||
|
||||
uint pwrmode = args[4].u_int;
|
||||
if (pwrmode > (PYB_PWR_MODE_ACTIVE | PYB_PWR_MODE_LPDS | PYB_PWR_MODE_HIBERNATE)) {
|
||||
goto invalid_args;
|
||||
}
|
||||
|
||||
// get the wake info from this pin
|
||||
uint hib_pin, idx;
|
||||
pin_get_hibernate_pin_and_idx ((const pin_obj_t *)self, &hib_pin, &idx);
|
||||
if (pwrmode & PYB_PWR_MODE_LPDS) {
|
||||
if (idx >= PYBPIN_NUM_WAKE_PINS) {
|
||||
goto invalid_args;
|
||||
}
|
||||
// wake modes are different in LDPS
|
||||
uint wake_mode;
|
||||
switch (intmode) {
|
||||
case GPIO_FALLING_EDGE:
|
||||
wake_mode = PRCM_LPDS_FALL_EDGE;
|
||||
break;
|
||||
case GPIO_RISING_EDGE:
|
||||
wake_mode = PRCM_LPDS_RISE_EDGE;
|
||||
break;
|
||||
case GPIO_LOW_LEVEL:
|
||||
wake_mode = PRCM_LPDS_LOW_LEVEL;
|
||||
break;
|
||||
case GPIO_HIGH_LEVEL:
|
||||
wake_mode = PRCM_LPDS_HIGH_LEVEL;
|
||||
break;
|
||||
default:
|
||||
goto invalid_args;
|
||||
break;
|
||||
}
|
||||
|
||||
// first clear the lpds value from all wake-able pins
|
||||
for (uint i = 0; i < PYBPIN_NUM_WAKE_PINS; i++) {
|
||||
pybpin_wake_pin[i].lpds = PYBPIN_WAKES_NOT;
|
||||
}
|
||||
|
||||
// enable this pin as a wake-up source during LPDS
|
||||
pybpin_wake_pin[idx].lpds = wake_mode;
|
||||
}
|
||||
else {
|
||||
// this pin was the previous LPDS wake source, so disable it completely
|
||||
if (pybpin_wake_pin[idx].lpds != PYBPIN_WAKES_NOT) {
|
||||
MAP_PRCMLPDSWakeupSourceDisable(PRCM_LPDS_GPIO);
|
||||
}
|
||||
pybpin_wake_pin[idx].lpds = PYBPIN_WAKES_NOT;
|
||||
}
|
||||
|
||||
if (pwrmode & PYB_PWR_MODE_HIBERNATE) {
|
||||
if (idx >= PYBPIN_NUM_WAKE_PINS) {
|
||||
goto invalid_args;
|
||||
}
|
||||
// wake modes are different in hibernate
|
||||
uint wake_mode;
|
||||
switch (intmode) {
|
||||
case GPIO_FALLING_EDGE:
|
||||
wake_mode = PRCM_HIB_FALL_EDGE;
|
||||
break;
|
||||
case GPIO_RISING_EDGE:
|
||||
wake_mode = PRCM_HIB_RISE_EDGE;
|
||||
break;
|
||||
case GPIO_LOW_LEVEL:
|
||||
wake_mode = PRCM_HIB_LOW_LEVEL;
|
||||
break;
|
||||
case GPIO_HIGH_LEVEL:
|
||||
wake_mode = PRCM_HIB_HIGH_LEVEL;
|
||||
break;
|
||||
default:
|
||||
goto invalid_args;
|
||||
break;
|
||||
}
|
||||
|
||||
// enable this pin as wake-up source during hibernate
|
||||
pybpin_wake_pin[idx].hib = wake_mode;
|
||||
}
|
||||
else {
|
||||
pybpin_wake_pin[idx].hib = PYBPIN_WAKES_NOT;
|
||||
}
|
||||
|
||||
// we need to update the callback atomically, so we disable the
|
||||
// interrupt before we update anything.
|
||||
pin_extint_disable(self);
|
||||
if (pwrmode & PYB_PWR_MODE_ACTIVE) {
|
||||
// register the interrupt
|
||||
pin_extint_register((pin_obj_t *)self, intmode, priority);
|
||||
if (idx < PYBPIN_NUM_WAKE_PINS) {
|
||||
pybpin_wake_pin[idx].active = true;
|
||||
}
|
||||
}
|
||||
else if (idx < PYBPIN_NUM_WAKE_PINS) {
|
||||
pybpin_wake_pin[idx].active = false;
|
||||
}
|
||||
|
||||
// all checks have passed, now we can create the callback
|
||||
_callback = mpcallback_new (self, args[1].u_obj, &pin_cb_methods, true);
|
||||
if (pwrmode & PYB_PWR_MODE_LPDS) {
|
||||
pybsleep_set_gpio_lpds_callback (_callback);
|
||||
}
|
||||
|
||||
// enable the interrupt just before leaving
|
||||
pin_extint_enable(self);
|
||||
} else if (!_callback) {
|
||||
_callback = mpcallback_new (self, mp_const_none, &pin_cb_methods, false);
|
||||
}
|
||||
return _callback;
|
||||
|
||||
uint8_t pwrmode = (args[3].u_obj == mp_const_none) ? PYB_PWR_MODE_ACTIVE : mp_obj_get_int(args[3].u_obj);
|
||||
if (pwrmode > (PYB_PWR_MODE_ACTIVE | PYB_PWR_MODE_LPDS | PYB_PWR_MODE_HIBERNATE)) {
|
||||
goto invalid_args;
|
||||
}
|
||||
|
||||
// get the wake info from this pin
|
||||
uint hib_pin, idx;
|
||||
pin_get_hibernate_pin_and_idx ((const pin_obj_t *)self, &hib_pin, &idx);
|
||||
if (pwrmode & PYB_PWR_MODE_LPDS) {
|
||||
if (idx >= PYBPIN_NUM_WAKE_PINS) {
|
||||
goto invalid_args;
|
||||
}
|
||||
// wake modes are different in LDPS
|
||||
uint wake_mode;
|
||||
switch (trigger) {
|
||||
case GPIO_FALLING_EDGE:
|
||||
wake_mode = PRCM_LPDS_FALL_EDGE;
|
||||
break;
|
||||
case GPIO_RISING_EDGE:
|
||||
wake_mode = PRCM_LPDS_RISE_EDGE;
|
||||
break;
|
||||
case GPIO_LOW_LEVEL:
|
||||
wake_mode = PRCM_LPDS_LOW_LEVEL;
|
||||
break;
|
||||
case GPIO_HIGH_LEVEL:
|
||||
wake_mode = PRCM_LPDS_HIGH_LEVEL;
|
||||
break;
|
||||
default:
|
||||
goto invalid_args;
|
||||
break;
|
||||
}
|
||||
|
||||
// first clear the lpds value from all wake-able pins
|
||||
for (uint i = 0; i < PYBPIN_NUM_WAKE_PINS; i++) {
|
||||
pybpin_wake_pin[i].lpds = PYBPIN_WAKES_NOT;
|
||||
}
|
||||
|
||||
// enable this pin as a wake-up source during LPDS
|
||||
pybpin_wake_pin[idx].lpds = wake_mode;
|
||||
} else if (idx < PYBPIN_NUM_WAKE_PINS) {
|
||||
// this pin was the previous LPDS wake source, so disable it completely
|
||||
if (pybpin_wake_pin[idx].lpds != PYBPIN_WAKES_NOT) {
|
||||
MAP_PRCMLPDSWakeupSourceDisable(PRCM_LPDS_GPIO);
|
||||
}
|
||||
pybpin_wake_pin[idx].lpds = PYBPIN_WAKES_NOT;
|
||||
}
|
||||
|
||||
if (pwrmode & PYB_PWR_MODE_HIBERNATE) {
|
||||
if (idx >= PYBPIN_NUM_WAKE_PINS) {
|
||||
goto invalid_args;
|
||||
}
|
||||
// wake modes are different in hibernate
|
||||
uint wake_mode;
|
||||
switch (trigger) {
|
||||
case GPIO_FALLING_EDGE:
|
||||
wake_mode = PRCM_HIB_FALL_EDGE;
|
||||
break;
|
||||
case GPIO_RISING_EDGE:
|
||||
wake_mode = PRCM_HIB_RISE_EDGE;
|
||||
break;
|
||||
case GPIO_LOW_LEVEL:
|
||||
wake_mode = PRCM_HIB_LOW_LEVEL;
|
||||
break;
|
||||
case GPIO_HIGH_LEVEL:
|
||||
wake_mode = PRCM_HIB_HIGH_LEVEL;
|
||||
break;
|
||||
default:
|
||||
goto invalid_args;
|
||||
break;
|
||||
}
|
||||
|
||||
// enable this pin as wake-up source during hibernate
|
||||
pybpin_wake_pin[idx].hib = wake_mode;
|
||||
} else if (idx < PYBPIN_NUM_WAKE_PINS) {
|
||||
pybpin_wake_pin[idx].hib = PYBPIN_WAKES_NOT;
|
||||
}
|
||||
|
||||
// we need to update the callback atomically, so we disable the
|
||||
// interrupt before we update anything.
|
||||
pin_irq_disable(self);
|
||||
if (pwrmode & PYB_PWR_MODE_ACTIVE) {
|
||||
// register the interrupt
|
||||
pin_extint_register((pin_obj_t *)self, trigger, priority);
|
||||
if (idx < PYBPIN_NUM_WAKE_PINS) {
|
||||
pybpin_wake_pin[idx].active = true;
|
||||
}
|
||||
} else if (idx < PYBPIN_NUM_WAKE_PINS) {
|
||||
pybpin_wake_pin[idx].active = false;
|
||||
}
|
||||
|
||||
// all checks have passed, we can create the irq object
|
||||
mp_obj_t _irq = mp_irq_new (self, args[2].u_obj, &pin_irq_methods);
|
||||
if (pwrmode & PYB_PWR_MODE_LPDS) {
|
||||
pyb_sleep_set_gpio_lpds_callback (_irq);
|
||||
}
|
||||
|
||||
// save the mp_trigge for later
|
||||
self->irq_trigger = mp_trigger;
|
||||
|
||||
// enable the interrupt just before leaving
|
||||
pin_irq_enable(self);
|
||||
|
||||
return _irq;
|
||||
|
||||
invalid_args:
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pin_callback_obj, 1, pin_callback);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pin_irq_obj, 1, pin_irq);
|
||||
|
||||
STATIC const mp_map_elem_t pin_locals_dict_table[] = {
|
||||
// instance methods
|
||||
@@ -867,7 +899,7 @@ STATIC const mp_map_elem_t pin_locals_dict_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_pull), (mp_obj_t)&pin_pull_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_drive), (mp_obj_t)&pin_drive_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_alt_list), (mp_obj_t)&pin_alt_list_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_callback), (mp_obj_t)&pin_callback_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_irq), (mp_obj_t)&pin_irq_obj },
|
||||
|
||||
// class attributes
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_board), (mp_obj_t)&pin_board_pins_obj_type },
|
||||
@@ -883,10 +915,10 @@ STATIC const mp_map_elem_t pin_locals_dict_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_LOW_POWER), MP_OBJ_NEW_SMALL_INT(PIN_STRENGTH_2MA) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_MED_POWER), MP_OBJ_NEW_SMALL_INT(PIN_STRENGTH_4MA) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_HIGH_POWER), MP_OBJ_NEW_SMALL_INT(PIN_STRENGTH_6MA) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_IRQ_FALLING), MP_OBJ_NEW_SMALL_INT(GPIO_FALLING_EDGE) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_IRQ_RISING), MP_OBJ_NEW_SMALL_INT(GPIO_RISING_EDGE) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_IRQ_LOW_LEVEL), MP_OBJ_NEW_SMALL_INT(GPIO_LOW_LEVEL) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_IRQ_HIGH_LEVEL), MP_OBJ_NEW_SMALL_INT(GPIO_HIGH_LEVEL) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_IRQ_FALLING), MP_OBJ_NEW_SMALL_INT(PYB_PIN_FALLING_EDGE) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_IRQ_RISING), MP_OBJ_NEW_SMALL_INT(PYB_PIN_RISING_EDGE) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_IRQ_LOW_LEVEL), MP_OBJ_NEW_SMALL_INT(PYB_PIN_LOW_LEVEL) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_IRQ_HIGH_LEVEL), MP_OBJ_NEW_SMALL_INT(PYB_PIN_HIGH_LEVEL) },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(pin_locals_dict, pin_locals_dict_table);
|
||||
@@ -900,10 +932,11 @@ const mp_obj_type_t pin_type = {
|
||||
.locals_dict = (mp_obj_t)&pin_locals_dict,
|
||||
};
|
||||
|
||||
STATIC const mp_cb_methods_t pin_cb_methods = {
|
||||
.init = pin_callback,
|
||||
.enable = pin_extint_enable,
|
||||
.disable = pin_extint_disable,
|
||||
STATIC const mp_irq_methods_t pin_irq_methods = {
|
||||
.init = pin_irq,
|
||||
.enable = pin_irq_enable,
|
||||
.disable = pin_irq_disable,
|
||||
.flags = pin_irq_flags,
|
||||
};
|
||||
|
||||
STATIC void pin_named_pins_obj_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
|
||||
@@ -110,9 +110,11 @@ typedef struct {
|
||||
int8_t af;
|
||||
uint8_t strength;
|
||||
uint8_t mode; // this is now a combination of type and mode
|
||||
uint8_t num_afs: 6; // up to 63 AFs
|
||||
uint8_t value : 1;
|
||||
uint8_t used : 1;
|
||||
const uint8_t num_afs; // 255 AFs
|
||||
uint8_t value;
|
||||
uint8_t used;
|
||||
uint8_t irq_trigger;
|
||||
uint8_t irq_flags;
|
||||
} pin_obj_t;
|
||||
|
||||
extern const mp_obj_type_t pin_type;
|
||||
|
||||
@@ -37,8 +37,8 @@
|
||||
#include "rom_map.h"
|
||||
#include "prcm.h"
|
||||
#include "pybrtc.h"
|
||||
#include "mpirq.h"
|
||||
#include "pybsleep.h"
|
||||
#include "mpcallback.h"
|
||||
#include "timeutils.h"
|
||||
#include "simplelink.h"
|
||||
#include "modnetwork.h"
|
||||
@@ -48,88 +48,148 @@
|
||||
/// \moduleref pyb
|
||||
/// \class RTC - real time clock
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE TYPES
|
||||
******************************************************************************/
|
||||
typedef struct _pyb_rtc_obj_t {
|
||||
mp_obj_base_t base;
|
||||
byte prwmode;
|
||||
bool alarmset;
|
||||
bool repeat;
|
||||
} pyb_rtc_obj_t;
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE DATA
|
||||
******************************************************************************/
|
||||
STATIC const mp_cb_methods_t pybrtc_cb_methods;
|
||||
STATIC pyb_rtc_obj_t pyb_rtc_obj = {.prwmode = 0, .alarmset = false, .repeat = false};
|
||||
STATIC const mp_irq_methods_t pyb_rtc_irq_methods;
|
||||
STATIC pyb_rtc_obj_t pyb_rtc_obj;
|
||||
|
||||
/******************************************************************************
|
||||
FUNCTION-LIKE MACROS
|
||||
******************************************************************************/
|
||||
#define RTC_U16MS_CYCLES(msec) ((msec * 1024) / 1000)
|
||||
#define RTC_CYCLES_U16MS(cycles) ((cycles * 1000) / 1024)
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE FUNCTIONS
|
||||
******************************************************************************/
|
||||
STATIC uint32_t pyb_rtc_reset (mp_obj_t self_in);
|
||||
STATIC void pyb_rtc_callback_enable (mp_obj_t self_in);
|
||||
STATIC void pyb_rtc_callback_disable (mp_obj_t self_in);
|
||||
STATIC void pyb_rtc_set_time (uint32_t secs, uint16_t msecs);
|
||||
STATIC uint32_t pyb_rtc_reset (void);
|
||||
STATIC void pyb_rtc_disable_interupt (void);
|
||||
STATIC void pyb_rtc_irq_enable (mp_obj_t self_in);
|
||||
STATIC void pyb_rtc_irq_disable (mp_obj_t self_in);
|
||||
STATIC int pyb_rtc_irq_flags (mp_obj_t self_in);
|
||||
STATIC uint pyb_rtc_datetime_s_us(const mp_obj_t datetime, uint32_t *seconds);
|
||||
STATIC mp_obj_t pyb_rtc_datetime(mp_obj_t self, const mp_obj_t datetime);
|
||||
STATIC void pyb_rtc_set_alarm (pyb_rtc_obj_t *self, uint32_t seconds, uint16_t mseconds);
|
||||
STATIC void rtc_msec_add(uint16_t msecs_1, uint32_t *secs, uint16_t *msecs_2);
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PUBLIC FUNCTIONS
|
||||
******************************************************************************/
|
||||
__attribute__ ((section (".boot")))
|
||||
void pyb_rtc_pre_init(void) {
|
||||
// if the RTC was previously set, leave it alone
|
||||
// only if comming out of a power-on reset
|
||||
if (MAP_PRCMSysResetCauseGet() == PRCM_POWER_ON) {
|
||||
// Mark the RTC in use first
|
||||
MAP_PRCMRTCInUseSet();
|
||||
// reset the time and date
|
||||
pyb_rtc_reset((mp_obj_t)&pyb_rtc_obj);
|
||||
pyb_rtc_reset();
|
||||
}
|
||||
}
|
||||
|
||||
void pyb_rtc_get_time (uint32_t *secs, uint16_t *msecs) {
|
||||
uint16_t cycles;
|
||||
MAP_PRCMRTCGet (secs, &cycles);
|
||||
*msecs = RTC_CYCLES_U16MS(cycles);
|
||||
}
|
||||
|
||||
uint32_t pyb_rtc_get_seconds (void) {
|
||||
uint32_t seconds;
|
||||
uint16_t mseconds;
|
||||
MAP_PRCMRTCGet(&seconds, &mseconds);
|
||||
pyb_rtc_get_time(&seconds, &mseconds);
|
||||
return seconds;
|
||||
}
|
||||
|
||||
void pyb_rtc_calc_future_time (uint32_t a_mseconds, uint32_t *f_seconds, uint16_t *f_mseconds) {
|
||||
uint32_t c_seconds;
|
||||
uint16_t c_mseconds;
|
||||
// get the current time
|
||||
pyb_rtc_get_time(&c_seconds, &c_mseconds);
|
||||
// calculate the future seconds
|
||||
*f_seconds = c_seconds + (a_mseconds / 1000);
|
||||
// calculate the "remaining" future mseconds
|
||||
*f_mseconds = a_mseconds % 1000;
|
||||
// add the current milliseconds
|
||||
rtc_msec_add (c_mseconds, f_seconds, f_mseconds);
|
||||
}
|
||||
|
||||
void pyb_rtc_repeat_alarm (pyb_rtc_obj_t *self) {
|
||||
if (self->repeat) {
|
||||
uint32_t f_seconds, c_seconds;
|
||||
uint16_t f_mseconds, c_mseconds;
|
||||
|
||||
pyb_rtc_get_time(&c_seconds, &c_mseconds);
|
||||
|
||||
// substract the time elapsed between waking up and setting up the alarm again
|
||||
int32_t wake_ms = ((c_seconds * 1000) + c_mseconds) - ((self->alarm_time_s * 1000) + self->alarm_time_ms);
|
||||
int32_t next_alarm = self->alarm_ms - wake_ms;
|
||||
next_alarm = next_alarm > 0 ? next_alarm : PYB_RTC_MIN_ALARM_TIME_MS;
|
||||
pyb_rtc_calc_future_time (next_alarm, &f_seconds, &f_mseconds);
|
||||
|
||||
// now configure the alarm
|
||||
pyb_rtc_set_alarm (self, f_seconds, f_mseconds);
|
||||
}
|
||||
}
|
||||
|
||||
void pyb_rtc_disable_alarm (void) {
|
||||
pyb_rtc_obj.alarmset = false;
|
||||
pyb_rtc_disable_interupt();
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE FUNCTIONS
|
||||
******************************************************************************/
|
||||
STATIC uint32_t pyb_rtc_reset (mp_obj_t self_in) {
|
||||
STATIC void pyb_rtc_set_time (uint32_t secs, uint16_t msecs) {
|
||||
// add the RTC access time
|
||||
rtc_msec_add(RTC_ACCESS_TIME_MSEC, &secs, &msecs);
|
||||
// convert from mseconds to cycles
|
||||
msecs = RTC_U16MS_CYCLES(msecs);
|
||||
// now set the time
|
||||
MAP_PRCMRTCSet(secs, msecs);
|
||||
}
|
||||
|
||||
STATIC uint32_t pyb_rtc_reset (void) {
|
||||
// fresh reset; configure the RTC Calendar
|
||||
// set the date to 1st Jan 2015
|
||||
// set the time to 00:00:00
|
||||
uint32_t seconds = timeutils_seconds_since_2000(2015, 1, 1, 0, 0, 0);
|
||||
// Now set the RTC calendar seconds
|
||||
MAP_PRCMRTCSet(seconds, 0);
|
||||
// disable any running alarm
|
||||
pyb_rtc_disable_alarm();
|
||||
// Now set the RTC calendar time
|
||||
pyb_rtc_set_time(seconds, 0);
|
||||
return seconds;
|
||||
}
|
||||
|
||||
STATIC void pyb_rtc_callback_enable (mp_obj_t self_in) {
|
||||
pyb_rtc_obj_t *self = self_in;
|
||||
// check the wake from param
|
||||
if (self->prwmode & PYB_PWR_MODE_ACTIVE) {
|
||||
// enable the slow clock interrupt
|
||||
MAP_PRCMIntEnable(PRCM_INT_SLOW_CLK_CTR);
|
||||
} else {
|
||||
// just in case it was already enabled before
|
||||
MAP_PRCMIntDisable(PRCM_INT_SLOW_CLK_CTR);
|
||||
}
|
||||
pybsleep_configure_timer_wakeup (self->prwmode);
|
||||
STATIC void pyb_rtc_disable_interupt (void) {
|
||||
uint primsk = disable_irq();
|
||||
MAP_PRCMIntDisable(PRCM_INT_SLOW_CLK_CTR);
|
||||
(void)MAP_PRCMIntStatus();
|
||||
enable_irq(primsk);
|
||||
}
|
||||
|
||||
STATIC void pyb_rtc_callback_disable (mp_obj_t self_in) {
|
||||
STATIC void pyb_rtc_irq_enable (mp_obj_t self_in) {
|
||||
pyb_rtc_obj_t *self = self_in;
|
||||
// check the wake from param
|
||||
if (self->prwmode & PYB_PWR_MODE_ACTIVE) {
|
||||
// disable the slow clock interrupt
|
||||
// we always need interrupts if repeat is enabled
|
||||
if ((self->pwrmode & PYB_PWR_MODE_ACTIVE) || self->repeat) {
|
||||
MAP_PRCMIntEnable(PRCM_INT_SLOW_CLK_CTR);
|
||||
} else { // just in case it was already enabled before
|
||||
MAP_PRCMIntDisable(PRCM_INT_SLOW_CLK_CTR);
|
||||
}
|
||||
// disable wake from ldps and hibernate
|
||||
pybsleep_configure_timer_wakeup (PYB_PWR_MODE_ACTIVE);
|
||||
// read the interrupt status to clear any pending interrupt
|
||||
(void)MAP_PRCMIntStatus();
|
||||
self->irq_enabled = true;
|
||||
}
|
||||
|
||||
STATIC void pyb_rtc_irq_disable (mp_obj_t self_in) {
|
||||
pyb_rtc_obj_t *self = self_in;
|
||||
self->irq_enabled = false;
|
||||
if (!self->repeat) { // we always need interrupts if repeat is enabled
|
||||
pyb_rtc_disable_interupt();
|
||||
}
|
||||
}
|
||||
|
||||
STATIC int pyb_rtc_irq_flags (mp_obj_t self_in) {
|
||||
pyb_rtc_obj_t *self = self_in;
|
||||
return self->irq_flags;
|
||||
}
|
||||
|
||||
STATIC uint pyb_rtc_datetime_s_us(const mp_obj_t datetime, uint32_t *seconds) {
|
||||
@@ -177,15 +237,15 @@ STATIC uint pyb_rtc_datetime_s_us(const mp_obj_t datetime, uint32_t *seconds) {
|
||||
///
|
||||
/// (year, month, day, hours, minutes, seconds, milliseconds, tzinfo=None)
|
||||
///
|
||||
STATIC mp_obj_t pyb_rtc_datetime(mp_obj_t self, const mp_obj_t datetime) {
|
||||
STATIC mp_obj_t pyb_rtc_datetime(mp_obj_t self_in, const mp_obj_t datetime) {
|
||||
uint32_t seconds;
|
||||
uint32_t useconds;
|
||||
|
||||
if (datetime != MP_OBJ_NULL) {
|
||||
useconds = pyb_rtc_datetime_s_us(datetime, &seconds);
|
||||
MAP_PRCMRTCSet(seconds, RTC_U16MS_CYCLES(useconds / 1000));
|
||||
pyb_rtc_set_time (seconds, useconds / 1000);
|
||||
} else {
|
||||
seconds = pyb_rtc_reset(self);
|
||||
seconds = pyb_rtc_reset();
|
||||
}
|
||||
|
||||
// set WLAN time and date, this is needed to verify certificates
|
||||
@@ -193,6 +253,32 @@ STATIC mp_obj_t pyb_rtc_datetime(mp_obj_t self, const mp_obj_t datetime) {
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
STATIC void pyb_rtc_set_alarm (pyb_rtc_obj_t *self, uint32_t seconds, uint16_t mseconds) {
|
||||
// disable the interrupt before updating anything
|
||||
if (self->irq_enabled) {
|
||||
MAP_PRCMIntDisable(PRCM_INT_SLOW_CLK_CTR);
|
||||
}
|
||||
// set the match value
|
||||
MAP_PRCMRTCMatchSet(seconds, RTC_U16MS_CYCLES(mseconds));
|
||||
self->alarmset = true;
|
||||
self->alarm_time_s = seconds;
|
||||
self->alarm_time_ms = mseconds;
|
||||
// enabled the interrupts again if applicable
|
||||
if (self->irq_enabled || self->repeat) {
|
||||
MAP_PRCMIntEnable(PRCM_INT_SLOW_CLK_CTR);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void rtc_msec_add (uint16_t msecs_1, uint32_t *secs, uint16_t *msecs_2) {
|
||||
if (msecs_1 + *msecs_2 >= 1000) { // larger than one second
|
||||
*msecs_2 = (msecs_1 + *msecs_2) - 1000;
|
||||
*secs += 1; // carry flag
|
||||
} else {
|
||||
// simply add the mseconds
|
||||
*msecs_2 = msecs_1 + *msecs_2;
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
// Micro Python bindings
|
||||
|
||||
@@ -219,6 +305,9 @@ STATIC mp_obj_t pyb_rtc_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n
|
||||
// set the time and date
|
||||
pyb_rtc_datetime((mp_obj_t)&pyb_rtc_obj, args[1].u_obj);
|
||||
|
||||
// pass it to the sleep module
|
||||
pyb_sleep_set_rtc_obj (self);
|
||||
|
||||
// return constant object
|
||||
return (mp_obj_t)&pyb_rtc_obj;
|
||||
}
|
||||
@@ -236,9 +325,8 @@ STATIC mp_obj_t pyb_rtc_now (mp_obj_t self_in) {
|
||||
uint32_t seconds;
|
||||
uint16_t mseconds;
|
||||
|
||||
// get the seconds and the milliseconds from the RTC
|
||||
MAP_PRCMRTCGet(&seconds, &mseconds);
|
||||
mseconds = RTC_CYCLES_U16MS(mseconds);
|
||||
// get the time from the RTC
|
||||
pyb_rtc_get_time(&seconds, &mseconds);
|
||||
timeutils_seconds_since_2000_to_struct_time(seconds, &tm);
|
||||
|
||||
mp_obj_t tuple[8] = {
|
||||
@@ -256,7 +344,7 @@ STATIC mp_obj_t pyb_rtc_now (mp_obj_t self_in) {
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_rtc_now_obj, pyb_rtc_now);
|
||||
|
||||
STATIC mp_obj_t pyb_rtc_deinit (mp_obj_t self_in) {
|
||||
pyb_rtc_reset (self_in);
|
||||
pyb_rtc_reset();
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_rtc_deinit_obj, pyb_rtc_deinit);
|
||||
@@ -264,7 +352,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_rtc_deinit_obj, pyb_rtc_deinit);
|
||||
STATIC mp_obj_t pyb_rtc_alarm (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
STATIC const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_id, MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_time, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
|
||||
{ MP_QSTR_time, MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||
{ MP_QSTR_repeat, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
|
||||
};
|
||||
|
||||
@@ -278,114 +366,97 @@ STATIC mp_obj_t pyb_rtc_alarm (mp_uint_t n_args, const mp_obj_t *pos_args, mp_ma
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable));
|
||||
}
|
||||
|
||||
uint32_t a_seconds;
|
||||
uint16_t a_mseconds;
|
||||
uint32_t f_seconds;
|
||||
uint16_t f_mseconds;
|
||||
bool repeat = args[2].u_bool;
|
||||
if (MP_OBJ_IS_TYPE(args[1].u_obj, &mp_type_tuple)) { // datetime tuple given
|
||||
a_mseconds = pyb_rtc_datetime_s_us (args[1].u_obj, &a_seconds) / 1000;
|
||||
} else { // then it must be an integer or MP_OBJ_NULL
|
||||
uint32_t c_seconds;
|
||||
uint16_t c_mseconds;
|
||||
if (MP_OBJ_IS_INT(args[1].u_obj)) {
|
||||
a_seconds = 0, a_mseconds = mp_obj_get_int(args[1].u_obj);
|
||||
} else {
|
||||
a_seconds = 1, a_mseconds = 0;
|
||||
// repeat cannot be used with a datetime tuple
|
||||
if (repeat) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
|
||||
}
|
||||
// get the seconds and the milliseconds from the RTC
|
||||
MAP_PRCMRTCGet(&c_seconds, &c_mseconds);
|
||||
a_mseconds += RTC_CYCLES_U16MS(c_mseconds);
|
||||
// calculate the future time
|
||||
a_seconds += c_seconds + (a_mseconds / 1000);
|
||||
a_mseconds -= ((a_mseconds / 1000) * 1000);
|
||||
f_mseconds = pyb_rtc_datetime_s_us (args[1].u_obj, &f_seconds) / 1000;
|
||||
} else { // then it must be an integer
|
||||
self->alarm_ms = mp_obj_get_int(args[1].u_obj);
|
||||
pyb_rtc_calc_future_time (self->alarm_ms, &f_seconds, &f_mseconds);
|
||||
}
|
||||
|
||||
// disable the interrupt before updating anything
|
||||
pyb_rtc_callback_disable((mp_obj_t)self);
|
||||
// store the repepat flag
|
||||
self->repeat = repeat;
|
||||
|
||||
// set the match value
|
||||
MAP_PRCMRTCMatchSet(a_seconds, a_mseconds);
|
||||
|
||||
// enabled it again (according to the power mode)
|
||||
pyb_rtc_callback_enable((mp_obj_t)self);
|
||||
|
||||
// set the alarmset flag and store the repeat one
|
||||
self->alarmset = true;
|
||||
self->repeat = args[2].u_bool;
|
||||
// now configure the alarm
|
||||
pyb_rtc_set_alarm (self, f_seconds, f_mseconds);
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_rtc_alarm_obj, 1, pyb_rtc_alarm);
|
||||
|
||||
STATIC mp_obj_t pyb_rtc_alarm_left (mp_obj_t self_in) {
|
||||
pyb_rtc_obj_t *self = self_in;
|
||||
uint32_t a_seconds, c_seconds;
|
||||
uint16_t a_mseconds, c_mseconds;
|
||||
STATIC mp_obj_t pyb_rtc_alarm_left (mp_uint_t n_args, const mp_obj_t *args) {
|
||||
pyb_rtc_obj_t *self = args[0];
|
||||
int32_t ms_left;
|
||||
uint32_t c_seconds;
|
||||
uint16_t c_mseconds;
|
||||
|
||||
// only alarm id 0 is available
|
||||
if (n_args > 1 && mp_obj_get_int(args[1]) != 0) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable));
|
||||
}
|
||||
|
||||
// get the alarm time
|
||||
MAP_PRCMRTCMatchGet(&a_seconds, &a_mseconds);
|
||||
a_mseconds = RTC_CYCLES_U16MS(a_mseconds);
|
||||
// get the current time
|
||||
MAP_PRCMRTCGet(&c_seconds, &c_mseconds);
|
||||
c_mseconds = RTC_CYCLES_U16MS(c_mseconds);
|
||||
pyb_rtc_get_time(&c_seconds, &c_mseconds);
|
||||
|
||||
// calculate the ms left
|
||||
ms_left = ((a_seconds * 1000) + a_mseconds) - ((c_seconds * 1000) + c_mseconds);
|
||||
ms_left = ((self->alarm_time_s * 1000) + self->alarm_time_ms) - ((c_seconds * 1000) + c_mseconds);
|
||||
if (!self->alarmset || ms_left < 0) {
|
||||
ms_left = 0;
|
||||
}
|
||||
return mp_obj_new_int(ms_left);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_rtc_alarm_left_obj, pyb_rtc_alarm_left);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_rtc_alarm_left_obj, 1, 2, pyb_rtc_alarm_left);
|
||||
|
||||
/// \method callback(handler, value, pwrmode)
|
||||
/// Creates a callback object associated with the real time clock
|
||||
/// min num of arguments is 1 (value). The value is the alarm time
|
||||
/// in the future, in msec
|
||||
/// FIXME
|
||||
STATIC mp_obj_t pyb_rtc_callback (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
mp_arg_val_t args[mpcallback_INIT_NUM_ARGS];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, mpcallback_INIT_NUM_ARGS, mpcallback_init_args, args);
|
||||
STATIC mp_obj_t pyb_rtc_alarm_cancel (mp_uint_t n_args, const mp_obj_t *args) {
|
||||
// only alarm id 0 is available
|
||||
if (n_args > 1 && mp_obj_get_int(args[1]) != 0) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable));
|
||||
}
|
||||
// disable the alarm
|
||||
pyb_rtc_disable_alarm();
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_rtc_alarm_cancel_obj, 1, 2, pyb_rtc_alarm_cancel);
|
||||
|
||||
/// \method irq(trigger, priority, handler, wake)
|
||||
STATIC mp_obj_t pyb_rtc_irq (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
mp_arg_val_t args[mp_irq_INIT_NUM_ARGS];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, mp_irq_INIT_NUM_ARGS, mp_irq_init_args, args);
|
||||
pyb_rtc_obj_t *self = pos_args[0];
|
||||
|
||||
// check if any parameters were passed
|
||||
mp_obj_t _callback = mpcallback_find((mp_obj_t)&pyb_rtc_obj);
|
||||
if (kw_args->used > 0) {
|
||||
uint32_t f_mseconds = MAX(1, mp_obj_get_int(args[3].u_obj));
|
||||
uint32_t seconds;
|
||||
uint16_t mseconds;
|
||||
// get the seconds and the milliseconds from the RTC
|
||||
MAP_PRCMRTCGet(&seconds, &mseconds);
|
||||
mseconds = RTC_CYCLES_U16MS(mseconds);
|
||||
|
||||
// configure the rtc alarm accordingly
|
||||
seconds += f_mseconds / 1000;
|
||||
mseconds += f_mseconds - ((f_mseconds / 1000) * 1000);
|
||||
|
||||
// disable the interrupt before updating anything
|
||||
pyb_rtc_callback_disable((mp_obj_t)&pyb_rtc_obj);
|
||||
|
||||
// set the match value
|
||||
MAP_PRCMRTCMatchSet(seconds, mseconds);
|
||||
|
||||
// save the power mode data for later
|
||||
self->prwmode = args[4].u_int;
|
||||
|
||||
// create the callback
|
||||
_callback = mpcallback_new ((mp_obj_t)&pyb_rtc_obj, args[1].u_obj, &pybrtc_cb_methods, true);
|
||||
|
||||
// set the lpds callback
|
||||
pybsleep_set_timer_lpds_callback(_callback);
|
||||
|
||||
// the interrupt priority is ignored since it's already set to to highest level by the sleep module
|
||||
// to make sure that the wakeup callbacks are always called first when resuming from sleep
|
||||
|
||||
// enable the interrupt
|
||||
pyb_rtc_callback_enable((mp_obj_t)&pyb_rtc_obj);
|
||||
} else if (!_callback) {
|
||||
_callback = mpcallback_new ((mp_obj_t)&pyb_rtc_obj, mp_const_none, &pybrtc_cb_methods, false);
|
||||
// save the power mode data for later
|
||||
uint8_t pwrmode = (args[3].u_obj == mp_const_none) ? PYB_PWR_MODE_ACTIVE : mp_obj_get_int(args[3].u_obj);
|
||||
if (pwrmode > (PYB_PWR_MODE_ACTIVE | PYB_PWR_MODE_LPDS | PYB_PWR_MODE_HIBERNATE)) {
|
||||
goto invalid_args;
|
||||
}
|
||||
return _callback;
|
||||
|
||||
// check the trigger
|
||||
if (mp_obj_get_int(args[0].u_obj) == PYB_RTC_ALARM0) {
|
||||
self->pwrmode = pwrmode;
|
||||
pyb_rtc_irq_enable((mp_obj_t)self);
|
||||
} else {
|
||||
goto invalid_args;
|
||||
}
|
||||
|
||||
// the interrupt priority is ignored since it's already set to to highest level by the sleep module
|
||||
// to make sure that the wakeup irqs are always called first when resuming from sleep
|
||||
|
||||
// create the callback
|
||||
mp_obj_t _irq = mp_irq_new ((mp_obj_t)self, args[2].u_obj, &pyb_rtc_irq_methods);
|
||||
self->irq_obj = _irq;
|
||||
|
||||
return _irq;
|
||||
|
||||
invalid_args:
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_rtc_callback_obj, 1, pyb_rtc_callback);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_rtc_irq_obj, 1, pyb_rtc_irq);
|
||||
|
||||
STATIC const mp_map_elem_t pyb_rtc_locals_dict_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)&pyb_rtc_init_obj },
|
||||
@@ -393,7 +464,11 @@ STATIC const mp_map_elem_t pyb_rtc_locals_dict_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_now), (mp_obj_t)&pyb_rtc_now_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_alarm), (mp_obj_t)&pyb_rtc_alarm_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_alarm_left), (mp_obj_t)&pyb_rtc_alarm_left_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_callback), (mp_obj_t)&pyb_rtc_callback_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_alarm_cancel), (mp_obj_t)&pyb_rtc_alarm_cancel_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_irq), (mp_obj_t)&pyb_rtc_irq_obj },
|
||||
|
||||
// class constants
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ALARM0), MP_OBJ_NEW_SMALL_INT(PYB_RTC_ALARM0) },
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(pyb_rtc_locals_dict, pyb_rtc_locals_dict_table);
|
||||
|
||||
@@ -404,8 +479,9 @@ const mp_obj_type_t pyb_rtc_type = {
|
||||
.locals_dict = (mp_obj_t)&pyb_rtc_locals_dict,
|
||||
};
|
||||
|
||||
STATIC const mp_cb_methods_t pybrtc_cb_methods = {
|
||||
.init = pyb_rtc_callback,
|
||||
.enable = pyb_rtc_callback_enable,
|
||||
.disable = pyb_rtc_callback_disable,
|
||||
STATIC const mp_irq_methods_t pyb_rtc_irq_methods = {
|
||||
.init = pyb_rtc_irq,
|
||||
.enable = pyb_rtc_irq_enable,
|
||||
.disable = pyb_rtc_irq_disable,
|
||||
.flags = pyb_rtc_irq_flags
|
||||
};
|
||||
|
||||
@@ -28,12 +28,32 @@
|
||||
#ifndef PYBRTC_H_
|
||||
#define PYBRTC_H_
|
||||
|
||||
#define RTC_U16MS_CYCLES(msec) ((msec * 1024) / 1000)
|
||||
#define RTC_CYCLES_U16MS(cycles) ((cycles * 1000) / 1024)
|
||||
// RTC triggers
|
||||
#define PYB_RTC_ALARM0 (0x01)
|
||||
|
||||
#define RTC_ACCESS_TIME_MSEC (5)
|
||||
#define PYB_RTC_MIN_ALARM_TIME_MS (RTC_ACCESS_TIME_MSEC * 2)
|
||||
|
||||
typedef struct _pyb_rtc_obj_t {
|
||||
mp_obj_base_t base;
|
||||
mp_obj_t irq_obj;
|
||||
uint32_t irq_flags;
|
||||
uint32_t alarm_ms;
|
||||
uint32_t alarm_time_s;
|
||||
uint16_t alarm_time_ms;
|
||||
byte pwrmode;
|
||||
bool alarmset;
|
||||
bool repeat;
|
||||
bool irq_enabled;
|
||||
} pyb_rtc_obj_t;
|
||||
|
||||
extern const mp_obj_type_t pyb_rtc_type;
|
||||
|
||||
extern void pyb_rtc_pre_init(void);
|
||||
extern void pyb_rtc_get_time (uint32_t *secs, uint16_t *msecs);
|
||||
extern uint32_t pyb_rtc_get_seconds (void);
|
||||
extern void pyb_rtc_calc_future_time (uint32_t a_mseconds, uint32_t *f_seconds, uint16_t *f_mseconds);
|
||||
extern void pyb_rtc_repeat_alarm (pyb_rtc_obj_t *self);
|
||||
extern void pyb_rtc_disable_alarm (void);
|
||||
|
||||
#endif // PYBRTC_H_
|
||||
|
||||
@@ -54,7 +54,7 @@
|
||||
/******************************************************************************
|
||||
DECLARE PUBLIC DATA
|
||||
******************************************************************************/
|
||||
pybsd_obj_t pybsd_obj = {.pin_clk = MP_OBJ_NULL, .enabled = false};
|
||||
pybsd_obj_t pybsd_obj;
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE DATA
|
||||
@@ -95,17 +95,13 @@ STATIC mp_obj_t pyb_sd_init_helper (pybsd_obj_t *self, const mp_arg_val_t *args)
|
||||
mp_obj_t pins_o = args[0].u_obj;
|
||||
if (pins_o != mp_const_none) {
|
||||
mp_obj_t *pins;
|
||||
mp_uint_t n_pins = MP_ARRAY_SIZE(pyb_sd_def_pin);
|
||||
if (pins_o == MP_OBJ_NULL) {
|
||||
// use the default pins
|
||||
pins = (mp_obj_t *)pyb_sd_def_pin;
|
||||
} else {
|
||||
mp_obj_get_array(pins_o, &n_pins, &pins);
|
||||
if (n_pins != MP_ARRAY_SIZE(pyb_sd_def_pin)) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
|
||||
}
|
||||
mp_obj_get_array_fixed_n(pins_o, MP_ARRAY_SIZE(pyb_sd_def_pin), &pins);
|
||||
}
|
||||
pin_assign_pins_af (pins, n_pins, PIN_TYPE_STD_PU, PIN_FN_SD, 0);
|
||||
pin_assign_pins_af (pins, MP_ARRAY_SIZE(pyb_sd_def_pin), PIN_TYPE_STD_PU, PIN_FN_SD, 0);
|
||||
// save the pins clock
|
||||
self->pin_clk = pin_find(pins[0]);
|
||||
}
|
||||
@@ -116,7 +112,7 @@ STATIC mp_obj_t pyb_sd_init_helper (pybsd_obj_t *self, const mp_arg_val_t *args)
|
||||
}
|
||||
|
||||
// register it with the sleep module
|
||||
pybsleep_add ((const mp_obj_t)self, (WakeUpCB_t)pyb_sd_hw_init);
|
||||
pyb_sleep_add ((const mp_obj_t)self, (WakeUpCB_t)pyb_sd_hw_init);
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
@@ -163,7 +159,7 @@ STATIC mp_obj_t pyb_sd_deinit (mp_obj_t self_in) {
|
||||
// de-initialze the sd card at diskio level
|
||||
sd_disk_deinit();
|
||||
// unregister it from the sleep module
|
||||
pybsleep_remove (self);
|
||||
pyb_sleep_remove (self);
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_sd_deinit_obj, pyb_sd_deinit);
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
#include "spi.h"
|
||||
#include "pin.h"
|
||||
#include "pybsleep.h"
|
||||
#include "mpirq.h"
|
||||
#include "pybpin.h"
|
||||
#include "simplelink.h"
|
||||
#include "modnetwork.h"
|
||||
@@ -50,12 +51,12 @@
|
||||
#include "osi.h"
|
||||
#include "debug.h"
|
||||
#include "mpexception.h"
|
||||
#include "mpcallback.h"
|
||||
#include "mperror.h"
|
||||
#include "sleeprestore.h"
|
||||
#include "serverstask.h"
|
||||
#include "antenna.h"
|
||||
#include "cryptohash.h"
|
||||
#include "pybrtc.h"
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE CONSTANTS
|
||||
@@ -70,7 +71,7 @@
|
||||
#define WAKEUP_TIME_LPDS (LPDS_UP_TIME + LPDS_DOWN_TIME + USER_OFFSET) // 20 msec
|
||||
#define WAKEUP_TIME_HIB (32768) // 1 s
|
||||
|
||||
#define FORCED_TIMER_INTERRUPT_MS (1)
|
||||
#define FORCED_TIMER_INTERRUPT_MS (PYB_RTC_MIN_ALARM_TIME_MS)
|
||||
#define FAILED_SLEEP_DELAY_MS (FORCED_TIMER_INTERRUPT_MS * 3)
|
||||
|
||||
/******************************************************************************
|
||||
@@ -110,35 +111,37 @@ typedef struct {
|
||||
mp_obj_base_t base;
|
||||
mp_obj_t obj;
|
||||
WakeUpCB_t wakeup;
|
||||
} pybsleep_obj_t;
|
||||
} pyb_sleep_obj_t;
|
||||
|
||||
typedef struct {
|
||||
mp_obj_t wlan_lpds_wake_cb;
|
||||
mp_obj_t timer_lpds_wake_cb;
|
||||
mp_obj_t gpio_lpds_wake_cb;
|
||||
uint timer_wake_pwrmode;
|
||||
mp_obj_t gpio_lpds_wake_cb;
|
||||
wlan_obj_t *wlan_obj;
|
||||
pyb_rtc_obj_t *rtc_obj;
|
||||
} pybsleep_data_t;
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE DATA
|
||||
******************************************************************************/
|
||||
STATIC const mp_obj_type_t pybsleep_type;
|
||||
STATIC nvic_reg_store_t *nvic_reg_store;
|
||||
STATIC pybsleep_data_t pybsleep_data = {NULL, NULL, NULL, 0};
|
||||
STATIC pybsleep_data_t pybsleep_data = {NULL, NULL, NULL};
|
||||
volatile arm_cm4_core_regs_t vault_arm_registers;
|
||||
STATIC pybsleep_reset_cause_t pybsleep_reset_cause = PYB_SLP_PWRON_RESET;
|
||||
STATIC pybsleep_wake_reason_t pybsleep_wake_reason = PYB_SLP_WAKED_PWRON;
|
||||
STATIC const mp_obj_type_t pyb_sleep_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_sleep,
|
||||
};
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE FUNCTIONS
|
||||
******************************************************************************/
|
||||
STATIC pybsleep_obj_t *pybsleep_find (mp_obj_t obj);
|
||||
STATIC void pybsleep_flash_powerdown (void);
|
||||
STATIC NORETURN void pybsleep_suspend_enter (void);
|
||||
void pybsleep_suspend_exit (void);
|
||||
STATIC void pybsleep_obj_wakeup (void);
|
||||
STATIC pyb_sleep_obj_t *pyb_sleep_find (mp_obj_t obj);
|
||||
STATIC void pyb_sleep_flash_powerdown (void);
|
||||
STATIC NORETURN void pyb_sleep_suspend_enter (void);
|
||||
void pyb_sleep_suspend_exit (void);
|
||||
STATIC void pyb_sleep_obj_wakeup (void);
|
||||
STATIC void PRCMInterruptHandler (void);
|
||||
STATIC void pybsleep_iopark (bool hibernate);
|
||||
STATIC void pyb_sleep_iopark (bool hibernate);
|
||||
STATIC bool setup_timer_lpds_wake (void);
|
||||
STATIC bool setup_timer_hibernate_wake (void);
|
||||
|
||||
@@ -146,14 +149,14 @@ STATIC bool setup_timer_hibernate_wake (void);
|
||||
DEFINE PUBLIC FUNCTIONS
|
||||
******************************************************************************/
|
||||
__attribute__ ((section (".boot")))
|
||||
void pybsleep_pre_init (void) {
|
||||
void pyb_sleep_pre_init (void) {
|
||||
// allocate memory for nvic registers vault
|
||||
ASSERT ((nvic_reg_store = mem_Malloc(sizeof(nvic_reg_store_t))) != NULL);
|
||||
}
|
||||
|
||||
void pybsleep_init0 (void) {
|
||||
void pyb_sleep_init0 (void) {
|
||||
// initialize the sleep objects list
|
||||
mp_obj_list_init(&MP_STATE_PORT(pybsleep_obj_list), 0);
|
||||
mp_obj_list_init(&MP_STATE_PORT(pyb_sleep_obj_list), 0);
|
||||
|
||||
// register and enable the PRCM interrupt
|
||||
osi_InterruptRegister(INT_PRCM, (P_OSI_INTR_ENTRY)PRCMInterruptHandler, INT_PRIORITY_LVL_1);
|
||||
@@ -164,7 +167,7 @@ void pybsleep_init0 (void) {
|
||||
MAP_PRCMHibernateWakeupSourceDisable(PRCM_HIB_SLOW_CLK_CTR | PRCM_HIB_GPIO2 | PRCM_HIB_GPIO4 | PRCM_HIB_GPIO13 |
|
||||
PRCM_HIB_GPIO17 | PRCM_HIB_GPIO11 | PRCM_HIB_GPIO24 | PRCM_HIB_GPIO26);
|
||||
|
||||
// store the reset casue (if it's soft reset, leave it as it is)
|
||||
// check the reset casue (if it's soft reset, leave it as it is)
|
||||
if (pybsleep_reset_cause != PYB_SLP_SOFT_RESET) {
|
||||
switch (MAP_PRCMSysResetCauseGet()) {
|
||||
case PRCM_POWER_ON:
|
||||
@@ -188,6 +191,7 @@ void pybsleep_init0 (void) {
|
||||
switch (MAP_PRCMHibernateWakeupCauseGet()) {
|
||||
case PRCM_HIB_WAKEUP_CAUSE_SLOW_CLOCK:
|
||||
pybsleep_wake_reason = PYB_SLP_WAKED_BY_RTC;
|
||||
// TODO repeat the alarm
|
||||
break;
|
||||
case PRCM_HIB_WAKEUP_CAUSE_GPIO:
|
||||
pybsleep_wake_reason = PYB_SLP_WAKED_BY_GPIO;
|
||||
@@ -203,54 +207,109 @@ void pybsleep_init0 (void) {
|
||||
}
|
||||
}
|
||||
|
||||
void pybsleep_signal_soft_reset (void) {
|
||||
void pyb_sleep_signal_soft_reset (void) {
|
||||
pybsleep_reset_cause = PYB_SLP_SOFT_RESET;
|
||||
}
|
||||
|
||||
void pybsleep_add (const mp_obj_t obj, WakeUpCB_t wakeup) {
|
||||
pybsleep_obj_t * sleep_obj = m_new_obj(pybsleep_obj_t);
|
||||
sleep_obj->base.type = &pybsleep_type;
|
||||
void pyb_sleep_add (const mp_obj_t obj, WakeUpCB_t wakeup) {
|
||||
pyb_sleep_obj_t *sleep_obj = m_new_obj(pyb_sleep_obj_t);
|
||||
sleep_obj->base.type = &pyb_sleep_type;
|
||||
sleep_obj->obj = obj;
|
||||
sleep_obj->wakeup = wakeup;
|
||||
// remove it in case it was already registered
|
||||
pybsleep_remove (obj);
|
||||
mp_obj_list_append(&MP_STATE_PORT(pybsleep_obj_list), sleep_obj);
|
||||
pyb_sleep_remove (obj);
|
||||
mp_obj_list_append(&MP_STATE_PORT(pyb_sleep_obj_list), sleep_obj);
|
||||
}
|
||||
|
||||
void pybsleep_remove (const mp_obj_t obj) {
|
||||
pybsleep_obj_t *sleep_obj;
|
||||
if ((sleep_obj = pybsleep_find(obj))) {
|
||||
mp_obj_list_remove(&MP_STATE_PORT(pybsleep_obj_list), sleep_obj);
|
||||
void pyb_sleep_remove (const mp_obj_t obj) {
|
||||
pyb_sleep_obj_t *sleep_obj;
|
||||
if ((sleep_obj = pyb_sleep_find(obj))) {
|
||||
mp_obj_list_remove(&MP_STATE_PORT(pyb_sleep_obj_list), sleep_obj);
|
||||
}
|
||||
}
|
||||
|
||||
void pybsleep_set_wlan_lpds_callback (mp_obj_t cb_obj) {
|
||||
pybsleep_data.wlan_lpds_wake_cb = cb_obj;
|
||||
}
|
||||
|
||||
void pybsleep_set_gpio_lpds_callback (mp_obj_t cb_obj) {
|
||||
void pyb_sleep_set_gpio_lpds_callback (mp_obj_t cb_obj) {
|
||||
pybsleep_data.gpio_lpds_wake_cb = cb_obj;
|
||||
}
|
||||
|
||||
void pybsleep_set_timer_lpds_callback (mp_obj_t cb_obj) {
|
||||
pybsleep_data.timer_lpds_wake_cb = cb_obj;
|
||||
void pyb_sleep_set_wlan_obj (mp_obj_t wlan_obj) {
|
||||
pybsleep_data.wlan_obj = (wlan_obj_t *)wlan_obj;
|
||||
}
|
||||
|
||||
void pybsleep_configure_timer_wakeup (uint pwrmode) {
|
||||
pybsleep_data.timer_wake_pwrmode = pwrmode;
|
||||
void pyb_sleep_set_rtc_obj (mp_obj_t rtc_obj) {
|
||||
pybsleep_data.rtc_obj = (pyb_rtc_obj_t *)rtc_obj;
|
||||
}
|
||||
|
||||
pybsleep_reset_cause_t pybsleep_get_reset_cause (void) {
|
||||
void pyb_sleep_sleep (void) {
|
||||
nlr_buf_t nlr;
|
||||
|
||||
// check if we should enable timer wake-up
|
||||
if (pybsleep_data.rtc_obj->irq_enabled && (pybsleep_data.rtc_obj->pwrmode & PYB_PWR_MODE_LPDS)) {
|
||||
if (!setup_timer_lpds_wake()) {
|
||||
// lpds entering is not possible, wait for the forced interrupt and return
|
||||
HAL_Delay (FAILED_SLEEP_DELAY_MS);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// disable the timer as wake source
|
||||
MAP_PRCMLPDSWakeupSourceDisable(PRCM_LPDS_TIMER);
|
||||
}
|
||||
|
||||
// do we need network wake-up?
|
||||
if (pybsleep_data.wlan_obj->irq_enabled) {
|
||||
MAP_PRCMLPDSWakeupSourceEnable (PRCM_LPDS_HOST_IRQ);
|
||||
server_sleep_sockets();
|
||||
} else {
|
||||
MAP_PRCMLPDSWakeupSourceDisable (PRCM_LPDS_HOST_IRQ);
|
||||
}
|
||||
|
||||
// entering and exiting suspended mode must be an atomic operation
|
||||
// therefore interrupts need to be disabled
|
||||
uint primsk = disable_irq();
|
||||
if (nlr_push(&nlr) == 0) {
|
||||
pyb_sleep_suspend_enter();
|
||||
nlr_pop();
|
||||
}
|
||||
|
||||
// an exception is always raised when exiting suspend mode
|
||||
enable_irq(primsk);
|
||||
}
|
||||
|
||||
void pyb_sleep_deepsleep (void) {
|
||||
// check if we should enable timer wake-up
|
||||
if (pybsleep_data.rtc_obj->irq_enabled && (pybsleep_data.rtc_obj->pwrmode & PYB_PWR_MODE_HIBERNATE)) {
|
||||
if (!setup_timer_hibernate_wake()) {
|
||||
// hibernating is not possible, wait for the forced interrupt and return
|
||||
HAL_Delay (FAILED_SLEEP_DELAY_MS);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// disable the timer as hibernate wake source
|
||||
MAP_PRCMLPDSWakeupSourceDisable(PRCM_HIB_SLOW_CLK_CTR);
|
||||
}
|
||||
|
||||
wlan_stop(SL_STOP_TIMEOUT);
|
||||
pyb_sleep_flash_powerdown();
|
||||
// must be done just before entering hibernate mode
|
||||
pyb_sleep_iopark(true);
|
||||
MAP_PRCMHibernateEnter();
|
||||
}
|
||||
|
||||
pybsleep_reset_cause_t pyb_sleep_get_reset_cause (void) {
|
||||
return pybsleep_reset_cause;
|
||||
}
|
||||
|
||||
pybsleep_wake_reason_t pyb_sleep_get_wake_reason (void) {
|
||||
return pybsleep_wake_reason;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PRIVATE FUNCTIONS
|
||||
******************************************************************************/
|
||||
STATIC pybsleep_obj_t *pybsleep_find (mp_obj_t obj) {
|
||||
for (mp_uint_t i = 0; i < MP_STATE_PORT(pybsleep_obj_list).len; i++) {
|
||||
STATIC pyb_sleep_obj_t *pyb_sleep_find (mp_obj_t obj) {
|
||||
for (mp_uint_t i = 0; i < MP_STATE_PORT(pyb_sleep_obj_list).len; i++) {
|
||||
// search for the object and then remove it
|
||||
pybsleep_obj_t *sleep_obj = ((pybsleep_obj_t *)(MP_STATE_PORT(pybsleep_obj_list).items[i]));
|
||||
pyb_sleep_obj_t *sleep_obj = ((pyb_sleep_obj_t *)(MP_STATE_PORT(pyb_sleep_obj_list).items[i]));
|
||||
if (sleep_obj->obj == obj) {
|
||||
return sleep_obj;
|
||||
}
|
||||
@@ -258,7 +317,7 @@ STATIC pybsleep_obj_t *pybsleep_find (mp_obj_t obj) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
STATIC void pybsleep_flash_powerdown (void) {
|
||||
STATIC void pyb_sleep_flash_powerdown (void) {
|
||||
uint32_t status;
|
||||
|
||||
// Enable clock for SSPI module
|
||||
@@ -303,7 +362,7 @@ STATIC void pybsleep_flash_powerdown (void) {
|
||||
MAP_SPICSDisable(SSPI_BASE);
|
||||
}
|
||||
|
||||
STATIC NORETURN void pybsleep_suspend_enter (void) {
|
||||
STATIC NORETURN void pyb_sleep_suspend_enter (void) {
|
||||
// enable full RAM retention
|
||||
MAP_PRCMSRAMRetentionEnable(PRCM_SRAM_COL_1 | PRCM_SRAM_COL_2 | PRCM_SRAM_COL_3 | PRCM_SRAM_COL_4, PRCM_SRAM_LPDS_RET);
|
||||
|
||||
@@ -340,7 +399,7 @@ STATIC NORETURN void pybsleep_suspend_enter (void) {
|
||||
mperror_heartbeat_switch_off();
|
||||
|
||||
// park the gpio pins
|
||||
pybsleep_iopark(false);
|
||||
pyb_sleep_iopark(false);
|
||||
|
||||
// store the cpu registers
|
||||
sleep_store();
|
||||
@@ -353,7 +412,7 @@ STATIC NORETURN void pybsleep_suspend_enter (void) {
|
||||
for ( ; ; );
|
||||
}
|
||||
|
||||
void pybsleep_suspend_exit (void) {
|
||||
void pyb_sleep_suspend_exit (void) {
|
||||
// take the I2C semaphore
|
||||
uint32_t reg = HWREG(COMMON_REG_BASE + COMMON_REG_O_I2C_Properties_Register);
|
||||
reg = (reg & ~0x3) | 0x1;
|
||||
@@ -407,13 +466,13 @@ void pybsleep_suspend_exit (void) {
|
||||
sl_IfOpen (NULL, 0);
|
||||
|
||||
// restore the configuration of all active peripherals
|
||||
pybsleep_obj_wakeup();
|
||||
pyb_sleep_obj_wakeup();
|
||||
|
||||
// reconfigure all the previously enabled interrupts
|
||||
mpcallback_wake_all();
|
||||
mp_irq_wake_all();
|
||||
|
||||
// we need to init the crypto hash engine again
|
||||
CRYPTOHASH_Init();
|
||||
//CRYPTOHASH_Init();
|
||||
|
||||
// trigger a sw interrupt
|
||||
MAP_IntPendSet(INT_PRCM);
|
||||
@@ -425,25 +484,35 @@ void pybsleep_suspend_exit (void) {
|
||||
STATIC void PRCMInterruptHandler (void) {
|
||||
// reading the interrupt status automatically clears the interrupt
|
||||
if (PRCM_INT_SLOW_CLK_CTR == MAP_PRCMIntStatus()) {
|
||||
// this interrupt is triggered during active mode
|
||||
mpcallback_handler(pybsleep_data.timer_lpds_wake_cb);
|
||||
}
|
||||
else {
|
||||
// reconfigure it again (if repeat is true)
|
||||
pyb_rtc_repeat_alarm (pybsleep_data.rtc_obj);
|
||||
pybsleep_data.rtc_obj->irq_flags = PYB_RTC_ALARM0;
|
||||
// need to check if irq's are enabled from the user point of view
|
||||
if (pybsleep_data.rtc_obj->irq_enabled && (pybsleep_data.rtc_obj->pwrmode & PYB_PWR_MODE_ACTIVE)) {
|
||||
mp_irq_handler(pybsleep_data.rtc_obj->irq_obj);
|
||||
}
|
||||
pybsleep_data.rtc_obj->irq_flags = 0;
|
||||
} else {
|
||||
// interrupt has been triggered while waking up from LPDS
|
||||
switch (MAP_PRCMLPDSWakeupCauseGet()) {
|
||||
case PRCM_LPDS_HOST_IRQ:
|
||||
mpcallback_handler(pybsleep_data.wlan_lpds_wake_cb);
|
||||
pybsleep_data.wlan_obj->irq_flags = MODWLAN_WIFI_EVENT_ANY;
|
||||
mp_irq_handler(pybsleep_data.wlan_obj->irq_obj);
|
||||
pybsleep_wake_reason = PYB_SLP_WAKED_BY_WLAN;
|
||||
pybsleep_data.wlan_obj->irq_flags = 0;
|
||||
break;
|
||||
case PRCM_LPDS_GPIO:
|
||||
mpcallback_handler(pybsleep_data.gpio_lpds_wake_cb);
|
||||
mp_irq_handler(pybsleep_data.gpio_lpds_wake_cb);
|
||||
pybsleep_wake_reason = PYB_SLP_WAKED_BY_GPIO;
|
||||
break;
|
||||
case PRCM_LPDS_TIMER:
|
||||
// disable the timer as wake-up source
|
||||
pybsleep_data.timer_wake_pwrmode &= ~PYB_PWR_MODE_LPDS;
|
||||
// reconfigure it again if repeat is true
|
||||
pyb_rtc_repeat_alarm (pybsleep_data.rtc_obj);
|
||||
pybsleep_data.rtc_obj->irq_flags = PYB_RTC_ALARM0;
|
||||
// next one clears the wake cause flag
|
||||
MAP_PRCMLPDSWakeupSourceDisable(PRCM_LPDS_TIMER);
|
||||
mpcallback_handler(pybsleep_data.timer_lpds_wake_cb);
|
||||
mp_irq_handler(pybsleep_data.rtc_obj->irq_obj);
|
||||
pybsleep_data.rtc_obj->irq_flags = 0;
|
||||
pybsleep_wake_reason = PYB_SLP_WAKED_BY_RTC;
|
||||
break;
|
||||
default:
|
||||
@@ -452,14 +521,14 @@ STATIC void PRCMInterruptHandler (void) {
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void pybsleep_obj_wakeup (void) {
|
||||
for (mp_uint_t i = 0; i < MP_STATE_PORT(pybsleep_obj_list).len; i++) {
|
||||
pybsleep_obj_t *sleep_obj = ((pybsleep_obj_t *)MP_STATE_PORT(pybsleep_obj_list).items[i]);
|
||||
STATIC void pyb_sleep_obj_wakeup (void) {
|
||||
for (mp_uint_t i = 0; i < MP_STATE_PORT(pyb_sleep_obj_list).len; i++) {
|
||||
pyb_sleep_obj_t *sleep_obj = ((pyb_sleep_obj_t *)MP_STATE_PORT(pyb_sleep_obj_list).items[i]);
|
||||
sleep_obj->wakeup(sleep_obj->obj);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void pybsleep_iopark (bool hibernate) {
|
||||
STATIC void pyb_sleep_iopark (bool hibernate) {
|
||||
mp_map_t *named_map = mp_obj_dict_get_map((mp_obj_t)&pin_board_pins_locals_dict);
|
||||
for (uint i = 0; i < named_map->used; i++) {
|
||||
pin_obj_t * pin = (pin_obj_t *)named_map->table[i].value;
|
||||
@@ -473,9 +542,9 @@ STATIC void pybsleep_iopark (bool hibernate) {
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
// enable a weak pull-down if the pin is unused
|
||||
// enable a weak pull-up if the pin is unused
|
||||
if (!pin->used) {
|
||||
MAP_PinConfigSet(pin->pin_num, pin->strength, PIN_TYPE_STD_PD);
|
||||
MAP_PinConfigSet(pin->pin_num, pin->strength, PIN_TYPE_STD_PU);
|
||||
}
|
||||
if (hibernate) {
|
||||
// make it an input
|
||||
@@ -517,191 +586,72 @@ STATIC void pybsleep_iopark (bool hibernate) {
|
||||
}
|
||||
|
||||
STATIC bool setup_timer_lpds_wake (void) {
|
||||
uint64_t t_match, t_curr, t_remaining;
|
||||
uint64_t t_match, t_curr;
|
||||
int64_t t_remaining;
|
||||
|
||||
// get the time remaining for the RTC timer to expire
|
||||
t_match = MAP_PRCMSlowClkCtrMatchGet();
|
||||
t_curr = MAP_PRCMSlowClkCtrGet();
|
||||
|
||||
if (t_match > t_curr) {
|
||||
// get the time remaining in terms of slow clocks
|
||||
t_remaining = (t_match - t_curr);
|
||||
if (t_remaining > WAKEUP_TIME_LPDS) {
|
||||
// subtract the time it takes for wakeup from lpds
|
||||
t_remaining -= WAKEUP_TIME_LPDS;
|
||||
t_remaining = (t_remaining > 0xFFFFFFFF) ? 0xFFFFFFFF: t_remaining;
|
||||
// setup the LPDS wake time
|
||||
MAP_PRCMLPDSIntervalSet((uint32_t)t_remaining);
|
||||
// enable the wake source
|
||||
MAP_PRCMLPDSWakeupSourceEnable(PRCM_LPDS_TIMER);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// setup a timer interrupt immediately
|
||||
MAP_PRCMRTCMatchSet(0, FORCED_TIMER_INTERRUPT_MS);
|
||||
// get the time remaining in terms of slow clocks
|
||||
t_remaining = (t_match - t_curr);
|
||||
if (t_remaining > WAKEUP_TIME_LPDS) {
|
||||
// subtract the time it takes to wakeup from lpds
|
||||
t_remaining -= WAKEUP_TIME_LPDS;
|
||||
t_remaining = (t_remaining > 0xFFFFFFFF) ? 0xFFFFFFFF: t_remaining;
|
||||
// setup the LPDS wake time
|
||||
MAP_PRCMLPDSIntervalSet((uint32_t)t_remaining);
|
||||
// enable the wake source
|
||||
MAP_PRCMLPDSWakeupSourceEnable(PRCM_LPDS_TIMER);
|
||||
return true;
|
||||
}
|
||||
|
||||
// disable the timer as wake source
|
||||
MAP_PRCMLPDSWakeupSourceDisable(PRCM_LPDS_TIMER);
|
||||
|
||||
// LPDS wake by timer was not possible, force
|
||||
// an interrupt in active mode instead
|
||||
uint32_t f_seconds;
|
||||
uint16_t f_mseconds;
|
||||
// setup a timer interrupt immediately
|
||||
pyb_rtc_calc_future_time (FORCED_TIMER_INTERRUPT_MS, &f_seconds, &f_mseconds);
|
||||
MAP_PRCMRTCMatchSet(f_seconds, f_mseconds);
|
||||
// LPDS wake by timer was not possible, force an interrupt in active mode instead
|
||||
MAP_PRCMIntEnable(PRCM_INT_SLOW_CLK_CTR);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
STATIC bool setup_timer_hibernate_wake (void) {
|
||||
uint64_t t_match, t_curr, t_remaining;
|
||||
uint64_t t_match, t_curr;
|
||||
int64_t t_remaining;
|
||||
|
||||
// get the time remaining for the RTC timer to expire
|
||||
t_match = MAP_PRCMSlowClkCtrMatchGet();
|
||||
t_curr = MAP_PRCMSlowClkCtrGet();
|
||||
|
||||
if (t_match > t_curr) {
|
||||
// get the time remaining in terms of slow clocks
|
||||
t_remaining = (t_match - t_curr);
|
||||
if (t_remaining > WAKEUP_TIME_HIB) {
|
||||
// subtract the time it takes for wakeup from hibernate
|
||||
t_remaining -= WAKEUP_TIME_HIB;
|
||||
// setup the LPDS wake time
|
||||
MAP_PRCMHibernateIntervalSet((uint32_t)t_remaining);
|
||||
// enable the wake source
|
||||
MAP_PRCMHibernateWakeupSourceEnable(PRCM_HIB_SLOW_CLK_CTR);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// setup a timer interrupt immediately
|
||||
MAP_PRCMRTCMatchSet(0, FORCED_TIMER_INTERRUPT_MS);
|
||||
// get the time remaining in terms of slow clocks
|
||||
t_remaining = (t_match - t_curr);
|
||||
if (t_remaining > WAKEUP_TIME_HIB) {
|
||||
// subtract the time it takes for wakeup from hibernate
|
||||
t_remaining -= WAKEUP_TIME_HIB;
|
||||
// setup the LPDS wake time
|
||||
MAP_PRCMHibernateIntervalSet((uint32_t)t_remaining);
|
||||
// enable the wake source
|
||||
MAP_PRCMHibernateWakeupSourceEnable(PRCM_HIB_SLOW_CLK_CTR);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// disable the timer as wake source
|
||||
MAP_PRCMLPDSWakeupSourceDisable(PRCM_HIB_SLOW_CLK_CTR);
|
||||
|
||||
// hibernate wake by timer was not possible, force
|
||||
// an interrupt in active mode instead
|
||||
uint32_t f_seconds;
|
||||
uint16_t f_mseconds;
|
||||
// setup a timer interrupt immediately
|
||||
pyb_rtc_calc_future_time (FORCED_TIMER_INTERRUPT_MS, &f_seconds, &f_mseconds);
|
||||
MAP_PRCMRTCMatchSet(f_seconds, f_mseconds);
|
||||
// LPDS wake by timer was not possible, force an interrupt in active mode instead
|
||||
MAP_PRCMIntEnable(PRCM_INT_SLOW_CLK_CTR);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
// Micro Python bindings; Sleep class
|
||||
|
||||
/// \function idle()
|
||||
/// Gates the processor clock until an interrupt is triggered
|
||||
STATIC mp_obj_t pyb_sleep_idle (mp_obj_t self_in) {
|
||||
__WFI();
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_sleep_idle_obj, pyb_sleep_idle);
|
||||
|
||||
/// \function suspend(wlan)
|
||||
/// Enters suspended mode. Wake up sources should have been enable prior to
|
||||
/// calling this method.
|
||||
STATIC mp_obj_t pyb_sleep_suspend (mp_obj_t self_in) {
|
||||
nlr_buf_t nlr;
|
||||
|
||||
// check if we should enable timer wake-up
|
||||
if (pybsleep_data.timer_wake_pwrmode & PYB_PWR_MODE_LPDS) {
|
||||
if (!setup_timer_lpds_wake()) {
|
||||
// lpds entering is not possible, wait for the forced interrupt and return
|
||||
pybsleep_data.timer_wake_pwrmode &= ~PYB_PWR_MODE_LPDS;
|
||||
HAL_Delay (FAILED_SLEEP_DELAY_MS);
|
||||
return mp_const_none;
|
||||
}
|
||||
}
|
||||
|
||||
// do we need network wake-up?
|
||||
if (pybsleep_data.wlan_lpds_wake_cb) {
|
||||
MAP_PRCMLPDSWakeupSourceEnable (PRCM_LPDS_HOST_IRQ);
|
||||
server_sleep_sockets();
|
||||
}
|
||||
else {
|
||||
MAP_PRCMLPDSWakeupSourceDisable (PRCM_LPDS_HOST_IRQ);
|
||||
}
|
||||
|
||||
// entering and exiting suspended mode must be an atomic operation
|
||||
// therefore interrupts need to be disabled
|
||||
uint primsk = disable_irq();
|
||||
if (nlr_push(&nlr) == 0) {
|
||||
pybsleep_suspend_enter();
|
||||
nlr_pop();
|
||||
}
|
||||
|
||||
// an exception is always raised when exiting suspend mode
|
||||
enable_irq(primsk);
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_sleep_suspend_obj, pyb_sleep_suspend);
|
||||
|
||||
/// \function hibernate()
|
||||
/// Enters hibernate mode. Wake up sources should have been enable prior to
|
||||
/// calling this method.
|
||||
STATIC mp_obj_t pyb_sleep_hibernate (mp_obj_t self_in) {
|
||||
// check if we should enable timer wake-up
|
||||
if (pybsleep_data.timer_wake_pwrmode & PYB_PWR_MODE_HIBERNATE) {
|
||||
if (!setup_timer_hibernate_wake()) {
|
||||
// hibernating is not possible, wait for the forced interrupt and return
|
||||
pybsleep_data.timer_wake_pwrmode &= ~PYB_PWR_MODE_HIBERNATE;
|
||||
HAL_Delay (FAILED_SLEEP_DELAY_MS);
|
||||
return mp_const_none;
|
||||
}
|
||||
}
|
||||
wlan_stop(SL_STOP_TIMEOUT);
|
||||
pybsleep_flash_powerdown();
|
||||
// must be done just before entering hibernate mode
|
||||
pybsleep_iopark(true);
|
||||
MAP_PRCMHibernateEnter();
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_sleep_hibernate_obj, pyb_sleep_hibernate);
|
||||
|
||||
/// \function reset_cause()
|
||||
/// Returns the last reset casue
|
||||
STATIC mp_obj_t pyb_sleep_reset_cause (mp_obj_t self_in) {
|
||||
return MP_OBJ_NEW_SMALL_INT(pybsleep_reset_cause);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_sleep_reset_cause_obj, pyb_sleep_reset_cause);
|
||||
|
||||
/// \function wake_reason()
|
||||
/// Returns the wake up reson from ldps or hibernate
|
||||
STATIC mp_obj_t pyb_sleep_wake_reason (mp_obj_t self_in) {
|
||||
return MP_OBJ_NEW_SMALL_INT(pybsleep_wake_reason);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_sleep_wake_reason_obj, pyb_sleep_wake_reason);
|
||||
|
||||
STATIC const mp_map_elem_t pybsleep_locals_dict_table[] = {
|
||||
// instance methods
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_idle), (mp_obj_t)&pyb_sleep_idle_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_suspend), (mp_obj_t)&pyb_sleep_suspend_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_hibernate), (mp_obj_t)&pyb_sleep_hibernate_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_reset_cause), (mp_obj_t)&pyb_sleep_reset_cause_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_wake_reason), (mp_obj_t)&pyb_sleep_wake_reason_obj },
|
||||
|
||||
// class constants
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ACTIVE), MP_OBJ_NEW_SMALL_INT(PYB_PWR_MODE_ACTIVE) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_SUSPENDED), MP_OBJ_NEW_SMALL_INT(PYB_PWR_MODE_LPDS) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_HIBERNATING), MP_OBJ_NEW_SMALL_INT(PYB_PWR_MODE_HIBERNATE) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_POWER_ON), MP_OBJ_NEW_SMALL_INT(PYB_SLP_PWRON_RESET) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_HARD_RESET), MP_OBJ_NEW_SMALL_INT(PYB_SLP_HARD_RESET) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_WDT_RESET), MP_OBJ_NEW_SMALL_INT(PYB_SLP_WDT_RESET) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_HIB_RESET), MP_OBJ_NEW_SMALL_INT(PYB_SLP_HIB_RESET) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_SOFT_RESET), MP_OBJ_NEW_SMALL_INT(PYB_SLP_SOFT_RESET) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_WLAN_WAKE), MP_OBJ_NEW_SMALL_INT(PYB_SLP_WAKED_BY_WLAN) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_PIN_WAKE), MP_OBJ_NEW_SMALL_INT(PYB_SLP_WAKED_BY_GPIO) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_RTC_WAKE), MP_OBJ_NEW_SMALL_INT(PYB_SLP_WAKED_BY_RTC) },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(pybsleep_locals_dict, pybsleep_locals_dict_table);
|
||||
|
||||
STATIC const mp_obj_type_t pybsleep_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_Sleep,
|
||||
.locals_dict = (mp_obj_t)&pybsleep_locals_dict,
|
||||
};
|
||||
|
||||
const mp_obj_base_t pyb_sleep_obj = {&pybsleep_type};
|
||||
|
||||
@@ -54,23 +54,20 @@ typedef enum {
|
||||
|
||||
typedef void (*WakeUpCB_t)(const mp_obj_t self);
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE EXPORTED VARIABLES
|
||||
******************************************************************************/
|
||||
extern const mp_obj_base_t pyb_sleep_obj;
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE FUNCTIONS
|
||||
******************************************************************************/
|
||||
void pybsleep_pre_init (void);
|
||||
void pybsleep_init0 (void);
|
||||
void pybsleep_signal_soft_reset (void);
|
||||
void pybsleep_add (const mp_obj_t obj, WakeUpCB_t wakeup);
|
||||
void pybsleep_remove (const mp_obj_t obj);
|
||||
void pybsleep_set_wlan_lpds_callback (mp_obj_t cb_obj);
|
||||
void pybsleep_set_gpio_lpds_callback (mp_obj_t cb_obj);
|
||||
void pybsleep_set_timer_lpds_callback (mp_obj_t cb_obj);
|
||||
void pybsleep_configure_timer_wakeup (uint pwrmode);
|
||||
pybsleep_reset_cause_t pybsleep_get_reset_cause (void);
|
||||
void pyb_sleep_pre_init (void);
|
||||
void pyb_sleep_init0 (void);
|
||||
void pyb_sleep_signal_soft_reset (void);
|
||||
void pyb_sleep_add (const mp_obj_t obj, WakeUpCB_t wakeup);
|
||||
void pyb_sleep_remove (const mp_obj_t obj);
|
||||
void pyb_sleep_set_gpio_lpds_callback (mp_obj_t cb_obj);
|
||||
void pyb_sleep_set_wlan_obj (mp_obj_t wlan_obj);
|
||||
void pyb_sleep_set_rtc_obj (mp_obj_t rtc_obj);
|
||||
void pyb_sleep_sleep (void);
|
||||
void pyb_sleep_deepsleep (void);
|
||||
pybsleep_reset_cause_t pyb_sleep_get_reset_cause (void);
|
||||
pybsleep_wake_reason_t pyb_sleep_get_wake_reason (void);
|
||||
|
||||
#endif /* PYBSLEEP_H_ */
|
||||
|
||||
@@ -201,24 +201,20 @@ STATIC mp_obj_t pyb_spi_init_helper(pyb_spi_obj_t *self, const mp_arg_val_t *arg
|
||||
mp_obj_t pins_o = args[6].u_obj;
|
||||
if (pins_o != mp_const_none) {
|
||||
mp_obj_t *pins;
|
||||
mp_uint_t n_pins = 3;
|
||||
if (pins_o == MP_OBJ_NULL) {
|
||||
// use the default pins
|
||||
pins = (mp_obj_t *)pyb_spi_def_pin;
|
||||
} else {
|
||||
mp_obj_get_array(pins_o, &n_pins, &pins);
|
||||
if (n_pins != 3) {
|
||||
goto invalid_args;
|
||||
}
|
||||
mp_obj_get_array_fixed_n(pins_o, 3, &pins);
|
||||
}
|
||||
pin_assign_pins_af (pins, n_pins, PIN_TYPE_STD_PU, PIN_FN_SPI, 0);
|
||||
pin_assign_pins_af (pins, 3, PIN_TYPE_STD_PU, PIN_FN_SPI, 0);
|
||||
}
|
||||
|
||||
// init the bus
|
||||
pybspi_init((const pyb_spi_obj_t *)self);
|
||||
|
||||
// register it with the sleep module
|
||||
pybsleep_add((const mp_obj_t)self, (WakeUpCB_t)pybspi_init);
|
||||
pyb_sleep_add((const mp_obj_t)self, (WakeUpCB_t)pybspi_init);
|
||||
|
||||
return mp_const_none;
|
||||
|
||||
@@ -275,7 +271,7 @@ STATIC mp_obj_t pyb_spi_deinit(mp_obj_t self_in) {
|
||||
// invalidate the baudrate
|
||||
pyb_spi_obj.baudrate = 0;
|
||||
// unregister it with the sleep module
|
||||
pybsleep_remove((const mp_obj_t)self_in);
|
||||
pyb_sleep_remove((const mp_obj_t)self_in);
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_spi_deinit_obj, pyb_spi_deinit);
|
||||
|
||||
@@ -44,8 +44,8 @@
|
||||
#include "prcm.h"
|
||||
#include "timer.h"
|
||||
#include "pybtimer.h"
|
||||
#include "mpirq.h"
|
||||
#include "pybsleep.h"
|
||||
#include "mpcallback.h"
|
||||
#include "mpexception.h"
|
||||
|
||||
|
||||
@@ -96,7 +96,8 @@ typedef struct _pyb_timer_obj_t {
|
||||
mp_obj_base_t base;
|
||||
uint32_t timer;
|
||||
uint32_t config;
|
||||
uint16_t intflags;
|
||||
uint16_t irq_trigger;
|
||||
uint16_t irq_flags;
|
||||
uint8_t peripheral;
|
||||
uint8_t id;
|
||||
} pyb_timer_obj_t;
|
||||
@@ -114,7 +115,7 @@ typedef struct _pyb_timer_channel_obj_t {
|
||||
/******************************************************************************
|
||||
DEFINE PRIVATE DATA
|
||||
******************************************************************************/
|
||||
STATIC const mp_cb_methods_t pyb_timer_channel_cb_methods;
|
||||
STATIC const mp_irq_methods_t pyb_timer_channel_irq_methods;
|
||||
STATIC pyb_timer_obj_t pyb_timer_obj[PYBTIMER_NUM_TIMERS] = {{.timer = TIMERA0_BASE, .peripheral = PRCM_TIMERA0},
|
||||
{.timer = TIMERA1_BASE, .peripheral = PRCM_TIMERA1},
|
||||
{.timer = TIMERA2_BASE, .peripheral = PRCM_TIMERA2},
|
||||
@@ -124,7 +125,7 @@ STATIC const mp_obj_type_t pyb_timer_channel_type;
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE FUNCTIONS
|
||||
******************************************************************************/
|
||||
STATIC mp_obj_t pyb_timer_channel_callback (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
STATIC mp_obj_t pyb_timer_channel_irq (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
|
||||
STATIC void timer_disable (pyb_timer_obj_t *tim);
|
||||
STATIC void TIMER0AIntHandler(void);
|
||||
STATIC void TIMER0BIntHandler(void);
|
||||
@@ -142,18 +143,26 @@ void timer_init0 (void) {
|
||||
mp_obj_list_init(&MP_STATE_PORT(pyb_timer_channel_obj_list), 0);
|
||||
}
|
||||
|
||||
void pyb_timer_channel_callback_enable (mp_obj_t self_in) {
|
||||
/******************************************************************************
|
||||
DEFINE PRIVATE FUNCTIONS
|
||||
******************************************************************************/
|
||||
STATIC void pyb_timer_channel_irq_enable (mp_obj_t self_in) {
|
||||
pyb_timer_channel_obj_t *self = self_in;
|
||||
MAP_TimerIntClear(self->timer->timer, self->timer->intflags & self->channel);
|
||||
MAP_TimerIntEnable(self->timer->timer, self->timer->intflags & self->channel);
|
||||
MAP_TimerIntClear(self->timer->timer, self->timer->irq_trigger & self->channel);
|
||||
MAP_TimerIntEnable(self->timer->timer, self->timer->irq_trigger & self->channel);
|
||||
}
|
||||
|
||||
void pyb_timer_channel_callback_disable (mp_obj_t self_in) {
|
||||
STATIC void pyb_timer_channel_irq_disable (mp_obj_t self_in) {
|
||||
pyb_timer_channel_obj_t *self = self_in;
|
||||
MAP_TimerIntDisable(self->timer->timer, self->timer->intflags & self->channel);
|
||||
MAP_TimerIntDisable(self->timer->timer, self->timer->irq_trigger & self->channel);
|
||||
}
|
||||
|
||||
pyb_timer_channel_obj_t *pyb_timer_channel_find (uint32_t timer, uint16_t channel_n) {
|
||||
STATIC int pyb_timer_channel_irq_flags (mp_obj_t self_in) {
|
||||
pyb_timer_channel_obj_t *self = self_in;
|
||||
return self->timer->irq_flags;
|
||||
}
|
||||
|
||||
STATIC pyb_timer_channel_obj_t *pyb_timer_channel_find (uint32_t timer, uint16_t channel_n) {
|
||||
for (mp_uint_t i = 0; i < MP_STATE_PORT(pyb_timer_channel_obj_list).len; i++) {
|
||||
pyb_timer_channel_obj_t *ch = ((pyb_timer_channel_obj_t *)(MP_STATE_PORT(pyb_timer_channel_obj_list).items[i]));
|
||||
// any 32-bit timer must be matched by any of its 16-bit versions
|
||||
@@ -164,14 +173,14 @@ pyb_timer_channel_obj_t *pyb_timer_channel_find (uint32_t timer, uint16_t channe
|
||||
return MP_OBJ_NULL;
|
||||
}
|
||||
|
||||
void pyb_timer_channel_remove (pyb_timer_channel_obj_t *ch) {
|
||||
STATIC void pyb_timer_channel_remove (pyb_timer_channel_obj_t *ch) {
|
||||
pyb_timer_channel_obj_t *channel;
|
||||
if ((channel = pyb_timer_channel_find(ch->timer->timer, ch->channel))) {
|
||||
mp_obj_list_remove(&MP_STATE_PORT(pyb_timer_channel_obj_list), channel);
|
||||
}
|
||||
}
|
||||
|
||||
void pyb_timer_channel_add (pyb_timer_channel_obj_t *ch) {
|
||||
STATIC void pyb_timer_channel_add (pyb_timer_channel_obj_t *ch) {
|
||||
// remove it in case it already exists
|
||||
pyb_timer_channel_remove(ch);
|
||||
mp_obj_list_append(&MP_STATE_PORT(pyb_timer_channel_obj_list), ch);
|
||||
@@ -180,8 +189,8 @@ void pyb_timer_channel_add (pyb_timer_channel_obj_t *ch) {
|
||||
STATIC void timer_disable (pyb_timer_obj_t *tim) {
|
||||
// disable all timers and it's interrupts
|
||||
MAP_TimerDisable(tim->timer, TIMER_A | TIMER_B);
|
||||
MAP_TimerIntDisable(tim->timer, tim->intflags);
|
||||
MAP_TimerIntClear(tim->timer, tim->intflags);
|
||||
MAP_TimerIntDisable(tim->timer, tim->irq_trigger);
|
||||
MAP_TimerIntClear(tim->timer, tim->irq_trigger);
|
||||
MAP_PRCMPeripheralClkDisable(tim->peripheral, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK);
|
||||
memset(&pyb_timer_obj[tim->id], 0, sizeof(pyb_timer_obj_t));
|
||||
}
|
||||
@@ -335,7 +344,7 @@ STATIC mp_obj_t pyb_timer_init_helper(pyb_timer_obj_t *tim, mp_uint_t n_args, co
|
||||
|
||||
timer_init(tim);
|
||||
// register it with the sleep module
|
||||
pybsleep_add ((const mp_obj_t)tim, (WakeUpCB_t)timer_init);
|
||||
pyb_sleep_add ((const mp_obj_t)tim, (WakeUpCB_t)timer_init);
|
||||
|
||||
return mp_const_none;
|
||||
|
||||
@@ -470,7 +479,7 @@ STATIC mp_obj_t pyb_timer_channel(mp_uint_t n_args, const mp_obj_t *pos_args, mp
|
||||
timer_channel_init(ch);
|
||||
|
||||
// register it with the sleep module
|
||||
pybsleep_add ((const mp_obj_t)ch, (WakeUpCB_t)timer_channel_init);
|
||||
pyb_sleep_add ((const mp_obj_t)ch, (WakeUpCB_t)timer_channel_init);
|
||||
|
||||
// add the timer to the list
|
||||
pyb_timer_channel_add(ch);
|
||||
@@ -509,10 +518,11 @@ const mp_obj_type_t pyb_timer_type = {
|
||||
.locals_dict = (mp_obj_t)&pyb_timer_locals_dict,
|
||||
};
|
||||
|
||||
STATIC const mp_cb_methods_t pyb_timer_channel_cb_methods = {
|
||||
.init = pyb_timer_channel_callback,
|
||||
.enable = pyb_timer_channel_callback_enable,
|
||||
.disable = pyb_timer_channel_callback_disable,
|
||||
STATIC const mp_irq_methods_t pyb_timer_channel_irq_methods = {
|
||||
.init = pyb_timer_channel_irq,
|
||||
.enable = pyb_timer_channel_irq_enable,
|
||||
.disable = pyb_timer_channel_irq_disable,
|
||||
.flags = pyb_timer_channel_irq_flags,
|
||||
};
|
||||
|
||||
STATIC void TIMERGenericIntHandler(uint32_t timer, uint16_t channel) {
|
||||
@@ -522,8 +532,7 @@ STATIC void TIMERGenericIntHandler(uint32_t timer, uint16_t channel) {
|
||||
if ((self = pyb_timer_channel_find(timer, channel))) {
|
||||
status = MAP_TimerIntStatus(self->timer->timer, true) & self->channel;
|
||||
MAP_TimerIntClear(self->timer->timer, status);
|
||||
mp_obj_t _callback = mpcallback_find(self);
|
||||
mpcallback_handler(_callback);
|
||||
mp_irq_handler(mp_irq_find(self));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -716,130 +725,107 @@ STATIC mp_obj_t pyb_timer_channel_duty_cycle(mp_uint_t n_args, const mp_obj_t *a
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_timer_channel_duty_cycle_obj, 1, 3, pyb_timer_channel_duty_cycle);
|
||||
|
||||
/// \method callback(handler, priority, value)
|
||||
/// create a callback object associated with the timer channel
|
||||
STATIC mp_obj_t pyb_timer_channel_callback (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
mp_arg_val_t args[mpcallback_INIT_NUM_ARGS];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, mpcallback_INIT_NUM_ARGS, mpcallback_init_args, args);
|
||||
|
||||
/// \method irq(trigger, priority, handler, wake)
|
||||
/// FIXME triggers!!
|
||||
STATIC mp_obj_t pyb_timer_channel_irq (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
mp_arg_val_t args[mp_irq_INIT_NUM_ARGS];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, mp_irq_INIT_NUM_ARGS, mp_irq_init_args, args);
|
||||
pyb_timer_channel_obj_t *ch = pos_args[0];
|
||||
mp_obj_t _callback = mpcallback_find(ch);
|
||||
if (kw_args->used > 0) {
|
||||
// convert the priority to the correct value
|
||||
uint priority = mpcallback_translate_priority (args[2].u_int);
|
||||
|
||||
// validate the power mode
|
||||
uint pwrmode = args[4].u_int;
|
||||
if (pwrmode != PYB_PWR_MODE_ACTIVE) {
|
||||
goto invalid_args;
|
||||
}
|
||||
// convert the priority to the correct value
|
||||
uint priority = mp_irq_translate_priority (args[1].u_int);
|
||||
|
||||
uint32_t _config = (ch->channel == TIMER_B) ? ((ch->timer->config & TIMER_B) >> 8) : (ch->timer->config & TIMER_A);
|
||||
uint32_t c_value = mp_obj_get_int(args[3].u_obj);
|
||||
|
||||
// validate and set the value if we are in edge count mode
|
||||
if (_config == TIMER_CFG_A_CAP_COUNT) {
|
||||
if (!c_value || c_value > 0xFFFF) {
|
||||
// zero or exceeds the maximum value of a 16-bit timer
|
||||
goto invalid_args;
|
||||
}
|
||||
MAP_TimerMatchSet(ch->timer->timer, ch->channel, c_value);
|
||||
}
|
||||
|
||||
// disable the callback first
|
||||
pyb_timer_channel_callback_disable(ch);
|
||||
|
||||
uint8_t shift = (ch->channel == TIMER_B) ? 8 : 0;
|
||||
switch (_config) {
|
||||
case TIMER_CFG_A_ONE_SHOT:
|
||||
case TIMER_CFG_A_PERIODIC:
|
||||
ch->timer->intflags |= TIMER_TIMA_TIMEOUT << shift;
|
||||
break;
|
||||
case TIMER_CFG_A_CAP_COUNT:
|
||||
ch->timer->intflags |= TIMER_CAPA_MATCH << shift;
|
||||
// set the match value and make 1 the minimum
|
||||
MAP_TimerMatchSet(ch->timer->timer, ch->channel, MAX(1, c_value));
|
||||
break;
|
||||
case TIMER_CFG_A_CAP_TIME:
|
||||
ch->timer->intflags |= TIMER_CAPA_EVENT << shift;
|
||||
break;
|
||||
case TIMER_CFG_A_PWM:
|
||||
// special case for the PWM match interrupt
|
||||
ch->timer->intflags |= ((ch->channel & TIMER_A) == TIMER_A) ? TIMER_TIMA_MATCH : TIMER_TIMB_MATCH;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// special case for a 32-bit timer
|
||||
if (ch->channel == (TIMER_A | TIMER_B)) {
|
||||
ch->timer->intflags |= (ch->timer->intflags << 8);
|
||||
}
|
||||
|
||||
void (*pfnHandler)(void);
|
||||
uint32_t intregister;
|
||||
switch (ch->timer->timer) {
|
||||
case TIMERA0_BASE:
|
||||
if (ch->channel == TIMER_B) {
|
||||
pfnHandler = &TIMER0BIntHandler;
|
||||
intregister = INT_TIMERA0B;
|
||||
} else {
|
||||
pfnHandler = &TIMER0AIntHandler;
|
||||
intregister = INT_TIMERA0A;
|
||||
}
|
||||
break;
|
||||
case TIMERA1_BASE:
|
||||
if (ch->channel == TIMER_B) {
|
||||
pfnHandler = &TIMER1BIntHandler;
|
||||
intregister = INT_TIMERA1B;
|
||||
} else {
|
||||
pfnHandler = &TIMER1AIntHandler;
|
||||
intregister = INT_TIMERA1A;
|
||||
}
|
||||
break;
|
||||
case TIMERA2_BASE:
|
||||
if (ch->channel == TIMER_B) {
|
||||
pfnHandler = &TIMER2BIntHandler;
|
||||
intregister = INT_TIMERA2B;
|
||||
} else {
|
||||
pfnHandler = &TIMER2AIntHandler;
|
||||
intregister = INT_TIMERA2A;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (ch->channel == TIMER_B) {
|
||||
pfnHandler = &TIMER3BIntHandler;
|
||||
intregister = INT_TIMERA3B;
|
||||
} else {
|
||||
pfnHandler = &TIMER3AIntHandler;
|
||||
intregister = INT_TIMERA3A;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// register the interrupt and configure the priority
|
||||
MAP_IntPrioritySet(intregister, priority);
|
||||
MAP_TimerIntRegister(ch->timer->timer, ch->channel, pfnHandler);
|
||||
|
||||
// create the callback
|
||||
_callback = mpcallback_new (ch, args[1].u_obj, &pyb_timer_channel_cb_methods, true);
|
||||
|
||||
// reload the timer
|
||||
uint32_t period_c;
|
||||
uint32_t match;
|
||||
compute_prescaler_period_and_match_value(ch, &period_c, &match);
|
||||
MAP_TimerLoadSet(ch->timer->timer, ch->channel, period_c);
|
||||
|
||||
// enable the callback before returning
|
||||
pyb_timer_channel_callback_enable(ch);
|
||||
} else if (!_callback) {
|
||||
_callback = mpcallback_new (ch, mp_const_none, &pyb_timer_channel_cb_methods, false);
|
||||
// validate the power mode
|
||||
uint8_t pwrmode = (args[3].u_obj == mp_const_none) ? PYB_PWR_MODE_ACTIVE : mp_obj_get_int(args[3].u_obj);
|
||||
if (pwrmode != PYB_PWR_MODE_ACTIVE) {
|
||||
goto invalid_args;
|
||||
}
|
||||
return _callback;
|
||||
|
||||
// disable the callback first
|
||||
pyb_timer_channel_irq_disable(ch);
|
||||
|
||||
uint8_t shift = (ch->channel == TIMER_B) ? 8 : 0;
|
||||
uint32_t _config = (ch->channel == TIMER_B) ? ((ch->timer->config & TIMER_B) >> 8) : (ch->timer->config & TIMER_A);
|
||||
switch (_config) {
|
||||
case TIMER_CFG_A_ONE_SHOT:
|
||||
case TIMER_CFG_A_PERIODIC:
|
||||
ch->timer->irq_trigger |= TIMER_TIMA_TIMEOUT << shift;
|
||||
break;
|
||||
case TIMER_CFG_A_CAP_COUNT:
|
||||
ch->timer->irq_trigger |= TIMER_CAPA_MATCH << shift;
|
||||
break;
|
||||
case TIMER_CFG_A_CAP_TIME:
|
||||
ch->timer->irq_trigger |= TIMER_CAPA_EVENT << shift;
|
||||
break;
|
||||
case TIMER_CFG_A_PWM:
|
||||
// special case for the PWM match interrupt
|
||||
ch->timer->irq_trigger |= ((ch->channel & TIMER_A) == TIMER_A) ? TIMER_TIMA_MATCH : TIMER_TIMB_MATCH;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// special case for a 32-bit timer
|
||||
if (ch->channel == (TIMER_A | TIMER_B)) {
|
||||
ch->timer->irq_trigger |= (ch->timer->irq_trigger << 8);
|
||||
}
|
||||
|
||||
void (*pfnHandler)(void);
|
||||
uint32_t intregister;
|
||||
switch (ch->timer->timer) {
|
||||
case TIMERA0_BASE:
|
||||
if (ch->channel == TIMER_B) {
|
||||
pfnHandler = &TIMER0BIntHandler;
|
||||
intregister = INT_TIMERA0B;
|
||||
} else {
|
||||
pfnHandler = &TIMER0AIntHandler;
|
||||
intregister = INT_TIMERA0A;
|
||||
}
|
||||
break;
|
||||
case TIMERA1_BASE:
|
||||
if (ch->channel == TIMER_B) {
|
||||
pfnHandler = &TIMER1BIntHandler;
|
||||
intregister = INT_TIMERA1B;
|
||||
} else {
|
||||
pfnHandler = &TIMER1AIntHandler;
|
||||
intregister = INT_TIMERA1A;
|
||||
}
|
||||
break;
|
||||
case TIMERA2_BASE:
|
||||
if (ch->channel == TIMER_B) {
|
||||
pfnHandler = &TIMER2BIntHandler;
|
||||
intregister = INT_TIMERA2B;
|
||||
} else {
|
||||
pfnHandler = &TIMER2AIntHandler;
|
||||
intregister = INT_TIMERA2A;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (ch->channel == TIMER_B) {
|
||||
pfnHandler = &TIMER3BIntHandler;
|
||||
intregister = INT_TIMERA3B;
|
||||
} else {
|
||||
pfnHandler = &TIMER3AIntHandler;
|
||||
intregister = INT_TIMERA3A;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// register the interrupt and configure the priority
|
||||
MAP_IntPrioritySet(intregister, priority);
|
||||
MAP_TimerIntRegister(ch->timer->timer, ch->channel, pfnHandler);
|
||||
|
||||
// create the callback
|
||||
mp_obj_t _irq = mp_irq_new (ch, args[2].u_obj, &pyb_timer_channel_irq_methods);
|
||||
|
||||
// enable the callback before returning
|
||||
pyb_timer_channel_irq_enable(ch);
|
||||
|
||||
return _irq;
|
||||
|
||||
invalid_args:
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_timer_channel_callback_obj, 1, pyb_timer_channel_callback);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_timer_channel_irq_obj, 1, pyb_timer_channel_irq);
|
||||
|
||||
STATIC const mp_map_elem_t pyb_timer_channel_locals_dict_table[] = {
|
||||
// instance methods
|
||||
@@ -849,7 +835,7 @@ STATIC const mp_map_elem_t pyb_timer_channel_locals_dict_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_event_count), (mp_obj_t)&pyb_timer_channel_event_count_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_event_time), (mp_obj_t)&pyb_timer_channel_event_time_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_duty_cycle), (mp_obj_t)&pyb_timer_channel_duty_cycle_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_callback), (mp_obj_t)&pyb_timer_channel_callback_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_irq), (mp_obj_t)&pyb_timer_channel_irq_obj },
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(pyb_timer_channel_locals_dict, pyb_timer_channel_locals_dict_table);
|
||||
|
||||
|
||||
@@ -45,9 +45,9 @@
|
||||
#include "prcm.h"
|
||||
#include "uart.h"
|
||||
#include "pybuart.h"
|
||||
#include "mpirq.h"
|
||||
#include "pybioctl.h"
|
||||
#include "pybsleep.h"
|
||||
#include "mpcallback.h"
|
||||
#include "mpexception.h"
|
||||
#include "py/mpstate.h"
|
||||
#include "osi.h"
|
||||
@@ -55,6 +55,7 @@
|
||||
#include "pin.h"
|
||||
#include "pybpin.h"
|
||||
#include "pins.h"
|
||||
#include "moduos.h"
|
||||
|
||||
/// \moduleref pyb
|
||||
/// \class UART - duplex serial communication bus
|
||||
@@ -64,18 +65,18 @@
|
||||
*******-***********************************************************************/
|
||||
#define PYBUART_FRAME_TIME_US(baud) ((11 * 1000000) / baud)
|
||||
#define PYBUART_2_FRAMES_TIME_US(baud) (PYBUART_FRAME_TIME_US(baud) * 2)
|
||||
#define PYBUART_RX_TIMEOUT_US(baud) (PYBUART_2_FRAMES_TIME_US(baud))
|
||||
#define PYBUART_RX_TIMEOUT_US(baud) (PYBUART_2_FRAMES_TIME_US(baud) * 8) // we need at least characters in the FIFO
|
||||
|
||||
#define PYBUART_TX_WAIT_US(baud) ((PYBUART_FRAME_TIME_US(baud)) + 1)
|
||||
#define PYBUART_TX_MAX_TIMEOUT_MS (5)
|
||||
|
||||
#define PYBUART_RX_BUFFER_LEN (128)
|
||||
#define PYBUART_RX_BUFFER_LEN (256)
|
||||
|
||||
// interrupt triggers
|
||||
#define E_UART_TRIGGER_RX_ANY (0x01)
|
||||
#define E_UART_TRIGGER_RX_HALF (0x02)
|
||||
#define E_UART_TRIGGER_RX_FULL (0x04)
|
||||
#define E_UART_TRIGGER_TX_DONE (0x08)
|
||||
#define UART_TRIGGER_RX_ANY (0x01)
|
||||
#define UART_TRIGGER_RX_HALF (0x02)
|
||||
#define UART_TRIGGER_RX_FULL (0x04)
|
||||
#define UART_TRIGGER_TX_DONE (0x08)
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE FUNCTIONS
|
||||
@@ -83,12 +84,12 @@
|
||||
STATIC void uart_init (pyb_uart_obj_t *self);
|
||||
STATIC bool uart_rx_wait (pyb_uart_obj_t *self);
|
||||
STATIC void uart_check_init(pyb_uart_obj_t *self);
|
||||
STATIC mp_obj_t uart_irq_new (pyb_uart_obj_t *self, byte trigger, mp_int_t priority, mp_obj_t handler);
|
||||
STATIC void UARTGenericIntHandler(uint32_t uart_id);
|
||||
STATIC void UART0IntHandler(void);
|
||||
STATIC void UART1IntHandler(void);
|
||||
STATIC void uart_callback_enable (mp_obj_t self_in);
|
||||
STATIC void uart_callback_disable (mp_obj_t self_in);
|
||||
STATIC mp_obj_t pyb_uart_deinit(mp_obj_t self_in);
|
||||
STATIC void uart_irq_enable (mp_obj_t self_in);
|
||||
STATIC void uart_irq_disable (mp_obj_t self_in);
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PRIVATE TYPES
|
||||
@@ -105,7 +106,8 @@ struct _pyb_uart_obj_t {
|
||||
uint16_t read_buf_tail; // indexes first full slot (not full if equals head)
|
||||
byte peripheral;
|
||||
byte irq_trigger;
|
||||
bool callback_enabled;
|
||||
bool irq_enabled;
|
||||
byte irq_flags;
|
||||
};
|
||||
|
||||
/******************************************************************************
|
||||
@@ -113,7 +115,7 @@ struct _pyb_uart_obj_t {
|
||||
******************************************************************************/
|
||||
STATIC pyb_uart_obj_t pyb_uart_obj[PYB_NUM_UARTS] = { {.reg = UARTA0_BASE, .baudrate = 0, .read_buf = NULL, .peripheral = PRCM_UARTA0},
|
||||
{.reg = UARTA1_BASE, .baudrate = 0, .read_buf = NULL, .peripheral = PRCM_UARTA1} };
|
||||
STATIC const mp_cb_methods_t uart_cb_methods;
|
||||
STATIC const mp_irq_methods_t uart_irq_methods;
|
||||
|
||||
STATIC const mp_obj_t pyb_uart_def_pin[PYB_NUM_UARTS][2] = { {&pin_GP1, &pin_GP2}, {&pin_GP3, &pin_GP4} };
|
||||
|
||||
@@ -167,37 +169,6 @@ bool uart_tx_strn(pyb_uart_obj_t *self, const char *str, uint len) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void uart_tx_strn_cooked(pyb_uart_obj_t *self, const char *str, uint len) {
|
||||
for (const char *top = str + len; str < top; str++) {
|
||||
if (*str == '\n') {
|
||||
uart_tx_char(self, '\r');
|
||||
}
|
||||
uart_tx_char(self, *str);
|
||||
}
|
||||
}
|
||||
|
||||
mp_obj_t uart_callback_new (pyb_uart_obj_t *self, mp_obj_t handler, mp_int_t priority, byte trigger) {
|
||||
// disable the uart interrupts before updating anything
|
||||
uart_callback_disable (self);
|
||||
|
||||
if (self->uart_id == PYB_UART_0) {
|
||||
MAP_IntPrioritySet(INT_UARTA0, priority);
|
||||
MAP_UARTIntRegister(self->reg, UART0IntHandler);
|
||||
} else {
|
||||
MAP_IntPrioritySet(INT_UARTA1, priority);
|
||||
MAP_UARTIntRegister(self->reg, UART1IntHandler);
|
||||
}
|
||||
|
||||
// create the callback
|
||||
mp_obj_t _callback = mpcallback_new ((mp_obj_t)self, handler, &uart_cb_methods, true);
|
||||
|
||||
// enable the interrupts now
|
||||
self->irq_trigger = trigger;
|
||||
uart_callback_enable (self);
|
||||
|
||||
return _callback;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PRIVATE FUNCTIONS
|
||||
******************************************************************************/
|
||||
@@ -248,24 +219,44 @@ STATIC bool uart_rx_wait (pyb_uart_obj_t *self) {
|
||||
}
|
||||
}
|
||||
|
||||
STATIC mp_obj_t uart_irq_new (pyb_uart_obj_t *self, byte trigger, mp_int_t priority, mp_obj_t handler) {
|
||||
// disable the uart interrupts before updating anything
|
||||
uart_irq_disable (self);
|
||||
|
||||
if (self->uart_id == PYB_UART_0) {
|
||||
MAP_IntPrioritySet(INT_UARTA0, priority);
|
||||
MAP_UARTIntRegister(self->reg, UART0IntHandler);
|
||||
} else {
|
||||
MAP_IntPrioritySet(INT_UARTA1, priority);
|
||||
MAP_UARTIntRegister(self->reg, UART1IntHandler);
|
||||
}
|
||||
|
||||
// create the callback
|
||||
mp_obj_t _irq = mp_irq_new ((mp_obj_t)self, handler, &uart_irq_methods);
|
||||
|
||||
// enable the interrupts now
|
||||
self->irq_trigger = trigger;
|
||||
uart_irq_enable (self);
|
||||
return _irq;
|
||||
}
|
||||
|
||||
STATIC void UARTGenericIntHandler(uint32_t uart_id) {
|
||||
pyb_uart_obj_t *self;
|
||||
uint32_t status;
|
||||
bool exec_callback = false;
|
||||
|
||||
self = &pyb_uart_obj[uart_id];
|
||||
status = MAP_UARTIntStatus(self->reg, true);
|
||||
// receive interrupt
|
||||
if (status & (UART_INT_RX | UART_INT_RT)) {
|
||||
// set the flags
|
||||
self->irq_flags = UART_TRIGGER_RX_ANY;
|
||||
MAP_UARTIntClear(self->reg, UART_INT_RX | UART_INT_RT);
|
||||
while (UARTCharsAvail(self->reg)) {
|
||||
int data = MAP_UARTCharGetNonBlocking(self->reg);
|
||||
if (pyb_stdio_uart == self && data == user_interrupt_char) {
|
||||
if (MP_STATE_PORT(os_term_dup_obj) && MP_STATE_PORT(os_term_dup_obj)->stream_o == self && data == user_interrupt_char) {
|
||||
// raise an exception when interrupts are finished
|
||||
mpexception_keyboard_nlr_jump();
|
||||
}
|
||||
// there's always a read buffer available
|
||||
else {
|
||||
} else { // there's always a read buffer available
|
||||
uint16_t next_head = (self->read_buf_head + 1) % PYBUART_RX_BUFFER_LEN;
|
||||
if (next_head != self->read_buf_tail) {
|
||||
// only store data if room in buf
|
||||
@@ -274,17 +265,16 @@ STATIC void UARTGenericIntHandler(uint32_t uart_id) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (self->irq_trigger & E_UART_TRIGGER_RX_ANY) {
|
||||
exec_callback = true;
|
||||
}
|
||||
|
||||
if (exec_callback && self->callback_enabled) {
|
||||
// call the user defined handler
|
||||
mp_obj_t _callback = mpcallback_find(self);
|
||||
mpcallback_handler(_callback);
|
||||
}
|
||||
}
|
||||
|
||||
// check the flags to see if the user handler should be called
|
||||
if ((self->irq_trigger & self->irq_flags) && self->irq_enabled) {
|
||||
// call the user defined handler
|
||||
mp_irq_handler(mp_irq_find(self));
|
||||
}
|
||||
|
||||
// clear the flags
|
||||
self->irq_flags = 0;
|
||||
}
|
||||
|
||||
STATIC void uart_check_init(pyb_uart_obj_t *self) {
|
||||
@@ -302,19 +292,24 @@ STATIC void UART1IntHandler(void) {
|
||||
UARTGenericIntHandler(1);
|
||||
}
|
||||
|
||||
STATIC void uart_callback_enable (mp_obj_t self_in) {
|
||||
STATIC void uart_irq_enable (mp_obj_t self_in) {
|
||||
pyb_uart_obj_t *self = self_in;
|
||||
// check for any of the rx interrupt types
|
||||
if (self->irq_trigger & (E_UART_TRIGGER_RX_ANY | E_UART_TRIGGER_RX_HALF | E_UART_TRIGGER_RX_FULL)) {
|
||||
if (self->irq_trigger & (UART_TRIGGER_RX_ANY | UART_TRIGGER_RX_HALF | UART_TRIGGER_RX_FULL)) {
|
||||
MAP_UARTIntClear(self->reg, UART_INT_RX | UART_INT_RT);
|
||||
MAP_UARTIntEnable(self->reg, UART_INT_RX | UART_INT_RT);
|
||||
}
|
||||
self->callback_enabled = true;
|
||||
self->irq_enabled = true;
|
||||
}
|
||||
|
||||
STATIC void uart_callback_disable (mp_obj_t self_in) {
|
||||
STATIC void uart_irq_disable (mp_obj_t self_in) {
|
||||
pyb_uart_obj_t *self = self_in;
|
||||
self->callback_enabled = false;
|
||||
self->irq_enabled = false;
|
||||
}
|
||||
|
||||
STATIC int uart_irq_flags (mp_obj_t self_in) {
|
||||
pyb_uart_obj_t *self = self_in;
|
||||
return self->irq_flags;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
@@ -428,9 +423,11 @@ STATIC mp_obj_t pyb_uart_init_helper(pyb_uart_obj_t *self, const mp_arg_val_t *a
|
||||
// initialize and enable the uart
|
||||
uart_init (self);
|
||||
// register it with the sleep module
|
||||
pybsleep_add ((const mp_obj_t)self, (WakeUpCB_t)uart_init);
|
||||
pyb_sleep_add ((const mp_obj_t)self, (WakeUpCB_t)uart_init);
|
||||
// enable the callback
|
||||
uart_callback_new (self, mp_const_none, INT_PRIORITY_LVL_3, E_UART_TRIGGER_RX_ANY);
|
||||
uart_irq_new (self, UART_TRIGGER_RX_ANY, INT_PRIORITY_LVL_3, mp_const_none);
|
||||
// disable the irq (from the user point of view)
|
||||
uart_irq_disable(self);
|
||||
|
||||
return mp_const_none;
|
||||
|
||||
@@ -439,7 +436,7 @@ error:
|
||||
}
|
||||
|
||||
STATIC const mp_arg_t pyb_uart_init_args[] = {
|
||||
{ MP_QSTR_id, MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||
{ MP_QSTR_id, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
|
||||
{ MP_QSTR_baudrate, MP_ARG_INT, {.u_int = 9600} },
|
||||
{ MP_QSTR_bits, MP_ARG_INT, {.u_int = 8} },
|
||||
{ MP_QSTR_parity, MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||
@@ -455,7 +452,7 @@ STATIC mp_obj_t pyb_uart_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t
|
||||
|
||||
// work out the uart id
|
||||
uint uart_id;
|
||||
if (args[0].u_obj == mp_const_none) {
|
||||
if (args[0].u_obj == MP_OBJ_NULL) {
|
||||
if (args[5].u_obj != MP_OBJ_NULL) {
|
||||
mp_obj_t *pins;
|
||||
mp_uint_t n_pins = 2;
|
||||
@@ -501,7 +498,7 @@ STATIC mp_obj_t pyb_uart_deinit(mp_obj_t self_in) {
|
||||
pyb_uart_obj_t *self = self_in;
|
||||
|
||||
// unregister it with the sleep module
|
||||
pybsleep_remove (self);
|
||||
pyb_sleep_remove (self);
|
||||
// invalidate the baudrate
|
||||
self->baudrate = 0;
|
||||
// free the read buffer
|
||||
@@ -531,33 +528,37 @@ STATIC mp_obj_t pyb_uart_sendbreak(mp_obj_t self_in) {
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_uart_sendbreak_obj, pyb_uart_sendbreak);
|
||||
|
||||
STATIC mp_obj_t pyb_uart_callback (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
mp_arg_val_t args[mpcallback_INIT_NUM_ARGS];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, mpcallback_INIT_NUM_ARGS, mpcallback_init_args, args);
|
||||
/// \method irq(trigger, priority, handler, wake)
|
||||
STATIC mp_obj_t pyb_uart_irq (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
mp_arg_val_t args[mp_irq_INIT_NUM_ARGS];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, mp_irq_INIT_NUM_ARGS, mp_irq_init_args, args);
|
||||
|
||||
// check if any parameters were passed
|
||||
pyb_uart_obj_t *self = pos_args[0];
|
||||
uart_check_init(self);
|
||||
mp_obj_t _callback = mpcallback_find((mp_obj_t)self);
|
||||
if (kw_args->used > 0) {
|
||||
|
||||
// convert the priority to the correct value
|
||||
uint priority = mpcallback_translate_priority (args[2].u_int);
|
||||
// convert the priority to the correct value
|
||||
uint priority = mp_irq_translate_priority (args[1].u_int);
|
||||
|
||||
// check the power mode
|
||||
if (PYB_PWR_MODE_ACTIVE != args[4].u_int) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
|
||||
}
|
||||
|
||||
// register a new callback
|
||||
// FIXME triggers!!
|
||||
return uart_callback_new (self, args[1].u_obj, mp_obj_get_int(args[3].u_obj), priority);
|
||||
} else if (!_callback) {
|
||||
_callback = mpcallback_new (self, mp_const_none, &uart_cb_methods, false);
|
||||
// check the power mode
|
||||
uint8_t pwrmode = (args[3].u_obj == mp_const_none) ? PYB_PWR_MODE_ACTIVE : mp_obj_get_int(args[3].u_obj);
|
||||
if (PYB_PWR_MODE_ACTIVE != pwrmode) {
|
||||
goto invalid_args;
|
||||
}
|
||||
return _callback;
|
||||
|
||||
// check the trigger
|
||||
uint trigger = mp_obj_get_int(args[0].u_obj);
|
||||
if (!trigger || trigger > (UART_TRIGGER_RX_ANY | UART_TRIGGER_RX_HALF | UART_TRIGGER_RX_FULL | UART_TRIGGER_TX_DONE)) {
|
||||
goto invalid_args;
|
||||
}
|
||||
|
||||
// register a new callback
|
||||
return uart_irq_new (self, trigger, priority, args[2].u_obj);
|
||||
|
||||
invalid_args:
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_uart_callback_obj, 1, pyb_uart_callback);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_uart_irq_obj, 1, pyb_uart_irq);
|
||||
|
||||
STATIC const mp_map_elem_t pyb_uart_locals_dict_table[] = {
|
||||
// instance methods
|
||||
@@ -565,7 +566,7 @@ STATIC const mp_map_elem_t pyb_uart_locals_dict_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_deinit), (mp_obj_t)&pyb_uart_deinit_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_any), (mp_obj_t)&pyb_uart_any_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_sendbreak), (mp_obj_t)&pyb_uart_sendbreak_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_callback), (mp_obj_t)&pyb_uart_callback_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_irq), (mp_obj_t)&pyb_uart_irq_obj },
|
||||
|
||||
/// \method read([nbytes])
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_read), (mp_obj_t)&mp_stream_read_obj },
|
||||
@@ -581,7 +582,7 @@ STATIC const mp_map_elem_t pyb_uart_locals_dict_table[] = {
|
||||
// class constants
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_EVEN), MP_OBJ_NEW_SMALL_INT(UART_CONFIG_PAR_EVEN) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ODD), MP_OBJ_NEW_SMALL_INT(UART_CONFIG_PAR_ODD) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_RX_ANY), MP_OBJ_NEW_SMALL_INT(E_UART_TRIGGER_RX_ANY) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_RX_ANY), MP_OBJ_NEW_SMALL_INT(UART_TRIGGER_RX_ANY) },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(pyb_uart_locals_dict, pyb_uart_locals_dict_table);
|
||||
@@ -598,9 +599,9 @@ STATIC mp_uint_t pyb_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_t size, i
|
||||
|
||||
// wait for first char to become available
|
||||
if (!uart_rx_wait(self)) {
|
||||
// we can either return 0 to indicate EOF (then read() method returns b'')
|
||||
// or return EAGAIN error to indicate non-blocking (then read() method returns None)
|
||||
return 0;
|
||||
// return EAGAIN error to indicate non-blocking (then read() method returns None)
|
||||
*errcode = EAGAIN;
|
||||
return MP_STREAM_ERROR;
|
||||
}
|
||||
|
||||
// read the data
|
||||
@@ -654,10 +655,11 @@ STATIC const mp_stream_p_t uart_stream_p = {
|
||||
.is_text = false,
|
||||
};
|
||||
|
||||
STATIC const mp_cb_methods_t uart_cb_methods = {
|
||||
.init = pyb_uart_callback,
|
||||
.enable = uart_callback_enable,
|
||||
.disable = uart_callback_disable,
|
||||
STATIC const mp_irq_methods_t uart_irq_methods = {
|
||||
.init = pyb_uart_irq,
|
||||
.enable = uart_irq_enable,
|
||||
.disable = uart_irq_disable,
|
||||
.flags = uart_irq_flags
|
||||
};
|
||||
|
||||
const mp_obj_type_t pyb_uart_type = {
|
||||
|
||||
@@ -42,7 +42,5 @@ uint32_t uart_rx_any(pyb_uart_obj_t *uart_obj);
|
||||
int uart_rx_char(pyb_uart_obj_t *uart_obj);
|
||||
bool uart_tx_char(pyb_uart_obj_t *self, int c);
|
||||
bool uart_tx_strn(pyb_uart_obj_t *uart_obj, const char *str, uint len);
|
||||
void uart_tx_strn_cooked(pyb_uart_obj_t *uart_obj, const char *str, uint len);
|
||||
mp_obj_t uart_callback_new (pyb_uart_obj_t *self, mp_obj_t handler, mp_int_t priority, byte trigger);
|
||||
|
||||
#endif // PYBUART_H_
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
#define MICROPY_HELPER_REPL (1)
|
||||
#define MICROPY_ENABLE_SOURCE_LINE (1)
|
||||
#define MICROPY_ENABLE_DOC_STRING (0)
|
||||
#define MICROPY_REPL_AUTO_INDENT (1)
|
||||
#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_TERSE)
|
||||
#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ)
|
||||
#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_NONE)
|
||||
@@ -67,6 +68,7 @@
|
||||
#define MICROPY_MODULE_WEAK_LINKS (1)
|
||||
#define MICROPY_CAN_OVERRIDE_BUILTINS (1)
|
||||
#define MICROPY_PY_BUILTINS_TIMEOUTERROR (1)
|
||||
#define MICROPY_PY_ALL_SPECIAL_METHODS (1)
|
||||
#ifndef DEBUG
|
||||
#define MICROPY_PY_BUILTINS_STR_UNICODE (1)
|
||||
#define MICROPY_PY_BUILTINS_STR_SPLITLINES (1)
|
||||
@@ -96,7 +98,7 @@
|
||||
#define MICROPY_PY_UZLIB (0)
|
||||
#define MICROPY_PY_UJSON (1)
|
||||
#define MICROPY_PY_URE (1)
|
||||
#define MICROPY_PY_UHEAPQ (1)
|
||||
#define MICROPY_PY_UHEAPQ (0)
|
||||
#define MICROPY_PY_UHASHLIB (0)
|
||||
|
||||
#define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (1)
|
||||
@@ -112,27 +114,26 @@ extern const struct _mp_obj_fun_builtin_t mp_builtin_open_obj;
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_open), (mp_obj_t)&mp_builtin_open_obj }, \
|
||||
|
||||
// extra built in modules to add to the list of known ones
|
||||
extern const struct _mp_obj_module_t pyb_module;
|
||||
extern const struct _mp_obj_module_t machine_module;
|
||||
extern const struct _mp_obj_module_t wipy_module;
|
||||
extern const struct _mp_obj_module_t mp_module_ure;
|
||||
extern const struct _mp_obj_module_t mp_module_ujson;
|
||||
extern const struct _mp_obj_module_t mp_module_uheapq;
|
||||
extern const struct _mp_obj_module_t mp_module_uos;
|
||||
extern const struct _mp_obj_module_t mp_module_utime;
|
||||
extern const struct _mp_obj_module_t mp_module_uselect;
|
||||
extern const struct _mp_obj_module_t mp_module_usocket;
|
||||
extern const struct _mp_obj_module_t mp_module_network;
|
||||
extern const struct _mp_obj_module_t mp_module_uhashlib;
|
||||
extern const struct _mp_obj_module_t mp_module_ubinascii;
|
||||
extern const struct _mp_obj_module_t mp_module_ussl;
|
||||
|
||||
#define MICROPY_PORT_BUILTIN_MODULES \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_pyb), (mp_obj_t)&pyb_module }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_machine), (mp_obj_t)&machine_module }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_wipy), (mp_obj_t)&wipy_module }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_uos), (mp_obj_t)&mp_module_uos }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_utime), (mp_obj_t)&mp_module_utime }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_uselect), (mp_obj_t)&mp_module_uselect }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_usocket), (mp_obj_t)&mp_module_usocket }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_network), (mp_obj_t)&mp_module_network }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_uhashlib), (mp_obj_t)&mp_module_uhashlib }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ubinascii), (mp_obj_t)&mp_module_ubinascii }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ussl), (mp_obj_t)&mp_module_ussl }, \
|
||||
|
||||
@@ -140,30 +141,29 @@ extern const struct _mp_obj_module_t mp_module_ussl;
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_struct), (mp_obj_t)&mp_module_ustruct }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_re), (mp_obj_t)&mp_module_ure }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_json), (mp_obj_t)&mp_module_ujson }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_heapq), (mp_obj_t)&mp_module_uheapq }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_os), (mp_obj_t)&mp_module_uos }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_time), (mp_obj_t)&mp_module_utime }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_select), (mp_obj_t)&mp_module_uselect }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_socket), (mp_obj_t)&mp_module_usocket }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_hashlib), (mp_obj_t)&mp_module_uhashlib }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_binascii), (mp_obj_t)&mp_module_ubinascii }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ssl), (mp_obj_t)&mp_module_ussl }, \
|
||||
|
||||
// extra constants
|
||||
#define MICROPY_PORT_CONSTANTS \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_pyb), (mp_obj_t)&pyb_module }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_machine), (mp_obj_t)&machine_module }, \
|
||||
|
||||
// vm state and root pointers for the gc
|
||||
#define MP_STATE_PORT MP_STATE_VM
|
||||
#define MICROPY_PORT_ROOT_POINTERS \
|
||||
const char *readline_hist[8]; \
|
||||
mp_obj_t mp_const_user_interrupt; \
|
||||
mp_obj_t pyb_config_main; \
|
||||
mp_obj_list_t pybsleep_obj_list; \
|
||||
mp_obj_list_t mpcallback_obj_list; \
|
||||
mp_obj_t machine_config_main; \
|
||||
mp_obj_list_t pyb_sleep_obj_list; \
|
||||
mp_obj_list_t mp_irq_obj_list; \
|
||||
mp_obj_list_t pyb_timer_channel_obj_list; \
|
||||
mp_obj_list_t mount_obj_list; \
|
||||
struct _pyb_uart_obj_t *pyb_uart_objs[2]; \
|
||||
struct _os_term_dup_obj_t *os_term_dup_obj; \
|
||||
|
||||
|
||||
// type definitions for the specific machine
|
||||
@@ -207,7 +207,6 @@ void mp_hal_stdout_tx_strn_cooked(const char *str, uint32_t len);
|
||||
#define MICROPY_HAL_H "cc3200_hal.h"
|
||||
#define MICROPY_PORT_HAS_TELNET (1)
|
||||
#define MICROPY_PORT_HAS_FTP (1)
|
||||
#define MICROPY_PORT_WLAN_URN (0)
|
||||
#define MICROPY_PY_SYS_PLATFORM "WiPy"
|
||||
|
||||
#define MICROPY_PORT_WLAN_AP_SSID "wipy-wlan"
|
||||
|
||||
@@ -64,10 +64,11 @@
|
||||
#include "pins.h"
|
||||
#include "pybsleep.h"
|
||||
#include "pybtimer.h"
|
||||
#include "mpcallback.h"
|
||||
#include "cryptohash.h"
|
||||
#include "mpirq.h"
|
||||
#include "updater.h"
|
||||
#include "moduos.h"
|
||||
#include "antenna.h"
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE CONSTANTS
|
||||
@@ -126,8 +127,8 @@ soft_reset:
|
||||
|
||||
// execute all basic initializations
|
||||
mpexception_init0();
|
||||
mpcallback_init0();
|
||||
pybsleep_init0();
|
||||
mp_irq_init0();
|
||||
pyb_sleep_init0();
|
||||
pin_init0();
|
||||
mperror_init0();
|
||||
uart_init0();
|
||||
@@ -137,18 +138,7 @@ soft_reset:
|
||||
moduos_init0();
|
||||
rng_init0();
|
||||
|
||||
#ifdef LAUNCHXL
|
||||
// instantiate the stdio uart on the default pins
|
||||
mp_obj_t args[2] = {
|
||||
mp_obj_new_int(MICROPY_STDIO_UART),
|
||||
mp_obj_new_int(MICROPY_STDIO_UART_BAUD),
|
||||
};
|
||||
pyb_stdio_uart = pyb_uart_type.make_new((mp_obj_t)&pyb_uart_type, MP_ARRAY_SIZE(args), 0, args);
|
||||
#else
|
||||
pyb_stdio_uart = MP_OBJ_NULL;
|
||||
#endif
|
||||
|
||||
pybsleep_reset_cause_t rstcause = pybsleep_get_reset_cause();
|
||||
pybsleep_reset_cause_t rstcause = pyb_sleep_get_reset_cause();
|
||||
if (rstcause < PYB_SLP_SOFT_RESET) {
|
||||
if (rstcause == PYB_SLP_HIB_RESET) {
|
||||
// when waking up from hibernate we just want
|
||||
@@ -172,7 +162,7 @@ soft_reset:
|
||||
mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_flash_slash_lib));
|
||||
|
||||
// reset config variables; they should be set by boot.py
|
||||
MP_STATE_PORT(pyb_config_main) = MP_OBJ_NULL;
|
||||
MP_STATE_PORT(machine_config_main) = MP_OBJ_NULL;
|
||||
|
||||
if (!safeboot) {
|
||||
// run boot.py
|
||||
@@ -196,10 +186,10 @@ soft_reset:
|
||||
// run the main script from the current directory.
|
||||
if (pyexec_mode_kind == PYEXEC_MODE_FRIENDLY_REPL) {
|
||||
const char *main_py;
|
||||
if (MP_STATE_PORT(pyb_config_main) == MP_OBJ_NULL) {
|
||||
if (MP_STATE_PORT(machine_config_main) == MP_OBJ_NULL) {
|
||||
main_py = "main.py";
|
||||
} else {
|
||||
main_py = mp_obj_str_get_str(MP_STATE_PORT(pyb_config_main));
|
||||
main_py = mp_obj_str_get_str(MP_STATE_PORT(machine_config_main));
|
||||
}
|
||||
int ret = pyexec_file(main_py);
|
||||
if (ret & PYEXEC_FORCED_EXIT) {
|
||||
@@ -229,12 +219,15 @@ soft_reset:
|
||||
soft_reset_exit:
|
||||
|
||||
// soft reset
|
||||
pybsleep_signal_soft_reset();
|
||||
pyb_sleep_signal_soft_reset();
|
||||
mp_printf(&mp_plat_print, "PYB: soft reboot\n");
|
||||
|
||||
// disable all callbacks to avoid undefined behaviour
|
||||
// when coming out of a soft reset
|
||||
mpcallback_disable_all();
|
||||
mp_irq_disable_all();
|
||||
|
||||
// cancel the RTC alarm which might be running independent of the irq state
|
||||
pyb_rtc_disable_alarm();
|
||||
|
||||
// flush the serial flash buffer
|
||||
sflash_disk_flush();
|
||||
@@ -263,7 +256,7 @@ STATIC void mptask_pre_init (void) {
|
||||
ASSERT ((sflash_fatfs = mem_Malloc(sizeof(FATFS))) != NULL);
|
||||
|
||||
// this one allocates memory for the nvic vault
|
||||
pybsleep_pre_init();
|
||||
pyb_sleep_pre_init();
|
||||
|
||||
// this one allocates memory for the WLAN semaphore
|
||||
wlan_pre_init();
|
||||
@@ -274,7 +267,7 @@ STATIC void mptask_pre_init (void) {
|
||||
// this one allocates memory for the socket semaphore
|
||||
modusocket_pre_init();
|
||||
|
||||
CRYPTOHASH_Init();
|
||||
//CRYPTOHASH_Init();
|
||||
|
||||
#ifdef DEBUG
|
||||
ASSERT (OSI_OK == osi_TaskCreate(TASK_Servers,
|
||||
@@ -357,11 +350,11 @@ STATIC void mptask_init_sflash_filesystem (void) {
|
||||
|
||||
STATIC void mptask_enter_ap_mode (void) {
|
||||
// append the mac only if it's not the first boot
|
||||
bool append_mac = !PRCMGetSpecialBit(PRCM_FIRST_BOOT_BIT);
|
||||
|
||||
bool add_mac = !PRCMGetSpecialBit(PRCM_FIRST_BOOT_BIT);
|
||||
// enable simplelink in ap mode (use the MAC address to make the ssid unique)
|
||||
wlan_sl_enable (ROLE_AP, MICROPY_PORT_WLAN_AP_SSID, strlen(MICROPY_PORT_WLAN_AP_SSID), MICROPY_PORT_WLAN_AP_SECURITY,
|
||||
MICROPY_PORT_WLAN_AP_KEY, strlen(MICROPY_PORT_WLAN_AP_KEY), MICROPY_PORT_WLAN_AP_CHANNEL, append_mac);
|
||||
wlan_sl_init (ROLE_AP, MICROPY_PORT_WLAN_AP_SSID, strlen(MICROPY_PORT_WLAN_AP_SSID),
|
||||
MICROPY_PORT_WLAN_AP_SECURITY, MICROPY_PORT_WLAN_AP_KEY, strlen(MICROPY_PORT_WLAN_AP_KEY),
|
||||
MICROPY_PORT_WLAN_AP_CHANNEL, ANTENNA_TYPE_INTERNAL, add_mac);
|
||||
}
|
||||
|
||||
STATIC void mptask_create_main_py (void) {
|
||||
@@ -373,10 +366,3 @@ STATIC void mptask_create_main_py (void) {
|
||||
f_close(&fp);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t pyb_main(mp_obj_t main) {
|
||||
if (MP_OBJ_IS_STR(main)) {
|
||||
MP_STATE_PORT(pyb_config_main) = main;
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(pyb_main_obj, pyb_main);
|
||||
|
||||
@@ -25,36 +25,54 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// qstrs specific to this port
|
||||
Q(__name__)
|
||||
Q(help)
|
||||
Q(pyb)
|
||||
// for machine module
|
||||
Q(machine)
|
||||
#ifdef DEBUG
|
||||
Q(info)
|
||||
#endif
|
||||
Q(reset)
|
||||
Q(main)
|
||||
Q(sync)
|
||||
Q(gc)
|
||||
Q(rng)
|
||||
Q(toggle)
|
||||
Q(write)
|
||||
Q(input)
|
||||
Q(freq)
|
||||
Q(unique_id)
|
||||
Q(disable_irq)
|
||||
Q(enable_irq)
|
||||
Q(flush)
|
||||
Q(repl_uart)
|
||||
Q(idle)
|
||||
Q(sleep)
|
||||
Q(deepsleep)
|
||||
Q(reset_cause)
|
||||
Q(wake_reason)
|
||||
Q(IDLE)
|
||||
Q(SLEEP)
|
||||
Q(DEEPSLEEP)
|
||||
Q(POWER_ON)
|
||||
Q(HARD_RESET)
|
||||
Q(WDT_RESET)
|
||||
Q(DEEPSLEEP_RESET)
|
||||
Q(SOFT_RESET)
|
||||
Q(WLAN_WAKE)
|
||||
Q(PIN_WAKE)
|
||||
Q(RTC_WAKE)
|
||||
|
||||
// for wipy module
|
||||
Q(wipy)
|
||||
Q(heartbeat)
|
||||
|
||||
// entries for sys.path
|
||||
Q(/flash)
|
||||
Q(/flash/lib)
|
||||
|
||||
// interactive help
|
||||
Q(help)
|
||||
|
||||
// for module weak links
|
||||
Q(struct)
|
||||
Q(binascii)
|
||||
Q(re)
|
||||
Q(json)
|
||||
Q(heapq)
|
||||
Q(hashlib)
|
||||
//Q(hashlib)
|
||||
|
||||
// for os module
|
||||
Q(os)
|
||||
@@ -81,6 +99,7 @@ Q(urandom)
|
||||
Q(mkfs)
|
||||
Q(mount)
|
||||
Q(unmount)
|
||||
Q(dupterm)
|
||||
Q(readonly)
|
||||
Q(readblocks)
|
||||
Q(writeblocks)
|
||||
@@ -90,6 +109,8 @@ Q(count)
|
||||
// for file class
|
||||
Q(seek)
|
||||
Q(tell)
|
||||
Q(input)
|
||||
Q(flush)
|
||||
|
||||
// for Pin class
|
||||
Q(Pin)
|
||||
@@ -176,13 +197,16 @@ Q(pins)
|
||||
|
||||
// for RTC class
|
||||
Q(RTC)
|
||||
Q(id)
|
||||
Q(init)
|
||||
Q(alarm)
|
||||
Q(alarm_left)
|
||||
Q(alarm_cancel)
|
||||
Q(now)
|
||||
Q(deinit)
|
||||
Q(datetime)
|
||||
Q(repeat)
|
||||
Q(ALARM0)
|
||||
|
||||
// for time class
|
||||
Q(time)
|
||||
@@ -228,14 +252,11 @@ Q(protocol)
|
||||
Q(error)
|
||||
Q(timeout)
|
||||
Q(AF_INET)
|
||||
Q(AF_INET6)
|
||||
Q(SOCK_STREAM)
|
||||
Q(SOCK_DGRAM)
|
||||
Q(SOCK_RAW)
|
||||
Q(IPPROTO_SEC)
|
||||
Q(IPPROTO_TCP)
|
||||
Q(IPPROTO_UDP)
|
||||
Q(IPPROTO_RAW)
|
||||
|
||||
// for ssl class
|
||||
Q(ssl)
|
||||
@@ -254,84 +275,59 @@ Q(CERT_REQUIRED)
|
||||
|
||||
// for network class
|
||||
Q(network)
|
||||
Q(server_running)
|
||||
Q(server_login)
|
||||
Q(server_timeout)
|
||||
Q(server)
|
||||
Q(init)
|
||||
Q(deinit)
|
||||
Q(login)
|
||||
Q(timeout)
|
||||
Q(isrunning)
|
||||
|
||||
// for WLAN class
|
||||
Q(WLAN)
|
||||
Q(iwconfig)
|
||||
Q(key)
|
||||
Q(security)
|
||||
Q(id)
|
||||
Q(init)
|
||||
Q(mode)
|
||||
Q(auth)
|
||||
Q(ssid)
|
||||
Q(bssid)
|
||||
Q(mac)
|
||||
Q(antenna)
|
||||
Q(scan)
|
||||
Q(connect)
|
||||
Q(isconnected)
|
||||
Q(disconnect)
|
||||
Q(sec)
|
||||
Q(channel)
|
||||
Q(rssi)
|
||||
Q(ifconfig)
|
||||
Q(info)
|
||||
Q(connections)
|
||||
#if MICROPY_PORT_WLAN_URN
|
||||
Q(urn)
|
||||
#endif
|
||||
Q(mode)
|
||||
Q(ip)
|
||||
Q(subnet)
|
||||
Q(gateway)
|
||||
Q(dns)
|
||||
Q(mac)
|
||||
Q(antenna)
|
||||
Q(config)
|
||||
//Q(connections)
|
||||
//Q(urn)
|
||||
Q(STA)
|
||||
Q(AP)
|
||||
Q(OPEN)
|
||||
Q(WEP)
|
||||
Q(WPA)
|
||||
Q(WPA2)
|
||||
Q(INTERNAL)
|
||||
Q(EXTERNAL)
|
||||
Q(INT_ANT)
|
||||
Q(EXT_ANT)
|
||||
Q(ANY_EVENT)
|
||||
|
||||
// for WDT class
|
||||
Q(WDT)
|
||||
Q(feed)
|
||||
Q(timeout)
|
||||
|
||||
// for HeartBeat class
|
||||
Q(HeartBeat)
|
||||
Q(enable)
|
||||
Q(disable)
|
||||
|
||||
// for callback class
|
||||
// for irq class
|
||||
Q(irq)
|
||||
Q(init)
|
||||
Q(enable)
|
||||
Q(disable)
|
||||
Q(callback)
|
||||
Q(flags)
|
||||
Q(trigger)
|
||||
Q(handler)
|
||||
Q(mode)
|
||||
Q(value)
|
||||
Q(priority)
|
||||
Q(wake_from)
|
||||
|
||||
// for Sleep class
|
||||
Q(Sleep)
|
||||
Q(idle)
|
||||
Q(suspend)
|
||||
Q(hibernate)
|
||||
Q(reset_cause)
|
||||
Q(wake_reason)
|
||||
Q(ACTIVE)
|
||||
Q(SUSPENDED)
|
||||
Q(HIBERNATING)
|
||||
Q(POWER_ON)
|
||||
Q(HARD_RESET)
|
||||
Q(WDT_RESET)
|
||||
Q(HIB_RESET)
|
||||
Q(SOFT_RESET)
|
||||
Q(WLAN_WAKE)
|
||||
Q(PIN_WAKE)
|
||||
Q(RTC_WAKE)
|
||||
Q(wake)
|
||||
|
||||
// for SPI class
|
||||
Q(SPI)
|
||||
@@ -349,7 +345,6 @@ Q(read)
|
||||
Q(readinto)
|
||||
Q(write_readinto)
|
||||
Q(nbytes)
|
||||
Q(write)
|
||||
Q(buf)
|
||||
Q(MASTER)
|
||||
Q(MSB)
|
||||
@@ -380,12 +375,12 @@ Q(POSITIVE)
|
||||
Q(NEGATIVE)
|
||||
|
||||
// for uhashlib module
|
||||
Q(uhashlib)
|
||||
Q(update)
|
||||
Q(digest)
|
||||
//Q(uhashlib)
|
||||
//Q(update)
|
||||
//Q(digest)
|
||||
//Q(md5)
|
||||
Q(sha1)
|
||||
Q(sha256)
|
||||
//Q(sha1)
|
||||
//Q(sha256)
|
||||
|
||||
// for ubinascii module
|
||||
Q(ubinascii)
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "py/mpconfig.h"
|
||||
#include MICROPY_HAL_H
|
||||
#include "py/misc.h"
|
||||
#include "py/nlr.h"
|
||||
#include "serverstask.h"
|
||||
#include "simplelink.h"
|
||||
#include "debug.h"
|
||||
@@ -37,17 +38,9 @@
|
||||
#include "ftp.h"
|
||||
#include "pybwdt.h"
|
||||
#include "modusocket.h"
|
||||
#include "mpexception.h"
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
DECLARE PRIVATE DEFINITIONS
|
||||
******************************************************************************/
|
||||
|
||||
#define SERVERS_DEF_USER "micro"
|
||||
#define SERVERS_DEF_PASS "python"
|
||||
#define SERVERS_DEF_TIMEOUT_MS 300000 // 5 minutes
|
||||
#define SERVERS_MIN_TIMEOUT_MS 5000 // 5 seconds
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PRIVATE TYPES
|
||||
******************************************************************************/
|
||||
@@ -144,7 +137,7 @@ void TASK_Servers (void *pvParameters) {
|
||||
|
||||
void servers_start (void) {
|
||||
servers_data.do_enable = true;
|
||||
HAL_Delay (SERVERS_CYCLE_TIME_MS * 5);
|
||||
HAL_Delay (SERVERS_CYCLE_TIME_MS * 3);
|
||||
}
|
||||
|
||||
void servers_stop (void) {
|
||||
@@ -152,7 +145,7 @@ void servers_stop (void) {
|
||||
do {
|
||||
HAL_Delay (SERVERS_CYCLE_TIME_MS);
|
||||
} while (servers_are_enabled());
|
||||
HAL_Delay (SERVERS_CYCLE_TIME_MS * 5);
|
||||
HAL_Delay (SERVERS_CYCLE_TIME_MS * 3);
|
||||
}
|
||||
|
||||
void servers_reset (void) {
|
||||
@@ -177,16 +170,19 @@ void servers_close_socket (int16_t *sd) {
|
||||
}
|
||||
|
||||
void servers_set_login (char *user, char *pass) {
|
||||
if (strlen(user) > SERVERS_USER_PASS_LEN_MAX || strlen(pass) > SERVERS_USER_PASS_LEN_MAX) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
|
||||
}
|
||||
memcpy(servers_user, user, SERVERS_USER_PASS_LEN_MAX);
|
||||
memcpy(servers_pass, pass, SERVERS_USER_PASS_LEN_MAX);
|
||||
}
|
||||
|
||||
bool servers_set_timeout (uint32_t timeout) {
|
||||
void servers_set_timeout (uint32_t timeout) {
|
||||
if (timeout < SERVERS_MIN_TIMEOUT_MS) {
|
||||
return false;
|
||||
// timeout is too low
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments));
|
||||
}
|
||||
servers_data.timeout = timeout;
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t servers_get_timeout (void) {
|
||||
|
||||
@@ -36,10 +36,15 @@
|
||||
#define SERVERS_SSID_LEN_MAX 16
|
||||
#define SERVERS_KEY_LEN_MAX 16
|
||||
|
||||
#define SERVERS_USER_PASS_LEN_MAX 16
|
||||
#define SERVERS_USER_PASS_LEN_MAX 32
|
||||
|
||||
#define SERVERS_CYCLE_TIME_MS 2
|
||||
|
||||
#define SERVERS_DEF_USER "micro"
|
||||
#define SERVERS_DEF_PASS "python"
|
||||
#define SERVERS_DEF_TIMEOUT_MS 300000 // 5 minutes
|
||||
#define SERVERS_MIN_TIMEOUT_MS 5000 // 5 seconds
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE TYPES
|
||||
******************************************************************************/
|
||||
@@ -61,7 +66,7 @@ extern bool servers_are_enabled (void);
|
||||
extern void servers_close_socket (int16_t *sd);
|
||||
extern void servers_set_login (char *user, char *pass);
|
||||
extern void server_sleep_sockets (void);
|
||||
extern bool servers_set_timeout (uint32_t timeout);
|
||||
extern void servers_set_timeout (uint32_t timeout);
|
||||
extern uint32_t servers_get_timeout (void);
|
||||
|
||||
#endif /* SERVERSTASK_H_ */
|
||||
|
||||
@@ -457,7 +457,7 @@ OsiReturnVal_e VStartSimpleLinkSpawnTask(unsigned portBASE_TYPE uxPriority)
|
||||
ASSERT (xSimpleLinkSpawnQueue != NULL);
|
||||
|
||||
ASSERT (pdPASS == xTaskCreate( vSimpleLinkSpawnTask, ( portCHAR * ) "SLSPAWN",\
|
||||
736 / sizeof(portSTACK_TYPE), NULL, uxPriority, &xSimpleLinkSpawnTaskHndl ));
|
||||
896 / sizeof(portSTACK_TYPE), NULL, uxPriority, &xSimpleLinkSpawnTaskHndl ));
|
||||
|
||||
return OSI_OK;
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@ typedef struct {
|
||||
DECLARE PRIVATE DATA
|
||||
******************************************************************************/
|
||||
static telnet_data_t telnet_data;
|
||||
static const char* telnet_welcome_msg = "Micro Python " MICROPY_GIT_TAG " on " MICROPY_BUILD_DATE "; " MICROPY_HW_BOARD_NAME " with " MICROPY_HW_MCU_NAME "\r\n";
|
||||
static const char* telnet_welcome_msg = "MicroPython " MICROPY_GIT_TAG " on " MICROPY_BUILD_DATE "; " MICROPY_HW_BOARD_NAME " with " MICROPY_HW_MCU_NAME "\r\n";
|
||||
static const char* telnet_request_user = "Login as: ";
|
||||
static const char* telnet_request_password = "Password: ";
|
||||
static const char* telnet_invalid_loggin = "\r\nInvalid credentials, try again.\r\n";
|
||||
@@ -244,34 +244,14 @@ void telnet_run (void) {
|
||||
}
|
||||
|
||||
void telnet_tx_strn (const char *str, int len) {
|
||||
if (len > 0 && telnet_data.n_sd > 0) {
|
||||
if (telnet_data.n_sd > 0 && telnet_data.state == E_TELNET_STE_LOGGED_IN && len > 0) {
|
||||
telnet_send_with_retries(telnet_data.n_sd, str, len);
|
||||
}
|
||||
}
|
||||
|
||||
void telnet_tx_strn_cooked (const char *str, uint len) {
|
||||
int32_t nslen = 0;
|
||||
const char *_str = str;
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (str[i] == '\n') {
|
||||
telnet_send_with_retries(telnet_data.n_sd, _str, nslen);
|
||||
telnet_send_with_retries(telnet_data.n_sd, "\r\n", 2);
|
||||
_str += nslen + 1;
|
||||
nslen = 0;
|
||||
}
|
||||
else {
|
||||
nslen++;
|
||||
}
|
||||
}
|
||||
if (_str < str + len) {
|
||||
telnet_send_with_retries(telnet_data.n_sd, _str, nslen);
|
||||
}
|
||||
}
|
||||
|
||||
bool telnet_rx_any (void) {
|
||||
return (telnet_data.n_sd > 0) ? ((telnet_data.rxRindex != telnet_data.rxWindex) &&
|
||||
(telnet_data.state == E_TELNET_STE_LOGGED_IN)) : false;
|
||||
return (telnet_data.n_sd > 0) ? (telnet_data.rxRindex != telnet_data.rxWindex &&
|
||||
telnet_data.state == E_TELNET_STE_LOGGED_IN) : false;
|
||||
}
|
||||
|
||||
int telnet_rx_char (void) {
|
||||
@@ -300,14 +280,6 @@ void telnet_reset (void) {
|
||||
telnet_data.state = E_TELNET_STE_START;
|
||||
}
|
||||
|
||||
bool telnet_is_enabled (void) {
|
||||
return telnet_data.enabled;
|
||||
}
|
||||
|
||||
bool telnet_is_active (void) {
|
||||
return (telnet_data.state == E_TELNET_STE_LOGGED_IN);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
DEFINE PRIVATE FUNCTIONS
|
||||
******************************************************************************/
|
||||
|
||||
@@ -33,13 +33,10 @@
|
||||
extern void telnet_init (void);
|
||||
extern void telnet_run (void);
|
||||
extern void telnet_tx_strn (const char *str, int len);
|
||||
extern void telnet_tx_strn_cooked (const char *str, uint len);
|
||||
extern bool telnet_rx_any (void);
|
||||
extern int telnet_rx_char (void);
|
||||
extern void telnet_enable (void);
|
||||
extern void telnet_disable (void);
|
||||
extern void telnet_reset (void);
|
||||
extern bool telnet_is_enabled (void);
|
||||
extern bool telnet_is_active (void);
|
||||
|
||||
#endif /* TELNET_H_ */
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import pyb
|
||||
from machine import Pin
|
||||
from machine import RTC
|
||||
import time
|
||||
import os
|
||||
|
||||
"""
|
||||
@@ -13,31 +15,31 @@ test_bytes = os.urandom(1024)
|
||||
def test_pin_read (pull):
|
||||
# enable the pull resistor on all pins, then read the value
|
||||
for p in pin_map:
|
||||
pin = pyb.Pin('GP' + str(p), mode=pyb.Pin.IN, pull=pull)
|
||||
pin = Pin('GP' + str(p), mode=Pin.IN, pull=pull)
|
||||
# read the pin value
|
||||
print(pin())
|
||||
|
||||
def test_pin_shorts (pull):
|
||||
if pull == pyb.Pin.PULL_UP:
|
||||
pull_inverted = pyb.Pin.PULL_DOWN
|
||||
if pull == Pin.PULL_UP:
|
||||
pull_inverted = Pin.PULL_DOWN
|
||||
else:
|
||||
pull_inverted = pyb.Pin.PULL_UP
|
||||
pull_inverted = Pin.PULL_UP
|
||||
# enable all pulls of the specified type
|
||||
for p in pin_map:
|
||||
pin = pyb.Pin('GP' + str(p), mode=pyb.Pin.IN, pull=pull_inverted)
|
||||
pin = Pin('GP' + str(p), mode=Pin.IN, pull=pull_inverted)
|
||||
# then change the pull one pin at a time and read its value
|
||||
i = 0
|
||||
while i < len(pin_map):
|
||||
pin = pyb.Pin('GP' + str(pin_map[i]), mode=pyb.Pin.IN, pull=pull)
|
||||
pyb.Pin('GP' + str(pin_map[i - 1]), mode=pyb.Pin.IN, pull=pull_inverted)
|
||||
pin = Pin('GP' + str(pin_map[i]), mode=Pin.IN, pull=pull)
|
||||
Pin('GP' + str(pin_map[i - 1]), mode=Pin.IN, pull=pull_inverted)
|
||||
i += 1
|
||||
# read the pin value
|
||||
print(pin())
|
||||
|
||||
test_pin_read(pyb.Pin.PULL_UP)
|
||||
test_pin_read(pyb.Pin.PULL_DOWN)
|
||||
test_pin_shorts(pyb.Pin.PULL_UP)
|
||||
test_pin_shorts(pyb.Pin.PULL_DOWN)
|
||||
test_pin_read(Pin.PULL_UP)
|
||||
test_pin_read(Pin.PULL_DOWN)
|
||||
test_pin_shorts(Pin.PULL_UP)
|
||||
test_pin_shorts(Pin.PULL_DOWN)
|
||||
|
||||
# create a test directory
|
||||
os.mkdir('/flash/test')
|
||||
@@ -62,12 +64,12 @@ print('test' not in ls)
|
||||
print(ls)
|
||||
|
||||
# test the real time clock
|
||||
rtc = pyb.RTC()
|
||||
rtc = RTC()
|
||||
while rtc.now()[6] > 800:
|
||||
pass
|
||||
|
||||
time1 = rtc.now()
|
||||
pyb.delay(1000)
|
||||
time.sleep_ms(1000)
|
||||
time2 = rtc.now()
|
||||
print(time2[5] - time1[5] == 1)
|
||||
print(time2[6] - time1[6] < 5000) # microseconds
|
||||
|
||||
@@ -17,6 +17,7 @@ Or:
|
||||
import sys
|
||||
import argparse
|
||||
import time
|
||||
import socket
|
||||
from ftplib import FTP
|
||||
from telnetlib import Telnet
|
||||
|
||||
@@ -89,9 +90,9 @@ def reset_board(args):
|
||||
time.sleep(1)
|
||||
tn.write(b'\r\x02') # ctrl-B: enter friendly REPL
|
||||
if b'Type "help()" for more information.' in tn.read_until(b'Type "help()" for more information.', timeout=5):
|
||||
tn.write(b"import pyb\r\n")
|
||||
tn.write(b"pyb.reset()\r\n")
|
||||
time.sleep(1)
|
||||
tn.write(b"import machine\r\n")
|
||||
tn.write(b"machine.reset()\r\n")
|
||||
time.sleep(2)
|
||||
print("Reset performed")
|
||||
success = True
|
||||
else:
|
||||
@@ -121,12 +122,23 @@ def verify_update(args):
|
||||
print("Error: verification failed, the git tag doesn't match")
|
||||
return False
|
||||
|
||||
try:
|
||||
# Specify a longer time out value here because the board has just been
|
||||
# reset and the wireless connection might not be fully established yet
|
||||
tn = Telnet(args.ip, timeout=15)
|
||||
print("Connected via telnet again, lets check the git tag")
|
||||
retries = 0
|
||||
while True:
|
||||
try:
|
||||
# Specify a longer time out value here because the board has just been
|
||||
# reset and the wireless connection might not be fully established yet
|
||||
tn = Telnet(args.ip, timeout=10)
|
||||
print("Connected via telnet again, lets check the git tag")
|
||||
break
|
||||
except socket.timeout:
|
||||
if retries < 5:
|
||||
print("Timeout while connecting via telnet, retrying...")
|
||||
retries += 1
|
||||
else:
|
||||
print('Error: Telnet connection timed out!')
|
||||
return False
|
||||
|
||||
try:
|
||||
firmware_tag = tn.read_until (b'with CC3200')
|
||||
tag_file_path = args.file.rstrip('mcuimg.bin') + 'genhdr/mpversion.h'
|
||||
|
||||
@@ -170,10 +182,9 @@ def main():
|
||||
if reset_board(args):
|
||||
if args.verify:
|
||||
print ('Waiting for the WiFi connection to come up again...')
|
||||
# this time is to allow the system's wireless network card to connect to the
|
||||
# WiPy again. Sometimes it might only take a couple of seconds, but let's
|
||||
# leave 15s to be on the safe side
|
||||
time.sleep(15)
|
||||
# this time is to allow the system's wireless network card to
|
||||
# connect to the WiPy again.
|
||||
time.sleep(5)
|
||||
if verify_update(args):
|
||||
result = 0
|
||||
else:
|
||||
|
||||
@@ -32,14 +32,13 @@
|
||||
#include "inc/hw_ints.h"
|
||||
#include "inc/hw_memmap.h"
|
||||
#include "rom_map.h"
|
||||
#include "prcm.h"
|
||||
#include "pybrtc.h"
|
||||
#include "simplelink.h"
|
||||
#include "modnetwork.h"
|
||||
#include "modwlan.h"
|
||||
#include "random.h"
|
||||
#include "debug.h"
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* LOCAL TYPES
|
||||
******************************************************************************/
|
||||
@@ -57,20 +56,23 @@ static uint32_t s_seed;
|
||||
/******************************************************************************
|
||||
* LOCAL FUNCTION DECLARATIONS
|
||||
******************************************************************************/
|
||||
static uint32_t lfsr (uint32_t input);
|
||||
STATIC uint32_t lfsr (uint32_t input);
|
||||
|
||||
/******************************************************************************
|
||||
* PRIVATE FUNCTIONS
|
||||
******************************************************************************/
|
||||
static uint32_t lfsr (uint32_t input) {
|
||||
STATIC uint32_t lfsr (uint32_t input) {
|
||||
assert( input != 0 );
|
||||
return (input >> 1) ^ (-(input & 0x01) & 0x00E10000);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t pyb_rng_get(void) {
|
||||
/******************************************************************************/
|
||||
// Micro Python bindings;
|
||||
|
||||
STATIC mp_obj_t machine_rng_get(void) {
|
||||
return mp_obj_new_int(rng_get());
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_0(pyb_rng_get_obj, pyb_rng_get);
|
||||
MP_DEFINE_CONST_FUN_OBJ_0(machine_rng_get_obj, machine_rng_get);
|
||||
|
||||
/******************************************************************************
|
||||
* PUBLIC FUNCTIONS
|
||||
@@ -81,7 +83,7 @@ void rng_init0 (void) {
|
||||
uint16_t mseconds;
|
||||
|
||||
// get the seconds and the milliseconds from the RTC
|
||||
MAP_PRCMRTCGet(&seconds, &mseconds);
|
||||
pyb_rtc_get_time(&seconds, &mseconds);
|
||||
|
||||
wlan_get_mac (juggler.id8);
|
||||
|
||||
|
||||
@@ -30,6 +30,6 @@
|
||||
void rng_init0 (void);
|
||||
uint32_t rng_get (void);
|
||||
|
||||
MP_DECLARE_CONST_FUN_OBJ(pyb_rng_get_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ(machine_rng_get_obj);
|
||||
|
||||
#endif // __RANDOM_H
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
@ global variable with the backup registers
|
||||
.extern vault_arm_registers
|
||||
@ global function that performs the wake up actions
|
||||
.extern pybsleep_suspend_exit
|
||||
.extern pyb_sleep_suspend_exit
|
||||
|
||||
@ uint sleep_store(void)
|
||||
.global sleep_store
|
||||
@@ -58,4 +58,4 @@ sleep_restore:
|
||||
msr basepri, r0
|
||||
dsb
|
||||
isb
|
||||
bl pybsleep_suspend_exit
|
||||
bl pyb_sleep_suspend_exit
|
||||
|
||||
@@ -27,6 +27,6 @@
|
||||
#ifndef VERSION_H_
|
||||
#define VERSION_H_
|
||||
|
||||
#define WIPY_SW_VERSION_NUMBER "0.9.1"
|
||||
#define WIPY_SW_VERSION_NUMBER "1.1.0"
|
||||
|
||||
#endif /* VERSION_H_ */
|
||||
|
||||
@@ -58,9 +58,9 @@ copyright = '2014, Damien P. George'
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = '1.4'
|
||||
version = '1.5'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = '1.4.6'
|
||||
release = '1.5'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
@@ -300,6 +300,11 @@ html_context = {
|
||||
|
||||
# Append the other ports' specific folders/files to the exclude pattern
|
||||
exclude_patterns.extend([port + '*' for port in ports if port != micropy_port])
|
||||
# Exclude pyb module if the port is the WiPy
|
||||
if micropy_port == 'wipy':
|
||||
exclude_patterns.append('library/pyb*')
|
||||
else: # exclude machine
|
||||
exclude_patterns.append('library/machine*')
|
||||
|
||||
# Specify a custom master document based on the port name
|
||||
master_doc = micropy_port + '_' + 'index'
|
||||
|
||||
@@ -10,18 +10,12 @@ The ``esp`` module contains specific functions related to the ESP8266 module.
|
||||
Functions
|
||||
---------
|
||||
|
||||
.. function:: status()
|
||||
.. function:: mac([address])
|
||||
|
||||
Return the current status of the wireless connection.
|
||||
Get or set the network interface's MAC address.
|
||||
|
||||
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 susccessful.
|
||||
If the ``address`` parameter is provided, sets the address to its value. If
|
||||
the function is called wihout parameters, returns the current address.
|
||||
|
||||
.. function:: getaddrinfo((hostname, port, lambda))
|
||||
|
||||
@@ -31,6 +25,61 @@ Functions
|
||||
called with two arguments, first being the hostname being resolved,
|
||||
second a tuple with information about that hostname.
|
||||
|
||||
.. function:: wifi_mode([mode])
|
||||
|
||||
Get or set the wireless network operating mode.
|
||||
|
||||
If the ``mode`` parameter is provided, sets the mode to its value. If
|
||||
the function is called wihout parameters, returns the current mode.
|
||||
|
||||
The possible modes are defined as constants:
|
||||
|
||||
* ``STA_MODE`` -- station mode,
|
||||
* ``AP_MODE`` -- software access point mode,
|
||||
* ``STA_AP_MODE`` -- mixed station and software access point mode.
|
||||
|
||||
.. function:: phy_mode([mode])
|
||||
|
||||
Get or set the network interface mode.
|
||||
|
||||
If the ``mode`` parameter is provided, sets the mode to its value. If
|
||||
the function is called wihout parameters, returns the current mode.
|
||||
|
||||
The possible modes are defined as constants:
|
||||
* ``MODE_11B`` -- IEEE 802.11b,
|
||||
* ``MODE_11G`` -- IEEE 802.11g,
|
||||
* ``MODE_11N`` -- IEEE 802.11n.
|
||||
|
||||
.. function:: sleep_type([sleep_type])
|
||||
|
||||
Get or set the sleep type.
|
||||
|
||||
If the ``sleep_type`` parameter is provided, sets the sleep type to its
|
||||
value. If the function is called wihout parameters, returns the current
|
||||
sleep type.
|
||||
|
||||
The possible sleep types are defined as constants:
|
||||
|
||||
* ``SLEEP_NONE`` -- all functions enabled,
|
||||
* ``SLEEP_MODEM`` -- modem sleep, shuts down the WiFi Modem circuit.
|
||||
* ``SLEEP_LIGHT`` -- light sleep, shuts down the WiFi Modem circuit
|
||||
and suspends the processor periodically.
|
||||
|
||||
The system enters the set sleep mode automatically when possible.
|
||||
|
||||
.. function:: deepsleep(time=0)
|
||||
|
||||
Enter deep sleep.
|
||||
|
||||
The whole module powers down, except for the RTC clock circuit, which can
|
||||
be used to restart the module after the specified time if the pin 16 is
|
||||
connected to the reset pin. Otherwise the module will sleep until manually
|
||||
reset.
|
||||
|
||||
.. function:: flash_id()
|
||||
|
||||
Read the device ID of the flash memory.
|
||||
|
||||
Classes
|
||||
-------
|
||||
|
||||
|
||||
@@ -74,12 +74,12 @@ it will fallback to loading the built-in ``ujson`` module.
|
||||
|
||||
Libraries specific to the pyboard
|
||||
---------------------------------
|
||||
|
||||
|
||||
The following libraries are specific to the pyboard.
|
||||
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
|
||||
pyb.rst
|
||||
network.rst
|
||||
|
||||
@@ -87,13 +87,12 @@ it will fallback to loading the built-in ``ujson`` module.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
|
||||
ubinascii.rst
|
||||
uhashlib.rst
|
||||
uheapq.rst
|
||||
ujson.rst
|
||||
ure.rst
|
||||
usocket.rst
|
||||
ussl.rst
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
@@ -105,8 +104,9 @@ it will fallback to loading the built-in ``ujson`` module.
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
pyb.rst
|
||||
machine.rst
|
||||
network.rst
|
||||
wipy.rst
|
||||
|
||||
|
||||
.. only:: port_esp8266
|
||||
|
||||
73
docs/library/machine.ADC.rst
Normal file
73
docs/library/machine.ADC.rst
Normal file
@@ -0,0 +1,73 @@
|
||||
.. _machine.ADC:
|
||||
|
||||
class ADC -- analog to digital conversion
|
||||
=========================================
|
||||
|
||||
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:: machine.ADC(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:: adc.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:: 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.
|
||||
117
docs/library/machine.I2C.rst
Normal file
117
docs/library/machine.I2C.rst
Normal file
@@ -0,0 +1,117 @@
|
||||
.. _machine.I2C:
|
||||
|
||||
class I2C -- a two-wire serial protocol
|
||||
=======================================
|
||||
|
||||
I2C is a two-wire protocol for communicating between devices. At the physical
|
||||
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_wipy
|
||||
|
||||
Example::
|
||||
|
||||
from machine import I2C
|
||||
|
||||
i2c = I2C(0) # create on bus 0
|
||||
i2c = I2C(0, I2C.MASTER) # create and init as a master
|
||||
i2c.init(I2C.MASTER, baudrate=20000) # init as a master
|
||||
i2c.deinit() # turn off the peripheral
|
||||
|
||||
Printing the i2c object gives you information about its configuration.
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
A master must specify the recipient's address::
|
||||
|
||||
i2c.init(I2C.MASTER)
|
||||
i2c.writeto(0x42, '123') # send 3 bytes to slave with address 0x42
|
||||
i2c.writeto(addr=0x42, b'456') # keyword for address
|
||||
|
||||
Master also has other methods::
|
||||
|
||||
i2c.scan() # scan for slaves on the bus, returning
|
||||
# a list of valid addresses
|
||||
i2c.readfrom_mem(0x42, 2, 3) # read 3 bytes from memory of slave 0x42,
|
||||
# starting at address 2 in the slave
|
||||
i2c.writeto_mem(0x42, 2, 'abc') # write 'abc' (3 bytes) to memory of slave 0x42
|
||||
# starting at address 2 in the slave, timeout after 1 second
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
.. class:: machine.I2C(bus, ...)
|
||||
|
||||
Construct an I2C object on the given bus. `bus` can only be 0.
|
||||
If the bus is not given, the default one will be selected (0).
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. method:: i2c.deinit()
|
||||
|
||||
Turn off the I2C bus.
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
.. method:: i2c.init(mode, \*, baudrate=100000, pins=(SDA, SCL))
|
||||
|
||||
Initialise the I2C bus with the given parameters:
|
||||
|
||||
- ``mode`` must be ``I2C.MASTER``
|
||||
- ``baudrate`` is the SCL clock rate
|
||||
- ``pins`` is an optional tuple with the pins to assign to the I2C bus.
|
||||
|
||||
.. method:: i2c.readfrom(addr, nbytes)
|
||||
|
||||
Read ``nbytes`` from the slave specified by ``addr``.
|
||||
Returns a ``bytes`` object with the data read.
|
||||
|
||||
.. method:: i2c.readfrom_into(addr, buf)
|
||||
|
||||
Read into ``buf`` from the slave specified by ``addr``.
|
||||
Returns the number of bytes read.
|
||||
|
||||
.. method:: i2c.writeto(addr, buf, \*, stop=True)
|
||||
|
||||
Write ``buf`` to the slave specified by ``addr``. Set ``stop`` to ``False``
|
||||
if the transfer should be continued.
|
||||
Returns the number of bytes written.
|
||||
|
||||
.. 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``.
|
||||
Param ``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)
|
||||
|
||||
Read into ``buf`` from the slave specified by ``addr`` starting from the memory
|
||||
address specified by ``memaddr``.
|
||||
Param ``addrsize`` specifies the address size in bits.
|
||||
Returns the number of bytes read.
|
||||
|
||||
.. 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``. Param ``addrsize`` specifies the
|
||||
address size in bits.
|
||||
Set ``stop`` to ``False`` if the transfer should be continued.
|
||||
Returns the number of bytes written.
|
||||
|
||||
.. method:: i2c.scan()
|
||||
|
||||
Scan all I2C addresses from 0x01 to 0x7f and return a list of those that respond.
|
||||
Only valid when in master mode.
|
||||
|
||||
Constants
|
||||
---------
|
||||
|
||||
.. data:: I2C.MASTER
|
||||
|
||||
for initialising the bus to master mode
|
||||
209
docs/library/machine.Pin.rst
Normal file
209
docs/library/machine.Pin.rst
Normal file
@@ -0,0 +1,209 @@
|
||||
.. _machine.Pin:
|
||||
|
||||
class Pin -- control I/O pins
|
||||
=============================
|
||||
|
||||
A pin is the basic object to control I/O pins. It has methods to set
|
||||
the mode of the pin (input, output, etc) and methods to get and set the
|
||||
digital logic level. For analog control of a pin, see the ADC class.
|
||||
|
||||
Usage Model:
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
Board pins are identified by their string id::
|
||||
|
||||
from machine import Pin
|
||||
g = machine.Pin('GP9', mode=Pin.OUT, pull=None, drive=Pin.MED_POWER, alt=-1)
|
||||
|
||||
You can also configure the Pin to generate interrupts. For instance::
|
||||
|
||||
from machine import Pin
|
||||
|
||||
def pincb(pin):
|
||||
print(pin.id())
|
||||
|
||||
pin_int = Pin('GP10', mode=Pin.IN, pull=Pin.PULL_DOWN)
|
||||
pin_int.irq(mode=Pin.IRQ_RISING, handler=pincb)
|
||||
# the callback can be triggered manually
|
||||
pin_int.irq()()
|
||||
# to disable the callback
|
||||
pin_int.irq().disable()
|
||||
|
||||
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
|
||||
------------
|
||||
|
||||
.. class:: machine.Pin(id, ...)
|
||||
|
||||
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`.
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
.. method:: pin.init(mode, pull, \*, drive, alt)
|
||||
|
||||
Initialise the pin:
|
||||
|
||||
- ``mode`` can be one of:
|
||||
|
||||
- ``Pin.IN`` - input pin.
|
||||
- ``Pin.OUT`` - output pin in push-pull mode.
|
||||
- ``Pin.OPEN_DRAIN`` - output pin in open-drain mode.
|
||||
- ``Pin.ALT`` - pin mapped to an alternate function.
|
||||
- ``Pin.ALT_OPEN_DRAIN`` - pin mapped to an alternate function in open-drain mode.
|
||||
|
||||
- ``pull`` can be one of:
|
||||
|
||||
- ``None`` - no pull up or down resistor.
|
||||
- ``Pin.PULL_UP`` - pull up resistor enabled.
|
||||
- ``Pin.PULL_DOWN`` - pull down resitor enabled.
|
||||
|
||||
- ``drive`` can be one of:
|
||||
|
||||
- ``Pin.LOW_POWER`` - 2mA drive capability.
|
||||
- ``Pin.MED_POWER`` - 4mA drive capability.
|
||||
- ``Pin.HIGH_POWER`` - 6mA drive capability.
|
||||
|
||||
- ``alt`` is the number of the alternate function. Please refer to the
|
||||
`pinout and alternate functions table. <https://raw.githubusercontent.com/wipy/wipy/master/docs/PinOUT.png>`_
|
||||
for the specific alternate functions that each pin supports.
|
||||
|
||||
Returns: ``None``.
|
||||
|
||||
.. method:: pin.id()
|
||||
|
||||
Get the pin id.
|
||||
|
||||
.. method:: pin.value([value])
|
||||
|
||||
Get or set the digital logic level of the pin:
|
||||
|
||||
- With no argument, return 0 or 1 depending on the logic level of the pin.
|
||||
- With ``value`` given, set the logic level of the pin. ``value`` can be
|
||||
anything that converts to a boolean. If it converts to ``True``, the pin
|
||||
is set high, otherwise it is set low.
|
||||
|
||||
.. method:: pin.alt_list()
|
||||
|
||||
Returns a list of the alternate functions supported by the pin. List items are
|
||||
a tuple of the form: ``('ALT_FUN_NAME', ALT_FUN_INDEX)``
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
.. method:: pin([value])
|
||||
|
||||
Pin objects are callable. The call method provides a (fast) shortcut to set and get the value of the pin.
|
||||
See **pin.value** for more details.
|
||||
|
||||
.. method:: pin.toggle()
|
||||
|
||||
Toggle the value of the pin.
|
||||
|
||||
.. method:: pin.mode([mode])
|
||||
|
||||
Get or set the pin mode.
|
||||
|
||||
.. method:: pin.pull([pull])
|
||||
|
||||
Get or set the pin pull.
|
||||
|
||||
.. method:: pin.drive([drive])
|
||||
|
||||
Get or set the pin drive strength.
|
||||
|
||||
.. method:: pin.irq(\*, trigger, priority=1, handler=None, wake=None)
|
||||
|
||||
Create a callback to be triggered when the input level at the pin changes.
|
||||
|
||||
- ``trigger`` configures the pin level which can generate an interrupt. Possible values are:
|
||||
|
||||
- ``Pin.IRQ_FALLING`` interrupt on falling edge.
|
||||
- ``Pin.IRQ_RISING`` interrupt on rising edge.
|
||||
- ``Pin.IRQ_LOW_LEVEL`` interrupt on low level.
|
||||
- ``Pin.IRQ_HIGH_LEVEL`` interrupt on high level.
|
||||
|
||||
The values can be *ORed* together, for instance mode=Pin.IRQ_FALLING | Pin.IRQ_RISING
|
||||
|
||||
- ``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 new characters arrive.
|
||||
- ``wakes`` selects the power mode in which this interrupt can wake up the
|
||||
board. Please note:
|
||||
|
||||
- If ``wake_from=machine.Sleep.ACTIVE`` any pin can wake the board.
|
||||
- If ``wake_from=machine.Sleep.SUSPENDED`` pins ``GP2``, ``GP4``, ``GP10``,
|
||||
``GP11``, GP17`` or ``GP24`` can wake the board. Note that only 1
|
||||
of this pins can be enabled as a wake source at the same time, so, only
|
||||
the last enabled pin as a ``machine.Sleep.SUSPENDED`` wake source will have effect.
|
||||
- If ``wake_from=machine.Sleep.SUSPENDED`` pins ``GP2``, ``GP4``, ``GP10``,
|
||||
``GP11``, ``GP17`` and ``GP24`` can wake the board. In this case all of the
|
||||
6 pins can be enabled as a ``machine.Sleep.HIBERNATE`` wake source at the same time.
|
||||
- Values can be ORed to make a pin generate interrupts in more than one power
|
||||
mode.
|
||||
|
||||
Returns a callback object.
|
||||
|
||||
Attributes
|
||||
----------
|
||||
|
||||
.. class:: Pin.board
|
||||
|
||||
Contains all ``Pin`` objects supported by the board. Examples::
|
||||
|
||||
Pin.board.GP25
|
||||
led = Pin(Pin.board.GP25, mode=Pin.OUT)
|
||||
Pin.board.GP2.alt_list()
|
||||
|
||||
|
||||
Constants
|
||||
---------
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
.. data:: Pin.IN
|
||||
|
||||
.. data:: Pin.OUT
|
||||
|
||||
.. data:: Pin.OPEN_DRAIN
|
||||
|
||||
.. data:: Pin.ALT
|
||||
|
||||
.. data:: Pin.ALT_OPEN_DRAIN
|
||||
|
||||
Selects the pin mode.
|
||||
|
||||
.. data:: Pin.PULL_UP
|
||||
|
||||
.. data:: Pin.PULL_DOWN
|
||||
|
||||
Selectes the wether there's pull up/down resistor.
|
||||
|
||||
.. data:: Pin.LOW_POWER
|
||||
|
||||
.. data:: Pin.MED_POWER
|
||||
|
||||
.. data:: Pin.HIGH_POWER
|
||||
|
||||
Selects the drive strength.
|
||||
|
||||
.. data:: Pin.IRQ_FALLING
|
||||
|
||||
.. data:: Pin.IRQ_RISING
|
||||
|
||||
.. data:: Pin.IRQ_LOW_LEVEL
|
||||
|
||||
.. data:: Pin.IRQ_HIGH_LEVEL
|
||||
|
||||
Selects the IRQ trigger type.
|
||||
68
docs/library/machine.RTC.rst
Normal file
68
docs/library/machine.RTC.rst
Normal file
@@ -0,0 +1,68 @@
|
||||
.. _machine.RTC:
|
||||
|
||||
class RTC -- real time clock
|
||||
============================
|
||||
|
||||
The RTC is and independent clock that keeps track of the date
|
||||
and time.
|
||||
|
||||
Example usage::
|
||||
|
||||
rtc = machine.RTC()
|
||||
rtc.datetime((2014, 5, 1, 4, 13, 0, 0, 0))
|
||||
print(rtc.datetime())
|
||||
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. class:: machine.RTC(id=0, ...)
|
||||
|
||||
Create an RTC object. See init for parameters of initialization.
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. method:: rtc.init(id, datetime)
|
||||
|
||||
Initialise the RTC. Datetime is a tuple of the form:
|
||||
|
||||
``(year, month, day[, hour[, minute[, second[, microsecond[, tzinfo]]]]])``
|
||||
|
||||
.. method:: rtc.now()
|
||||
|
||||
Get get the current datetime tuple.
|
||||
|
||||
.. method:: rtc.deinit()
|
||||
|
||||
Resets the RTC to the time of January 1, 2015 and starts running it again.
|
||||
|
||||
.. method:: rtc.alarm(id, time, /*, repeat=False)
|
||||
|
||||
Set the RTC alarm. Time might be either a milllisecond value to program the alarm to
|
||||
current time + time_in_ms in the future, or a datetimetuple. If the time passed is in
|
||||
milliseconds, repeat can be set to ``True`` to make the alarm periodic.
|
||||
|
||||
.. method:: rtc.alarm_left(alarm_id=0)
|
||||
|
||||
Get the number of milliseconds left before the alarm expires.
|
||||
|
||||
.. method:: rtc.cancel(alarm_id=0)
|
||||
|
||||
Cancel a running alarm.
|
||||
|
||||
.. method:: rtc.irq(\*, trigger, handler=None, wake=machine.IDLE)
|
||||
|
||||
Create an irq object triggered by a real time clock alarm.
|
||||
|
||||
- ``trigger`` must be ``RTC.ALARM0``
|
||||
- ``handler`` is the function to be called when the callback is triggered.
|
||||
- ``wake`` specifies the sleep mode from where this interrupt can wake
|
||||
up the system.
|
||||
|
||||
Constants
|
||||
---------
|
||||
|
||||
.. data:: RTC.ALARM0
|
||||
|
||||
irq trigger source
|
||||
@@ -1,4 +1,4 @@
|
||||
.. _pyb.SD:
|
||||
.. _machine.SD:
|
||||
|
||||
class SD -- secure digital memory card
|
||||
======================================
|
||||
@@ -13,36 +13,29 @@ more info regarding the pins which can be remapped to be used with a SD card.
|
||||
|
||||
Example usage::
|
||||
|
||||
# data, clk and cmd pins must be passed along with
|
||||
from machine import SD
|
||||
import os
|
||||
# clk cmd and dat0 pins must be passed along with
|
||||
# their respective alternate functions
|
||||
sd = pyb.SD(('GP15', 8, 'GP10', 6, 'GP11', 6))
|
||||
sd.mount()
|
||||
sd = machine.SD(pins=('GP10', 'GP11', 'GP15'))
|
||||
os.mount(sd, '/sd')
|
||||
# do normal file operations
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. class:: pyb.SD([pins_tuple])
|
||||
.. class:: machine.SD(id,... )
|
||||
|
||||
Create a SD card object. In order to initalize the card, give it a 6-tuple
|
||||
``(dat_pin, dat_af, clk_pin, clk_af, cmd_pin, cmd_af)`` with the data, clock
|
||||
and cmd pins together their respective alternate functions.
|
||||
Create a SD card object. See ``init()`` for parameters if initialization.
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. method:: sd.init([pins_tuple])
|
||||
.. method:: sd.init(id=0, pins=('GP10', 'GP11', 'GP15'))
|
||||
|
||||
Enable the SD card.
|
||||
Enable the SD card. In order to initalize the card, give it a 3-tuple:
|
||||
``(clk_pin, cmd_pin, dat0_pin)``.
|
||||
|
||||
.. method:: sd.deinit()
|
||||
|
||||
Disable the SD card (also unmounts it to avoid file system crashes).
|
||||
|
||||
.. method:: sd.mount()
|
||||
|
||||
Mount the SD card on the file system. Accesible as ``/sd``.
|
||||
|
||||
.. method:: sd.unmount()
|
||||
|
||||
Unmount the SD card from the file system.
|
||||
Disable the SD card.
|
||||
85
docs/library/machine.SPI.rst
Normal file
85
docs/library/machine.SPI.rst
Normal file
@@ -0,0 +1,85 @@
|
||||
.. _machine.SPI:
|
||||
|
||||
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_wipy
|
||||
|
||||
See usage model of I2C; SPI is very similar. Main difference is
|
||||
parameters to init the SPI bus::
|
||||
|
||||
from machine import SPI
|
||||
spi = SPI(0, mode=SPI.MASTER, baudrate=1000000, polarity=0, phase=0, firstbit=SPI.MSB)
|
||||
|
||||
Only required parameter is mode, must be SPI.MASTER. 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.
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
.. class:: machine.SPI(id, ...)
|
||||
|
||||
Construct an SPI object on the given bus. ``id`` can be only 0.
|
||||
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.
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. method:: spi.init(mode, baudrate=1000000, \*, polarity=0, phase=0, bits=8, firstbit=SPI.MSB, pins=(CLK, MOSI, MISO))
|
||||
|
||||
Initialise the SPI bus with the given parameters:
|
||||
|
||||
- ``mode`` must be ``SPI.MASTER``.
|
||||
- ``baudrate`` is the SCK clock rate.
|
||||
- ``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`` is the width of each transfer, accepted values are 8, 16 and 32.
|
||||
- ``firstbit`` can be ``SPI.MSB`` only.
|
||||
- ``pins`` is an optional tupple with the pins to assign to the SPI bus.
|
||||
|
||||
.. method:: spi.deinit()
|
||||
|
||||
Turn off the SPI bus.
|
||||
|
||||
.. method:: spi.write(buf)
|
||||
|
||||
Write the data contained in ``buf``.
|
||||
Returns the number of bytes written.
|
||||
|
||||
.. method:: spi.read(nbytes, *, write=0x00)
|
||||
|
||||
Read the ``nbytes`` while writing the data specified by ``write``.
|
||||
Return the number of bytes read.
|
||||
|
||||
.. method:: spi.readinto(buf, *, write=0x00)
|
||||
|
||||
Read into the buffer specified by ``buf`` while writing the data specified by
|
||||
``write``.
|
||||
Return the number of bytes read.
|
||||
|
||||
.. method:: spi.write_readinto(write_buf, read_buf)
|
||||
|
||||
Write from ``write_buf`` and read into ``read_buf``. Both buffers must have the
|
||||
same length.
|
||||
Returns the number of bytes written
|
||||
|
||||
Constants
|
||||
---------
|
||||
|
||||
.. data:: SPI.MASTER
|
||||
|
||||
for initialising the SPI bus to master
|
||||
|
||||
.. data:: SPI.MSB
|
||||
|
||||
set the first bit to be the most significant bit
|
||||
196
docs/library/machine.Timer.rst
Normal file
196
docs/library/machine.Timer.rst
Normal file
@@ -0,0 +1,196 @@
|
||||
.. _machine.Timer:
|
||||
|
||||
class Timer -- control internal timers
|
||||
======================================
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
.. note::
|
||||
|
||||
Contrary with the rest of the API, timer IDs start at 1, not a t zero. This is because
|
||||
the ``Timer`` API is still provisional. A new MicroPython wide API will come soon.
|
||||
|
||||
Timers can be used for a great variety of tasks, calling a function periodically,
|
||||
counting events, and generating a PWM signal are among the most common use cases.
|
||||
Each timer consists of 2 16-bit channels and this channels can be tied together to
|
||||
form 1 32-bit timer. The operating mode needs to be configured per timer, but then
|
||||
the period (or the frequency) can be independently configured on each channel.
|
||||
By using the callback method, the timer event can call a Python function.
|
||||
|
||||
Example usage to toggle an LED at a fixed frequency::
|
||||
|
||||
from machine import Timer
|
||||
tim = Timer(4) # create a timer object using timer 4
|
||||
tim.init(mode=Timer.PERIODIC) # initialize it in periodic mode
|
||||
tim_ch = tim.channel(Timer.A, freq=2) # configure channel A at a frequency of 2Hz
|
||||
tim_ch.callback(handler=lambda t:led.toggle()) # toggle a LED on every cycle of the timer
|
||||
|
||||
Example using named function for the callback::
|
||||
|
||||
from machine import Timer
|
||||
tim = Timer(1, mode=Timer.PERIODIC)
|
||||
tim_a = tim.channel(Timer.A, freq=1000)
|
||||
|
||||
led = Pin('GPIO2', mode=Pin.OUT)
|
||||
|
||||
def tick(timer): # we will receive the timer object when being called
|
||||
print(timer.time()) # show current timer's time value (is microseconds)
|
||||
led.toggle() # toggle the LED
|
||||
|
||||
tim_a.callback(handler=tick)
|
||||
|
||||
Further examples::
|
||||
|
||||
from machine import Timer
|
||||
tim1 = Timer(2, mode=Timer.EVENT_COUNT) # initialize it capture mode
|
||||
tim2 = Timer(1, mode=Timer.PWM) # initialize it in PWM mode
|
||||
tim_ch = tim1.channel(Timer.A, freq=1, polarity=Timer.POSITIVE) # start the event counter with a frequency of 1Hz and triggered by positive edges
|
||||
tim_ch = tim2.channel(Timer.B, freq=10000, duty_cycle=50) # start the PWM on channel B with a 50% duty cycle
|
||||
tim_ch.time() # get the current time in usec (can also be set)
|
||||
tim_ch.freq(20) # set the frequency (can also get)
|
||||
tim_ch.duty_cycle(30) # set the duty cycle to 30% (can also get)
|
||||
tim_ch.duty_cycle(30, Timer.NEGATIVE) # set the duty cycle to 30% and change the polarity to negative
|
||||
tim_ch.event_count() # get the number of captured events
|
||||
tim_ch.event_time() # get the the time of the last captured event
|
||||
tim_ch.period(2000000) # change the period to 2 seconds
|
||||
|
||||
|
||||
.. 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:: machine.Timer(id, ...)
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
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 4.
|
||||
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
.. method:: timer.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:
|
||||
|
||||
- ``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.EDGE_TIME`` - Meaure the time pin level changes.
|
||||
- ``Timer.EDGE_COUNT`` - Count the number of pin level changes.
|
||||
|
||||
- ``width`` must be either 16 or 32 (bits). For really low frequencies <= ~1Hz
|
||||
(or large periods), 32-bit timers should be used. 32-bit mode is only available
|
||||
for ``ONE_SHOT`` AND ``PERIODIC`` modes.
|
||||
|
||||
.. method:: timer.deinit()
|
||||
|
||||
Deinitialises the timer. Disables all channels and associated IRQs.
|
||||
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).
|
||||
|
||||
Othwerwise, 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``, defines the polarity of the duty cycle
|
||||
- ``EDGE_TIME`` and ``EDGE_COUNT``, defines the polarity of the pin level change to detect.
|
||||
To detect both rising and falling edges, make ``polarity=Timer.POSITIVE | Timer.NEGATIVE``.
|
||||
- ``duty_cycle`` only applicable to ``PWM``. It's a percentage (0-100)
|
||||
|
||||
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
|
||||
-------
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
.. method:: timerchannel.irq(\*, trigger, priority=1, handler=None)
|
||||
|
||||
The behavior of this callback is heaviliy 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.
|
||||
|
||||
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.time([value])
|
||||
|
||||
Get or set the timer channel current **time** value (in microseconds).
|
||||
|
||||
.. method:: timerchannel.event_count()
|
||||
|
||||
Get the number of edge events counted.
|
||||
|
||||
.. method:: timerchannel.event_time()
|
||||
|
||||
Get the time of ocurrance of the last event.
|
||||
|
||||
.. method:: timerchannel.duty_cycle([value])
|
||||
|
||||
Get or set the duty cycle of the PWM signal (in the range of 0-100).
|
||||
170
docs/library/machine.UART.rst
Normal file
170
docs/library/machine.UART.rst
Normal file
@@ -0,0 +1,170 @@
|
||||
.. _machine.UART:
|
||||
|
||||
class UART -- duplex serial communication bus
|
||||
=============================================
|
||||
|
||||
UART implements the standard UART/USART duplex serial communications protocol. At
|
||||
the physical level it consists of 2 lines: RX and TX. The unit of communication
|
||||
is a character (not to be confused with a string character) which can be 8 or 9
|
||||
bits wide.
|
||||
|
||||
UART objects can be created and initialised using::
|
||||
|
||||
from machine import UART
|
||||
|
||||
uart = UART(1, 9600) # init with given baudrate
|
||||
uart.init(9600, bits=8, parity=None, stop=1) # init with given parameters
|
||||
|
||||
.. only:: port_machineoard
|
||||
|
||||
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.
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
Bits can be 5, 6, 7, 8. Parity can be ``None``, ``UART.EVEN`` or ``UART.ODD``. Stop can be 1 or 2.
|
||||
|
||||
|
||||
A UART object acts like a stream object and reading and writing is done
|
||||
using the standard stream methods::
|
||||
|
||||
uart.read(10) # read 10 characters, returns a bytes object
|
||||
uart.readall() # read all available characters
|
||||
uart.readline() # read a line
|
||||
uart.readinto(buf) # read and store into the given buffer
|
||||
uart.write('abc') # write the 3 characters
|
||||
|
||||
.. only:: port_machineoard
|
||||
|
||||
Individual characters can be read/written using::
|
||||
|
||||
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::
|
||||
|
||||
uart.any() # returns True if any characters waiting
|
||||
|
||||
*Note:* The stream functions ``read``, ``write``, etc. are new in MicroPython v1.3.4.
|
||||
Earlier versions use ``uart.send`` and ``uart.recv``.
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
To check if there is anything to be read, use::
|
||||
|
||||
uart.any() # returns the number of characters available for reading
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
.. class:: machine.UART(bus, ...)
|
||||
|
||||
Construct a UART object on the given bus. ``bus`` can be 0 or 1.
|
||||
If the bus is not given, the default one will be selected (0) or the selection
|
||||
will be made based on the given pins.
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
.. 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``, ``UART.EVEN`` or ``UART.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.
|
||||
|
||||
.. method:: uart.deinit()
|
||||
|
||||
Turn off the UART bus.
|
||||
|
||||
.. method:: uart.any()
|
||||
|
||||
Return the number of characters available for reading.
|
||||
|
||||
.. method:: uart.read([nbytes])
|
||||
|
||||
Read characters. If ``nbytes`` is specified then read at most that many bytes.
|
||||
|
||||
Return value: a bytes object containing the bytes read in. Returns ``b''``
|
||||
on timeout.
|
||||
|
||||
.. method:: uart.readall()
|
||||
|
||||
Read as much data as possible.
|
||||
|
||||
Return value: a bytes object.
|
||||
|
||||
.. 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.
|
||||
|
||||
Return value: number of bytes read and stored into ``buf``.
|
||||
|
||||
.. method:: uart.readline()
|
||||
|
||||
Read a line, ending in a newline character.
|
||||
|
||||
Return value: the line read.
|
||||
|
||||
.. method:: uart.write(buf)
|
||||
|
||||
Write the buffer of bytes to the bus.
|
||||
|
||||
Return value: number of bytes written.
|
||||
|
||||
.. method:: uart.sendbreak()
|
||||
|
||||
Send a break condition on the bus. This drives the bus low for a duration
|
||||
of 13 bits.
|
||||
Return value: ``None``.
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
.. method:: uart.irq(trigger, priority=1, handler=None, wake=machine.IDLE)
|
||||
|
||||
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``.
|
||||
|
||||
.. note::
|
||||
|
||||
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.
|
||||
|
||||
This means that when the handler function is called there will be between 1 to 8
|
||||
characters waiting.
|
||||
|
||||
Returns an irq object.
|
||||
|
||||
Constants
|
||||
---------
|
||||
|
||||
.. data:: UART.EVEN
|
||||
.. data:: UART.ODD
|
||||
|
||||
parity types (anlong with ``None``)
|
||||
|
||||
.. data:: UART.RX_ANY
|
||||
|
||||
IRQ trigger sources
|
||||
@@ -1,22 +1,23 @@
|
||||
.. _pyb.WDT:
|
||||
.. _machine.WDT:
|
||||
|
||||
class WDT -- watchdog timer
|
||||
===========================
|
||||
|
||||
The WDT is used to restart the system when the application crashes and ends
|
||||
up into a non recoverable state. Once started it cannot be stopped or
|
||||
reconfigured in any way. After enabling, the application must "kick" the
|
||||
reconfigured in any way. After enabling, the application must "feed" the
|
||||
watchdog periodically to prevent it from expiring and resetting the system.
|
||||
|
||||
Example usage::
|
||||
|
||||
wdt = pyb.WDT(timeout=2000) # enable with a timeout of 2s
|
||||
from machine import WDT
|
||||
wdt = WDT(timeout=2000) # enable it with a timeout of 2s
|
||||
wdt.feed()
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. class:: pyb.WDT(id=0, timeout=5000)
|
||||
.. class:: machine.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
|
||||
131
docs/library/machine.rst
Normal file
131
docs/library/machine.rst
Normal file
@@ -0,0 +1,131 @@
|
||||
:mod:`machine` --- functions related to the board
|
||||
=================================================
|
||||
|
||||
.. module:: machine
|
||||
:synopsis: functions related to the board
|
||||
|
||||
The ``machine`` module contains specific functions related to the board.
|
||||
|
||||
Reset related functions
|
||||
-----------------------
|
||||
|
||||
.. function:: reset()
|
||||
|
||||
Resets the WiPy in a manner similar to pushing the external RESET
|
||||
button.
|
||||
|
||||
.. function:: reset_cause()
|
||||
|
||||
Get the reset cause. See :ref:`constants <machine_constants>` for the possible return values.
|
||||
|
||||
Interrupt related functions
|
||||
---------------------------
|
||||
|
||||
.. function:: disable_irq()
|
||||
|
||||
Disable interrupt requests.
|
||||
Returns the previous IRQ state: ``False``/``True`` for disabled/enabled IRQs
|
||||
respectively. This return value can be passed to enable_irq to restore
|
||||
the IRQ to its original state.
|
||||
|
||||
.. function:: enable_irq(state=True)
|
||||
|
||||
Enable interrupt requests.
|
||||
If ``state`` is ``True`` (the default value) then IRQs are enabled.
|
||||
If ``state`` is ``False`` then IRQs are disabled. The most common use of
|
||||
this function is to pass it the value returned by ``disable_irq`` to
|
||||
exit a critical section.
|
||||
|
||||
Power related functions
|
||||
-----------------------
|
||||
|
||||
.. function:: freq()
|
||||
|
||||
Returns a tuple of clock frequencies: ``(sysclk,)``
|
||||
These correspond to:
|
||||
|
||||
- sysclk: frequency of the CPU
|
||||
|
||||
.. function:: idle()
|
||||
|
||||
Gates the clock to the CPU, useful to reduce power consumption at any time during
|
||||
short or long periods. Peripherals continue working and execution resumes as soon
|
||||
as any interrupt is triggered (including the systick which has a period of 1ms).
|
||||
Current consumption is reduced to ~12mA (in WLAN STA mode)
|
||||
|
||||
.. function:: sleep()
|
||||
|
||||
Stops the CPU and disables all peripherals except for WLAN. Execution is resumed from
|
||||
the point where the sleep was requested. Wake sources are ``Pin``, ``RTC`` and ``WLAN``.
|
||||
Current consumption is reduced to 950uA (in WLAN STA mode).
|
||||
|
||||
.. function:: deepsleep()
|
||||
|
||||
Stops the CPU and all peripherals including WLAN. Execution is resumed from main, just
|
||||
as with a reset. The reset cause can be checked to know that we are coming from
|
||||
from ``machine.DEEPSLEEP``. Wake sources are ``Pin`` and ``RTC``. Current consumption
|
||||
is reduced to ~5uA.
|
||||
|
||||
.. function:: wake_reason()
|
||||
|
||||
Get the wake reason. See :ref:`constants <machine_constants>` for the possible return values.
|
||||
|
||||
Miscellaneous functions
|
||||
-----------------------
|
||||
|
||||
.. function:: main(filename)
|
||||
|
||||
Set the filename of the main script to run after boot.py is finished. If
|
||||
this function is not called then the default file main.py will be executed.
|
||||
|
||||
It only makes sense to call this function from within boot.py.
|
||||
|
||||
.. function:: rng()
|
||||
|
||||
Return a 24-bit software generated random number.
|
||||
|
||||
.. function:: unique_id()
|
||||
|
||||
Returns a string of 6 bytes (48 bits), which is the unique ID of the MCU.
|
||||
This also corresponds to the ``MAC address`` of the WiPy.
|
||||
|
||||
.. _machine_constants:
|
||||
|
||||
Constants
|
||||
---------
|
||||
|
||||
.. data:: machine.IDLE
|
||||
.. data:: machine.SLEEP
|
||||
.. data:: machine.DEEPSLEEP
|
||||
|
||||
irq wake values
|
||||
|
||||
.. data:: machine.POWER_ON
|
||||
.. data:: machine.HARD_RESET
|
||||
.. data:: machine.WDT_RESET
|
||||
.. data:: machine.DEEPSLEEP_RESET
|
||||
.. data:: machine.SOFT_RESET
|
||||
|
||||
reset causes
|
||||
|
||||
.. data:: machine.WLAN_WAKE
|
||||
.. data:: machine.PIN_WAKE
|
||||
.. data:: machine.RTC_WAKE
|
||||
|
||||
wake reasons
|
||||
|
||||
Classes
|
||||
-------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
machine.ADC.rst
|
||||
machine.I2C.rst
|
||||
machine.Pin.rst
|
||||
machine.RTC.rst
|
||||
machine.SD.rst
|
||||
machine.SPI.rst
|
||||
machine.Timer.rst
|
||||
machine.UART.rst
|
||||
machine.WDT.rst
|
||||
@@ -27,6 +27,44 @@ For example::
|
||||
data = s.recv(1000)
|
||||
s.close()
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
.. _network.server:
|
||||
|
||||
class server
|
||||
============
|
||||
|
||||
The server class controls the behaviour and the configuration of the FTP and telnet
|
||||
services running on the WiPy. Any changes performed using this class' methods will
|
||||
affect both.
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. class:: network.server(id, ...)
|
||||
|
||||
Create a server instance, see ``init`` for parameters of initialization.
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. method:: server.init(\*, login=('micro', 'python'), timeout=300)
|
||||
|
||||
Init (and effectively start the server). Optionally a new ``user``, ``password``
|
||||
and ``timeout`` (in seconds) can be passed.
|
||||
|
||||
.. method:: server.deinit()
|
||||
|
||||
Stop the server
|
||||
|
||||
.. method:: server.timeout([timeout_in_seconds])
|
||||
|
||||
Get or set the server timeout.
|
||||
|
||||
.. method:: server.isrunning()
|
||||
|
||||
Returns ``True`` is the server is running, ``False`` otherwise.
|
||||
|
||||
.. only:: port_pyboard
|
||||
|
||||
class CC3K
|
||||
@@ -178,13 +216,13 @@ For example::
|
||||
|
||||
Dump the WIZnet5x00 registers. Useful for debugging.
|
||||
|
||||
class WLAN
|
||||
==========
|
||||
|
||||
.. _network.WLAN:
|
||||
|
||||
.. only:: port_esp8266
|
||||
|
||||
class WLAN
|
||||
==========
|
||||
|
||||
This class provides a driver for WiFi network processor in the ESP8266. Example usage::
|
||||
|
||||
import network
|
||||
@@ -236,17 +274,41 @@ class WLAN
|
||||
* 0 -- visible
|
||||
* 1 -- hidden
|
||||
|
||||
.. method:: status()
|
||||
|
||||
Return the current status of the wireless connection.
|
||||
|
||||
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 susccessful.
|
||||
|
||||
.. 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.
|
||||
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
class WLAN
|
||||
==========
|
||||
|
||||
This class provides a driver for WiFi network processor in the WiPy. Example usage::
|
||||
|
||||
|
||||
import network
|
||||
import time
|
||||
# setup as a station
|
||||
nic = network.WLAN(mode=WLAN.STA)
|
||||
nic.connect('your-ssid', security=WLAN.WPA2, key='your-key')
|
||||
while not nic.isconnected():
|
||||
pyb.delay(50)
|
||||
print(nic.ifconfig())
|
||||
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
|
||||
...
|
||||
@@ -254,14 +316,22 @@ class WLAN
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. class:: WLAN(..)
|
||||
.. class:: WLAN(id=0, ...)
|
||||
|
||||
Create a WLAN object, and optionally configure it. See ``iwconfig`` for params of configuration.
|
||||
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 exisiting ``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:: iwconfig(\*, mode, ssid, security, key, channel, antenna)
|
||||
.. method:: wlan.init(mode, \*, ssid, auth, channel, antenna)
|
||||
|
||||
Set or get the WiFi network processor configuration.
|
||||
|
||||
@@ -269,101 +339,111 @@ class WLAN
|
||||
|
||||
- ``mode`` can be either ``WLAN.STA`` or ``WLAN.AP``.
|
||||
- ``ssid`` is a string with the ssid name. Only needed when mode is ``WLAN.AP``.
|
||||
- ``security`` can be ``WLAN.OPEN``, ``WLAN.WEP``, ``WLAN.WPA`` or ``WLAN.WPA2``.
|
||||
Only needed when mode is ``WLAN.AP``.
|
||||
- ``key`` is a string with the network password. Not needed when mode is ``WLAN.STA``
|
||||
or security is ``WLAN.OPEN``. If ``security`` is ``WLAN.WEP`` the key must be a
|
||||
string representing hexadecimal values (e.g. 'ABC1DE45BF').
|
||||
- ``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.INTERNAL`` or ``WLAN.EXTERNAL``.
|
||||
``WLAN.INT_ANT`` or ``WLAN.EXT_ANT``.
|
||||
|
||||
For example, you can do::
|
||||
|
||||
# create and configure as an access point
|
||||
nic.iwconfig(mode=WLAN.AP, ssid='wipy-wlan', security=WLAN.WPA2, key='www.wipy.io', channel=7, antenna=WLAN.INTERNAL)
|
||||
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
|
||||
nic.iwconfig(mode=WLAN.STA)
|
||||
wlan.init(mode=WLAN.STA)
|
||||
|
||||
With no arguments given, the current configuration is returned as a namedtuple that looks like this:
|
||||
``(mode=2, ssid='wipy-wlan', security=2, key='www.wipy.io', channel=5, antenna=0)``
|
||||
.. method:: wlan.connect(ssid, \*, auth=None, bssid=None, timeout=5000)
|
||||
|
||||
.. method:: wlan.connect(ssid, \*, security=WLAN.OPEN, key=None, bssid=None, timeout=5000)
|
||||
|
||||
Connect to a wifi access point using the given SSID, and other security
|
||||
parameters.
|
||||
|
||||
- ``key`` is always a string, but if ``security`` 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.
|
||||
|
||||
- ``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``
|
||||
- ``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, security, channel, rssi).
|
||||
|
||||
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. Returns ``False`` otherwise.
|
||||
|
||||
.. method:: wlan.ifconfig(['dhcp' or configtuple])
|
||||
|
||||
With no parameters given eturns a 4-tuple of ``(ip, subnet mask, gateway, DNS server)``.
|
||||
|
||||
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 eturns 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 example::
|
||||
|
||||
nic.ifconfig(('192.168.0.4', '255.255.255.0', '192.168.0.1', '8.8.8.8'))
|
||||
|
||||
.. method:: wlan.mac()
|
||||
|
||||
Returns a 6-byte long bytes object with the MAC address.
|
||||
|
||||
.. method:: wlan.connections()
|
||||
|
||||
Returns a list of the devices currently connected. Each item in the list is a
|
||||
tuple of ``(ssid, mac)``.
|
||||
If the 4-tuple config is given then a static IP is configured. For instance::
|
||||
|
||||
.. method:: wlan.callback(wake_from)
|
||||
wlan.ifconfig(config=('192.168.0.4', '255.255.255.0', '192.168.0.1', '8.8.8.8'))
|
||||
|
||||
Create a callback to be triggered when a WLAN event occurs during ``pyb.Sleep.SUSPENDED``
|
||||
.. 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.
|
||||
|
||||
- ``wake_from`` must be ``pyb.Sleep.SUSPENDED``.
|
||||
- ``handler`` is the function that gets called when the irq is triggered.
|
||||
- ``wake`` must be ``machine.SLEEP``.
|
||||
|
||||
Returns a callback object.
|
||||
Returns an irq object.
|
||||
|
||||
Constants
|
||||
---------
|
||||
|
||||
|
||||
.. data:: WLAN.STA
|
||||
|
||||
WiFi station mode
|
||||
|
||||
.. data:: WLAN.AP
|
||||
|
||||
WiFi access point mode
|
||||
selects the WLAN mode
|
||||
|
||||
.. data:: WLAN.OPEN
|
||||
.. data:: WLAN.WEP
|
||||
.. data:: WLAN.WPA
|
||||
.. data:: WLAN.WPA2
|
||||
|
||||
selects the network security
|
||||
|
||||
.. data:: WLAN.INTERNAL
|
||||
.. data:: WLAN.EXTERNAL
|
||||
.. data:: WLAN.INT_ANT
|
||||
.. data:: WLAN.EXT_ANT
|
||||
|
||||
selects the antenna type
|
||||
|
||||
@@ -71,9 +71,27 @@ Functions
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
.. function:: mkfs(drive)
|
||||
|
||||
Formats the specified drive, must be either ``/flash`` or ``/sd``.
|
||||
.. function:: mount(block_device, mount_point, \*, readonly=False)
|
||||
|
||||
Mounts a block device (like an ``SD`` object) in the specified mount
|
||||
point. Example::
|
||||
|
||||
os.mount(sd, '/sd')
|
||||
|
||||
.. function:: unmount(path)
|
||||
|
||||
Unmounts a prevoulsy mounted block device from the given path.
|
||||
|
||||
.. function:: mkfs(block_device or path)
|
||||
|
||||
Formats the specified path, must be either ``/flash`` or ``/sd``.
|
||||
A block device can also be passed like an ``SD`` object before
|
||||
being mounted.
|
||||
|
||||
.. function:: dupterm(stream_object)
|
||||
|
||||
Duplicate the terminal (the REPL) on the passed stream-like object.
|
||||
The given object must at least implement the ``.read()`` and ``.write()`` methods.
|
||||
|
||||
Constants
|
||||
---------
|
||||
|
||||
@@ -18,16 +18,6 @@ class ADC -- analog to digital conversion
|
||||
val = adc.read_core_vbat() # read MCU VBAT
|
||||
val = adc.read_core_vref() # read MCU VREF
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
Usage::
|
||||
|
||||
import pyb
|
||||
|
||||
adc = pyb.ADC() # create an ADC object
|
||||
apin = adc.channel(pin='GP3') # create an analog pin on GP3
|
||||
val = apin() # read an analog value
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
@@ -39,22 +29,6 @@ Constructors
|
||||
Create an ADC object associated with the given pin.
|
||||
This allows you to then read analog values on that pin.
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
.. class:: pyb.ADC(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
|
||||
-------
|
||||
|
||||
@@ -100,48 +74,3 @@ Methods
|
||||
|
||||
This function does not allocate any memory.
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
.. method:: adc.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:: adc.init()
|
||||
|
||||
Enable the ADC block.
|
||||
|
||||
.. method:: adc.deinit()
|
||||
|
||||
Disable the ADC block.
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
class ADCChannel --- read analog values from internal or external sources
|
||||
=========================================================================
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
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.
|
||||
|
||||
@@ -15,6 +15,9 @@ Example usage::
|
||||
dac = DAC(1) # create DAC 1 on pin X5
|
||||
dac.write(128) # write a value to the DAC (makes X5 1.65V)
|
||||
|
||||
dac = DAC(1, bits=12) # use 12 bit resolution
|
||||
dac.write(4095) # output maximum value, 3.3V
|
||||
|
||||
To output a continuous sine-wave::
|
||||
|
||||
import math
|
||||
@@ -23,27 +26,46 @@ To output a continuous sine-wave::
|
||||
# create a buffer containing a sine-wave
|
||||
buf = bytearray(100)
|
||||
for i in range(len(buf)):
|
||||
buf[i] = 128 + int(127 \* math.sin(2 \* math.pi \* i / len(buf)))
|
||||
buf[i] = 128 + int(127 * math.sin(2 * math.pi * i / len(buf)))
|
||||
|
||||
# output the sine-wave at 400Hz
|
||||
dac = DAC(1)
|
||||
dac.write_timed(buf, 400 \* len(buf), mode=DAC.CIRCULAR)
|
||||
dac.write_timed(buf, 400 * len(buf), mode=DAC.CIRCULAR)
|
||||
|
||||
To output a continuous sine-wave at 12-bit resolution::
|
||||
|
||||
import math
|
||||
from array import array
|
||||
from pyb import DAC
|
||||
|
||||
# create a buffer containing a sine-wave, using half-word samples
|
||||
buf = array('H', 2048 + int(2047 * math.sin(2 * math.pi * i / 128)) for i in range(128))
|
||||
|
||||
# output the sine-wave at 400Hz
|
||||
dac = DAC(1, bits=12)
|
||||
dac.write_timed(buf, 400 * len(buf), mode=DAC.CIRCULAR)
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. class:: pyb.DAC(port)
|
||||
.. class:: pyb.DAC(port, bits=8)
|
||||
|
||||
Construct a new DAC object.
|
||||
|
||||
|
||||
``port`` can be a pin object, or an integer (1 or 2).
|
||||
DAC(1) is on pin X5 and DAC(2) is on pin X6.
|
||||
|
||||
``bits`` is an integer specifying the resolution, and can be 8 or 12.
|
||||
The maximum value for the write and write_timed methods will be
|
||||
2\*\*``bits``-1.
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. method:: dac.init(bits=8)
|
||||
|
||||
Reinitialise the DAC. ``bits`` can be 8 or 12.
|
||||
|
||||
.. method:: dac.noise(freq)
|
||||
|
||||
Generate a pseudo-random noise signal. A new random sample is written
|
||||
@@ -57,13 +79,16 @@ Methods
|
||||
|
||||
.. method:: dac.write(value)
|
||||
|
||||
Direct access to the DAC output (8 bit only at the moment).
|
||||
Direct access to the DAC output. The minimum value is 0. The maximum
|
||||
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)
|
||||
|
||||
Initiates a burst of RAM to DAC using a DMA transfer.
|
||||
The input data is treated as an array of bytes (8 bit data).
|
||||
|
||||
The input data is treated as an array of bytes in 8-bit mode, and
|
||||
an array of unsigned half-words (array typecode 'H') in 12-bit mode.
|
||||
|
||||
``freq`` can be an integer specifying the frequency to write the DAC
|
||||
samples at, using Timer(6). Or it can be an already-initialised
|
||||
Timer object which is used to trigger the DAC sample. Valid timers
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
.. _pyb.HeartBeat:
|
||||
|
||||
class HeartBeat -- heart beat LED
|
||||
=================================
|
||||
|
||||
The HeartBeat class controls the heart beat led which by default
|
||||
flashes once every 5s. The user can disable the HeartBeat and then
|
||||
is free to control this LED manually through GP25 using the Pin
|
||||
class. The GP25 can also be remapped as a PWM output, an this
|
||||
can be used to control the light intesity of the heart beat LED.
|
||||
|
||||
Example usage::
|
||||
|
||||
hb = pyb.HeartBeat()
|
||||
hb.disable() # disable the heart beat
|
||||
hb.enable() # enable the heart beat
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
.. class:: pyb.HeartBeat()
|
||||
|
||||
Create a HeartBeat object.
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. method:: heartbeat.enable()
|
||||
|
||||
Enable the heart beat. The LED will flash once every 5 seconds.
|
||||
|
||||
.. method:: heartbeat.disable()
|
||||
|
||||
Disable the heart beat. The LED can then be controlled manually.
|
||||
|
||||
Example::
|
||||
|
||||
import pyb
|
||||
|
||||
# disable the heart beat
|
||||
pyb.HeartBeat().disable()
|
||||
# get the GP25 pin object
|
||||
hbl = pyb.Pin('GP25')
|
||||
# toggle the led
|
||||
hbl.toggle()
|
||||
...
|
||||
@@ -21,17 +21,6 @@ when created, or initialised later on.
|
||||
i2c.init(I2C.SLAVE, addr=0x42) # init as a slave with given address
|
||||
i2c.deinit() # turn off the peripheral
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
Example::
|
||||
|
||||
from pyb import I2C
|
||||
|
||||
i2c = I2C(0) # create on bus 0
|
||||
i2c = I2C(0, I2C.MASTER) # create and init as a master
|
||||
i2c.init(I2C.MASTER, baudrate=20000) # init as a master
|
||||
i2c.deinit() # turn off the peripheral
|
||||
|
||||
Printing the i2c object gives you information about its configuration.
|
||||
|
||||
.. only:: port_pyboard
|
||||
@@ -67,23 +56,6 @@ Printing the i2c object gives you information about its configuration.
|
||||
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
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
A master must specify the recipient's address::
|
||||
|
||||
i2c.init(I2C.MASTER)
|
||||
i2c.writeto(0x42, '123') # send 3 bytes to slave with address 0x42
|
||||
i2c.writeto(addr=0x42, b'456') # keyword for address
|
||||
|
||||
Master also has other methods::
|
||||
|
||||
i2c.scan() # scan for slaves on the bus, returning
|
||||
# a list of valid addresses
|
||||
i2c.readfrom_mem(0x42, 2, 3) # read 3 bytes from memory of slave 0x42,
|
||||
# starting at address 2 in the slave
|
||||
i2c.writeto_mem(0x42, 2, 'abc') # write 'abc' (3 bytes) to memory of slave 0x42
|
||||
# starting at address 2 in the slave, timeout after 1 second
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
@@ -102,13 +74,6 @@ Constructors
|
||||
- ``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)``
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
.. class:: pyb.I2C(bus, ...)
|
||||
|
||||
Construct an I2C object on the given bus. `bus` can only be 0.
|
||||
If the bus is not given, the default one will be selected (0).
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
@@ -179,54 +144,6 @@ Methods
|
||||
|
||||
Return value: ``None``.
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
.. method:: i2c.init(mode, \*, baudrate=100000, pins=(SDA, SCL))
|
||||
|
||||
Initialise the I2C bus with the given parameters:
|
||||
|
||||
- ``mode`` must be ``I2C.MASTER``
|
||||
- ``baudrate`` is the SCL clock rate
|
||||
- ``pins`` is an optional tuple with the pins to assign to the I2C bus.
|
||||
|
||||
.. method:: i2c.readfrom(addr, nbytes)
|
||||
|
||||
Read ``nbytes`` from the slave specified by ``addr``.
|
||||
Returns a ``bytes`` object with the data read.
|
||||
|
||||
.. method:: i2c.readfrom_into(addr, buf)
|
||||
|
||||
Read into ``buf`` from the slave specified by ``addr``.
|
||||
Returns the number of bytes read.
|
||||
|
||||
.. method:: i2c.writeto(addr, buf, \*, stop=True)
|
||||
|
||||
Write ``buf`` to the slave specified by ``addr``. Set ``stop`` to ``False``
|
||||
if the transfer should be continued.
|
||||
Returns the number of bytes written.
|
||||
|
||||
.. 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``.
|
||||
Param ``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)
|
||||
|
||||
Read into ``buf`` from the slave specified by ``addr`` starting from the memory
|
||||
address specified by ``memaddr``.
|
||||
Param ``addrsize`` specifies the address size in bits.
|
||||
Returns the number of bytes read.
|
||||
|
||||
.. 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``. Param ``addrsize`` specifies the
|
||||
address size in bits.
|
||||
Set ``stop`` to ``False`` if the transfer should be continued.
|
||||
Returns the number of bytes written.
|
||||
|
||||
.. method:: i2c.scan()
|
||||
|
||||
Scan all I2C addresses from 0x01 to 0x7f and return a list of those that respond.
|
||||
|
||||
@@ -63,24 +63,6 @@ Usage Model:
|
||||
that pin has an effective 40k Ohm resistor pulling it to 3V3 or GND
|
||||
respectively (except pin Y5 which has 11k Ohm resistors).
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
Board pins are identified by their string id::
|
||||
|
||||
g = pyb.Pin('GP9', mode=pyb.Pin.OUT, pull=None, drive=pyb.Pin.MED_POWER, alt=-1)
|
||||
|
||||
You can also configure the Pin to generate interrupts. For instance::
|
||||
|
||||
def pincb(pin):
|
||||
print(pin.id())
|
||||
|
||||
pin_int = pyb.Pin('GP10', mode=Pin.IN, pull=pyb.Pin.PULL_DOWN)
|
||||
pin_int.irq(mode=pyb.Pin.IRQ_RISING, handler=pincb)
|
||||
# the callback can be triggered manually
|
||||
pin_int.irq()()
|
||||
# to disable the callback
|
||||
pin_int.irq().disable()
|
||||
|
||||
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.
|
||||
@@ -149,42 +131,6 @@ Methods
|
||||
|
||||
Returns: ``None``.
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
.. method:: pin.init(mode, pull, \*, drive, alt)
|
||||
|
||||
Initialise the pin:
|
||||
|
||||
- ``mode`` can be one of:
|
||||
|
||||
- ``Pin.IN`` - input pin.
|
||||
- ``Pin.OUT`` - output pin in push-pull mode.
|
||||
- ``Pin.OPEN_DRAIN`` - output pin in open-drain mode.
|
||||
- ``Pin.ALT`` - pin mapped to an alternate function.
|
||||
- ``Pin.ALT_OPEN_DRAIN`` - pin mapped to an alternate function in open-drain mode.
|
||||
|
||||
- ``pull`` can be one of:
|
||||
|
||||
- ``None`` - no pull up or down resistor.
|
||||
- ``Pin.PULL_UP`` - pull up resistor enabled.
|
||||
- ``Pin.PULL_DOWN`` - pull down resitor enabled.
|
||||
|
||||
- ``drive`` can be one of:
|
||||
|
||||
- ``Pin.LOW_POWER`` - 2mA drive capability.
|
||||
- ``Pin.MED_POWER`` - 4mA drive capability.
|
||||
- ``Pin.HIGH_POWER`` - 6mA drive capability.
|
||||
|
||||
- ``alt`` is the number of the alternate function. Please refer to the
|
||||
`pinout and alternate functions table. <https://raw.githubusercontent.com/wipy/wipy/master/docs/PinOUT.png>`_
|
||||
for the specific alternate functions that each pin supports.
|
||||
|
||||
Returns: ``None``.
|
||||
|
||||
.. method:: pin.id()
|
||||
|
||||
Get the pin id.
|
||||
|
||||
.. method:: pin.value([value])
|
||||
|
||||
Get or set the digital logic level of the pin:
|
||||
@@ -238,62 +184,6 @@ Methods
|
||||
will match one of the allowed constants for the pull argument to the init
|
||||
function.
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
.. method:: pin([value])
|
||||
|
||||
Pin objects are callable. The call method provides a (fast) shortcut to set and get the value of the pin.
|
||||
See **pin.value** for more details.
|
||||
|
||||
.. method:: pin.toggle()
|
||||
|
||||
Toggle the value of the pin.
|
||||
|
||||
.. method:: pin.mode([mode])
|
||||
|
||||
Get or set the pin mode.
|
||||
|
||||
.. method:: pin.pull([pull])
|
||||
|
||||
Get or set the pin pull.
|
||||
|
||||
.. method:: pin.drive([drive])
|
||||
|
||||
Get or set the pin drive strength.
|
||||
|
||||
.. method:: pin.irq(\*, trigger, priority=1, handler=None, wake=None)
|
||||
|
||||
Create a callback to be triggered when the input level at the pin changes.
|
||||
|
||||
- ``trigger`` configures the pin level which can generate an interrupt. Possible values are:
|
||||
|
||||
- ``Pin.IRQ_FALLING`` interrupt on falling edge.
|
||||
- ``Pin.IRQ_RISING`` interrupt on rising edge.
|
||||
- ``Pin.IRQ_LOW_LEVEL`` interrupt on low level.
|
||||
- ``Pin.IRQ_HIGH_LEVEL`` interrupt on high level.
|
||||
|
||||
The values can be *ORed* together, for instance mode=Pin.IRQ_FALLING | Pin.IRQ_RISING
|
||||
|
||||
- ``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 new characters arrive.
|
||||
- ``wakes`` selects the power mode in which this interrupt can wake up the
|
||||
board. Please note:
|
||||
|
||||
- If ``wake_from=pyb.Sleep.ACTIVE`` any pin can wake the board.
|
||||
- If ``wake_from=pyb.Sleep.SUSPENDED`` pins ``GP2``, ``GP4``, ``GP10``,
|
||||
``GP11``, GP17`` or ``GP24`` can wake the board. Note that only 1
|
||||
of this pins can be enabled as a wake source at the same time, so, only
|
||||
the last enabled pin as a ``pyb.Sleep.SUSPENDED`` wake source will have effect.
|
||||
- If ``wake_from=pyb.Sleep.SUSPENDED`` pins ``GP2``, ``GP4``, ``GP10``,
|
||||
``GP11``, ``GP17`` and ``GP24`` can wake the board. In this case all of the
|
||||
6 pins can be enabled as a ``pyb.Sleep.HIBERNATE`` wake source at the same time.
|
||||
- Values can be ORed to make a pin generate interrupts in more than one power
|
||||
mode.
|
||||
|
||||
Returns a callback object.
|
||||
|
||||
|
||||
Constants
|
||||
---------
|
||||
|
||||
@@ -335,44 +225,6 @@ Constants
|
||||
|
||||
enable the pull-up resistor on the pin
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
.. data:: Pin.IN
|
||||
|
||||
.. data:: Pin.OUT
|
||||
|
||||
.. data:: Pin.OPEN_DRAIN
|
||||
|
||||
.. data:: Pin.ALT
|
||||
|
||||
.. data:: Pin.ALT_OPEN_DRAIN
|
||||
|
||||
Selects the pin mode.
|
||||
|
||||
.. data:: Pin.PULL_UP
|
||||
|
||||
.. data:: Pin.PULL_DOWN
|
||||
|
||||
Selectes the wether there's pull up/down resistor.
|
||||
|
||||
.. data:: Pin.LOW_POWER
|
||||
|
||||
.. data:: Pin.MED_POWER
|
||||
|
||||
.. data:: Pin.HIGH_POWER
|
||||
|
||||
Selects the drive strength.
|
||||
|
||||
.. data:: Pin.IRQ_FALLING
|
||||
|
||||
.. data:: Pin.IRQ_RISING
|
||||
|
||||
.. data:: Pin.IRQ_LOW_LEVEL
|
||||
|
||||
.. data:: Pin.IRQ_HIGH_LEVEL
|
||||
|
||||
Selects the IRQ trigger type.
|
||||
|
||||
.. only:: port_pyboard
|
||||
|
||||
class PinAF -- Pin Alternate Functions
|
||||
|
||||
@@ -41,14 +41,6 @@ Methods
|
||||
``weekday`` is 1-7 for Monday through Sunday.
|
||||
|
||||
``subseconds`` counts down from 255 to 0
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
The 8-tuple has the following format:
|
||||
|
||||
``(year, month, day, weekday, hours, minutes, seconds, milliseconds)``
|
||||
|
||||
``weekday`` is 0-6 for Monday through Sunday.
|
||||
|
||||
.. only:: port_pyboard
|
||||
|
||||
@@ -88,14 +80,3 @@ Methods
|
||||
usable calibration range is:
|
||||
(-511 * 0.954) ~= -487.5 ppm up to (512 * 0.954) ~= 488.5 ppm
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
.. method:: rtc.callback(\*, value, handler=None, wake_from=pyb.Sleep.ACTIVE)
|
||||
|
||||
Create a callback object triggered by a real time clock alarm.
|
||||
|
||||
- ``value`` is the alarm timeout in milliseconds. This parameter is required.
|
||||
- ``handler`` is the function to be called when the callback is triggered.
|
||||
- ``wake_from`` specifies the power mode from where this interrupt can wake
|
||||
up the system.
|
||||
|
||||
|
||||
@@ -26,18 +26,6 @@ there are 3 lines: SCK, MOSI, MISO.
|
||||
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
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
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=1000000, polarity=0, phase=0, firstbit=SPI.MSB)
|
||||
|
||||
Only required parameter is mode, must be SPI.MASTER. 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.
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
@@ -59,16 +47,6 @@ Constructors
|
||||
At the moment, the NSS pin is not used by the SPI driver and is free
|
||||
for other use.
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
.. class:: pyb.SPI(bus, ...)
|
||||
|
||||
Construct an SPI object on the given bus. ``bus`` can be only 1.
|
||||
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.
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
@@ -102,43 +80,6 @@ Methods
|
||||
Printing the SPI object will show you the computed baudrate and the chosen
|
||||
prescaler.
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
.. method:: spi.init(mode, baudrate=1000000, \*, polarity=0, phase=0, bits=8, firstbit=SPI.MSB, pins=(CLK, MOSI, MISO))
|
||||
|
||||
Initialise the SPI bus with the given parameters:
|
||||
|
||||
- ``mode`` must be ``SPI.MASTER``.
|
||||
- ``baudrate`` is the SCK clock rate.
|
||||
- ``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`` is the width of each transfer, accepted values are 8, 16 and 32.
|
||||
- ``firstbit`` can be ``SPI.MSB`` only.
|
||||
- ``pins`` is an optional tupple with the pins to assign to the SPI bus.
|
||||
|
||||
.. method:: spi.write(buf)
|
||||
|
||||
Write the data contained in ``buf``.
|
||||
Returns the number of bytes written.
|
||||
|
||||
.. method:: spi.read(nbytes, *, write=0x00)
|
||||
|
||||
Read the ``nbytes`` while writing the data specified by ``write``.
|
||||
Return the number of bytes read.
|
||||
|
||||
.. method:: spi.readinto(buf, *, write=0x00)
|
||||
|
||||
Read into the buffer specified by ``buf`` while writing the data specified by
|
||||
``write``.
|
||||
Return the number of bytes read.
|
||||
|
||||
.. method:: spi.write_readinto(write_buf, read_buf)
|
||||
|
||||
Write from ``write_buf`` and read into ``read_buf``. Both buffers must have the
|
||||
same length.
|
||||
Returns the number of bytes written
|
||||
|
||||
.. only:: port_pyboard
|
||||
|
||||
.. method:: spi.recv(recv, \*, timeout=5000)
|
||||
@@ -187,13 +128,3 @@ Constants
|
||||
.. data:: SPI.MSB
|
||||
|
||||
set the first bit to be the least or most significant bit
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
.. data:: SPI.MASTER
|
||||
|
||||
for initialising the SPI bus to master
|
||||
|
||||
.. data:: SPI.MSB
|
||||
|
||||
set the first bit to be the most significant bit
|
||||
|
||||
@@ -41,50 +41,6 @@ class Timer -- control internal timers
|
||||
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.
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
Timers can be used for a great variety of tasks, calling a function periodically,
|
||||
counting events, and generating a PWM signal are among the most common use cases.
|
||||
Each timer consists of 2 16-bit channels and this channels can be tied together to
|
||||
form 1 32-bit timer. The operating mode needs to be configured per timer, but then
|
||||
the period (or the frequency) can be independently configured on each channel.
|
||||
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(mode=Timer.PERIODIC) # initialize it in periodic mode
|
||||
tim_ch = tim.channel(Timer.A, freq=2) # configure channel A at a frequency of 2Hz
|
||||
tim_ch.callback(handler=lambda t:led.toggle()) # toggle a LED on every cycle of the timer
|
||||
|
||||
Example using named function for the callback::
|
||||
|
||||
tim = Timer(1, mode=Timer.PERIODIC)
|
||||
tim_a = tim.channel(Timer.A, freq=1000)
|
||||
|
||||
led = Pin('GPIO2', af=0, mode=Pin.OUT)
|
||||
|
||||
def tick(timer): # we will receive the timer object when being called
|
||||
print(timer.time()) # show current timer's time value (is microseconds)
|
||||
led.toggle() # toggle the LED
|
||||
|
||||
tim_a.callback(handler=tick)
|
||||
|
||||
Further examples::
|
||||
|
||||
tim1 = pyb.Timer(2, mode=Timer.EVENT_COUNT) # initialize it capture mode
|
||||
tim2 = pyb.Timer(1, mode=Timer.PWM) # initialize it in PWM mode
|
||||
tim_ch = tim1.channel(Timer.A, freq=1, polarity=Timer.POSITIVE) # start the event counter with a frequency of 1Hz and triggered by positive edges
|
||||
tim_ch = tim2.channel(Timer.B, freq=10000, duty_cycle=50) # start the PWM on channel B with a 50% duty cycle
|
||||
tim_ch.time() # get the current time in usec (can also be set)
|
||||
tim_ch.freq(20) # set the frequency (can also get)
|
||||
tim_ch.duty_cycle(30) # set the duty cycle to 30% (can also get)
|
||||
tim_ch.duty_cycle(30, Timer.NEGATIVE) # set the duty cycle to 30% and change the polarity to negative
|
||||
tim_ch.event_count() # get the number of captured events
|
||||
tim_ch.event_time() # get the the time of the last captured event
|
||||
tim_ch.period(2000000) # change the period to 2 seconds
|
||||
|
||||
|
||||
*Note:* Memory can't be allocated during a callback (an interrupt) and so
|
||||
exceptions raised within a callback don't give much information. See
|
||||
:func:`micropython.alloc_emergency_exception_buf` for how to get around this
|
||||
@@ -102,13 +58,6 @@ Constructors
|
||||
arguments are given, then the timer is initialised by ``init(...)``.
|
||||
``id`` can be 1 to 14, excluding 3.
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
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 4.
|
||||
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
@@ -161,30 +110,6 @@ Methods
|
||||
|
||||
You must either specify freq or both of period and prescaler.
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
.. method:: timer.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:
|
||||
|
||||
- ``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.EDGE_TIME`` - Meaure the time pin level changes.
|
||||
- ``Timer.EDGE_COUNT`` - Count the number of pin level changes.
|
||||
|
||||
- ``width`` must be either 16 or 32 (bits). For really low frequencies <= ~1Hz
|
||||
(or large periods), 32-bit timers should be used. 32-bit mode is only available
|
||||
for ``ONE_SHOT`` AND ``PERIODIC`` modes.
|
||||
|
||||
.. method:: timer.deinit()
|
||||
|
||||
Deinitialises the timer.
|
||||
@@ -280,37 +205,6 @@ Methods
|
||||
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)
|
||||
|
||||
.. 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).
|
||||
|
||||
Othwerwise, 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``, defines the polarity of the duty cycle
|
||||
- ``EDGE_TIME`` and ``EDGE_COUNT``, defines the polarity of the pin level change to detect.
|
||||
To detect both rising and falling edges, make ``polarity=Timer.POSITIVE | Timer.NEGATIVE``.
|
||||
- ``duty_cycle`` only applicable to ``PWM``. It's a percentage (0-100)
|
||||
|
||||
.. only:: port_pyboard
|
||||
|
||||
.. method:: timer.counter([value])
|
||||
@@ -355,32 +249,6 @@ Methods
|
||||
``fun`` is passed 1 argument, the timer object.
|
||||
If ``fun`` is ``None`` then the callback will be disabled.
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
.. method:: timerchannel.callback(\**, value, priority=1, handler=None)
|
||||
|
||||
The behavior of this callback is heaviliy 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.EDGE_COUNT`` the callback is executed when reaching
|
||||
the configured number of events (see ``value`` param below).
|
||||
- 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.
|
||||
- ``value`` is **only valid** when in ``Timer.EDGE_COUNT`` mode and is used to set
|
||||
the number of edge events that will trigger the interrupt.
|
||||
|
||||
Returns a callback object.
|
||||
|
||||
.. only:: port_pyboard
|
||||
|
||||
.. method:: timerchannel.capture([value])
|
||||
@@ -411,29 +279,3 @@ Methods
|
||||
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%.
|
||||
|
||||
.. 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.time([value])
|
||||
|
||||
Get or set the timer channel current **time** value (in microseconds).
|
||||
|
||||
.. method:: timerchannel.event_count()
|
||||
|
||||
Get the number of edge events counted.
|
||||
|
||||
.. method:: timerchannel.event_time()
|
||||
|
||||
Get the time of ocurrance of the last event.
|
||||
|
||||
.. method:: timerchannel.duty_cycle([value])
|
||||
|
||||
Get or set the duty cycle of the PWM signal (in the range of 0-100).
|
||||
|
||||
@@ -22,11 +22,6 @@ UART objects can be created and initialised using::
|
||||
*Note:* with parity=None, only 8 and 9 bits are supported. With parity enabled,
|
||||
only 7 and 8 bits are supported.
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
Bits can be 5, 6, 7, 8. Parity can be ``None``, ``UART.EVEN`` or ``UART.ODD``. Stop can be 1 or 2.
|
||||
|
||||
|
||||
A UART object acts like a stream object and reading and writing is done
|
||||
using the standard stream methods::
|
||||
|
||||
@@ -50,12 +45,6 @@ using the standard stream methods::
|
||||
*Note:* The stream functions ``read``, ``write``, etc. are new in MicroPython v1.3.4.
|
||||
Earlier versions use ``uart.send`` and ``uart.recv``.
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
To check if there is anything to be read, use::
|
||||
|
||||
uart.any() # returns the number of characters available for reading
|
||||
|
||||
Constructors
|
||||
------------
|
||||
|
||||
@@ -77,14 +66,6 @@ Constructors
|
||||
- ``UART(3)`` is on ``YB``: ``(TX, RX) = (Y9, Y10) = (PB10, PB11)``
|
||||
- ``UART(2)`` is on: ``(TX, RX) = (X3, X4) = (PA2, PA3)``
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
.. class:: pyb.UART(bus, ...)
|
||||
|
||||
Construct a UART object on the given bus. ``bus`` can be 0 or 1.
|
||||
If the bus is not given, the default one will be selected (0) or the selection
|
||||
will be made based on the given pins.
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
@@ -114,22 +95,6 @@ Methods
|
||||
*Note:* with parity=None, only 8 and 9 bits are supported. With parity enabled,
|
||||
only 7 and 8 bits are supported.
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
.. 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``, ``UART.EVEN`` or ``UART.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.
|
||||
|
||||
.. method:: uart.deinit()
|
||||
|
||||
Turn off the UART bus.
|
||||
@@ -145,12 +110,6 @@ Methods
|
||||
Write a single character on the bus. ``char`` is an integer to write.
|
||||
Return value: ``None``.
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
.. method:: uart.any()
|
||||
|
||||
Return the number of characters available for reading.
|
||||
|
||||
.. method:: uart.read([nbytes])
|
||||
|
||||
Read characters. If ``nbytes`` is specified then read at most that many bytes.
|
||||
@@ -163,11 +122,6 @@ Methods
|
||||
Return value: a bytes object containing the bytes read in. Returns ``b''``
|
||||
on timeout.
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
Return value: a bytes object containing the bytes read in. Returns ``b''``
|
||||
on timeout.
|
||||
|
||||
.. method:: uart.readall()
|
||||
|
||||
Read as much data as possible.
|
||||
@@ -204,43 +158,12 @@ Methods
|
||||
|
||||
Return value: number of bytes written.
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
Write the buffer of bytes to the bus.
|
||||
|
||||
Return value: number of bytes written.
|
||||
|
||||
.. method:: uart.sendbreak()
|
||||
|
||||
Send a break condition on the bus. This drives the bus low for a duration
|
||||
of 13 bits.
|
||||
Return value: ``None``.
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
.. method:: uart.callback(value, priority=1, handler=None)
|
||||
|
||||
Create a callback to be triggered when data is received on the UART.
|
||||
|
||||
- ``value`` sets the size in bytes of the Rx buffer. Every character
|
||||
received is put into this buffer as long as there's space free.
|
||||
- ``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.
|
||||
|
||||
.. note::
|
||||
|
||||
The handler will be called whenever any of the following two conditions are met:
|
||||
|
||||
- 4 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 might be 1, 2, 3 or 4
|
||||
characters waiting.
|
||||
|
||||
Return a callback object.
|
||||
|
||||
Constants
|
||||
---------
|
||||
|
||||
@@ -250,9 +173,3 @@ Constants
|
||||
.. data:: UART.CTS
|
||||
|
||||
to select the flow control type
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
.. data:: UART.RX_ANY
|
||||
|
||||
IRQ trigger sources
|
||||
|
||||
@@ -63,25 +63,14 @@ Time related functions
|
||||
Reset related functions
|
||||
-----------------------
|
||||
|
||||
.. only:: port_pyboard
|
||||
.. function:: hard_reset()
|
||||
|
||||
.. function:: hard_reset()
|
||||
|
||||
Resets the pyboard in a manner similar to pushing the external RESET
|
||||
button.
|
||||
Resets the pyboard in a manner similar to pushing the external RESET
|
||||
button.
|
||||
|
||||
.. only:: port_wipy
|
||||
.. function:: bootloader()
|
||||
|
||||
.. function:: reset()
|
||||
|
||||
Resets the WiPy in a manner similar to pushing the external RESET
|
||||
button.
|
||||
|
||||
.. only:: port_pyboard
|
||||
|
||||
.. function:: bootloader()
|
||||
|
||||
Activate the bootloader without BOOT\* pins.
|
||||
Activate the bootloader without BOOT\* pins.
|
||||
|
||||
Interrupt related functions
|
||||
---------------------------
|
||||
@@ -169,20 +158,12 @@ Power related functions
|
||||
Put the pyboard into a "deep sleep" state.
|
||||
|
||||
This reduces power consumption to less than 50 uA. To wake from this
|
||||
sleep state requires an external interrupt or a real-time-clock event.
|
||||
sleep state requires a real-time-clock event, or an external interrupt
|
||||
on X1 (PA0=WKUP) or X18 (PC13=TAMP1).
|
||||
Upon waking the system undergoes a hard reset.
|
||||
|
||||
See :meth:`rtc.wakeup` to configure a real-time-clock wakeup event.
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
.. function:: freq([sysclk])
|
||||
|
||||
Returns a tuple of clock frequencies: ``(sysclk)``
|
||||
These correspond to:
|
||||
|
||||
- sysclk: frequency of the CPU
|
||||
|
||||
Miscellaneous functions
|
||||
-----------------------
|
||||
|
||||
@@ -255,12 +236,6 @@ Miscellaneous functions
|
||||
|
||||
Return a 30-bit hardware generated random number.
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
.. function:: rng()
|
||||
|
||||
Return a 24-bit software generated random number.
|
||||
|
||||
.. function:: sync()
|
||||
|
||||
Sync all file systems.
|
||||
@@ -271,13 +246,6 @@ Miscellaneous functions
|
||||
|
||||
Returns a string of 12 bytes (96 bits), which is the unique ID of the MCU.
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
.. function:: unique_id()
|
||||
|
||||
Returns a string of 6 bytes (48 bits), which is the unique ID of the MCU.
|
||||
This also corresponds to the ``MAC address`` of the WiPy.
|
||||
|
||||
Classes
|
||||
-------
|
||||
|
||||
@@ -302,19 +270,3 @@ Classes
|
||||
pyb.Timer.rst
|
||||
pyb.UART.rst
|
||||
pyb.USB_VCP.rst
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
pyb.ADC.rst
|
||||
pyb.HeartBeat.rst
|
||||
pyb.I2C.rst
|
||||
pyb.Pin.rst
|
||||
pyb.RTC.rst
|
||||
pyb.SD.rst
|
||||
pyb.SPI.rst
|
||||
pyb.Timer.rst
|
||||
pyb.UART.rst
|
||||
pyb.WDT.rst
|
||||
|
||||
@@ -44,6 +44,46 @@ Functions
|
||||
|
||||
Sleep for the given number of seconds.
|
||||
|
||||
.. only:: port_wipy
|
||||
|
||||
.. function:: sleep_ms(ms)
|
||||
|
||||
Delay for given number of milliseconds, should be positive or 0.
|
||||
|
||||
.. function:: sleep_us(us)
|
||||
|
||||
Delay for given number of microseconds, should be positive or 0
|
||||
|
||||
.. function:: ticks_ms()
|
||||
|
||||
Returns an increasing millisecond counter with arbitrary reference point,
|
||||
that wraps after some (unspecified) value. The value should be treated as
|
||||
opaque, suitable for use only with ticks_diff().
|
||||
|
||||
.. function:: ticks_us()
|
||||
|
||||
Just like ``ticks_ms`` above, but in microseconds.
|
||||
|
||||
.. function:: ticks_cpu()
|
||||
|
||||
Similar to ``ticks_ms`` and ``ticks_us``, but with higher resolution (usually CPU clocks).
|
||||
|
||||
.. function:: ticks_diff(old, new)
|
||||
|
||||
Measure period between consecutive calls to ticks_ms(), ticks_us(), or ticks_cpu().
|
||||
The value returned by these functions may wrap around at any time, so directly
|
||||
subtracting them is not supported. ticks_diff() should be used instead. "old" value should
|
||||
actually precede "new" value in time, or result is undefined. This function should not be
|
||||
used to measure arbitrarily long periods of time (because ticks_*() functions wrap around
|
||||
and usually would have short period). The expected usage pattern is implementing event
|
||||
polling with timeout::
|
||||
|
||||
# Wait for GPIO pin to be asserted, but at most 500us
|
||||
start = time.ticks_us()
|
||||
while pin.value() == 0:
|
||||
if time.ticks_diff(start, time.ticks_us()) > 500:
|
||||
raise TimeoutError
|
||||
|
||||
.. function:: time()
|
||||
|
||||
Returns the number of seconds, as an integer, since 1/1/2000.
|
||||
|
||||
@@ -1,17 +1,193 @@
|
||||
*******************************
|
||||
:mod:`usocket` -- socket module
|
||||
===============================
|
||||
*******************************
|
||||
|
||||
.. module:: usocket
|
||||
:synopsis: socket module
|
||||
|
||||
Socket functionality.
|
||||
This module provides access to the BSD socket interface.
|
||||
|
||||
Functions
|
||||
---------
|
||||
|
||||
.. function:: getaddrinfo(host, port)
|
||||
.. function:: socket.socket(socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_TCP)
|
||||
|
||||
Create a new socket using the given address family, socket type and protocol number.
|
||||
|
||||
.. function:: socket(family=AF_INET, type=SOCK_STREAM, fileno=-1)
|
||||
.. only:: port_wipy
|
||||
|
||||
Create a socket.
|
||||
.. note::
|
||||
|
||||
SSL sockets need to be created the following way before wrapping them with
|
||||
``ssl.wrap_socket``::
|
||||
|
||||
import socket
|
||||
import ssl
|
||||
s = socket(socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_SEC)
|
||||
ss = ssl.wrap_socket(s)
|
||||
|
||||
.. function:: socket.getaddrinfo(host, port)
|
||||
|
||||
Translate the host/port argument into a sequence of 5-tuples that contain all the
|
||||
necessary arguments for creating a socket connected to that service. The list of
|
||||
5-tuples has following structure::
|
||||
|
||||
(family, type, proto, canonname, sockaddr)
|
||||
|
||||
The following example shows how to connect to a given url::
|
||||
|
||||
s = socket.socket()
|
||||
s.connect(socket.getaddrinfo('www.micropython.org', 80)[0][4])
|
||||
|
||||
Exceptions
|
||||
----------
|
||||
|
||||
.. data:: socket.error
|
||||
.. data:: socket.timeout
|
||||
|
||||
Constants
|
||||
---------
|
||||
|
||||
.. data:: socket.AF_INET
|
||||
|
||||
family types
|
||||
|
||||
.. data:: socket.SOCK_STREAM
|
||||
.. data:: socket.SOCK_DGRAM
|
||||
|
||||
socket types
|
||||
|
||||
.. data:: socket.IPPROTO_UDP
|
||||
.. data:: socket.IPPROTO_TCP
|
||||
.. data:: socket.IPPROTO_SEC
|
||||
|
||||
protocol numbers
|
||||
|
||||
class socket
|
||||
============
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. method:: socket.close
|
||||
|
||||
Mark the socket closed. Once that happens, all future operations on the socket
|
||||
object will fail. The remote end will receive no more data (after queued data is flushed).
|
||||
|
||||
Sockets are automatically closed when they are garbage-collected, but it is recommended
|
||||
to close() them explicitly, or to use a with statement around them.
|
||||
|
||||
.. method:: socket.bind(address)
|
||||
|
||||
Bind the socket to address. The socket must not already be bound. The format of ``address``
|
||||
is: ``(ipv4 address, port)``
|
||||
|
||||
.. method:: socket.listen([backlog])
|
||||
|
||||
Enable a server to accept connections. If backlog is specified, it must be at least 0
|
||||
(if it's lower, it will be set to 0); and specifies the number of unaccepted connections
|
||||
tha the system will allow before refusing new connections. If not specified, a default
|
||||
reasonable value is chosen.
|
||||
|
||||
.. method:: socket.accept()
|
||||
|
||||
Accept a connection. The socket must be bound to an address and listening for connections.
|
||||
The return value is a pair (conn, address) where conn is a new socket object usable to send
|
||||
and receive data on the connection, and address is the address bound to the socket on the
|
||||
other end of the connection.
|
||||
|
||||
.. method:: socket.connect(address)
|
||||
|
||||
Connect to a remote socket at address. The format of address is: ``(ipv4 address, port)``
|
||||
|
||||
.. method:: socket.send(bytes)
|
||||
|
||||
Send data to the socket. The socket must be connected to a remote socket.
|
||||
|
||||
.. method:: socket.sendall(bytes)
|
||||
|
||||
Send data to the socket. The socket must be connected to a remote socket.
|
||||
|
||||
.. method:: socket.recv(bufsize)
|
||||
|
||||
Receive data from the socket. The return value is a bytes object representing the data
|
||||
received. The maximum amount of data to be received at once is specified by bufsize.
|
||||
|
||||
.. method:: socket.sendto(bytes, address)
|
||||
|
||||
Send data to the socket. The socket should not be connected to a remote socket, since the
|
||||
destination socket is specified by address. The ``address`` has the same format as the
|
||||
rest of the methods, see above.
|
||||
|
||||
.. method:: socket.recvfrom(bufsize)
|
||||
|
||||
Receive data from the socket. The return value is a pair (bytes, address) where bytes is a
|
||||
bytes object representing the data received and address is the address of the socket sending
|
||||
the data.
|
||||
|
||||
.. method:: socket.setsockopt(level, optname, value)
|
||||
|
||||
Set the value of the given socket option. The needed symbolic constants are defined in the
|
||||
socket module (SO_* etc.). The value can be an integer or a bytes-like object representing
|
||||
a buffer.
|
||||
|
||||
.. method:: socket.settimeout(value)
|
||||
|
||||
Set a timeout on blocking socket operations. The value argument can be a nonnegative floating
|
||||
point number expressing seconds, or None. If a non-zero value is given, subsequent socket operations
|
||||
will raise a timeout exception if the timeout period value has elapsed before the operation has
|
||||
completed. If zero is given, the socket is put in non-blocking mode. If None is given, the socket
|
||||
is put in blocking mode.
|
||||
|
||||
.. method:: socket.setblocking(flag)
|
||||
|
||||
Set blocking or non-blocking mode of the socket: if flag is false, the socket is set to non-blocking,
|
||||
else to blocking mode.
|
||||
|
||||
This method is a shorthand for certain ``settimeout()`` calls::
|
||||
|
||||
sock.setblocking(True) is equivalent to sock.settimeout(None)
|
||||
sock.setblocking(False) is equivalent to sock.settimeout(0.0)
|
||||
|
||||
.. method:: socket.makefile(mode='rb')
|
||||
|
||||
Return a file object associated with the socket. The exact returned type depends on the arguments
|
||||
given to makefile(). The support is limited to binary modes only ('rb' and 'wb').
|
||||
CPython's arguments: ``encoding``, ``errors`` and ``newline`` are not supported.
|
||||
|
||||
The socket must be in blocking mode; it can have a timeout, but the file object’s internal buffer
|
||||
may end up in a inconsistent state if a timeout occurs.
|
||||
|
||||
.. note::
|
||||
|
||||
**CPython difference:** closing the file object returned by makefile() WILL close the
|
||||
original socket as well.
|
||||
|
||||
.. method:: socket.read(size)
|
||||
|
||||
Read up to size bytes from the socket. Return a bytes object. If ``size`` is not given, it
|
||||
behaves just like ``socket.readall()``, see below.
|
||||
|
||||
.. method:: socket.readall()
|
||||
|
||||
Read all data available from the socket until ``EOF``. This function will not return until
|
||||
the socket is closed.
|
||||
|
||||
.. method:: socket.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.
|
||||
|
||||
Return value: number of bytes read and stored into ``buf``.
|
||||
|
||||
.. method:: socket.readline()
|
||||
|
||||
Read a line, ending in a newline character.
|
||||
|
||||
Return value: the line read.
|
||||
|
||||
.. method:: socket.write(buf)
|
||||
|
||||
Write the buffer of bytes to the socket.
|
||||
|
||||
Return value: number of bytes written.
|
||||
|
||||
61
docs/library/ussl.rst
Normal file
61
docs/library/ussl.rst
Normal file
@@ -0,0 +1,61 @@
|
||||
:mod:`ussl` -- ssl module
|
||||
===============================
|
||||
|
||||
.. module:: ussl
|
||||
:synopsis: TLS/SSL wrapper for socket objects
|
||||
|
||||
This module provides access to Transport Layer Security (often known as
|
||||
“Secure Sockets Layer”) encryption and peer authentication facilities for
|
||||
network sockets, both client-side and server-side.
|
||||
|
||||
Functions
|
||||
---------
|
||||
|
||||
.. function:: ssl.wrap_socket(sock, keyfile=None, certfile=None, server_side=False, cert_reqs=CERT_NONE, ca_certs=None)
|
||||
|
||||
Takes an instance sock of socket.socket, and returns an instance of ssl.SSLSocket, a subtype of
|
||||
``socket.socket``, which wraps the underlying socket in an SSL context. sock must be a ``SOCK_STREAM``
|
||||
socket and protocol number ``socket.IPPROTO_SEC``; other socket types are unsupported. Example::
|
||||
|
||||
import socket
|
||||
import ssl
|
||||
s = socket(socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_SEC)
|
||||
ss = ssl.wrap_socket(s)
|
||||
ss.connect(socket.getaddrinfo('www.google.com', 443)[0][4])
|
||||
|
||||
Certificates must be used in order to validate the other side of the connection, and also to
|
||||
authenticate ourselves with the other end. Such certificates must be stored as files using the
|
||||
FTP server, and they must be placed in specific paths with specific names.
|
||||
|
||||
- The certificate to validate the other side goes in: **'/flash/cert/ca.pem'**
|
||||
- The certificate to authenticate ourselves goes in: **'/flash/cert/cert.pem'**
|
||||
- The key for our own certificate goes in: **'/flash/cert/private.key'**
|
||||
|
||||
.. note::
|
||||
|
||||
When these files are stored, they are placed inside the internal **hidden** file system
|
||||
(just like firmware updates), and therefore they are never visible.
|
||||
|
||||
For instance to connect to the Blynk servers using certificates, take the file ``ca.pem`` located
|
||||
in the `blynk examples folder <https://github.com/wipy/wipy/tree/master/examples/blynk>`_
|
||||
and put it in '/flash/cert/'. Then do::
|
||||
|
||||
import socket
|
||||
import ssl
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_SEC)
|
||||
ss = ssl.wrap_socket(s, cert_reqs=ssl.CERT_REQUIRED, ca_certs='/flash/cert/ca.pem')
|
||||
ss.connect(socket.getaddrinfo('cloud.blynk.cc', 8441)[0][4])
|
||||
|
||||
Exceptions
|
||||
----------
|
||||
|
||||
.. data:: ssl.SSLError
|
||||
|
||||
Constants
|
||||
---------
|
||||
|
||||
.. data:: ssl.CERT_NONE
|
||||
.. data:: ssl.CERT_OPTIONAL
|
||||
.. data:: ssl.CERT_REQUIRED
|
||||
|
||||
supported values in ``cert_reqs``
|
||||
17
docs/library/wipy.rst
Normal file
17
docs/library/wipy.rst
Normal file
@@ -0,0 +1,17 @@
|
||||
*************************************
|
||||
:mod:`wipy` -- WiPy specific features
|
||||
*************************************
|
||||
|
||||
.. module:: wipy
|
||||
:synopsis: WiPy specific features
|
||||
|
||||
The ``wipy`` module contains functions to control specific features of the
|
||||
WiPy, such as the heartbeat LED.
|
||||
|
||||
Functions
|
||||
---------
|
||||
|
||||
.. function:: heartbeat([enable])
|
||||
|
||||
Get or set the state (enabled or disabled) of the heartbeat LED. Accepts and
|
||||
returns boolean values (``True`` or ``False``).
|
||||
@@ -34,8 +34,6 @@
|
||||
<a class="biglink" href="{{ pathto(port + "/general") }}">General information about {{ port_name }}</a><br/>
|
||||
<span class="linkdescr">read this first for a quick overview</span>
|
||||
</p>
|
||||
{% endif %}
|
||||
{% if port == "pyboard" %}
|
||||
<p class="biglink">
|
||||
<a class="biglink" href="{{ pathto(port + "/tutorial/index") }}">Tutorials and code examples</a><br/>
|
||||
<span class="linkdescr">start here</span>
|
||||
@@ -43,7 +41,11 @@
|
||||
{% endif %}
|
||||
<p class="biglink">
|
||||
<a class="biglink" href="{{ pathto("library/index") }}">Library Reference</a><br/>
|
||||
<span class="linkdescr">MicroPython libraries, including the <a href="{{ pathto("library/pyb") }}">pyb module</a></span>
|
||||
{% if port == "wipy" %}
|
||||
<span class="linkdescr">MicroPython libraries, including the <a href="{{ pathto("library/machine") }}">machine module</a></span>
|
||||
{% else %}
|
||||
<span class="linkdescr">MicroPython libraries, including the <a href="{{ pathto("library/pyb") }}">pyb module</a></span>
|
||||
{% endif %}
|
||||
</p>
|
||||
</td>
|
||||
<td width="40%" style="padding-left:2em;">
|
||||
|
||||
@@ -1,6 +1,26 @@
|
||||
General information about the WiPy
|
||||
==================================
|
||||
|
||||
No floating point support
|
||||
-------------------------
|
||||
|
||||
Due to space reasons, there's no floating point support, and no math module. This
|
||||
means that floating point numbers cannot be used anywhere in the code, and that
|
||||
all divisions must be performed using '//' instead of '/'. Example::
|
||||
|
||||
>>> r = 4 // 2 # this will work
|
||||
>>> r = 4 / 2 # this WON'T
|
||||
|
||||
Before applying power
|
||||
---------------------
|
||||
|
||||
.. warning::
|
||||
|
||||
The GPIO pins of the WiPy are NOT 5V tolerant, connecting them to voltages higer
|
||||
than 3.6V will cause irreparable damage to the board. ADC pins, when configured
|
||||
in analog mode cannot withstand voltages above 1.8V. Keep these considerations in
|
||||
mind when wiring your electronics.
|
||||
|
||||
WLAN default behaviour
|
||||
----------------------
|
||||
|
||||
@@ -11,22 +31,46 @@ to gain access to the interactive prompt, open a telnet session to that IP addre
|
||||
the default port (23). You will be asked for credentials:
|
||||
``login: micro`` and ``password: python``
|
||||
|
||||
Local file system and SD card
|
||||
-----------------------------
|
||||
.. _wipy_telnet:
|
||||
|
||||
Telnet REPL
|
||||
-----------
|
||||
|
||||
Linux stock telnet works like a charm (also on OSX), but other tools like putty
|
||||
work quite too. The default credentials are: **user:** ``micro``, **password:** ``python``.
|
||||
See :ref:`network.server <network.server>` for info on how to change the defaults.
|
||||
For instance, on a linux shell (when connected to the WiPy in AP mode)::
|
||||
|
||||
$ telnet 192.168.1.1
|
||||
|
||||
Local file system and FTP access
|
||||
--------------------------------
|
||||
|
||||
There is a small internal file system (a drive) on the WiPy, called ``/flash``,
|
||||
which is stored within the external serial flash memory. If a micro SD card
|
||||
is hooked-up and enabled, it is available as ``/sd``.
|
||||
is hooked-up and mounted, it will be available as well.
|
||||
|
||||
When the WiPy boots up, it always boots from the ``boot.py`` located in the
|
||||
``/flash`` file system. If during the boot process the SD card is enabled and
|
||||
it's selected as the current drive then the WiPy will try to execute ``main.py``
|
||||
that should be located in the SD card.
|
||||
When the WiPy starts up, it always boots from the ``boot.py`` located in the
|
||||
``/flash`` file system.
|
||||
|
||||
The file system is accessible via the native FTP server running in the WiPy.
|
||||
The file system is accessible via the native FTP server running in the WiPy.
|
||||
Open your FTP client of choice and connect to:
|
||||
|
||||
``ftp://192.168.1.1``, ``user: micro``, ``password: python``
|
||||
**url:** ``ftp://192.168.1.1``, **user:** ``micro``, **password:** ``python``
|
||||
|
||||
See :ref:`network.server <network.server>` for info on how to change the defaults.
|
||||
The recommended clients are: Linux stock FTP (also in OSX), Filezilla and FireFTP.
|
||||
For example, on a linux shell::
|
||||
|
||||
$ ftp 192.168.1.1
|
||||
|
||||
The FTP server on the WiPy doesn't support active mode, only passive, therefore,
|
||||
if using the native unix ftp client, just after logging in do::
|
||||
|
||||
ftp> passive
|
||||
|
||||
Besides that, the FTP server only supports one data connection at a time. Check out
|
||||
the Filezilla settings section below for more info.
|
||||
|
||||
FileZilla settings
|
||||
------------------
|
||||
@@ -37,20 +81,37 @@ to one, otherwise FileZilla will try to open a second command connection when re
|
||||
and saving files, and for simplicity and to reduce code size, only one command and one
|
||||
data connections are possible. Other FTP clients might behave in a similar way.
|
||||
|
||||
.. _wipy_firmware_upgrade:
|
||||
|
||||
Upgrading the firmware Over The Air
|
||||
-----------------------------------
|
||||
|
||||
OTA software updates can be performed through the FTP server. Upload the ``mcuimg.bin`` file
|
||||
to: ``/flash/sys/mcuimg.bin`` it will take around 6s. You won't see the file being stored
|
||||
inside ``/flash/sys/`` because it's actually saved bypassing the user file system, but rest
|
||||
assured that it was successfully transferred, and it has been signed with a MD5 checksum to
|
||||
verify its integrity. Now, reset the MCU by pressing the switch on the board, or by typing::
|
||||
inside ``/flash/sys/`` because it's actually saved bypassing the user file system, so it
|
||||
ends up inside the internal **hidden** file system, but rest assured that it was successfully
|
||||
transferred, and it has been signed with a MD5 checksum to verify its integrity. Now, reset
|
||||
the WiPy by pressing the switch on the board, or by typing::
|
||||
|
||||
import pyb
|
||||
pyb.reset()
|
||||
>>> import machine
|
||||
>>> machine.reset()
|
||||
|
||||
Boot modes
|
||||
----------
|
||||
Software updates can be found in: https://github.com/wipy/wipy/releases
|
||||
It's always recommended to update to the latest software, but make sure to
|
||||
read the **release notes** before.
|
||||
|
||||
In order to check your software version, do::
|
||||
|
||||
>>> import os
|
||||
>>> os.uname().release
|
||||
|
||||
If the version number is lower than the latest release found in
|
||||
`the releases <https://github.com/wipy/wipy/releases>`_, go ahead and update your WiPy!
|
||||
|
||||
.. _wipy_boot_modes:
|
||||
|
||||
Boot modes and safe boot
|
||||
------------------------
|
||||
|
||||
If you power up normally, or press the reset button, the WiPy will boot
|
||||
into standard mode; the ``boot.py`` file will be executed first, then
|
||||
@@ -61,7 +122,7 @@ it to the 3v3 output pin) during reset. This procedure also allows going
|
||||
back in time to old firmware versions. The WiPy can hold up to 3 different
|
||||
firmware versions, which are: the factory firmware plus 2 user updates.
|
||||
|
||||
After reset, if ``GP28`` is held high, the heart beat LED will start flashing
|
||||
After reset, if ``GP28`` is held high, the heartbeat LED will start flashing
|
||||
slowly, if after 3 seconds the pin is still being held high, the LED will start
|
||||
blinking a bit faster and the WiPy will select the previous user update to boot.
|
||||
If the previous user update is the desired firmware image, ``GP28`` must be
|
||||
@@ -85,18 +146,19 @@ useful to recover from crash situations caused by the user scripts. The selectio
|
||||
made during safe boot is not persistent, meaning that after the next normal reset,
|
||||
the latest firmware will run again.
|
||||
|
||||
The heart beat LED
|
||||
The heartbeat LED
|
||||
------------------
|
||||
|
||||
By default the heart beat LED flashes once every 4s to signal that the system is
|
||||
alive. This can be overridden through the HeartBeat class:
|
||||
By default the heartbeat LED flashes once every 4s to signal that the system is
|
||||
alive. This can be overridden through the :mod:`wipy` module::
|
||||
|
||||
``pyb.HeartBeat().disable()``
|
||||
>>> import wipy
|
||||
>>> wipy.heartbeat(False)
|
||||
|
||||
There are currently 2 kinds of errors that you might see:
|
||||
|
||||
1. If the heart beat LED flashes quickly, then a Python script(eg ``main.py``)
|
||||
1. If the heartbeat LED flashes quickly, then a Python script(eg ``main.py``)
|
||||
has an error. Use the REPL to debug it.
|
||||
2. If the heart beat LED stays on, then there was a hard fault, you cannot
|
||||
2. If the heartbeat LED stays on, then there was a hard fault, you cannot
|
||||
recover from this, the only way out is to press the reset switch.
|
||||
|
||||
|
||||
@@ -7,27 +7,30 @@ Quick reference for the WiPy
|
||||
:alt: WiPy pinout and alternate functions table
|
||||
:width: 800px
|
||||
|
||||
General board control
|
||||
---------------------
|
||||
General board control (including sleep modes)
|
||||
---------------------------------------------
|
||||
|
||||
See :mod:`pyb`. ::
|
||||
See the :mod:`machine` module::
|
||||
|
||||
import pyb
|
||||
import machine
|
||||
|
||||
help(pyb) # display all members from the pyb module
|
||||
pyb.delay(50) # wait 50 milliseconds
|
||||
pyb.millis() # number of milliseconds since boot-up
|
||||
pyb.freq() # get the CPU frequency
|
||||
pyb.unique_id() # return the 6-byte unique id of the board (the WiPy's MAC address)
|
||||
help(machine) # display all members from the machine module
|
||||
machine.freq() # get the CPU frequency
|
||||
machine.unique_id() # return the 6-byte unique id of the board (the WiPy's MAC address)
|
||||
|
||||
machine.idle() # average curernt decreases to (~12mA), any interrupts wakes it up
|
||||
machine.sleep() # everything except for WLAN is powered down (~950uA avg. current)
|
||||
# wakes from Pin, RTC or WLAN
|
||||
machine.deepsleep() # deepest sleep mode, MCU starts from reset. Wakes from Pin and RTC.
|
||||
|
||||
Pins and GPIO
|
||||
-------------
|
||||
|
||||
See :ref:`pyb.Pin <pyb.Pin>`. ::
|
||||
See :ref:`machine.Pin <machine.Pin>`. ::
|
||||
|
||||
from pyb import Pin
|
||||
from machine import Pin
|
||||
|
||||
# initialize GP2 in gpio mode (af=0) and make it an output
|
||||
# initialize GP2 in gpio mode (alt=0) and make it an output
|
||||
p_out = Pin('GP2', mode=Pin.OUT)
|
||||
p_out.value(1)
|
||||
p_out.value(0)
|
||||
@@ -35,35 +38,35 @@ See :ref:`pyb.Pin <pyb.Pin>`. ::
|
||||
p_out(True)
|
||||
|
||||
# make GP1 an input with the pull-up enabled
|
||||
p_in = Pin('GP1', mode=Pin.IN, pull = Pin.PULL_UP)
|
||||
p_in = Pin('GP1', mode=Pin.IN, pull=Pin.PULL_UP)
|
||||
p_in() # get value, 0 or 1
|
||||
|
||||
Timers
|
||||
------
|
||||
|
||||
See :ref:`pyb.Timer <pyb.Timer>` and :ref:`pyb.Pin <pyb.Pin>`. ::
|
||||
See :ref:`machine.Timer <machine.Timer>` and :ref:`machine.Pin <machine.Pin>`. ::
|
||||
|
||||
from pyb import Timer
|
||||
from pyb import Pin
|
||||
from machine import Timer
|
||||
from machine import Pin
|
||||
|
||||
tim = Timer(1, mode=Timer.PERIODIC)
|
||||
tim_a = tim.channel(Timer.A, freq=1000)
|
||||
tim_a.time() # get the value in microseconds
|
||||
tim_a.freq(1) # 1 Hz
|
||||
|
||||
p_out = Pin('GP2', af=0, mode=Pin.OUT)
|
||||
tim_a.callback(handler=lambda t: p_out.toggle())
|
||||
p_out = Pin('GP2', mode=Pin.OUT)
|
||||
tim_a.irq(handler=lambda t: p_out.toggle())
|
||||
|
||||
PWM (pulse width modulation)
|
||||
----------------------------
|
||||
|
||||
See :ref:`pyb.Pin <pyb.Pin>` and :ref:`pyb.Timer <pyb.Timer>`. ::
|
||||
See :ref:`machine.Pin <machine.Pin>` and :ref:`machine.Timer <machine.Timer>`. ::
|
||||
|
||||
from pyb import Timer
|
||||
from pyb import Pin
|
||||
from machine import Timer
|
||||
from machine import Pin
|
||||
|
||||
# assign GP25 to alternate function 5 (PWM)
|
||||
p_out = Pin('GP25', af=9, type=Pin.STD)
|
||||
# assign GP25 to alternate function 9 (PWM)
|
||||
p_out = Pin('GP25', mode=Pin.AF, alt=9)
|
||||
|
||||
# timer 2 in PWM mode and width must be 16 buts
|
||||
tim = Timer(2, mode=Timer.PWM, width=16)
|
||||
@@ -74,9 +77,9 @@ See :ref:`pyb.Pin <pyb.Pin>` and :ref:`pyb.Timer <pyb.Timer>`. ::
|
||||
ADC (analog to digital conversion)
|
||||
----------------------------------
|
||||
|
||||
See :ref:`pyb.ADC <pyb.ADC>`. ::
|
||||
See :ref:`machine.ADC <machine.ADC>`. ::
|
||||
|
||||
from pyb import ADC
|
||||
from machine import ADC
|
||||
|
||||
adc = ADC()
|
||||
apin = adc.channel(pin='GP3')
|
||||
@@ -85,19 +88,19 @@ See :ref:`pyb.ADC <pyb.ADC>`. ::
|
||||
UART (serial bus)
|
||||
-----------------
|
||||
|
||||
See :ref:`pyb.Pin <pyb.Pin>` and :ref:`pyb.UART <pyb.UART>`. ::
|
||||
See :ref:`machine.UART <machine.UART>`. ::
|
||||
|
||||
from pyb import Pin, UART
|
||||
uart = UART(0, 9600)
|
||||
from machine import UART
|
||||
uart = UART(0, baudrate=9600)
|
||||
uart.write('hello')
|
||||
uart.read(5) # read up to 5 bytes
|
||||
|
||||
SPI bus
|
||||
-------
|
||||
|
||||
See :ref:`pyb.SPI <pyb.SPI>`. ::
|
||||
See :ref:`machine.SPI <machine.SPI>`. ::
|
||||
|
||||
from pyb SPI
|
||||
from machine import SPI
|
||||
|
||||
# configure the SPI master @ 2MHz
|
||||
spi = SPI(0, SPI.MASTER, baudrate=200000, polarity=0, phase=0)
|
||||
@@ -109,9 +112,9 @@ See :ref:`pyb.SPI <pyb.SPI>`. ::
|
||||
I2C bus
|
||||
-------
|
||||
|
||||
See :ref:`pyb.Pin <pyb.Pin>` and :ref:`pyb.I2C <pyb.I2C>`. ::
|
||||
See :ref:`machine.I2C <machine.I2C>`. ::
|
||||
|
||||
from pyb import Pin, I2C
|
||||
from machine import I2C
|
||||
# configure the I2C bus
|
||||
i2c = I2C(0, I2C.MASTER, baudrate=100000)
|
||||
i2c.scan() # returns list of slave addresses
|
||||
@@ -123,9 +126,9 @@ See :ref:`pyb.Pin <pyb.Pin>` and :ref:`pyb.I2C <pyb.I2C>`. ::
|
||||
Watchdog timer (WDT)
|
||||
--------------------
|
||||
|
||||
See :ref:`pyb.WDT <pyb.WDT>`. ::
|
||||
See :ref:`machine.WDT <machine.WDT>`. ::
|
||||
|
||||
from pyb import WDT
|
||||
from machine import WDT
|
||||
|
||||
# enable the WDT with a timeout of 5s (1s is the minimum)
|
||||
wdt = WDT(timeout=5000)
|
||||
@@ -134,81 +137,87 @@ See :ref:`pyb.WDT <pyb.WDT>`. ::
|
||||
Real time clock (RTC)
|
||||
---------------------
|
||||
|
||||
See :ref:`pyb.RTC <pyb.RTC>` and ``pyb.Sleep``. ::
|
||||
See :ref:`machine.RTC <machine.RTC>` ::
|
||||
|
||||
from pyb import RTC, Sleep
|
||||
import machine
|
||||
from machine import RTC
|
||||
|
||||
rtc = pyb.RTC()
|
||||
rtc.datetime((2014, 5, 1, 4, 13, 0, 0, 0))
|
||||
print(rtc.datetime())
|
||||
rtc = machine.RTC() # init with default time and date
|
||||
rtc = RTC(datetime=(2015, 8, 29, 9, 0, 0, 0, None)) # init with a specific time and date
|
||||
print(rtc.now())
|
||||
|
||||
def some_handler (rtc_obj):
|
||||
# trigger the callback again in 30s
|
||||
rtc_obj.callback(value=30000, handler=some_handler)
|
||||
def alarm_handler (rtc_o):
|
||||
pass
|
||||
# do some non blocking operations
|
||||
# warning printing on an irq via telnet is not
|
||||
# possible, only via UART
|
||||
|
||||
# create a RTC alarm that expires in 30s
|
||||
rtc.callback(value=30000, handler=some_handler, wake_from=Sleep.SUSPENDED)
|
||||
# create a RTC alarm that expires after 5 seconds
|
||||
rtc.alarm(time=5000, repeat=False)
|
||||
|
||||
# enable RTC interrupts
|
||||
rtc_i = rtc.irq(trigger=RTC.ALARM0, handler=alarm_handler, wake=machine.SLEEP)
|
||||
|
||||
# go into suspended mode waiting for the RTC alarm to expire and wake us up
|
||||
Sleep.suspend()
|
||||
machine.sleep()
|
||||
|
||||
SD card
|
||||
-------
|
||||
|
||||
See :ref:`pyb.SD <pyb.SD>`. ::
|
||||
See :ref:`machine.SD <machine.SD>`. ::
|
||||
|
||||
from pyb import SD
|
||||
from machine import SD
|
||||
import os
|
||||
|
||||
# SD card pins need special configuration so we pass them to the constructor
|
||||
# clock pin, cmd pin, data0 pin
|
||||
sd = SD(pins=('GP10', 'GP11', 'GP15'))
|
||||
# or use default ones for the expansion board
|
||||
sd = SD()
|
||||
os.mount(sd, '/sd')
|
||||
|
||||
WLAN (WiFi)
|
||||
-----------
|
||||
|
||||
See :ref:`network.WLAN <network.WLAN>` and ``pyb.Sleep``. ::
|
||||
See :ref:`network.WLAN <network.WLAN>` and :mod:`machine`. ::
|
||||
|
||||
import machine
|
||||
from network import WLAN
|
||||
from pyb import Sleep
|
||||
|
||||
# configure the WLAN subsystem in station mode (the default is AP)
|
||||
wifi = WLAN(WLAN.STA)
|
||||
wifi = WLAN(mode=WLAN.STA)
|
||||
# go for fixed IP settings
|
||||
wifi.ifconfig(('192.168.0.107', '255.255.255.0', '192.168.0.1', '8.8.8.8'))
|
||||
wifi.ifconfig(config=('192.168.0.107', '255.255.255.0', '192.168.0.1', '8.8.8.8'))
|
||||
wifi.scan() # scan for available netrworks
|
||||
wifi.connect(ssid='mynetwork', security=2, key='mynetworkkey')
|
||||
wifi.connect(ssid='mynetwork', auth=(WLAN.WPA2, 'mynetworkkey'))
|
||||
while not wifi.isconnected():
|
||||
pass
|
||||
print(wifi.ifconfig())
|
||||
# enable wake on WLAN
|
||||
wifi.callback(wake_from=Sleep.SUSPENDED)
|
||||
wifi.irq(wake=machine.SLEEP)
|
||||
# go to sleep
|
||||
Sleep.suspend()
|
||||
machine.sleep()
|
||||
# now, connect to the FTP or the Telnet server and the WiPy will wake-up
|
||||
|
||||
Sleep and power modes control
|
||||
-----------------------------
|
||||
Telnet and FTP server
|
||||
---------------------
|
||||
|
||||
See ``pyb.Sleep``. ::
|
||||
See :ref:`network.server <network.server>` ::
|
||||
|
||||
from pyb import Sleep
|
||||
from network import server
|
||||
|
||||
Sleep.idle() # lowest sleep mode (~12mA), any interrupts wakes it up
|
||||
Sleep.suspend() # everything except for WLAN is powered down (~950uA)
|
||||
# wakes from Pin, RTC or WLAN
|
||||
|
||||
Sleep.hibernate() # deepest sleep mode, MCU starts from reset. Wakes from Pin and RTC.
|
||||
# init with new user, pass word and seconds timeout
|
||||
server = server.init(login=('user', 'password'), timeout=60)
|
||||
server.timeout(300) # change the timeout
|
||||
server.timeout() # get the timeout
|
||||
server.isrunning() # check wether the server is running or not
|
||||
|
||||
Heart beat LED
|
||||
--------------
|
||||
|
||||
See :ref:`pyb.HeartBeat <pyb.HeartBeat>`. ::
|
||||
See :mod:`wipy`. ::
|
||||
|
||||
from pyb import HeartBeat
|
||||
import wipy
|
||||
|
||||
# disable the heart beat indication (you are free to use this LED connected to GP25)
|
||||
HeartBeat().disable()
|
||||
# enable the heart beat again
|
||||
HeartBeat().enable()
|
||||
wipy.heartbeat(False) # disable the heartbeat LED
|
||||
wipy.heartbeat(True) # enable the heartbeat LED
|
||||
wipy.heartbeat() # get the heartbeat state
|
||||
|
||||
19
docs/wipy/tutorial/blynk.rst
Normal file
19
docs/wipy/tutorial/blynk.rst
Normal file
@@ -0,0 +1,19 @@
|
||||
Getting started with Blynk and the WiPy
|
||||
---------------------------------------
|
||||
|
||||
Blynk is a platform with iOS and Android apps to control
|
||||
Arduino, Raspberry Pi and the likes over the Internet.
|
||||
You can easily build graphic interfaces for all your
|
||||
projects by simply dragging and dropping widgets.
|
||||
|
||||
There are several examples available that work out-of-the-box with
|
||||
the WiPy. Before anything else, make sure that your WiPy is running
|
||||
the latest software, check :ref:`OTA How-To <wipy_firmware_upgrade>` for instructions.
|
||||
|
||||
1. Get the `Blynk library <https://github.com/wipy/wipy/blob/master/lib/blynk/BlynkLib.py>`_ and put it in ``/flash/lib/`` via FTP.
|
||||
2. Get the `Blynk examples <https://github.com/wipy/wipy/tree/master/examples/blynk>`_ edit the network settings, and afterwards
|
||||
upload them to ``/flash/lib/`` via FTP as well.
|
||||
3. Follow the instructions on each example to setup the Blynk dashboard on your smartphone or tablet.
|
||||
4. Give it a try, for instance::
|
||||
|
||||
>>> execfile('01_simple.py')
|
||||
17
docs/wipy/tutorial/index.rst
Normal file
17
docs/wipy/tutorial/index.rst
Normal file
@@ -0,0 +1,17 @@
|
||||
.. _wipy_tutorial_index:
|
||||
|
||||
WiPy tutorials and examples
|
||||
===========================
|
||||
|
||||
Before starting, make sure that you are running the latest firmware,
|
||||
for instrucctions see :ref:`OTA How-To <wipy_firmware_upgrade>`.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
:numbered:
|
||||
|
||||
intro.rst
|
||||
repl.rst
|
||||
blynk.rst
|
||||
wlan.rst
|
||||
reset.rst
|
||||
64
docs/wipy/tutorial/intro.rst
Normal file
64
docs/wipy/tutorial/intro.rst
Normal file
@@ -0,0 +1,64 @@
|
||||
Introduction to the WiPy
|
||||
========================
|
||||
|
||||
To get the most out of your WiPy, there are a few basic things to
|
||||
understand about how it works.
|
||||
|
||||
Caring for your WiPy and expansion board
|
||||
----------------------------------------
|
||||
|
||||
Because the WiPy/expansion board does not have a housing it needs a bit of care:
|
||||
|
||||
- Be gentle when plugging/unplugging the USB cable. Whilst the USB connector
|
||||
is well soldered and is relatively strong, if it breaks off it can be very
|
||||
difficult to fix.
|
||||
|
||||
- Static electricity can shock the components on the WiPy and destroy them.
|
||||
If you experience a lot of static electricity in your area (eg dry and cold
|
||||
climates), take extra care not to shock the WiPy. If your WiPy came
|
||||
in a ESD bag, then this bag is the best way to store and carry the
|
||||
pyboard as it will protect it agains static discharges.
|
||||
|
||||
As long as you take care of the hardware, you should be okay. It's almost
|
||||
impossible to break the software on the WiPy, so feel free to play around
|
||||
with writing code as much as you like. If the filesystem gets corrupt, see
|
||||
below on how to reset it. In the worst case you might need to do a safe boot,
|
||||
which is explained in detail :ref:`here <wipy_boot_modes>`.
|
||||
|
||||
Plugging into the expansion board and powering on
|
||||
-------------------------------------------------
|
||||
|
||||
The expansion board can power the WiPy via USB. The WiPy comes with a sticker
|
||||
on top of the RF shield tha labels all pins, and this should match the label
|
||||
numbers on the expansion board headers. When pluggin it in, the WiPy antenna
|
||||
will end up on top of the SD card connector of the expansion board. A video
|
||||
showing how to do this can be found `here <https://www.youtube.com/watch?v=47D9MZ9zFQw>`_.
|
||||
|
||||
Expansion board hardware guide
|
||||
------------------------------
|
||||
|
||||
The document explaining the hardware details of the expansion board can be found
|
||||
`here <https://github.com/wipy/wipy/blob/master/docs/User_manual_exp_board.pdf>`_.
|
||||
|
||||
Powering by an external power source
|
||||
------------------------------------
|
||||
|
||||
The WiPy can be powered by a battery or other external power source.
|
||||
|
||||
**Be sure to connect the positive lead of the power supply to VIN, and
|
||||
ground to GND. There is no polarity protection on the pyboard so you
|
||||
must be careful when connecting anything to VIN.**
|
||||
|
||||
- When powering via ``VIN``:
|
||||
|
||||
**The input voltage must be between 3.6V and 5.5V.**
|
||||
|
||||
- When powering via ``3V3``:
|
||||
|
||||
**The input volatge must be exactly 3V3, ripple free and from a supply capable
|
||||
of sourcing at least 300mA of current**
|
||||
|
||||
Performing firmware upgrades
|
||||
----------------------------
|
||||
|
||||
For detalied instructions see :ref:`OTA How-To <wipy_firmware_upgrade>`.
|
||||
137
docs/wipy/tutorial/repl.rst
Normal file
137
docs/wipy/tutorial/repl.rst
Normal file
@@ -0,0 +1,137 @@
|
||||
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 WiPy. Using
|
||||
the REPL is by far the easiest way to test out your code and run commands.
|
||||
You can use the REPL in addition to writing scripts in ``main.py``.
|
||||
|
||||
To use the REPL, you must connect to the WiPy either via :ref:`telnet <wipy_telnet>`,
|
||||
or with a USB to serial converter wired to the one the two UARTs on the
|
||||
WiPy. To enable REPL duplication on UART0 (the one accesible via the expansion board)
|
||||
do::
|
||||
|
||||
>>> from machine import UART
|
||||
>>> import os
|
||||
>>> uart = UART(0, 115200)
|
||||
>>> o.dupterm(uart)
|
||||
|
||||
Place this piece of code inside your `boot.py` so that it's done automatically after
|
||||
reset.
|
||||
|
||||
Windows
|
||||
-------
|
||||
|
||||
You need to install the pyboard driver to use the serial USB device.
|
||||
The driver is on the pyboard's USB flash drive, and is called ``pybcdc.inf``.
|
||||
|
||||
To install this driver you need to go to Device Manager
|
||||
for your computer, find the pyboard in the list of devices (it should have
|
||||
a warning sign next to it because it's not working yet), right click on
|
||||
the pyboard device, select Properties, then Install Driver. You need to
|
||||
then select the option to find the driver manually (don't use Windows auto update),
|
||||
navigate to the pyboard's USB drive, and select that. It should then install.
|
||||
After installing, go back to the Device Manager to find the installed pyboard,
|
||||
and see which COM port it is (eg COM4).
|
||||
More comprehensive instructions can be found in the
|
||||
`Guide for pyboard on Windows (PDF) <http://micropython.org/resources/Micro-Python-Windows-setup.pdf>`_.
|
||||
Please consult this guide if you are having problems installing the driver.
|
||||
|
||||
The best option is to download the free program PuTTY:
|
||||
`putty.exe <http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html>`_.
|
||||
|
||||
**In order to get to the telnet REPL:**
|
||||
|
||||
Using putty, select ``Telnet`` as connection type, leave the default port (23)
|
||||
and enter the IP address of your WiPy (192.168.1.1 when in ``WLAN.AP`` mode),
|
||||
then click open.
|
||||
|
||||
**In order to get to the REPL UART:**
|
||||
|
||||
Using your serial program you must connect to the COM port that you found in the
|
||||
previous step. With PuTTY, click on "Session" in the left-hand panel, then click
|
||||
the "Serial" radio button on the right, then enter you COM port (eg COM4) in the
|
||||
"Serial Line" box. Finally, click the "Open" button.
|
||||
|
||||
Mac OS X
|
||||
--------
|
||||
|
||||
Open a terminal and run::
|
||||
|
||||
$ telnet 192.168.1.1
|
||||
|
||||
or::
|
||||
|
||||
$ screen /dev/tty.usbmodem* 115200
|
||||
|
||||
When you are finished and want to exit screen, type CTRL-A CTRL-\\.
|
||||
|
||||
Linux
|
||||
-----
|
||||
|
||||
Open a terminal and run::
|
||||
|
||||
$ telnet 192.168.1.1
|
||||
|
||||
or::
|
||||
|
||||
$ screen /dev/ttyUSB0 115200
|
||||
|
||||
You can also try ``picocom`` or ``minicom`` instead of screen. You may have to
|
||||
use ``/dev/ttyUSB01`` or a higher number for ``ttyUSB``. And, you may need to give
|
||||
yourself the correct permissions to access this devices (eg group ``uucp`` or ``dialout``,
|
||||
or use sudo).
|
||||
|
||||
Using the REPL prompt
|
||||
---------------------
|
||||
|
||||
Now let's try running some MicroPython code directly on the WiPy.
|
||||
|
||||
With your serial program open (PuTTY, screen, picocom, etc) you may see a blank
|
||||
screen with a flashing cursor. Press Enter and you should be presented with a
|
||||
MicroPython prompt, i.e. ``>>>``. Let's make sure it is working with the obligatory test::
|
||||
|
||||
>>> print("hello WiPy!")
|
||||
hello WiPy!
|
||||
|
||||
In the above, you should not type in the ``>>>`` characters. They are there to
|
||||
indicate that you should type the text after it at the prompt. In the end, once
|
||||
you have entered the text ``print("hello pyboard!")`` and pressed Enter, the output
|
||||
on your screen should look like it does above.
|
||||
|
||||
If you already know some python you can now try some basic commands here.
|
||||
|
||||
If any of this is not working you can try either a hard reset or a soft reset;
|
||||
see below.
|
||||
|
||||
Go ahead and try typing in some other commands. For example::
|
||||
|
||||
>>> from machine import Pin
|
||||
>>> import wipy
|
||||
>>> wipy.heartbeat(False) # disable the heartbeat
|
||||
>>> led = Pin('GP25', mode=Pin.OUT)
|
||||
>>> led(1)
|
||||
>>> led(0)
|
||||
>>> led.toggle()
|
||||
>>> 1 + 2
|
||||
3
|
||||
>>> 4 // 2
|
||||
2
|
||||
>>> 20 * 'py'
|
||||
'pypypypypypypypypypypypypypypypypypypypy'
|
||||
|
||||
Resetting the board
|
||||
-------------------
|
||||
|
||||
If something goes wrong, you can reset the board in two ways. The first is to press CTRL-D
|
||||
at the MicroPython prompt, which performs a soft reset. You will see a message something like::
|
||||
|
||||
>>>
|
||||
PYB: soft reboot
|
||||
MicroPython v1.4.6-146-g1d8b5e5 on 2015-10-21; WiPy with CC3200
|
||||
Type "help()" for more information.
|
||||
>>>
|
||||
|
||||
If that isn't working you can perform a hard reset (turn-it-off-and-on-again) by pressing the
|
||||
RST switch (the small black button next to the heartbeat LED). During telnet, this will end
|
||||
your session, disconnecting whatever program that you used to connect to the WiPy.
|
||||
54
docs/wipy/tutorial/reset.rst
Normal file
54
docs/wipy/tutorial/reset.rst
Normal file
@@ -0,0 +1,54 @@
|
||||
Reset and boot modes
|
||||
====================
|
||||
|
||||
There are soft resets and hard resets.
|
||||
|
||||
- A soft reset simply clears the state of the MicroPython virtual machine,
|
||||
but leaves hardware peripherals unaffected. To do a soft reset, simply press
|
||||
**Ctrl+D** on the REPL, or within a script do::
|
||||
|
||||
import sys
|
||||
sys.exit()
|
||||
|
||||
- A hard reset is the same as performing a power cycle to the board. In order to
|
||||
hard reset the WiPy, press the switch on the board or::
|
||||
|
||||
import machine
|
||||
machine.reset()
|
||||
|
||||
Safe boot
|
||||
---------
|
||||
|
||||
If something goes wrong with your WiPy, don't panic! It is almost
|
||||
impossible for you to break the WiPy by programming the wrong thing.
|
||||
|
||||
The first thing to try is to boot in safe mode: this temporarily skips
|
||||
execution of ``boot.py`` and ``main.py`` and gives default WLAN settings.
|
||||
|
||||
If you have problems with the filesystem you can :ref:`format the internal flash
|
||||
drive <wipy_factory_reset>`.
|
||||
|
||||
To boot in safe mode, follow the detailed instructions described :ref:`here <wipy_boot_modes>`.
|
||||
|
||||
In safe mode, the ``boot.py`` and ``main.py`` files are not executed, and so
|
||||
the WiPy boots up with default settings. This means you now have access
|
||||
to the filesystem, and you can edit ``boot.py`` and ``main.py`` to fix any problems.
|
||||
|
||||
Entering safe mode is temporary, and does not make any changes to the
|
||||
files on the WiPy.
|
||||
|
||||
.. _wipy_factory_reset:
|
||||
|
||||
Factory reset the filesystem
|
||||
----------------------------
|
||||
|
||||
If you WiPy's filesystem gets corrupted (very unlikely, but possible), you
|
||||
can format it very easily byt doing::
|
||||
|
||||
>>> import os
|
||||
>>> os.mkfs('/flash')
|
||||
|
||||
Resetting the filesystem deletes all files on the internal WiPy storage
|
||||
(not the SD card), and restores the files ``boot.py`` and ``main.py`` back
|
||||
to their original state after the next reset.
|
||||
|
||||
61
docs/wipy/tutorial/wlan.rst
Normal file
61
docs/wipy/tutorial/wlan.rst
Normal file
@@ -0,0 +1,61 @@
|
||||
WLAN step by step
|
||||
=================
|
||||
|
||||
The WLAN is a system feature of the WiPy, therefore it is always enabled
|
||||
(even while in ``machine.SLEEP``), except when deepsleep mode is entered.
|
||||
|
||||
In order to retrieve the current WLAN instance, do::
|
||||
|
||||
>>> from network import WLAN
|
||||
>>> wlan = WLAN() # we call the constructor without params
|
||||
|
||||
You can check the current mode (which is always ``WLAN.AP`` after power up)::
|
||||
|
||||
>>> wlan.mode()
|
||||
|
||||
Connecting to your home router
|
||||
------------------------------
|
||||
|
||||
The WLAN network card always boots in ``WLAN.AP`` mode, so we must first configure
|
||||
it as a station::
|
||||
|
||||
from network import WLAN
|
||||
wlan = WLAN(mode=WLAN.STA)
|
||||
|
||||
Now you can proceed to scan for networks::
|
||||
|
||||
nets = wlan.scan()
|
||||
for net in nets:
|
||||
if net.ssid == 'mywifi':
|
||||
print('Network found!')
|
||||
wlan.connect(net.ssid, auth=(net.sec, 'mywifikey'), timeout=5000)
|
||||
while not wlan.isconnected():
|
||||
machine.idle() # save power while waiting
|
||||
print('WLAN connection succeeded!)
|
||||
break
|
||||
|
||||
Assigning a static IP address when booting
|
||||
------------------------------------------
|
||||
|
||||
If you want your WiPy to connect to your home router while after boot-up, and with a fixed
|
||||
IP address so that you can access it via telnet or FTP, use the following script::
|
||||
|
||||
import machine
|
||||
from network import WLAN
|
||||
wlan = WLAN() # get current object, without changing the mode
|
||||
|
||||
if machine.reset_cause() != machine.SOFT_RESET:
|
||||
wlan.init(WLAN.STA)
|
||||
# configuration below MUST match your home router settings!!
|
||||
wlan.ifconfig(config=('192.168.178.107', '255.255.255.0', '192.168.178.1', '8.8.8.8'))
|
||||
|
||||
if not wlan.isconnected():
|
||||
wlan.connect(net.ssid, auth=(net.sec, 'mywifikey'), timeout=5000)
|
||||
while not wlan.isconnected():
|
||||
machine.idle() # save power while waiting
|
||||
break
|
||||
|
||||
.. note::
|
||||
|
||||
Notice how we check for the reset cause and the connection status, this is crucial in order
|
||||
to be able to soft reset the WiPy during a telnet session without breaking the connection.
|
||||
@@ -5,6 +5,7 @@ MicroPython documentation contents
|
||||
|
||||
wipy/quickref.rst
|
||||
wipy/general.rst
|
||||
wipy/tutorial/index.rst
|
||||
library/index.rst
|
||||
reference/index.rst
|
||||
license.rst
|
||||
|
||||
@@ -5,6 +5,7 @@ MicroPython documentation and references
|
||||
|
||||
wipy/quickref.rst
|
||||
wipy/general.rst
|
||||
wipy/tutorial/index.rst
|
||||
library/index.rst
|
||||
license.rst
|
||||
wipy_contents.rst
|
||||
|
||||
@@ -51,10 +51,12 @@ class SDCard:
|
||||
for i in range(16):
|
||||
self.spi.send(0xff)
|
||||
|
||||
# CMD0: init card; should return R1_IDLE_STATE (allow 2 attempts)
|
||||
if self.cmd(0, 0, 0x95) != R1_IDLE_STATE:
|
||||
if self.cmd(0, 0, 0x95) != R1_IDLE_STATE:
|
||||
raise OSError("no SD card")
|
||||
# CMD0: init card; should return R1_IDLE_STATE (allow 5 attempts)
|
||||
for _ in range(5):
|
||||
if self.cmd(0, 0, 0x95) == R1_IDLE_STATE:
|
||||
break
|
||||
else:
|
||||
raise OSError("no SD card")
|
||||
|
||||
# CMD8: determine card version
|
||||
r = self.cmd(8, 0x01aa, 0x87, 4)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user