From 2146cdab5e276f9c1fc26156579491d3d3a2c3ac Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Tue, 9 Aug 2016 21:13:27 +0300 Subject: [PATCH 001/129] docs/esp8266/tutorial/pins: Fix typo in commands for pin input mode. --- docs/esp8266/tutorial/pins.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/esp8266/tutorial/pins.rst b/docs/esp8266/tutorial/pins.rst index 639267d2ee..a44f40d3a7 100644 --- a/docs/esp8266/tutorial/pins.rst +++ b/docs/esp8266/tutorial/pins.rst @@ -14,7 +14,7 @@ Here, the "0" is the pin that you want to access. Usually you want to configure the pin to be input or output, and you do this when constructing it. To make an input pin use:: - >>> pin = machine.Pin(0, machine.Pin.OUT, machine.Pin.PULL_UP) + >>> pin = machine.Pin(0, machine.Pin.IN, machine.Pin.PULL_UP) You can either use PULL_UP or None for the input pull-mode. If it's not specified then it defaults to None, which is no pull resistor. From b203c1774e4eb6bb6bc04b99d0a5f06f0aa04e40 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 10 Aug 2016 12:44:47 +1000 Subject: [PATCH 002/129] esp8266: Fix reading of pin object for GPIO16. Pin(16) now works as an input. --- esp8266/modpybpin.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esp8266/modpybpin.c b/esp8266/modpybpin.c index 166d6f566f..79406867af 100644 --- a/esp8266/modpybpin.c +++ b/esp8266/modpybpin.c @@ -301,7 +301,7 @@ STATIC mp_obj_t pyb_pin_call(mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw, pyb_pin_obj_t *self = self_in; if (n_args == 0) { // get pin - return MP_OBJ_NEW_SMALL_INT(GPIO_INPUT_GET(self->phys_port)); + return MP_OBJ_NEW_SMALL_INT(pin_get(self->phys_port)); } else { // set pin pin_set(self->phys_port, mp_obj_is_true(args[0])); From 8a15e0b1c74f0251ad549b1c8ec8f41538b4a2ac Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 10 Aug 2016 12:45:40 +1000 Subject: [PATCH 003/129] esp8266: PULL_UP is not supported on Pin(16), so raise an exception. --- esp8266/modpybpin.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/esp8266/modpybpin.c b/esp8266/modpybpin.c index 79406867af..8916da64f6 100644 --- a/esp8266/modpybpin.c +++ b/esp8266/modpybpin.c @@ -244,7 +244,11 @@ STATIC mp_obj_t pyb_pin_obj_init_helper(pyb_pin_obj_t *self, mp_uint_t n_args, c // configure the GPIO as requested if (self->phys_port == 16) { - // TODO: Set pull up/pull down + // only pull-down seems to be supported by the hardware, and + // we only expose pull-up behaviour in software + if (pull != GPIO_PULL_NONE) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Pin(16) doesn't support pull")); + } } else { PIN_FUNC_SELECT(self->periph, self->func); #if 0 From 72ae3c72c7341656bcc610a5671e5cc23f7cf280 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 10 Aug 2016 13:26:11 +1000 Subject: [PATCH 004/129] tools/mpy-tool.py: Support freezing float literals with obj-repr C. The tool now generates code for freezing floats in obj-repr A, B or C, with the specific representation detected at compile time using macros. --- tools/mpy-tool.py | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/tools/mpy-tool.py b/tools/mpy-tool.py index 972ede8325..a7c3d8f918 100755 --- a/tools/mpy-tool.py +++ b/tools/mpy-tool.py @@ -42,6 +42,7 @@ else: # end compatibility code import sys +import struct from collections import namedtuple sys.path.append('../py') @@ -315,9 +316,10 @@ class RawCode: '{.neg=%u, .fixed_dig=1, .alloc=%u, .len=%u, .dig=(uint%u_t[]){%s}}};' % (obj_name, neg, ndigs, ndigs, bits_per_dig, digs)) elif type(obj) is float: - # works for REPR A and B only + print('#if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_A || MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_B') print('STATIC const mp_obj_float_t %s = {{&mp_type_float}, %.16g};' % (obj_name, obj)) + print('#endif') else: # TODO raise FreezeError(self, 'freezing of object %r is not implemented' % (obj,)) @@ -328,7 +330,18 @@ class RawCode: for qst in self.qstrs: print(' (mp_uint_t)MP_OBJ_NEW_QSTR(%s),' % global_qstrs[qst].qstr_id) for i in range(len(self.objs)): - print(' (mp_uint_t)&const_obj_%s_%u,' % (self.escaped_name, i)) + if type(self.objs[i]) is float: + print('#if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_A || MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_B') + print(' (mp_uint_t)&const_obj_%s_%u,' % (self.escaped_name, i)) + print('#elif MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C') + n = struct.unpack(' Date: Wed, 10 Aug 2016 21:39:23 +0300 Subject: [PATCH 005/129] docs/esp8266/intro: Add command to install esptool.py 1.0.1 via pip. It used a standard BootROM programming algo and may be useful as a fallback. --- docs/esp8266/tutorial/intro.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/esp8266/tutorial/intro.rst b/docs/esp8266/tutorial/intro.rst index 8c356b913f..32e9326b37 100644 --- a/docs/esp8266/tutorial/intro.rst +++ b/docs/esp8266/tutorial/intro.rst @@ -135,6 +135,10 @@ after it, here are troubleshooting recommendations: rate may be too high and lead to errors. Try a more common 115200 baud rate instead in such cases. +* If lower baud rate didn't help, you may want to try older version of + esptool.py, which had a different programming algorithm:: + pip install esptool==1.0.1 + * The ``--flash_size`` option in the commands above is mandatory. Omitting it will lead to a corrupted firmware. From 4e36dd570ba039a5d9af7b181eb5a4b8f6f921de Mon Sep 17 00:00:00 2001 From: ilovezfs Date: Wed, 10 Aug 2016 07:35:20 -0700 Subject: [PATCH 006/129] unix/mpconfigport.h: Don't include stdio.h on MacOS. Fixes build errors such as "../lib/utils/printf.c:43:5: error: expected parameter declarator" --- unix/mpconfigport.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/unix/mpconfigport.h b/unix/mpconfigport.h index c449e7316f..86b6001d5b 100644 --- a/unix/mpconfigport.h +++ b/unix/mpconfigport.h @@ -305,5 +305,7 @@ void mp_unix_mark_exec(void); #define _DIRENT_HAVE_D_INO (1) #endif +#ifndef __APPLE__ // For debugging purposes, make printf() available to any source file. #include +#endif From dfb8144037b5d61a55397871801d560f21a232dd Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 11 Aug 2016 13:00:23 +1000 Subject: [PATCH 007/129] stmhal/boards: Update STM32L476 pin defs to include ADC channels. This patch introduces proper ADC Pin definitions in stm32l476_af.csv. Originally provided by @tobbad. --- stmhal/boards/stm32l476_af.csv | 238 ++++++++++++++++----------------- 1 file changed, 116 insertions(+), 122 deletions(-) diff --git a/stmhal/boards/stm32l476_af.csv b/stmhal/boards/stm32l476_af.csv index 6dea7e092e..d67c33880f 100644 --- a/stmhal/boards/stm32l476_af.csv +++ b/stmhal/boards/stm32l476_af.csv @@ -1,122 +1,116 @@ -Port,,AF0,AF1,AF2,AF3,AF4,AF5,AF6,AF7,AF8,AF9,AF10,AF11,AF12,AF13,AF14,AF15 -,,SYS_AF,TIM1/TIM2/TIM5/TIM8/LPTIM1,TIM1/TIM2/TIM3/TIM4/TIM5,TIM8,I2C1/I2C2/I2C3,SPI1/SPI2,SPI3/DFSDM,USART1/USART2/USART3,"UART4, -UART5, -LPUART1","CAN1, TSC","OTG_FS, QUADSPI",LCD,"SDMMC1, COMP1, -COMP2, FMC, -SWPMI1","SAI1, SAI2","TIM2, TIM15, -TIM16, TIM17, -LPTIM2",EVENTOUT -PortA,PA0,,TIM2_CH1,TIM5_CH1,TIM8_ETR,,,,USART2_CTS,UART4_TX,,,,,SAI1_EXTCLK,TIM2_ETR,EVENTOUT -PortA,PA1,,TIM2_CH2,TIM5_CH2,,,,,USART2_RTS_DE,UART4_RX,,,LCD_SEG0,,,TIM15_CH1N,EVENTOUT -PortA,PA2,,TIM2_CH3,TIM5_CH3,,,,,USART2_TX,,,,LCD_SEG1,,SAI2_EXTCLK,TIM15_CH1,EVENTOUT -PortA,PA3,,TIM2_CH4,TIM5_CH4,,,,,USART2_RX,,,,LCD_SEG2,,,TIM15_CH2,EVENTOUT -PortA,PA4,,,,,,SPI1_NSS,SPI3_NSS,USART2_CK,,,,,,SAI1_FS_B,LPTIM2_OUT,EVENTOUT -PortA,PA5,,TIM2_CH1,TIM2_ETR,TIM8_CH1N,,SPI1_SCK,,,,,,,,,LPTIM2_ETR,EVENTOUT -PortA,PA6,,TIM1_BKIN,TIM3_CH1,TIM8_BKIN,,SPI1_MISO,,USART3_CTS,,,QUADSPI_BK1_IO3,LCD_SEG3,TIM1_BKIN_COMP2,TIM8_BKIN_COMP2,TIM16_CH1,EVENTOUT -PortA,PA7,,TIM1_CH1N,TIM3_CH2,TIM8_CH1N,,SPI1_MOSI,,,,,QUADSPI_BK1_IO2,LCD_SEG4,,,TIM17_CH1,EVENTOUT -PortA,PA8,MCO,TIM1_CH1,,,,,,USART1_CK,,,OTG_FS_SOF,LCD_COM0,,,LPTIM2_OUT,EVENTOUT -PortA,PA9,,TIM1_CH2,,,,,,USART1_TX,,,,LCD_COM1,,,TIM15_BKIN,EVENTOUT -PortA,PA10,,TIM1_CH3,,,,,,USART1_RX,,,OTG_FS_ID,LCD_COM2,,,TIM17_BKIN,EVENTOUT -PortA,PA11,,TIM1_CH4,TIM1_BKIN2,,,,,USART1_CTS,,CAN1_RX,OTG_FS_DM,,TIM1_BKIN2_COMP1,,,EVENTOUT -PortA,PA12,,TIM1_ETR,,,,,,USART1_RTS_DE,,CAN1_TX,OTG_FS_DP,,,,,EVENTOUT -PortA,PA13,JTMS-SWDIO,IR_OUT,,,,,,,,,OTG_FS_NOE,,,,,EVENTOUT -PortA,PA14,JTCK-SWCLK,,,,,,,,,,,,,,,EVENTOUT -PortA,PA15,JTDI,TIM2_CH1,TIM2_ETR,,,SPI1_NSS,SPI3_NSS,,UART4_RTS_DE,TSC_G3_IO1,,LCD_SEG17,,SAI2_FS_B,,EVENTOUT -PortB,PB0,,TIM1_CH2N,TIM3_CH3,TIM8_CH2N,,,,USART3_CK,,,QUADSPI_BK1_IO1,LCD_SEG5,COMP1_OUT,,,EVENTOUT -PortB,PB1,,TIM1_CH3N,TIM3_CH4,TIM8_CH3N,,,DFSDM_DATIN0,USART3_RTS_DE,,,QUADSPI_BK1_IO0,LCD_SEG6,,,LPTIM2_IN1,EVENTOUT -PortB,PB2,RTC_OUT,LPTIM1_OUT,,,I2C3_SMBA,,DFSDM_CKIN0,,,,,,,,,EVENTOUT -PortB,PB3,JTDO-TRACESWO,TIM2_CH2,,,,SPI1_SCK,SPI3_SCK,USART1_RTS_DE,,,,LCD_SEG7,,SAI1_SCK_B,,EVENTOUT -PortB,PB4,NJTRST,,TIM3_CH1,,,SPI1_MISO,SPI3_MISO,USART1_CTS,UART5_RTS_DE,TSC_G2_IO1,,LCD_SEG8,,SAI1_MCLK_B,TIM17_BKIN,EVENTOUT -PortB,PB5,,LPTIM1_IN1,TIM3_CH2,,I2C1_SMBA,SPI1_MOSI,SPI3_MOSI,USART1_CK,UART5_CTS,TSC_G2_IO2,,LCD_SEG9,COMP2_OUT,SAI1_SD_B,TIM16_BKIN,EVENTOUT -PortB,PB6,,LPTIM1_ETR,TIM4_CH1,TIM8_BKIN2,I2C1_SCL,,DFSDM_DATIN5,USART1_TX,,TSC_G2_IO3,,,TIM8_BKIN2_COMP2,SAI1_FS_B,TIM16_CH1N,EVENTOUT -PortB,PB7,,LPTIM1_IN2,TIM4_CH2,TIM8_BKIN,I2C1_SDA,,DFSDM_CKIN5,USART1_RX,UART4_CTS,TSC_G2_IO4,,LCD_SEG21,FMC_NL,TIM8_BKIN_COMP1,TIM17_CH1N,EVENTOUT -PortB,PB8,,,TIM4_CH3,,I2C1_SCL,,DFSDM_DATIN6,,,CAN1_RX,,LCD_SEG16,SDMMC1_D4,SAI1_MCLK_A,TIM16_CH1,EVENTOUT -PortB,PB9,,IR_OUT,TIM4_CH4,,I2C1_SDA,SPI2_NSS,DFSDM_CKIN6,,,CAN1_TX,,LCD_COM3,SDMMC1_D5,SAI1_FS_A,TIM17_CH1,EVENTOUT -PortB,PB10,,TIM2_CH3,,,I2C2_SCL,SPI2_SCK,DFSDM_DATIN7,USART3_TX,LPUART1_RX,,QUADSPI_CLK,LCD_SEG10,COMP1_OUT,SAI1_SCK_A,,EVENTOUT -PortB,PB11,,TIM2_CH4,,,I2C2_SDA,,DFSDM_CKIN7,USART3_RX,LPUART1_TX,,QUADSPI_NCS,LCD_SEG11,COMP2_OUT,,,EVENTOUT -PortB,PB12,,TIM1_BKIN,,TIM1_BKIN_COMP2,I2C2_SMBA,SPI2_NSS,DFSDM_DATIN1,USART3_CK,LPUART1_RTS_DE,TSC_G1_IO1,,LCD_SEG12,SWPMI1_IO,SAI2_FS_A,TIM15_BKIN,EVENTOUT -PortB,PB13,,TIM1_CH1N,,,I2C2_SCL,SPI2_SCK,DFSDM_CKIN1,USART3_CTS,LPUART1_CTS,TSC_G1_IO2,,LCD_SEG13,SWPMI1_TX,SAI2_SCK_A,TIM15_CH1N,EVENTOUT -PortB,PB14,,TIM1_CH2N,,TIM8_CH2N,I2C2_SDA,SPI2_MISO,DFSDM_DATIN2,USART3_RTS_DE,,TSC_G1_IO3,,LCD_SEG14,SWPMI1_RX,SAI2_MCLK_A,TIM15_CH1,EVENTOUT -PortB,PB15,RTC_REFIN,TIM1_CH3N,,TIM8_CH3N,,SPI2_MOSI,DFSDM_CKIN2,,,TSC_G1_IO4,,LCD_SEG15,SWPMI1_SUSPEND,SAI2_SD_A,TIM15_CH2,EVENTOUT -PortC,PC0,,LPTIM1_IN1,,,I2C3_SCL,,DFSDM_DATIN4,,LPUART1_RX,,,LCD_SEG18,,,LPTIM2_IN1,EVENTOUT -PortC,PC1,,LPTIM1_OUT,,,I2C3_SDA,,DFSDM_CKIN4,,LPUART1_TX,,,LCD_SEG19,,,,EVENTOUT -PortC,PC2,,LPTIM1_IN2,,,,SPI2_MISO,DFSDM_CKOUT,,,,,LCD_SEG20,,,,EVENTOUT -PortC,PC3,,LPTIM1_ETR,,,,SPI2_MOSI,,,,,,LCD_VLCD,,SAI1_SD_A,LPTIM2_ETR,EVENTOUT -PortC,PC4,,,,,,,,USART3_TX,,,,LCD_SEG22,,,,EVENTOUT -PortC,PC5,,,,,,,,USART3_RX,,,,LCD_SEG23,,,,EVENTOUT -PortC,PC6,,,TIM3_CH1,TIM8_CH1,,,DFSDM_CKIN3,,,TSC_G4_IO1,,LCD_SEG24,SDMMC1_D6,SAI2_MCLK_A,,EVENTOUT -PortC,PC7,,,TIM3_CH2,TIM8_CH2,,,DFSDM_DATIN3,,,TSC_G4_IO2,,LCD_SEG25,SDMMC1_D7,SAI2_MCLK_B,,EVENTOUT -PortC,PC8,,,TIM3_CH3,TIM8_CH3,,,,,,TSC_G4_IO3,,LCD_SEG26,SDMMC1_D0,,,EVENTOUT -PortC,PC9,,TIM8_BKIN2,TIM3_CH4,TIM8_CH4,,,,,,TSC_G4_IO4,OTG_FS_NOE,LCD_SEG27,SDMMC1_D1,SAI2_EXTCLK,TIM8_BKIN2_COMP1,EVENTOUT -PortC,PC10,,,,,,,SPI3_SCK,USART3_TX,UART4_TX,TSC_G3_IO2,,LCD_COM4/LCD_SEG28/LCD_SEG40,SDMMC1_D2,SAI2_SCK_B,,EVENTOUT -PortC,PC11,,,,,,,SPI3_MISO,USART3_RX,UART4_RX,TSC_G3_IO3,,LCD_COM5/LCD_SEG29/LCD_SEG41,SDMMC1_D3,SAI2_MCLK_B,,EVENTOUT -PortC,PC12,,,,,,,SPI3_MOSI,USART3_CK,UART5_TX,TSC_G3_IO4,,LCD_COM6/LCD_SEG30/LCD_SEG42,SDMMC1_CK,SAI2_SD_B,,EVENTOUT -PortC,PC13,,,,,,,,,,,,,,,,EVENTOUT -PortC,PC14,,,,,,,,,,,,,,,,EVENTOUT -PortC,PC15,,,,,,,,,,,,,,,,EVENTOUT -PortD,PD0,,,,,,SPI2_NSS,DFSDM_DATIN7,,,CAN1_RX,,,FMC_D2,,,EVENTOUT -PortD,PD1,,,,,,SPI2_SCK,DFSDM_CKIN7,,,CAN1_TX,,,FMC_D3,,,EVENTOUT -PortD,PD2,,,TIM3_ETR,,,,,USART3_RTS_DE,UART5_RX,TSC_SYNC,,LCD_COM7/LCD_SEG31/LCD_SEG43,SDMMC1_CMD,,,EVENTOUT -PortD,PD3,,,,,,SPI2_MISO,DFSDM_DATIN0,USART2_CTS,,,,,FMC_CLK,,,EVENTOUT -PortD,PD4,,,,,,SPI2_MOSI,DFSDM_CKIN0,USART2_RTS_DE,,,,,FMC_NOE,,,EVENTOUT -PortD,PD5,,,,,,,,USART2_TX,,,,,FMC_NWE,,,EVENTOUT -PortD,PD6,,,,,,,DFSDM_DATIN1,USART2_RX,,,,,FMC_NWAIT,SAI1_SD_A,,EVENTOUT -PortD,PD7,,,,,,,DFSDM_CKIN1,USART2_CK,,,,,FMC_NE1,,,EVENTOUT -PortD,PD8,,,,,,,,USART3_TX,,,,LCD_SEG28,FMC_D13,,,EVENTOUT -PortD,PD9,,,,,,,,USART3_RX,,,,LCD_SEG29,FMC_D14,SAI2_MCLK_A,,EVENTOUT -PortD,PD10,,,,,,,,USART3_CK,,TSC_G6_IO1,,LCD_SEG30,FMC_D15,SAI2_SCK_A,,EVENTOUT -PortD,PD11,,,,,,,,USART3_CTS,,TSC_G6_IO2,,LCD_SEG31,FMC_A16,SAI2_SD_A,LPTIM2_ETR,EVENTOUT -PortD,PD12,,,TIM4_CH1,,,,,USART3_RTS_DE,,TSC_G6_IO3,,LCD_SEG32,FMC_A17,SAI2_FS_A,LPTIM2_IN1,EVENTOUT -PortD,PD13,,,TIM4_CH2,,,,,,,TSC_G6_IO4,,LCD_SEG33,FMC_A18,,LPTIM2_OUT,EVENTOUT -PortD,PD14,,,TIM4_CH3,,,,,,,,,LCD_SEG34,FMC_D0,,,EVENTOUT -PortD,PD15,,,TIM4_CH4,,,,,,,,,LCD_SEG35,FMC_D1,,,EVENTOUT -PortE,PE0,,,TIM4_ETR,,,,,,,,,LCD_SEG36,FMC_NBL0,,TIM16_CH1,EVENTOUT -PortE,PE1,,,,,,,,,,,,LCD_SEG37,FMC_NBL1,,TIM17_CH1,EVENTOUT -PortE,PE2,TRACECK,,TIM3_ETR,,,,,,,TSC_G7_IO1,,LCD_SEG38,FMC_A23,SAI1_MCLK_A,,EVENTOUT -PortE,PE3,TRACED0,,TIM3_CH1,,,,,,,TSC_G7_IO2,,LCD_SEG39,FMC_A19,SAI1_SD_B,,EVENTOUT -PortE,PE4,TRACED1,,TIM3_CH2,,,,DFSDM_DATIN3,,,TSC_G7_IO3,,,FMC_A20,SAI1_FS_A,,EVENTOUT -PortE,PE5,TRACED2,,TIM3_CH3,,,,DFSDM_CKIN3,,,TSC_G7_IO4,,,FMC_A21,SAI1_SCK_A,,EVENTOUT -PortE,PE6,TRACED3,,TIM3_CH4,,,,,,,,,,FMC_A22,SAI1_SD_A,,EVENTOUT -PortE,PE7,,TIM1_ETR,,,,,DFSDM_DATIN2,,,,,,FMC_D4,SAI1_SD_B,,EVENTOUT -PortE,PE8,,TIM1_CH1N,,,,,DFSDM_CKIN2,,,,,,FMC_D5,SAI1_SCK_B,,EVENTOUT -PortE,PE9,,TIM1_CH1,,,,,DFSDM_CKOUT,,,,,,FMC_D6,SAI1_FS_B,,EVENTOUT -PortE,PE10,,TIM1_CH2N,,,,,DFSDM_DATIN4,,,TSC_G5_IO1,QUADSPI_CLK,,FMC_D7,SAI1_MCLK_B,,EVENTOUT -PortE,PE11,,TIM1_CH2,,,,,DFSDM_CKIN4,,,TSC_G5_IO2,QUADSPI_NCS,,FMC_D8,,,EVENTOUT -PortE,PE12,,TIM1_CH3N,,,,SPI1_NSS,DFSDM_DATIN5,,,TSC_G5_IO3,QUADSPI_BK1_IO0,,FMC_D9,,,EVENTOUT -PortE,PE13,,TIM1_CH3,,,,SPI1_SCK,DFSDM_CKIN5,,,TSC_G5_IO4,QUADSPI_BK1_IO1,,FMC_D10,,,EVENTOUT -PortE,PE14,,TIM1_CH4,TIM1_BKIN2,TIM1_BKIN2_COMP2,,SPI1_MISO,,,,,QUADSPI_BK1_IO2,,FMC_D11,,,EVENTOUT -PortE,PE15,,TIM1_BKIN,,TIM1_BKIN_COMP1,,SPI1_MOSI,,,,,QUADSPI_BK1_IO3,,FMC_D12,,,EVENTOUT -PortF,PF0,,,,,I2C2_SDA,,,,,,,,FMC_A0,,,EVENTOUT -PortF,PF1,,,,,I2C2_SCL,,,,,,,,FMC_A1,,,EVENTOUT -PortF,PF2,,,,,I2C2_SMBA,,,,,,,,FMC_A2,,,EVENTOUT -PortF,PF3,,,,,,,,,,,,,FMC_A3,,,EVENTOUT -PortF,PF4,,,,,,,,,,,,,FMC_A4,,,EVENTOUT -PortF,PF5,,,,,,,,,,,,,FMC_A5,,,EVENTOUT -PortF,PF6,,TIM5_ETR,TIM5_CH1,,,,,,,,,,,SAI1_SD_B,,EVENTOUT -PortF,PF7,,,TIM5_CH2,,,,,,,,,,,SAI1_MCLK_B,,EVENTOUT -PortF,PF8,,,TIM5_CH3,,,,,,,,,,,SAI1_SCK_B,,EVENTOUT -PortF,PF9,,,TIM5_CH4,,,,,,,,,,,SAI1_FS_B,TIM15_CH1,EVENTOUT -PortF,PF10,,,,,,,,,,,,,,,TIM15_CH2,EVENTOUT -PortF,PF11,,,,,,,,,,,,,,,,EVENTOUT -PortF,PF12,,,,,,,,,,,,,FMC_A6,,,EVENTOUT -PortF,PF13,,,,,,,DFSDM_DATIN6,,,,,,FMC_A7,,,EVENTOUT -PortF,PF14,,,,,,,DFSDM_CKIN6,,,TSC_G8_IO1,,,FMC_A8,,,EVENTOUT -PortF,PF15,,,,,,,,,,TSC_G8_IO2,,,FMC_A9,,,EVENTOUT -PortG,PG0,,,,,,,,,,TSC_G8_IO3,,,FMC_A10,,,EVENTOUT -PortG,PG1,,,,,,,,,,TSC_G8_IO4,,,FMC_A11,,,EVENTOUT -PortG,PG2,,,,,,SPI1_SCK,,,,,,,FMC_A12,SAI2_SCK_B,,EVENTOUT -PortG,PG3,,,,,,SPI1_MISO,,,,,,,FMC_A13,SAI2_FS_B,,EVENTOUT -PortG,PG4,,,,,,SPI1_MOSI,,,,,,,FMC_A14,SAI2_MCLK_B,,EVENTOUT -PortG,PG5,,,,,,SPI1_NSS,,,LPUART1_CTS,,,,FMC_A15,SAI2_SD_B,,EVENTOUT -PortG,PG6,,,,,I2C3_SMBA,,,,LPUART1_RTS_DE,,,,,,,EVENTOUT -PortG,PG7,,,,,I2C3_SCL,,,,LPUART1_TX,,,,FMC_INT3,,,EVENTOUT -PortG,PG8,,,,,I2C3_SDA,,,,LPUART1_RX,,,,,,,EVENTOUT -PortG,PG9,,,,,,,SPI3_SCK,USART1_TX,,,,,FMC_NCE3/FMC_NE2,SAI2_SCK_A,TIM15_CH1N,EVENTOUT -PortG,PG10,,LPTIM1_IN1,,,,,SPI3_MISO,USART1_RX,,,,,FMC_NE3,SAI2_FS_A,TIM15_CH1,EVENTOUT -PortG,PG11,,LPTIM1_IN2,,,,,SPI3_MOSI,USART1_CTS,,,,,,SAI2_MCLK_A,TIM15_CH2,EVENTOUT -PortG,PG12,,LPTIM1_ETR,,,,,SPI3_NSS,USART1_RTS_DE,,,,,FMC_NE4,SAI2_SD_A,,EVENTOUT -PortG,PG13,,,,,I2C1_SDA,,,USART1_CK,,,,,FMC_A24,,,EVENTOUT -PortG,PG14,,,,,I2C1_SCL,,,,,,,,FMC_A25,,,EVENTOUT -PortG,PG15,,LPTIM1_OUT,,,I2C1_SMBA,,,,,,,,,,,EVENTOUT -PortH,PH0,,,,,,,,,,,,,,,,EVENTOUT -PortH,PH1,,,,,,,,,,,,,,,,EVENTOUT +Port,,AF0,AF1,AF2,AF3,AF4,AF5,AF6,AF7,AF8,AF9,AF10,AF11,AF12,AF13,AF14,AF15,, +,,SYS_AF,TIM1/TIM2/TIM5/TIM8/LPTIM1,TIM1/TIM2/TIM3/TIM4/TIM5,TIM8,I2C1/I2C2/I2C3,SPI1/SPI2,SPI3/DFSDM,USART1/USART2/USART3,UART4/UART5/LPUART1,CAN1/TSC,OTG_FS/QUADSPI,LCD,SDMMC1/COMP1/COMP2/FMC/SWPMI1,SAI1/SAI2,TIM2/TIM15/TIM16/TIM17/LPTIM2,EVENTOUT,ADC,COMP +PortA,PA0,,TIM2_CH1,TIM5_CH1,TIM8_ETR,,,,USART2_CTS,UART4_TX,,,,,SAI1_EXTCLK,TIM2_ETR,EVENTOUT,ADC12_IN5, +PortA,PA1,,TIM2_CH2,TIM5_CH2,,,,,USART2_RTS_DE,UART4_RX,,,LCD_SEG0,,,TIM15_CH1N,EVENTOUT,ADC12_IN6, +PortA,PA2,,TIM2_CH3,TIM5_CH3,,,,,USART2_TX,,,,LCD_SEG1,,SAI2_EXTCLK,TIM15_CH1,EVENTOUT,ADC12_IN7, +PortA,PA3,,TIM2_CH4,TIM5_CH4,,,,,USART2_RX,,,,LCD_SEG2,,,TIM15_CH2,EVENTOUT,ADC12_IN8, +PortA,PA4,,,,,,SPI1_NSS,SPI3_NSS,USART2_CK,,,,,,SAI1_FS_B,LPTIM2_OUT,EVENTOUT,ADC12_IN9, +PortA,PA5,,TIM2_CH1,TIM2_ETR,TIM8_CH1N,,SPI1_SCK,,,,,,,,,LPTIM2_ETR,EVENTOUT,ADC12_IN10, +PortA,PA6,,TIM1_BKIN,TIM3_CH1,TIM8_BKIN,,SPI1_MISO,,USART3_CTS,,,QUADSPI_BK1_IO3,LCD_SEG3,TIM1_BKIN_COMP2,TIM8_BKIN_COMP2,TIM16_CH1,EVENTOUT,ADC12_IN11, +PortA,PA7,,TIM1_CH1N,TIM3_CH2,TIM8_CH1N,,SPI1_MOSI,,,,,QUADSPI_BK1_IO2,LCD_SEG4,,,TIM17_CH1,EVENTOUT,ADC12_IN12, +PortA,PA8,MCO,TIM1_CH1,,,,,,USART1_CK,,,OTG_FS_SOF,LCD_COM0,,,LPTIM2_OUT,EVENTOUT,, +PortA,PA9,,TIM1_CH2,,,,,,USART1_TX,,,,LCD_COM1,,,TIM15_BKIN,EVENTOUT,, +PortA,PA10,,TIM1_CH3,,,,,,USART1_RX,,,OTG_FS_ID,LCD_COM2,,,TIM17_BKIN,EVENTOUT,, +PortA,PA11,,TIM1_CH4,TIM1_BKIN2,,,,,USART1_CTS,,CAN1_RX,OTG_FS_DM,,TIM1_BKIN2_COMP1,,,EVENTOUT,, +PortA,PA12,,TIM1_ETR,,,,,,USART1_RTS_DE,,CAN1_TX,OTG_FS_DP,,,,,EVENTOUT,, +PortA,PA13,JTMS-SWDIO,IR_OUT,,,,,,,,,OTG_FS_NOE,,,,,EVENTOUT,, +PortA,PA14,JTCK-SWCLK,,,,,,,,,,,,,,,EVENTOUT,, +PortA,PA15,JTDI,TIM2_CH1,TIM2_ETR,,,SPI1_NSS,SPI3_NSS,,UART4_RTS_DE,TSC_G3_IO1,,LCD_SEG17,,SAI2_FS_B,,EVENTOUT,, +PortB,PB0,,TIM1_CH2N,TIM3_CH3,TIM8_CH2N,,,,USART3_CK,,,QUADSPI_BK1_IO1,LCD_SEG5,COMP1_OUT,,,EVENTOUT,ADC12_IN15, +PortB,PB1,,TIM1_CH3N,TIM3_CH4,TIM8_CH3N,,,DFSDM_DATIN0,USART3_RTS_DE,,,QUADSPI_BK1_IO0,LCD_SEG6,,,LPTIM2_IN1,EVENTOUT,ADC12_IN16,COMP1_INN +PortB,PB2,RTC_OUT,LPTIM1_OUT,,,I2C3_SMBA,,DFSDM_CKIN0,,,,,,,,,EVENTOUT,,COMP1_INP +PortB,PB3,JTDO-TRACESWO,TIM2_CH2,,,,SPI1_SCK,SPI3_SCK,USART1_RTS_DE,,,,LCD_SEG7,,SAI1_SCK_B,,EVENTOUT,,COMP2_INM +PortB,PB4,NJTRST,,TIM3_CH1,,,SPI1_MISO,SPI3_MISO,USART1_CTS,UART5_RTS_DE,TSC_G2_IO1,,LCD_SEG8,,SAI1_MCLK_B,TIM17_BKIN,EVENTOUT,,COMP2_INP +PortB,PB5,,LPTIM1_IN1,TIM3_CH2,,I2C1_SMBA,SPI1_MOSI,SPI3_MOSI,USART1_CK,UART5_CTS,TSC_G2_IO2,,LCD_SEG9,COMP2_OUT,SAI1_SD_B,TIM16_BKIN,EVENTOUT,, +PortB,PB6,,LPTIM1_ETR,TIM4_CH1,TIM8_BKIN2,I2C1_SCL,,DFSDM_DATIN5,USART1_TX,,TSC_G2_IO3,,,TIM8_BKIN2_COMP2,SAI1_FS_B,TIM16_CH1N,EVENTOUT,,COMP2_INP +PortB,PB7,,LPTIM1_IN2,TIM4_CH2,TIM8_BKIN,I2C1_SDA,,DFSDM_CKIN5,USART1_RX,UART4_CTS,TSC_G2_IO4,,LCD_SEG21,FMC_NL,TIM8_BKIN_COMP1,TIM17_CH1N,EVENTOUT,,COMP2_INM +PortB,PB8,,,TIM4_CH3,,I2C1_SCL,,DFSDM_DATIN6,,,CAN1_RX,,LCD_SEG16,SDMMC1_D4,SAI1_MCLK_A,TIM16_CH1,EVENTOUT,, +PortB,PB9,,IR_OUT,TIM4_CH4,,I2C1_SDA,SPI2_NSS,DFSDM_CKIN6,,,CAN1_TX,,LCD_COM3,SDMMC1_D5,SAI1_FS_A,TIM17_CH1,EVENTOUT,, +PortB,PB10,,TIM2_CH3,,,I2C2_SCL,SPI2_SCK,DFSDM_DATIN7,USART3_TX,LPUART1_RX,,QUADSPI_CLK,LCD_SEG10,COMP1_OUT,SAI1_SCK_A,,EVENTOUT,, +PortB,PB11,,TIM2_CH4,,,I2C2_SDA,,DFSDM_CKIN7,USART3_RX,LPUART1_TX,,QUADSPI_NCS,LCD_SEG11,COMP2_OUT,,,EVENTOUT,, +PortB,PB12,,TIM1_BKIN,,TIM1_BKIN_COMP2,I2C2_SMBA,SPI2_NSS,DFSDM_DATIN1,USART3_CK,LPUART1_RTS_DE,TSC_G1_IO1,,LCD_SEG12,SWPMI1_IO,SAI2_FS_A,TIM15_BKIN,EVENTOUT,, +PortB,PB13,,TIM1_CH1N,,,I2C2_SCL,SPI2_SCK,DFSDM_CKIN1,USART3_CTS,LPUART1_CTS,TSC_G1_IO2,,LCD_SEG13,SWPMI1_TX,SAI2_SCK_A,TIM15_CH1N,EVENTOUT,, +PortB,PB14,,TIM1_CH2N,,TIM8_CH2N,I2C2_SDA,SPI2_MISO,DFSDM_DATIN2,USART3_RTS_DE,,TSC_G1_IO3,,LCD_SEG14,SWPMI1_RX,SAI2_MCLK_A,TIM15_CH1,EVENTOUT,, +PortB,PB15,RTC_REFIN,TIM1_CH3N,,TIM8_CH3N,,SPI2_MOSI,DFSDM_CKIN2,,,TSC_G1_IO4,,LCD_SEG15,SWPMI1_SUSPEND,SAI2_SD_A,TIM15_CH2,EVENTOUT,, +PortC,PC0,,LPTIM1_IN1,,,I2C3_SCL,,DFSDM_DATIN4,,LPUART1_RX,,,LCD_SEG18,,,LPTIM2_IN1,EVENTOUT,ADC123_IN1, +PortC,PC1,,LPTIM1_OUT,,,I2C3_SDA,,DFSDM_CKIN4,,LPUART1_TX,,,LCD_SEG19,,,,EVENTOUT,ADC123_IN2, +PortC,PC2,,LPTIM1_IN2,,,,SPI2_MISO,DFSDM_CKOUT,,,,,LCD_SEG20,,,,EVENTOUT,ADC123_IN3, +PortC,PC3,,LPTIM1_ETR,,,,SPI2_MOSI,,,,,,LCD_VLCD,,SAI1_SD_A,LPTIM2_ETR,EVENTOUT,ADC123_IN4, +PortC,PC4,,,,,,,,USART3_TX,,,,LCD_SEG22,,,,EVENTOUT,ADC12_IN13,COMP1_INM +PortC,PC5,,,,,,,,USART3_RX,,,,LCD_SEG23,,,,EVENTOUT,ADC12_IN14,COMP1_INP +PortC,PC6,,,TIM3_CH1,TIM8_CH1,,,DFSDM_CKIN3,,,TSC_G4_IO1,,LCD_SEG24,SDMMC1_D6,SAI2_MCLK_A,,EVENTOUT,, +PortC,PC7,,,TIM3_CH2,TIM8_CH2,,,DFSDM_DATIN3,,,TSC_G4_IO2,,LCD_SEG25,SDMMC1_D7,SAI2_MCLK_B,,EVENTOUT,, +PortC,PC8,,,TIM3_CH3,TIM8_CH3,,,,,,TSC_G4_IO3,,LCD_SEG26,SDMMC1_D0,,,EVENTOUT,, +PortC,PC9,,TIM8_BKIN2,TIM3_CH4,TIM8_CH4,,,,,,TSC_G4_IO4,OTG_FS_NOE,LCD_SEG27,SDMMC1_D1,SAI2_EXTCLK,TIM8_BKIN2_COMP1,EVENTOUT,, +PortC,PC10,,,,,,,SPI3_SCK,USART3_TX,UART4_TX,TSC_G3_IO2,,LCD_COM4/LCD_SEG28/LCD_SEG40,SDMMC1_D2,SAI2_SCK_B,,EVENTOUT,, +PortC,PC11,,,,,,,SPI3_MISO,USART3_RX,UART4_RX,TSC_G3_IO3,,LCD_COM5/LCD_SEG29/LCD_SEG41,SDMMC1_D3,SAI2_MCLK_B,,EVENTOUT,, +PortC,PC12,,,,,,,SPI3_MOSI,USART3_CK,UART5_TX,TSC_G3_IO4,,LCD_COM6/LCD_SEG30/LCD_SEG42,SDMMC1_CK,SAI2_SD_B,,EVENTOUT,, +PortC,PC13,,,,,,,,,,,,,,,,EVENTOUT,, +PortC,PC14,,,,,,,,,,,,,,,,EVENTOUT,, +PortC,PC15,,,,,,,,,,,,,,,,EVENTOUT,, +PortD,PD0,,,,,,SPI2_NSS,DFSDM_DATIN7,,,CAN1_RX,,,FMC_D2,,,EVENTOUT,, +PortD,PD1,,,,,,SPI2_SCK,DFSDM_CKIN7,,,CAN1_TX,,,FMC_D3,,,EVENTOUT,, +PortD,PD2,,,TIM3_ETR,,,,,USART3_RTS_DE,UART5_RX,TSC_SYNC,,LCD_COM7/LCD_SEG31/LCD_SEG43,SDMMC1_CMD,,,EVENTOUT,, +PortD,PD3,,,,,,SPI2_MISO,DFSDM_DATIN0,USART2_CTS,,,,,FMC_CLK,,,EVENTOUT,, +PortD,PD4,,,,,,SPI2_MOSI,DFSDM_CKIN0,USART2_RTS_DE,,,,,FMC_NOE,,,EVENTOUT,, +PortD,PD5,,,,,,,,USART2_TX,,,,,FMC_NWE,,,EVENTOUT,, +PortD,PD6,,,,,,,DFSDM_DATIN1,USART2_RX,,,,,FMC_NWAIT,SAI1_SD_A,,EVENTOUT,, +PortD,PD7,,,,,,,DFSDM_CKIN1,USART2_CK,,,,,FMC_NE1,,,EVENTOUT,, +PortD,PD8,,,,,,,,USART3_TX,,,,LCD_SEG28,FMC_D13,,,EVENTOUT,, +PortD,PD9,,,,,,,,USART3_RX,,,,LCD_SEG29,FMC_D14,SAI2_MCLK_A,,EVENTOUT,, +PortD,PD10,,,,,,,,USART3_CK,,TSC_G6_IO1,,LCD_SEG30,FMC_D15,SAI2_SCK_A,,EVENTOUT,, +PortD,PD11,,,,,,,,USART3_CTS,,TSC_G6_IO2,,LCD_SEG31,FMC_A16,SAI2_SD_A,LPTIM2_ETR,EVENTOUT,, +PortD,PD12,,,TIM4_CH1,,,,,USART3_RTS_DE,,TSC_G6_IO3,,LCD_SEG32,FMC_A17,SAI2_FS_A,LPTIM2_IN1,EVENTOUT,, +PortD,PD13,,,TIM4_CH2,,,,,,,TSC_G6_IO4,,LCD_SEG33,FMC_A18,,LPTIM2_OUT,EVENTOUT,, +PortD,PD14,,,TIM4_CH3,,,,,,,,,LCD_SEG34,FMC_D0,,,EVENTOUT,, +PortD,PD15,,,TIM4_CH4,,,,,,,,,LCD_SEG35,FMC_D1,,,EVENTOUT,, +PortE,PE0,,,TIM4_ETR,,,,,,,,,LCD_SEG36,FMC_NBL0,,TIM16_CH1,EVENTOUT,, +PortE,PE1,,,,,,,,,,,,LCD_SEG37,FMC_NBL1,,TIM17_CH1,EVENTOUT,, +PortE,PE2,TRACECK,,TIM3_ETR,,,,,,,TSC_G7_IO1,,LCD_SEG38,FMC_A23,SAI1_MCLK_A,,EVENTOUT,, +PortE,PE3,TRACED0,,TIM3_CH1,,,,,,,TSC_G7_IO2,,LCD_SEG39,FMC_A19,SAI1_SD_B,,EVENTOUT,, +PortE,PE4,TRACED1,,TIM3_CH2,,,,DFSDM_DATIN3,,,TSC_G7_IO3,,,FMC_A20,SAI1_FS_A,,EVENTOUT,, +PortE,PE5,TRACED2,,TIM3_CH3,,,,DFSDM_CKIN3,,,TSC_G7_IO4,,,FMC_A21,SAI1_SCK_A,,EVENTOUT,, +PortE,PE6,TRACED3,,TIM3_CH4,,,,,,,,,,FMC_A22,SAI1_SD_A,,EVENTOUT,, +PortE,PE7,,TIM1_ETR,,,,,DFSDM_DATIN2,,,,,,FMC_D4,SAI1_SD_B,,EVENTOUT,, +PortE,PE8,,TIM1_CH1N,,,,,DFSDM_CKIN2,,,,,,FMC_D5,SAI1_SCK_B,,EVENTOUT,, +PortE,PE9,,TIM1_CH1,,,,,DFSDM_CKOUT,,,,,,FMC_D6,SAI1_FS_B,,EVENTOUT,, +PortE,PE10,,TIM1_CH2N,,,,,DFSDM_DATIN4,,,TSC_G5_IO1,QUADSPI_CLK,,FMC_D7,SAI1_MCLK_B,,EVENTOUT,, +PortE,PE11,,TIM1_CH2,,,,,DFSDM_CKIN4,,,TSC_G5_IO2,QUADSPI_NCS,,FMC_D8,,,EVENTOUT,, +PortE,PE12,,TIM1_CH3N,,,,SPI1_NSS,DFSDM_DATIN5,,,TSC_G5_IO3,QUADSPI_BK1_IO0,,FMC_D9,,,EVENTOUT,, +PortE,PE13,,TIM1_CH3,,,,SPI1_SCK,DFSDM_CKIN5,,,TSC_G5_IO4,QUADSPI_BK1_IO1,,FMC_D10,,,EVENTOUT,, +PortE,PE14,,TIM1_CH4,TIM1_BKIN2,TIM1_BKIN2_COMP2,,SPI1_MISO,,,,,QUADSPI_BK1_IO2,,FMC_D11,,,EVENTOUT,, +PortE,PE15,,TIM1_BKIN,,TIM1_BKIN_COMP1,,SPI1_MOSI,,,,,QUADSPI_BK1_IO3,,FMC_D12,,,EVENTOUT,, +PortF,PF0,,,,,I2C2_SDA,,,,,,,,FMC_A0,,,EVENTOUT,, +PortF,PF1,,,,,I2C2_SCL,,,,,,,,FMC_A1,,,EVENTOUT,, +PortF,PF2,,,,,I2C2_SMBA,,,,,,,,FMC_A2,,,EVENTOUT,, +PortF,PF3,,,,,,,,,,,,,FMC_A3,,,EVENTOUT,ADC3_IN6, +PortF,PF4,,,,,,,,,,,,,FMC_A4,,,EVENTOUT,ADC3_IN7, +PortF,PF5,,,,,,,,,,,,,FMC_A5,,,EVENTOUT,ADC3_IN8, +PortF,PF6,,TIM5_ETR,TIM5_CH1,,,,,,,,,,,SAI1_SD_B,,EVENTOUT,ADC3_IN9, +PortF,PF7,,,TIM5_CH2,,,,,,,,,,,SAI1_MCLK_B,,EVENTOUT,ADC3_IN10, +PortF,PF8,,,TIM5_CH3,,,,,,,,,,,SAI1_SCK_B,,EVENTOUT,ADC3_IN11, +PortF,PF9,,,TIM5_CH4,,,,,,,,,,,SAI1_FS_B,TIM15_CH1,EVENTOUT,ADC3_IN12, +PortF,PF10,,,,,,,,,,,,,,,TIM15_CH2,EVENTOUT,ADC3_IN13, +PortF,PF11,,,,,,,,,,,,,,,,EVENTOUT,, +PortF,PF12,,,,,,,,,,,,,FMC_A6,,,EVENTOUT,, +PortF,PF13,,,,,,,DFSDM_DATIN6,,,,,,FMC_A7,,,EVENTOUT,, +PortF,PF14,,,,,,,DFSDM_CKIN6,,,TSC_G8_IO1,,,FMC_A8,,,EVENTOUT,, +PortF,PF15,,,,,,,,,,TSC_G8_IO2,,,FMC_A9,,,EVENTOUT,, +PortG,PG0,,,,,,,,,,TSC_G8_IO3,,,FMC_A10,,,EVENTOUT,, +PortG,PG1,,,,,,,,,,TSC_G8_IO4,,,FMC_A11,,,EVENTOUT,, +PortG,PG2,,,,,,SPI1_SCK,,,,,,,FMC_A12,SAI2_SCK_B,,EVENTOUT,, +PortG,PG3,,,,,,SPI1_MISO,,,,,,,FMC_A13,SAI2_FS_B,,EVENTOUT,, +PortG,PG4,,,,,,SPI1_MOSI,,,,,,,FMC_A14,SAI2_MCLK_B,,EVENTOUT,, +PortG,PG5,,,,,,SPI1_NSS,,,LPUART1_CTS,,,,FMC_A15,SAI2_SD_B,,EVENTOUT,, +PortG,PG6,,,,,I2C3_SMBA,,,,LPUART1_RTS_DE,,,,,,,EVENTOUT,, +PortG,PG7,,,,,I2C3_SCL,,,,LPUART1_TX,,,,FMC_INT3,,,EVENTOUT,, +PortG,PG8,,,,,I2C3_SDA,,,,LPUART1_RX,,,,,,,EVENTOUT,, +PortG,PG9,,,,,,,SPI3_SCK,USART1_TX,,,,,FMC_NCE3/FMC_NE2,SAI2_SCK_A,TIM15_CH1N,EVENTOUT,, +PortG,PG10,,LPTIM1_IN1,,,,,SPI3_MISO,USART1_RX,,,,,FMC_NE3,SAI2_FS_A,TIM15_CH1,EVENTOUT,, +PortG,PG11,,LPTIM1_IN2,,,,,SPI3_MOSI,USART1_CTS,,,,,,SAI2_MCLK_A,TIM15_CH2,EVENTOUT,, +PortG,PG12,,LPTIM1_ETR,,,,,SPI3_NSS,USART1_RTS_DE,,,,,FMC_NE4,SAI2_SD_A,,EVENTOUT,, +PortG,PG13,,,,,I2C1_SDA,,,USART1_CK,,,,,FMC_A24,,,EVENTOUT,, +PortG,PG14,,,,,I2C1_SCL,,,,,,,,FMC_A25,,,EVENTOUT,, +PortG,PG15,,LPTIM1_OUT,,,I2C1_SMBA,,,,,,,,,,,EVENTOUT,, +PortH,PH0,,,,,,,,,,,,,,,,EVENTOUT,, +PortH,PH1,,,,,,,,,,,,,,,,EVENTOUT,, From af9889f99a325adb725c61476bd580b11593ca50 Mon Sep 17 00:00:00 2001 From: Tobias Badertscher Date: Tue, 19 Jul 2016 11:35:33 +0200 Subject: [PATCH 008/129] stmhal/adc.c: Get ADC working on STM32L4 MCUs. Fixing Issue #2243. Main problems were: - HAL_ADC_GetState(adcHandle) may return other bits set (not only HAL_ADC_STATE_EOC_REG) when called - so I AND-ed it out as proposed by mattbrejza in Issue #2243. - ADC Pin has to be configured as GPIO_MODE_ANALOG_ADC_CONTROL not only GPIO_MODE_ANALOG. - Resolved ADC resolution L4 specific (Use L4 define ADC_RESOLUTION_12B). - Changed setting of Init.EOCSelection toADC_EOC_SINGLE_CONV for L4. - Added call to ADC_MultiModeTypeDef as this is done on a STM32Cube generated project too. - Clean up: Configuration of ADC is done only in ONE function not the same is done in two functions. Test is done on PA5 pin of STM32L4Discovery-Kit which is connected to the DOWN button. Thanks to mattbrejza for discovering the bug. --- stmhal/adc.c | 55 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 23 deletions(-) diff --git a/stmhal/adc.c b/stmhal/adc.c index da93a44741..39f0364078 100644 --- a/stmhal/adc.c +++ b/stmhal/adc.c @@ -131,7 +131,13 @@ STATIC void adc_init_single(pyb_obj_adc_t *adc_obj) { mp_hal_gpio_clock_enable(pin->gpio); GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.Pin = pin->pin_mask; +#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) GPIO_InitStructure.Mode = GPIO_MODE_ANALOG; +#elif defined(MCU_SERIES_L4) + GPIO_InitStructure.Mode = GPIO_MODE_ANALOG_ADC_CONTROL; +#else + #error Unsupported processor +#endif GPIO_InitStructure.Pull = GPIO_NOPULL; HAL_GPIO_Init(pin->gpio, &GPIO_InitStructure); } @@ -140,7 +146,6 @@ STATIC void adc_init_single(pyb_obj_adc_t *adc_obj) { ADC_HandleTypeDef *adcHandle = &adc_obj->handle; adcHandle->Instance = ADCx; - adcHandle->Init.Resolution = ADC_RESOLUTION12b; adcHandle->Init.ContinuousConvMode = DISABLE; adcHandle->Init.DiscontinuousConvMode = DISABLE; adcHandle->Init.NbrOfDiscConversion = 0; @@ -148,15 +153,19 @@ STATIC void adc_init_single(pyb_obj_adc_t *adc_obj) { adcHandle->Init.DataAlign = ADC_DATAALIGN_RIGHT; adcHandle->Init.NbrOfConversion = 1; adcHandle->Init.DMAContinuousRequests = DISABLE; - adcHandle->Init.EOCSelection = DISABLE; #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) + adcHandle->Init.Resolution = ADC_RESOLUTION12b; adcHandle->Init.ClockPrescaler = ADC_CLOCKPRESCALER_PCLK_DIV2; adcHandle->Init.ScanConvMode = DISABLE; adcHandle->Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T1_CC1; + adcHandle->Init.EOCSelection = DISABLE; #elif defined(MCU_SERIES_L4) - adcHandle->Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV2; + adcHandle->Init.Resolution = ADC_RESOLUTION_12B; + adcHandle->Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1; adcHandle->Init.ScanConvMode = ADC_SCAN_DISABLE; - adcHandle->Init.ExternalTrigConv = ADC_EXTERNALTRIG_T1_CC1; + adcHandle->Init.EOCSelection = ADC_EOC_SINGLE_CONV; + adcHandle->Init.ExternalTrigConv = ADC_SOFTWARE_START; + adcHandle->Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; adcHandle->Init.LowPowerAutoWait = DISABLE; adcHandle->Init.Overrun = ADC_OVR_DATA_PRESERVED; adcHandle->Init.OversamplingMode = DISABLE; @@ -165,30 +174,42 @@ STATIC void adc_init_single(pyb_obj_adc_t *adc_obj) { #endif HAL_ADC_Init(adcHandle); + +#if defined(MCU_SERIES_L4) + ADC_MultiModeTypeDef multimode; + multimode.Mode = ADC_MODE_INDEPENDENT; + if (HAL_ADCEx_MultiModeConfigChannel(adcHandle, &multimode) != HAL_OK) + { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Can not set multimode on ADC1 channel: %d", adc_obj->channel)); + } +#endif } -STATIC void adc_config_channel(pyb_obj_adc_t *adc_obj) { +STATIC void adc_config_channel(ADC_HandleTypeDef *adc_handle, uint32_t channel) { ADC_ChannelConfTypeDef sConfig; - sConfig.Channel = adc_obj->channel; + sConfig.Channel = channel; sConfig.Rank = 1; #if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) sConfig.SamplingTime = ADC_SAMPLETIME_15CYCLES; #elif defined(MCU_SERIES_L4) sConfig.SamplingTime = ADC_SAMPLETIME_12CYCLES_5; + sConfig.SingleDiff = ADC_SINGLE_ENDED; + sConfig.OffsetNumber = ADC_OFFSET_NONE; #else #error Unsupported processor #endif sConfig.Offset = 0; - HAL_ADC_ConfigChannel(&adc_obj->handle, &sConfig); + HAL_ADC_ConfigChannel(adc_handle, &sConfig); } STATIC uint32_t adc_read_channel(ADC_HandleTypeDef *adcHandle) { uint32_t rawValue = 0; HAL_ADC_Start(adcHandle); - if (HAL_ADC_PollForConversion(adcHandle, 10) == HAL_OK && HAL_ADC_GetState(adcHandle) == HAL_ADC_STATE_EOC_REG) { + if (HAL_ADC_PollForConversion(adcHandle, 10) == HAL_OK + && (HAL_ADC_GetState(adcHandle) & HAL_ADC_STATE_EOC_REG) == HAL_ADC_STATE_EOC_REG) { rawValue = HAL_ADC_GetValue(adcHandle); } HAL_ADC_Stop(adcHandle); @@ -252,7 +273,7 @@ STATIC mp_obj_t adc_make_new(const mp_obj_type_t *type, mp_uint_t n_args, mp_uin STATIC mp_obj_t adc_read(mp_obj_t self_in) { pyb_obj_adc_t *self = self_in; - adc_config_channel(self); + adc_config_channel(&self->handle, self->channel); uint32_t data = adc_read_channel(&self->handle); return mp_obj_new_int(data); } @@ -313,7 +334,7 @@ STATIC mp_obj_t adc_read_timed(mp_obj_t self_in, mp_obj_t buf_in, mp_obj_t freq_ } // configure the ADC channel - adc_config_channel(self); + adc_config_channel(&self->handle, self->channel); // This uses the timer in polling mode to do the sampling // TODO use DMA @@ -446,19 +467,7 @@ void adc_init_all(pyb_adc_all_obj_t *adc_all, uint32_t resolution) { } uint32_t adc_config_and_read_channel(ADC_HandleTypeDef *adcHandle, uint32_t channel) { - ADC_ChannelConfTypeDef sConfig; - sConfig.Channel = channel; - sConfig.Rank = 1; -#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) - sConfig.SamplingTime = ADC_SAMPLETIME_15CYCLES; -#elif defined(MCU_SERIES_L4) - sConfig.SamplingTime = ADC_SAMPLETIME_12CYCLES_5; -#else - #error Unsupported processor -#endif - sConfig.Offset = 0; - HAL_ADC_ConfigChannel(adcHandle, &sConfig); - + adc_config_channel(adcHandle, channel); return adc_read_channel(adcHandle); } From 9e1b61dedd82dffccbe4f20996eadaf79726d427 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Fri, 12 Aug 2016 21:26:12 +0300 Subject: [PATCH 009/129] py/runtime: Factor out exception raising helpers. Introduce mp_raise_msg(), mp_raise_ValueError(), mp_raise_TypeError() instead of previous pattern nlr_raise(mp_obj_new_exception_msg(...)). Save few bytes on each call, which are many. --- py/objstr.c | 81 +++++++++++++++++++++++----------------------------- py/runtime.c | 16 +++++++++-- py/runtime.h | 4 +++ 3 files changed, 54 insertions(+), 47 deletions(-) diff --git a/py/objstr.c b/py/objstr.c index a6ee617c03..ecf6199165 100644 --- a/py/objstr.c +++ b/py/objstr.c @@ -231,7 +231,7 @@ STATIC mp_obj_t bytes_make_new(const mp_obj_type_t *type_in, size_t n_args, size mp_int_t val = mp_obj_get_int(item); #if MICROPY_CPYTHON_COMPAT if (val < 0 || val > 255) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "bytes value out of range")); + mp_raise_ValueError("bytes value out of range"); } #endif vstr_add_byte(&vstr, val); @@ -240,7 +240,7 @@ STATIC mp_obj_t bytes_make_new(const mp_obj_type_t *type_in, size_t n_args, size return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); wrong_args: - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "wrong number of arguments")); + mp_raise_TypeError("wrong number of arguments"); } // like strstr but with specified length and allows \0 bytes @@ -436,8 +436,8 @@ STATIC mp_obj_t str_join(mp_obj_t self_in, mp_obj_t arg) { mp_uint_t required_len = 0; for (mp_uint_t i = 0; i < seq_len; i++) { if (mp_obj_get_type(seq_items[i]) != self_type) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, - "join expects a list of str/bytes objects consistent with self object")); + mp_raise_msg(&mp_type_TypeError, + "join expects a list of str/bytes objects consistent with self object"); } if (i > 0) { required_len += sep_len; @@ -511,7 +511,7 @@ mp_obj_t mp_obj_str_split(size_t n_args, const mp_obj_t *args) { const char *sep_str = mp_obj_str_get_data(sep, &sep_len); if (sep_len == 0) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "empty separator")); + mp_raise_ValueError("empty separator"); } for (;;) { @@ -609,7 +609,7 @@ STATIC mp_obj_t str_rsplit(size_t n_args, const mp_obj_t *args) { const char *sep_str = mp_obj_str_get_data(sep, &sep_len); if (sep_len == 0) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "empty separator")); + mp_raise_ValueError("empty separator"); } const byte *beg = s; @@ -672,7 +672,7 @@ STATIC mp_obj_t str_finder(mp_uint_t n_args, const mp_obj_t *args, mp_int_t dire if (p == NULL) { // not found if (is_index) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "substring not found")); + mp_raise_ValueError("substring not found"); } else { return MP_OBJ_NEW_SMALL_INT(-1); } @@ -878,7 +878,7 @@ STATIC mp_obj_t arg_as_int(mp_obj_t arg) { } STATIC NORETURN void terse_str_format_value_error(void) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "bad format string")); + mp_raise_ValueError("bad format string"); } STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *arg_i, mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kwargs) { @@ -896,8 +896,8 @@ STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { terse_str_format_value_error(); } else { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, - "single '}' encountered in format string")); + mp_raise_msg(&mp_type_ValueError, + "single '}' encountered in format string"); } } if (*str != '{') { @@ -936,12 +936,11 @@ STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { terse_str_format_value_error(); } else if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_NORMAL) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, - "bad conversion specifier")); + mp_raise_ValueError("bad conversion specifier"); } else { if (str >= top) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, - "end of format while looking for conversion specifier")); + mp_raise_msg(&mp_type_ValueError, + "end of format while looking for conversion specifier"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "unknown conversion specifier %c", *str)); @@ -975,16 +974,14 @@ STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { terse_str_format_value_error(); } else { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, - "unmatched '{' in format")); + mp_raise_ValueError("unmatched '{' in format"); } } if (*str != '}') { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { terse_str_format_value_error(); } else { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, - "expected ':' after format specifier")); + mp_raise_ValueError("expected ':' after format specifier"); } } @@ -997,13 +994,13 @@ STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { terse_str_format_value_error(); } else { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, - "can't switch from automatic field numbering to manual field specification")); + mp_raise_msg(&mp_type_ValueError, + "can't switch from automatic field numbering to manual field specification"); } } field_name = str_to_int(field_name, field_name_top, &index); if ((uint)index >= n_args - 1) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_IndexError, "tuple index out of range")); + mp_raise_msg(&mp_type_IndexError, "tuple index out of range"); } arg = args[index + 1]; *arg_i = -1; @@ -1026,12 +1023,12 @@ STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { terse_str_format_value_error(); } else { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, - "can't switch from manual field specification to automatic field numbering")); + mp_raise_msg(&mp_type_ValueError, + "can't switch from manual field specification to automatic field numbering"); } } if ((uint)*arg_i >= n_args - 1) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_IndexError, "tuple index out of range")); + mp_raise_msg(&mp_type_IndexError, "tuple index out of range"); } arg = args[(*arg_i) + 1]; (*arg_i)++; @@ -1120,8 +1117,7 @@ STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { terse_str_format_value_error(); } else { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, - "invalid format specifier")); + mp_raise_ValueError("invalid format specifier"); } } vstr_clear(&format_spec_vstr); @@ -1142,16 +1138,16 @@ STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { terse_str_format_value_error(); } else { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, - "sign not allowed in string format specifier")); + mp_raise_msg(&mp_type_ValueError, + "sign not allowed in string format specifier"); } } if (type == 'c') { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { terse_str_format_value_error(); } else { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, - "sign not allowed with integer format specifier 'c'")); + mp_raise_msg(&mp_type_ValueError, + "sign not allowed with integer format specifier 'c'"); } } } else { @@ -1295,8 +1291,8 @@ STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { terse_str_format_value_error(); } else { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, - "'=' alignment not allowed in string format specifier")); + mp_raise_msg(&mp_type_ValueError, + "'=' alignment not allowed in string format specifier"); } } @@ -1372,8 +1368,7 @@ STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, mp_uint_t n_args, const mp_o if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { terse_str_format_value_error(); } else { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, - "incomplete format key")); + mp_raise_ValueError("incomplete format key"); } } ++str; @@ -1431,8 +1426,7 @@ incomplete_format: if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { terse_str_format_value_error(); } else { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, - "incomplete format")); + mp_raise_ValueError("incomplete format"); } } @@ -1440,7 +1434,7 @@ incomplete_format: if (arg == MP_OBJ_NULL) { if ((uint)arg_i >= n_args) { not_enough_args: - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "not enough arguments for format string")); + mp_raise_TypeError("not enough arguments for format string"); } arg = args[arg_i++]; } @@ -1450,16 +1444,14 @@ not_enough_args: mp_uint_t slen; const char *s = mp_obj_str_get_data(arg, &slen); if (slen != 1) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, - "%%c requires int or char")); + mp_raise_TypeError("%%c requires int or char"); } mp_print_strn(&print, s, 1, flags, ' ', width); } else if (arg_looks_integer(arg)) { char ch = mp_obj_get_int(arg); mp_print_strn(&print, &ch, 1, flags, ' ', width); } else { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, - "integer required")); + mp_raise_TypeError("integer required"); } break; @@ -1529,7 +1521,7 @@ not_enough_args: } if ((uint)arg_i != n_args) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "not all arguments converted during string formatting")); + mp_raise_TypeError("not all arguments converted during string formatting"); } return mp_obj_new_str_from_vstr(is_bytes ? &mp_type_bytes : &mp_type_str, &vstr); @@ -1695,7 +1687,7 @@ STATIC mp_obj_t str_partitioner(mp_obj_t self_in, mp_obj_t arg, mp_int_t directi GET_STR_DATA_LEN(arg, sep, sep_len); if (sep_len == 0) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "empty separator")); + mp_raise_ValueError("empty separator"); } mp_obj_t result[3]; @@ -2061,8 +2053,7 @@ bool mp_obj_str_equal(mp_obj_t s1, mp_obj_t s2) { STATIC void bad_implicit_conversion(mp_obj_t self_in) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, - "can't convert to str implicitly")); + mp_raise_TypeError("can't convert to str implicitly"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "can't convert '%s' object to str implicitly", diff --git a/py/runtime.c b/py/runtime.c index f88c92be63..04b3a34de4 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -1390,6 +1390,18 @@ void *m_malloc_fail(size_t num_bytes) { } } -NORETURN void mp_not_implemented(const char *msg) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_NotImplementedError, msg)); +NORETURN void mp_raise_msg(const mp_obj_type_t *exc_type, const char *msg) { + nlr_raise(mp_obj_new_exception_msg(exc_type, msg)); +} + +NORETURN void mp_raise_ValueError(const char *msg) { + mp_raise_msg(&mp_type_ValueError, msg); +} + +NORETURN void mp_raise_TypeError(const char *msg) { + mp_raise_msg(&mp_type_TypeError, msg); +} + +NORETURN void mp_not_implemented(const char *msg) { + mp_raise_msg(&mp_type_NotImplementedError, msg); } diff --git a/py/runtime.h b/py/runtime.h index 3e325a31b3..df5e45b2d3 100644 --- a/py/runtime.h +++ b/py/runtime.h @@ -134,6 +134,10 @@ mp_obj_t mp_import_from(mp_obj_t module, qstr name); void mp_import_all(mp_obj_t module); // Raise NotImplementedError with given message +NORETURN void mp_raise_msg(const mp_obj_type_t *exc_type, const char *msg); +//NORETURN void nlr_raise_msg_varg(const mp_obj_type_t *exc_type, const char *fmt, ...); +NORETURN void mp_raise_ValueError(const char *msg); +NORETURN void mp_raise_TypeError(const char *msg); NORETURN void mp_not_implemented(const char *msg); NORETURN void mp_exc_recursion_depth(void); From 8c50f93a4177b56ec1aa36563c93c04b19f89a9f Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Fri, 12 Aug 2016 21:58:56 +0300 Subject: [PATCH 010/129] py/runtime.h: Define mp_check_self(pred) helper macro. Indended to replace raw asserts in bunch of files. Expands to empty if MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG is defined, otehrwise by default still to assert, though a particular port may define it to something else. --- py/runtime.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/py/runtime.h b/py/runtime.h index df5e45b2d3..f81a6263d0 100644 --- a/py/runtime.h +++ b/py/runtime.h @@ -141,6 +141,16 @@ NORETURN void mp_raise_TypeError(const char *msg); NORETURN void mp_not_implemented(const char *msg); NORETURN void mp_exc_recursion_depth(void); +#if MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG +#undef mp_check_self +#define mp_check_self(pred) +#else +// A port may define to raise TypeError for example +#ifndef mp_check_self +#define mp_check_self(pred) assert(pred) +#endif +#endif + // helper functions for native/viper code mp_uint_t mp_convert_obj_to_native(mp_obj_t obj, mp_uint_t type); mp_obj_t mp_convert_native_to_obj(mp_uint_t val, mp_uint_t type); From 83e0ebabb4c3c9144027609876ec62d428f8bba8 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Fri, 12 Aug 2016 22:01:11 +0300 Subject: [PATCH 011/129] py/objdict: Get rid of asserts (remove/replace with mp_check_self()). --- py/objdict.c | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/py/objdict.c b/py/objdict.c index 91d5b75e2b..7a74557dc1 100644 --- a/py/objdict.c +++ b/py/objdict.c @@ -223,7 +223,7 @@ STATIC mp_obj_t dict_getiter(mp_obj_t self_in) { /* dict methods */ STATIC mp_obj_t dict_clear(mp_obj_t self_in) { - assert(MP_OBJ_IS_DICT_TYPE(self_in)); + mp_check_self(MP_OBJ_IS_DICT_TYPE(self_in)); mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in); mp_map_clear(&self->map); @@ -233,7 +233,7 @@ STATIC mp_obj_t dict_clear(mp_obj_t self_in) { STATIC MP_DEFINE_CONST_FUN_OBJ_1(dict_clear_obj, dict_clear); STATIC mp_obj_t dict_copy(mp_obj_t self_in) { - assert(MP_OBJ_IS_DICT_TYPE(self_in)); + mp_check_self(MP_OBJ_IS_DICT_TYPE(self_in)); mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_t other_out = mp_obj_new_dict(self->map.alloc); mp_obj_dict_t *other = MP_OBJ_TO_PTR(other_out); @@ -249,7 +249,6 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(dict_copy_obj, dict_copy); // this is a classmethod STATIC mp_obj_t dict_fromkeys(size_t n_args, const mp_obj_t *args) { - assert(2 <= n_args && n_args <= 3); mp_obj_t iter = mp_getiter(args[1]); mp_obj_t len = mp_obj_len_maybe(iter); mp_obj_t value = mp_const_none; @@ -303,8 +302,7 @@ STATIC mp_obj_t dict_get_helper(mp_map_t *self, mp_obj_t key, mp_obj_t deflt, mp } STATIC mp_obj_t dict_get(size_t n_args, const mp_obj_t *args) { - assert(2 <= n_args && n_args <= 3); - assert(MP_OBJ_IS_DICT_TYPE(args[0])); + mp_check_self(MP_OBJ_IS_DICT_TYPE(args[0])); mp_obj_dict_t *self = MP_OBJ_TO_PTR(args[0]); return dict_get_helper(&self->map, @@ -315,8 +313,7 @@ STATIC mp_obj_t dict_get(size_t n_args, const mp_obj_t *args) { STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(dict_get_obj, 2, 3, dict_get); STATIC mp_obj_t dict_pop(size_t n_args, const mp_obj_t *args) { - assert(2 <= n_args && n_args <= 3); - assert(MP_OBJ_IS_DICT_TYPE(args[0])); + mp_check_self(MP_OBJ_IS_DICT_TYPE(args[0])); mp_obj_dict_t *self = MP_OBJ_TO_PTR(args[0]); return dict_get_helper(&self->map, @@ -328,8 +325,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(dict_pop_obj, 2, 3, dict_pop); STATIC mp_obj_t dict_setdefault(size_t n_args, const mp_obj_t *args) { - assert(2 <= n_args && n_args <= 3); - assert(MP_OBJ_IS_DICT_TYPE(args[0])); + mp_check_self(MP_OBJ_IS_DICT_TYPE(args[0])); mp_obj_dict_t *self = MP_OBJ_TO_PTR(args[0]); return dict_get_helper(&self->map, @@ -341,7 +337,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(dict_setdefault_obj, 2, 3, dict_setde STATIC mp_obj_t dict_popitem(mp_obj_t self_in) { - assert(MP_OBJ_IS_DICT_TYPE(self_in)); + mp_check_self(MP_OBJ_IS_DICT_TYPE(self_in)); mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in); mp_uint_t cur = 0; mp_map_elem_t *next = dict_iter_next(self, &cur); @@ -359,7 +355,7 @@ STATIC mp_obj_t dict_popitem(mp_obj_t self_in) { STATIC MP_DEFINE_CONST_FUN_OBJ_1(dict_popitem_obj, dict_popitem); STATIC mp_obj_t dict_update(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) { - assert(MP_OBJ_IS_DICT_TYPE(args[0])); + mp_check_self(MP_OBJ_IS_DICT_TYPE(args[0])); mp_obj_dict_t *self = MP_OBJ_TO_PTR(args[0]); mp_arg_check_num(n_args, kwargs->used, 1, 2, true); @@ -438,7 +434,7 @@ typedef struct _mp_obj_dict_view_t { } mp_obj_dict_view_t; STATIC mp_obj_t dict_view_it_iternext(mp_obj_t self_in) { - assert(MP_OBJ_IS_TYPE(self_in, &dict_view_it_type)); + mp_check_self(MP_OBJ_IS_TYPE(self_in, &dict_view_it_type)); mp_obj_dict_view_it_t *self = MP_OBJ_TO_PTR(self_in); mp_map_elem_t *next = dict_iter_next(MP_OBJ_TO_PTR(self->dict), &self->cur); @@ -467,7 +463,7 @@ STATIC const mp_obj_type_t dict_view_it_type = { }; STATIC mp_obj_t dict_view_getiter(mp_obj_t view_in) { - assert(MP_OBJ_IS_TYPE(view_in, &dict_view_type)); + mp_check_self(MP_OBJ_IS_TYPE(view_in, &dict_view_type)); mp_obj_dict_view_t *view = MP_OBJ_TO_PTR(view_in); mp_obj_dict_view_it_t *o = m_new_obj(mp_obj_dict_view_it_t); o->base.type = &dict_view_it_type; @@ -479,7 +475,7 @@ STATIC mp_obj_t dict_view_getiter(mp_obj_t view_in) { STATIC void dict_view_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { (void)kind; - assert(MP_OBJ_IS_TYPE(self_in, &dict_view_type)); + mp_check_self(MP_OBJ_IS_TYPE(self_in, &dict_view_type)); mp_obj_dict_view_t *self = MP_OBJ_TO_PTR(self_in); bool first = true; mp_print_str(print, mp_dict_view_names[self->kind]); @@ -525,7 +521,7 @@ STATIC mp_obj_t mp_obj_new_dict_view(mp_obj_t dict, mp_dict_view_kind_t kind) { } STATIC mp_obj_t dict_view(mp_obj_t self_in, mp_dict_view_kind_t kind) { - assert(MP_OBJ_IS_DICT_TYPE(self_in)); + mp_check_self(MP_OBJ_IS_DICT_TYPE(self_in)); return mp_obj_new_dict_view(self_in, kind); } @@ -612,21 +608,21 @@ mp_uint_t mp_obj_dict_len(mp_obj_t self_in) { } mp_obj_t mp_obj_dict_store(mp_obj_t self_in, mp_obj_t key, mp_obj_t value) { - assert(MP_OBJ_IS_DICT_TYPE(self_in)); + mp_check_self(MP_OBJ_IS_DICT_TYPE(self_in)); mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in); mp_map_lookup(&self->map, key, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value; return self_in; } mp_obj_t mp_obj_dict_delete(mp_obj_t self_in, mp_obj_t key) { - assert(MP_OBJ_IS_DICT_TYPE(self_in)); + mp_check_self(MP_OBJ_IS_DICT_TYPE(self_in)); mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in); dict_get_helper(&self->map, key, MP_OBJ_NULL, MP_MAP_LOOKUP_REMOVE_IF_FOUND); return self_in; } mp_map_t *mp_obj_dict_get_map(mp_obj_t self_in) { - assert(MP_OBJ_IS_DICT_TYPE(self_in)); + mp_check_self(MP_OBJ_IS_DICT_TYPE(self_in)); mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in); return &self->map; } From c4a8004933d1ae4da52f175d456d6fbe765c3923 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Fri, 12 Aug 2016 22:06:47 +0300 Subject: [PATCH 012/129] py: Get rid of assert() in method argument checking functions. Checks for number of args removes where guaranteed by function descriptor, self checking is replaced with mp_check_self(). In few cases, exception is raised instead of assert. --- py/modbuiltins.c | 3 --- py/objfilter.c | 2 +- py/objgenerator.c | 2 +- py/objlist.c | 32 +++++++++++++++----------------- py/objmap.c | 2 +- py/objproperty.c | 2 +- py/objreversed.c | 2 +- py/objset.c | 6 +----- py/objstr.c | 19 ++++++++----------- py/objtuple.c | 6 +++--- py/objzip.c | 2 +- 11 files changed, 33 insertions(+), 45 deletions(-) diff --git a/py/modbuiltins.c b/py/modbuiltins.c index 87446f7fae..ac3d3041f5 100644 --- a/py/modbuiltins.c +++ b/py/modbuiltins.c @@ -376,7 +376,6 @@ STATIC mp_obj_t mp_builtin_ord(mp_obj_t o_in) { MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_ord_obj, mp_builtin_ord); STATIC mp_obj_t mp_builtin_pow(size_t n_args, const mp_obj_t *args) { - assert(2 <= n_args && n_args <= 3); switch (n_args) { case 2: return mp_binary_op(MP_BINARY_OP_POWER, args[0], args[1]); default: return mp_binary_op(MP_BINARY_OP_MODULO, mp_binary_op(MP_BINARY_OP_POWER, args[0], args[1]), args[2]); // TODO optimise... @@ -492,7 +491,6 @@ STATIC mp_obj_t mp_builtin_round(size_t n_args, const mp_obj_t *args) { MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_round_obj, 1, 2, mp_builtin_round); STATIC mp_obj_t mp_builtin_sum(size_t n_args, const mp_obj_t *args) { - assert(1 <= n_args && n_args <= 2); mp_obj_t value; switch (n_args) { case 1: value = MP_OBJ_NEW_SMALL_INT(0); break; @@ -508,7 +506,6 @@ STATIC mp_obj_t mp_builtin_sum(size_t n_args, const mp_obj_t *args) { MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_sum_obj, 1, 2, mp_builtin_sum); STATIC mp_obj_t mp_builtin_sorted(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) { - assert(n_args >= 1); if (n_args > 1) { nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "must use keyword argument for key function")); diff --git a/py/objfilter.c b/py/objfilter.c index e288102d38..a5c85b2cef 100644 --- a/py/objfilter.c +++ b/py/objfilter.c @@ -44,7 +44,7 @@ STATIC mp_obj_t filter_make_new(const mp_obj_type_t *type, size_t n_args, size_t } STATIC mp_obj_t filter_iternext(mp_obj_t self_in) { - assert(MP_OBJ_IS_TYPE(self_in, &mp_type_filter)); + mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_filter)); mp_obj_filter_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_t next; while ((next = mp_iternext(self->iter)) != MP_OBJ_STOP_ITERATION) { diff --git a/py/objgenerator.c b/py/objgenerator.c index 2480b0a4b8..99d9445377 100644 --- a/py/objgenerator.c +++ b/py/objgenerator.c @@ -96,7 +96,7 @@ STATIC void gen_instance_print(const mp_print_t *print, mp_obj_t self_in, mp_pri } mp_vm_return_kind_t mp_obj_gen_resume(mp_obj_t self_in, mp_obj_t send_value, mp_obj_t throw_value, mp_obj_t *ret_val) { - assert(MP_OBJ_IS_TYPE(self_in, &mp_type_gen_instance)); + mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_gen_instance)); mp_obj_gen_instance_t *self = MP_OBJ_TO_PTR(self_in); if (self->code_state.ip == 0) { // Trying to resume already stopped generator diff --git a/py/objlist.c b/py/objlist.c index df6b1bc99a..b5e8b99651 100644 --- a/py/objlist.c +++ b/py/objlist.c @@ -89,7 +89,7 @@ STATIC mp_obj_t list_make_new(const mp_obj_type_t *type_in, size_t n_args, size_ // Don't pass MP_BINARY_OP_NOT_EQUAL here STATIC bool list_cmp_helper(mp_uint_t op, mp_obj_t self_in, mp_obj_t another_in) { - assert(MP_OBJ_IS_TYPE(self_in, &mp_type_list)); + mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_list)); if (!MP_OBJ_IS_TYPE(another_in, &mp_type_list)) { return false; } @@ -156,7 +156,7 @@ STATIC mp_obj_t list_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in); mp_bound_slice_t slice; if (!mp_seq_get_fast_slice_indexes(self->len, index, &slice)) { - assert(0); + mp_not_implemented(""); } mp_int_t len_adj = slice.start - slice.stop; @@ -192,11 +192,11 @@ STATIC mp_obj_t list_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { #if MICROPY_PY_BUILTINS_SLICE if (MP_OBJ_IS_TYPE(index, &mp_type_slice)) { mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in); - assert(MP_OBJ_IS_TYPE(value, &mp_type_list)); + mp_check_self(MP_OBJ_IS_TYPE(value, &mp_type_list)); mp_obj_list_t *slice = MP_OBJ_TO_PTR(value); mp_bound_slice_t slice_out; if (!mp_seq_get_fast_slice_indexes(self->len, index, &slice_out)) { - assert(0); + mp_not_implemented(""); } mp_int_t len_adj = slice->len - (slice_out.stop - slice_out.start); //printf("Len adj: %d\n", len_adj); @@ -230,7 +230,7 @@ STATIC mp_obj_t list_getiter(mp_obj_t o_in) { } mp_obj_t mp_obj_list_append(mp_obj_t self_in, mp_obj_t arg) { - assert(MP_OBJ_IS_TYPE(self_in, &mp_type_list)); + mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_list)); mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in); if (self->len >= self->alloc) { self->items = m_renew(mp_obj_t, self->items, self->alloc, self->alloc * 2); @@ -242,7 +242,7 @@ mp_obj_t mp_obj_list_append(mp_obj_t self_in, mp_obj_t arg) { } STATIC mp_obj_t list_extend(mp_obj_t self_in, mp_obj_t arg_in) { - assert(MP_OBJ_IS_TYPE(self_in, &mp_type_list)); + mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_list)); if (MP_OBJ_IS_TYPE(arg_in, &mp_type_list)) { mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_list_t *arg = MP_OBJ_TO_PTR(arg_in); @@ -263,8 +263,7 @@ STATIC mp_obj_t list_extend(mp_obj_t self_in, mp_obj_t arg_in) { } STATIC mp_obj_t list_pop(size_t n_args, const mp_obj_t *args) { - assert(1 <= n_args && n_args <= 2); - assert(MP_OBJ_IS_TYPE(args[0], &mp_type_list)); + mp_check_self(MP_OBJ_IS_TYPE(args[0], &mp_type_list)); mp_obj_list_t *self = MP_OBJ_TO_PTR(args[0]); if (self->len == 0) { nlr_raise(mp_obj_new_exception_msg(&mp_type_IndexError, "pop from empty list")); @@ -324,7 +323,7 @@ mp_obj_t mp_obj_list_sort(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, (mp_arg_val_t*)&args); - assert(MP_OBJ_IS_TYPE(pos_args[0], &mp_type_list)); + mp_check_self(MP_OBJ_IS_TYPE(pos_args[0], &mp_type_list)); mp_obj_list_t *self = MP_OBJ_TO_PTR(pos_args[0]); if (self->len > 1) { @@ -337,7 +336,7 @@ mp_obj_t mp_obj_list_sort(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ } STATIC mp_obj_t list_clear(mp_obj_t self_in) { - assert(MP_OBJ_IS_TYPE(self_in, &mp_type_list)); + mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_list)); mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in); self->len = 0; self->items = m_renew(mp_obj_t, self->items, self->alloc, LIST_MIN_ALLOC); @@ -347,26 +346,25 @@ STATIC mp_obj_t list_clear(mp_obj_t self_in) { } STATIC mp_obj_t list_copy(mp_obj_t self_in) { - assert(MP_OBJ_IS_TYPE(self_in, &mp_type_list)); + mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_list)); mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in); return mp_obj_new_list(self->len, self->items); } STATIC mp_obj_t list_count(mp_obj_t self_in, mp_obj_t value) { - assert(MP_OBJ_IS_TYPE(self_in, &mp_type_list)); + mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_list)); mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in); return mp_seq_count_obj(self->items, self->len, value); } STATIC mp_obj_t list_index(size_t n_args, const mp_obj_t *args) { - assert(2 <= n_args && n_args <= 4); - assert(MP_OBJ_IS_TYPE(args[0], &mp_type_list)); + mp_check_self(MP_OBJ_IS_TYPE(args[0], &mp_type_list)); mp_obj_list_t *self = MP_OBJ_TO_PTR(args[0]); return mp_seq_index_obj(self->items, self->len, n_args, args); } STATIC mp_obj_t list_insert(mp_obj_t self_in, mp_obj_t idx, mp_obj_t obj) { - assert(MP_OBJ_IS_TYPE(self_in, &mp_type_list)); + mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_list)); mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in); // insert has its own strange index logic mp_int_t index = MP_OBJ_SMALL_INT_VALUE(idx); @@ -391,7 +389,7 @@ STATIC mp_obj_t list_insert(mp_obj_t self_in, mp_obj_t idx, mp_obj_t obj) { } mp_obj_t mp_obj_list_remove(mp_obj_t self_in, mp_obj_t value) { - assert(MP_OBJ_IS_TYPE(self_in, &mp_type_list)); + mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_list)); mp_obj_t args[] = {self_in, value}; args[1] = list_index(2, args); list_pop(2, args); @@ -400,7 +398,7 @@ mp_obj_t mp_obj_list_remove(mp_obj_t self_in, mp_obj_t value) { } STATIC mp_obj_t list_reverse(mp_obj_t self_in) { - assert(MP_OBJ_IS_TYPE(self_in, &mp_type_list)); + mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_list)); mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in); mp_int_t len = self->len; diff --git a/py/objmap.c b/py/objmap.c index 526bc05600..ed0291435d 100644 --- a/py/objmap.c +++ b/py/objmap.c @@ -49,7 +49,7 @@ STATIC mp_obj_t map_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_ } STATIC mp_obj_t map_iternext(mp_obj_t self_in) { - assert(MP_OBJ_IS_TYPE(self_in, &mp_type_map)); + mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_map)); mp_obj_map_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_t *nextses = m_new(mp_obj_t, self->n_iters); diff --git a/py/objproperty.c b/py/objproperty.c index 618f517e74..8189935d20 100644 --- a/py/objproperty.c +++ b/py/objproperty.c @@ -100,7 +100,7 @@ const mp_obj_type_t mp_type_property = { }; const mp_obj_t *mp_obj_property_get(mp_obj_t self_in) { - assert(MP_OBJ_IS_TYPE(self_in, &mp_type_property)); + mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_property)); mp_obj_property_t *self = MP_OBJ_TO_PTR(self_in); return self->proxy; } diff --git a/py/objreversed.c b/py/objreversed.c index 1e54bb522a..4343c19780 100644 --- a/py/objreversed.c +++ b/py/objreversed.c @@ -57,7 +57,7 @@ STATIC mp_obj_t reversed_make_new(const mp_obj_type_t *type, size_t n_args, size } STATIC mp_obj_t reversed_iternext(mp_obj_t self_in) { - assert(MP_OBJ_IS_TYPE(self_in, &mp_type_reversed)); + mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_reversed)); mp_obj_reversed_t *self = MP_OBJ_TO_PTR(self_in); // "raise" stop iteration if we are at the end (the start) of the sequence diff --git a/py/objset.c b/py/objset.c index 8730918c15..fb89c07f3d 100644 --- a/py/objset.c +++ b/py/objset.c @@ -224,8 +224,6 @@ STATIC mp_obj_t set_discard(mp_obj_t self_in, mp_obj_t item) { STATIC MP_DEFINE_CONST_FUN_OBJ_2(set_discard_obj, set_discard); STATIC mp_obj_t set_diff_int(size_t n_args, const mp_obj_t *args, bool update) { - assert(n_args > 0); - mp_obj_t self; if (update) { check_set(args[0]); @@ -443,8 +441,6 @@ STATIC void set_update_int(mp_obj_set_t *self, mp_obj_t other_in) { } STATIC mp_obj_t set_update(size_t n_args, const mp_obj_t *args) { - assert(n_args > 0); - for (mp_uint_t i = 1; i < n_args; i++) { set_update_int(MP_OBJ_TO_PTR(args[0]), args[i]); } @@ -587,7 +583,7 @@ mp_obj_t mp_obj_new_set(mp_uint_t n_args, mp_obj_t *items) { } void mp_obj_set_store(mp_obj_t self_in, mp_obj_t item) { - assert(MP_OBJ_IS_TYPE(self_in, &mp_type_set)); + mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_set)); mp_obj_set_t *self = MP_OBJ_TO_PTR(self_in); mp_set_lookup(&self->set, item, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND); } diff --git a/py/objstr.c b/py/objstr.c index ecf6199165..4bae03d760 100644 --- a/py/objstr.c +++ b/py/objstr.c @@ -412,7 +412,7 @@ STATIC mp_obj_t bytes_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { } STATIC mp_obj_t str_join(mp_obj_t self_in, mp_obj_t arg) { - assert(MP_OBJ_IS_STR_OR_BYTES(self_in)); + mp_check_self(MP_OBJ_IS_STR_OR_BYTES(self_in)); const mp_obj_type_t *self_type = mp_obj_get_type(self_in); // get separation string @@ -648,8 +648,7 @@ STATIC mp_obj_t str_rsplit(size_t n_args, const mp_obj_t *args) { STATIC mp_obj_t str_finder(mp_uint_t n_args, const mp_obj_t *args, mp_int_t direction, bool is_index) { const mp_obj_type_t *self_type = mp_obj_get_type(args[0]); - assert(2 <= n_args && n_args <= 4); - assert(MP_OBJ_IS_STR_OR_BYTES(args[0])); + mp_check_self(MP_OBJ_IS_STR_OR_BYTES(args[0])); // check argument type if (mp_obj_get_type(args[1]) != self_type) { @@ -734,8 +733,7 @@ STATIC mp_obj_t str_endswith(size_t n_args, const mp_obj_t *args) { enum { LSTRIP, RSTRIP, STRIP }; STATIC mp_obj_t str_uni_strip(int type, mp_uint_t n_args, const mp_obj_t *args) { - assert(1 <= n_args && n_args <= 2); - assert(MP_OBJ_IS_STR_OR_BYTES(args[0])); + mp_check_self(MP_OBJ_IS_STR_OR_BYTES(args[0])); const mp_obj_type_t *self_type = mp_obj_get_type(args[0]); const byte *chars_to_del; @@ -1327,7 +1325,7 @@ STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar } mp_obj_t mp_obj_str_format(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) { - assert(MP_OBJ_IS_STR_OR_BYTES(args[0])); + mp_check_self(MP_OBJ_IS_STR_OR_BYTES(args[0])); GET_STR_DATA_LEN(args[0], str, len); int arg_i = 0; @@ -1336,7 +1334,7 @@ mp_obj_t mp_obj_str_format(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs } STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, mp_uint_t n_args, const mp_obj_t *args, mp_obj_t dict) { - assert(MP_OBJ_IS_STR_OR_BYTES(pattern)); + mp_check_self(MP_OBJ_IS_STR_OR_BYTES(pattern)); GET_STR_DATA_LEN(pattern, str, len); const byte *start_str = str; @@ -1530,7 +1528,7 @@ not_enough_args: // The implementation is optimized, returning the original string if there's // nothing to replace. STATIC mp_obj_t str_replace(size_t n_args, const mp_obj_t *args) { - assert(MP_OBJ_IS_STR_OR_BYTES(args[0])); + mp_check_self(MP_OBJ_IS_STR_OR_BYTES(args[0])); mp_int_t max_rep = -1; if (n_args == 4) { @@ -1636,8 +1634,7 @@ STATIC mp_obj_t str_replace(size_t n_args, const mp_obj_t *args) { STATIC mp_obj_t str_count(size_t n_args, const mp_obj_t *args) { const mp_obj_type_t *self_type = mp_obj_get_type(args[0]); - assert(2 <= n_args && n_args <= 4); - assert(MP_OBJ_IS_STR_OR_BYTES(args[0])); + mp_check_self(MP_OBJ_IS_STR_OR_BYTES(args[0])); // check argument type if (mp_obj_get_type(args[1]) != self_type) { @@ -1677,7 +1674,7 @@ STATIC mp_obj_t str_count(size_t n_args, const mp_obj_t *args) { #if MICROPY_PY_BUILTINS_STR_PARTITION STATIC mp_obj_t str_partitioner(mp_obj_t self_in, mp_obj_t arg, mp_int_t direction) { - assert(MP_OBJ_IS_STR_OR_BYTES(self_in)); + mp_check_self(MP_OBJ_IS_STR_OR_BYTES(self_in)); mp_obj_type_t *self_type = mp_obj_get_type(self_in); if (self_type != mp_obj_get_type(arg)) { bad_implicit_conversion(arg); diff --git a/py/objtuple.c b/py/objtuple.c index c21390a603..e7e24ab188 100644 --- a/py/objtuple.c +++ b/py/objtuple.c @@ -106,7 +106,7 @@ STATIC mp_obj_t mp_obj_tuple_make_new(const mp_obj_type_t *type_in, size_t n_arg STATIC bool tuple_cmp_helper(mp_uint_t op, mp_obj_t self_in, mp_obj_t another_in) { mp_obj_type_t *self_type = mp_obj_get_type(self_in); if (self_type->getiter != mp_obj_tuple_getiter) { - assert(0); + mp_raise_TypeError(""); } mp_obj_type_t *another_type = mp_obj_get_type(another_in); mp_obj_tuple_t *self = MP_OBJ_TO_PTR(self_in); @@ -202,14 +202,14 @@ mp_obj_t mp_obj_tuple_getiter(mp_obj_t o_in) { } STATIC mp_obj_t tuple_count(mp_obj_t self_in, mp_obj_t value) { - assert(MP_OBJ_IS_TYPE(self_in, &mp_type_tuple)); + mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_tuple)); mp_obj_tuple_t *self = MP_OBJ_TO_PTR(self_in); return mp_seq_count_obj(self->items, self->len, value); } STATIC MP_DEFINE_CONST_FUN_OBJ_2(tuple_count_obj, tuple_count); STATIC mp_obj_t tuple_index(size_t n_args, const mp_obj_t *args) { - assert(MP_OBJ_IS_TYPE(args[0], &mp_type_tuple)); + mp_check_self(MP_OBJ_IS_TYPE(args[0], &mp_type_tuple)); mp_obj_tuple_t *self = MP_OBJ_TO_PTR(args[0]); return mp_seq_index_obj(self->items, self->len, n_args, args); } diff --git a/py/objzip.c b/py/objzip.c index d4cd614a4c..6edefc3611 100644 --- a/py/objzip.c +++ b/py/objzip.c @@ -49,7 +49,7 @@ STATIC mp_obj_t zip_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_ } STATIC mp_obj_t zip_iternext(mp_obj_t self_in) { - assert(MP_OBJ_IS_TYPE(self_in, &mp_type_zip)); + mp_check_self(MP_OBJ_IS_TYPE(self_in, &mp_type_zip)); mp_obj_zip_t *self = MP_OBJ_TO_PTR(self_in); if (self->n_iters == 0) { return MP_OBJ_STOP_ITERATION; From 0be4a7712d0dbba8bf01065457e99a432bdda0ad Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Fri, 12 Aug 2016 22:50:45 +0300 Subject: [PATCH 013/129] tests: Rename zlibd_decompress.py -> uzlib_decompress.py. To use the actual current name. --- tests/extmod/{zlibd_decompress.py => uzlib_decompress.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/extmod/{zlibd_decompress.py => uzlib_decompress.py} (100%) diff --git a/tests/extmod/zlibd_decompress.py b/tests/extmod/uzlib_decompress.py similarity index 100% rename from tests/extmod/zlibd_decompress.py rename to tests/extmod/uzlib_decompress.py From 9cf29493569d6292fc672e757b2aa96b42f1fe1d Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sun, 14 Aug 2016 01:02:35 +0300 Subject: [PATCH 014/129] esp8266/mpconfigport.h: Enable support for all special methods. --- esp8266/mpconfigport.h | 1 + 1 file changed, 1 insertion(+) diff --git a/esp8266/mpconfigport.h b/esp8266/mpconfigport.h index 7b3558ffc2..15410f00c5 100644 --- a/esp8266/mpconfigport.h +++ b/esp8266/mpconfigport.h @@ -25,6 +25,7 @@ #define MICROPY_MODULE_WEAK_LINKS (1) #define MICROPY_CAN_OVERRIDE_BUILTINS (1) #define MICROPY_USE_INTERNAL_ERRNO (1) +#define MICROPY_PY_ALL_SPECIAL_METHODS (1) #define MICROPY_PY_BUILTINS_COMPLEX (0) #define MICROPY_PY_BUILTINS_STR_UNICODE (1) #define MICROPY_PY_BUILTINS_BYTEARRAY (1) From 4aaa5adf9f13dc875cd0eaadc2951a3b24c8cf15 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sun, 14 Aug 2016 16:28:05 +1000 Subject: [PATCH 015/129] py/objtuple: In tuple_cmp_helper, use mp_check_self instead of raising. Only tuple, namedtuple and attrtuple use the tuple_cmp_helper function, and they all have getiter=mp_obj_tuple_getiter, so the check here is only to ensure that the self object is consistent. Hence use mp_check_self. --- py/objtuple.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/py/objtuple.c b/py/objtuple.c index e7e24ab188..c547da9406 100644 --- a/py/objtuple.c +++ b/py/objtuple.c @@ -104,10 +104,8 @@ STATIC mp_obj_t mp_obj_tuple_make_new(const mp_obj_type_t *type_in, size_t n_arg // Don't pass MP_BINARY_OP_NOT_EQUAL here STATIC bool tuple_cmp_helper(mp_uint_t op, mp_obj_t self_in, mp_obj_t another_in) { - mp_obj_type_t *self_type = mp_obj_get_type(self_in); - if (self_type->getiter != mp_obj_tuple_getiter) { - mp_raise_TypeError(""); - } + // type check is done on getiter method to allow tuple, namedtuple, attrtuple + mp_check_self(mp_obj_get_type(self_in)->getiter == mp_obj_tuple_getiter); mp_obj_type_t *another_type = mp_obj_get_type(another_in); mp_obj_tuple_t *self = MP_OBJ_TO_PTR(self_in); if (another_type->getiter != mp_obj_tuple_getiter) { From 1a0d3fd6325ed8d7ff0f893c575055b7cd4c8dd3 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sun, 14 Aug 2016 16:35:10 +1000 Subject: [PATCH 016/129] py/runtime.h: Move comment about mp_not_implemented to correct place. --- py/runtime.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/py/runtime.h b/py/runtime.h index f81a6263d0..06e68924b2 100644 --- a/py/runtime.h +++ b/py/runtime.h @@ -133,12 +133,11 @@ mp_obj_t mp_import_name(qstr name, mp_obj_t fromlist, mp_obj_t level); mp_obj_t mp_import_from(mp_obj_t module, qstr name); void mp_import_all(mp_obj_t module); -// Raise NotImplementedError with given message NORETURN void mp_raise_msg(const mp_obj_type_t *exc_type, const char *msg); //NORETURN void nlr_raise_msg_varg(const mp_obj_type_t *exc_type, const char *fmt, ...); NORETURN void mp_raise_ValueError(const char *msg); NORETURN void mp_raise_TypeError(const char *msg); -NORETURN void mp_not_implemented(const char *msg); +NORETURN void mp_not_implemented(const char *msg); // Raise NotImplementedError with given message NORETURN void mp_exc_recursion_depth(void); #if MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG From 21967990519b3d0778770ddb0994216d012101c3 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sun, 14 Aug 2016 16:51:54 +1000 Subject: [PATCH 017/129] py/objstr: Use mp_raise_{Type,Value}Error instead of mp_raise_msg. This patch does further refactoring using the new mp_raise_TypeError and mp_raise_ValueError functions. --- py/objstr.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/py/objstr.c b/py/objstr.c index 4bae03d760..e83ff7c844 100644 --- a/py/objstr.c +++ b/py/objstr.c @@ -436,7 +436,7 @@ STATIC mp_obj_t str_join(mp_obj_t self_in, mp_obj_t arg) { mp_uint_t required_len = 0; for (mp_uint_t i = 0; i < seq_len; i++) { if (mp_obj_get_type(seq_items[i]) != self_type) { - mp_raise_msg(&mp_type_TypeError, + mp_raise_TypeError( "join expects a list of str/bytes objects consistent with self object"); } if (i > 0) { @@ -894,8 +894,7 @@ STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { terse_str_format_value_error(); } else { - mp_raise_msg(&mp_type_ValueError, - "single '}' encountered in format string"); + mp_raise_ValueError("single '}' encountered in format string"); } } if (*str != '{') { @@ -937,7 +936,7 @@ STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar mp_raise_ValueError("bad conversion specifier"); } else { if (str >= top) { - mp_raise_msg(&mp_type_ValueError, + mp_raise_ValueError( "end of format while looking for conversion specifier"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, @@ -992,7 +991,7 @@ STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { terse_str_format_value_error(); } else { - mp_raise_msg(&mp_type_ValueError, + mp_raise_ValueError( "can't switch from automatic field numbering to manual field specification"); } } @@ -1021,7 +1020,7 @@ STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { terse_str_format_value_error(); } else { - mp_raise_msg(&mp_type_ValueError, + mp_raise_ValueError( "can't switch from manual field specification to automatic field numbering"); } } @@ -1136,15 +1135,14 @@ STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { terse_str_format_value_error(); } else { - mp_raise_msg(&mp_type_ValueError, - "sign not allowed in string format specifier"); + mp_raise_ValueError("sign not allowed in string format specifier"); } } if (type == 'c') { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { terse_str_format_value_error(); } else { - mp_raise_msg(&mp_type_ValueError, + mp_raise_ValueError( "sign not allowed with integer format specifier 'c'"); } } @@ -1289,7 +1287,7 @@ STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { terse_str_format_value_error(); } else { - mp_raise_msg(&mp_type_ValueError, + mp_raise_ValueError( "'=' alignment not allowed in string format specifier"); } } From 3c82d1d34b6450e73816e206fa5a5d3330a4df48 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 15 Aug 2016 10:46:02 +1000 Subject: [PATCH 018/129] tests/basics: Add more tuple tests to improve coverage testing. --- tests/basics/builtin_hash.py | 1 + tests/basics/tuple1.py | 15 +++++++++++++++ tests/basics/tuple_mult.py | 6 ++++++ 3 files changed, 22 insertions(+) diff --git a/tests/basics/builtin_hash.py b/tests/basics/builtin_hash.py index c9731a3b59..ffea08e575 100644 --- a/tests/basics/builtin_hash.py +++ b/tests/basics/builtin_hash.py @@ -3,6 +3,7 @@ print(hash(False)) print(hash(True)) print({():1}) # hash tuple +print({(1,):1}) # hash non-empty tuple print({1 << 66:1}) # hash big int print({-(1 << 66):2}) # hash negative big int print(hash in {hash:1}) # hash function diff --git a/tests/basics/tuple1.py b/tests/basics/tuple1.py index 53eac2a306..2993391d53 100644 --- a/tests/basics/tuple1.py +++ b/tests/basics/tuple1.py @@ -16,3 +16,18 @@ print(x[:-1]) print(x[2:3]) print(x + (10, 100, 10000)) + +# construction of tuple from large iterator (tests implementation detail of uPy) +print(tuple(range(20))) + +# unsupported unary operation +try: + +() +except TypeError: + print('TypeError') + +# unsupported type on RHS of add +try: + () + None +except TypeError: + print('TypeError') diff --git a/tests/basics/tuple_mult.py b/tests/basics/tuple_mult.py index 0f52bce44e..b128b29689 100644 --- a/tests/basics/tuple_mult.py +++ b/tests/basics/tuple_mult.py @@ -10,3 +10,9 @@ for i in (-4, -2, 0, 2, 4): a = (1, 2, 3) c = a * 3 print(a, c) + +# unsupported type on RHS +try: + () * None +except TypeError: + print('TypeError') From d5f42c9daf12f11b2a7a2db17409331b6f2a484e Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 15 Aug 2016 10:46:35 +1000 Subject: [PATCH 019/129] tests/basics: Add more list tests to improve coverage testing. --- tests/basics/list1.py | 6 ++++++ tests/basics/list_mult.py | 6 ++++++ tests/basics/list_pop.py | 6 ++++++ 3 files changed, 18 insertions(+) diff --git a/tests/basics/list1.py b/tests/basics/list1.py index c8317baa3d..fa426c0e58 100644 --- a/tests/basics/list1.py +++ b/tests/basics/list1.py @@ -22,3 +22,9 @@ print(x) print(x[1:]) print(x[:-1]) print(x[2:3]) + +# unsupported type on RHS of add +try: + [] + None +except TypeError: + print('TypeError') diff --git a/tests/basics/list_mult.py b/tests/basics/list_mult.py index 16948f74c2..548f88534e 100644 --- a/tests/basics/list_mult.py +++ b/tests/basics/list_mult.py @@ -10,3 +10,9 @@ for i in (-4, -2, 0, 2, 4): a = [1, 2, 3] c = a * 3 print(a, c) + +# unsupported type on RHS +try: + [] * None +except TypeError: + print('TypeError') diff --git a/tests/basics/list_pop.py b/tests/basics/list_pop.py index bb2ccc6d67..87ed456f85 100644 --- a/tests/basics/list_pop.py +++ b/tests/basics/list_pop.py @@ -9,3 +9,9 @@ except IndexError: print("IndexError raised") else: raise AssertionError("No IndexError raised") + +# popping such that list storage shrinks (tests implementation detail of uPy) +l = list(range(20)) +for i in range(len(l)): + l.pop() +print(l) From b359cf2911781120f5c866107734269435c4e424 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 15 Aug 2016 10:46:46 +1000 Subject: [PATCH 020/129] tests/misc/non_compliant: Add tests to improve coverage testing. --- tests/misc/non_compliant.py | 17 +++++++++++++++++ tests/misc/non_compliant.py.exp | 3 +++ 2 files changed, 20 insertions(+) diff --git a/tests/misc/non_compliant.py b/tests/misc/non_compliant.py index c760c2accd..ba2dd15c6a 100644 --- a/tests/misc/non_compliant.py +++ b/tests/misc/non_compliant.py @@ -70,3 +70,20 @@ try: except NotImplementedError: print('NotImplementedError') +# tuple load with step!=1 not implemented +try: + ()[2:3:4] +except NotImplementedError: + print('NotImplementedError') + +# list store with step!=1 not implemented +try: + [][2:3:4] = [] +except NotImplementedError: + print('NotImplementedError') + +# list delete with step!=1 not implemented +try: + del [][2:3:4] +except NotImplementedError: + print('NotImplementedError') diff --git a/tests/misc/non_compliant.py.exp b/tests/misc/non_compliant.py.exp index 28b1470d7c..5937ccb2fb 100644 --- a/tests/misc/non_compliant.py.exp +++ b/tests/misc/non_compliant.py.exp @@ -9,3 +9,6 @@ NotImplementedError NotImplementedError NotImplementedError NotImplementedError +NotImplementedError +NotImplementedError +NotImplementedError From 41fceae559ff2272a88441dbf531232f173ccbd6 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 15 Aug 2016 10:56:55 +1000 Subject: [PATCH 021/129] py/obj.h: For obj reprs A,B,C use void* explicitly for mp_obj_t typedef. The machine_ptr_t type is long obsolete as the type of mp_obj_t is now defined by the object representation, ie by MICROPY_OBJ_REPR. So just use void* explicitly for the typedef of mp_obj_t. If a port wants to use something different then they should define a new object representation. --- py/obj.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/py/obj.h b/py/obj.h index 82abbac90d..22aa196fd1 100644 --- a/py/obj.h +++ b/py/obj.h @@ -31,15 +31,15 @@ #include "py/qstr.h" #include "py/mpprint.h" -// All Micro Python objects are at least this type -// The bit-size must be at least pointer size - +// This is the definition of the opaque MicroPython object type. +// All concrete objects have an encoding within this type and the +// particular encoding is specified by MICROPY_OBJ_REPR. #if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D typedef uint64_t mp_obj_t; typedef uint64_t mp_const_obj_t; #else -typedef machine_ptr_t mp_obj_t; -typedef machine_const_ptr_t mp_const_obj_t; +typedef void *mp_obj_t; +typedef const void *mp_const_obj_t; #endif // This mp_obj_type_t struct is a concrete MicroPython object which holds info From 675d1c9c600224820f49f912e4ff7d6cf2f97711 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 15 Aug 2016 11:02:59 +1000 Subject: [PATCH 022/129] ports: Remove typedef of machine_ptr_t, it's no longer needed. This type was used only for the typedef of mp_obj_t, which is now defined by the object representation. So we can now remove this unused typedef, to simplify the mpconfigport.h file. --- bare-arm/mpconfigport.h | 2 -- cc3200/mpconfigport.h | 2 -- esp8266/mpconfigport.h | 2 -- examples/embedding/mpconfigport_minimal.h | 3 --- minimal/mpconfigport.h | 2 -- mpy-cross/mpconfigport.h | 3 --- pic16bit/mpconfigport.h | 2 -- qemu-arm/mpconfigport.h | 2 -- stmhal/mpconfigport.h | 2 -- teensy/mpconfigport.h | 2 -- unix/mpconfigport.h | 3 --- unix/mpconfigport_minimal.h | 3 --- windows/mpconfigport.h | 3 --- 13 files changed, 31 deletions(-) diff --git a/bare-arm/mpconfigport.h b/bare-arm/mpconfigport.h index caf37419af..7c448d13c1 100644 --- a/bare-arm/mpconfigport.h +++ b/bare-arm/mpconfigport.h @@ -54,8 +54,6 @@ typedef int32_t mp_int_t; // must be pointer size typedef uint32_t mp_uint_t; // must be pointer size -typedef void *machine_ptr_t; // must be of pointer size -typedef const void *machine_const_ptr_t; // must be of pointer size typedef long mp_off_t; // dummy print diff --git a/cc3200/mpconfigport.h b/cc3200/mpconfigport.h index 331db8100e..0b16d730d0 100644 --- a/cc3200/mpconfigport.h +++ b/cc3200/mpconfigport.h @@ -185,8 +185,6 @@ extern const struct _mp_obj_module_t mp_module_ussl; typedef int32_t mp_int_t; // must be pointer size typedef unsigned int mp_uint_t; // must be pointer size -typedef void *machine_ptr_t; // must be of pointer size -typedef const void *machine_const_ptr_t; // must be of pointer size typedef long mp_off_t; #define MP_PLAT_PRINT_STRN(str, len) mp_hal_stdout_tx_strn_cooked(str, len) diff --git a/esp8266/mpconfigport.h b/esp8266/mpconfigport.h index 15410f00c5..63b9258a20 100644 --- a/esp8266/mpconfigport.h +++ b/esp8266/mpconfigport.h @@ -115,8 +115,6 @@ typedef int32_t mp_int_t; // must be pointer size typedef uint32_t mp_uint_t; // must be pointer size -typedef void *machine_ptr_t; // must be of pointer size -typedef const void *machine_const_ptr_t; // must be of pointer size typedef long mp_off_t; typedef uint32_t sys_prot_t; // for modlwip // ssize_t, off_t as required by POSIX-signatured functions in stream.h diff --git a/examples/embedding/mpconfigport_minimal.h b/examples/embedding/mpconfigport_minimal.h index 9f080ab0e1..90011b3f81 100644 --- a/examples/embedding/mpconfigport_minimal.h +++ b/examples/embedding/mpconfigport_minimal.h @@ -127,9 +127,6 @@ typedef long long mp_off_t; typedef long mp_off_t; #endif -typedef void *machine_ptr_t; // must be of pointer size -typedef const void *machine_const_ptr_t; // must be of pointer size - // We need to provide a declaration/definition of alloca() #ifdef __FreeBSD__ #include diff --git a/minimal/mpconfigport.h b/minimal/mpconfigport.h index 165b058794..fc696c77e5 100644 --- a/minimal/mpconfigport.h +++ b/minimal/mpconfigport.h @@ -65,8 +65,6 @@ typedef int mp_int_t; // must be pointer size typedef unsigned mp_uint_t; // must be pointer size -typedef void *machine_ptr_t; // must be of pointer size -typedef const void *machine_const_ptr_t; // must be of pointer size typedef long mp_off_t; #define MP_PLAT_PRINT_STRN(str, len) mp_hal_stdout_tx_strn_cooked(str, len) diff --git a/mpy-cross/mpconfigport.h b/mpy-cross/mpconfigport.h index b3f7d9c3cd..c919e42911 100644 --- a/mpy-cross/mpconfigport.h +++ b/mpy-cross/mpconfigport.h @@ -107,9 +107,6 @@ typedef long long mp_off_t; typedef long mp_off_t; #endif -typedef void *machine_ptr_t; // must be of pointer size -typedef const void *machine_const_ptr_t; // must be of pointer size - #define MP_PLAT_PRINT_STRN(str, len) (void)0 #ifndef MP_NOINLINE diff --git a/pic16bit/mpconfigport.h b/pic16bit/mpconfigport.h index 7335ecf348..24cfe43529 100644 --- a/pic16bit/mpconfigport.h +++ b/pic16bit/mpconfigport.h @@ -83,8 +83,6 @@ typedef int mp_int_t; // must be pointer size typedef unsigned int mp_uint_t; // must be pointer size -typedef void *machine_ptr_t; // must be pointer size -typedef const void *machine_const_ptr_t; // must be pointer size typedef int mp_off_t; #define MP_PLAT_PRINT_STRN(str, len) mp_hal_stdout_tx_strn_cooked(str, len) diff --git a/qemu-arm/mpconfigport.h b/qemu-arm/mpconfigport.h index ff0e3f99b5..33cc300a4d 100644 --- a/qemu-arm/mpconfigport.h +++ b/qemu-arm/mpconfigport.h @@ -36,8 +36,6 @@ typedef int32_t mp_int_t; // must be pointer size typedef uint32_t mp_uint_t; // must be pointer size -typedef void *machine_ptr_t; // must be of pointer size -typedef const void *machine_const_ptr_t; // must be of pointer size typedef long mp_off_t; #include diff --git a/stmhal/mpconfigport.h b/stmhal/mpconfigport.h index c2a2cbc1f1..3122a90655 100644 --- a/stmhal/mpconfigport.h +++ b/stmhal/mpconfigport.h @@ -202,8 +202,6 @@ extern const struct _mp_obj_module_t mp_module_network; typedef int mp_int_t; // must be pointer size typedef unsigned int mp_uint_t; // must be pointer size -typedef void *machine_ptr_t; // must be of pointer size -typedef const void *machine_const_ptr_t; // must be of pointer size typedef long mp_off_t; #define MP_PLAT_PRINT_STRN(str, len) mp_hal_stdout_tx_strn_cooked(str, len) diff --git a/teensy/mpconfigport.h b/teensy/mpconfigport.h index 05c040d415..334f76d8a0 100644 --- a/teensy/mpconfigport.h +++ b/teensy/mpconfigport.h @@ -59,8 +59,6 @@ extern const struct _mp_obj_module_t time_module; typedef int32_t mp_int_t; // must be pointer size typedef unsigned int mp_uint_t; // must be pointer size -typedef void *machine_ptr_t; // must be of pointer size -typedef const void *machine_const_ptr_t; // must be of pointer size typedef long mp_off_t; #define MP_PLAT_PRINT_STRN(str, len) mp_hal_stdout_tx_strn_cooked(str, len) diff --git a/unix/mpconfigport.h b/unix/mpconfigport.h index 86b6001d5b..9845e1ce5f 100644 --- a/unix/mpconfigport.h +++ b/unix/mpconfigport.h @@ -231,9 +231,6 @@ typedef long long mp_off_t; typedef long mp_off_t; #endif -typedef void *machine_ptr_t; // must be of pointer size -typedef const void *machine_const_ptr_t; // must be of pointer size - void mp_unix_alloc_exec(mp_uint_t min_size, void** ptr, mp_uint_t *size); void mp_unix_free_exec(void *ptr, mp_uint_t size); void mp_unix_mark_exec(void); diff --git a/unix/mpconfigport_minimal.h b/unix/mpconfigport_minimal.h index 054e82c243..15a5f7d852 100644 --- a/unix/mpconfigport_minimal.h +++ b/unix/mpconfigport_minimal.h @@ -135,9 +135,6 @@ typedef long long mp_off_t; typedef long mp_off_t; #endif -typedef void *machine_ptr_t; // must be of pointer size -typedef const void *machine_const_ptr_t; // must be of pointer size - // We need to provide a declaration/definition of alloca() #ifdef __FreeBSD__ #include diff --git a/windows/mpconfigport.h b/windows/mpconfigport.h index a860c2e322..ccf8768bf5 100644 --- a/windows/mpconfigport.h +++ b/windows/mpconfigport.h @@ -138,9 +138,6 @@ typedef long long mp_off_t; typedef long mp_off_t; #endif -typedef void *machine_ptr_t; // must be of pointer size -typedef const void *machine_const_ptr_t; // must be of pointer size - #if MICROPY_PY_OS_DUPTERM #define MP_PLAT_PRINT_STRN(str, len) mp_hal_stdout_tx_strn_cooked(str, len) void mp_hal_dupterm_tx_strn(const char *str, size_t len); From f6a8e84a2557c5edf29a6f3afa4d1cce1d42d389 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 15 Aug 2016 21:28:41 +1000 Subject: [PATCH 023/129] tests/basics: Add test for break from within try within a for-loop. --- tests/basics/try_finally_loops.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/basics/try_finally_loops.py b/tests/basics/try_finally_loops.py index 28a8373dc0..06a6b4a0ce 100644 --- a/tests/basics/try_finally_loops.py +++ b/tests/basics/try_finally_loops.py @@ -33,3 +33,11 @@ for i in range(4): print('here') finally: print('finnaly 3') + +# break from within try-finally, within for-loop +for i in [1]: + try: + print(i) + break + finally: + print('finally 4') From 095e43a9a5b3fc7c1220cdbabe6a4fed0973b1e1 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 15 Aug 2016 23:26:34 +1000 Subject: [PATCH 024/129] py/sequence: Allow to use bignums as indices in slice objects. See issue #2264. --- py/sequence.c | 6 +++--- tests/basics/slice_bignum.py | 5 +++++ 2 files changed, 8 insertions(+), 3 deletions(-) create mode 100644 tests/basics/slice_bignum.py diff --git a/py/sequence.c b/py/sequence.c index 6f715ff795..239f1b2cc5 100644 --- a/py/sequence.c +++ b/py/sequence.c @@ -56,12 +56,12 @@ bool mp_seq_get_fast_slice_indexes(mp_uint_t len, mp_obj_t slice, mp_bound_slice if (ostart == mp_const_none) { start = 0; } else { - start = MP_OBJ_SMALL_INT_VALUE(ostart); + start = mp_obj_get_int(ostart); } if (ostop == mp_const_none) { stop = len; } else { - stop = MP_OBJ_SMALL_INT_VALUE(ostop); + stop = mp_obj_get_int(ostop); } // Unlike subscription, out-of-bounds slice indexes are never error @@ -88,7 +88,7 @@ bool mp_seq_get_fast_slice_indexes(mp_uint_t len, mp_obj_t slice, mp_bound_slice indexes->stop = stop; if (ostep != mp_const_none && ostep != MP_OBJ_NEW_SMALL_INT(1)) { - indexes->step = MP_OBJ_SMALL_INT_VALUE(ostep); + indexes->step = mp_obj_get_int(ostep); return false; } indexes->step = 1; diff --git a/tests/basics/slice_bignum.py b/tests/basics/slice_bignum.py new file mode 100644 index 0000000000..cc820522b0 --- /dev/null +++ b/tests/basics/slice_bignum.py @@ -0,0 +1,5 @@ +# test slicing when arguments are bignums + +print(list(range(10))[(1<<66)>>65:]) +print(list(range(10))[:(1<<66)>>65]) +print(list(range(10))[::(1<<66)>>65]) From d2cc7c720b3c6cd0f48f235a04d2e0bb740dad44 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Tue, 16 Aug 2016 17:02:04 +0300 Subject: [PATCH 025/129] extmod/modwebrepl: set_password(): Raise exception for too long password. --- extmod/modwebrepl.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/extmod/modwebrepl.c b/extmod/modwebrepl.c index 4e3780fa4d..858d2c1c0b 100644 --- a/extmod/modwebrepl.c +++ b/extmod/modwebrepl.c @@ -310,9 +310,10 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(webrepl_close_obj, webrepl_close); STATIC mp_obj_t webrepl_set_password(mp_obj_t passwd_in) { mp_uint_t len; const char *passwd = mp_obj_str_get_data(passwd_in, &len); - len = MIN(len, sizeof(webrepl_passwd) - 1); - memcpy(webrepl_passwd, passwd, len); - webrepl_passwd[len] = 0; + if (len > sizeof(webrepl_passwd) - 1) { + mp_raise_ValueError(""); + } + strcpy(webrepl_passwd, passwd); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(webrepl_set_password_obj, webrepl_set_password); From ed6a1ada2470617cb4fd4a65b0947ae982cfe927 Mon Sep 17 00:00:00 2001 From: rguillon Date: Sun, 14 Aug 2016 17:59:47 +0200 Subject: [PATCH 026/129] tests/basics: Add a test file for overriding special methods. --- tests/basics/special_methods.py | 153 ++++++++++++++++++++++++++++++++ 1 file changed, 153 insertions(+) create mode 100644 tests/basics/special_methods.py diff --git a/tests/basics/special_methods.py b/tests/basics/special_methods.py new file mode 100644 index 0000000000..b4eb8710d3 --- /dev/null +++ b/tests/basics/special_methods.py @@ -0,0 +1,153 @@ +class Cud(): + + def __init__(self): + print("__init__ called") + + def __repr__(self): + print("__repr__ called") + return "" + + def __lt__(self, other): + print("__lt__ called") + + def __le__(self, other): + print("__le__ called") + + def __eq__(self, other): + print("__eq__ called") + + def __ne__(self, other): + print("__ne__ called") + + def __ge__(self, other): + print("__ge__ called") + + def __gt__(self, other): + print("__gt__ called") + + def __abs__(self): + print("__abs__ called") + + def __add__(self, other): + print("__add__ called") + + def __and__(self, other): + print("__and__ called") + + def __floordiv__(self, other): + print("__floordiv__ called") + + def __index__(self, other): + print("__index__ called") + + def __inv__(self): + print("__inv__ called") + + def __invert__(self): + print("__invert__ called") + + def __lshift__(self, val): + print("__lshift__ called") + + def __mod__(self, val): + print("__mod__ called") + + def __mul__(self, other): + print("__mul__ called") + + def __matmul__(self, other): + print("__matmul__ called") + + def __neg__(self): + print("__neg__ called") + + def __or__(self, other): + print("__or__ called") + + def __pos__(self): + print("__pos__ called") + + def __pow__(self, val): + print("__pow__ called") + + def __rshift__(self, val): + print("__rshift__ called") + + def __sub__(self, other): + print("__sub__ called") + + def __truediv__(self, other): + print("__truediv__ called") + + def __div__(self, other): + print("__div__ called") + + def __xor__(self, other): + print("__xor__ called") + +cud1 = Cud() +cud2 = Cud() +str(cud1) +cud1 < cud2 +cud1 <= cud2 +cud1 == cud2 +cud1 >= cud2 +cud1 > cud2 +cud1 + cud2 + +# TODO: the following operations are not supported on every ports +# +# ne is not supported, !(eq) is called instead +#cud1 != cud2 +# +# binary and is not supported +# cud1 & cud2 +# +# floor div is not supported on the qemu arm port +# cud2 // cud1 +# +# inv is not supported on the qemu arm port +# ~cud1 +# +# binary lshift is not supported +# cud1<<1 +# +# modulus is not supported +# cud1 % 2 +# +# mult is not supported on the qemu arm port +# cud1 * cud2 +# +# mult is not supported on the qemu arm port +# cud1 * 2 +# +# inv is not supported on the qemu arm port +# -cud1 +# +# binary or is not supported +# cud1 | cud2 +# +# pos is not supported on the qemu arm port +# +cud1 +# +# pow is not supported +# cud1**2 +# +# rshift is not suported +# cud1>>1 +# +# sub is not supported on the qemu arm port +# cud1 - cud2 +# +# div is not supported on the qemu arm port +# cud1 / cud2 +# +# div is not supported on the qemu arm port +# cud1 / 2 +# +# xor is not supported +# cud1^cud2 +# +# in the followin test, cpython still calls __eq__ +# cud3=cud1 +# cud3==cud1 From f003310deeaf524a7db4428304f6cbdd2aa80e72 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 17 Aug 2016 12:37:28 +1000 Subject: [PATCH 027/129] qemu-arm: Enable MICROPY_PY_ALL_SPECIAL_METHODS. The qemu-arm port is for testing, so should have features enabled. --- qemu-arm/mpconfigport.h | 1 + 1 file changed, 1 insertion(+) diff --git a/qemu-arm/mpconfigport.h b/qemu-arm/mpconfigport.h index 33cc300a4d..57277b1569 100644 --- a/qemu-arm/mpconfigport.h +++ b/qemu-arm/mpconfigport.h @@ -16,6 +16,7 @@ #define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ) #define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_NONE) #define MICROPY_CAN_OVERRIDE_BUILTINS (1) +#define MICROPY_PY_ALL_SPECIAL_METHODS (1) #define MICROPY_PY_ARRAY_SLICE_ASSIGN (1) #define MICROPY_PY_BUILTINS_FROZENSET (1) #define MICROPY_PY_BUILTINS_MEMORYVIEW (1) From bb19e7b94bd8cc69b75e6d39dd9f2ec6e0cebba6 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 17 Aug 2016 12:38:19 +1000 Subject: [PATCH 028/129] tests/basics/special_methods: Enable tests for extra special methods. These additional special methods are enabled on most ports so we can test them in this test. --- tests/basics/special_methods.py | 47 ++++++++++++++------------------- 1 file changed, 20 insertions(+), 27 deletions(-) diff --git a/tests/basics/special_methods.py b/tests/basics/special_methods.py index b4eb8710d3..1df7a7c4c7 100644 --- a/tests/basics/special_methods.py +++ b/tests/basics/special_methods.py @@ -85,8 +85,17 @@ class Cud(): def __xor__(self, other): print("__xor__ called") + def __iadd__(self, other): + print("__iadd__ called") + return self + + def __isub__(self, other): + print("__isub__ called") + return self + cud1 = Cud() cud2 = Cud() + str(cud1) cud1 < cud2 cud1 <= cud2 @@ -94,6 +103,17 @@ cud1 == cud2 cud1 >= cud2 cud1 > cud2 cud1 + cud2 +cud1 - cud2 + +# the following require MICROPY_PY_ALL_SPECIAL_METHODS ++cud1 +-cud1 +~cud1 +cud1 * cud2 +cud1 / cud2 +cud2 // cud1 +cud1 += cud2 +cud1 -= cud2 # TODO: the following operations are not supported on every ports # @@ -103,48 +123,21 @@ cud1 + cud2 # binary and is not supported # cud1 & cud2 # -# floor div is not supported on the qemu arm port -# cud2 // cud1 -# -# inv is not supported on the qemu arm port -# ~cud1 -# # binary lshift is not supported # cud1<<1 # # modulus is not supported # cud1 % 2 # -# mult is not supported on the qemu arm port -# cud1 * cud2 -# -# mult is not supported on the qemu arm port -# cud1 * 2 -# -# inv is not supported on the qemu arm port -# -cud1 -# # binary or is not supported # cud1 | cud2 # -# pos is not supported on the qemu arm port -# +cud1 -# # pow is not supported # cud1**2 # # rshift is not suported # cud1>>1 # -# sub is not supported on the qemu arm port -# cud1 - cud2 -# -# div is not supported on the qemu arm port -# cud1 / cud2 -# -# div is not supported on the qemu arm port -# cud1 / 2 -# # xor is not supported # cud1^cud2 # From ff1c2b03a90af57589e29d17f8846961b9bdae95 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Wed, 17 Aug 2016 06:00:28 +0300 Subject: [PATCH 029/129] extmod/uzlib/: Update uzlib to v2.0. New API supporting stream decompression. --- extmod/uzlib/adler32.c | 6 +- extmod/uzlib/crc32.c | 63 +++++++ extmod/uzlib/tinf.h | 78 ++++---- extmod/uzlib/tinflate.c | 381 +++++++++++++++++++++------------------- extmod/uzlib/tinfzlib.c | 53 +----- 5 files changed, 326 insertions(+), 255 deletions(-) create mode 100644 extmod/uzlib/crc32.c diff --git a/extmod/uzlib/adler32.c b/extmod/uzlib/adler32.c index f99b2d7f40..b06a7b37cc 100644 --- a/extmod/uzlib/adler32.c +++ b/extmod/uzlib/adler32.c @@ -41,12 +41,12 @@ #define A32_BASE 65521 #define A32_NMAX 5552 -unsigned int tinf_adler32(const void *data, unsigned int length) +unsigned int uzlib_adler32(const void *data, unsigned int length, unsigned int prev_sum /* 1 */) { const unsigned char *buf = (const unsigned char *)data; - unsigned int s1 = 1; - unsigned int s2 = 0; + unsigned int s1 = prev_sum & 0xffff; + unsigned int s2 = prev_sum >> 16; while (length > 0) { diff --git a/extmod/uzlib/crc32.c b/extmod/uzlib/crc32.c new file mode 100644 index 0000000000..8c9976594d --- /dev/null +++ b/extmod/uzlib/crc32.c @@ -0,0 +1,63 @@ +/* + * CRC32 checksum + * + * Copyright (c) 1998-2003 by Joergen Ibsen / Jibz + * All Rights Reserved + * + * http://www.ibsensoftware.com/ + * + * This software is provided 'as-is', without any express + * or implied warranty. In no event will the authors be + * held liable for any damages arising from the use of + * this software. + * + * Permission is granted to anyone to use this software + * for any purpose, including commercial applications, + * and to alter it and redistribute it freely, subject to + * the following restrictions: + * + * 1. The origin of this software must not be + * misrepresented; you must not claim that you + * wrote the original software. If you use this + * software in a product, an acknowledgment in + * the product documentation would be appreciated + * but is not required. + * + * 2. Altered source versions must be plainly marked + * as such, and must not be misrepresented as + * being the original software. + * + * 3. This notice may not be removed or altered from + * any source distribution. + */ + +/* + * CRC32 algorithm taken from the zlib source, which is + * Copyright (C) 1995-1998 Jean-loup Gailly and Mark Adler + */ + +#include "tinf.h" + +static const unsigned int tinf_crc32tab[16] = { + 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, + 0x6b6b51f4, 0x4db26158, 0x5005713c, 0xedb88320, 0xf00f9344, + 0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, + 0xbdbdf21c +}; + +/* crc is previous value for incremental computation, 0xffffffff initially */ +unsigned int uzlib_crc32(const void *data, unsigned int length, unsigned int crc) +{ + const unsigned char *buf = (const unsigned char *)data; + unsigned int i; + + for (i = 0; i < length; ++i) + { + crc ^= buf[i]; + crc = tinf_crc32tab[crc & 0x0f] ^ (crc >> 4); + crc = tinf_crc32tab[crc & 0x0f] ^ (crc >> 4); + } + + // return value suitable for passing in next time, for final value invert it + return crc/* ^ 0xffffffff*/; +} diff --git a/extmod/uzlib/tinf.h b/extmod/uzlib/tinf.h index e9401f2de5..3545bbd883 100644 --- a/extmod/uzlib/tinf.h +++ b/extmod/uzlib/tinf.h @@ -5,7 +5,7 @@ * All Rights Reserved * http://www.ibsensoftware.com/ * - * Copyright (c) 2014 by Paul Sokolovsky + * Copyright (c) 2014-2016 by Paul Sokolovsky */ #ifndef TINF_H_INCLUDED @@ -26,9 +26,17 @@ extern "C" { #endif +/* ok status, more data produced */ #define TINF_OK 0 +/* end of compressed stream reached */ +#define TINF_DONE 1 #define TINF_DATA_ERROR (-3) -#define TINF_DEST_OVERFLOW (-4) +#define TINF_CHKSUM_ERROR (-4) + +/* checksum types */ +#define TINF_CHKSUM_NONE 0 +#define TINF_CHKSUM_ADLER 1 +#define TINF_CHKSUM_CRC 2 /* data structures */ @@ -40,6 +48,10 @@ typedef struct { struct TINF_DATA; typedef struct TINF_DATA { const unsigned char *source; + /* If source above is NULL, this function will be used to read + next byte from source stream */ + unsigned char (*readSource)(struct TINF_DATA *data); + unsigned int tag; unsigned int bitcount; @@ -51,49 +63,51 @@ typedef struct TINF_DATA { unsigned char *dest; /* Remaining bytes in buffer */ unsigned int destRemaining; - /* Argument is the allocation size which didn't fit into buffer. Note that - exact mimumum size to grow buffer by is lastAlloc - destRemaining. But - growing by this exact size is ineficient, as the next allocation will - fail again. */ - int (*destGrow)(struct TINF_DATA *data, unsigned int lastAlloc); + + /* Accumulating checksum */ + unsigned int checksum; + char checksum_type; + + int btype; + int bfinal; + unsigned int curlen; + int lzOff; + unsigned char *dict_ring; + unsigned int dict_size; + unsigned int dict_idx; TINF_TREE ltree; /* dynamic length/symbol tree */ TINF_TREE dtree; /* dynamic distance tree */ } TINF_DATA; +#define TINF_PUT(d, c) \ + { \ + *d->dest++ = c; \ + if (d->dict_ring) { d->dict_ring[d->dict_idx++] = c; if (d->dict_idx == d->dict_size) d->dict_idx = 0; } \ + } -/* low-level API */ +unsigned char TINFCC uzlib_get_byte(TINF_DATA *d); -/* Step 1: Allocate TINF_DATA structure */ -/* Step 2: Set destStart, destSize, and destGrow fields */ -/* Step 3: Set source field */ -/* Step 4: Call tinf_uncompress_dyn() */ -/* Step 5: In response to destGrow callback, update destStart and destSize fields */ -/* Step 6: When tinf_uncompress_dyn() returns, buf.dest points to a byte past last uncompressed byte */ +/* Decompression API */ -int TINFCC tinf_uncompress_dyn(TINF_DATA *d); -int TINFCC tinf_zlib_uncompress_dyn(TINF_DATA *d, unsigned int sourceLen); +void TINFCC uzlib_init(void); +void TINFCC uzlib_uncompress_init(TINF_DATA *d, void *dict, unsigned int dictLen); +int TINFCC uzlib_uncompress(TINF_DATA *d); +int TINFCC uzlib_uncompress_chksum(TINF_DATA *d); -/* high-level API */ +int TINFCC uzlib_zlib_parse_header(TINF_DATA *d); +int TINFCC uzlib_gzip_parse_header(TINF_DATA *d); -void TINFCC tinf_init(void); +/* Compression API */ -int TINFCC tinf_uncompress(void *dest, unsigned int *destLen, - const void *source, unsigned int sourceLen); +void TINFCC uzlib_compress(void *data, const uint8_t *src, unsigned slen); -int TINFCC tinf_gzip_uncompress(void *dest, unsigned int *destLen, - const void *source, unsigned int sourceLen); +/* Checksum API */ -int TINFCC tinf_zlib_uncompress(void *dest, unsigned int *destLen, - const void *source, unsigned int sourceLen); - -unsigned int TINFCC tinf_adler32(const void *data, unsigned int length); - -unsigned int TINFCC tinf_crc32(const void *data, unsigned int length); - -/* compression API */ - -void TINFCC tinf_compress(void *data, const uint8_t *src, unsigned slen); +/* prev_sum is previous value for incremental computation, 1 initially */ +uint32_t TINFCC uzlib_adler32(const void *data, unsigned int length, uint32_t prev_sum); +/* crc is previous value for incremental computation, 0xffffffff initially */ +uint32_t TINFCC uzlib_crc32(const void *data, unsigned int length, uint32_t crc); #ifdef __cplusplus } /* extern "C" */ diff --git a/extmod/uzlib/tinflate.c b/extmod/uzlib/tinflate.c index faf27e5739..47644bfcb8 100644 --- a/extmod/uzlib/tinflate.c +++ b/extmod/uzlib/tinflate.c @@ -5,7 +5,7 @@ * All Rights Reserved * http://www.ibsensoftware.com/ * - * Copyright (c) 2014 by Paul Sokolovsky + * Copyright (c) 2014-2016 by Paul Sokolovsky * * This software is provided 'as-is', without any express * or implied warranty. In no event will the authors be @@ -32,6 +32,7 @@ * any source distribution. */ +#include #include "tinf.h" /* --------------------------------------------------- * @@ -89,21 +90,6 @@ const unsigned char clcidx[] = { * -- utility functions -- * * ----------------------- */ -/* Execute callback to grow destination buffer */ -static int tinf_grow_dest_buf(TINF_DATA *d, unsigned int lastAlloc) -{ - unsigned int oldsize = d->dest - d->destStart; - /* This will update only destStart and destSize */ - if (!d->destGrow) - { - return TINF_DEST_OVERFLOW; - } - d->destGrow(d, lastAlloc); - d->dest = d->destStart + oldsize; - d->destRemaining = d->destSize - oldsize; - return 0; -} - #ifdef RUNTIME_BITS_TABLES /* build extra bits and base tables */ static void tinf_build_bits_base(unsigned char *bits, unsigned short *base, int delta, int first) @@ -180,6 +166,34 @@ static void tinf_build_tree(TINF_TREE *t, const unsigned char *lengths, unsigned * -- decode functions -- * * ---------------------- */ +unsigned char uzlib_get_byte(TINF_DATA *d) +{ + if (d->source) { + return *d->source++; + } + return d->readSource(d); +} + +uint32_t tinf_get_le_uint32(TINF_DATA *d) +{ + uint32_t val = 0; + int i; + for (i = 4; i--;) { + val = val >> 8 | uzlib_get_byte(d) << 24; + } + return val; +} + +uint32_t tinf_get_be_uint32(TINF_DATA *d) +{ + uint32_t val = 0; + int i; + for (i = 4; i--;) { + val = val << 8 | uzlib_get_byte(d); + } + return val; +} + /* get one bit from source stream */ static int tinf_getbit(TINF_DATA *d) { @@ -189,7 +203,7 @@ static int tinf_getbit(TINF_DATA *d) if (!d->bitcount--) { /* load next tag */ - d->tag = *d->source++; + d->tag = uzlib_get_byte(d); d->bitcount = 7; } @@ -318,113 +332,83 @@ static void tinf_decode_trees(TINF_DATA *d, TINF_TREE *lt, TINF_TREE *dt) /* given a stream and two trees, inflate a block of data */ static int tinf_inflate_block_data(TINF_DATA *d, TINF_TREE *lt, TINF_TREE *dt) { - while (1) - { - int sym = tinf_decode_symbol(d, lt); + if (d->curlen == 0) { + unsigned int offs; + int dist; + int sym = tinf_decode_symbol(d, lt); + //printf("huff sym: %02x\n", sym); - /* check for end of block */ - if (sym == 256) - { - return TINF_OK; - } + /* literal byte */ + if (sym < 256) { + TINF_PUT(d, sym); + return TINF_OK; + } - if (sym < 256) - { - if (d->destRemaining == 0) - { - int res = tinf_grow_dest_buf(d, 1); - if (res) return res; - } + /* end of block */ + if (sym == 256) { + return TINF_DONE; + } - *d->dest++ = sym; - d->destRemaining--; + /* substring from sliding dictionary */ + sym -= 257; + /* possibly get more bits from length code */ + d->curlen = tinf_read_bits(d, length_bits[sym], length_base[sym]); - } else { + dist = tinf_decode_symbol(d, dt); + /* possibly get more bits from distance code */ + offs = tinf_read_bits(d, dist_bits[dist], dist_base[dist]); + if (d->dict_ring) { + d->lzOff = d->dict_idx - offs; + if (d->lzOff < 0) { + d->lzOff += d->dict_size; + } + } else { + d->lzOff = -offs; + } + } - unsigned int length, offs, i; - int dist; - - sym -= 257; - - /* possibly get more bits from length code */ - length = tinf_read_bits(d, length_bits[sym], length_base[sym]); - - dist = tinf_decode_symbol(d, dt); - - /* possibly get more bits from distance code */ - offs = tinf_read_bits(d, dist_bits[dist], dist_base[dist]); - - if (d->destRemaining < length) - { - int res = tinf_grow_dest_buf(d, length); - if (res) return res; - } - - /* copy match */ - for (i = 0; i < length; ++i) - { - d->dest[i] = d->dest[(int)(i - offs)]; - } - - d->dest += length; - d->destRemaining -= length; - } - } + /* copy next byte from dict substring */ + if (d->dict_ring) { + TINF_PUT(d, d->dict_ring[d->lzOff]); + if (++d->lzOff == d->dict_size) { + d->lzOff = 0; + } + } else { + d->dest[0] = d->dest[d->lzOff]; + d->dest++; + } + d->curlen--; + return TINF_OK; } /* inflate an uncompressed block of data */ static int tinf_inflate_uncompressed_block(TINF_DATA *d) { - unsigned int length, invlength; - unsigned int i; + if (d->curlen == 0) { + unsigned int length, invlength; - /* get length */ - length = d->source[1]; - length = 256*length + d->source[0]; + /* get length */ + length = uzlib_get_byte(d) + 256 * uzlib_get_byte(d); + /* get one's complement of length */ + invlength = uzlib_get_byte(d) + 256 * uzlib_get_byte(d); + /* check length */ + if (length != (~invlength & 0x0000ffff)) return TINF_DATA_ERROR; - /* get one's complement of length */ - invlength = d->source[3]; - invlength = 256*invlength + d->source[2]; + /* increment length to properly return TINF_DONE below, without + producing data at the same time */ + d->curlen = length + 1; - /* check length */ - if (length != (~invlength & 0x0000ffff)) return TINF_DATA_ERROR; + /* make sure we start next block on a byte boundary */ + d->bitcount = 0; + } - if (d->destRemaining < length) - { - int res = tinf_grow_dest_buf(d, length); - if (res) return res; - } + if (--d->curlen == 0) { + return TINF_DONE; + } - d->source += 4; - - /* copy block */ - for (i = length; i; --i) *d->dest++ = *d->source++; - d->destRemaining -= length; - - /* make sure we start next block on a byte boundary */ - d->bitcount = 0; - - return TINF_OK; -} - -/* inflate a block of data compressed with fixed huffman trees */ -static int tinf_inflate_fixed_block(TINF_DATA *d) -{ - /* build fixed huffman trees */ - tinf_build_fixed_trees(&d->ltree, &d->dtree); - - /* decode block using fixed trees */ - return tinf_inflate_block_data(d, &d->ltree, &d->dtree); -} - -/* inflate a block of data compressed with dynamic huffman trees */ -static int tinf_inflate_dynamic_block(TINF_DATA *d) -{ - /* decode trees from stream */ - tinf_decode_trees(d, &d->ltree, &d->dtree); - - /* decode block using decoded trees */ - return tinf_inflate_block_data(d, &d->ltree, &d->dtree); + unsigned char c = uzlib_get_byte(d); + TINF_PUT(d, c); + return TINF_OK; } /* ---------------------- * @@ -432,7 +416,7 @@ static int tinf_inflate_dynamic_block(TINF_DATA *d) * ---------------------- */ /* initialize global (static) data */ -void tinf_init(void) +void uzlib_init(void) { #ifdef RUNTIME_BITS_TABLES /* build extra bits and base tables */ @@ -445,72 +429,117 @@ void tinf_init(void) #endif } -/* inflate stream from source to dest */ -int tinf_uncompress(void *dest, unsigned int *destLen, - const void *source, unsigned int sourceLen) +/* initialize decompression structure */ +void uzlib_uncompress_init(TINF_DATA *d, void *dict, unsigned int dictLen) { - (void)sourceLen; - TINF_DATA d; - int res; - - /* initialise data */ - d.source = (const unsigned char *)source; - - d.destStart = (unsigned char *)dest; - d.destRemaining = *destLen; - d.destSize = *destLen; - - res = tinf_uncompress_dyn(&d); - - *destLen = d.dest - d.destStart; - - return res; -} - -/* inflate stream from source to dest */ -int tinf_uncompress_dyn(TINF_DATA *d) -{ - int bfinal; - - /* initialise data */ d->bitcount = 0; - - d->dest = d->destStart; - d->destRemaining = d->destSize; - - do { - - unsigned int btype; - int res; - - /* read final block flag */ - bfinal = tinf_getbit(d); - - /* read block type (2 bits) */ - btype = tinf_read_bits(d, 2, 0); - - /* decompress block */ - switch (btype) - { - case 0: - /* decompress uncompressed block */ - res = tinf_inflate_uncompressed_block(d); - break; - case 1: - /* decompress block with fixed huffman trees */ - res = tinf_inflate_fixed_block(d); - break; - case 2: - /* decompress block with dynamic huffman trees */ - res = tinf_inflate_dynamic_block(d); - break; - default: - return TINF_DATA_ERROR; - } - - if (res != TINF_OK) return TINF_DATA_ERROR; - - } while (!bfinal); - - return TINF_OK; + d->bfinal = 0; + d->btype = -1; + d->dict_size = dictLen; + d->dict_ring = dict; + d->dict_idx = 0; + d->curlen = 0; +} + +/* inflate next byte of compressed stream */ +int uzlib_uncompress(TINF_DATA *d) +{ + do { + int res; + + /* start a new block */ + if (d->btype == -1) { +next_blk: + /* read final block flag */ + d->bfinal = tinf_getbit(d); + /* read block type (2 bits) */ + d->btype = tinf_read_bits(d, 2, 0); + + //printf("Started new block: type=%d final=%d\n", d->btype, d->bfinal); + + if (d->btype == 1) { + /* build fixed huffman trees */ + tinf_build_fixed_trees(&d->ltree, &d->dtree); + } else if (d->btype == 2) { + /* decode trees from stream */ + tinf_decode_trees(d, &d->ltree, &d->dtree); + } + } + + /* process current block */ + switch (d->btype) + { + case 0: + /* decompress uncompressed block */ + res = tinf_inflate_uncompressed_block(d); + break; + case 1: + case 2: + /* decompress block with fixed/dyanamic huffman trees */ + /* trees were decoded previously, so it's the same routine for both */ + res = tinf_inflate_block_data(d, &d->ltree, &d->dtree); + break; + default: + return TINF_DATA_ERROR; + } + + if (res == TINF_DONE && !d->bfinal) { + /* the block has ended (without producing more data), but we + can't return without data, so start procesing next block */ + goto next_blk; + } + + if (res != TINF_OK) { + return res; + } + + } while (--d->destSize); + + return TINF_OK; +} + +int uzlib_uncompress_chksum(TINF_DATA *d) +{ + int res; + unsigned char *data = d->dest; + + res = uzlib_uncompress(d); + + if (res < 0) return res; + + switch (d->checksum_type) { + + case TINF_CHKSUM_ADLER: + d->checksum = uzlib_adler32(data, d->dest - data, d->checksum); + break; + + case TINF_CHKSUM_CRC: + d->checksum = uzlib_crc32(data, d->dest - data, d->checksum); + break; + } + + if (res == TINF_DONE) { + unsigned int val; + + switch (d->checksum_type) { + + case TINF_CHKSUM_ADLER: + val = tinf_get_be_uint32(d); + if (d->checksum != val) { + return TINF_CHKSUM_ERROR; + } + break; + + case TINF_CHKSUM_CRC: + val = tinf_get_le_uint32(d); + if (~d->checksum != val) { + return TINF_CHKSUM_ERROR; + } + // Uncompressed size. TODO: Check + val = tinf_get_le_uint32(d); + break; + } + } + + return res; } diff --git a/extmod/uzlib/tinfzlib.c b/extmod/uzlib/tinfzlib.c index dbacc1d9db..74fade3b9d 100644 --- a/extmod/uzlib/tinfzlib.c +++ b/extmod/uzlib/tinfzlib.c @@ -6,6 +6,8 @@ * * http://www.ibsensoftware.com/ * + * Copyright (c) 2014-2016 by Paul Sokolovsky + * * This software is provided 'as-is', without any express * or implied warranty. In no event will the authors be * held liable for any damages arising from the use of @@ -33,35 +35,14 @@ #include "tinf.h" -int tinf_zlib_uncompress(void *dest, unsigned int *destLen, - const void *source, unsigned int sourceLen) +int uzlib_zlib_parse_header(TINF_DATA *d) { - TINF_DATA d; - int res; - - /* initialise data */ - d.source = (const unsigned char *)source; - - d.destStart = (unsigned char *)dest; - d.destRemaining = *destLen; - - res = tinf_zlib_uncompress_dyn(&d, sourceLen); - - *destLen = d.dest - d.destStart; - - return res; -} - -int tinf_zlib_uncompress_dyn(TINF_DATA *d, unsigned int sourceLen) -{ - unsigned int a32; - int res; unsigned char cmf, flg; /* -- get header bytes -- */ - cmf = d->source[0]; - flg = d->source[1]; + cmf = uzlib_get_byte(d); + flg = uzlib_get_byte(d); /* -- check format -- */ @@ -77,25 +58,9 @@ int tinf_zlib_uncompress_dyn(TINF_DATA *d, unsigned int sourceLen) /* check there is no preset dictionary */ if (flg & 0x20) return TINF_DATA_ERROR; - /* -- get adler32 checksum -- */ + /* initialize for adler32 checksum */ + d->checksum_type = TINF_CHKSUM_ADLER; + d->checksum = 1; - a32 = d->source[sourceLen - 4]; - a32 = 256*a32 + d->source[sourceLen - 3]; - a32 = 256*a32 + d->source[sourceLen - 2]; - a32 = 256*a32 + d->source[sourceLen - 1]; - - d->source += 2; - - /* -- inflate -- */ - - res = tinf_uncompress_dyn(d); - - if (res != TINF_OK) return res; - - /* -- check adler32 checksum -- */ - - if (a32 != tinf_adler32(d->destStart, d->dest - d->destStart)) return TINF_DATA_ERROR; - - return TINF_OK; + return cmf >> 4; } - From ed4ce196ed098684c85770134ce42a9dd217a560 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Wed, 17 Aug 2016 06:05:37 +0300 Subject: [PATCH 030/129] extmod/moduzlib: Refactor to new stream-compatible uzlib 2.0 API. --- extmod/moduzlib.c | 63 ++++++++++++++++++++++++++++++----------------- 1 file changed, 40 insertions(+), 23 deletions(-) diff --git a/extmod/moduzlib.c b/extmod/moduzlib.c index 3d945abba5..b733ae2e04 100644 --- a/extmod/moduzlib.c +++ b/extmod/moduzlib.c @@ -25,6 +25,7 @@ */ #include +#include #include "py/nlr.h" #include "py/runtime.h" @@ -39,16 +40,6 @@ #define DEBUG_printf(...) (void)0 #endif -STATIC int mod_uzlib_grow_buf(TINF_DATA *d, unsigned alloc_req) { - if (alloc_req < 256) { - alloc_req = 256; - } - DEBUG_printf("uzlib: Resizing buffer to " UINT_FMT " bytes\n", d->destSize + alloc_req); - d->destStart = m_renew(byte, d->destStart, d->destSize, d->destSize + alloc_req); - d->destSize += alloc_req; - return 0; -} - STATIC mp_obj_t mod_uzlib_decompress(size_t n_args, const mp_obj_t *args) { (void)n_args; mp_obj_t data = args[0]; @@ -56,30 +47,55 @@ STATIC mp_obj_t mod_uzlib_decompress(size_t n_args, const mp_obj_t *args) { mp_get_buffer_raise(data, &bufinfo, MP_BUFFER_READ); TINF_DATA *decomp = m_new_obj(TINF_DATA); + memset(decomp, 0, sizeof(*decomp)); DEBUG_printf("sizeof(TINF_DATA)=" UINT_FMT "\n", sizeof(*decomp)); + uzlib_uncompress_init(decomp, NULL, 0); + mp_uint_t dest_buf_size = (bufinfo.len + 15) & ~15; + byte *dest_buf = m_new(byte, dest_buf_size); - decomp->destSize = (bufinfo.len + 15) & ~15; - decomp->destStart = m_new(byte, decomp->destSize); + decomp->dest = dest_buf; + decomp->destSize = dest_buf_size; DEBUG_printf("uzlib: Initial out buffer: " UINT_FMT " bytes\n", decomp->destSize); - decomp->destGrow = mod_uzlib_grow_buf; decomp->source = bufinfo.buf; int st; + bool is_zlib = true; + if (n_args > 1 && MP_OBJ_SMALL_INT_VALUE(args[1]) < 0) { - st = tinf_uncompress_dyn(decomp); - } else { - st = tinf_zlib_uncompress_dyn(decomp, bufinfo.len); - } - if (st != 0) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_ValueError, MP_OBJ_NEW_SMALL_INT(st))); + is_zlib = false; } - mp_uint_t final_sz = decomp->dest - decomp->destStart; - DEBUG_printf("uzlib: Resizing from " UINT_FMT " to final size: " UINT_FMT " bytes\n", decomp->destSize, final_sz); - decomp->destStart = (byte*)m_renew(byte, decomp->destStart, decomp->destSize, final_sz); - mp_obj_t res = mp_obj_new_bytearray_by_ref(final_sz, decomp->destStart); + if (is_zlib) { + st = uzlib_zlib_parse_header(decomp); + if (st < 0) { + goto error; + } + } + + while (1) { + st = uzlib_uncompress_chksum(decomp); + if (st < 0) { + goto error; + } + if (st == TINF_DONE) { + break; + } + size_t offset = decomp->dest - dest_buf; + dest_buf = m_renew(byte, dest_buf, dest_buf_size, dest_buf_size + 256); + dest_buf_size += 256; + decomp->dest = dest_buf + offset; + decomp->destSize = 256; + } + + mp_uint_t final_sz = decomp->dest - dest_buf; + DEBUG_printf("uzlib: Resizing from " UINT_FMT " to final size: " UINT_FMT " bytes\n", dest_buf_size, final_sz); + dest_buf = (byte*)m_renew(byte, dest_buf, dest_buf_size, final_sz); + mp_obj_t res = mp_obj_new_bytearray_by_ref(final_sz, dest_buf); m_del_obj(TINF_DATA, decomp); return res; + +error: + nlr_raise(mp_obj_new_exception_arg1(&mp_type_ValueError, MP_OBJ_NEW_SMALL_INT(st))); } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_uzlib_decompress_obj, 1, 3, mod_uzlib_decompress); @@ -102,5 +118,6 @@ const mp_obj_module_t mp_module_uzlib = { #include "uzlib/tinflate.c" #include "uzlib/tinfzlib.c" #include "uzlib/adler32.c" +#include "uzlib/crc32.c" #endif // MICROPY_PY_UZLIB From a6fc90f92ac0f2275c59cba131f99e541139c3cf Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Wed, 17 Aug 2016 06:10:16 +0300 Subject: [PATCH 031/129] tests/uzlib_decompress: Actually test raw DEFLATE stream. --- tests/extmod/uzlib_decompress.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/extmod/uzlib_decompress.py b/tests/extmod/uzlib_decompress.py index 4a898f27c7..468335a0d1 100644 --- a/tests/extmod/uzlib_decompress.py +++ b/tests/extmod/uzlib_decompress.py @@ -18,11 +18,17 @@ for unpacked, packed in PATTERNS: # Raw DEFLATE bitstream -v = b'\xcbH\xcd\xc9\xc9\x07\x00\x86\xa6\x106\x05\x00\x00\x00' +v = b'\xcbH\xcd\xc9\xc9\x07\x00' exp = b"hello" out = zlib.decompress(v, -15) assert(out == exp) print(exp) +# Even when you ask CPython zlib.compress to produce Raw DEFLATE stream, +# it returns it with adler2 and oriignal size appended, as if it was a +# zlib stream. Make sure there're no random issues decompressing such. +v = b'\xcbH\xcd\xc9\xc9\x07\x00\x86\xa6\x106\x05\x00\x00\x00' +out = zlib.decompress(v, -15) +assert(out == exp) # this should error try: From 244332df9f887ee2743431db80c4685fe6c24a2f Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Wed, 17 Aug 2016 06:24:12 +0300 Subject: [PATCH 032/129] extmod/uzlib/: Update uzlib to v2.0.1. Fixes for pedantic compiler warnings. --- extmod/uzlib/tinflate.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/extmod/uzlib/tinflate.c b/extmod/uzlib/tinflate.c index 47644bfcb8..0e53f7f072 100644 --- a/extmod/uzlib/tinflate.c +++ b/extmod/uzlib/tinflate.c @@ -35,6 +35,9 @@ #include #include "tinf.h" +uint32_t tinf_get_le_uint32(TINF_DATA *d); +uint32_t tinf_get_be_uint32(TINF_DATA *d); + /* --------------------------------------------------- * * -- uninitialized global data (static structures) -- * * --------------------------------------------------- */ @@ -370,7 +373,7 @@ static int tinf_inflate_block_data(TINF_DATA *d, TINF_TREE *lt, TINF_TREE *dt) /* copy next byte from dict substring */ if (d->dict_ring) { TINF_PUT(d, d->dict_ring[d->lzOff]); - if (++d->lzOff == d->dict_size) { + if ((unsigned)++d->lzOff == d->dict_size) { d->lzOff = 0; } } else { From 567e7fcd12078e5a27eacaea193dd1e4c846e43e Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 17 Aug 2016 13:48:09 +1000 Subject: [PATCH 033/129] tests/run-tests: Disable thread/thread_lock4.py on Travis. It has reliability issues that need to be worked out. --- tests/run-tests | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/run-tests b/tests/run-tests index 32d334a008..f796f28630 100755 --- a/tests/run-tests +++ b/tests/run-tests @@ -200,6 +200,7 @@ def run_tests(pyb, tests, args): # Some tests shouldn't be run under Travis CI if os.getenv('TRAVIS') == 'true': skip_tests.add('basics/memoryerror.py') + skip_tests.add('thread/thread_lock4.py') # has reliability issues if not has_complex: skip_tests.add('float/complex1.py') From 64c5a9435c3b100fdc50daafebf8550ab5f40780 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 17 Aug 2016 14:22:39 +1000 Subject: [PATCH 034/129] docs/library/machine.WDT: Add note that WDT is only available on WiPy. --- docs/library/machine.WDT.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/library/machine.WDT.rst b/docs/library/machine.WDT.rst index d7c801356e..ff534fd9b4 100644 --- a/docs/library/machine.WDT.rst +++ b/docs/library/machine.WDT.rst @@ -14,6 +14,8 @@ Example usage:: wdt = WDT(timeout=2000) # enable it with a timeout of 2s wdt.feed() +Availability of this class: WiPy. + Constructors ------------ From 49dd532180282f24ad31daf7f4f661722d4f9b16 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Wed, 17 Aug 2016 14:47:30 +0300 Subject: [PATCH 035/129] extmod/uzlib/: Update uzlib to v2.0.2. Consistently use stdint types. Fixes stmhal build. --- extmod/uzlib/adler32.c | 2 +- extmod/uzlib/crc32.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/extmod/uzlib/adler32.c b/extmod/uzlib/adler32.c index b06a7b37cc..1f1759493b 100644 --- a/extmod/uzlib/adler32.c +++ b/extmod/uzlib/adler32.c @@ -41,7 +41,7 @@ #define A32_BASE 65521 #define A32_NMAX 5552 -unsigned int uzlib_adler32(const void *data, unsigned int length, unsigned int prev_sum /* 1 */) +uint32_t uzlib_adler32(const void *data, unsigned int length, uint32_t prev_sum /* 1 */) { const unsigned char *buf = (const unsigned char *)data; diff --git a/extmod/uzlib/crc32.c b/extmod/uzlib/crc32.c index 8c9976594d..e24c643b6a 100644 --- a/extmod/uzlib/crc32.c +++ b/extmod/uzlib/crc32.c @@ -46,7 +46,7 @@ static const unsigned int tinf_crc32tab[16] = { }; /* crc is previous value for incremental computation, 0xffffffff initially */ -unsigned int uzlib_crc32(const void *data, unsigned int length, unsigned int crc) +uint32_t uzlib_crc32(const void *data, unsigned int length, uint32_t crc) { const unsigned char *buf = (const unsigned char *)data; unsigned int i; From 8e7dfea803f618beaa2ad976dff0b196e449d5d9 Mon Sep 17 00:00:00 2001 From: Radomir Dopieralski Date: Tue, 7 Jun 2016 21:40:56 +0200 Subject: [PATCH 036/129] esp8266/modpybhspi: Add a HSPI module for hardware SPI support This module uses ESP8266's SPI hardware, which allows much higher speeds. It uses a library from https://github.com/MetalPhreak/ESP8266_SPI_Driver --- docs/esp8266/quickref.rst | 14 ++ esp8266/Makefile | 2 + esp8266/esp8266.ld | 2 + esp8266/hspi.c | 327 ++++++++++++++++++++++++++++++++++++++ esp8266/hspi.h | 79 +++++++++ esp8266/hspi_register.h | 278 ++++++++++++++++++++++++++++++++ esp8266/modmachine.c | 1 + esp8266/modpyb.h | 1 + esp8266/modpybhspi.c | 258 ++++++++++++++++++++++++++++++ 9 files changed, 962 insertions(+) create mode 100644 esp8266/hspi.c create mode 100644 esp8266/hspi.h create mode 100644 esp8266/hspi_register.h create mode 100644 esp8266/modpybhspi.c diff --git a/docs/esp8266/quickref.rst b/docs/esp8266/quickref.rst index 48543dfab6..be58f9332c 100644 --- a/docs/esp8266/quickref.rst +++ b/docs/esp8266/quickref.rst @@ -189,6 +189,20 @@ The SPI driver is implemented in software and works on all pins:: spi.write_readinto(b'1234', buf) # write to MOSI and read from MISO into the buffer spi.write_readinto(buf, buf) # write buf to MOSI and read MISO back into buf + +Hardware SPI +------------ + +The hardware SPI is faster (up to 80Mhz), but only works on following pins: +``MISO`` is gpio2, ``MOSI`` is gpio13, and ``SCK`` is gpio14. It has the same +methods as SPI, except for the pin parameters for the constructor and init +(as those are fixed). + + from machine import Pin, HSPI + + hspi = HSPI(baudrate=800000000, polarity=0, phase=0) + + I2C bus ------- diff --git a/esp8266/Makefile b/esp8266/Makefile index ea9c7eb871..22591f209b 100644 --- a/esp8266/Makefile +++ b/esp8266/Makefile @@ -79,6 +79,7 @@ SRC_C = \ modpybadc.c \ modpybuart.c \ modpybspi.c \ + modpybhspi.c \ modesp.c \ modnetwork.c \ modutime.c \ @@ -89,6 +90,7 @@ SRC_C = \ $(BUILD)/frozen.c \ fatfs_port.c \ axtls_helpers.c \ + hspi.c \ $(SRC_MOD) STM_SRC_C = $(addprefix stmhal/,\ diff --git a/esp8266/esp8266.ld b/esp8266/esp8266.ld index a55aff52e5..6c89858070 100644 --- a/esp8266/esp8266.ld +++ b/esp8266/esp8266.ld @@ -142,6 +142,8 @@ SECTIONS *modpybuart.o(.literal*, .text*) *modpybi2c.o(.literal*, .text*) *modpybspi.o(.literal*, .text*) + *modpybhspi.o(.literal*, .text*) + *hspi.o(.literal*, .text*) *modesp.o(.literal* .text*) *modnetwork.o(.literal* .text*) *moduos.o(.literal* .text*) diff --git a/esp8266/hspi.c b/esp8266/hspi.c new file mode 100644 index 0000000000..7315dc8a12 --- /dev/null +++ b/esp8266/hspi.c @@ -0,0 +1,327 @@ +/* +* The MIT License (MIT) +* +* Copyright (c) 2015 David Ogilvy (MetalPhreak) +* Modified 2016 by Radomir Dopieralski +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +#include "hspi.h" + +/* +Wrapper to setup HSPI/SPI GPIO pins and default SPI clock + spi_no - SPI (0) or HSPI (1) +Not used in Micropython. +*/ +void spi_init(uint8_t spi_no) { + spi_init_gpio(spi_no, SPI_CLK_USE_DIV); + spi_clock(spi_no, SPI_CLK_PREDIV, SPI_CLK_CNTDIV); + spi_tx_byte_order(spi_no, SPI_BYTE_ORDER_HIGH_TO_LOW); + spi_rx_byte_order(spi_no, SPI_BYTE_ORDER_HIGH_TO_LOW); + + SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_CS_SETUP|SPI_CS_HOLD); + CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_FLASH_MODE); +} + + +/* +Configures SPI mode parameters for clock edge and clock polarity. + spi_no - SPI (0) or HSPI (1) + spi_cpha - (0) Data is valid on clock leading edge + (1) Data is valid on clock trailing edge + spi_cpol - (0) Clock is low when inactive + (1) Clock is high when inactive +For Micropython this version is different from original. +*/ +void spi_mode(uint8_t spi_no, uint8_t spi_cpha, uint8_t spi_cpol) { + if (spi_cpol) { + SET_PERI_REG_MASK(SPI_PIN(HSPI), SPI_IDLE_EDGE); + } else { + CLEAR_PERI_REG_MASK(SPI_PIN(HSPI), SPI_IDLE_EDGE); + } + if (spi_cpha == spi_cpol) { + // Mode 3 - MOSI is set on falling edge of clock + // Mode 0 - MOSI is set on falling edge of clock + CLEAR_PERI_REG_MASK(SPI_USER(HSPI), SPI_CK_OUT_EDGE); + SET_PERI_REG_MASK(SPI_USER(HSPI), SPI_CK_I_EDGE); + } else { + // Mode 2 - MOSI is set on rising edge of clock + // Mode 1 - MOSI is set on rising edge of clock + SET_PERI_REG_MASK(SPI_USER(HSPI), SPI_CK_OUT_EDGE); + CLEAR_PERI_REG_MASK(SPI_USER(HSPI), SPI_CK_I_EDGE); + } +} + + +/* +Initialise the GPIO pins for use as SPI pins. + spi_no - SPI (0) or HSPI (1) + sysclk_as_spiclk - + SPI_CLK_80MHZ_NODIV (1) if using 80MHz for SPI clock. + SPI_CLK_USE_DIV (0) if using divider for lower speed. +*/ +void spi_init_gpio(uint8_t spi_no, uint8_t sysclk_as_spiclk) { + uint32_t clock_div_flag = 0; + if (sysclk_as_spiclk) { + clock_div_flag = 0x0001; + } + if (spi_no == SPI) { + // Set bit 8 if 80MHz sysclock required + WRITE_PERI_REG(PERIPHS_IO_MUX, 0x005 | (clock_div_flag<<8)); + PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CLK_U, 1); + PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CMD_U, 1); + PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA0_U, 1); + PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA1_U, 1); + } else if (spi_no == HSPI) { + // Set bit 9 if 80MHz sysclock required + WRITE_PERI_REG(PERIPHS_IO_MUX, 0x105 | (clock_div_flag<<9)); + // GPIO12 is HSPI MISO pin (Master Data In) + PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDI_U, 2); + // GPIO13 is HSPI MOSI pin (Master Data Out) + PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, 2); + // GPIO14 is HSPI CLK pin (Clock) + PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTMS_U, 2); + // GPIO15 is HSPI CS pin (Chip Select / Slave Select) + // In Micropython, we are handling CS ourself in drivers. + // PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, 2); + } +} + + +/* +Set up the control registers for the SPI clock + spi_no - SPI (0) or HSPI (1) + prediv - predivider value (actual division value) + cntdiv - postdivider value (actual division value) +Set either divider to 0 to disable all division (80MHz sysclock) +*/ +void spi_clock(uint8_t spi_no, uint16_t prediv, uint8_t cntdiv) { + if (prediv == 0 || cntdiv == 0) { + WRITE_PERI_REG(SPI_CLOCK(spi_no), SPI_CLK_EQU_SYSCLK); + } else { + WRITE_PERI_REG(SPI_CLOCK(spi_no), + (((prediv - 1) & SPI_CLKDIV_PRE) << SPI_CLKDIV_PRE_S) | + (((cntdiv - 1) & SPI_CLKCNT_N) << SPI_CLKCNT_N_S) | + (((cntdiv >> 1) & SPI_CLKCNT_H) << SPI_CLKCNT_H_S) | + ((0 & SPI_CLKCNT_L) << SPI_CLKCNT_L_S) + ); + } +} + + +/* +Setup the byte order for shifting data out of buffer + spi_no - SPI (0) or HSPI (1) + byte_order - + SPI_BYTE_ORDER_HIGH_TO_LOW (1) + Data is sent out starting with Bit31 and down to Bit0 + SPI_BYTE_ORDER_LOW_TO_HIGH (0) + Data is sent out starting with the lowest BYTE, from MSB to LSB, + followed by the second lowest BYTE, from MSB to LSB, followed by + the second highest BYTE, from MSB to LSB, followed by the highest + BYTE, from MSB to LSB 0xABCDEFGH would be sent as 0xGHEFCDAB. +*/ +void spi_tx_byte_order(uint8_t spi_no, uint8_t byte_order) { + if (byte_order) { + SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_WR_BYTE_ORDER); + } else { + CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_WR_BYTE_ORDER); + } +} + + +/* +Setup the byte order for shifting data into buffer + spi_no - SPI (0) or HSPI (1) + byte_order - + SPI_BYTE_ORDER_HIGH_TO_LOW (1) + Data is read in starting with Bit31 and down to Bit0 + SPI_BYTE_ORDER_LOW_TO_HIGH (0) + Data is read in starting with the lowest BYTE, from MSB to LSB, + followed by the second lowest BYTE, from MSB to LSB, followed by + the second highest BYTE, from MSB to LSB, followed by the highest + BYTE, from MSB to LSB 0xABCDEFGH would be read as 0xGHEFCDAB +*/ +void spi_rx_byte_order(uint8_t spi_no, uint8_t byte_order) { + if (byte_order) { + SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_RD_BYTE_ORDER); + } else { + CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_RD_BYTE_ORDER); + } +} + + +/* +SPI transaction function + spi_no - SPI (0) or HSPI (1) + cmd_bits - actual number of bits to transmit + cmd_data - command data + addr_bits - actual number of bits to transmit + addr_data - address data + dout_bits - actual number of bits to transmit + dout_data - output data + din_bits - actual number of bits to receive +Returns: read data - uint32_t containing read in data only if RX was set + 0 - something went wrong (or actual read data was 0) + 1 - data sent ok (or actual read data is 1) +Note: all data is assumed to be stored in the lower bits of the data variables +(for anything <32 bits). +*/ +uint32_t spi_transaction(uint8_t spi_no, uint8_t cmd_bits, uint16_t cmd_data, + uint32_t addr_bits, uint32_t addr_data, + uint32_t dout_bits, uint32_t dout_data, + uint32_t din_bits, uint32_t dummy_bits) { + while (spi_busy(spi_no)) {}; // Wait for SPI to be ready + +// Enable SPI Functions + // Disable MOSI, MISO, ADDR, COMMAND, DUMMY in case previously set. + CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MOSI | SPI_USR_MISO | + SPI_USR_COMMAND | SPI_USR_ADDR | SPI_USR_DUMMY); + + // Enable functions based on number of bits. 0 bits = disabled. + // This is rather inefficient but allows for a very generic function. + // CMD ADDR and MOSI are set below to save on an extra if statement. + if (din_bits) { + SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MISO); + } + if (dummy_bits) { + SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_DUMMY); + } + +// Setup Bitlengths + WRITE_PERI_REG(SPI_USER1(spi_no), + // Number of bits in Address + ((addr_bits - 1) & SPI_USR_ADDR_BITLEN) << SPI_USR_ADDR_BITLEN_S | + // Number of bits to Send + ((dout_bits - 1) & SPI_USR_MOSI_BITLEN) << SPI_USR_MOSI_BITLEN_S | + // Number of bits to receive + ((din_bits - 1) & SPI_USR_MISO_BITLEN) << SPI_USR_MISO_BITLEN_S | + // Number of Dummy bits to insert + ((dummy_bits - 1) & SPI_USR_DUMMY_CYCLELEN) << SPI_USR_DUMMY_CYCLELEN_S); + +// Setup Command Data + if (cmd_bits) { + // Enable COMMAND function in SPI module + SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_COMMAND); + // Align command data to high bits + uint16_t command = cmd_data << (16-cmd_bits); + // Swap byte order + command = ((command>>8)&0xff) | ((command<<8)&0xff00); + WRITE_PERI_REG(SPI_USER2(spi_no), ( + (((cmd_bits - 1) & SPI_USR_COMMAND_BITLEN) << SPI_USR_COMMAND_BITLEN_S) | + (command & SPI_USR_COMMAND_VALUE) + )); + } + +// Setup Address Data + if (addr_bits) { + // Enable ADDRess function in SPI module + SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_ADDR); + // Align address data to high bits + WRITE_PERI_REG(SPI_ADDR(spi_no), addr_data << (32 - addr_bits)); + } + +// Setup DOUT data + if (dout_bits) { + // Enable MOSI function in SPI module + SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MOSI); + // Copy data to W0 + if (READ_PERI_REG(SPI_USER(spi_no))&SPI_WR_BYTE_ORDER) { + WRITE_PERI_REG(SPI_W0(spi_no), dout_data << (32 - dout_bits)); + } else { + uint8_t dout_extra_bits = dout_bits%8; + + if (dout_extra_bits) { + // If your data isn't a byte multiple (8/16/24/32 bits) and you + // don't have SPI_WR_BYTE_ORDER set, you need this to move the + // non-8bit remainder to the MSBs. Not sure if there's even a use + // case for this, but it's here if you need it... For example, + // 0xDA4 12 bits without SPI_WR_BYTE_ORDER would usually be output + // as if it were 0x0DA4, of which 0xA4, and then 0x0 would be + // shifted out (first 8 bits of low byte, then 4 MSB bits of high + // byte - ie reverse byte order). + // The code below shifts it out as 0xA4 followed by 0xD as you + // might require. + WRITE_PERI_REG(SPI_W0(spi_no), ( + (0xFFFFFFFF << (dout_bits - dout_extra_bits) & dout_data) + << (8-dout_extra_bits) | + ((0xFFFFFFFF >> (32 - (dout_bits - dout_extra_bits))) + & dout_data) + )); + } else { + WRITE_PERI_REG(SPI_W0(spi_no), dout_data); + } + } +} + +// Begin SPI Transaction + SET_PERI_REG_MASK(SPI_CMD(spi_no), SPI_USR); + +// Return DIN data + if (din_bits) { + while (spi_busy(spi_no)) {}; // Wait for SPI transaction to complete + if (READ_PERI_REG(SPI_USER(spi_no))&SPI_RD_BYTE_ORDER) { + // Assuming data in is written to MSB. TBC + return READ_PERI_REG(SPI_W0(spi_no)) >> (32 - din_bits); + } else { + // Read in the same way as DOUT is sent. Note existing contents of + // SPI_W0 remain unless overwritten! + return READ_PERI_REG(SPI_W0(spi_no)); + } + return 0; // Something went wrong + } + + // Transaction completed + return 1; // Success +} + + +/* +Just do minimal work needed to send 8 bits. +*/ +inline void spi_tx8fast(uint8_t spi_no, uint8_t dout_data) { + while (spi_busy(spi_no)) {}; // Wait for SPI to be ready + +// Enable SPI Functions + // Disable MOSI, MISO, ADDR, COMMAND, DUMMY in case previously set. + CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MOSI | SPI_USR_MISO | + SPI_USR_COMMAND | SPI_USR_ADDR | SPI_USR_DUMMY); + +// Setup Bitlengths + WRITE_PERI_REG(SPI_USER1(spi_no), + // Number of bits to Send + ((8 - 1) & SPI_USR_MOSI_BITLEN) << SPI_USR_MOSI_BITLEN_S | + // Number of bits to receive + ((8 - 1) & SPI_USR_MISO_BITLEN) << SPI_USR_MISO_BITLEN_S); + + +// Setup DOUT data + // Enable MOSI function in SPI module + SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MOSI); + // Copy data to W0 + if (READ_PERI_REG(SPI_USER(spi_no)) & SPI_WR_BYTE_ORDER) { + WRITE_PERI_REG(SPI_W0(spi_no), dout_data << (32 - 8)); + } else { + WRITE_PERI_REG(SPI_W0(spi_no), dout_data); + } + +// Begin SPI Transaction + SET_PERI_REG_MASK(SPI_CMD(spi_no), SPI_USR); +} diff --git a/esp8266/hspi.h b/esp8266/hspi.h new file mode 100644 index 0000000000..c68366ef44 --- /dev/null +++ b/esp8266/hspi.h @@ -0,0 +1,79 @@ +/* +* The MIT License (MIT) +* +* Copyright (c) 2015 David Ogilvy (MetalPhreak) +* Modified 2016 by Radomir Dopieralski +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +#ifndef SPI_APP_H +#define SPI_APP_H + +#include "hspi_register.h" +#include "ets_sys.h" +#include "osapi.h" +#include "os_type.h" + +// Define SPI hardware modules +#define SPI 0 +#define HSPI 1 + +#define SPI_CLK_USE_DIV 0 +#define SPI_CLK_80MHZ_NODIV 1 + +#define SPI_BYTE_ORDER_HIGH_TO_LOW 1 +#define SPI_BYTE_ORDER_LOW_TO_HIGH 0 + +#ifndef CPU_CLK_FREQ //Should already be defined in eagle_soc.h +#define CPU_CLK_FREQ (80 * 1000000) +#endif + +// Define some default SPI clock settings +#define SPI_CLK_PREDIV 10 +#define SPI_CLK_CNTDIV 2 +#define SPI_CLK_FREQ (CPU_CLK_FREQ / (SPI_CLK_PREDIV * SPI_CLK_CNTDIV)) +// 80 / 20 = 4 MHz + +void spi_init(uint8_t spi_no); +void spi_mode(uint8_t spi_no, uint8_t spi_cpha,uint8_t spi_cpol); +void spi_init_gpio(uint8_t spi_no, uint8_t sysclk_as_spiclk); +void spi_clock(uint8_t spi_no, uint16_t prediv, uint8_t cntdiv); +void spi_tx_byte_order(uint8_t spi_no, uint8_t byte_order); +void spi_rx_byte_order(uint8_t spi_no, uint8_t byte_order); +uint32_t spi_transaction(uint8_t spi_no, uint8_t cmd_bits, uint16_t cmd_data, + uint32_t addr_bits, uint32_t addr_data, + uint32_t dout_bits, uint32_t dout_data, + uint32_t din_bits, uint32_t dummy_bits); +void spi_tx8fast(uint8_t spi_no, uint8_t dout_data); + +// Expansion Macros +#define spi_busy(spi_no) READ_PERI_REG(SPI_CMD(spi_no))&SPI_USR + +#define spi_txd(spi_no, bits, data) spi_transaction(spi_no, 0, 0, 0, 0, bits, (uint32_t) data, 0, 0) +#define spi_tx8(spi_no, data) spi_transaction(spi_no, 0, 0, 0, 0, 8, (uint32_t) data, 0, 0) +#define spi_tx16(spi_no, data) spi_transaction(spi_no, 0, 0, 0, 0, 16, (uint32_t) data, 0, 0) +#define spi_tx32(spi_no, data) spi_transaction(spi_no, 0, 0, 0, 0, 32, (uint32_t) data, 0, 0) + +#define spi_rxd(spi_no, bits) spi_transaction(spi_no, 0, 0, 0, 0, 0, 0, bits, 0) +#define spi_rx8(spi_no) spi_transaction(spi_no, 0, 0, 0, 0, 0, 0, 8, 0) +#define spi_rx16(spi_no) spi_transaction(spi_no, 0, 0, 0, 0, 0, 0, 16, 0) +#define spi_rx32(spi_no) spi_transaction(spi_no, 0, 0, 0, 0, 0, 0, 32, 0) + +#endif diff --git a/esp8266/hspi_register.h b/esp8266/hspi_register.h new file mode 100644 index 0000000000..30a5ff5884 --- /dev/null +++ b/esp8266/hspi_register.h @@ -0,0 +1,278 @@ +/* + * Copyright (c) 2010 - 2011 Espressif System + * Modified by David Ogilvy (MetalPhreak) + * Based on original file included in SDK 1.0.0 + * + * Missing defines from previous SDK versions have + * been added and are noted with comments. The + * names of these defines are likely to change. + */ + +#ifndef SPI_REGISTER_H_INCLUDED +#define SPI_REGISTER_H_INCLUDED + +#define REG_SPI_BASE(i) (0x60000200-i*0x100) + +#define SPI_CMD(i) (REG_SPI_BASE(i) + 0x0) +#define SPI_FLASH_READ (BIT(31)) //From previous SDK +#define SPI_FLASH_WREN (BIT(30)) //From previous SDK +#define SPI_FLASH_WRDI (BIT(29)) //From previous SDK +#define SPI_FLASH_RDID (BIT(28)) //From previous SDK +#define SPI_FLASH_RDSR (BIT(27)) //From previous SDK +#define SPI_FLASH_WRSR (BIT(26)) //From previous SDK +#define SPI_FLASH_PP (BIT(25)) //From previous SDK +#define SPI_FLASH_SE (BIT(24)) //From previous SDK +#define SPI_FLASH_BE (BIT(23)) //From previous SDK +#define SPI_FLASH_CE (BIT(22)) //From previous SDK +#define SPI_FLASH_DP (BIT(21)) //From previous SDK +#define SPI_FLASH_RES (BIT(20)) //From previous SDK +#define SPI_FLASH_HPM (BIT(19)) //From previous SDK +#define SPI_USR (BIT(18)) + +#define SPI_ADDR(i) (REG_SPI_BASE(i) + 0x4) + +#define SPI_CTRL(i) (REG_SPI_BASE(i) + 0x8) +#define SPI_WR_BIT_ORDER (BIT(26)) +#define SPI_RD_BIT_ORDER (BIT(25)) +#define SPI_QIO_MODE (BIT(24)) +#define SPI_DIO_MODE (BIT(23)) +#define SPI_TWO_BYTE_STATUS_EN (BIT(22)) //From previous SDK +#define SPI_WP_REG (BIT(21)) //From previous SDK +#define SPI_QOUT_MODE (BIT(20)) +#define SPI_SHARE_BUS (BIT(19)) //From previous SDK +#define SPI_HOLD_MODE (BIT(18)) //From previous SDK +#define SPI_ENABLE_AHB (BIT(17)) //From previous SDK +#define SPI_SST_AAI (BIT(16)) //From previous SDK +#define SPI_RESANDRES (BIT(15)) //From previous SDK +#define SPI_DOUT_MODE (BIT(14)) +#define SPI_FASTRD_MODE (BIT(13)) + +#define SPI_CTRL1(i) (REG_SPI_BASE (i) + 0xC) //From previous SDK. Removed _FLASH_ from name to match other registers. +#define SPI_CS_HOLD_DELAY 0x0000000F //Espressif BBS +#define SPI_CS_HOLD_DELAY_S 28 //Espressif BBS +#define SPI_CS_HOLD_DELAY_RES 0x00000FFF //Espressif BBS +#define SPI_CS_HOLD_DELAY_RES_S 16 //Espressif BBS +#define SPI_BUS_TIMER_LIMIT 0x0000FFFF //From previous SDK +#define SPI_BUS_TIMER_LIMIT_S 0 //From previous SDK + + +#define SPI_RD_STATUS(i) (REG_SPI_BASE(i) + 0x10) +#define SPI_STATUS_EXT 0x000000FF //From previous SDK +#define SPI_STATUS_EXT_S 24 //From previous SDK +#define SPI_WB_MODE 0x000000FF //From previous SDK +#define SPI_WB_MODE_S 16 //From previous SDK +#define SPI_FLASH_STATUS_PRO_FLAG (BIT(7)) //From previous SDK +#define SPI_FLASH_TOP_BOT_PRO_FLAG (BIT(5)) //From previous SDK +#define SPI_FLASH_BP2 (BIT(4)) //From previous SDK +#define SPI_FLASH_BP1 (BIT(3)) //From previous SDK +#define SPI_FLASH_BP0 (BIT(2)) //From previous SDK +#define SPI_FLASH_WRENABLE_FLAG (BIT(1)) //From previous SDK +#define SPI_FLASH_BUSY_FLAG (BIT(0)) //From previous SDK + +#define SPI_CTRL2(i) (REG_SPI_BASE(i) + 0x14) +#define SPI_CS_DELAY_NUM 0x0000000F +#define SPI_CS_DELAY_NUM_S 28 +#define SPI_CS_DELAY_MODE 0x00000003 +#define SPI_CS_DELAY_MODE_S 26 +#define SPI_MOSI_DELAY_NUM 0x00000007 +#define SPI_MOSI_DELAY_NUM_S 23 +#define SPI_MOSI_DELAY_MODE 0x00000003 //mode 0 : posedge; data set at positive edge of clk + //mode 1 : negedge + 1 cycle delay, only if freq<10MHz ; data set at negitive edge of clk + //mode 2 : Do not use this mode. +#define SPI_MOSI_DELAY_MODE_S 21 +#define SPI_MISO_DELAY_NUM 0x00000007 +#define SPI_MISO_DELAY_NUM_S 18 +#define SPI_MISO_DELAY_MODE 0x00000003 +#define SPI_MISO_DELAY_MODE_S 16 +#define SPI_CK_OUT_HIGH_MODE 0x0000000F +#define SPI_CK_OUT_HIGH_MODE_S 12 +#define SPI_CK_OUT_LOW_MODE 0x0000000F +#define SPI_CK_OUT_LOW_MODE_S 8 +#define SPI_HOLD_TIME 0x0000000F +#define SPI_HOLD_TIME_S 4 +#define SPI_SETUP_TIME 0x0000000F +#define SPI_SETUP_TIME_S 0 + +#define SPI_CLOCK(i) (REG_SPI_BASE(i) + 0x18) +#define SPI_CLK_EQU_SYSCLK (BIT(31)) +#define SPI_CLKDIV_PRE 0x00001FFF +#define SPI_CLKDIV_PRE_S 18 +#define SPI_CLKCNT_N 0x0000003F +#define SPI_CLKCNT_N_S 12 +#define SPI_CLKCNT_H 0x0000003F +#define SPI_CLKCNT_H_S 6 +#define SPI_CLKCNT_L 0x0000003F +#define SPI_CLKCNT_L_S 0 + +#define SPI_USER(i) (REG_SPI_BASE(i) + 0x1C) +#define SPI_USR_COMMAND (BIT(31)) +#define SPI_USR_ADDR (BIT(30)) +#define SPI_USR_DUMMY (BIT(29)) +#define SPI_USR_MISO (BIT(28)) +#define SPI_USR_MOSI (BIT(27)) +#define SPI_USR_DUMMY_IDLE (BIT(26)) //From previous SDK +#define SPI_USR_MOSI_HIGHPART (BIT(25)) +#define SPI_USR_MISO_HIGHPART (BIT(24)) +#define SPI_USR_PREP_HOLD (BIT(23)) //From previous SDK +#define SPI_USR_CMD_HOLD (BIT(22)) //From previous SDK +#define SPI_USR_ADDR_HOLD (BIT(21)) //From previous SDK +#define SPI_USR_DUMMY_HOLD (BIT(20)) //From previous SDK +#define SPI_USR_DIN_HOLD (BIT(19)) //From previous SDK +#define SPI_USR_DOUT_HOLD (BIT(18)) //From previous SDK +#define SPI_USR_HOLD_POL (BIT(17)) //From previous SDK +#define SPI_SIO (BIT(16)) +#define SPI_FWRITE_QIO (BIT(15)) +#define SPI_FWRITE_DIO (BIT(14)) +#define SPI_FWRITE_QUAD (BIT(13)) +#define SPI_FWRITE_DUAL (BIT(12)) +#define SPI_WR_BYTE_ORDER (BIT(11)) +#define SPI_RD_BYTE_ORDER (BIT(10)) +#define SPI_AHB_ENDIAN_MODE 0x00000003 //From previous SDK +#define SPI_AHB_ENDIAN_MODE_S 8 //From previous SDK +#define SPI_CK_OUT_EDGE (BIT(7)) +#define SPI_CK_I_EDGE (BIT(6)) +#define SPI_CS_SETUP (BIT(5)) +#define SPI_CS_HOLD (BIT(4)) +#define SPI_AHB_USR_COMMAND (BIT(3)) //From previous SDK +#define SPI_FLASH_MODE (BIT(2)) +#define SPI_AHB_USR_COMMAND_4BYTE (BIT(1)) //From previous SDK +#define SPI_DOUTDIN (BIT(0)) //From previous SDK + +//AHB = http://en.wikipedia.org/wiki/Advanced_Microcontroller_Bus_Architecture ? + + +#define SPI_USER1(i) (REG_SPI_BASE(i) + 0x20) +#define SPI_USR_ADDR_BITLEN 0x0000003F +#define SPI_USR_ADDR_BITLEN_S 26 +#define SPI_USR_MOSI_BITLEN 0x000001FF +#define SPI_USR_MOSI_BITLEN_S 17 +#define SPI_USR_MISO_BITLEN 0x000001FF +#define SPI_USR_MISO_BITLEN_S 8 +#define SPI_USR_DUMMY_CYCLELEN 0x000000FF +#define SPI_USR_DUMMY_CYCLELEN_S 0 + +#define SPI_USER2(i) (REG_SPI_BASE(i) + 0x24) +#define SPI_USR_COMMAND_BITLEN 0x0000000F +#define SPI_USR_COMMAND_BITLEN_S 28 +#define SPI_USR_COMMAND_VALUE 0x0000FFFF +#define SPI_USR_COMMAND_VALUE_S 0 + +#define SPI_WR_STATUS(i) (REG_SPI_BASE(i) + 0x28) + //previously defined as SPI_FLASH_USER3. No further info available. + +#define SPI_PIN(i) (REG_SPI_BASE(i) + 0x2C) +#define SPI_IDLE_EDGE (BIT(29)) +#define SPI_CS2_DIS (BIT(2)) +#define SPI_CS1_DIS (BIT(1)) +#define SPI_CS0_DIS (BIT(0)) + +#define SPI_SLAVE(i) (REG_SPI_BASE(i) + 0x30) +#define SPI_SYNC_RESET (BIT(31)) +#define SPI_SLAVE_MODE (BIT(30)) +#define SPI_SLV_WR_RD_BUF_EN (BIT(29)) +#define SPI_SLV_WR_RD_STA_EN (BIT(28)) +#define SPI_SLV_CMD_DEFINE (BIT(27)) +#define SPI_TRANS_CNT 0x0000000F +#define SPI_TRANS_CNT_S 23 +#define SPI_SLV_LAST_STATE 0x00000007 //From previous SDK +#define SPI_SLV_LAST_STATE_S 20 //From previous SDK +#define SPI_SLV_LAST_COMMAND 0x00000007 //From previous SDK +#define SPI_SLV_LAST_COMMAND_S 17 //From previous SDK +#define SPI_CS_I_MODE 0x00000003 //From previous SDK +#define SPI_CS_I_MODE_S 10 //From previous SDK +#define SPI_TRANS_DONE_EN (BIT(9)) +#define SPI_SLV_WR_STA_DONE_EN (BIT(8)) +#define SPI_SLV_RD_STA_DONE_EN (BIT(7)) +#define SPI_SLV_WR_BUF_DONE_EN (BIT(6)) +#define SPI_SLV_RD_BUF_DONE_EN (BIT(5)) +#define SLV_SPI_INT_EN 0x0000001f +#define SLV_SPI_INT_EN_S 5 +#define SPI_TRANS_DONE (BIT(4)) +#define SPI_SLV_WR_STA_DONE (BIT(3)) +#define SPI_SLV_RD_STA_DONE (BIT(2)) +#define SPI_SLV_WR_BUF_DONE (BIT(1)) +#define SPI_SLV_RD_BUF_DONE (BIT(0)) + +#define SPI_SLAVE1(i) (REG_SPI_BASE(i) + 0x34) +#define SPI_SLV_STATUS_BITLEN 0x0000001F +#define SPI_SLV_STATUS_BITLEN_S 27 +#define SPI_SLV_STATUS_FAST_EN (BIT(26)) //From previous SDK +#define SPI_SLV_STATUS_READBACK (BIT(25)) //From previous SDK +#define SPI_SLV_BUF_BITLEN 0x000001FF +#define SPI_SLV_BUF_BITLEN_S 16 +#define SPI_SLV_RD_ADDR_BITLEN 0x0000003F +#define SPI_SLV_RD_ADDR_BITLEN_S 10 +#define SPI_SLV_WR_ADDR_BITLEN 0x0000003F +#define SPI_SLV_WR_ADDR_BITLEN_S 4 +#define SPI_SLV_WRSTA_DUMMY_EN (BIT(3)) +#define SPI_SLV_RDSTA_DUMMY_EN (BIT(2)) +#define SPI_SLV_WRBUF_DUMMY_EN (BIT(1)) +#define SPI_SLV_RDBUF_DUMMY_EN (BIT(0)) + + + +#define SPI_SLAVE2(i) (REG_SPI_BASE(i) + 0x38) +#define SPI_SLV_WRBUF_DUMMY_CYCLELEN 0X000000FF +#define SPI_SLV_WRBUF_DUMMY_CYCLELEN_S 24 +#define SPI_SLV_RDBUF_DUMMY_CYCLELEN 0X000000FF +#define SPI_SLV_RDBUF_DUMMY_CYCLELEN_S 16 +#define SPI_SLV_WRSTR_DUMMY_CYCLELEN 0X000000FF +#define SPI_SLV_WRSTR_DUMMY_CYCLELEN_S 8 +#define SPI_SLV_RDSTR_DUMMY_CYCLELEN 0x000000FF +#define SPI_SLV_RDSTR_DUMMY_CYCLELEN_S 0 + +#define SPI_SLAVE3(i) (REG_SPI_BASE(i) + 0x3C) +#define SPI_SLV_WRSTA_CMD_VALUE 0x000000FF +#define SPI_SLV_WRSTA_CMD_VALUE_S 24 +#define SPI_SLV_RDSTA_CMD_VALUE 0x000000FF +#define SPI_SLV_RDSTA_CMD_VALUE_S 16 +#define SPI_SLV_WRBUF_CMD_VALUE 0x000000FF +#define SPI_SLV_WRBUF_CMD_VALUE_S 8 +#define SPI_SLV_RDBUF_CMD_VALUE 0x000000FF +#define SPI_SLV_RDBUF_CMD_VALUE_S 0 + +//Previous SDKs referred to these following registers as SPI_C0 etc. + +#define SPI_W0(i) (REG_SPI_BASE(i) +0x40) +#define SPI_W1(i) (REG_SPI_BASE(i) +0x44) +#define SPI_W2(i) (REG_SPI_BASE(i) +0x48) +#define SPI_W3(i) (REG_SPI_BASE(i) +0x4C) +#define SPI_W4(i) (REG_SPI_BASE(i) +0x50) +#define SPI_W5(i) (REG_SPI_BASE(i) +0x54) +#define SPI_W6(i) (REG_SPI_BASE(i) +0x58) +#define SPI_W7(i) (REG_SPI_BASE(i) +0x5C) +#define SPI_W8(i) (REG_SPI_BASE(i) +0x60) +#define SPI_W9(i) (REG_SPI_BASE(i) +0x64) +#define SPI_W10(i) (REG_SPI_BASE(i) +0x68) +#define SPI_W11(i) (REG_SPI_BASE(i) +0x6C) +#define SPI_W12(i) (REG_SPI_BASE(i) +0x70) +#define SPI_W13(i) (REG_SPI_BASE(i) +0x74) +#define SPI_W14(i) (REG_SPI_BASE(i) +0x78) +#define SPI_W15(i) (REG_SPI_BASE(i) +0x7C) + + // +0x80 to +0xBC could be SPI_W16 through SPI_W31? + + // +0xC0 to +0xEC not currently defined. + +#define SPI_EXT0(i) (REG_SPI_BASE(i) + 0xF0) //From previous SDK. Removed _FLASH_ from name to match other registers. +#define SPI_T_PP_ENA (BIT(31)) //From previous SDK +#define SPI_T_PP_SHIFT 0x0000000F //From previous SDK +#define SPI_T_PP_SHIFT_S 16 //From previous SDK +#define SPI_T_PP_TIME 0x00000FFF //From previous SDK +#define SPI_T_PP_TIME_S 0 //From previous SDK + +#define SPI_EXT1(i) (REG_SPI_BASE(i) + 0xF4) //From previous SDK. Removed _FLASH_ from name to match other registers. +#define SPI_T_ERASE_ENA (BIT(31)) //From previous SDK +#define SPI_T_ERASE_SHIFT 0x0000000F //From previous SDK +#define SPI_T_ERASE_SHIFT_S 16 //From previous SDK +#define SPI_T_ERASE_TIME 0x00000FFF //From previous SDK +#define SPI_T_ERASE_TIME_S 0 //From previous SDK + +#define SPI_EXT2(i) (REG_SPI_BASE(i) + 0xF8) //From previous SDK. Removed _FLASH_ from name to match other registers. +#define SPI_ST 0x00000007 //From previous SDK +#define SPI_ST_S 0 //From previous SDK + +#define SPI_EXT3(i) (REG_SPI_BASE(i) + 0xFC) +#define SPI_INT_HOLD_ENA 0x00000003 +#define SPI_INT_HOLD_ENA_S 0 +#endif // SPI_REGISTER_H_INCLUDED diff --git a/esp8266/modmachine.c b/esp8266/modmachine.c index b3a42618e5..624ce2ac56 100644 --- a/esp8266/modmachine.c +++ b/esp8266/modmachine.c @@ -252,6 +252,7 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&pyb_uart_type) }, { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&machine_i2c_type) }, { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&pyb_spi_type) }, + { MP_ROM_QSTR(MP_QSTR_HSPI), MP_ROM_PTR(&pyb_hspi_type) }, // wake abilities { MP_ROM_QSTR(MP_QSTR_DEEPSLEEP), MP_ROM_INT(MACHINE_WAKE_DEEPSLEEP) }, diff --git a/esp8266/modpyb.h b/esp8266/modpyb.h index dc399ad819..0eec556b15 100644 --- a/esp8266/modpyb.h +++ b/esp8266/modpyb.h @@ -10,6 +10,7 @@ extern const mp_obj_type_t pyb_rtc_type; extern const mp_obj_type_t pyb_uart_type; extern const mp_obj_type_t pyb_i2c_type; extern const mp_obj_type_t pyb_spi_type; +extern const mp_obj_type_t pyb_hspi_type; MP_DECLARE_CONST_FUN_OBJ(pyb_info_obj); diff --git a/esp8266/modpybhspi.c b/esp8266/modpybhspi.c new file mode 100644 index 0000000000..ad78c83fd8 --- /dev/null +++ b/esp8266/modpybhspi.c @@ -0,0 +1,258 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "ets_sys.h" +#include "etshal.h" +#include "ets_alt_task.h" + +#include "py/runtime.h" +#include "py/stream.h" +#include "py/mphal.h" + +#include "hspi.h" + + +typedef struct _pyb_hspi_obj_t { + mp_obj_base_t base; + uint32_t baudrate; + uint8_t polarity; + uint8_t phase; +} pyb_hspi_obj_t; + + +/******************************************************************************/ +// MicroPython bindings for HSPI + +STATIC void pyb_hspi_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + pyb_hspi_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_printf(print, "HSPI(baudrate=%u, polarity=%u, phase=%u)", + self->baudrate, self->polarity, self->phase); +} + +STATIC void pyb_hspi_init_helper(pyb_hspi_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_baudrate, ARG_polarity, ARG_phase }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_baudrate, MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_polarity, MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_phase, MP_ARG_INT, {.u_int = -1} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), + allowed_args, args); + + if (args[ARG_baudrate].u_int != -1) { + self->baudrate = args[ARG_baudrate].u_int; + } + if (args[ARG_polarity].u_int != -1) { + self->polarity = args[ARG_polarity].u_int; + } + if (args[ARG_phase].u_int != -1) { + self->phase = args[ARG_phase].u_int; + } + if (self->baudrate == 80000000L) { + // Special case for full speed. + spi_init_gpio(HSPI, SPI_CLK_80MHZ_NODIV); + spi_clock(HSPI, 0, 0); + } else if (self->baudrate > 40000000L) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, + "impossible baudrate")); + } else { + uint32_t divider = 40000000L / self->baudrate; + uint16_t prediv = MIN(divider, SPI_CLKDIV_PRE + 1); + uint16_t cntdiv = (divider / prediv) * 2; // cntdiv has to be even + if (cntdiv > SPI_CLKCNT_N + 1 || cntdiv == 0 || prediv == 0) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, + "impossible baudrate")); + } + self->baudrate = 80000000L / (prediv * cntdiv); + spi_init_gpio(HSPI, SPI_CLK_USE_DIV); + spi_clock(HSPI, prediv, cntdiv); + } + // TODO: Make the byte order configurable too (discuss param names) + spi_tx_byte_order(HSPI, SPI_BYTE_ORDER_HIGH_TO_LOW); + spi_rx_byte_order(HSPI, SPI_BYTE_ORDER_HIGH_TO_LOW); + CLEAR_PERI_REG_MASK(SPI_USER(HSPI), SPI_FLASH_MODE | SPI_USR_MISO | + SPI_USR_ADDR | SPI_USR_COMMAND | SPI_USR_DUMMY); + // Clear Dual or Quad lines transmission mode + CLEAR_PERI_REG_MASK(SPI_CTRL(HSPI), SPI_QIO_MODE | SPI_DIO_MODE | + SPI_DOUT_MODE | SPI_QOUT_MODE); + spi_mode(HSPI, self->phase, self->polarity); +} + +STATIC mp_obj_t pyb_hspi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 0, MP_OBJ_FUN_ARGS_MAX, true); + pyb_hspi_obj_t *self = m_new_obj(pyb_hspi_obj_t); + self->base.type = &pyb_hspi_type; + // set defaults + self->baudrate = 80000000L; + self->polarity = 0; + self->phase = 0; + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); + pyb_hspi_init_helper(self, n_args, args, &kw_args); + return MP_OBJ_FROM_PTR(self); +} + +STATIC mp_obj_t pyb_hspi_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { + pyb_hspi_init_helper(args[0], n_args - 1, args + 1, kw_args); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(pyb_hspi_init_obj, 1, pyb_hspi_init); + + +STATIC mp_obj_t pyb_hspi_read(size_t n_args, const mp_obj_t *args) { + vstr_t dest_buf; + vstr_init_len(&dest_buf, mp_obj_get_int(args[1])); + uint8_t write_byte = 0; + if (n_args == 3) { + write_byte = mp_obj_get_int(args[2]); + } + // Process data in chunks, let the pending tasks run in between + size_t chunk_size = 1024; // TODO this should depend on baudrate + size_t count = dest_buf.len / chunk_size; + size_t i = 0; + for (size_t j = 0; j < count; ++j) { + for (size_t k = 0; k < chunk_size; ++k) { + ((uint8_t*)dest_buf.buf)[i] = spi_transaction(HSPI, 0, 0, 0, 0, 8, + (uint32_t)write_byte, 8, 0); + ++i; + } + ets_loop_iter(); + } + while (i < dest_buf.len) { + ((uint8_t*)dest_buf.buf)[i] = spi_transaction(HSPI, 0, 0, 0, 0, 8, + (uint32_t)write_byte, 8, 0); + ++i; + } + return mp_obj_new_str_from_vstr(&mp_type_bytes, &dest_buf); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_hspi_read_obj, 2, 3, pyb_hspi_read); + + +STATIC mp_obj_t pyb_hspi_readinto(size_t n_args, const mp_obj_t *args) { + mp_buffer_info_t dest_buf; + mp_get_buffer_raise(args[1], &dest_buf, MP_BUFFER_WRITE); + uint8_t write_byte = 0; + if (n_args == 3) { + write_byte = mp_obj_get_int(args[2]); + } + + size_t chunk_size = 1024; + size_t count = dest_buf.len / chunk_size; + size_t i = 0; + for (size_t j = 0; j < count; ++j) { + for (size_t k = 0; k < chunk_size; ++k) { + ((uint8_t*)dest_buf.buf)[i] = spi_transaction(HSPI, 0, 0, 0, 0, 8, + (uint32_t)write_byte, 8, 0); + ++i; + } + ets_loop_iter(); + } + while (i < dest_buf.len) { + ((uint8_t*)dest_buf.buf)[i] = spi_transaction(HSPI, 0, 0, 0, 0, 8, + (uint32_t)write_byte, 8, 0); + ++i; + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_hspi_readinto_obj, 2, 3, pyb_hspi_readinto); + + +STATIC mp_obj_t pyb_hspi_write(mp_obj_t self_in, mp_obj_t wr_buf_in) { + mp_buffer_info_t src_buf; + mp_get_buffer_raise(wr_buf_in, &src_buf, MP_BUFFER_READ); + + size_t chunk_size = 1024; + size_t count = src_buf.len / chunk_size; + size_t i = 0; + for (size_t j = 0; j < count; ++j) { + for (size_t k = 0; k < chunk_size; ++k) { + spi_tx8fast(HSPI, ((const uint8_t*)src_buf.buf)[i]); + ++i; + } + ets_loop_iter(); + } + while (i < src_buf.len) { + spi_tx8fast(HSPI, ((const uint8_t*)src_buf.buf)[i]); + ++i; + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(pyb_hspi_write_obj, pyb_hspi_write); + + +STATIC mp_obj_t pyb_hspi_write_readinto(mp_obj_t self_in, mp_obj_t wr_buf_in, mp_obj_t rd_buf_in) { + mp_buffer_info_t src_buf; + mp_get_buffer_raise(wr_buf_in, &src_buf, MP_BUFFER_READ); + mp_buffer_info_t dest_buf; + mp_get_buffer_raise(rd_buf_in, &dest_buf, MP_BUFFER_WRITE); + if (src_buf.len != dest_buf.len) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + "buffers must be the same length")); + } + + size_t chunk_size = 1024; + size_t count = src_buf.len / chunk_size; + size_t i = 0; + for (size_t j = 0; j < count; ++j) { + for (size_t k = 0; k < chunk_size; ++k) { + ((uint8_t*)dest_buf.buf)[i] = spi_transaction(HSPI, 0, 0, 0, 0, 8, + (uint32_t)(((const uint8_t*)src_buf.buf)[i]), 8, 0); + ++i; + } + ets_loop_iter(); + } + while (i < src_buf.len) { + ((uint8_t*)dest_buf.buf)[i] = spi_transaction(HSPI, 0, 0, 0, 0, 8, + (uint32_t)(((const uint8_t*)src_buf.buf)[i]), 8, 0); + ++i; + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_3(pyb_hspi_write_readinto_obj, pyb_hspi_write_readinto); + + +STATIC const mp_rom_map_elem_t pyb_hspi_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&pyb_hspi_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&pyb_hspi_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&pyb_hspi_readinto_obj) }, + { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&pyb_hspi_write_obj) }, + { MP_ROM_QSTR(MP_QSTR_write_readinto), MP_ROM_PTR(&pyb_hspi_write_readinto_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(pyb_hspi_locals_dict, pyb_hspi_locals_dict_table); + +const mp_obj_type_t pyb_hspi_type = { + { &mp_type_type }, + .name = MP_QSTR_HSPI, + .print = pyb_hspi_print, + .make_new = pyb_hspi_make_new, + .locals_dict = (mp_obj_dict_t*)&pyb_hspi_locals_dict, +}; From d076fae2194fc1b1cacc1c6d09012baa12ee93a5 Mon Sep 17 00:00:00 2001 From: Radomir Dopieralski Date: Fri, 19 Aug 2016 18:55:07 +0200 Subject: [PATCH 037/129] esp8266/modmachinespi: Add a factory method for SoftSPI/HSPI --- esp8266/Makefile | 1 + esp8266/esp8266.ld | 1 + esp8266/modmachine.c | 3 +- esp8266/modmachinespi.c | 71 +++++++++++++++++++++++++++++++++++++++++ esp8266/modpyb.h | 1 + esp8266/modpybhspi.c | 2 +- esp8266/modpybspi.c | 4 +-- 7 files changed, 79 insertions(+), 4 deletions(-) create mode 100644 esp8266/modmachinespi.c diff --git a/esp8266/Makefile b/esp8266/Makefile index 22591f209b..0b498602f2 100644 --- a/esp8266/Makefile +++ b/esp8266/Makefile @@ -78,6 +78,7 @@ SRC_C = \ modpybrtc.c \ modpybadc.c \ modpybuart.c \ + modmachinespi.c \ modpybspi.c \ modpybhspi.c \ modesp.c \ diff --git a/esp8266/esp8266.ld b/esp8266/esp8266.ld index 6c89858070..dec3bf5a30 100644 --- a/esp8266/esp8266.ld +++ b/esp8266/esp8266.ld @@ -141,6 +141,7 @@ SECTIONS *modpybadc.o(.literal*, .text*) *modpybuart.o(.literal*, .text*) *modpybi2c.o(.literal*, .text*) + *modmachinespi.o(.literal*, .text*) *modpybspi.o(.literal*, .text*) *modpybhspi.o(.literal*, .text*) *hspi.o(.literal*, .text*) diff --git a/esp8266/modmachine.c b/esp8266/modmachine.c index 624ce2ac56..7672834aac 100644 --- a/esp8266/modmachine.c +++ b/esp8266/modmachine.c @@ -251,8 +251,9 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_ADC), MP_ROM_PTR(&pyb_adc_type) }, { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&pyb_uart_type) }, { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&machine_i2c_type) }, - { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&pyb_spi_type) }, + { MP_ROM_QSTR(MP_QSTR_SoftSPI), MP_ROM_PTR(&pyb_spi_type) }, { MP_ROM_QSTR(MP_QSTR_HSPI), MP_ROM_PTR(&pyb_hspi_type) }, + { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&machine_spi_type) }, // wake abilities { MP_ROM_QSTR(MP_QSTR_DEEPSLEEP), MP_ROM_INT(MACHINE_WAKE_DEEPSLEEP) }, diff --git a/esp8266/modmachinespi.c b/esp8266/modmachinespi.c new file mode 100644 index 0000000000..1c6a373698 --- /dev/null +++ b/esp8266/modmachinespi.c @@ -0,0 +1,71 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "ets_sys.h" +#include "etshal.h" +#include "ets_alt_task.h" + +#include "py/runtime.h" +#include "py/stream.h" +#include "py/mphal.h" + + +mp_obj_t pyb_spi_make_new(const mp_obj_type_t *type, size_t n_args, + size_t n_kw, const mp_obj_t *args); +mp_obj_t pyb_hspi_make_new(const mp_obj_type_t *type, size_t n_args, + size_t n_kw, const mp_obj_t *args); + + +STATIC mp_obj_t machine_spi_make_new(const mp_obj_type_t *type, size_t n_args, + size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true); + switch (mp_obj_get_int(args[0])) { + case -1: + return pyb_spi_make_new(type, n_args - 1, n_kw, args + 1); + case 0: + return pyb_hspi_make_new(type, n_args - 1, n_kw, args + 1); + default: + nlr_raise(mp_obj_new_exception_msg_varg( + &mp_type_ValueError, "no such SPI peripheral")); + } +} + + +STATIC const mp_rom_map_elem_t machine_spi_locals_dict_table[] = {}; + +STATIC MP_DEFINE_CONST_DICT(machine_spi_locals_dict, + machine_spi_locals_dict_table); + +const mp_obj_type_t machine_spi_type = { + { &mp_type_type }, + .name = MP_QSTR_SPI, + .make_new = machine_spi_make_new, + .locals_dict = (mp_obj_dict_t*)&machine_spi_locals_dict, +}; diff --git a/esp8266/modpyb.h b/esp8266/modpyb.h index 0eec556b15..45d0bb8cfd 100644 --- a/esp8266/modpyb.h +++ b/esp8266/modpyb.h @@ -11,6 +11,7 @@ extern const mp_obj_type_t pyb_uart_type; extern const mp_obj_type_t pyb_i2c_type; extern const mp_obj_type_t pyb_spi_type; extern const mp_obj_type_t pyb_hspi_type; +extern const mp_obj_type_t machine_spi_type; MP_DECLARE_CONST_FUN_OBJ(pyb_info_obj); diff --git a/esp8266/modpybhspi.c b/esp8266/modpybhspi.c index ad78c83fd8..f80fbae00a 100644 --- a/esp8266/modpybhspi.c +++ b/esp8266/modpybhspi.c @@ -106,7 +106,7 @@ STATIC void pyb_hspi_init_helper(pyb_hspi_obj_t *self, size_t n_args, const mp_o spi_mode(HSPI, self->phase, self->polarity); } -STATIC mp_obj_t pyb_hspi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { +mp_obj_t pyb_hspi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { mp_arg_check_num(n_args, n_kw, 0, MP_OBJ_FUN_ARGS_MAX, true); pyb_hspi_obj_t *self = m_new_obj(pyb_hspi_obj_t); self->base.type = &pyb_hspi_type; diff --git a/esp8266/modpybspi.c b/esp8266/modpybspi.c index c2bcc33edc..fafe3b2fa5 100644 --- a/esp8266/modpybspi.c +++ b/esp8266/modpybspi.c @@ -131,7 +131,7 @@ STATIC void pyb_spi_init_helper(pyb_spi_obj_t *self, size_t n_args, const mp_obj mp_hal_pin_input(self->miso); } -STATIC mp_obj_t pyb_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { +mp_obj_t pyb_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { mp_arg_check_num(n_args, n_kw, 0, MP_OBJ_FUN_ARGS_MAX, true); pyb_spi_obj_t *self = m_new_obj(pyb_spi_obj_t); self->base.type = &pyb_spi_type; @@ -215,7 +215,7 @@ STATIC MP_DEFINE_CONST_DICT(pyb_spi_locals_dict, pyb_spi_locals_dict_table); const mp_obj_type_t pyb_spi_type = { { &mp_type_type }, - .name = MP_QSTR_SPI, + .name = MP_QSTR_SoftSPI, .print = pyb_spi_print, .make_new = pyb_spi_make_new, .locals_dict = (mp_obj_dict_t*)&pyb_spi_locals_dict, From f2a21a2489325df88acf14a20a286932ed32d500 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sat, 20 Aug 2016 16:33:04 +0300 Subject: [PATCH 038/129] esp8266/esp_mphal: No longer disable watchdog on startup. Disabling it was an omission from early development stages. --- esp8266/esp_mphal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esp8266/esp_mphal.c b/esp8266/esp_mphal.c index a2710af2e6..06049e3956 100644 --- a/esp8266/esp_mphal.c +++ b/esp8266/esp_mphal.c @@ -46,7 +46,7 @@ void mp_hal_debug_tx_strn_cooked(void *env, const char *str, uint32_t len); const mp_print_t mp_debug_print = {NULL, mp_hal_debug_tx_strn_cooked}; void mp_hal_init(void) { - ets_wdt_disable(); // it's a pain while developing + //ets_wdt_disable(); // it's a pain while developing mp_hal_rtc_init(); uart_init(UART_BIT_RATE_115200, UART_BIT_RATE_115200); } From c6983e3ce0bb9708afabb9fb7cbdf54ba46fb594 Mon Sep 17 00:00:00 2001 From: Dave Hylands Date: Thu, 18 Aug 2016 20:47:49 -0700 Subject: [PATCH 039/129] stmhal: Fix timer capture/compare interrupt handling for TIM1 and TIM8. It turns out that TIM1 and TIM8 have their own Capture/Compare interrupt vector. For all of the other timers, the capture/compare interrupt vector is the same as the update vector. So we need to add handlers for these vectors and enable them when using capture/compare callbacks. During testing of this, I also found that passing a channel callback into the channel constructor would not enable interrupts properly. I tested using: ``` >>> pyb.Timer(1, freq=4).channel(1, pyb.Timer.OC_TOGGLE, callback=lambda t: print('.', end='')) ``` I tested the above with channels 1, 4, and 8 --- stmhal/stm32_it.c | 18 ++++++++++++++++++ stmhal/timer.c | 24 ++++++++++++++++++++---- 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/stmhal/stm32_it.c b/stmhal/stm32_it.c index c9af20ce58..d2f8c271c4 100644 --- a/stmhal/stm32_it.c +++ b/stmhal/stm32_it.c @@ -556,6 +556,12 @@ void TIM1_TRG_COM_TIM17_IRQHandler(void) { } #endif +void TIM1_CC_IRQHandler(void) { + IRQ_ENTER(TIM1_CC_IRQn); + timer_irq_handler(1); + IRQ_EXIT(TIM1_CC_IRQn); +} + void TIM2_IRQHandler(void) { IRQ_ENTER(TIM2_IRQn); timer_irq_handler(2); @@ -581,18 +587,23 @@ void TIM5_IRQHandler(void) { IRQ_EXIT(TIM5_IRQn); } +#if defined(TIM6) // STM32F401 doesn't have TIM6 void TIM6_DAC_IRQHandler(void) { IRQ_ENTER(TIM6_DAC_IRQn); timer_irq_handler(6); IRQ_EXIT(TIM6_DAC_IRQn); } +#endif +#if defined(TIM7) // STM32F401 doesn't have TIM7 void TIM7_IRQHandler(void) { IRQ_ENTER(TIM7_IRQn); timer_irq_handler(7); IRQ_EXIT(TIM7_IRQn); } +#endif +#if defined(TIM8) // STM32F401 doesn't have TIM8 void TIM8_BRK_TIM12_IRQHandler(void) { IRQ_ENTER(TIM8_BRK_TIM12_IRQn); timer_irq_handler(12); @@ -614,11 +625,18 @@ void TIM8_UP_IRQHandler(void) { } #endif +void TIM8_CC_IRQHandler(void) { + IRQ_ENTER(TIM8_CC_IRQn); + timer_irq_handler(8); + IRQ_EXIT(TIM8_CC_IRQn); +} + void TIM8_TRG_COM_TIM14_IRQHandler(void) { IRQ_ENTER(TIM8_TRG_COM_TIM14_IRQn); timer_irq_handler(14); IRQ_EXIT(TIM8_TRG_COM_TIM14_IRQn); } +#endif // UART/USART IRQ handlers void USART1_IRQHandler(void) { diff --git a/stmhal/timer.c b/stmhal/timer.c index f1f14f3315..e8b29eb97f 100644 --- a/stmhal/timer.c +++ b/stmhal/timer.c @@ -603,6 +603,13 @@ STATIC mp_obj_t pyb_timer_init_helper(pyb_timer_obj_t *self, mp_uint_t n_args, c // set IRQ priority (if not a special timer) if (self->tim_id != 3 && self->tim_id != 5) { HAL_NVIC_SetPriority(self->irqn, IRQ_PRI_TIMX, IRQ_SUBPRI_TIMX); + if (self->tim_id == 1) { + HAL_NVIC_SetPriority(TIM1_CC_IRQn, IRQ_PRI_TIMX, IRQ_SUBPRI_TIMX); + #if defined(TIM8) + } else if (self->tim_id == 8) { + HAL_NVIC_SetPriority(TIM8_CC_IRQn, IRQ_PRI_TIMX, IRQ_SUBPRI_TIMX); + #endif + } } // init TIM @@ -932,7 +939,7 @@ STATIC mp_obj_t pyb_timer_channel(mp_uint_t n_args, const mp_obj_t *pos_args, mp if (chan->callback == mp_const_none) { HAL_TIM_PWM_Start(&self->tim, TIMER_CHANNEL(chan)); } else { - HAL_TIM_PWM_Start_IT(&self->tim, TIMER_CHANNEL(chan)); + pyb_timer_channel_callback(chan, chan->callback); } // Start the complimentary channel too (if its supported) if (IS_TIM_CCXN_INSTANCE(self->tim.Instance, TIMER_CHANNEL(chan))) { @@ -970,7 +977,7 @@ STATIC mp_obj_t pyb_timer_channel(mp_uint_t n_args, const mp_obj_t *pos_args, mp if (chan->callback == mp_const_none) { HAL_TIM_OC_Start(&self->tim, TIMER_CHANNEL(chan)); } else { - HAL_TIM_OC_Start_IT(&self->tim, TIMER_CHANNEL(chan)); + pyb_timer_channel_callback(chan, chan->callback); } // Start the complimentary channel too (if its supported) if (IS_TIM_CCXN_INSTANCE(self->tim.Instance, TIMER_CHANNEL(chan))) { @@ -997,7 +1004,7 @@ STATIC mp_obj_t pyb_timer_channel(mp_uint_t n_args, const mp_obj_t *pos_args, mp if (chan->callback == mp_const_none) { HAL_TIM_IC_Start(&self->tim, TIMER_CHANNEL(chan)); } else { - HAL_TIM_IC_Start_IT(&self->tim, TIMER_CHANNEL(chan)); + pyb_timer_channel_callback(chan, chan->callback); } break; } @@ -1294,7 +1301,16 @@ STATIC mp_obj_t pyb_timer_channel_callback(mp_obj_t self_in, mp_obj_t callback) self->callback = mp_const_none; } else if (mp_obj_is_callable(callback)) { self->callback = callback; - HAL_NVIC_EnableIRQ(self->timer->irqn); + uint8_t tim_id = self->timer->tim_id; + if (tim_id == 1) { + HAL_NVIC_EnableIRQ(TIM1_CC_IRQn); + #if defined(TIM8) // STM32F401 doesn't have a TIM8 + } else if (tim_id == 8) { + HAL_NVIC_EnableIRQ(TIM8_CC_IRQn); + #endif + } else { + HAL_NVIC_EnableIRQ(self->timer->irqn); + } // start timer, so that it interrupts on overflow switch (self->mode) { case CHANNEL_MODE_PWM_NORMAL: From d2d9dfcd40caafa99177ca36bd3e3faf52ee05b3 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 22 Aug 2016 12:24:49 +1000 Subject: [PATCH 040/129] stmhal: Remove obsolete code for special handling of TIM3 irq settings. TIM3 is no longer special, or at least does not have special IRQ settings. --- stmhal/irq.h | 3 --- stmhal/timer.c | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/stmhal/irq.h b/stmhal/irq.h index f3a8a2cc9e..5a08a7d501 100644 --- a/stmhal/irq.h +++ b/stmhal/irq.h @@ -126,9 +126,6 @@ MP_DECLARE_CONST_FUN_OBJ(pyb_irq_stats_obj); #define IRQ_PRI_OTG_HS 6 #define IRQ_SUBPRI_OTG_HS 0 -#define IRQ_PRI_TIM3 6 -#define IRQ_SUBPRI_TIM3 0 - #define IRQ_PRI_TIM5 6 #define IRQ_SUBPRI_TIM5 0 diff --git a/stmhal/timer.c b/stmhal/timer.c index e8b29eb97f..5727a95b73 100644 --- a/stmhal/timer.c +++ b/stmhal/timer.c @@ -601,7 +601,7 @@ STATIC mp_obj_t pyb_timer_init_helper(pyb_timer_obj_t *self, mp_uint_t n_args, c } // set IRQ priority (if not a special timer) - if (self->tim_id != 3 && self->tim_id != 5) { + if (self->tim_id != 5) { HAL_NVIC_SetPriority(self->irqn, IRQ_PRI_TIMX, IRQ_SUBPRI_TIMX); if (self->tim_id == 1) { HAL_NVIC_SetPriority(TIM1_CC_IRQn, IRQ_PRI_TIMX, IRQ_SUBPRI_TIMX); From 253e1a6f6771c09db742c22a25ab53ffbd68eab2 Mon Sep 17 00:00:00 2001 From: Dave Hylands Date: Fri, 19 Aug 2016 21:09:52 -0700 Subject: [PATCH 041/129] teensy: Fix execution of frozen boot.py and main.py --- teensy/main.c | 4 ++-- teensy/memzip_files/main.py | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/teensy/main.c b/teensy/main.c index 41e445cb59..890ee81493 100644 --- a/teensy/main.c +++ b/teensy/main.c @@ -302,7 +302,7 @@ soft_reset: #endif #if MICROPY_MODULE_FROZEN - pyexec_frozen_module("boot"); + pyexec_frozen_module("boot.py"); #else if (!pyexec_file("/boot.py")) { flash_error(4); @@ -314,7 +314,7 @@ soft_reset: // run main script #if MICROPY_MODULE_FROZEN - pyexec_frozen_module("main"); + pyexec_frozen_module("main.py"); #else { vstr_t *vstr = vstr_new(); diff --git a/teensy/memzip_files/main.py b/teensy/memzip_files/main.py index 4f30f2fc5f..b652377f97 100644 --- a/teensy/memzip_files/main.py +++ b/teensy/memzip_files/main.py @@ -1,3 +1,5 @@ +import pyb + print("Executing main.py") led = pyb.LED(1) From 5a5449d4eb46465e5d47fb20104e13122ea4110b Mon Sep 17 00:00:00 2001 From: Krzysztof Blazewicz Date: Sat, 20 Aug 2016 16:59:53 +0200 Subject: [PATCH 042/129] extmod/modbtree: do CHECK_ERROR after __bt_seq() In `btree_seq()`, when `__bt_seq()` gets called with invalid `flags` argument it will return `RET_ERROR` and it won't initialize `val`. If field `data` of uninitialized `val` is passed to `mp_obj_new_bytes()` it causes a segfault. --- extmod/modbtree.c | 1 + 1 file changed, 1 insertion(+) diff --git a/extmod/modbtree.c b/extmod/modbtree.c index f21e7e4421..ea2ea582c8 100644 --- a/extmod/modbtree.c +++ b/extmod/modbtree.c @@ -133,6 +133,7 @@ STATIC mp_obj_t btree_seq(size_t n_args, const mp_obj_t *args) { } int res = __bt_seq(self->db, &key, &val, flags); + CHECK_ERROR(res); if (res == RET_SPECIAL) { return mp_const_none; } From 656207645485295477411224fdf41cfd4d598a88 Mon Sep 17 00:00:00 2001 From: Krzysztof Blazewicz Date: Sat, 20 Aug 2016 13:45:25 +0200 Subject: [PATCH 043/129] py/stream.c: use mp_obj_get_type in mp_get_stream_raise In current state `mp_get_stream_raise` assumes that `self_in` is an object and always performs a pointer derefence which may cause a segfault. This function shall throw an exception whenever `self_in` does not implement a stream protocol, that includes qstr's and numbers. fixes #2331 --- py/stream.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/py/stream.c b/py/stream.c index 473eb96904..eef9080b7b 100644 --- a/py/stream.c +++ b/py/stream.c @@ -94,8 +94,8 @@ mp_uint_t mp_stream_rw(mp_obj_t stream, void *buf_, mp_uint_t size, int *errcode } const mp_stream_p_t *mp_get_stream_raise(mp_obj_t self_in, int flags) { - mp_obj_base_t *o = (mp_obj_base_t*)MP_OBJ_TO_PTR(self_in); - const mp_stream_p_t *stream_p = o->type->protocol; + mp_obj_type_t *type = mp_obj_get_type(self_in); + const mp_stream_p_t *stream_p = type->protocol; if (stream_p == NULL || ((flags & MP_STREAM_OP_READ) && stream_p->read == NULL) || ((flags & MP_STREAM_OP_WRITE) && stream_p->write == NULL) @@ -167,7 +167,7 @@ STATIC mp_obj_t stream_read_generic(size_t n_args, const mp_obj_t *args, byte fl // TODO what if we have read only half a non-ASCII char? vstr_cut_tail_bytes(&vstr, more_bytes - out_sz); if (out_sz == 0) { - break; + break; } } From 39799f7564d28737fa815a3a5d370c91414998ef Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 18 Jul 2016 18:35:33 +0200 Subject: [PATCH 044/129] extmod/modubinascii: implement binascii.crc32 --- extmod/modubinascii.c | 11 +++++++++++ extmod/modubinascii.h | 2 ++ tests/extmod/ubinascii_crc32.py | 14 ++++++++++++++ 3 files changed, 27 insertions(+) create mode 100644 tests/extmod/ubinascii_crc32.py diff --git a/extmod/modubinascii.c b/extmod/modubinascii.c index 3cceb991f1..dc41d1dc98 100644 --- a/extmod/modubinascii.c +++ b/extmod/modubinascii.c @@ -33,6 +33,7 @@ #include "py/binary.h" #include "extmod/modubinascii.h" +#include "uzlib/tinf.h" mp_obj_t mod_binascii_hexlify(size_t n_args, const mp_obj_t *args) { // Second argument is for an extension to allow a separator to be used @@ -203,6 +204,15 @@ mp_obj_t mod_binascii_b2a_base64(mp_obj_t data) { } MP_DEFINE_CONST_FUN_OBJ_1(mod_binascii_b2a_base64_obj, mod_binascii_b2a_base64); +mp_obj_t mod_binascii_crc32(size_t n_args, const mp_obj_t *args) { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_READ); + uint32_t crc = (n_args > 1) ? mp_obj_get_int(args[1]) : 0; + crc = uzlib_crc32(bufinfo.buf, bufinfo.len, crc ^ 0xffffffff); + return MP_OBJ_NEW_SMALL_INT(crc ^ 0xffffffff); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_binascii_crc32_obj, 1, 2, mod_binascii_crc32); + #if MICROPY_PY_UBINASCII STATIC const mp_rom_map_elem_t mp_module_binascii_globals_table[] = { @@ -211,6 +221,7 @@ STATIC const mp_rom_map_elem_t mp_module_binascii_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_unhexlify), MP_ROM_PTR(&mod_binascii_unhexlify_obj) }, { MP_ROM_QSTR(MP_QSTR_a2b_base64), MP_ROM_PTR(&mod_binascii_a2b_base64_obj) }, { MP_ROM_QSTR(MP_QSTR_b2a_base64), MP_ROM_PTR(&mod_binascii_b2a_base64_obj) }, + { MP_ROM_QSTR(MP_QSTR_crc32), MP_ROM_PTR(&mod_binascii_crc32_obj) }, }; STATIC MP_DEFINE_CONST_DICT(mp_module_binascii_globals, mp_module_binascii_globals_table); diff --git a/extmod/modubinascii.h b/extmod/modubinascii.h index 0f9b82c1cb..71dd8a6936 100644 --- a/extmod/modubinascii.h +++ b/extmod/modubinascii.h @@ -31,10 +31,12 @@ extern mp_obj_t mod_binascii_hexlify(size_t n_args, const mp_obj_t *args); extern mp_obj_t mod_binascii_unhexlify(mp_obj_t data); extern mp_obj_t mod_binascii_a2b_base64(mp_obj_t data); extern mp_obj_t mod_binascii_b2a_base64(mp_obj_t data); +extern mp_obj_t mod_binascii_crc32(size_t n_args, const mp_obj_t *args); MP_DECLARE_CONST_FUN_OBJ(mod_binascii_hexlify_obj); MP_DECLARE_CONST_FUN_OBJ(mod_binascii_unhexlify_obj); MP_DECLARE_CONST_FUN_OBJ(mod_binascii_a2b_base64_obj); MP_DECLARE_CONST_FUN_OBJ(mod_binascii_b2a_base64_obj); +MP_DECLARE_CONST_FUN_OBJ(mod_binascii_crc32_obj); #endif /* MICROPY_EXTMOD_MODUBINASCII */ diff --git a/tests/extmod/ubinascii_crc32.py b/tests/extmod/ubinascii_crc32.py new file mode 100644 index 0000000000..cb86603d53 --- /dev/null +++ b/tests/extmod/ubinascii_crc32.py @@ -0,0 +1,14 @@ +try: + import ubinascii as binascii +except ImportError: + import binascii + +print(hex(binascii.crc32(b'The quick brown fox jumps over the lazy dog'))) +print(hex(binascii.crc32(b'\x00' * 32))) +print(hex(binascii.crc32(b'\xff' * 32))) +print(hex(binascii.crc32(bytes(range(32))))) + +print(hex(binascii.crc32(b' over the lazy dog', binascii.crc32(b'The quick brown fox jumps')))) +print(hex(binascii.crc32(b'\x00' * 16, binascii.crc32(b'\x00' * 16)))) +print(hex(binascii.crc32(b'\xff' * 16, binascii.crc32(b'\xff' * 16)))) +print(hex(binascii.crc32(bytes(range(16, 32)), binascii.crc32(bytes(range(16)))))) From c4283675439d549fac09c5695aa5f8d6c3319dd5 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Wed, 24 Aug 2016 18:28:43 +0300 Subject: [PATCH 045/129] extmod/modubinascii: Make crc32() support configurable. Disable by default, enable in unix port. --- extmod/modubinascii.c | 4 ++++ py/mpconfig.h | 5 +++++ tests/extmod/ubinascii_crc32.py | 6 ++++++ unix/mpconfigport.h | 1 + 4 files changed, 16 insertions(+) diff --git a/extmod/modubinascii.c b/extmod/modubinascii.c index dc41d1dc98..562c754b52 100644 --- a/extmod/modubinascii.c +++ b/extmod/modubinascii.c @@ -204,6 +204,7 @@ mp_obj_t mod_binascii_b2a_base64(mp_obj_t data) { } MP_DEFINE_CONST_FUN_OBJ_1(mod_binascii_b2a_base64_obj, mod_binascii_b2a_base64); +#if MICROPY_PY_UBINASCII_CRC32 mp_obj_t mod_binascii_crc32(size_t n_args, const mp_obj_t *args) { mp_buffer_info_t bufinfo; mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_READ); @@ -212,6 +213,7 @@ mp_obj_t mod_binascii_crc32(size_t n_args, const mp_obj_t *args) { return MP_OBJ_NEW_SMALL_INT(crc ^ 0xffffffff); } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_binascii_crc32_obj, 1, 2, mod_binascii_crc32); +#endif #if MICROPY_PY_UBINASCII @@ -221,7 +223,9 @@ STATIC const mp_rom_map_elem_t mp_module_binascii_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_unhexlify), MP_ROM_PTR(&mod_binascii_unhexlify_obj) }, { MP_ROM_QSTR(MP_QSTR_a2b_base64), MP_ROM_PTR(&mod_binascii_a2b_base64_obj) }, { MP_ROM_QSTR(MP_QSTR_b2a_base64), MP_ROM_PTR(&mod_binascii_b2a_base64_obj) }, + #if MICROPY_PY_UBINASCII_CRC32 { MP_ROM_QSTR(MP_QSTR_crc32), MP_ROM_PTR(&mod_binascii_crc32_obj) }, + #endif }; STATIC MP_DEFINE_CONST_DICT(mp_module_binascii_globals, mp_module_binascii_globals_table); diff --git a/py/mpconfig.h b/py/mpconfig.h index 3808df7430..491a537460 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -887,6 +887,11 @@ typedef double mp_float_t; #define MICROPY_PY_UBINASCII (0) #endif +// Depends on MICROPY_PY_UZLIB +#ifndef MICROPY_PY_UBINASCII_CRC32 +#define MICROPY_PY_UBINASCII_CRC32 (0) +#endif + #ifndef MICROPY_PY_URANDOM #define MICROPY_PY_URANDOM (0) #endif diff --git a/tests/extmod/ubinascii_crc32.py b/tests/extmod/ubinascii_crc32.py index cb86603d53..2c40177518 100644 --- a/tests/extmod/ubinascii_crc32.py +++ b/tests/extmod/ubinascii_crc32.py @@ -2,6 +2,12 @@ try: import ubinascii as binascii except ImportError: import binascii +try: + binascii.crc32 +except AttributeError: + print("SKIP") + import sys + sys.exit() print(hex(binascii.crc32(b'The quick brown fox jumps over the lazy dog'))) print(hex(binascii.crc32(b'\x00' * 32))) diff --git a/unix/mpconfigport.h b/unix/mpconfigport.h index 9845e1ce5f..56cfaa2ac1 100644 --- a/unix/mpconfigport.h +++ b/unix/mpconfigport.h @@ -117,6 +117,7 @@ #define MICROPY_PY_UHASHLIB_SHA1 (1) #endif #define MICROPY_PY_UBINASCII (1) +#define MICROPY_PY_UBINASCII_CRC32 (1) #define MICROPY_PY_URANDOM (1) #ifndef MICROPY_PY_USELECT #define MICROPY_PY_USELECT (1) From 5af6184e7251e44c17714466981c624dc7bd225d Mon Sep 17 00:00:00 2001 From: Matt Brejza Date: Tue, 23 Aug 2016 23:13:03 +0100 Subject: [PATCH 046/129] stmhal: Make ADC channel 16 available on L4 MCUs. --- stmhal/adc.c | 25 ++++++++++++++++++++----- stmhal/boards/make-pins.py | 6 +++++- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/stmhal/adc.c b/stmhal/adc.c index 39f0364078..bcf8956254 100644 --- a/stmhal/adc.c +++ b/stmhal/adc.c @@ -54,7 +54,16 @@ #define ADCx (ADC1) #define ADCx_CLK_ENABLE __ADC1_CLK_ENABLE #define ADC_NUM_CHANNELS (19) -#define ADC_NUM_GPIO_CHANNELS (16) + +#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7) +#define ADC_FIRST_GPIO_CHANNEL (0) +#define ADC_LAST_GPIO_CHANNEL (15) +#elif defined(MCU_SERIES_L4) +#define ADC_FIRST_GPIO_CHANNEL (1) +#define ADC_LAST_GPIO_CHANNEL (16) +#else +#error Unsupported processor +#endif #if defined(STM32F405xx) || defined(STM32F415xx) || \ defined(STM32F407xx) || defined(STM32F417xx) || \ @@ -124,7 +133,7 @@ STATIC void adc_init_single(pyb_obj_adc_t *adc_obj) { return; } - if (adc_obj->channel < ADC_NUM_GPIO_CHANNELS) { + if (ADC_FIRST_GPIO_CHANNEL <= adc_obj->channel && adc_obj->channel <= ADC_LAST_GPIO_CHANNEL) { // Channels 0-16 correspond to real pins. Configure the GPIO pin in // ADC mode. const pin_obj_t *pin = pin_adc1[adc_obj->channel]; @@ -253,8 +262,14 @@ STATIC mp_obj_t adc_make_new(const mp_obj_type_t *type, mp_uint_t n_args, mp_uin if (!is_adcx_channel(channel)) { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "not a valid ADC Channel: %d", channel)); } - if (pin_adc1[channel] == NULL) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "channel %d not available on this board", channel)); + + + if (ADC_FIRST_GPIO_CHANNEL <= channel && channel <= ADC_LAST_GPIO_CHANNEL) { + // these channels correspond to physical GPIO ports so make sure they exist + if (pin_adc1[channel] == NULL) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, + "channel %d not available on this board", channel)); + } } pyb_obj_adc_t *o = m_new_obj(pyb_obj_adc_t); @@ -423,7 +438,7 @@ void adc_init_all(pyb_adc_all_obj_t *adc_all, uint32_t resolution) { "resolution %d not supported", resolution)); } - for (uint32_t channel = 0; channel < ADC_NUM_GPIO_CHANNELS; channel++) { + for (uint32_t channel = ADC_FIRST_GPIO_CHANNEL; channel <= ADC_LAST_GPIO_CHANNEL; ++channel) { // Channels 0-16 correspond to real pins. Configure the GPIO pin in // ADC mode. const pin_obj_t *pin = pin_adc1[channel]; diff --git a/stmhal/boards/make-pins.py b/stmhal/boards/make-pins.py index b7f4842144..ae614877d5 100755 --- a/stmhal/boards/make-pins.py +++ b/stmhal/boards/make-pins.py @@ -303,7 +303,9 @@ class Pins(object): def print_adc(self, adc_num): print(''); print('const pin_obj_t * const pin_adc{:d}[] = {{'.format(adc_num)) - for channel in range(16): + for channel in range(17): + if channel == 16: + print('#if defined(MCU_SERIES_L4)') adc_found = False for named_pin in self.cpu_pins: pin = named_pin.pin() @@ -314,6 +316,8 @@ class Pins(object): break if not adc_found: print(' NULL, // {:d}'.format(channel)) + if channel == 16: + print('#endif') print('};') From 78bc31e29409b5e059de0641fc7df9ed58483187 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 25 Aug 2016 14:06:40 +1000 Subject: [PATCH 047/129] tests/run-tests: Disable thread/stress_heap.py when running on Travis. It has reliability issues and sometimes fails on Travis (reason currently unknown). --- tests/run-tests | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/run-tests b/tests/run-tests index f796f28630..80536f2423 100755 --- a/tests/run-tests +++ b/tests/run-tests @@ -201,6 +201,7 @@ def run_tests(pyb, tests, args): if os.getenv('TRAVIS') == 'true': skip_tests.add('basics/memoryerror.py') skip_tests.add('thread/thread_lock4.py') # has reliability issues + skip_tests.add('thread/stress_heap.py') # has reliability issues if not has_complex: skip_tests.add('float/complex1.py') From d09b6b9aa1c2ed82a4795f5abbc02f50f00927d9 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 25 Aug 2016 14:10:25 +1000 Subject: [PATCH 048/129] esp8266/modpybrtc: Use 64-bit arithmetic when computing alarm expiry. --- esp8266/modpybrtc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esp8266/modpybrtc.c b/esp8266/modpybrtc.c index 9685248034..500b2bc545 100644 --- a/esp8266/modpybrtc.c +++ b/esp8266/modpybrtc.c @@ -212,7 +212,7 @@ STATIC mp_obj_t pyb_rtc_alarm(mp_obj_t self_in, mp_obj_t alarm_id, mp_obj_t time } // set expiry time (in microseconds) - pyb_rtc_alarm0_expiry = pyb_rtc_get_us_since_2000() + mp_obj_get_int(time_in) * 1000; + pyb_rtc_alarm0_expiry = pyb_rtc_get_us_since_2000() + (uint64_t)mp_obj_get_int(time_in) * 1000; return mp_const_none; From a589fa3e0bdb65f9aa9ad30f720bfc93788689e9 Mon Sep 17 00:00:00 2001 From: Dave Hylands Date: Mon, 22 Aug 2016 23:22:04 -0700 Subject: [PATCH 049/129] stmhal: Update pin print to print new constants This updates the print function for machine.Pin to print out the new constants from the Hardware API defintion rather than the legacy definitions. --- stmhal/pin.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/stmhal/pin.c b/stmhal/pin.c index e3ae0be400..9bd4e7a6d9 100644 --- a/stmhal/pin.c +++ b/stmhal/pin.c @@ -199,15 +199,15 @@ STATIC void pin_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t if (mode == GPIO_MODE_INPUT) { mode_qst = MP_QSTR_IN; } else if (mode == GPIO_MODE_OUTPUT_PP) { - mode_qst = MP_QSTR_OUT_PP; + mode_qst = MP_QSTR_OUT; } else if (mode == GPIO_MODE_OUTPUT_OD) { - mode_qst = MP_QSTR_OUT_OD; + mode_qst = MP_QSTR_OPEN_DRAIN; } else { af = true; if (mode == GPIO_MODE_AF_PP) { - mode_qst = MP_QSTR_AF_PP; + mode_qst = MP_QSTR_ALT; } else { - mode_qst = MP_QSTR_AF_OD; + mode_qst = MP_QSTR_ALT_OPEN_DRAIN; } } mp_print_str(print, qstr_str(mode_qst)); From 9897bcaa731d9dfe62cac61b56698799c8e6bac8 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Thu, 25 Aug 2016 15:22:25 +0300 Subject: [PATCH 050/129] lib/utils/stdout_helpers: Fix function signature to match py/mphal.h. --- lib/utils/stdout_helpers.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/utils/stdout_helpers.c b/lib/utils/stdout_helpers.c index 6efe10b92c..5f7a17d320 100644 --- a/lib/utils/stdout_helpers.c +++ b/lib/utils/stdout_helpers.c @@ -11,7 +11,7 @@ // Send "cooked" string of given length, where every occurance of // LF character is replaced with CR LF. -void mp_hal_stdout_tx_strn_cooked(const char *str, mp_uint_t len) { +void mp_hal_stdout_tx_strn_cooked(const char *str, size_t len) { while (len--) { if (*str == '\n') { mp_hal_stdout_tx_strn("\r", 1); From 891479e62a8db32d5a6351e9e3eb9e5dd570ba9c Mon Sep 17 00:00:00 2001 From: Radomir Dopieralski Date: Thu, 25 Aug 2016 10:42:33 +0200 Subject: [PATCH 051/129] esp8266/hspi: Enable duplex operation of hardware SPI Without this, spi.read(1, 0xff) would use 16 clock cycles, first to send 0xff and then to receive one byte, as visible with a logic analyzer. --- esp8266/hspi.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/esp8266/hspi.c b/esp8266/hspi.c index 7315dc8a12..436fb4f6f4 100644 --- a/esp8266/hspi.c +++ b/esp8266/hspi.c @@ -199,7 +199,11 @@ uint32_t spi_transaction(uint8_t spi_no, uint8_t cmd_bits, uint16_t cmd_data, // This is rather inefficient but allows for a very generic function. // CMD ADDR and MOSI are set below to save on an extra if statement. if (din_bits) { - SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MISO); + if (dout_bits) { + SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_DOUTDIN); + } else { + SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MISO); + } } if (dummy_bits) { SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_DUMMY); From b0e2106fb89d108bd0249c85707b800d23d0273f Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Thu, 25 Aug 2016 21:30:20 +0300 Subject: [PATCH 052/129] lib/berkeley-db-1.xx: Update to upstream, fixes MacOSX build. --- lib/berkeley-db-1.xx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/berkeley-db-1.xx b/lib/berkeley-db-1.xx index 78a4787948..dab957dacd 160000 --- a/lib/berkeley-db-1.xx +++ b/lib/berkeley-db-1.xx @@ -1 +1 @@ -Subproject commit 78a4787948bb80cbfafcfd7910f95f61a4dd0d4c +Subproject commit dab957dacddcbf6cbc85d42df62e189e4877bb72 From d29ca28288581ca788e468528ea1680b99eb49e5 Mon Sep 17 00:00:00 2001 From: Radomir Dopieralski Date: Mon, 22 Aug 2016 16:10:34 +0200 Subject: [PATCH 053/129] esp8266/modous: Add os.umount method to unmount a filesystem. This is an object-oriented approach, where uos is only a proxy for the methods on the vfs object. Some internals had to be exposed (the STATIC keyword removed) for this to work. Fixes #2338. --- esp8266/moduos.c | 5 +++++ extmod/fsusermount.c | 2 +- extmod/fsusermount.h | 1 + extmod/vfs_fat.c | 8 ++++++++ 4 files changed, 15 insertions(+), 1 deletion(-) diff --git a/esp8266/moduos.c b/esp8266/moduos.c index af149625d6..bbbf2b6b8b 100644 --- a/esp8266/moduos.c +++ b/esp8266/moduos.c @@ -123,6 +123,10 @@ STATIC mp_obj_t os_rename(mp_obj_t path_old, mp_obj_t path_new) { } STATIC MP_DEFINE_CONST_FUN_OBJ_2(os_rename_obj, os_rename); +STATIC mp_obj_t os_umount(void) { + return vfs_proxy_call(MP_QSTR_umount, 0, NULL); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(os_umount_obj, os_umount); #endif STATIC mp_obj_t os_urandom(mp_obj_t num) { @@ -166,6 +170,7 @@ STATIC const mp_rom_map_elem_t os_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&os_remove_obj) }, { MP_ROM_QSTR(MP_QSTR_rename), MP_ROM_PTR(&os_rename_obj) }, { MP_ROM_QSTR(MP_QSTR_stat), MP_ROM_PTR(&os_stat_obj) }, + { MP_ROM_QSTR(MP_QSTR_umount), MP_ROM_PTR(&os_umount_obj) }, #endif }; diff --git a/extmod/fsusermount.c b/extmod/fsusermount.c index 9ddc98f3dd..cbc1e36220 100644 --- a/extmod/fsusermount.c +++ b/extmod/fsusermount.c @@ -162,7 +162,7 @@ STATIC mp_obj_t fatfs_mount(size_t n_args, const mp_obj_t *pos_args, mp_map_t *k } MP_DEFINE_CONST_FUN_OBJ_KW(fsuser_mount_obj, 2, fatfs_mount); -STATIC mp_obj_t fatfs_umount(mp_obj_t bdev_or_path_in) { +mp_obj_t fatfs_umount(mp_obj_t bdev_or_path_in) { size_t i = 0; if (MP_OBJ_IS_STR(bdev_or_path_in)) { mp_uint_t mnt_len; diff --git a/extmod/fsusermount.h b/extmod/fsusermount.h index a25434b781..e1f26f2ce8 100644 --- a/extmod/fsusermount.h +++ b/extmod/fsusermount.h @@ -55,6 +55,7 @@ typedef struct _fs_user_mount_t { } fs_user_mount_t; fs_user_mount_t *fatfs_mount_mkfs(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args, bool mkfs); +mp_obj_t fatfs_umount(mp_obj_t bdev_or_path_in); MP_DECLARE_CONST_FUN_OBJ(fsuser_mount_obj); MP_DECLARE_CONST_FUN_OBJ(fsuser_umount_obj); diff --git a/extmod/vfs_fat.c b/extmod/vfs_fat.c index a691ee062c..eea075f6b0 100644 --- a/extmod/vfs_fat.c +++ b/extmod/vfs_fat.c @@ -250,6 +250,13 @@ STATIC mp_obj_t fat_vfs_stat(mp_obj_t vfs_in, mp_obj_t path_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_2(fat_vfs_stat_obj, fat_vfs_stat); +// Unmount the filesystem +STATIC mp_obj_t fat_vfs_umount(mp_obj_t vfs_in) { + fatfs_umount(((fs_user_mount_t *)vfs_in)->readblocks[1]); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(fat_vfs_umount_obj, fat_vfs_umount); + STATIC const mp_rom_map_elem_t fat_vfs_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_mkfs), MP_ROM_PTR(&fat_vfs_mkfs_obj) }, { MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&fat_vfs_open_obj) }, @@ -261,6 +268,7 @@ STATIC const mp_rom_map_elem_t fat_vfs_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&fat_vfs_remove_obj) }, { MP_ROM_QSTR(MP_QSTR_rename), MP_ROM_PTR(&fat_vfs_rename_obj) }, { MP_ROM_QSTR(MP_QSTR_stat), MP_ROM_PTR(&fat_vfs_stat_obj) }, + { MP_ROM_QSTR(MP_QSTR_umount), MP_ROM_PTR(&fat_vfs_umount_obj) }, }; STATIC MP_DEFINE_CONST_DICT(fat_vfs_locals_dict, fat_vfs_locals_dict_table); From 5ffe1d8dc07930818bbac6a88bec2aa5bd973402 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 26 Aug 2016 15:35:26 +1000 Subject: [PATCH 054/129] py/gc: Add MICROPY_GC_CONSERVATIVE_CLEAR option to always zero memory. There can be stray pointers in memory blocks that are not properly zero'd after allocation. This patch adds a new config option to always zero all allocated memory (via gc_alloc and gc_realloc) and hence help to eliminate stray pointers. See issue #2195. --- py/gc.c | 10 ++++++++++ py/malloc.c | 3 +++ py/mpconfig.h | 9 +++++++++ 3 files changed, 22 insertions(+) diff --git a/py/gc.c b/py/gc.c index 97868c07f8..7ed53cfc7f 100644 --- a/py/gc.c +++ b/py/gc.c @@ -480,12 +480,17 @@ found: GC_EXIT(); + #if MICROPY_GC_CONSERVATIVE_CLEAR + // be conservative and zero out all the newly allocated blocks + memset((byte*)ret_ptr, 0, (end_block - start_block + 1) * BYTES_PER_BLOCK); + #else // zero out the additional bytes of the newly allocated blocks // This is needed because the blocks may have previously held pointers // to the heap and will not be set to something else if the caller // doesn't actually use the entire block. As such they will continue // to point to the heap and may prevent other blocks from being reclaimed. memset((byte*)ret_ptr + n_bytes, 0, (end_block - start_block + 1) * BYTES_PER_BLOCK - n_bytes); + #endif #if MICROPY_ENABLE_FINALISER if (has_finaliser) { @@ -713,8 +718,13 @@ void *gc_realloc(void *ptr_in, size_t n_bytes, bool allow_move) { GC_EXIT(); + #if MICROPY_GC_CONSERVATIVE_CLEAR + // be conservative and zero out all the newly allocated blocks + memset((byte*)ptr_in + n_blocks * BYTES_PER_BLOCK, 0, (new_blocks - n_blocks) * BYTES_PER_BLOCK); + #else // zero out the additional bytes of the newly allocated blocks (see comment above in gc_alloc) memset((byte*)ptr_in + n_bytes, 0, new_blocks * BYTES_PER_BLOCK - n_bytes); + #endif #if EXTENSIVE_HEAP_PROFILING gc_dump_alloc_table(); diff --git a/py/malloc.c b/py/malloc.c index b0493d9341..f48cb8da4f 100644 --- a/py/malloc.c +++ b/py/malloc.c @@ -117,7 +117,10 @@ void *m_malloc0(size_t num_bytes) { if (ptr == NULL && num_bytes != 0) { return m_malloc_fail(num_bytes); } + // If this config is set then the GC clears all memory, so we don't need to. + #if !MICROPY_GC_CONSERVATIVE_CLEAR memset(ptr, 0, num_bytes); + #endif return ptr; } diff --git a/py/mpconfig.h b/py/mpconfig.h index 491a537460..23591e0da3 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -107,6 +107,15 @@ #define MICROPY_ALLOC_GC_STACK_SIZE (64) #endif +// Be conservative and always clear to zero newly (re)allocated memory in the GC. +// This helps eliminate stray pointers that hold on to memory that's no longer +// used. It decreases performance due to unnecessary memory clearing. +// TODO Do analysis to understand why some memory is not properly cleared and +// find a more efficient way to clear it. +#ifndef MICROPY_GC_CONSERVATIVE_CLEAR +#define MICROPY_GC_CONSERVATIVE_CLEAR (1) +#endif + // Support automatic GC when reaching allocation threshold, // configurable by gc.threshold(). #ifndef MICROPY_GC_ALLOC_THRESHOLD From fc73c9b4b28e903641888a81a76169a929407383 Mon Sep 17 00:00:00 2001 From: Krzysztof Blazewicz Date: Fri, 26 Aug 2016 10:50:37 +0200 Subject: [PATCH 055/129] stmhal/modusocket: set self->nic to MP_OBJ_NULL after socket close This patch makes second and next calls to .close() a no-op. It prevents GC from closing the underlying resource after user already used .close() explicitly. fixes #2355 --- stmhal/modusocket.c | 1 + 1 file changed, 1 insertion(+) diff --git a/stmhal/modusocket.c b/stmhal/modusocket.c index fbd1196446..c0e30ce050 100644 --- a/stmhal/modusocket.c +++ b/stmhal/modusocket.c @@ -83,6 +83,7 @@ STATIC mp_obj_t socket_close(mp_obj_t self_in) { mod_network_socket_obj_t *self = self_in; if (self->nic != MP_OBJ_NULL) { self->nic_type->close(self); + self->nic = MP_OBJ_NULL; } return mp_const_none; } From 24df30c1336fc72ad7dcd5cfc08a5e7f9a1f9808 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 26 Aug 2016 22:28:22 +1000 Subject: [PATCH 056/129] py/compile: Don't compile assert statements when optimisations enabled. As per CPython. --- py/compile.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/py/compile.c b/py/compile.c index df6dab063c..c8b4e5470d 100644 --- a/py/compile.c +++ b/py/compile.c @@ -1200,6 +1200,11 @@ STATIC void compile_nonlocal_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) } STATIC void compile_assert_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { + // with optimisations enabled we don't compile assertions + if (MP_STATE_VM(mp_optimise_value) != 0) { + return; + } + uint l_end = comp_next_label(comp); c_if_cond(comp, pns->nodes[0], true, l_end); EMIT_LOAD_GLOBAL(MP_QSTR_AssertionError); // we load_global instead of load_id, to be consistent with CPython From 3b5affa0d1f7c1e81dd4a48bba2742e8013804da Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 26 Aug 2016 22:29:38 +1000 Subject: [PATCH 057/129] tests/cmdline: Add test for -O option to check optimisation value. --- tests/cmdline/cmd_optimise.py | 4 ++++ tests/cmdline/cmd_optimise.py.exp | 1 + 2 files changed, 5 insertions(+) create mode 100644 tests/cmdline/cmd_optimise.py create mode 100644 tests/cmdline/cmd_optimise.py.exp diff --git a/tests/cmdline/cmd_optimise.py b/tests/cmdline/cmd_optimise.py new file mode 100644 index 0000000000..79d3bb44fd --- /dev/null +++ b/tests/cmdline/cmd_optimise.py @@ -0,0 +1,4 @@ +# cmdline: -O +# test optimisation output +print(__debug__) +assert 0 diff --git a/tests/cmdline/cmd_optimise.py.exp b/tests/cmdline/cmd_optimise.py.exp new file mode 100644 index 0000000000..bc59c12aa1 --- /dev/null +++ b/tests/cmdline/cmd_optimise.py.exp @@ -0,0 +1 @@ +False From fe3cc5bb53198cc1462fb6748137d57a68960933 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 26 Aug 2016 23:42:40 +1000 Subject: [PATCH 058/129] py/modstruct: Use more compact mp_raise_ValueError function. Saves a few bytes of code size. --- py/modstruct.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/py/modstruct.c b/py/modstruct.c index 2016add17e..be0d0110de 100644 --- a/py/modstruct.c +++ b/py/modstruct.c @@ -114,7 +114,7 @@ STATIC mp_obj_t struct_calcsize(mp_obj_t fmt_in) { mp_uint_t align; size_t sz = mp_binary_get_size(fmt_type, *fmt, &align); if (sz == 0) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "unsupported format")); + mp_raise_ValueError("unsupported format"); } while (cnt--) { // Apply alignment @@ -149,7 +149,7 @@ STATIC mp_obj_t struct_unpack_from(size_t n_args, const mp_obj_t *args) { // negative offsets are relative to the end of the buffer offset = bufinfo.len + offset; if (offset < 0) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "buffer too small")); + mp_raise_ValueError("buffer too small"); } } p += offset; @@ -164,7 +164,7 @@ STATIC mp_obj_t struct_unpack_from(size_t n_args, const mp_obj_t *args) { sz = get_fmt_num(&fmt); } if (p + sz > end_p) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "buffer too small")); + mp_raise_ValueError("buffer too small"); } mp_obj_t item; if (*fmt == 's') { @@ -197,7 +197,7 @@ STATIC void struct_pack_into_internal(mp_obj_t fmt_in, byte *p, byte* end_p, siz sz = get_fmt_num(&fmt); } if (p + sz > end_p) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "buffer too small")); + mp_raise_ValueError("buffer too small"); } if (*fmt == 's') { @@ -240,7 +240,7 @@ STATIC mp_obj_t struct_pack_into(size_t n_args, const mp_obj_t *args) { // negative offsets are relative to the end of the buffer offset = (mp_int_t)bufinfo.len + offset; if (offset < 0) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "buffer too small")); + mp_raise_ValueError("buffer too small"); } } byte *p = (byte *)bufinfo.buf; From 26295e04ff878d821ff4fbb9a5d8176906907da5 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 26 Aug 2016 23:45:07 +1000 Subject: [PATCH 059/129] py/emitglue: Use more compact mp_raise_ValueError function. --- py/emitglue.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/py/emitglue.c b/py/emitglue.c index 1b9992b8e1..0b5903092a 100644 --- a/py/emitglue.c +++ b/py/emitglue.c @@ -348,12 +348,10 @@ mp_raw_code_t *mp_raw_code_load(mp_reader_t *reader) { byte header[4]; read_bytes(reader, header, sizeof(header)); if (strncmp((char*)header, "M\x00", 2) != 0) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, - "invalid .mpy file")); + mp_raise_ValueError("invalid .mpy file"); } if (header[2] != MPY_FEATURE_FLAGS || header[3] > mp_small_int_bits()) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, - "incompatible .mpy file")); + mp_raise_ValueError("incompatible .mpy file"); } return load_raw_code(reader); } @@ -559,8 +557,7 @@ STATIC void save_bytecode_qstrs(mp_print_t *print, const byte *ip, const byte *i STATIC void save_raw_code(mp_print_t *print, mp_raw_code_t *rc) { if (rc->kind != MP_CODE_BYTECODE) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, - "can only save bytecode")); + mp_raise_ValueError("can only save bytecode"); } // save bytecode From fea7fe45ea4145fff7afc2f07f461613ad31e781 Mon Sep 17 00:00:00 2001 From: Radomir Dopieralski Date: Fri, 26 Aug 2016 15:22:53 +0200 Subject: [PATCH 060/129] tests/extmod/vfs_fat_ramdisk: Add tests for VFS.umount() Try to un-mount a file system and re-mount it again. --- tests/extmod/vfs_fat_ramdisk.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/extmod/vfs_fat_ramdisk.py b/tests/extmod/vfs_fat_ramdisk.py index 7860d68124..57c8eeba89 100644 --- a/tests/extmod/vfs_fat_ramdisk.py +++ b/tests/extmod/vfs_fat_ramdisk.py @@ -1,5 +1,6 @@ import sys import uos +import uerrno try: uos.VfsFat except AttributeError: @@ -84,3 +85,15 @@ assert vfs.listdir() == ["sub_file.txt"] vfs.chdir("..") print("getcwd:", vfs.getcwd()) + + +vfs.umount() +try: + vfs.listdir() +except OSError as e: + assert e.args[0] == uerrno.ENODEV +else: + raise AssertionError("expected OSError not thrown") + +vfs = uos.VfsFat(bdev, "/ramdisk") +assert vfs.listdir() == ['foo_dir', 'moved-to-root.txt'] From 531217a06b54d612ac49c341a358b3fca1d59985 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 27 Aug 2016 18:31:58 +1000 Subject: [PATCH 061/129] extmod/modframebuf: Fix pixel accessor to return a 1-bit result. --- extmod/modframebuf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extmod/modframebuf.c b/extmod/modframebuf.c index d0ef238075..a1e7c079be 100644 --- a/extmod/modframebuf.c +++ b/extmod/modframebuf.c @@ -83,7 +83,7 @@ STATIC mp_obj_t framebuf1_pixel(size_t n_args, const mp_obj_t *args) { int index = (y / 8) * self->stride + x; if (n_args == 3) { // get - return MP_OBJ_NEW_SMALL_INT(self->buf[index] >> (y & 7)); + return MP_OBJ_NEW_SMALL_INT((self->buf[index] >> (y & 7)) & 1); } else { // set if (mp_obj_get_int(args[3])) { From 581a59a456654e881a228a99f135777e0335f1e1 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 27 Aug 2016 23:21:00 +1000 Subject: [PATCH 062/129] py: Rename struct mp_code_state to mp_code_state_t. Also at _t to mp_exc_stack pre-declaration in struct typedef. --- py/bc.c | 2 +- py/bc.h | 12 ++++++------ py/emitnative.c | 6 +++--- py/objfun.c | 14 +++++++------- py/objgenerator.c | 2 +- py/vm.c | 10 +++++----- 6 files changed, 23 insertions(+), 23 deletions(-) diff --git a/py/bc.c b/py/bc.c index 5cdaa4770d..0d0a0b12f9 100644 --- a/py/bc.c +++ b/py/bc.c @@ -89,7 +89,7 @@ STATIC void dump_args(const mp_obj_t *a, size_t sz) { // - code_state->ip should contain the offset in bytes from the start of // the bytecode chunk to just after n_state and n_exc_stack // - code_state->n_state should be set to the state size (locals plus stack) -void mp_setup_code_state(mp_code_state *code_state, mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, const mp_obj_t *args) { +void mp_setup_code_state(mp_code_state_t *code_state, mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, const mp_obj_t *args) { // This function is pretty complicated. It's main aim is to be efficient in speed and RAM // usage for the common case of positional only args. size_t n_state = code_state->n_state; diff --git a/py/bc.h b/py/bc.h index c2d95bedde..11f5bb632f 100644 --- a/py/bc.h +++ b/py/bc.h @@ -60,7 +60,7 @@ // constN : obj // Exception stack entry -typedef struct _mp_exc_stack { +typedef struct _mp_exc_stack_t { const byte *handler; // bit 0 is saved currently_in_except_block value // bit 1 is whether the opcode was SETUP_WITH or SETUP_FINALLY @@ -69,7 +69,7 @@ typedef struct _mp_exc_stack { mp_obj_base_t *prev_exc; } mp_exc_stack_t; -typedef struct _mp_code_state { +typedef struct _mp_code_state_t { const byte *code_info; const byte *ip; const mp_uint_t *const_table; @@ -85,14 +85,14 @@ typedef struct _mp_code_state { mp_obj_t state[0]; // Variable-length, never accessed by name, only as (void*)(state + n_state) //mp_exc_stack_t exc_state[0]; -} mp_code_state; +} mp_code_state_t; mp_uint_t mp_decode_uint(const byte **ptr); -mp_vm_return_kind_t mp_execute_bytecode(mp_code_state *code_state, volatile mp_obj_t inject_exc); -mp_code_state *mp_obj_fun_bc_prepare_codestate(mp_obj_t func, size_t n_args, size_t n_kw, const mp_obj_t *args); +mp_vm_return_kind_t mp_execute_bytecode(mp_code_state_t *code_state, volatile mp_obj_t inject_exc); +mp_code_state_t *mp_obj_fun_bc_prepare_codestate(mp_obj_t func, size_t n_args, size_t n_kw, const mp_obj_t *args); struct _mp_obj_fun_bc_t; -void mp_setup_code_state(mp_code_state *code_state, struct _mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, const mp_obj_t *args); +void mp_setup_code_state(mp_code_state_t *code_state, struct _mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, const mp_obj_t *args); void mp_bytecode_print(const void *descr, const byte *code, mp_uint_t len, const mp_uint_t *const_table); void mp_bytecode_print2(const byte *code, mp_uint_t len); const byte *mp_bytecode_print_str(const byte *ip); diff --git a/py/emitnative.c b/py/emitnative.c index 9adaabc11c..2cf4711feb 100644 --- a/py/emitnative.c +++ b/py/emitnative.c @@ -628,7 +628,7 @@ STATIC void emit_post_push_reg(emit_t *emit, vtype_kind_t vtype, int reg); STATIC void emit_native_load_fast(emit_t *emit, qstr qst, mp_uint_t local_num); STATIC void emit_native_store_fast(emit_t *emit, qstr qst, mp_uint_t local_num); -#define STATE_START (sizeof(mp_code_state) / sizeof(mp_uint_t)) +#define STATE_START (sizeof(mp_code_state_t) / sizeof(mp_uint_t)) STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) { DEBUG_printf("start_pass(pass=%u, scope=%p)\n", pass, scope); @@ -775,10 +775,10 @@ STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop // set code_state.ip (offset from start of this function to prelude info) // XXX this encoding may change size - ASM_MOV_IMM_TO_LOCAL_USING(emit->as, emit->prelude_offset, offsetof(mp_code_state, ip) / sizeof(mp_uint_t), REG_ARG_1); + ASM_MOV_IMM_TO_LOCAL_USING(emit->as, emit->prelude_offset, offsetof(mp_code_state_t, ip) / sizeof(mp_uint_t), REG_ARG_1); // set code_state.n_state - ASM_MOV_IMM_TO_LOCAL_USING(emit->as, emit->n_state, offsetof(mp_code_state, n_state) / sizeof(mp_uint_t), REG_ARG_1); + ASM_MOV_IMM_TO_LOCAL_USING(emit->as, emit->n_state, offsetof(mp_code_state_t, n_state) / sizeof(mp_uint_t), REG_ARG_1); // put address of code_state into first arg ASM_MOV_LOCAL_ADDR_TO_REG(emit->as, 0, REG_ARG_1); diff --git a/py/objfun.c b/py/objfun.c index 293d06427d..3fd25fb224 100644 --- a/py/objfun.c +++ b/py/objfun.c @@ -165,7 +165,7 @@ STATIC void dump_args(const mp_obj_t *a, mp_uint_t sz) { #define VM_DETECT_STACK_OVERFLOW (0) #if MICROPY_STACKLESS -mp_code_state *mp_obj_fun_bc_prepare_codestate(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { +mp_code_state_t *mp_obj_fun_bc_prepare_codestate(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { MP_STACK_CHECK(); mp_obj_fun_bc_t *self = MP_OBJ_TO_PTR(self_in); @@ -178,8 +178,8 @@ mp_code_state *mp_obj_fun_bc_prepare_codestate(mp_obj_t self_in, size_t n_args, // allocate state for locals and stack size_t state_size = n_state * sizeof(mp_obj_t) + n_exc_stack * sizeof(mp_exc_stack_t); - mp_code_state *code_state; - code_state = m_new_obj_var_maybe(mp_code_state, byte, state_size); + mp_code_state_t *code_state; + code_state = m_new_obj_var_maybe(mp_code_state_t, byte, state_size); if (!code_state) { return NULL; } @@ -220,12 +220,12 @@ STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const // allocate state for locals and stack mp_uint_t state_size = n_state * sizeof(mp_obj_t) + n_exc_stack * sizeof(mp_exc_stack_t); - mp_code_state *code_state = NULL; + mp_code_state_t *code_state = NULL; if (state_size > VM_MAX_STATE_ON_STACK) { - code_state = m_new_obj_var_maybe(mp_code_state, byte, state_size); + code_state = m_new_obj_var_maybe(mp_code_state_t, byte, state_size); } if (code_state == NULL) { - code_state = alloca(sizeof(mp_code_state) + state_size); + code_state = alloca(sizeof(mp_code_state_t) + state_size); state_size = 0; // indicate that we allocated using alloca } @@ -287,7 +287,7 @@ STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const // free the state if it was allocated on the heap if (state_size != 0) { - m_del_var(mp_code_state, byte, state_size, code_state); + m_del_var(mp_code_state_t, byte, state_size, code_state); } if (vm_return_kind == MP_VM_RETURN_NORMAL) { diff --git a/py/objgenerator.c b/py/objgenerator.c index 99d9445377..8c32a36496 100644 --- a/py/objgenerator.c +++ b/py/objgenerator.c @@ -46,7 +46,7 @@ typedef struct _mp_obj_gen_wrap_t { typedef struct _mp_obj_gen_instance_t { mp_obj_base_t base; mp_obj_dict_t *globals; - mp_code_state code_state; + mp_code_state_t code_state; } mp_obj_gen_instance_t; STATIC mp_obj_t gen_wrap_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { diff --git a/py/vm.c b/py/vm.c index 65801401d1..f9bdedff88 100644 --- a/py/vm.c +++ b/py/vm.c @@ -127,7 +127,7 @@ typedef enum { // MP_VM_RETURN_NORMAL, sp valid, return value in *sp // MP_VM_RETURN_YIELD, ip, sp valid, yielded value in *sp // MP_VM_RETURN_EXCEPTION, exception in fastn[0] -mp_vm_return_kind_t mp_execute_bytecode(mp_code_state *code_state, volatile mp_obj_t inject_exc) { +mp_vm_return_kind_t mp_execute_bytecode(mp_code_state_t *code_state, volatile mp_obj_t inject_exc) { #define SELECTIVE_EXC_IP (0) #if SELECTIVE_EXC_IP #define MARK_EXC_IP_SELECTIVE() { code_state->ip = ip; } /* stores ip 1 byte past last opcode */ @@ -904,7 +904,7 @@ unwind_jump:; code_state->ip = ip; code_state->sp = sp; code_state->exc_sp = MP_TAGPTR_MAKE(exc_sp, currently_in_except_block); - mp_code_state *new_state = mp_obj_fun_bc_prepare_codestate(*sp, unum & 0xff, (unum >> 8) & 0xff, sp + 1); + mp_code_state_t *new_state = mp_obj_fun_bc_prepare_codestate(*sp, unum & 0xff, (unum >> 8) & 0xff, sp + 1); if (new_state) { new_state->prev = code_state; code_state = new_state; @@ -940,7 +940,7 @@ unwind_jump:; mp_call_args_t out_args; mp_call_prepare_args_n_kw_var(false, unum, sp, &out_args); - mp_code_state *new_state = mp_obj_fun_bc_prepare_codestate(out_args.fun, + mp_code_state_t *new_state = mp_obj_fun_bc_prepare_codestate(out_args.fun, out_args.n_args, out_args.n_kw, out_args.args); m_del(mp_obj_t, out_args.args, out_args.n_alloc); if (new_state) { @@ -976,7 +976,7 @@ unwind_jump:; mp_uint_t n_kw = (unum >> 8) & 0xff; int adjust = (sp[1] == MP_OBJ_NULL) ? 0 : 1; - mp_code_state *new_state = mp_obj_fun_bc_prepare_codestate(*sp, n_args + adjust, n_kw, sp + 2 - adjust); + mp_code_state_t *new_state = mp_obj_fun_bc_prepare_codestate(*sp, n_args + adjust, n_kw, sp + 2 - adjust); if (new_state) { new_state->prev = code_state; code_state = new_state; @@ -1011,7 +1011,7 @@ unwind_jump:; mp_call_args_t out_args; mp_call_prepare_args_n_kw_var(true, unum, sp, &out_args); - mp_code_state *new_state = mp_obj_fun_bc_prepare_codestate(out_args.fun, + mp_code_state_t *new_state = mp_obj_fun_bc_prepare_codestate(out_args.fun, out_args.n_args, out_args.n_kw, out_args.args); m_del(mp_obj_t, out_args.args, out_args.n_alloc); if (new_state) { From f4ee9f88539e64a88bd837c5877354f6b7141119 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 27 Aug 2016 23:23:51 +1000 Subject: [PATCH 063/129] py/bc.h: Rename _mp_code_state to _mp_code_state_t. This rename was missed in the previous patch. --- py/bc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/py/bc.h b/py/bc.h index 11f5bb632f..4707da1793 100644 --- a/py/bc.h +++ b/py/bc.h @@ -78,7 +78,7 @@ typedef struct _mp_code_state_t { mp_exc_stack_t *exc_sp; mp_obj_dict_t *old_globals; #if MICROPY_STACKLESS - struct _mp_code_state *prev; + struct _mp_code_state_t *prev; #endif size_t n_state; // Variable-length From 8f8f699eb72446e94253eaa73a3c893562eef82d Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 27 Aug 2016 23:41:16 +1000 Subject: [PATCH 064/129] tests/run-tests: Disable thread_gc1.py test on Travis. It has reliability issues (cause unknown at this time). --- tests/run-tests | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/run-tests b/tests/run-tests index 80536f2423..5e8819729e 100755 --- a/tests/run-tests +++ b/tests/run-tests @@ -200,6 +200,7 @@ def run_tests(pyb, tests, args): # Some tests shouldn't be run under Travis CI if os.getenv('TRAVIS') == 'true': skip_tests.add('basics/memoryerror.py') + skip_tests.add('thread/thread_gc1.py') # has reliability issues skip_tests.add('thread/thread_lock4.py') # has reliability issues skip_tests.add('thread/stress_heap.py') # has reliability issues From 263aaa70302aa60d0338abbe439be2a77eb49a52 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sun, 28 Aug 2016 14:48:49 +0300 Subject: [PATCH 065/129] esp8266/modmachinewdt: Implement machine.WDT class. --- esp8266/Makefile | 1 + esp8266/modmachine.c | 3 ++ esp8266/modmachinewdt.c | 76 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 80 insertions(+) create mode 100644 esp8266/modmachinewdt.c diff --git a/esp8266/Makefile b/esp8266/Makefile index 0b498602f2..7da83f1aaf 100644 --- a/esp8266/Makefile +++ b/esp8266/Makefile @@ -78,6 +78,7 @@ SRC_C = \ modpybrtc.c \ modpybadc.c \ modpybuart.c \ + modmachinewdt.c \ modmachinespi.c \ modpybspi.c \ modpybhspi.c \ diff --git a/esp8266/modmachine.c b/esp8266/modmachine.c index 7672834aac..0972ce29fb 100644 --- a/esp8266/modmachine.c +++ b/esp8266/modmachine.c @@ -49,6 +49,8 @@ //#define MACHINE_WAKE_SLEEP (0x02) #define MACHINE_WAKE_DEEPSLEEP (0x04) +extern const mp_obj_type_t esp_wdt_type; + STATIC mp_obj_t machine_freq(mp_uint_t n_args, const mp_obj_t *args) { if (n_args == 0) { // get @@ -246,6 +248,7 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_RTC), MP_ROM_PTR(&pyb_rtc_type) }, { MP_ROM_QSTR(MP_QSTR_Timer), MP_ROM_PTR(&esp_timer_type) }, + { MP_ROM_QSTR(MP_QSTR_WDT), MP_ROM_PTR(&esp_wdt_type) }, { MP_ROM_QSTR(MP_QSTR_Pin), MP_ROM_PTR(&pyb_pin_type) }, { MP_ROM_QSTR(MP_QSTR_PWM), MP_ROM_PTR(&pyb_pwm_type) }, { MP_ROM_QSTR(MP_QSTR_ADC), MP_ROM_PTR(&pyb_adc_type) }, diff --git a/esp8266/modmachinewdt.c b/esp8266/modmachinewdt.c new file mode 100644 index 0000000000..e0b1ff5d78 --- /dev/null +++ b/esp8266/modmachinewdt.c @@ -0,0 +1,76 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +//#include +#include + +#include "py/nlr.h" +#include "py/obj.h" +#include "py/runtime.h" +#include "user_interface.h" + +const mp_obj_type_t esp_wdt_type; + +typedef struct _machine_wdt_obj_t { + mp_obj_base_t base; +} machine_wdt_obj_t; + +STATIC machine_wdt_obj_t wdt_default = {{&esp_wdt_type}}; + +STATIC mp_obj_t machine_wdt_make_new(const mp_obj_type_t *type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 0, 1, false); + + mp_int_t id = 0; + if (n_args > 0) { + id = mp_obj_get_int(args[0]); + } + + switch (id) { + case 0: + return &wdt_default; + default: + mp_raise_ValueError(""); + } +} + +STATIC mp_obj_t machine_wdt_feed(mp_obj_t self_in) { + (void)self_in; + system_soft_wdt_feed(); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_wdt_feed_obj, machine_wdt_feed); + +STATIC const mp_map_elem_t machine_wdt_locals_dict_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR_feed), (mp_obj_t)&machine_wdt_feed_obj } +}; +STATIC MP_DEFINE_CONST_DICT(machine_wdt_locals_dict, machine_wdt_locals_dict_table); + +const mp_obj_type_t esp_wdt_type = { + { &mp_type_type }, + .name = MP_QSTR_WDT, + .make_new = machine_wdt_make_new, + .locals_dict = (mp_obj_t)&machine_wdt_locals_dict, +}; From ed0a06a93fc275e4f3980b81e4e5314ed63279c6 Mon Sep 17 00:00:00 2001 From: Radomir Dopieralski Date: Sat, 27 Aug 2016 19:07:14 +0200 Subject: [PATCH 066/129] docs/esp8266/quickref: Fix and update the SPI docs Use the `SPI` factory function in the examples, and use proper baud rate of 80 000 000. --- docs/esp8266/quickref.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/esp8266/quickref.rst b/docs/esp8266/quickref.rst index be58f9332c..d8ec603727 100644 --- a/docs/esp8266/quickref.rst +++ b/docs/esp8266/quickref.rst @@ -165,14 +165,14 @@ Use the ``machine.ADC`` class:: SPI bus ------- -The SPI driver is implemented in software and works on all pins:: +There are two SPI drivers. One is implemented in software and works on all pins:: from machine import Pin, SPI # construct an SPI bus on the given pins # polarity is the idle state of SCK # phase=0 means sample on the first edge of SCK, phase=1 means the second - spi = SPI(baudrate=100000, polarity=1, phase=0, sck=Pin(0), mosi=Pin(2), miso=Pin(4)) + spi = SPI(-1, baudrate=100000, polarity=1, phase=0, sck=Pin(0), mosi=Pin(2), miso=Pin(4)) spi.init(baudrate=200000) # set the baudrate @@ -194,13 +194,13 @@ Hardware SPI ------------ The hardware SPI is faster (up to 80Mhz), but only works on following pins: -``MISO`` is gpio2, ``MOSI`` is gpio13, and ``SCK`` is gpio14. It has the same +``MISO`` is gpio12, ``MOSI`` is gpio13, and ``SCK`` is gpio14. It has the same methods as SPI, except for the pin parameters for the constructor and init (as those are fixed). - from machine import Pin, HSPI + from machine import Pin, SPI - hspi = HSPI(baudrate=800000000, polarity=0, phase=0) + hspi = SPI(0, baudrate=80000000, polarity=0, phase=0) I2C bus From 9fba618356679b0eede00b7cd746d1a53e6b3772 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 29 Aug 2016 12:12:49 +1000 Subject: [PATCH 067/129] esp8266/modules: Split onewire.py into OneWire and DS18X20 driver. The OneWire class is now in its own onewire.py module, and the temperature sensor class is in its own ds18x20.py module. The latter is renamed to DS18X20 to reflect the fact that it will support both the "S" and "B" variants of the device. These files are moved to the modules/ subdirectory to take advantage of frozen bytecode. --- esp8266/modules/ds18x20.py | 37 ++++++++++++++++++++ esp8266/{scripts => modules}/onewire.py | 45 +++---------------------- 2 files changed, 42 insertions(+), 40 deletions(-) create mode 100644 esp8266/modules/ds18x20.py rename esp8266/{scripts => modules}/onewire.py (69%) diff --git a/esp8266/modules/ds18x20.py b/esp8266/modules/ds18x20.py new file mode 100644 index 0000000000..66983f5bcc --- /dev/null +++ b/esp8266/modules/ds18x20.py @@ -0,0 +1,37 @@ +# DS18x20 temperature sensor driver for MicroPython. +# MIT license; Copyright (c) 2016 Damien P. George + +_CONVERT = const(0x44) +_RD_SCRATCH = const(0xbe) +_WR_SCRATCH = const(0x4e) + +class DS18X20: + def __init__(self, onewire): + self.ow = onewire + + def scan(self): + return [rom for rom in self.ow.scan() if rom[0] == 0x28] + + def convert_temp(self): + self.ow.reset(True) + self.ow.writebyte(self.ow.SKIP_ROM) + self.ow.writebyte(_CONVERT) + + def read_scratch(self, rom): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_RD_SCRATCH) + buf = self.ow.read(9) + if self.ow.crc8(buf): + raise Exception('CRC error') + return buf + + def write_scratch(self, rom, buf): + self.ow.reset(True) + self.ow.select_rom(rom) + self.ow.writebyte(_WR_SCRATCH) + self.ow.write(buf) + + def read_temp(self, rom): + buf = self.read_scratch(rom) + return (buf[1] << 8 | buf[0]) / 16 diff --git a/esp8266/scripts/onewire.py b/esp8266/modules/onewire.py similarity index 69% rename from esp8266/scripts/onewire.py rename to esp8266/modules/onewire.py index 686616950a..af5675649b 100644 --- a/esp8266/scripts/onewire.py +++ b/esp8266/modules/onewire.py @@ -15,8 +15,11 @@ class OneWire: self.pin = pin self.pin.init(pin.OPEN_DRAIN) - def reset(self): - return _ow.reset(self.pin) + def reset(self, required=False): + reset = _ow.reset(self.pin) + if required and not reset: + raise OneWireError + return reset def readbit(self): return _ow.readbit(self.pin) @@ -87,41 +90,3 @@ class OneWire: def crc8(self, data): return _ow.crc8(data) - -class DS18B20: - CONVERT = const(0x44) - RD_SCRATCH = const(0xbe) - WR_SCRATCH = const(0x4e) - - def __init__(self, onewire): - self.ow = onewire - - def scan(self): - return [rom for rom in self.ow.scan() if rom[0] == 0x28] - - def convert_temp(self): - if not self.ow.reset(): - raise OneWireError - self.ow.writebyte(SKIP_ROM) - self.ow.writebyte(CONVERT) - - def read_scratch(self, rom): - if not self.ow.reset(): - raise OneWireError - self.ow.select_rom(rom) - self.ow.writebyte(RD_SCRATCH) - buf = self.ow.read(9) - if self.ow.crc8(buf): - raise OneWireError - return buf - - def write_scratch(self, rom, buf): - if not self.ow.reset(): - raise OneWireError - self.ow.select_rom(rom) - self.ow.writebyte(WR_SCRATCH) - self.ow.write(buf) - - def read_temp(self, rom): - buf = self.read_scratch(rom) - return (buf[1] << 8 | buf[0]) / 16 From 8e9b98e974ff141ba78918021f3203f620d1de8a Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 29 Aug 2016 12:27:21 +1000 Subject: [PATCH 068/129] esp8266/modules/onewire: Change onewire.read() to onewire.readinto(). This allows 1-wire drivers (eg DS18X20) to perform in-place operations and hence do less memory allocations. --- esp8266/modules/ds18x20.py | 7 ++++--- esp8266/modules/onewire.py | 6 ++---- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/esp8266/modules/ds18x20.py b/esp8266/modules/ds18x20.py index 66983f5bcc..9c5bb8eb6b 100644 --- a/esp8266/modules/ds18x20.py +++ b/esp8266/modules/ds18x20.py @@ -8,6 +8,7 @@ _WR_SCRATCH = const(0x4e) class DS18X20: def __init__(self, onewire): self.ow = onewire + self.buf = bytearray(9) def scan(self): return [rom for rom in self.ow.scan() if rom[0] == 0x28] @@ -21,10 +22,10 @@ class DS18X20: self.ow.reset(True) self.ow.select_rom(rom) self.ow.writebyte(_RD_SCRATCH) - buf = self.ow.read(9) - if self.ow.crc8(buf): + self.ow.readinto(self.buf) + if self.ow.crc8(self.buf): raise Exception('CRC error') - return buf + return self.buf def write_scratch(self, rom, buf): self.ow.reset(True) diff --git a/esp8266/modules/onewire.py b/esp8266/modules/onewire.py index af5675649b..06b216a57a 100644 --- a/esp8266/modules/onewire.py +++ b/esp8266/modules/onewire.py @@ -27,11 +27,9 @@ class OneWire: def readbyte(self): return _ow.readbyte(self.pin) - def read(self, count): - buf = bytearray(count) - for i in range(count): + def readinto(self, buf): + for i in range(len(buf)): buf[i] = _ow.readbyte(self.pin) - return buf def writebit(self, value): return _ow.writebit(self.pin, value) From 59a9509703c6e525b3419ffea1b69f3b6992e006 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 29 Aug 2016 12:45:07 +1000 Subject: [PATCH 069/129] esp8266/modules/ds18x20.py: Add support for DS18S20 devices. --- esp8266/modules/ds18x20.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/esp8266/modules/ds18x20.py b/esp8266/modules/ds18x20.py index 9c5bb8eb6b..eb22e2ae30 100644 --- a/esp8266/modules/ds18x20.py +++ b/esp8266/modules/ds18x20.py @@ -11,7 +11,7 @@ class DS18X20: self.buf = bytearray(9) def scan(self): - return [rom for rom in self.ow.scan() if rom[0] == 0x28] + return [rom for rom in self.ow.scan() if rom[0] == 0x10 or rom[0] == 0x28] def convert_temp(self): self.ow.reset(True) @@ -35,4 +35,12 @@ class DS18X20: def read_temp(self, rom): buf = self.read_scratch(rom) - return (buf[1] << 8 | buf[0]) / 16 + if rom[0] == 0x10: + if buf[1]: + t = buf[0] >> 1 | 0x80 + t = -((~t + 1) & 0xff) + else: + t = buf[0] >> 1 + return t - 0.25 + (buf[7] - buf[6]) / buf[7] + else: + return (buf[1] << 8 | buf[0]) / 16 From 13c5a228c9ec9881087bdddd162f3b633edc3aa5 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 29 Aug 2016 12:52:50 +1000 Subject: [PATCH 070/129] docs/esp8266: Update quickref and tutorial for OneWire/DS18X20 driver. --- docs/esp8266/quickref.rst | 7 +++---- docs/esp8266/tutorial/onewire.rst | 6 +++--- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/docs/esp8266/quickref.rst b/docs/esp8266/quickref.rst index d8ec603727..f15cb72bbe 100644 --- a/docs/esp8266/quickref.rst +++ b/docs/esp8266/quickref.rst @@ -253,15 +253,14 @@ The OneWire driver is implemented in software and works on all pins:: ow.scan() # return a list of devices on the bus ow.reset() # reset the bus ow.readbyte() # read a byte - ow.read(5) # read 5 bytes ow.writebyte(0x12) # write a byte on the bus ow.write('123') # write bytes on the bus ow.select_rom(b'12345678') # select a specific device by its ROM code -There is a specific driver for DS18B20 devices:: +There is a specific driver for DS18S20 and DS18B20 devices:: - import time - ds = onewire.DS18B20(ow) + import time, ds18x20 + ds = ds18x20.DS18X20(ow) roms = ds.scan() ds.convert_temp() time.sleep_ms(750) diff --git a/docs/esp8266/tutorial/onewire.rst b/docs/esp8266/tutorial/onewire.rst index c90044b7a8..c2cede9e38 100644 --- a/docs/esp8266/tutorial/onewire.rst +++ b/docs/esp8266/tutorial/onewire.rst @@ -6,19 +6,19 @@ The 1-wire bus is a serial bus that uses just a single wire for communication is a very popular 1-wire device, and here we show how to use the onewire module to read from such a device. -For the following code to work you need to have at least one DS18B20 temperature +For the following code to work you need to have at least one DS18S20 or DS18B20 temperature sensor with its data line connected to GPIO12. You must also power the sensors and connect a 4.7k Ohm resistor between the data pin and the power pin. :: import time import machine - import onewire + import onewire, ds18x20 # the device is on GPIO12 dat = machine.Pin(12) # create the onewire object - ds = onewire.DS18B20(onewire.OneWire(dat)) + ds = ds18x20.DS18X20(onewire.OneWire(dat)) # scan for devices on the bus roms = ds.scan() From 57c92d90b0be9f353c5f0501f4d78a408911f8b2 Mon Sep 17 00:00:00 2001 From: Philip Potter Date: Sat, 27 Aug 2016 20:57:22 +0100 Subject: [PATCH 071/129] docs/pyboard: Update USB mouse tutorial to use VCP instead of CDC. --- docs/pyboard/tutorial/usb_mouse.rst | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/pyboard/tutorial/usb_mouse.rst b/docs/pyboard/tutorial/usb_mouse.rst index ac1de6e275..6e4feb6220 100644 --- a/docs/pyboard/tutorial/usb_mouse.rst +++ b/docs/pyboard/tutorial/usb_mouse.rst @@ -13,23 +13,23 @@ will look something like this:: import pyb #pyb.main('main.py') # main script to run after this one - #pyb.usb_mode('CDC+MSC') # act as a serial and a storage device - #pyb.usb_mode('CDC+HID') # act as a serial device and a mouse + #pyb.usb_mode('VCP+MSC') # act as a serial and a storage device + #pyb.usb_mode('VCP+HID') # act as a serial device and a mouse To enable the mouse mode, uncomment the last line of the file, to make it look like:: - pyb.usb_mode('CDC+HID') # act as a serial device and a mouse + pyb.usb_mode('VCP+HID') # act as a serial device and a mouse If you already changed your ``boot.py`` file, then the minimum code it needs to work is:: import pyb - pyb.usb_mode('CDC+HID') + pyb.usb_mode('VCP+HID') -This tells the pyboard to configure itself as a CDC (serial) and HID -(human interface device, in our case a mouse) USB device when it boots -up. +This tells the pyboard to configure itself as a VCP (Virtual COM Port, +ie serial port) and HID (human interface device, in our case a mouse) +USB device when it boots up. Eject/unmount the pyboard drive and reset it using the RST switch. Your PC should now detect the pyboard as a mouse! @@ -121,9 +121,9 @@ If you leave your pyboard as-is, it'll behave as a mouse everytime you plug it in. You probably want to change it back to normal. To do this you need to first enter safe mode (see above), and then edit the ``boot.py`` file. In the ``boot.py`` file, comment out (put a # in front of) the line with the -``CDC+HID`` setting, so it looks like:: +``VCP+HID`` setting, so it looks like:: - #pyb.usb_mode('CDC+HID') # act as a serial device and a mouse + #pyb.usb_mode('VCP+HID') # act as a serial device and a mouse Save your file, eject/unmount the drive, and reset the pyboard. It is now back to normal operating mode. From f2da6467a9579c564f297a90a23c8b576c9cf6b1 Mon Sep 17 00:00:00 2001 From: Philip Potter Date: Sat, 27 Aug 2016 21:06:51 +0100 Subject: [PATCH 072/129] docs/pyboard: Update USB mouse tutorial to use pyb.USB_HID(). --- docs/pyboard/tutorial/usb_mouse.rst | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/pyboard/tutorial/usb_mouse.rst b/docs/pyboard/tutorial/usb_mouse.rst index 6e4feb6220..6f8831edb4 100644 --- a/docs/pyboard/tutorial/usb_mouse.rst +++ b/docs/pyboard/tutorial/usb_mouse.rst @@ -41,7 +41,8 @@ To get the py-mouse to do anything we need to send mouse events to the PC. We will first do this manually using the REPL prompt. Connect to your pyboard using your serial program and type the following:: - >>> pyb.hid((0, 10, 0, 0)) + >>> hid = pyb.USB_HID() + >>> hid.send((0, 10, 0, 0)) Your mouse should move 10 pixels to the right! In the command above you are sending 4 pieces of information: button status, x, y and scroll. The @@ -52,7 +53,7 @@ Let's make the mouse oscillate left and right:: >>> import math >>> def osc(n, d): ... for i in range(n): - ... pyb.hid((0, int(20 * math.sin(i / 10)), 0, 0)) + ... hid.send((0, int(20 * math.sin(i / 10)), 0, 0)) ... pyb.delay(d) ... >>> osc(100, 50) @@ -100,9 +101,10 @@ In ``main.py`` put the following code:: switch = pyb.Switch() accel = pyb.Accel() + hid = pyb.USB_HID() while not switch(): - pyb.hid((0, accel.x(), accel.y(), 0)) + hid.send((0, accel.x(), accel.y(), 0)) pyb.delay(20) Save your file, eject/unmount your pyboard drive, and reset it using the RST @@ -112,7 +114,7 @@ the mouse around. Try it out, and see if you can make the mouse stand still! Press the USR switch to stop the mouse motion. You'll note that the y-axis is inverted. That's easy to fix: just put a -minus sign in front of the y-coordinate in the ``pyb.hid()`` line above. +minus sign in front of the y-coordinate in the ``hid.send()`` line above. Restoring your pyboard to normal -------------------------------- From 0f8b1ba8a2c3588f319f6b426aa07e97d2e17b24 Mon Sep 17 00:00:00 2001 From: Philip Potter Date: Sun, 28 Aug 2016 18:05:40 +0100 Subject: [PATCH 073/129] docs/library: Add reference for pyb.usb_mode and pyb.USB_HID. --- docs/library/pyb.USB_HID.rst | 28 ++++++++++++++++++++++++++++ docs/library/pyb.rst | 30 +++++++++++++++++++++++++++++- 2 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 docs/library/pyb.USB_HID.rst diff --git a/docs/library/pyb.USB_HID.rst b/docs/library/pyb.USB_HID.rst new file mode 100644 index 0000000000..65fb4014e0 --- /dev/null +++ b/docs/library/pyb.USB_HID.rst @@ -0,0 +1,28 @@ +.. currentmodule:: pyb + +class USB_HID -- USB Human Interface Device (HID) +================================================= + +The USB_HID class allows creation of an object representing the USB +Human Interface Device (HID) interface. It can be used to emulate +a peripheral such as a mouse or keyboard. + +Before you can use this class, you need to use :meth:`pyb.usb_mode()` to set the USB mode to include the HID interface. + +Constructors +------------ + +.. class:: pyb.USB_HID() + + Create a new USB_HID object. + + +Methods +------- + +.. method:: USB_HID.send(data) + + Send data over the USB HID interface: + + - ``data`` is the data to send (a tuple/list of integers, or a + bytearray). diff --git a/docs/library/pyb.rst b/docs/library/pyb.rst index 2f3e7d36bd..910b2f45b4 100644 --- a/docs/library/pyb.rst +++ b/docs/library/pyb.rst @@ -188,7 +188,7 @@ Miscellaneous functions Takes a 4-tuple (or list) and sends it to the USB host (the PC) to signal a HID mouse-motion event. - .. note:: This function is deprecated. Use pyb.USB_HID().send(...) instead. + .. note:: This function is deprecated. Use :meth:`pyb.USB_HID.send()` instead. .. function:: info([dump_alloc_table]) @@ -254,6 +254,33 @@ Miscellaneous functions Returns a string of 12 bytes (96 bits), which is the unique ID of the MCU. +.. function:: usb_mode([modestr], vid=0xf055, pid=0x9801, hid=pyb.hid_mouse) + + If called with no arguments, return the current USB mode as a string. + + If called with ``modestr`` provided, attempts to set USB mode. + This can only be done when called from ``boot.py`` before + :meth:`pyb.main()` has been called. The following values of + ``modestr`` are understood: + + - ``None``: disables USB + - ``'VCP'``: enable with VCP (Virtual COM Port) interface + - ``'VCP+MSC'``: enable with VCP and MSC (mass storage device class) + - ``'VCP+HID'``: enable with VCP and HID (human interface device) + + For backwards compatibility, ``'CDC'`` is understood to mean + ``'VCP'`` (and similarly for ``'CDC+MSC'`` and ``'CDC+HID'``). + + The ``vid`` and ``pid`` parameters allow you to specify the VID + (vendor id) and PID (product id). + + If enabling HID mode, you may also specify the HID details by + passing the ``hid`` keyword parameter. It takes a tuple of + (subclass, protocol, max packet length, polling interval, report + descriptor). By default it will set appropriate values for a USB + mouse. There is also a ``pyb.hid_keyboard`` constant, which is an + appropriate tuple for a USB keyboard. + Classes ------- @@ -277,4 +304,5 @@ Classes pyb.Switch.rst pyb.Timer.rst pyb.UART.rst + pyb.USB_HID.rst pyb.USB_VCP.rst From c777b6950eed1b48bb88fb8b343eeed85b13560f Mon Sep 17 00:00:00 2001 From: Philip Potter Date: Sun, 28 Aug 2016 18:19:08 +0100 Subject: [PATCH 074/129] stmhal: Update boot.py files to use VCP instead of CDC. --- examples/SDdatalogger/boot.py | 4 ++-- stmhal/main.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/SDdatalogger/boot.py b/examples/SDdatalogger/boot.py index aa943fde93..4ac94bbaa4 100644 --- a/examples/SDdatalogger/boot.py +++ b/examples/SDdatalogger/boot.py @@ -16,10 +16,10 @@ pyb.LED(3).off() # indicate that we finished waiting for the swit pyb.LED(4).on() # indicate that we are selecting the mode if switch_value: - pyb.usb_mode('CDC+MSC') + pyb.usb_mode('VCP+MSC') pyb.main('cardreader.py') # if switch was pressed, run this else: - pyb.usb_mode('CDC+HID') + pyb.usb_mode('VCP+HID') pyb.main('datalogger.py') # if switch wasn't pressed, run this pyb.LED(4).off() # indicate that we finished selecting the mode diff --git a/stmhal/main.c b/stmhal/main.c index 30dddaf989..32baae5320 100644 --- a/stmhal/main.c +++ b/stmhal/main.c @@ -137,8 +137,8 @@ static const char fresh_boot_py[] = "import machine\r\n" "import pyb\r\n" "#pyb.main('main.py') # main script to run after this one\r\n" -"#pyb.usb_mode('CDC+MSC') # act as a serial and a storage device\r\n" -"#pyb.usb_mode('CDC+HID') # act as a serial device and a mouse\r\n" +"#pyb.usb_mode('VCP+MSC') # act as a serial and a storage device\r\n" +"#pyb.usb_mode('VCP+HID') # act as a serial device and a mouse\r\n" ; static const char fresh_main_py[] = From d1a366fdd4a0f60e0487bd45a8b456804c75ea5d Mon Sep 17 00:00:00 2001 From: Krzysztof Blazewicz Date: Sat, 27 Aug 2016 10:15:00 +0200 Subject: [PATCH 075/129] .gitignore: Add *.pyc, because Python 2 doesn't use __pycache__. --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 450bbd8639..a6295928d3 100644 --- a/.gitignore +++ b/.gitignore @@ -32,6 +32,7 @@ tests/*.out # Python cache files ###################### __pycache__/ +*.pyc # Customized Makefile/project overrides ###################### From 5c3a2f162ec08aa2df900f25e87abb5d74e39c7c Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 29 Aug 2016 17:32:38 +1000 Subject: [PATCH 076/129] docs/pyboard/quickref: Add links to pinouts for other pyboard variants. --- docs/pyboard/quickref.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/pyboard/quickref.rst b/docs/pyboard/quickref.rst index 2a1429cb05..140452a9b0 100644 --- a/docs/pyboard/quickref.rst +++ b/docs/pyboard/quickref.rst @@ -3,6 +3,12 @@ Quick reference for the pyboard =============================== +The below pinout is for PYBv1.0. You can also view pinouts for +other versions of the pyboard: +`PYBv1.1 `__ +or `PYBLITEv1.0-AC `__ +or `PYBLITEv1.0 `__. + .. image:: http://micropython.org/resources/pybv10-pinout.jpg :alt: PYBv1.0 pinout :width: 700px From efc904c41d4acc631ec0781a7489c382d6d0b396 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 29 Aug 2016 17:33:02 +1000 Subject: [PATCH 077/129] docs/pyboard/quickref: Add section on "delay and timing" for utime mod. And remove reference to deprecated pyb.delay() and pyb.millis(). --- docs/pyboard/quickref.rst | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/docs/pyboard/quickref.rst b/docs/pyboard/quickref.rst index 140452a9b0..3d08ae9109 100644 --- a/docs/pyboard/quickref.rst +++ b/docs/pyboard/quickref.rst @@ -20,14 +20,25 @@ See :mod:`pyb`. :: import pyb - pyb.delay(50) # wait 50 milliseconds - pyb.millis() # number of milliseconds since bootup pyb.repl_uart(pyb.UART(1, 9600)) # duplicate REPL on UART(1) pyb.wfi() # pause CPU, waiting for interrupt pyb.freq() # get CPU and bus frequencies pyb.freq(60000000) # set CPU freq to 60MHz pyb.stop() # stop CPU, waiting for external interrupt +Delay and timing +---------------- + +Use the :mod:`time ` module:: + + import time + + time.sleep(1) # sleep for 1 second + time.sleep_ms(500) # sleep for 500 milliseconds + time.sleep_us(10) # sleep for 10 microseconds + start = time.ticks_ms() # get value of millisecond counter + delta = time.ticks_diff(start, time.ticks_ms()) # compute time difference + LEDs ---- From 76dcaddc0f647bd597013980108b0b28bb6eb1c9 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 29 Aug 2016 17:40:36 +1000 Subject: [PATCH 078/129] docs/esp8266/quickref: Add internal links to docs for some modules. --- docs/esp8266/quickref.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/esp8266/quickref.rst b/docs/esp8266/quickref.rst index f15cb72bbe..d209871361 100644 --- a/docs/esp8266/quickref.rst +++ b/docs/esp8266/quickref.rst @@ -23,14 +23,14 @@ Tab-completion is useful to find out what methods an object has. Paste mode (ctrl-E) is useful to paste a large slab of Python code into the REPL. -The ``machine`` module:: +The :mod:`machine` module:: import machine machine.freq() # get the current frequency of the CPU machine.freq(160000000) # set the CPU frequency to 160 MHz -The ``esp`` module:: +The :mod:`esp` module:: import esp @@ -40,7 +40,7 @@ The ``esp`` module:: Networking ---------- -The ``network`` module:: +The :mod:`network` module:: import network @@ -69,13 +69,13 @@ A useful function for connecting to your local WiFi network is:: pass print('network config:', wlan.ifconfig()) -Once the network is established the ``socket`` module can be used +Once the network is established the :mod:`socket ` module can be used to create and use TCP/UDP sockets as usual. Delay and timing ---------------- -Use the ``time`` module:: +Use the :mod:`time ` module:: import time From bae62d9abe3db0f60f681f79b684ec7e5fb25fda Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Tue, 30 Aug 2016 00:58:42 +0300 Subject: [PATCH 079/129] lib/utils/pyexec: qstr_pool_info() requires size_t* parameters. --- lib/utils/pyexec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/utils/pyexec.c b/lib/utils/pyexec.c index 411ee969d6..2bc7a00cc0 100644 --- a/lib/utils/pyexec.c +++ b/lib/utils/pyexec.c @@ -112,7 +112,7 @@ STATIC int parse_compile_execute(void *source, mp_parse_input_kind_t input_kind, printf("took " UINT_FMT " ms\n", ticks); // qstr info { - mp_uint_t n_pool, n_qstr, n_str_data_bytes, n_total_bytes; + size_t n_pool, n_qstr, n_str_data_bytes, n_total_bytes; qstr_pool_info(&n_pool, &n_qstr, &n_str_data_bytes, &n_total_bytes); printf("qstr:\n n_pool=" UINT_FMT "\n n_qstr=" UINT_FMT "\n n_str_data_bytes=" UINT_FMT "\n n_total_bytes=" UINT_FMT "\n", n_pool, n_qstr, n_str_data_bytes, n_total_bytes); } From 1f61fe07a2bca5374fdb402a41785a81b193f5ed Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Tue, 30 Aug 2016 00:59:17 +0300 Subject: [PATCH 080/129] py/mkrules.mk: Allow to override name of libmicropython.a Or alternatively, refer to an exact library file, not just phony target "lib". --- py/mkrules.mk | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/py/mkrules.mk b/py/mkrules.mk index 3cf0e30584..a3a408dc89 100644 --- a/py/mkrules.mk +++ b/py/mkrules.mk @@ -123,8 +123,9 @@ clean-prog: .PHONY: clean-prog endif -lib: $(OBJ) - $(AR) rcs libmicropython.a $^ +LIBMICROPYTHON = libmicropython.a +lib $(LIBMICROPYTHON): $(OBJ) + $(AR) rcs $(LIBMICROPYTHON) $^ clean: $(RM) -rf $(BUILD) $(CLEAN_EXTRA) From 9c04ef2a6772cabbd92abe6c826b56cc04a1a7b8 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 31 Aug 2016 15:12:57 +1000 Subject: [PATCH 081/129] unix,stmhal,esp8266: When find'ing frozen files don't use extra slash. This extra forward slash for the starting-point directory is unnecessary and leads to additional slashes on Max OS X which mean that the frozen files cannot be imported. Fixes #2374. --- esp8266/Makefile | 2 +- stmhal/Makefile | 2 +- unix/Makefile | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/esp8266/Makefile b/esp8266/Makefile index 7da83f1aaf..2786510388 100644 --- a/esp8266/Makefile +++ b/esp8266/Makefile @@ -141,7 +141,7 @@ DRIVERS_SRC_C = $(addprefix drivers/,\ SRC_S = \ gchelper.s \ -FROZEN_MPY_PY_FILES := $(shell find $(FROZEN_MPY_DIR)/ -type f -name '*.py') +FROZEN_MPY_PY_FILES := $(shell find $(FROZEN_MPY_DIR) -type f -name '*.py') FROZEN_MPY_MPY_FILES := $(addprefix $(BUILD)/,$(FROZEN_MPY_PY_FILES:.py=.mpy)) OBJ = diff --git a/stmhal/Makefile b/stmhal/Makefile index 1ad2783fca..2c6ea806eb 100644 --- a/stmhal/Makefile +++ b/stmhal/Makefile @@ -284,7 +284,7 @@ endif ifneq ($(FROZEN_MPY_DIR),) # To use frozen bytecode, put your .py files in a subdirectory (eg frozen/) and # then invoke make with FROZEN_MPY_DIR=frozen (be sure to build from scratch). -FROZEN_MPY_PY_FILES := $(shell find $(FROZEN_MPY_DIR)/ -type f -name '*.py') +FROZEN_MPY_PY_FILES := $(shell find $(FROZEN_MPY_DIR) -type f -name '*.py') FROZEN_MPY_MPY_FILES := $(addprefix $(BUILD)/,$(FROZEN_MPY_PY_FILES:.py=.mpy)) CFLAGS += -DMICROPY_QSTR_EXTRA_POOL=mp_qstr_frozen_const_pool CFLAGS += -DMICROPY_MODULE_FROZEN_MPY diff --git a/unix/Makefile b/unix/Makefile index cb9a999f08..3afa80dfa8 100644 --- a/unix/Makefile +++ b/unix/Makefile @@ -183,7 +183,7 @@ ifneq ($(FROZEN_MPY_DIR),) # then invoke make with FROZEN_MPY_DIR=frozen (be sure to build from scratch). MPY_CROSS = ../mpy-cross/mpy-cross MPY_TOOL = ../tools/mpy-tool.py -FROZEN_MPY_PY_FILES := $(shell find $(FROZEN_MPY_DIR)/ -type f -name '*.py') +FROZEN_MPY_PY_FILES := $(shell find $(FROZEN_MPY_DIR) -type f -name '*.py') FROZEN_MPY_MPY_FILES := $(addprefix $(BUILD)/,$(FROZEN_MPY_PY_FILES:.py=.mpy)) CFLAGS += -DMICROPY_QSTR_EXTRA_POOL=mp_qstr_frozen_const_pool CFLAGS += -DMICROPY_MODULE_FROZEN_MPY From 0823c1baf864f2e8fd60e49a5e42a958fd89ff43 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 1 Sep 2016 15:07:20 +1000 Subject: [PATCH 082/129] extmod: Add machine_spi with generic SPI C-protocol and helper methods. The idea is that all ports can use these helper methods and only need to provide initialisation of the SPI bus, as well as a single transfer function. The coding pattern follows the stream protocol and helper methods. --- extmod/machine_spi.c | 85 ++++++++++++++++++++++++++++++++++++++++++++ extmod/machine_spi.h | 42 ++++++++++++++++++++++ py/mpconfig.h | 4 +++ py/py.mk | 1 + 4 files changed, 132 insertions(+) create mode 100644 extmod/machine_spi.c create mode 100644 extmod/machine_spi.h diff --git a/extmod/machine_spi.c b/extmod/machine_spi.c new file mode 100644 index 0000000000..6b6202a221 --- /dev/null +++ b/extmod/machine_spi.c @@ -0,0 +1,85 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/runtime.h" +#include "extmod/machine_spi.h" + +#if MICROPY_PY_MACHINE_SPI + +STATIC void mp_machine_spi_transfer(mp_obj_t self, size_t slen, const uint8_t *src, size_t dlen, uint8_t *dest) { + mp_obj_base_t *s = (mp_obj_base_t*)MP_OBJ_TO_PTR(self); + mp_machine_spi_p_t *spi_p = (mp_machine_spi_p_t*)s->type->protocol; + spi_p->transfer(s, slen, src, dlen, dest); +} + +STATIC mp_obj_t mp_machine_spi_read(size_t n_args, const mp_obj_t *args) { + uint8_t write_byte = 0; + if (n_args == 3) { + write_byte = mp_obj_get_int(args[2]); + } + vstr_t vstr; + vstr_init_len(&vstr, mp_obj_get_int(args[1])); + mp_machine_spi_transfer(args[0], 1, &write_byte, vstr.len, (uint8_t*)vstr.buf); + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_machine_spi_read_obj, 2, 3, mp_machine_spi_read); + +STATIC mp_obj_t mp_machine_spi_readinto(size_t n_args, const mp_obj_t *args) { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_WRITE); + uint8_t write_byte = 0; + if (n_args == 3) { + write_byte = mp_obj_get_int(args[2]); + } + mp_machine_spi_transfer(args[0], 1, &write_byte, bufinfo.len, (uint8_t*)bufinfo.buf); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_machine_spi_readinto_obj, 2, 3, mp_machine_spi_readinto); + +STATIC mp_obj_t mp_machine_spi_write(mp_obj_t self, mp_obj_t wr_buf) { + mp_buffer_info_t src; + mp_get_buffer_raise(wr_buf, &src, MP_BUFFER_READ); + mp_machine_spi_transfer(self, src.len, (const uint8_t*)src.buf, 0, NULL); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(mp_machine_spi_write_obj, mp_machine_spi_write); + +STATIC mp_obj_t mp_machine_spi_write_readinto(mp_obj_t self, mp_obj_t wr_buf, mp_obj_t rd_buf) { + mp_buffer_info_t src; + mp_get_buffer_raise(wr_buf, &src, MP_BUFFER_READ); + mp_buffer_info_t dest; + mp_get_buffer_raise(rd_buf, &dest, MP_BUFFER_WRITE); + if (src.len != dest.len) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "buffers must be the same length")); + } + mp_machine_spi_transfer(self, src.len, (const uint8_t*)src.buf, dest.len, (uint8_t*)dest.buf); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_3(mp_machine_spi_write_readinto_obj, mp_machine_spi_write_readinto); + +#endif // MICROPY_PY_MACHINE_SPI diff --git a/extmod/machine_spi.h b/extmod/machine_spi.h new file mode 100644 index 0000000000..26d716fc11 --- /dev/null +++ b/extmod/machine_spi.h @@ -0,0 +1,42 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MICROPY_INCLUDED_EXTMOD_MACHINE_SPI_H +#define MICROPY_INCLUDED_EXTMOD_MACHINE_SPI_H + +#include "py/obj.h" + +// SPI protocol +typedef struct _mp_machine_spi_p_t { + void (*transfer)(mp_obj_base_t *obj, size_t slen, const uint8_t *src, size_t dlen, uint8_t *dest); +} mp_machine_spi_p_t; + +MP_DECLARE_CONST_FUN_OBJ(mp_machine_spi_read_obj); +MP_DECLARE_CONST_FUN_OBJ(mp_machine_spi_readinto_obj); +MP_DECLARE_CONST_FUN_OBJ(mp_machine_spi_write_obj); +MP_DECLARE_CONST_FUN_OBJ(mp_machine_spi_write_readinto_obj); + +#endif // MICROPY_INCLUDED_EXTMOD_MACHINE_SPI_H diff --git a/py/mpconfig.h b/py/mpconfig.h index 23591e0da3..455f870ac7 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -923,6 +923,10 @@ typedef double mp_float_t; #define MICROPY_PY_MACHINE_I2C (0) #endif +#ifndef MICROPY_PY_MACHINE_SPI +#define MICROPY_PY_MACHINE_SPI (0) +#endif + #ifndef MICROPY_PY_USSL #define MICROPY_PY_USSL (0) #endif diff --git a/py/py.mk b/py/py.mk index a110c9f608..abea7215b2 100644 --- a/py/py.mk +++ b/py/py.mk @@ -208,6 +208,7 @@ PY_O_BASENAME = \ ../extmod/machine_pinbase.o \ ../extmod/machine_pulse.o \ ../extmod/machine_i2c.o \ + ../extmod/machine_spi.o \ ../extmod/modussl_axtls.o \ ../extmod/modurandom.o \ ../extmod/modwebsocket.o \ From 5863e15a23910f46c716876e171a23008993db77 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 1 Sep 2016 15:10:27 +1000 Subject: [PATCH 083/129] esp8266/modpybspi: Use generic SPI helper methods to implement SPI. --- esp8266/modpybspi.c | 66 ++++++++---------------------------------- esp8266/mpconfigport.h | 1 + 2 files changed, 13 insertions(+), 54 deletions(-) diff --git a/esp8266/modpybspi.c b/esp8266/modpybspi.c index fafe3b2fa5..4c4b843c5d 100644 --- a/esp8266/modpybspi.c +++ b/esp8266/modpybspi.c @@ -35,6 +35,7 @@ #include "py/runtime.h" #include "py/stream.h" #include "py/mphal.h" +#include "extmod/machine_spi.h" typedef struct _pyb_spi_obj_t { mp_obj_base_t base; @@ -46,7 +47,8 @@ typedef struct _pyb_spi_obj_t { mp_hal_pin_obj_t miso; } pyb_spi_obj_t; -STATIC void mp_hal_spi_transfer(pyb_spi_obj_t *self, size_t src_len, const uint8_t *src_buf, size_t dest_len, uint8_t *dest_buf) { +STATIC void mp_hal_spi_transfer(mp_obj_base_t *self_in, size_t src_len, const uint8_t *src_buf, size_t dest_len, uint8_t *dest_buf) { + pyb_spi_obj_t *self = (pyb_spi_obj_t*)self_in; // only MSB transfer is implemented uint32_t delay_half = 500000 / self->baudrate + 1; for (size_t i = 0; i < src_len || i < dest_len; ++i) { @@ -154,69 +156,25 @@ STATIC mp_obj_t pyb_spi_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_a } MP_DEFINE_CONST_FUN_OBJ_KW(pyb_spi_init_obj, 1, pyb_spi_init); -STATIC mp_obj_t pyb_spi_read(size_t n_args, const mp_obj_t *args) { - pyb_spi_obj_t *self = MP_OBJ_TO_PTR(args[0]); - uint8_t write_byte = 0; - if (n_args == 3) { - write_byte = mp_obj_get_int(args[2]); - } - vstr_t vstr; - vstr_init_len(&vstr, mp_obj_get_int(args[1])); - mp_hal_spi_transfer(self, 1, &write_byte, vstr.len, (uint8_t*)vstr.buf); - return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); -} -MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_spi_read_obj, 2, 3, pyb_spi_read); - -STATIC mp_obj_t pyb_spi_readinto(size_t n_args, const mp_obj_t *args) { - pyb_spi_obj_t *self = MP_OBJ_TO_PTR(args[0]); - mp_buffer_info_t bufinfo; - mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_WRITE); - uint8_t write_byte = 0; - if (n_args == 3) { - write_byte = mp_obj_get_int(args[2]); - } - mp_hal_spi_transfer(self, 1, &write_byte, bufinfo.len, (uint8_t*)bufinfo.buf); - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_spi_readinto_obj, 2, 3, pyb_spi_readinto); - -STATIC mp_obj_t pyb_spi_write(mp_obj_t self_in, mp_obj_t wr_buf_in) { - pyb_spi_obj_t *self = MP_OBJ_TO_PTR(self_in); - mp_buffer_info_t src_buf; - mp_get_buffer_raise(wr_buf_in, &src_buf, MP_BUFFER_READ); - mp_hal_spi_transfer(self, src_buf.len, (const uint8_t*)src_buf.buf, 0, NULL); - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_2(pyb_spi_write_obj, pyb_spi_write); - -STATIC mp_obj_t pyb_spi_write_readinto(mp_obj_t self_in, mp_obj_t wr_buf_in, mp_obj_t rd_buf_in) { - pyb_spi_obj_t *self = MP_OBJ_TO_PTR(self_in); - mp_buffer_info_t src_buf; - mp_get_buffer_raise(wr_buf_in, &src_buf, MP_BUFFER_READ); - mp_buffer_info_t dest_buf; - mp_get_buffer_raise(rd_buf_in, &dest_buf, MP_BUFFER_WRITE); - if (src_buf.len != dest_buf.len) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "buffers must be the same length")); - } - mp_hal_spi_transfer(self, src_buf.len, (const uint8_t*)src_buf.buf, dest_buf.len, (uint8_t*)dest_buf.buf); - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_3(pyb_spi_write_readinto_obj, pyb_spi_write_readinto); - STATIC const mp_rom_map_elem_t pyb_spi_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&pyb_spi_init_obj) }, - { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&pyb_spi_read_obj) }, - { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&pyb_spi_readinto_obj) }, - { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&pyb_spi_write_obj) }, - { MP_ROM_QSTR(MP_QSTR_write_readinto), MP_ROM_PTR(&pyb_spi_write_readinto_obj) }, + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_machine_spi_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_machine_spi_readinto_obj) }, + { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_machine_spi_write_obj) }, + { MP_ROM_QSTR(MP_QSTR_write_readinto), MP_ROM_PTR(&mp_machine_spi_write_readinto_obj) }, }; STATIC MP_DEFINE_CONST_DICT(pyb_spi_locals_dict, pyb_spi_locals_dict_table); +STATIC const mp_machine_spi_p_t pyb_spi_p = { + .transfer = mp_hal_spi_transfer, +}; + const mp_obj_type_t pyb_spi_type = { { &mp_type_type }, .name = MP_QSTR_SoftSPI, .print = pyb_spi_print, .make_new = pyb_spi_make_new, + .protocol = &pyb_spi_p, .locals_dict = (mp_obj_dict_t*)&pyb_spi_locals_dict, }; diff --git a/esp8266/mpconfigport.h b/esp8266/mpconfigport.h index 63b9258a20..4fc8d856b6 100644 --- a/esp8266/mpconfigport.h +++ b/esp8266/mpconfigport.h @@ -63,6 +63,7 @@ #define MICROPY_PY_MACHINE (1) #define MICROPY_PY_MACHINE_PULSE (1) #define MICROPY_PY_MACHINE_I2C (1) +#define MICROPY_PY_MACHINE_SPI (1) #define MICROPY_PY_WEBSOCKET (1) #define MICROPY_PY_WEBREPL (1) #define MICROPY_PY_WEBREPL_DELAY (20) From 3be8b688c04d7210872d099d9d65269bbe5c13c5 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 1 Sep 2016 15:29:20 +1000 Subject: [PATCH 084/129] esp8266/modpybhspi: Simplify HSPI driver by using 1 function for xfers. --- esp8266/modpybhspi.c | 179 +++++++++++++++---------------------------- 1 file changed, 62 insertions(+), 117 deletions(-) diff --git a/esp8266/modpybhspi.c b/esp8266/modpybhspi.c index f80fbae00a..c4d4dcee8d 100644 --- a/esp8266/modpybhspi.c +++ b/esp8266/modpybhspi.c @@ -35,6 +35,7 @@ #include "py/runtime.h" #include "py/stream.h" #include "py/mphal.h" +#include "extmod/machine_spi.h" #include "hspi.h" @@ -47,6 +48,58 @@ typedef struct _pyb_hspi_obj_t { } pyb_hspi_obj_t; +STATIC void hspi_transfer(mp_obj_base_t *self_in, size_t src_len, const uint8_t *src_buf, size_t dest_len, uint8_t *dest_buf) { + (void)self_in; + + if (dest_len == 0) { + // fast case when we only need to write data + size_t chunk_size = 1024; + size_t count = src_len / chunk_size; + size_t i = 0; + for (size_t j = 0; j < count; ++j) { + for (size_t k = 0; k < chunk_size; ++k) { + spi_tx8fast(HSPI, src_buf[i]); + ++i; + } + ets_loop_iter(); + } + while (i < src_len) { + spi_tx8fast(HSPI, src_buf[i]); + ++i; + } + } else { + // we need to read and write data + + // Process data in chunks, let the pending tasks run in between + size_t chunk_size = 1024; // TODO this should depend on baudrate + size_t count = dest_len / chunk_size; + size_t i = 0; + for (size_t j = 0; j < count; ++j) { + for (size_t k = 0; k < chunk_size; ++k) { + uint32_t data_out; + if (src_len == 1) { + data_out = src_buf[0]; + } else { + data_out = src_buf[i]; + } + dest_buf[i] = spi_transaction(HSPI, 0, 0, 0, 0, 8, data_out, 8, 0); + ++i; + } + ets_loop_iter(); + } + while (i < dest_len) { + uint32_t data_out; + if (src_len == 1) { + data_out = src_buf[0]; + } else { + data_out = src_buf[i]; + } + dest_buf[i] = spi_transaction(HSPI, 0, 0, 0, 0, 8, data_out, 8, 0); + ++i; + } + } +} + /******************************************************************************/ // MicroPython bindings for HSPI @@ -126,133 +179,25 @@ STATIC mp_obj_t pyb_hspi_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_ } MP_DEFINE_CONST_FUN_OBJ_KW(pyb_hspi_init_obj, 1, pyb_hspi_init); - -STATIC mp_obj_t pyb_hspi_read(size_t n_args, const mp_obj_t *args) { - vstr_t dest_buf; - vstr_init_len(&dest_buf, mp_obj_get_int(args[1])); - uint8_t write_byte = 0; - if (n_args == 3) { - write_byte = mp_obj_get_int(args[2]); - } - // Process data in chunks, let the pending tasks run in between - size_t chunk_size = 1024; // TODO this should depend on baudrate - size_t count = dest_buf.len / chunk_size; - size_t i = 0; - for (size_t j = 0; j < count; ++j) { - for (size_t k = 0; k < chunk_size; ++k) { - ((uint8_t*)dest_buf.buf)[i] = spi_transaction(HSPI, 0, 0, 0, 0, 8, - (uint32_t)write_byte, 8, 0); - ++i; - } - ets_loop_iter(); - } - while (i < dest_buf.len) { - ((uint8_t*)dest_buf.buf)[i] = spi_transaction(HSPI, 0, 0, 0, 0, 8, - (uint32_t)write_byte, 8, 0); - ++i; - } - return mp_obj_new_str_from_vstr(&mp_type_bytes, &dest_buf); -} -MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_hspi_read_obj, 2, 3, pyb_hspi_read); - - -STATIC mp_obj_t pyb_hspi_readinto(size_t n_args, const mp_obj_t *args) { - mp_buffer_info_t dest_buf; - mp_get_buffer_raise(args[1], &dest_buf, MP_BUFFER_WRITE); - uint8_t write_byte = 0; - if (n_args == 3) { - write_byte = mp_obj_get_int(args[2]); - } - - size_t chunk_size = 1024; - size_t count = dest_buf.len / chunk_size; - size_t i = 0; - for (size_t j = 0; j < count; ++j) { - for (size_t k = 0; k < chunk_size; ++k) { - ((uint8_t*)dest_buf.buf)[i] = spi_transaction(HSPI, 0, 0, 0, 0, 8, - (uint32_t)write_byte, 8, 0); - ++i; - } - ets_loop_iter(); - } - while (i < dest_buf.len) { - ((uint8_t*)dest_buf.buf)[i] = spi_transaction(HSPI, 0, 0, 0, 0, 8, - (uint32_t)write_byte, 8, 0); - ++i; - } - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_hspi_readinto_obj, 2, 3, pyb_hspi_readinto); - - -STATIC mp_obj_t pyb_hspi_write(mp_obj_t self_in, mp_obj_t wr_buf_in) { - mp_buffer_info_t src_buf; - mp_get_buffer_raise(wr_buf_in, &src_buf, MP_BUFFER_READ); - - size_t chunk_size = 1024; - size_t count = src_buf.len / chunk_size; - size_t i = 0; - for (size_t j = 0; j < count; ++j) { - for (size_t k = 0; k < chunk_size; ++k) { - spi_tx8fast(HSPI, ((const uint8_t*)src_buf.buf)[i]); - ++i; - } - ets_loop_iter(); - } - while (i < src_buf.len) { - spi_tx8fast(HSPI, ((const uint8_t*)src_buf.buf)[i]); - ++i; - } - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_2(pyb_hspi_write_obj, pyb_hspi_write); - - -STATIC mp_obj_t pyb_hspi_write_readinto(mp_obj_t self_in, mp_obj_t wr_buf_in, mp_obj_t rd_buf_in) { - mp_buffer_info_t src_buf; - mp_get_buffer_raise(wr_buf_in, &src_buf, MP_BUFFER_READ); - mp_buffer_info_t dest_buf; - mp_get_buffer_raise(rd_buf_in, &dest_buf, MP_BUFFER_WRITE); - if (src_buf.len != dest_buf.len) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, - "buffers must be the same length")); - } - - size_t chunk_size = 1024; - size_t count = src_buf.len / chunk_size; - size_t i = 0; - for (size_t j = 0; j < count; ++j) { - for (size_t k = 0; k < chunk_size; ++k) { - ((uint8_t*)dest_buf.buf)[i] = spi_transaction(HSPI, 0, 0, 0, 0, 8, - (uint32_t)(((const uint8_t*)src_buf.buf)[i]), 8, 0); - ++i; - } - ets_loop_iter(); - } - while (i < src_buf.len) { - ((uint8_t*)dest_buf.buf)[i] = spi_transaction(HSPI, 0, 0, 0, 0, 8, - (uint32_t)(((const uint8_t*)src_buf.buf)[i]), 8, 0); - ++i; - } - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_3(pyb_hspi_write_readinto_obj, pyb_hspi_write_readinto); - - STATIC const mp_rom_map_elem_t pyb_hspi_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&pyb_hspi_init_obj) }, - { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&pyb_hspi_read_obj) }, - { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&pyb_hspi_readinto_obj) }, - { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&pyb_hspi_write_obj) }, - { MP_ROM_QSTR(MP_QSTR_write_readinto), MP_ROM_PTR(&pyb_hspi_write_readinto_obj) }, + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_machine_spi_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_machine_spi_readinto_obj) }, + { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_machine_spi_write_obj) }, + { MP_ROM_QSTR(MP_QSTR_write_readinto), MP_ROM_PTR(&mp_machine_spi_write_readinto_obj) }, }; STATIC MP_DEFINE_CONST_DICT(pyb_hspi_locals_dict, pyb_hspi_locals_dict_table); +STATIC const mp_machine_spi_p_t pyb_hspi_p = { + .transfer = hspi_transfer, +}; + const mp_obj_type_t pyb_hspi_type = { { &mp_type_type }, .name = MP_QSTR_HSPI, .print = pyb_hspi_print, .make_new = pyb_hspi_make_new, + .protocol = &pyb_hspi_p, .locals_dict = (mp_obj_dict_t*)&pyb_hspi_locals_dict, }; From 9b64d1966b831be971e6f743a7d2a93047205c05 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 1 Sep 2016 16:36:41 +1000 Subject: [PATCH 085/129] stmhal/spi: Factor out SPI transfer code to a single function. --- stmhal/spi.c | 147 +++++++++++++++++++++++++++------------------------ 1 file changed, 77 insertions(+), 70 deletions(-) diff --git a/stmhal/spi.c b/stmhal/spi.c index fbc5f9aa48..c72c3662c1 100644 --- a/stmhal/spi.c +++ b/stmhal/spi.c @@ -327,6 +327,79 @@ STATIC HAL_StatusTypeDef spi_wait_dma_finished(SPI_HandleTypeDef *spi, uint32_t return HAL_OK; } +STATIC void spi_transfer(mp_obj_base_t *self_in, size_t src_len, const uint8_t *src_buf, size_t dest_len, uint8_t *dest_buf, uint32_t timeout) { + // Note: there seems to be a problem sending 1 byte using DMA the first + // time directly after the SPI/DMA is initialised. The cause of this is + // unknown but we sidestep the issue by using polling for 1 byte transfer. + + pyb_spi_obj_t *self = (pyb_spi_obj_t*)self_in; + HAL_StatusTypeDef status; + + if (dest_len == 0) { + // send only + if (src_len == 1 || query_irq() == IRQ_STATE_DISABLED) { + status = HAL_SPI_Transmit(self->spi, (uint8_t*)src_buf, src_len, timeout); + } else { + DMA_HandleTypeDef tx_dma; + dma_init(&tx_dma, self->tx_dma_descr, self->spi); + self->spi->hdmatx = &tx_dma; + self->spi->hdmarx = NULL; + status = HAL_SPI_Transmit_DMA(self->spi, (uint8_t*)src_buf, src_len); + if (status == HAL_OK) { + status = spi_wait_dma_finished(self->spi, timeout); + } + dma_deinit(self->tx_dma_descr); + } + } else if (src_len == 0) { + // receive only + if (dest_len == 1 || query_irq() == IRQ_STATE_DISABLED) { + status = HAL_SPI_Receive(self->spi, dest_buf, dest_len, timeout); + } else { + DMA_HandleTypeDef tx_dma, rx_dma; + if (self->spi->Init.Mode == SPI_MODE_MASTER) { + // in master mode the HAL actually does a TransmitReceive call + dma_init(&tx_dma, self->tx_dma_descr, self->spi); + self->spi->hdmatx = &tx_dma; + } else { + self->spi->hdmatx = NULL; + } + dma_init(&rx_dma, self->rx_dma_descr, self->spi); + self->spi->hdmarx = &rx_dma; + + status = HAL_SPI_Receive_DMA(self->spi, dest_buf, dest_len); + if (status == HAL_OK) { + status = spi_wait_dma_finished(self->spi, timeout); + } + if (self->spi->hdmatx != NULL) { + dma_deinit(self->tx_dma_descr); + } + dma_deinit(self->rx_dma_descr); + } + } else { + // send and receive + // requires src_len==dest_len + if (src_len == 1 || query_irq() == IRQ_STATE_DISABLED) { + status = HAL_SPI_TransmitReceive(self->spi, (uint8_t*)src_buf, dest_buf, src_len, timeout); + } else { + DMA_HandleTypeDef tx_dma, rx_dma; + dma_init(&tx_dma, self->tx_dma_descr, self->spi); + self->spi->hdmatx = &tx_dma; + dma_init(&rx_dma, self->rx_dma_descr, self->spi); + self->spi->hdmarx = &rx_dma; + status = HAL_SPI_TransmitReceive_DMA(self->spi, (uint8_t*)src_buf, dest_buf, src_len); + if (status == HAL_OK) { + status = spi_wait_dma_finished(self->spi, timeout); + } + dma_deinit(self->tx_dma_descr); + dma_deinit(self->rx_dma_descr); + } + } + + if (status != HAL_OK) { + mp_hal_raise(status); + } +} + /******************************************************************************/ /* Micro Python bindings */ @@ -556,27 +629,7 @@ STATIC mp_obj_t pyb_spi_send(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_ pyb_buf_get_for_send(args[0].u_obj, &bufinfo, data); // send the data - // Note: there seems to be a problem sending 1 byte using DMA the first - // time directly after the SPI/DMA is initialised. The cause of this is - // unknown but we sidestep the issue by using polling for 1 byte transfer. - HAL_StatusTypeDef status; - if (bufinfo.len == 1 || query_irq() == IRQ_STATE_DISABLED) { - status = HAL_SPI_Transmit(self->spi, bufinfo.buf, bufinfo.len, args[1].u_int); - } else { - DMA_HandleTypeDef tx_dma; - dma_init(&tx_dma, self->tx_dma_descr, self->spi); - self->spi->hdmatx = &tx_dma; - self->spi->hdmarx = NULL; - status = HAL_SPI_Transmit_DMA(self->spi, bufinfo.buf, bufinfo.len); - if (status == HAL_OK) { - status = spi_wait_dma_finished(self->spi, args[1].u_int); - } - dma_deinit(self->tx_dma_descr); - } - - if (status != HAL_OK) { - mp_hal_raise(status); - } + spi_transfer((mp_obj_base_t*)self, bufinfo.len, bufinfo.buf, 0, NULL, args[1].u_int); return mp_const_none; } @@ -610,34 +663,7 @@ STATIC mp_obj_t pyb_spi_recv(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_ mp_obj_t o_ret = pyb_buf_get_for_recv(args[0].u_obj, &vstr); // receive the data - HAL_StatusTypeDef status; - if (vstr.len == 1 || query_irq() == IRQ_STATE_DISABLED) { - status = HAL_SPI_Receive(self->spi, (uint8_t*)vstr.buf, vstr.len, args[1].u_int); - } else { - DMA_HandleTypeDef tx_dma, rx_dma; - if (self->spi->Init.Mode == SPI_MODE_MASTER) { - // in master mode the HAL actually does a TransmitReceive call - dma_init(&tx_dma, self->tx_dma_descr, self->spi); - self->spi->hdmatx = &tx_dma; - } else { - self->spi->hdmatx = NULL; - } - dma_init(&rx_dma, self->rx_dma_descr, self->spi); - self->spi->hdmarx = &rx_dma; - - status = HAL_SPI_Receive_DMA(self->spi, (uint8_t*)vstr.buf, vstr.len); - if (status == HAL_OK) { - status = spi_wait_dma_finished(self->spi, args[1].u_int); - } - if (self->spi->hdmatx != NULL) { - dma_deinit(self->tx_dma_descr); - } - dma_deinit(self->rx_dma_descr); - } - - if (status != HAL_OK) { - mp_hal_raise(status); - } + spi_transfer((mp_obj_base_t*)self, 0, NULL, vstr.len, (uint8_t*)vstr.buf, args[1].u_int); // return the received data if (o_ret != MP_OBJ_NULL) { @@ -706,27 +732,8 @@ STATIC mp_obj_t pyb_spi_send_recv(mp_uint_t n_args, const mp_obj_t *pos_args, mp } } - // send and receive the data - HAL_StatusTypeDef status; - if (bufinfo_send.len == 1 || query_irq() == IRQ_STATE_DISABLED) { - status = HAL_SPI_TransmitReceive(self->spi, bufinfo_send.buf, bufinfo_recv.buf, bufinfo_send.len, args[2].u_int); - } else { - DMA_HandleTypeDef tx_dma, rx_dma; - dma_init(&tx_dma, self->tx_dma_descr, self->spi); - self->spi->hdmatx = &tx_dma; - dma_init(&rx_dma, self->rx_dma_descr, self->spi); - self->spi->hdmarx = &rx_dma; - status = HAL_SPI_TransmitReceive_DMA(self->spi, bufinfo_send.buf, bufinfo_recv.buf, bufinfo_send.len); - if (status == HAL_OK) { - status = spi_wait_dma_finished(self->spi, args[2].u_int); - } - dma_deinit(self->tx_dma_descr); - dma_deinit(self->rx_dma_descr); - } - - if (status != HAL_OK) { - mp_hal_raise(status); - } + // do the transfer + spi_transfer((mp_obj_base_t*)self, bufinfo_send.len, bufinfo_send.buf, bufinfo_recv.len, bufinfo_recv.buf, args[2].u_int); // return the received data if (o_ret != MP_OBJ_NULL) { From 49406b0ac6a10406e1505d3fda2447571649f853 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 1 Sep 2016 16:37:15 +1000 Subject: [PATCH 086/129] stmhal/spi: Support new machine SPI methods in legacy SPI object. --- stmhal/mpconfigport.h | 1 + stmhal/spi.c | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/stmhal/mpconfigport.h b/stmhal/mpconfigport.h index 3122a90655..98d1e17e3d 100644 --- a/stmhal/mpconfigport.h +++ b/stmhal/mpconfigport.h @@ -93,6 +93,7 @@ #define MICROPY_PY_UHASHLIB (1) #define MICROPY_PY_MACHINE (1) #define MICROPY_PY_MACHINE_I2C (1) +#define MICROPY_PY_MACHINE_SPI (1) #define MICROPY_PY_FRAMEBUF (1) #define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (1) diff --git a/stmhal/spi.c b/stmhal/spi.c index c72c3662c1..85f1709200 100644 --- a/stmhal/spi.c +++ b/stmhal/spi.c @@ -30,6 +30,7 @@ #include "py/nlr.h" #include "py/runtime.h" #include "py/mphal.h" +#include "extmod/machine_spi.h" #include "irq.h" #include "pin.h" #include "genhdr/pins.h" @@ -400,6 +401,17 @@ STATIC void spi_transfer(mp_obj_base_t *self_in, size_t src_len, const uint8_t * } } +STATIC void spi_transfer_machine(mp_obj_base_t *self_in, size_t src_len, const uint8_t *src_buf, size_t dest_len, uint8_t *dest_buf) { + if (src_len == 1 && dest_len > 1) { + // this catches read and readinto + // copy the single output byte to the dest buffer and use that as source + memset(dest_buf, src_buf[0], dest_len); + src_len = dest_len; + src_buf = dest_buf; + } + spi_transfer(self_in, src_len, src_buf, dest_len, dest_buf, 100); +} + /******************************************************************************/ /* Micro Python bindings */ @@ -748,6 +760,13 @@ STATIC const mp_map_elem_t pyb_spi_locals_dict_table[] = { // instance methods { MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)&pyb_spi_init_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_deinit), (mp_obj_t)&pyb_spi_deinit_obj }, + + { MP_OBJ_NEW_QSTR(MP_QSTR_read), (mp_obj_t)&mp_machine_spi_read_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_readinto), (mp_obj_t)&mp_machine_spi_readinto_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_write), (mp_obj_t)&mp_machine_spi_write_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_write_readinto), (mp_obj_t)&mp_machine_spi_write_readinto_obj }, + + // legacy methods { MP_OBJ_NEW_QSTR(MP_QSTR_send), (mp_obj_t)&pyb_spi_send_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_recv), (mp_obj_t)&pyb_spi_recv_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_send_recv), (mp_obj_t)&pyb_spi_send_recv_obj }, @@ -773,10 +792,15 @@ STATIC const mp_map_elem_t pyb_spi_locals_dict_table[] = { STATIC MP_DEFINE_CONST_DICT(pyb_spi_locals_dict, pyb_spi_locals_dict_table); +STATIC const mp_machine_spi_p_t pyb_spi_p = { + .transfer = spi_transfer_machine, +}; + const mp_obj_type_t pyb_spi_type = { { &mp_type_type }, .name = MP_QSTR_SPI, .print = pyb_spi_print, .make_new = pyb_spi_make_new, + .protocol = &pyb_spi_p, .locals_dict = (mp_obj_t)&pyb_spi_locals_dict, }; From ce1c786297e69df4a82e83ac379f8ef068e709f6 Mon Sep 17 00:00:00 2001 From: Radomir Dopieralski Date: Thu, 25 Aug 2016 10:54:59 +0200 Subject: [PATCH 087/129] drivers/sdcard: Port the SDCard driver to new machine API. With backwards compatibility for pyboard. --- drivers/sdcard/sdcard.py | 139 ++++++++++++++++++++++----------------- 1 file changed, 79 insertions(+), 60 deletions(-) diff --git a/drivers/sdcard/sdcard.py b/drivers/sdcard/sdcard.py index fba383ae39..fc7a8af7c5 100644 --- a/drivers/sdcard/sdcard.py +++ b/drivers/sdcard/sdcard.py @@ -4,31 +4,41 @@ Micro Python driver for SD cards using SPI bus. Requires an SPI bus and a CS pin. Provides readblocks and writeblocks methods so the device can be mounted as a filesystem. -Example usage: +Example usage on pyboard: import pyb, sdcard, os sd = sdcard.SDCard(pyb.SPI(1), pyb.Pin.board.X5) pyb.mount(sd, '/sd2') os.listdir('/') +Example usage on ESP8266: + + import machine, sdcard, os + sd = sdcard.SDCard(machine.SPI(0), machine.Pin(15)) + os.umount() + os.VfsFat(sd, "") + os.listdir() + """ -import pyb +import time + + +_CMD_TIMEOUT = const(100) + +_R1_IDLE_STATE = const(1 << 0) +#R1_ERASE_RESET = const(1 << 1) +_R1_ILLEGAL_COMMAND = const(1 << 2) +#R1_COM_CRC_ERROR = const(1 << 3) +#R1_ERASE_SEQUENCE_ERROR = const(1 << 4) +#R1_ADDRESS_ERROR = const(1 << 5) +#R1_PARAMETER_ERROR = const(1 << 6) +_TOKEN_CMD25 = const(0xfc) +_TOKEN_STOP_TRAN = const(0xfd) +_TOKEN_DATA = const(0xfe) + class SDCard: - CMD_TIMEOUT = const(100) - - R1_IDLE_STATE = const(1 << 0) - #R1_ERASE_RESET = const(1 << 1) - R1_ILLEGAL_COMMAND = const(1 << 2) - #R1_COM_CRC_ERROR = const(1 << 3) - #R1_ERASE_SEQUENCE_ERROR = const(1 << 4) - #R1_ADDRESS_ERROR = const(1 << 5) - #R1_PARAMETER_ERROR = const(1 << 6) - TOKEN_CMD25 = const(0xfc) - TOKEN_STOP_TRAN = const(0xfd) - TOKEN_DATA = const(0xfe) - def __init__(self, spi, cs): self.spi = spi self.cs = cs @@ -42,30 +52,39 @@ class SDCard: # initialise the card self.init_card() + def init_spi(self, baudrate): + try: + master = self.spi.MASTER + except AttributeError: + # on ESP8266 + self.spi.init(baudrate=baudrate, phase=0, polarity=0) + else: + # on pyboard + self.spi.init(master, baudrate=baudrate, phase=0, polarity=0) + def init_card(self): # init CS pin - self.cs.high() - self.cs.init(self.cs.OUT_PP) + self.cs.init(self.cs.OUT, value=1) # init SPI bus; use low data rate for initialisation - self.spi.init(self.spi.MASTER, baudrate=100000, phase=0, polarity=0) + self.init_spi(100000) # clock card at least 100 cycles with cs high for i in range(16): - self.spi.send(0xff) + self.spi.write(b'\xff') - # CMD0: init card; should return R1_IDLE_STATE (allow 5 attempts) + # CMD0: init card; should return _R1_IDLE_STATE (allow 5 attempts) for _ in range(5): - if self.cmd(0, 0, 0x95) == R1_IDLE_STATE: + if self.cmd(0, 0, 0x95) == _R1_IDLE_STATE: break else: raise OSError("no SD card") # CMD8: determine card version r = self.cmd(8, 0x01aa, 0x87, 4) - if r == R1_IDLE_STATE: + if r == _R1_IDLE_STATE: self.init_card_v2() - elif r == (R1_IDLE_STATE | R1_ILLEGAL_COMMAND): + elif r == (_R1_IDLE_STATE | _R1_ILLEGAL_COMMAND): self.init_card_v1() else: raise OSError("couldn't determine SD card version") @@ -86,10 +105,10 @@ class SDCard: raise OSError("can't set 512 block size") # set to high data rate now that it's initialised - self.spi.init(self.spi.MASTER, baudrate=1320000, phase=0, polarity=0) + self.init_spi(1320000) def init_card_v1(self): - for i in range(CMD_TIMEOUT): + for i in range(_CMD_TIMEOUT): self.cmd(55, 0, 0) if self.cmd(41, 0, 0) == 0: self.cdv = 512 @@ -98,8 +117,8 @@ class SDCard: raise OSError("timeout waiting for v1 card") def init_card_v2(self): - for i in range(CMD_TIMEOUT): - pyb.delay(50) + for i in range(_CMD_TIMEOUT): + time.sleep_ms(50) self.cmd(58, 0, 0, 4) self.cmd(55, 0, 0) if self.cmd(41, 0x40000000, 0) == 0: @@ -120,87 +139,87 @@ class SDCard: buf[3] = arg >> 8 buf[4] = arg buf[5] = crc - self.spi.send(buf) + self.spi.write(buf) # wait for the repsonse (response[7] == 0) - for i in range(CMD_TIMEOUT): - response = self.spi.send_recv(0xff)[0] + for i in range(_CMD_TIMEOUT): + response = self.spi.read(1, 0xff)[0] if not (response & 0x80): # this could be a big-endian integer that we are getting here for j in range(final): - self.spi.send(0xff) + self.spi.write(b'\xff') if release: self.cs.high() - self.spi.send(0xff) + self.spi.write(b'\xff') return response # timeout self.cs.high() - self.spi.send(0xff) + self.spi.write(b'\xff') return -1 def cmd_nodata(self, cmd): - self.spi.send(cmd) - self.spi.send_recv(0xff) # ignore stuff byte - for _ in range(CMD_TIMEOUT): - if self.spi.send_recv(0xff)[0] == 0xff: + self.spi.write(cmd) + self.spi.read(1, 0xff) # ignore stuff byte + for _ in range(_CMD_TIMEOUT): + if self.spi.read(1, 0xff)[0] == 0xff: self.cs.high() - self.spi.send(0xff) + self.spi.write(b'\xff') return 0 # OK self.cs.high() - self.spi.send(0xff) + self.spi.write(b'\xff') return 1 # timeout def readinto(self, buf): self.cs.low() # read until start byte (0xff) - while self.spi.send_recv(0xff)[0] != 0xfe: + while self.spi.read(1, 0xff)[0] != 0xfe: pass # read data mv = self.dummybuf_memoryview[:len(buf)] - self.spi.send_recv(mv, recv=buf) + self.spi.write_readinto(mv, buf) # read checksum - self.spi.send(0xff) - self.spi.send(0xff) + self.spi.write(b'\xff') + self.spi.write(b'\xff') self.cs.high() - self.spi.send(0xff) + self.spi.write(b'\xff') def write(self, token, buf): self.cs.low() # send: start of block, data, checksum - self.spi.send(token) - self.spi.send(buf) - self.spi.send(0xff) - self.spi.send(0xff) + self.spi.read(1, token) + self.spi.write(buf) + self.spi.write(b'\xff') + self.spi.write(b'\xff') # check the response - if (self.spi.send_recv(0xff)[0] & 0x1f) != 0x05: + if (self.spi.read(1, 0xff)[0] & 0x1f) != 0x05: self.cs.high() - self.spi.send(0xff) + self.spi.write(b'\xff') return # wait for write to finish - while self.spi.send_recv(0xff)[0] == 0: + while self.spi.read(1, 0xff)[0] == 0: pass self.cs.high() - self.spi.send(0xff) + self.spi.write(b'\xff') def write_token(self, token): self.cs.low() - self.spi.send(token) - self.spi.send(0xff) + self.spi.read(1, token) + self.spi.write(b'\xff') # wait for write to finish - while self.spi.send_recv(0xff)[0] == 0: + while self.spi.read(1, 0xff)[0] == 0x00: pass self.cs.high() - self.spi.send(0xff) + self.spi.write(b'\xff') def count(self): return self.sectors @@ -224,7 +243,7 @@ class SDCard: self.readinto(mv[offset : offset + 512]) offset += 512 nblocks -= 1 - return self.cmd_nodata(12) + return self.cmd_nodata(b'\x0c') # cmd 12 return 0 def writeblocks(self, block_num, buf): @@ -236,7 +255,7 @@ class SDCard: return 1 # send the data - self.write(TOKEN_DATA, buf) + self.write(_TOKEN_DATA, buf) else: # CMD25: set write address for first block if self.cmd(25, block_num * self.cdv, 0) != 0: @@ -245,8 +264,8 @@ class SDCard: offset = 0 mv = memoryview(buf) while nblocks: - self.write(TOKEN_CMD25, mv[offset : offset + 512]) + self.write(_TOKEN_CMD25, mv[offset : offset + 512]) offset += 512 nblocks -= 1 - self.write_token(TOKEN_STOP_TRAN) + self.write_token(_TOKEN_STOP_TRAN) return 0 From f98bb2ddcbfed7033ae93ae8fe98b0540a9fb42f Mon Sep 17 00:00:00 2001 From: Delio Brignoli Date: Sat, 20 Aug 2016 10:51:28 +0200 Subject: [PATCH 088/129] py/mpprint: Fail an assertion with unsupported format specifiers. Arguments of an unknown type cannot be skipped and continuing to parse a format string after encountering an unknown format specifier leads to undefined behaviour. This patch helps to find use of unsupported formats. --- py/mpprint.c | 4 +++- tests/unix/extra_coverage.py.exp | 1 - unix/coverage.c | 2 -- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/py/mpprint.c b/py/mpprint.c index cb49b1227a..97ea33ad2a 100644 --- a/py/mpprint.c +++ b/py/mpprint.c @@ -537,10 +537,12 @@ int mp_vprintf(const mp_print_t *print, const char *fmt, va_list args) { chrs += mp_print_int(print, arg_value, *fmt == 'd', 10, 'a', flags, fill, width); break; } - // fall through to default case to print unknown format char + assert(!"unsupported fmt char"); } #endif default: + // if it's not %% then it's an unsupported format character + assert(*fmt == '%' || !"unsupported fmt char"); print->print_strn(print->data, fmt, 1); chrs += 1; break; diff --git a/tests/unix/extra_coverage.py.exp b/tests/unix/extra_coverage.py.exp index db282b152c..44749c45ea 100644 --- a/tests/unix/extra_coverage.py.exp +++ b/tests/unix/extra_coverage.py.exp @@ -7,7 +7,6 @@ ab abc false true (null) -t -2147483648 2147483648 80000000 diff --git a/unix/coverage.c b/unix/coverage.c index 9d53725543..ce1da50e2f 100644 --- a/unix/coverage.c +++ b/unix/coverage.c @@ -12,7 +12,6 @@ STATIC mp_obj_t extra_coverage(void) { // mp_printf (used by ports that don't have a native printf) { mp_printf(&mp_plat_print, "# mp_printf\n"); - mp_printf(&mp_plat_print, "%"); // nothing after percent mp_printf(&mp_plat_print, "%d %+d % d\n", -123, 123, 123); // sign mp_printf(&mp_plat_print, "%05d\n", -123); // negative number with zero padding mp_printf(&mp_plat_print, "%ld\n", 123); // long @@ -21,7 +20,6 @@ STATIC mp_obj_t extra_coverage(void) { mp_printf(&mp_plat_print, "%.*s\n", -1, "abc"); // negative string precision mp_printf(&mp_plat_print, "%b %b\n", 0, 1); // bools mp_printf(&mp_plat_print, "%s\n", NULL); // null string - mp_printf(&mp_plat_print, "%t\n"); // non-format char mp_printf(&mp_plat_print, "%d\n", 0x80000000); // should print signed mp_printf(&mp_plat_print, "%u\n", 0x80000000); // should print unsigned mp_printf(&mp_plat_print, "%x\n", 0x80000000); // should print unsigned From f127bef3e41f25eea6da73a52aab2fdc53be2464 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 2 Sep 2016 14:32:47 +1000 Subject: [PATCH 089/129] py/makeqstrdata.py: Compute the qstr hash from bytes, not characters. --- py/makeqstrdata.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/py/makeqstrdata.py b/py/makeqstrdata.py index 8a3136b1f1..7249769f47 100644 --- a/py/makeqstrdata.py +++ b/py/makeqstrdata.py @@ -14,11 +14,13 @@ import sys # - codepoint2name lives in a different module import platform if platform.python_version_tuple()[0] == '2': - ord_bytes = ord + bytes_cons = lambda val, enc=None: bytearray(val) from htmlentitydefs import codepoint2name elif platform.python_version_tuple()[0] == '3': - ord_bytes = lambda x:x + bytes_cons = bytes from html.entities import codepoint2name +# end compatibility code + codepoint2name[ord('-')] = 'hyphen'; # add some custom names to map characters that aren't in HTML @@ -52,8 +54,8 @@ codepoint2name[ord('~')] = 'tilde' # this must match the equivalent function in qstr.c def compute_hash(qstr, bytes_hash): hash = 5381 - for char in qstr: - hash = (hash * 33) ^ ord(char) + for b in qstr: + hash = (hash * 33) ^ b # Make sure that valid hash is never zero, zero means "hash not computed" return (hash & ((1 << (8 * bytes_hash)) - 1)) or 1 @@ -115,16 +117,15 @@ def parse_input_headers(infiles): return qcfgs, qstrs def make_bytes(cfg_bytes_len, cfg_bytes_hash, qstr): - qhash = compute_hash(qstr, cfg_bytes_hash) + qbytes = bytes_cons(qstr, 'utf8') + qlen = len(qbytes) + qhash = compute_hash(qbytes, cfg_bytes_hash) if all(32 <= ord(c) <= 126 and c != '\\' and c != '"' for c in qstr): # qstr is all printable ASCII so render it as-is (for easier debugging) - qlen = len(qstr) qdata = qstr else: # qstr contains non-printable codes so render entire thing as hex pairs - qbytes = qstr.encode('utf8') - qlen = len(qbytes) - qdata = ''.join(('\\x%02x' % ord_bytes(b)) for b in qbytes) + qdata = ''.join(('\\x%02x' % b) for b in qbytes) if qlen >= (1 << (8 * cfg_bytes_len)): print('qstr is too long:', qstr) assert False From 5f3bda422a18d49fb282a93968b658c568343b7d Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 2 Sep 2016 14:42:53 +1000 Subject: [PATCH 090/129] py: If str/bytes hash is 0 then explicitly compute it. --- py/objstr.c | 6 ++++++ py/objstr.h | 1 + py/runtime.c | 4 ++++ 3 files changed, 11 insertions(+) diff --git a/py/objstr.c b/py/objstr.c index e83ff7c844..406ccf290a 100644 --- a/py/objstr.c +++ b/py/objstr.c @@ -158,6 +158,9 @@ mp_obj_t mp_obj_str_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_ if (MP_OBJ_IS_TYPE(args[0], &mp_type_bytes)) { GET_STR_DATA_LEN(args[0], str_data, str_len); GET_STR_HASH(args[0], str_hash); + if (str_hash == 0) { + str_hash = qstr_compute_hash(str_data, str_len); + } mp_obj_str_t *o = MP_OBJ_TO_PTR(mp_obj_new_str_of_type(type, NULL, str_len)); o->data = str_data; o->hash = str_hash; @@ -191,6 +194,9 @@ STATIC mp_obj_t bytes_make_new(const mp_obj_type_t *type_in, size_t n_args, size } GET_STR_DATA_LEN(args[0], str_data, str_len); GET_STR_HASH(args[0], str_hash); + if (str_hash == 0) { + str_hash = qstr_compute_hash(str_data, str_len); + } mp_obj_str_t *o = MP_OBJ_TO_PTR(mp_obj_new_str_of_type(&mp_type_bytes, NULL, str_len)); o->data = str_data; o->hash = str_hash; diff --git a/py/objstr.h b/py/objstr.h index 07929156cb..e14568dac4 100644 --- a/py/objstr.h +++ b/py/objstr.h @@ -39,6 +39,7 @@ typedef struct _mp_obj_str_t { #define MP_DEFINE_STR_OBJ(obj_name, str) mp_obj_str_t obj_name = {{&mp_type_str}, 0, sizeof(str) - 1, (const byte*)str} // use this macro to extract the string hash +// warning: the hash can be 0, meaning invalid, and must then be explicitly computed from the data #define GET_STR_HASH(str_obj_in, str_hash) \ mp_uint_t str_hash; if (MP_OBJ_IS_QSTR(str_obj_in)) \ { str_hash = qstr_hash(MP_OBJ_QSTR_VALUE(str_obj_in)); } else { str_hash = ((mp_obj_str_t*)MP_OBJ_TO_PTR(str_obj_in))->hash; } diff --git a/py/runtime.c b/py/runtime.c index 04b3a34de4..48e815f0fa 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -217,6 +217,10 @@ mp_obj_t mp_unary_op(mp_uint_t op, mp_obj_t arg) { } else if (op == MP_UNARY_OP_HASH && MP_OBJ_IS_STR_OR_BYTES(arg)) { // fast path for hashing str/bytes GET_STR_HASH(arg, h); + if (h == 0) { + GET_STR_DATA_LEN(arg, data, len); + h = qstr_compute_hash(data, len); + } return MP_OBJ_NEW_SMALL_INT(h); } else { mp_obj_type_t *type = mp_obj_get_type(arg); From 58f386135813ab6e55641bec6eae32cc0fd35115 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 2 Sep 2016 15:07:42 +1000 Subject: [PATCH 091/129] tests/unix/extra_coverage: Add test for str/bytes with invalid hash. --- tests/unix/extra_coverage.py | 9 ++++++++- tests/unix/extra_coverage.py.exp | 5 +++++ unix/coverage.c | 9 ++++++++- 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/tests/unix/extra_coverage.py b/tests/unix/extra_coverage.py index 8f330f1da2..72bcc9994a 100644 --- a/tests/unix/extra_coverage.py +++ b/tests/unix/extra_coverage.py @@ -5,4 +5,11 @@ except NameError: import sys sys.exit() -extra_coverage() +data = extra_coverage() + +# test hashing of str/bytes that have an invalid hash +print(data) +print(hash(data[0])) +print(hash(data[1])) +print(hash(bytes(data[0], 'utf8'))) +print(hash(str(data[1], 'utf8'))) diff --git a/tests/unix/extra_coverage.py.exp b/tests/unix/extra_coverage.py.exp index 44749c45ea..ea73a54e4c 100644 --- a/tests/unix/extra_coverage.py.exp +++ b/tests/unix/extra_coverage.py.exp @@ -35,3 +35,8 @@ ementation 12345678 0 0 +('0123456789', b'0123456789') +7300 +7300 +7300 +7300 diff --git a/unix/coverage.c b/unix/coverage.c index ce1da50e2f..c84a653f75 100644 --- a/unix/coverage.c +++ b/unix/coverage.c @@ -1,12 +1,17 @@ #include #include "py/obj.h" +#include "py/objstr.h" #include "py/runtime.h" #include "py/repl.h" #include "py/mpz.h" #if defined(MICROPY_UNIX_COVERAGE) +// str/bytes objects without a valid hash +STATIC const mp_obj_str_t str_no_hash_obj = {{&mp_type_str}, 0, 10, (const byte*)"0123456789"}; +STATIC const mp_obj_str_t bytes_no_hash_obj = {{&mp_type_bytes}, 0, 10, (const byte*)"0123456789"}; + // function to run extra tests for things that can't be checked by scripts STATIC mp_obj_t extra_coverage(void) { // mp_printf (used by ports that don't have a native printf) @@ -109,7 +114,9 @@ STATIC mp_obj_t extra_coverage(void) { mp_printf(&mp_plat_print, "%d\n", mpz_as_uint_checked(&mpz, &value)); } - return mp_const_none; + // return a tuple of data for testing on the Python side + mp_obj_t items[] = {(mp_obj_t)&str_no_hash_obj, (mp_obj_t)&bytes_no_hash_obj}; + return mp_obj_new_tuple(MP_ARRAY_SIZE(items), items); } MP_DEFINE_CONST_FUN_OBJ_0(extra_coverage_obj, extra_coverage); From b4790afdafaf243ca7a1ec250917f30ed00a2d2d Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 2 Sep 2016 15:09:21 +1000 Subject: [PATCH 092/129] tools/mpy-tool.py: Store qstr config values in global config object. Makes it easier to access them without passing around another dict of the config values. --- tools/mpy-tool.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/tools/mpy-tool.py b/tools/mpy-tool.py index a7c3d8f918..c5bbf88e8b 100755 --- a/tools/mpy-tool.py +++ b/tools/mpy-tool.py @@ -444,10 +444,7 @@ def dump_mpy(raw_codes): for rc in raw_codes: rc.dump() -def freeze_mpy(qcfgs, base_qstrs, raw_codes): - cfg_bytes_len = int(qcfgs['BYTES_IN_LEN']) - cfg_bytes_hash = int(qcfgs['BYTES_IN_HASH']) - +def freeze_mpy(base_qstrs, raw_codes): # add to qstrs new = {} for q in global_qstrs: @@ -505,7 +502,8 @@ def freeze_mpy(qcfgs, base_qstrs, raw_codes): print(' %u, // used entries' % len(new)) print(' {') for _, _, qstr in new: - print(' %s,' % qstrutil.make_bytes(cfg_bytes_len, cfg_bytes_hash, qstr)) + print(' %s,' + % qstrutil.make_bytes(config.MICROPY_QSTR_BYTES_IN_LEN, config.MICROPY_QSTR_BYTES_IN_HASH, qstr)) print(' },') print('};') @@ -549,10 +547,15 @@ def main(): }[args.mlongint_impl] config.MPZ_DIG_SIZE = args.mmpz_dig_size + # set config values for qstrs, and get the existing base set of qstrs if args.qstr_header: qcfgs, base_qstrs = qstrutil.parse_input_headers([args.qstr_header]) + config.MICROPY_QSTR_BYTES_IN_LEN = int(qcfgs['BYTES_IN_LEN']) + config.MICROPY_QSTR_BYTES_IN_HASH = int(qcfgs['BYTES_IN_HASH']) else: - qcfgs, base_qstrs = {'BYTES_IN_LEN':1, 'BYTES_IN_HASH':1}, {} + config.MICROPY_QSTR_BYTES_IN_LEN = 1 + config.MICROPY_QSTR_BYTES_IN_HASH = 1 + base_qstrs = {} raw_codes = [read_mpy(file) for file in args.files] @@ -560,7 +563,7 @@ def main(): dump_mpy(raw_codes) elif args.freeze: try: - freeze_mpy(qcfgs, base_qstrs, raw_codes) + freeze_mpy(base_qstrs, raw_codes) except FreezeError as er: print(er, file=sys.stderr) sys.exit(1) From b6bdf18debfd75e9d39c2e8452c7b4ade448bcc5 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 2 Sep 2016 15:10:45 +1000 Subject: [PATCH 093/129] tools/mpy-tool.py: Compute the hash value for str/bytes objects. This makes it more efficient at runtime to hash str/bytes objects. --- tools/mpy-tool.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tools/mpy-tool.py b/tools/mpy-tool.py index c5bbf88e8b..bfb2a5da79 100755 --- a/tools/mpy-tool.py +++ b/tools/mpy-tool.py @@ -283,15 +283,15 @@ class RawCode: # generate constant objects for i, obj in enumerate(self.objs): obj_name = 'const_obj_%s_%u' % (self.escaped_name, i) - if is_str_type(obj): - obj = bytes_cons(obj, 'utf8') - print('STATIC const mp_obj_str_t %s = ' - '{{&mp_type_str}, 0, %u, (const byte*)"%s"};' - % (obj_name, len(obj), ''.join(('\\x%02x' % b) for b in obj))) - elif is_bytes_type(obj): - print('STATIC const mp_obj_str_t %s = ' - '{{&mp_type_bytes}, 0, %u, (const byte*)"%s"};' - % (obj_name, len(obj), ''.join(('\\x%02x' % b) for b in obj))) + if is_str_type(obj) or is_bytes_type(obj): + if is_str_type(obj): + obj = bytes_cons(obj, 'utf8') + obj_type = 'mp_type_str' + else: + obj_type = 'mp_type_bytes' + print('STATIC const mp_obj_str_t %s = {{&%s}, %u, %u, (const byte*)"%s"};' + % (obj_name, obj_type, qstrutil.compute_hash(obj, config.MICROPY_QSTR_BYTES_IN_HASH), + len(obj), ''.join(('\\x%02x' % b) for b in obj))) elif is_int_type(obj): if config.MICROPY_LONGINT_IMPL == config.MICROPY_LONGINT_IMPL_NONE: # TODO check if we can actually fit this long-int into a small-int From 41ec22632da8f61ca5c841e13206258048d1be5b Mon Sep 17 00:00:00 2001 From: Radomir Dopieralski Date: Sun, 28 Aug 2016 19:13:32 +0200 Subject: [PATCH 094/129] extmod/modframebuf: Fix fill and scroll when height not divisible by 8. There was a bug in `framebuf1_fill` function, that makes it leave a few lines unfilled at the bottom if the height is not divisible by 8. A similar bug is fixed in the scroll method. --- extmod/modframebuf.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/extmod/modframebuf.c b/extmod/modframebuf.c index a1e7c079be..84f1246fba 100644 --- a/extmod/modframebuf.c +++ b/extmod/modframebuf.c @@ -68,7 +68,8 @@ STATIC mp_obj_t framebuf1_fill(mp_obj_t self_in, mp_obj_t col_in) { if (col) { col = 0xff; } - for (int y = 0; y < self->height / 8; ++y) { + int end = (self->height + 7) >> 3; + for (int y = 0; y < end; ++y) { memset(self->buf + y * self->stride, col, self->width); } return mp_const_none; @@ -101,8 +102,9 @@ STATIC mp_obj_t framebuf1_scroll(mp_obj_t self_in, mp_obj_t xstep_in, mp_obj_t y mp_obj_framebuf1_t *self = MP_OBJ_TO_PTR(self_in); mp_int_t xstep = mp_obj_get_int(xstep_in); mp_int_t ystep = mp_obj_get_int(ystep_in); + int end = (self->height + 7) >> 3; if (xstep == 0 && ystep > 0) { - for (int y = self->height / 8; y > 0;) { + for (int y = end; y > 0;) { --y; for (int x = 0; x < self->width; ++x) { int prev = 0; @@ -113,10 +115,10 @@ STATIC mp_obj_t framebuf1_scroll(mp_obj_t self_in, mp_obj_t xstep_in, mp_obj_t y } } } else if (xstep == 0 && ystep < 0) { - for (int y = 0; y < self->height / 8; ++y) { + for (int y = 0; y < end; ++y) { for (int x = 0; x < self->width; ++x) { int prev = 0; - if (y + 1 < self->height / 8) { + if (y + 1 < end) { prev = self->buf[(y + 1) * self->stride + x] << (8 + ystep); } self->buf[y * self->stride + x] = (self->buf[y * self->stride + x] >> -ystep) | prev; From c51c883cc84bb680dcc810a81e81dd1df879a07c Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 3 Sep 2016 00:19:02 +1000 Subject: [PATCH 095/129] tools/mpy-tool.py: Support freezing of complex numbers. --- tools/mpy-tool.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tools/mpy-tool.py b/tools/mpy-tool.py index bfb2a5da79..bc8ac4fbd3 100755 --- a/tools/mpy-tool.py +++ b/tools/mpy-tool.py @@ -320,6 +320,9 @@ class RawCode: print('STATIC const mp_obj_float_t %s = {{&mp_type_float}, %.16g};' % (obj_name, obj)) print('#endif') + elif type(obj) is complex: + print('STATIC const mp_obj_complex_t %s = {{&mp_type_complex}, %.16g, %.16g};' + % (obj_name, obj.real, obj.imag)) else: # TODO raise FreezeError(self, 'freezing of object %r is not implemented' % (obj,)) @@ -485,6 +488,15 @@ def freeze_mpy(base_qstrs, raw_codes): print('#endif') print() + print('#if MICROPY_PY_BUILTINS_COMPLEX') + print('typedef struct _mp_obj_complex_t {') + print(' mp_obj_base_t base;') + print(' mp_float_t real;') + print(' mp_float_t imag;') + print('} mp_obj_complex_t;') + print('#endif') + print() + print('enum {') for i in range(len(new)): if i == 0: From a6864a13c7e82e182e36dab8fb350fb2f7ece766 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sat, 3 Sep 2016 00:07:08 +0300 Subject: [PATCH 096/129] extmod/moduzlib: Implement zlib stream decompressor class, DecompIO. --- extmod/moduzlib.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 82 insertions(+), 1 deletion(-) diff --git a/extmod/moduzlib.c b/extmod/moduzlib.c index b733ae2e04..7fc655fdaf 100644 --- a/extmod/moduzlib.c +++ b/extmod/moduzlib.c @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2014 Paul Sokolovsky + * Copyright (c) 2014-2016 Paul Sokolovsky * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -29,6 +29,7 @@ #include "py/nlr.h" #include "py/runtime.h" +#include "py/stream.h" #if MICROPY_PY_UZLIB @@ -40,6 +41,85 @@ #define DEBUG_printf(...) (void)0 #endif +typedef struct _mp_obj_decompio_t { + mp_obj_base_t base; + mp_obj_t src_stream; + TINF_DATA decomp; + bool eof; +} mp_obj_decompio_t; + +STATIC unsigned char read_src_stream(TINF_DATA *data) { + byte *p = (void*)data; + p -= offsetof(mp_obj_decompio_t, decomp); + mp_obj_decompio_t *self = (mp_obj_decompio_t*)p; + + const mp_stream_p_t *stream = mp_get_stream_raise(self->src_stream, MP_STREAM_OP_READ); + int err; + byte c; + mp_uint_t out_sz = stream->read(self->src_stream, &c, 1, &err); + if (out_sz == MP_STREAM_ERROR) { + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(err))); + } + if (out_sz == 0) { + nlr_raise(mp_obj_new_exception(&mp_type_EOFError)); + } + return c; +} + +#define DICT_SIZE 32768 + +STATIC mp_obj_t decompio_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 1, 1, false); + mp_obj_decompio_t *o = m_new_obj(mp_obj_decompio_t); + o->base.type = type; + memset(&o->decomp, 0, sizeof(o->decomp)); + uzlib_uncompress_init(&o->decomp, m_new(byte, DICT_SIZE), DICT_SIZE); + o->decomp.readSource = read_src_stream; + o->src_stream = args[0]; + o->eof = false; + return MP_OBJ_FROM_PTR(o); +} + +STATIC mp_uint_t decompio_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) { + mp_obj_decompio_t *o = MP_OBJ_TO_PTR(o_in); + if (o->eof) { + return 0; + } + + o->decomp.dest = buf; + o->decomp.destSize = size; + int st = uzlib_uncompress_chksum(&o->decomp); + if (st == TINF_DONE) { + o->eof = true; + } + if (st < 0) { + *errcode = EINVAL; + return MP_STREAM_ERROR; + } + return o->decomp.dest - (byte*)buf; +} + +STATIC const mp_rom_map_elem_t decompio_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_readall), MP_ROM_PTR(&mp_stream_readall_obj) }, + { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) }, + { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(decompio_locals_dict, decompio_locals_dict_table); + +STATIC const mp_stream_p_t decompio_stream_p = { + .read = decompio_read, +}; + +STATIC const mp_obj_type_t decompio_type = { + { &mp_type_type }, + .name = MP_QSTR_DecompIO, + .make_new = decompio_make_new, + .protocol = &decompio_stream_p, + .locals_dict = (void*)&decompio_locals_dict, +}; + STATIC mp_obj_t mod_uzlib_decompress(size_t n_args, const mp_obj_t *args) { (void)n_args; mp_obj_t data = args[0]; @@ -102,6 +182,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_uzlib_decompress_obj, 1, 3, mod_u STATIC const mp_rom_map_elem_t mp_module_uzlib_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uzlib) }, { MP_ROM_QSTR(MP_QSTR_decompress), MP_ROM_PTR(&mod_uzlib_decompress_obj) }, + { MP_ROM_QSTR(MP_QSTR_DecompIO), MP_ROM_PTR(&decompio_type) }, }; STATIC MP_DEFINE_CONST_DICT(mp_module_uzlib_globals, mp_module_uzlib_globals_table); From fafd587514ece8ee394b9587c1494e35ec2634fb Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sat, 3 Sep 2016 00:20:30 +0300 Subject: [PATCH 097/129] tests/extmod: Add test for uzlib.DecompIO. --- tests/extmod/uzlib_decompio.py | 19 +++++++++++++++++++ tests/extmod/uzlib_decompio.py.exp | 9 +++++++++ 2 files changed, 28 insertions(+) create mode 100644 tests/extmod/uzlib_decompio.py create mode 100644 tests/extmod/uzlib_decompio.py.exp diff --git a/tests/extmod/uzlib_decompio.py b/tests/extmod/uzlib_decompio.py new file mode 100644 index 0000000000..ee3204d07c --- /dev/null +++ b/tests/extmod/uzlib_decompio.py @@ -0,0 +1,19 @@ +try: + import zlib +except ImportError: + import uzlib as zlib +import uio as io + + +# Raw DEFLATE bitstream +buf = io.BytesIO(b'\xcbH\xcd\xc9\xc9\x07\x00') +inp = zlib.DecompIO(buf) +print(buf.seek(0, 1)) +print(inp.read(1)) +print(buf.seek(0, 1)) +print(inp.read(2)) +print(inp.read()) +print(buf.seek(0, 1)) +print(inp.read(1)) +print(inp.read()) +print(buf.seek(0, 1)) diff --git a/tests/extmod/uzlib_decompio.py.exp b/tests/extmod/uzlib_decompio.py.exp new file mode 100644 index 0000000000..6ef811d7db --- /dev/null +++ b/tests/extmod/uzlib_decompio.py.exp @@ -0,0 +1,9 @@ +0 +b'h' +2 +b'el' +b'lo' +7 +b'' +b'' +7 From f7c461152364650b71231387c3f80b37277c9161 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sat, 3 Sep 2016 00:34:57 +0300 Subject: [PATCH 098/129] extmod/moduzlib: Use mperrno.h for error constants. --- extmod/moduzlib.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/extmod/moduzlib.c b/extmod/moduzlib.c index 7fc655fdaf..dbf513527a 100644 --- a/extmod/moduzlib.c +++ b/extmod/moduzlib.c @@ -30,6 +30,7 @@ #include "py/nlr.h" #include "py/runtime.h" #include "py/stream.h" +#include "py/mperrno.h" #if MICROPY_PY_UZLIB @@ -93,7 +94,7 @@ STATIC mp_uint_t decompio_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *er o->eof = true; } if (st < 0) { - *errcode = EINVAL; + *errcode = MP_EINVAL; return MP_STREAM_ERROR; } return o->decomp.dest - (byte*)buf; From 76c366df56ad64eae3b021304954954e663bf1df Mon Sep 17 00:00:00 2001 From: Damien George Date: Sun, 4 Sep 2016 00:12:48 +1000 Subject: [PATCH 099/129] stmhal: Add machine.WDT class. Usage: import machine wdt = machine.WDT(0, 5000) # 5 second timeout wdt.feed() Thanks to Moritz for the initial implementation. --- stmhal/Makefile | 1 + stmhal/modmachine.c | 3 +- stmhal/wdt.c | 102 ++++++++++++++++++++++++++++++++++++++++++++ stmhal/wdt.h | 27 ++++++++++++ 4 files changed, 132 insertions(+), 1 deletion(-) create mode 100644 stmhal/wdt.c create mode 100644 stmhal/wdt.h diff --git a/stmhal/Makefile b/stmhal/Makefile index 2c6ea806eb..e06eed1cc0 100644 --- a/stmhal/Makefile +++ b/stmhal/Makefile @@ -138,6 +138,7 @@ SRC_C = \ uart.c \ can.c \ usb.c \ + wdt.c \ gccollect.c \ pybstdio.c \ help.c \ diff --git a/stmhal/modmachine.c b/stmhal/modmachine.c index 0b01058fa5..68c43d67ef 100644 --- a/stmhal/modmachine.c +++ b/stmhal/modmachine.c @@ -44,6 +44,7 @@ #include "rtc.h" #include "i2c.h" #include "spi.h" +#include "wdt.h" // machine.info([dump_alloc_table]) // Print out lots of information about the board. @@ -490,10 +491,10 @@ STATIC const mp_map_elem_t machine_module_globals_table[] = { // initialize master mode on the peripheral. { MP_OBJ_NEW_QSTR(MP_QSTR_I2C), (mp_obj_t)&machine_i2c_type }, { MP_OBJ_NEW_QSTR(MP_QSTR_SPI), (mp_obj_t)&pyb_spi_type }, + { MP_OBJ_NEW_QSTR(MP_QSTR_WDT), (mp_obj_t)&pyb_wdt_type }, #if 0 { 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_HeartBeat), (mp_obj_t)&pyb_heartbeat_type }, { MP_OBJ_NEW_QSTR(MP_QSTR_SD), (mp_obj_t)&pyb_sd_type }, diff --git a/stmhal/wdt.c b/stmhal/wdt.c new file mode 100644 index 0000000000..6e1172caf6 --- /dev/null +++ b/stmhal/wdt.c @@ -0,0 +1,102 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include STM32_HAL_H + +#include "py/runtime.h" +#include "wdt.h" + +typedef struct _pyb_wdt_obj_t { + mp_obj_base_t base; +} pyb_wdt_obj_t; + +STATIC pyb_wdt_obj_t pyb_wdt = {{&pyb_wdt_type}}; + +STATIC mp_obj_t pyb_wdt_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + // check arguments + mp_arg_check_num(n_args, n_kw, 2, 2, false); + + mp_int_t id = mp_obj_get_int(args[0]); + if (id != 0) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "WDT(%d) does not exist", id)); + } + + // timeout is in milliseconds + mp_int_t timeout = mp_obj_get_int(args[1]); + + // compute prescaler + uint32_t prescaler; + for (prescaler = 0; prescaler < 6 && timeout >= 512; ++prescaler, timeout /= 2) { + } + + // convert milliseconds to ticks + timeout *= 8; // 32kHz / 4 = 8 ticks per millisecond (approx) + if (timeout <= 0) { + mp_raise_ValueError("WDT timeout too short"); + } else if (timeout > 0xfff) { + mp_raise_ValueError("WDT timeout too long"); + } + timeout -= 1; + + // set the reload register + while (IWDG->SR & 2) { + } + IWDG->KR = 0x5555; + IWDG->RLR = timeout; + + // set the prescaler + while (IWDG->SR & 1) { + } + IWDG->KR = 0x5555; + IWDG->PR = prescaler; + + // start the watch dog + IWDG->KR = 0xcccc; + + return (mp_obj_t)&pyb_wdt; +} + +STATIC mp_obj_t pyb_wdt_feed(mp_obj_t self_in) { + (void)self_in; + IWDG->KR = 0xaaaa; + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_wdt_feed_obj, pyb_wdt_feed); + +STATIC const mp_map_elem_t pyb_wdt_locals_dict_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR_feed), (mp_obj_t)&pyb_wdt_feed_obj }, +}; + +STATIC MP_DEFINE_CONST_DICT(pyb_wdt_locals_dict, pyb_wdt_locals_dict_table); + +const mp_obj_type_t pyb_wdt_type = { + { &mp_type_type }, + .name = MP_QSTR_WDT, + .make_new = pyb_wdt_make_new, + .locals_dict = (mp_obj_t)&pyb_wdt_locals_dict, +}; diff --git a/stmhal/wdt.h b/stmhal/wdt.h new file mode 100644 index 0000000000..362d6ef68b --- /dev/null +++ b/stmhal/wdt.h @@ -0,0 +1,27 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +extern const mp_obj_type_t pyb_wdt_type; From 4a33677c9720bd7f2ce5b0f816cc4c87220570ac Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sat, 3 Sep 2016 20:44:24 +0300 Subject: [PATCH 100/129] esp8266/esp8266.ld: Move modmachinewdt to FlashROM. --- esp8266/esp8266.ld | 1 + 1 file changed, 1 insertion(+) diff --git a/esp8266/esp8266.ld b/esp8266/esp8266.ld index dec3bf5a30..853f8fb0f1 100644 --- a/esp8266/esp8266.ld +++ b/esp8266/esp8266.ld @@ -142,6 +142,7 @@ SECTIONS *modpybuart.o(.literal*, .text*) *modpybi2c.o(.literal*, .text*) *modmachinespi.o(.literal*, .text*) + *modmachinewdt.o(.literal*, .text*) *modpybspi.o(.literal*, .text*) *modpybhspi.o(.literal*, .text*) *hspi.o(.literal*, .text*) From 015774a04faa50708ce3692dc3748989e19e98e9 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sat, 3 Sep 2016 20:45:11 +0300 Subject: [PATCH 101/129] esp8266/modmachinewdt: Add .deinit() method. --- esp8266/esp_mphal.c | 4 ---- esp8266/etshal.h | 3 +++ esp8266/modmachinewdt.c | 11 ++++++++++- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/esp8266/esp_mphal.c b/esp8266/esp_mphal.c index 06049e3956..dc6944fd4c 100644 --- a/esp8266/esp_mphal.c +++ b/esp8266/esp_mphal.c @@ -36,10 +36,6 @@ #include "extmod/misc.h" #include "lib/utils/pyexec.h" -extern void ets_wdt_disable(void); -extern void wdt_feed(void); -extern void ets_delay_us(); - STATIC byte input_buf_array[256]; ringbuf_t input_buf = {input_buf_array, sizeof(input_buf_array)}; void mp_hal_debug_tx_strn_cooked(void *env, const char *str, uint32_t len); diff --git a/esp8266/etshal.h b/esp8266/etshal.h index dd61ddec93..e7326a43ba 100644 --- a/esp8266/etshal.h +++ b/esp8266/etshal.h @@ -20,6 +20,9 @@ void ets_timer_arm_new(os_timer_t *tim, uint32_t millis, bool repeat, bool is_mi void ets_timer_setfn(os_timer_t *tim, ETSTimerFunc callback, void *cb_data); void ets_timer_disarm(os_timer_t *tim); +extern void ets_wdt_disable(void); +extern void wdt_feed(void); + // Opaque structure typedef char MD5_CTX[64]; diff --git a/esp8266/modmachinewdt.c b/esp8266/modmachinewdt.c index e0b1ff5d78..6dc4c0d18c 100644 --- a/esp8266/modmachinewdt.c +++ b/esp8266/modmachinewdt.c @@ -31,6 +31,7 @@ #include "py/obj.h" #include "py/runtime.h" #include "user_interface.h" +#include "etshal.h" const mp_obj_type_t esp_wdt_type; @@ -63,8 +64,16 @@ STATIC mp_obj_t machine_wdt_feed(mp_obj_t self_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_wdt_feed_obj, machine_wdt_feed); +STATIC mp_obj_t machine_wdt_deinit(mp_obj_t self_in) { + (void)self_in; + ets_wdt_disable(); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_wdt_deinit_obj, machine_wdt_deinit); + STATIC const mp_map_elem_t machine_wdt_locals_dict_table[] = { - { MP_OBJ_NEW_QSTR(MP_QSTR_feed), (mp_obj_t)&machine_wdt_feed_obj } + { MP_OBJ_NEW_QSTR(MP_QSTR_feed), (mp_obj_t)&machine_wdt_feed_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_deinit), (mp_obj_t)&machine_wdt_deinit_obj }, }; STATIC MP_DEFINE_CONST_DICT(machine_wdt_locals_dict, machine_wdt_locals_dict_table); From 8c6856d2e76c5865d9f30cad2c51615d4a1a1418 Mon Sep 17 00:00:00 2001 From: Chris Packham Date: Sat, 3 Sep 2016 20:44:12 +1200 Subject: [PATCH 102/129] py/emitglue.c: provide mp_raw_code_load_file for any unix architecture Signed-off-by: Chris Packham --- py/emitglue.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/py/emitglue.c b/py/emitglue.c index 0b5903092a..f4b59df3eb 100644 --- a/py/emitglue.c +++ b/py/emitglue.c @@ -379,7 +379,7 @@ mp_raw_code_t *mp_raw_code_load_mem(const byte *buf, size_t len) { // here we define mp_raw_code_load_file depending on the port // TODO abstract this away properly -#if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__) || (defined(__arm__) && (defined(__unix__))) +#if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__) || defined(__unix__) // unix file reader #include From 47899a1ab8756c3850bb275f3756544da0e7b050 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sun, 4 Sep 2016 16:39:28 +1000 Subject: [PATCH 103/129] extmod/modframebuf: Include font from stmhal directory explicitly. So that users of framebuf don't need to have stmhal directory in their path. (Eventually the font can be moved elsewhere.) --- extmod/modframebuf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extmod/modframebuf.c b/extmod/modframebuf.c index 84f1246fba..569b75e1c6 100644 --- a/extmod/modframebuf.c +++ b/extmod/modframebuf.c @@ -33,7 +33,7 @@ #if MICROPY_PY_FRAMEBUF -#include "font_petme128_8x8.h" +#include "stmhal/font_petme128_8x8.h" // 1-bit frame buffer, each byte is a column of 8 pixels typedef struct _mp_obj_framebuf1_t { From 2d8740a4d11fbc4d147636e2161ec08eb46ecf66 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sun, 4 Sep 2016 16:40:40 +1000 Subject: [PATCH 104/129] tests/extmod: Add a test for framebuf module, tested by coverage build. --- tests/extmod/framebuf1.py | 35 +++++++++++++++++++++++++++++++++++ tests/extmod/framebuf1.py.exp | 6 ++++++ unix/mpconfigport_coverage.h | 1 + 3 files changed, 42 insertions(+) create mode 100644 tests/extmod/framebuf1.py create mode 100644 tests/extmod/framebuf1.py.exp diff --git a/tests/extmod/framebuf1.py b/tests/extmod/framebuf1.py new file mode 100644 index 0000000000..85555d0d2c --- /dev/null +++ b/tests/extmod/framebuf1.py @@ -0,0 +1,35 @@ +try: + import framebuf +except ImportError: + print("SKIP") + import sys + sys.exit() + +w = 5 +h = 16 +buf = bytearray(w * h // 8) +fbuf = framebuf.FrameBuffer1(buf, w, h, w) + +# fill +fbuf.fill(1) +print(buf) +fbuf.fill(0) +print(buf) + +# put pixel +fbuf.pixel(0, 0, 1) +fbuf.pixel(4, 0, 1) +fbuf.pixel(0, 15, 1) +fbuf.pixel(4, 15, 1) +print(buf) + +# get pixel +print(fbuf.pixel(0, 0), fbuf.pixel(1, 1)) + +# scroll +fbuf.fill(0) +fbuf.pixel(2, 7, 1) +fbuf.scroll(0, 1) +print(buf) +fbuf.scroll(0, -2) +print(buf) diff --git a/tests/extmod/framebuf1.py.exp b/tests/extmod/framebuf1.py.exp new file mode 100644 index 0000000000..5aca194614 --- /dev/null +++ b/tests/extmod/framebuf1.py.exp @@ -0,0 +1,6 @@ +bytearray(b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x01\x00\x00\x00\x01\x80\x00\x00\x00\x80') +1 0 +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00') +bytearray(b'\x00\x00@\x00\x00\x00\x00\x00\x00\x00') diff --git a/unix/mpconfigport_coverage.h b/unix/mpconfigport_coverage.h index f9a6fbd9dd..5fd5b82c1b 100644 --- a/unix/mpconfigport_coverage.h +++ b/unix/mpconfigport_coverage.h @@ -35,3 +35,4 @@ #undef MICROPY_VFS_FAT #define MICROPY_FSUSERMOUNT (1) #define MICROPY_VFS_FAT (1) +#define MICROPY_PY_FRAMEBUF (1) From fedab995ee60d94d708ba27d7d903ccfb2b0919f Mon Sep 17 00:00:00 2001 From: Dave Hylands Date: Fri, 2 Sep 2016 13:22:49 -0700 Subject: [PATCH 105/129] stmhal: Set STM32F7DISC CPU Frequency to 216 MHz This set the CPU frequency to 216 MHz (the max) and leaves the USB Frequency at 48 MHz. These settings were copied from one of the HAL examples. --- stmhal/boards/STM32F7DISC/mpconfigboard.h | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/stmhal/boards/STM32F7DISC/mpconfigboard.h b/stmhal/boards/STM32F7DISC/mpconfigboard.h index c0e47c3ceb..a1dbc0f468 100644 --- a/stmhal/boards/STM32F7DISC/mpconfigboard.h +++ b/stmhal/boards/STM32F7DISC/mpconfigboard.h @@ -20,12 +20,19 @@ void STM32F7DISC_board_early_init(void); // HSE is 25MHz +// VCOClock = HSE * PLLN / PLLM = 25 MHz * 432 / 25 = 432 MHz +// SYSCLK = VCOClock / PLLP = 432 MHz / 2 = 216 MHz +// USB/SDMMC/RNG Clock = VCOClock / PLLQ = 432 MHz / 9 = 48 MHz #define MICROPY_HW_CLK_PLLM (25) -#define MICROPY_HW_CLK_PLLN (336) +#define MICROPY_HW_CLK_PLLN (432) #define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV2) -#define MICROPY_HW_CLK_PLLQ (7) +#define MICROPY_HW_CLK_PLLQ (9) -#define MICROPY_HW_FLASH_LATENCY FLASH_LATENCY_6 +// From the reference manual, for 2.7V to 3.6V +// 151-180 MHz => 5 wait states +// 181-210 MHz => 6 wait states +// 211-216 MHz => 7 wait states +#define MICROPY_HW_FLASH_LATENCY FLASH_LATENCY_7 // 210-216 MHz needs 7 wait states // UART config #define MICROPY_HW_UART1_TX_PORT (GPIOA) From 1bc5cb4312cae9702ab5fe5412b16156a08b8280 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sun, 4 Sep 2016 14:44:12 +0300 Subject: [PATCH 106/129] extmod/moduzlib: Support wbits arg to DecompIO. --- extmod/moduzlib.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/extmod/moduzlib.c b/extmod/moduzlib.c index dbf513527a..65cbc5eb01 100644 --- a/extmod/moduzlib.c +++ b/extmod/moduzlib.c @@ -67,17 +67,31 @@ STATIC unsigned char read_src_stream(TINF_DATA *data) { return c; } -#define DICT_SIZE 32768 - STATIC mp_obj_t decompio_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { - mp_arg_check_num(n_args, n_kw, 1, 1, false); + mp_arg_check_num(n_args, n_kw, 1, 2, false); mp_obj_decompio_t *o = m_new_obj(mp_obj_decompio_t); o->base.type = type; memset(&o->decomp, 0, sizeof(o->decomp)); - uzlib_uncompress_init(&o->decomp, m_new(byte, DICT_SIZE), DICT_SIZE); o->decomp.readSource = read_src_stream; o->src_stream = args[0]; o->eof = false; + + mp_int_t dict_opt = 0; + int dict_sz; + if (n_args > 1) { + dict_opt = mp_obj_get_int(args[1]); + } + if (dict_opt >= 0) { + dict_opt = uzlib_zlib_parse_header(&o->decomp); + if (dict_opt < 0) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "zlib header")); + } + dict_sz = 1 << dict_opt; + } else { + dict_sz = 1 << -dict_opt; + } + + uzlib_uncompress_init(&o->decomp, m_new(byte, dict_sz), dict_sz); return MP_OBJ_FROM_PTR(o); } From 61e2dfd97dde31c6f6f1005aa0c0a1f616963f7a Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sun, 4 Sep 2016 14:45:27 +0300 Subject: [PATCH 107/129] tests/extmod/uzlib_decompio: Add zlib bitstream testcases. --- tests/extmod/uzlib_decompio.py | 15 ++++++++++++++- tests/extmod/uzlib_decompio.py.exp | 3 +++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/tests/extmod/uzlib_decompio.py b/tests/extmod/uzlib_decompio.py index ee3204d07c..75a6df0ca4 100644 --- a/tests/extmod/uzlib_decompio.py +++ b/tests/extmod/uzlib_decompio.py @@ -7,7 +7,7 @@ import uio as io # Raw DEFLATE bitstream buf = io.BytesIO(b'\xcbH\xcd\xc9\xc9\x07\x00') -inp = zlib.DecompIO(buf) +inp = zlib.DecompIO(buf, -8) print(buf.seek(0, 1)) print(inp.read(1)) print(buf.seek(0, 1)) @@ -17,3 +17,16 @@ print(buf.seek(0, 1)) print(inp.read(1)) print(inp.read()) print(buf.seek(0, 1)) + + +# zlib bitstream +inp = zlib.DecompIO(io.BytesIO(b'x\x9c30\xa0=\x00\x00\xb3q\x12\xc1')) +print(inp.read(10)) +print(inp.read()) + +# zlib bitstream, wrong checksum +inp = zlib.DecompIO(io.BytesIO(b'x\x9c30\xa0=\x00\x00\xb3q\x12\xc0')) +try: + print(inp.read()) +except OSError as e: + print(repr(e)) diff --git a/tests/extmod/uzlib_decompio.py.exp b/tests/extmod/uzlib_decompio.py.exp index 6ef811d7db..3f5f360fa3 100644 --- a/tests/extmod/uzlib_decompio.py.exp +++ b/tests/extmod/uzlib_decompio.py.exp @@ -7,3 +7,6 @@ b'lo' b'' b'' 7 +b'0000000000' +b'000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +OSError(22,) From 1708fe3cc719aec15b9f6d5a39cb0181b4547161 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sun, 4 Sep 2016 19:45:58 +0300 Subject: [PATCH 108/129] esp8266/modmachine: Add WDT_RESET and SOFT_RESET constants. Both tested to work. (WDT_RESET can be seen by issuing machine.disable_irq() and waiting for WDT reset, SOFT_RESET - by machine.reset()). --- esp8266/modmachine.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/esp8266/modmachine.c b/esp8266/modmachine.c index 0972ce29fb..e7d91c2377 100644 --- a/esp8266/modmachine.c +++ b/esp8266/modmachine.c @@ -265,6 +265,8 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_PWR_ON_RESET), MP_ROM_INT(REASON_EXT_SYS_RST) }, { MP_ROM_QSTR(MP_QSTR_HARD_RESET), MP_ROM_INT(REASON_EXT_SYS_RST) }, { MP_ROM_QSTR(MP_QSTR_DEEPSLEEP_RESET), MP_ROM_INT(REASON_DEEP_SLEEP_AWAKE) }, + { MP_ROM_QSTR(MP_QSTR_WDT_RESET), MP_ROM_INT(REASON_WDT_RST) }, + { MP_ROM_QSTR(MP_QSTR_SOFT_RESET), MP_ROM_INT(REASON_SOFT_RESTART) }, }; STATIC MP_DEFINE_CONST_DICT(machine_module_globals, machine_module_globals_table); From 7ddd1a58f6ec90a35e2ca815f62358acfb801c52 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sun, 4 Sep 2016 19:57:16 +0300 Subject: [PATCH 109/129] esp8266/modmachine: Don't expose internal SoftSPI and HSPI classes. There functionality is available via standard SPI class. --- esp8266/modmachine.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/esp8266/modmachine.c b/esp8266/modmachine.c index e7d91c2377..a6d5fc3dbb 100644 --- a/esp8266/modmachine.c +++ b/esp8266/modmachine.c @@ -254,8 +254,6 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_ADC), MP_ROM_PTR(&pyb_adc_type) }, { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&pyb_uart_type) }, { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&machine_i2c_type) }, - { MP_ROM_QSTR(MP_QSTR_SoftSPI), MP_ROM_PTR(&pyb_spi_type) }, - { MP_ROM_QSTR(MP_QSTR_HSPI), MP_ROM_PTR(&pyb_hspi_type) }, { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&machine_spi_type) }, // wake abilities From dba40afa706a1ac4b102dceba217844dc1540ce7 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sun, 4 Sep 2016 20:33:11 +0300 Subject: [PATCH 110/129] esp8266/modmachine: Simplify SPI class implementation multiplexing. modpybhspi now does the needed multiplexing, calling out to modpybspi (bitbanging SPI) for suitable peripheral ID's. modmachinespi (previous multiplexer class) thus not needed and removed. modpybhspi also updated to following standard SPI peripheral naming: SPI0 is used for FlashROM and thus not supported so far. SPI1 is available for users, and thus needs to be instantiated as: spi = machine.SPI(1, ...) --- esp8266/Makefile | 1 - esp8266/esp8266.ld | 1 - esp8266/modmachine.c | 2 +- esp8266/modmachinespi.c | 71 ----------------------------------------- esp8266/modpybhspi.c | 27 ++++++++++++++-- 5 files changed, 25 insertions(+), 77 deletions(-) delete mode 100644 esp8266/modmachinespi.c diff --git a/esp8266/Makefile b/esp8266/Makefile index 2786510388..521cbb4725 100644 --- a/esp8266/Makefile +++ b/esp8266/Makefile @@ -79,7 +79,6 @@ SRC_C = \ modpybadc.c \ modpybuart.c \ modmachinewdt.c \ - modmachinespi.c \ modpybspi.c \ modpybhspi.c \ modesp.c \ diff --git a/esp8266/esp8266.ld b/esp8266/esp8266.ld index 853f8fb0f1..c726790d38 100644 --- a/esp8266/esp8266.ld +++ b/esp8266/esp8266.ld @@ -141,7 +141,6 @@ SECTIONS *modpybadc.o(.literal*, .text*) *modpybuart.o(.literal*, .text*) *modpybi2c.o(.literal*, .text*) - *modmachinespi.o(.literal*, .text*) *modmachinewdt.o(.literal*, .text*) *modpybspi.o(.literal*, .text*) *modpybhspi.o(.literal*, .text*) diff --git a/esp8266/modmachine.c b/esp8266/modmachine.c index a6d5fc3dbb..df1ae0fcf6 100644 --- a/esp8266/modmachine.c +++ b/esp8266/modmachine.c @@ -254,7 +254,7 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_ADC), MP_ROM_PTR(&pyb_adc_type) }, { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&pyb_uart_type) }, { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&machine_i2c_type) }, - { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&machine_spi_type) }, + { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&pyb_hspi_type) }, // wake abilities { MP_ROM_QSTR(MP_QSTR_DEEPSLEEP), MP_ROM_INT(MACHINE_WAKE_DEEPSLEEP) }, diff --git a/esp8266/modmachinespi.c b/esp8266/modmachinespi.c deleted file mode 100644 index 1c6a373698..0000000000 --- a/esp8266/modmachinespi.c +++ /dev/null @@ -1,71 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2016 Damien P. George - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include -#include -#include - -#include "ets_sys.h" -#include "etshal.h" -#include "ets_alt_task.h" - -#include "py/runtime.h" -#include "py/stream.h" -#include "py/mphal.h" - - -mp_obj_t pyb_spi_make_new(const mp_obj_type_t *type, size_t n_args, - size_t n_kw, const mp_obj_t *args); -mp_obj_t pyb_hspi_make_new(const mp_obj_type_t *type, size_t n_args, - size_t n_kw, const mp_obj_t *args); - - -STATIC mp_obj_t machine_spi_make_new(const mp_obj_type_t *type, size_t n_args, - size_t n_kw, const mp_obj_t *args) { - mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true); - switch (mp_obj_get_int(args[0])) { - case -1: - return pyb_spi_make_new(type, n_args - 1, n_kw, args + 1); - case 0: - return pyb_hspi_make_new(type, n_args - 1, n_kw, args + 1); - default: - nlr_raise(mp_obj_new_exception_msg_varg( - &mp_type_ValueError, "no such SPI peripheral")); - } -} - - -STATIC const mp_rom_map_elem_t machine_spi_locals_dict_table[] = {}; - -STATIC MP_DEFINE_CONST_DICT(machine_spi_locals_dict, - machine_spi_locals_dict_table); - -const mp_obj_type_t machine_spi_type = { - { &mp_type_type }, - .name = MP_QSTR_SPI, - .make_new = machine_spi_make_new, - .locals_dict = (mp_obj_dict_t*)&machine_spi_locals_dict, -}; diff --git a/esp8266/modpybhspi.c b/esp8266/modpybhspi.c index c4d4dcee8d..c1cd7f662d 100644 --- a/esp8266/modpybhspi.c +++ b/esp8266/modpybhspi.c @@ -39,6 +39,8 @@ #include "hspi.h" +mp_obj_t pyb_spi_make_new(const mp_obj_type_t *type, size_t n_args, + size_t n_kw, const mp_obj_t *args); typedef struct _pyb_hspi_obj_t { mp_obj_base_t base; @@ -105,13 +107,14 @@ STATIC void hspi_transfer(mp_obj_base_t *self_in, size_t src_len, const uint8_t STATIC void pyb_hspi_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { pyb_hspi_obj_t *self = MP_OBJ_TO_PTR(self_in); - mp_printf(print, "HSPI(baudrate=%u, polarity=%u, phase=%u)", + mp_printf(print, "HSPI(id=1, baudrate=%u, polarity=%u, phase=%u)", self->baudrate, self->polarity, self->phase); } STATIC void pyb_hspi_init_helper(pyb_hspi_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_baudrate, ARG_polarity, ARG_phase }; + enum { ARG_id, ARG_baudrate, ARG_polarity, ARG_phase }; static const mp_arg_t allowed_args[] = { + { MP_QSTR_id, MP_ARG_INT, {.u_int = -1} }, { MP_QSTR_baudrate, MP_ARG_INT, {.u_int = -1} }, { MP_QSTR_polarity, MP_ARG_INT, {.u_int = -1} }, { MP_QSTR_phase, MP_ARG_INT, {.u_int = -1} }, @@ -160,7 +163,25 @@ STATIC void pyb_hspi_init_helper(pyb_hspi_obj_t *self, size_t n_args, const mp_o } mp_obj_t pyb_hspi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { - mp_arg_check_num(n_args, n_kw, 0, MP_OBJ_FUN_ARGS_MAX, true); + mp_arg_check_num(n_args, n_kw, 0, 1, true); + mp_int_t id = -1; + if (n_args > 0) { + id = mp_obj_get_int(args[0]); + } + + if (id == -1) { + // Multiplex to bitbanging SPI + if (n_args > 0) { + args++; + } + return pyb_spi_make_new(type, 0, n_kw, args); + } + + if (id != 1) { + // FlashROM is on SPI0, so far we don't support its usage + mp_raise_ValueError(""); + } + pyb_hspi_obj_t *self = m_new_obj(pyb_hspi_obj_t); self->base.type = &pyb_hspi_type; // set defaults From 20da9064d7492b2f37a2140c17e468fb5785a593 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sun, 4 Sep 2016 21:13:55 +0300 Subject: [PATCH 111/129] docs/esp8266/quickref: Update information on SPI classes. SPI(1) is not used for hardware SPI. Few more details are provided. --- docs/esp8266/quickref.rst | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/esp8266/quickref.rst b/docs/esp8266/quickref.rst index d209871361..ae7a8f724f 100644 --- a/docs/esp8266/quickref.rst +++ b/docs/esp8266/quickref.rst @@ -165,7 +165,8 @@ Use the ``machine.ADC`` class:: SPI bus ------- -There are two SPI drivers. One is implemented in software and works on all pins:: +There are two SPI drivers. One is implemented in software (bit-banging) +and works on all pins:: from machine import Pin, SPI @@ -194,14 +195,15 @@ Hardware SPI ------------ The hardware SPI is faster (up to 80Mhz), but only works on following pins: -``MISO`` is gpio12, ``MOSI`` is gpio13, and ``SCK`` is gpio14. It has the same +``MISO`` is GPIO12, ``MOSI`` is GPIO13, and ``SCK`` is GPIO14. It has the same methods as SPI, except for the pin parameters for the constructor and init (as those are fixed). from machine import Pin, SPI - hspi = SPI(0, baudrate=80000000, polarity=0, phase=0) + hspi = SPI(1, baudrate=80000000, polarity=0, phase=0) +(SPI(0) is used for FlashROM and not available to users.) I2C bus ------- From b4df3e74e15ac1658c125b13bbaca5203bab5505 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sun, 4 Sep 2016 23:31:05 +0300 Subject: [PATCH 112/129] docs/esp8266/quickref: Further improvements for SPI subsections. Consistency and formatting. --- docs/esp8266/quickref.rst | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/esp8266/quickref.rst b/docs/esp8266/quickref.rst index ae7a8f724f..d06fe5a6f1 100644 --- a/docs/esp8266/quickref.rst +++ b/docs/esp8266/quickref.rst @@ -162,8 +162,8 @@ Use the ``machine.ADC`` class:: adc = ADC(0) # create ADC object on ADC pin adc.read() # read value, 0-1024 -SPI bus -------- +Software SPI bus +---------------- There are two SPI drivers. One is implemented in software (bit-banging) and works on all pins:: @@ -191,19 +191,19 @@ and works on all pins:: spi.write_readinto(buf, buf) # write buf to MOSI and read MISO back into buf -Hardware SPI ------------- +Hardware SPI bus +---------------- The hardware SPI is faster (up to 80Mhz), but only works on following pins: ``MISO`` is GPIO12, ``MOSI`` is GPIO13, and ``SCK`` is GPIO14. It has the same -methods as SPI, except for the pin parameters for the constructor and init -(as those are fixed). +methods as the bitbanging SPI class above, except for the pin parameters for the +constructor and init (as those are fixed):: from machine import Pin, SPI hspi = SPI(1, baudrate=80000000, polarity=0, phase=0) -(SPI(0) is used for FlashROM and not available to users.) +(``SPI(0)`` is used for FlashROM and not available to users.) I2C bus ------- From 778729c5977633978aef2ec302472505973a657e Mon Sep 17 00:00:00 2001 From: Radomir Dopieralski Date: Fri, 2 Sep 2016 16:15:37 +0200 Subject: [PATCH 113/129] extmod/framebuf: Add the xstep!=0 case to scroll() method. Adds horizontal scrolling. Right now, I'm just leaving the margins created by the scrolling as they were -- so they will repeat the edge of the framebuf. This is fast, and the user can always fill the margins themselves. --- extmod/modframebuf.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/extmod/modframebuf.c b/extmod/modframebuf.c index 569b75e1c6..3c884c6898 100644 --- a/extmod/modframebuf.c +++ b/extmod/modframebuf.c @@ -103,7 +103,7 @@ STATIC mp_obj_t framebuf1_scroll(mp_obj_t self_in, mp_obj_t xstep_in, mp_obj_t y mp_int_t xstep = mp_obj_get_int(xstep_in); mp_int_t ystep = mp_obj_get_int(ystep_in); int end = (self->height + 7) >> 3; - if (xstep == 0 && ystep > 0) { + if (ystep > 0) { for (int y = end; y > 0;) { --y; for (int x = 0; x < self->width; ++x) { @@ -114,7 +114,7 @@ STATIC mp_obj_t framebuf1_scroll(mp_obj_t self_in, mp_obj_t xstep_in, mp_obj_t y self->buf[y * self->stride + x] = (self->buf[y * self->stride + x] << ystep) | prev; } } - } else if (xstep == 0 && ystep < 0) { + } else if (ystep < 0) { for (int y = 0; y < end; ++y) { for (int x = 0; x < self->width; ++x) { int prev = 0; @@ -125,7 +125,20 @@ STATIC mp_obj_t framebuf1_scroll(mp_obj_t self_in, mp_obj_t xstep_in, mp_obj_t y } } } - // TODO xstep!=0 + if (xstep < 0) { + for (int y = 0; y < end; ++y) { + for (int x = 0; x < self->width + xstep; ++x) { + self->buf[y * self->stride + x] = self->buf[y * self->stride + x - xstep]; + } + } + } else if (xstep > 0) { + for (int y = 0; y < end; ++y) { + for (int x = self->width - 1; x >= xstep; --x) { + self->buf[y * self->stride + x] = self->buf[y * self->stride + x - xstep]; + } + } + } + // TODO: Should we clear the margin created by scrolling? return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_3(framebuf1_scroll_obj, framebuf1_scroll); From cac8dc34149686679b67037d393d3ea1c6aff779 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 5 Sep 2016 12:08:25 +1000 Subject: [PATCH 114/129] tests/extmod/framebuf1: Add tests for scrolling in the x-direction. --- tests/extmod/framebuf1.py | 6 ++++++ tests/extmod/framebuf1.py.exp | 3 +++ 2 files changed, 9 insertions(+) diff --git a/tests/extmod/framebuf1.py b/tests/extmod/framebuf1.py index 85555d0d2c..f550b6b4f4 100644 --- a/tests/extmod/framebuf1.py +++ b/tests/extmod/framebuf1.py @@ -33,3 +33,9 @@ fbuf.scroll(0, 1) print(buf) fbuf.scroll(0, -2) print(buf) +fbuf.scroll(1, 0) +print(buf) +fbuf.scroll(-1, 0) +print(buf) +fbuf.scroll(2, 2) +print(buf) diff --git a/tests/extmod/framebuf1.py.exp b/tests/extmod/framebuf1.py.exp index 5aca194614..8fd8c37098 100644 --- a/tests/extmod/framebuf1.py.exp +++ b/tests/extmod/framebuf1.py.exp @@ -4,3 +4,6 @@ bytearray(b'\x01\x00\x00\x00\x01\x80\x00\x00\x00\x80') 1 0 bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00') bytearray(b'\x00\x00@\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00@\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00@\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01') From e2ac8bb3f14b076a29244022865e3b47c6c0800a Mon Sep 17 00:00:00 2001 From: Delio Brignoli Date: Sun, 21 Aug 2016 11:33:37 +0200 Subject: [PATCH 115/129] py: Add MICROPY_USE_INTERNAL_PRINTF option, defaults to enabled. This new config option allows to control whether MicroPython uses its own internal printf or not (if not, an external one should be linked in). Accompanying this new option is the inclusion of lib/utils/printf.c in the core list of source files, so that ports no longer need to include it themselves. --- bare-arm/mpconfigport.h | 1 + cc3200/application.mk | 1 - esp8266/Makefile | 1 - lib/utils/printf.c | 6 ++++++ minimal/Makefile | 1 - py/mpconfig.h | 5 +++++ py/py.mk | 1 + qemu-arm/mpconfigport.h | 1 + stmhal/Makefile | 1 - teensy/Makefile | 1 - unix/Makefile | 1 - 11 files changed, 14 insertions(+), 6 deletions(-) diff --git a/bare-arm/mpconfigport.h b/bare-arm/mpconfigport.h index 7c448d13c1..79b2b73283 100644 --- a/bare-arm/mpconfigport.h +++ b/bare-arm/mpconfigport.h @@ -42,6 +42,7 @@ #define MICROPY_CPYTHON_COMPAT (0) #define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_NONE) #define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_NONE) +#define MICROPY_USE_INTERNAL_PRINTF (0) // type definitions for the specific machine diff --git a/cc3200/application.mk b/cc3200/application.mk index dca6fcbc65..300262c971 100644 --- a/cc3200/application.mk +++ b/cc3200/application.mk @@ -154,7 +154,6 @@ APP_LIB_SRC_C = $(addprefix lib/,\ timeutils/timeutils.c \ utils/pyexec.c \ utils/pyhelp.c \ - utils/printf.c \ ) APP_STM_SRC_C = $(addprefix stmhal/,\ diff --git a/esp8266/Makefile b/esp8266/Makefile index 521cbb4725..1dfcec809c 100644 --- a/esp8266/Makefile +++ b/esp8266/Makefile @@ -128,7 +128,6 @@ LIB_SRC_C = $(addprefix lib/,\ timeutils/timeutils.c \ utils/pyexec.c \ utils/pyhelp.c \ - utils/printf.c \ fatfs/ff.c \ fatfs/option/ccsbcs.c \ ) diff --git a/lib/utils/printf.c b/lib/utils/printf.c index 308525b6e8..303edfcca0 100644 --- a/lib/utils/printf.c +++ b/lib/utils/printf.c @@ -24,6 +24,10 @@ * THE SOFTWARE. */ +#include "py/mpconfig.h" + +#if MICROPY_USE_INTERNAL_PRINTF + #include #include #include @@ -127,3 +131,5 @@ int snprintf(char *str, size_t size, const char *fmt, ...) { va_end(ap); return ret; } + +#endif //MICROPY_USE_INTERNAL_PRINTF diff --git a/minimal/Makefile b/minimal/Makefile index 02096f9f0e..0cecd1c0fd 100644 --- a/minimal/Makefile +++ b/minimal/Makefile @@ -46,7 +46,6 @@ SRC_C = \ main.c \ uart_core.c \ lib/utils/stdout_helpers.c \ - lib/utils/printf.c \ lib/utils/pyexec.c \ lib/libc/string0.c \ lib/mp-readline/readline.c \ diff --git a/py/mpconfig.h b/py/mpconfig.h index 455f870ac7..e33a41f7a0 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -581,6 +581,11 @@ typedef double mp_float_t; #define MICROPY_USE_INTERNAL_ERRNO (0) #endif +// Whether to use internally defined *printf() functions (otherwise external ones) +#ifndef MICROPY_USE_INTERNAL_PRINTF +#define MICROPY_USE_INTERNAL_PRINTF (1) +#endif + // Support for user-space VFS mount (selected ports) #ifndef MICROPY_FSUSERMOUNT #define MICROPY_FSUSERMOUNT (0) diff --git a/py/py.mk b/py/py.mk index abea7215b2..37b98de928 100644 --- a/py/py.mk +++ b/py/py.mk @@ -223,6 +223,7 @@ PY_O_BASENAME = \ ../extmod/vfs_fat_misc.o \ ../extmod/moduos_dupterm.o \ ../lib/embed/abort_.o \ + ../lib/utils/printf.o \ # prepend the build destination prefix to the py object files PY_O = $(addprefix $(PY_BUILD)/, $(PY_O_BASENAME)) diff --git a/qemu-arm/mpconfigport.h b/qemu-arm/mpconfigport.h index 57277b1569..1f23148c2a 100644 --- a/qemu-arm/mpconfigport.h +++ b/qemu-arm/mpconfigport.h @@ -23,6 +23,7 @@ #define MICROPY_PY_IO (0) #define MICROPY_PY_SYS_EXIT (1) #define MICROPY_PY_SYS_MAXSIZE (1) +#define MICROPY_USE_INTERNAL_PRINTF (0) // type definitions for the specific machine diff --git a/stmhal/Makefile b/stmhal/Makefile index e06eed1cc0..881c073f13 100644 --- a/stmhal/Makefile +++ b/stmhal/Makefile @@ -111,7 +111,6 @@ SRC_LIB = $(addprefix lib/,\ timeutils/timeutils.c \ utils/pyexec.c \ utils/pyhelp.c \ - utils/printf.c \ ) SRC_C = \ diff --git a/teensy/Makefile b/teensy/Makefile index 7b34ba90e2..0ab07121ca 100644 --- a/teensy/Makefile +++ b/teensy/Makefile @@ -110,7 +110,6 @@ LIB_SRC_C = $(addprefix lib/,\ mp-readline/readline.c \ utils/pyexec.c \ utils/pyhelp.c \ - utils/printf.c \ ) SRC_TEENSY = $(addprefix core/,\ diff --git a/unix/Makefile b/unix/Makefile index 3afa80dfa8..49b605f124 100644 --- a/unix/Makefile +++ b/unix/Makefile @@ -157,7 +157,6 @@ endif LIB_SRC_C = $(addprefix lib/,\ $(LIB_SRC_C_EXTRA) \ - utils/printf.c \ timeutils/timeutils.c \ ) From 9526e24234bba06fcbf42c590743087bc8527319 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 5 Sep 2016 12:35:05 +1000 Subject: [PATCH 116/129] unix,stmhal,esp8266: When find'ing frozen files follow symbolic links. It's useful to be able to use symbolic links to add files and directories to the set of scripts to be frozen. --- esp8266/Makefile | 2 +- stmhal/Makefile | 2 +- unix/Makefile | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/esp8266/Makefile b/esp8266/Makefile index 1dfcec809c..433b41ecfd 100644 --- a/esp8266/Makefile +++ b/esp8266/Makefile @@ -139,7 +139,7 @@ DRIVERS_SRC_C = $(addprefix drivers/,\ SRC_S = \ gchelper.s \ -FROZEN_MPY_PY_FILES := $(shell find $(FROZEN_MPY_DIR) -type f -name '*.py') +FROZEN_MPY_PY_FILES := $(shell find -L $(FROZEN_MPY_DIR) -type f -name '*.py') FROZEN_MPY_MPY_FILES := $(addprefix $(BUILD)/,$(FROZEN_MPY_PY_FILES:.py=.mpy)) OBJ = diff --git a/stmhal/Makefile b/stmhal/Makefile index 881c073f13..b320e0c898 100644 --- a/stmhal/Makefile +++ b/stmhal/Makefile @@ -284,7 +284,7 @@ endif ifneq ($(FROZEN_MPY_DIR),) # To use frozen bytecode, put your .py files in a subdirectory (eg frozen/) and # then invoke make with FROZEN_MPY_DIR=frozen (be sure to build from scratch). -FROZEN_MPY_PY_FILES := $(shell find $(FROZEN_MPY_DIR) -type f -name '*.py') +FROZEN_MPY_PY_FILES := $(shell find -L $(FROZEN_MPY_DIR) -type f -name '*.py') FROZEN_MPY_MPY_FILES := $(addprefix $(BUILD)/,$(FROZEN_MPY_PY_FILES:.py=.mpy)) CFLAGS += -DMICROPY_QSTR_EXTRA_POOL=mp_qstr_frozen_const_pool CFLAGS += -DMICROPY_MODULE_FROZEN_MPY diff --git a/unix/Makefile b/unix/Makefile index 49b605f124..956b1daef3 100644 --- a/unix/Makefile +++ b/unix/Makefile @@ -182,7 +182,7 @@ ifneq ($(FROZEN_MPY_DIR),) # then invoke make with FROZEN_MPY_DIR=frozen (be sure to build from scratch). MPY_CROSS = ../mpy-cross/mpy-cross MPY_TOOL = ../tools/mpy-tool.py -FROZEN_MPY_PY_FILES := $(shell find $(FROZEN_MPY_DIR) -type f -name '*.py') +FROZEN_MPY_PY_FILES := $(shell find -L $(FROZEN_MPY_DIR) -type f -name '*.py') FROZEN_MPY_MPY_FILES := $(addprefix $(BUILD)/,$(FROZEN_MPY_PY_FILES:.py=.mpy)) CFLAGS += -DMICROPY_QSTR_EXTRA_POOL=mp_qstr_frozen_const_pool CFLAGS += -DMICROPY_MODULE_FROZEN_MPY From ef47a67cf42246bbcf3c81e5f89e0e25db9dff74 Mon Sep 17 00:00:00 2001 From: Peter Hinch Date: Mon, 13 Jun 2016 08:54:57 +0100 Subject: [PATCH 117/129] stmhal/dac: Fix DAC (re-)initialisation by resetting DMA. Fixes issue #2176. --- stmhal/dac.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/stmhal/dac.c b/stmhal/dac.c index 7493bb59ab..a9b1b9eca7 100644 --- a/stmhal/dac.c +++ b/stmhal/dac.c @@ -171,6 +171,14 @@ STATIC mp_obj_t pyb_dac_init_helper(pyb_dac_obj_t *self, mp_uint_t n_args, const #endif // stop anything already going on + __DMA1_CLK_ENABLE(); + DMA_HandleTypeDef DMA_Handle; + /* Get currently configured dma */ + dma_init_handle(&DMA_Handle, self->tx_dma_descr, (void*)NULL); + // Need to deinit DMA first + DMA_Handle.State = HAL_DMA_STATE_READY; + HAL_DMA_DeInit(&DMA_Handle); + HAL_DAC_Stop(&DAC_Handle, self->dac_channel); if ((self->dac_channel == DAC_CHANNEL_1 && DAC_Handle.DMA_Handle1 != NULL) || (self->dac_channel == DAC_CHANNEL_2 && DAC_Handle.DMA_Handle2 != NULL)) { From 2b882e9acaecd92cf3107a597c9aba99f23b794e Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 5 Sep 2016 17:30:24 +1000 Subject: [PATCH 118/129] mpy-cross: Don't use the internal printf functions. They require mp_hal_stdout_tx_strn_cooked, which requires extra work to add to mpy-cross. --- mpy-cross/mpconfigport.h | 1 + 1 file changed, 1 insertion(+) diff --git a/mpy-cross/mpconfigport.h b/mpy-cross/mpconfigport.h index c919e42911..c0a404103b 100644 --- a/mpy-cross/mpconfigport.h +++ b/mpy-cross/mpconfigport.h @@ -59,6 +59,7 @@ #define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_DOUBLE) #define MICROPY_CPYTHON_COMPAT (1) +#define MICROPY_USE_INTERNAL_PRINTF (0) #define MICROPY_PY_BUILTINS_STR_UNICODE (1) From e4d6a10dc91f8af8b4ba3647c94e6ce730671864 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 5 Sep 2016 17:33:56 +1000 Subject: [PATCH 119/129] travis: Build mpy-cross as part of the Travis process. It's built first in case any ports need to use it. --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index f9ee2ab0fe..99d8b8f0fb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,6 +23,7 @@ before_script: - python3 --version script: + - make -C mpy-cross - make -C minimal test - make -C unix deplibs - make -C unix From 69768c97c060d1b6160e2abcd2fda9c63ce65a2d Mon Sep 17 00:00:00 2001 From: Torsten Wagner Date: Thu, 30 Jun 2016 11:11:56 +0200 Subject: [PATCH 120/129] esp8266/espneopixel: Disable IRQs during eps.neopixel_write. Interrupts during neopixel_write causes timing problems and therefore wrong light patterns. Switching off IRQs should help to keep the strict timing schedule. --- esp8266/espneopixel.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/esp8266/espneopixel.c b/esp8266/espneopixel.c index 0f12f4c820..e16c874f23 100644 --- a/esp8266/espneopixel.c +++ b/esp8266/espneopixel.c @@ -41,6 +41,7 @@ void /*ICACHE_RAM_ATTR*/ esp_neopixel_write(uint8_t pin, uint8_t *pixels, uint32 } #endif + uint32_t irq_state = mp_hal_quiet_timing_enter(); for(t = time0;; t = time0) { if(pix & mask) t = time1; // Bit high duration while(((c = mp_hal_ticks_cpu()) - startTime) < period); // Wait for bit start @@ -55,4 +56,5 @@ void /*ICACHE_RAM_ATTR*/ esp_neopixel_write(uint8_t pin, uint8_t *pixels, uint32 } } while((mp_hal_ticks_cpu() - startTime) < period); // Wait for last bit + mp_hal_quiet_timing_exit(irq_state); } From b88bf6c76b9105110b7b2befe77ad58b90be8097 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 6 Sep 2016 14:19:40 +1000 Subject: [PATCH 121/129] stmhal/wdt: Implement keyword args to WDT constructor. --- stmhal/wdt.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/stmhal/wdt.c b/stmhal/wdt.c index 6e1172caf6..d9a089d011 100644 --- a/stmhal/wdt.c +++ b/stmhal/wdt.c @@ -37,17 +37,23 @@ typedef struct _pyb_wdt_obj_t { STATIC pyb_wdt_obj_t pyb_wdt = {{&pyb_wdt_type}}; -STATIC mp_obj_t pyb_wdt_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { - // check arguments - mp_arg_check_num(n_args, n_kw, 2, 2, false); +STATIC mp_obj_t pyb_wdt_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + // parse arguments + enum { ARG_id, ARG_timeout }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_id, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_timeout, MP_ARG_INT, {.u_int = 5000} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - mp_int_t id = mp_obj_get_int(args[0]); + mp_int_t id = args[ARG_id].u_int; if (id != 0) { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "WDT(%d) does not exist", id)); } // timeout is in milliseconds - mp_int_t timeout = mp_obj_get_int(args[1]); + mp_int_t timeout = args[ARG_timeout].u_int; // compute prescaler uint32_t prescaler; From 9103cbe36629b121b1a8a927b3fa199c6ee5ddf3 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 6 Sep 2016 14:20:19 +1000 Subject: [PATCH 122/129] stmhal/modmachine: Implement machine.reset_cause() function, and consts. --- stmhal/main.c | 3 +++ stmhal/modmachine.c | 62 +++++++++++++++++++++++++++++++++++++-------- stmhal/modmachine.h | 2 ++ 3 files changed, 57 insertions(+), 10 deletions(-) diff --git a/stmhal/main.c b/stmhal/main.c index 32baae5320..2446225034 100644 --- a/stmhal/main.c +++ b/stmhal/main.c @@ -44,6 +44,7 @@ #include "pendsv.h" #include "gccollect.h" #include "readline.h" +#include "modmachine.h" #include "i2c.h" #include "spi.h" #include "uart.h" @@ -410,6 +411,8 @@ soft_reset: led_state(4, 0); uint reset_mode = update_reset_mode(1); + machine_init(); + #if MICROPY_HW_ENABLE_RTC if (first_soft_reset) { rtc_init_start(false); diff --git a/stmhal/modmachine.c b/stmhal/modmachine.c index 68c43d67ef..dbeabec55b 100644 --- a/stmhal/modmachine.c +++ b/stmhal/modmachine.c @@ -46,6 +46,49 @@ #include "spi.h" #include "wdt.h" +#if defined(MCU_SERIES_F4) +// the HAL does not define these constants +#define RCC_CSR_IWDGRSTF (0x20000000) +#define RCC_CSR_PINRSTF (0x04000000) +#elif defined(MCU_SERIES_L4) +// L4 does not have a POR, so use BOR instead +#define RCC_CSR_PORRSTF RCC_CSR_BORRSTF +#endif + +#define PYB_RESET_SOFT (0) +#define PYB_RESET_POWER_ON (1) +#define PYB_RESET_HARD (2) +#define PYB_RESET_WDT (3) +#define PYB_RESET_DEEPSLEEP (4) + +STATIC uint32_t reset_cause; + +void machine_init(void) { + #if defined(MCU_SERIES_F4) + if (PWR->CSR & PWR_CSR_SBF) { + // came out of standby + reset_cause = PYB_RESET_DEEPSLEEP; + PWR->CR = PWR_CR_CSBF; + } else + #endif + { + // get reset cause from RCC flags + uint32_t state = RCC->CSR; + if (state & RCC_CSR_IWDGRSTF || state & RCC_CSR_WWDGRSTF) { + reset_cause = PYB_RESET_WDT; + } else if (state & RCC_CSR_PORRSTF || state & RCC_CSR_BORRSTF) { + reset_cause = PYB_RESET_POWER_ON; + } else if (state & RCC_CSR_PINRSTF) { + reset_cause = PYB_RESET_HARD; + } else { + // default is soft reset + reset_cause = PYB_RESET_SOFT; + } + } + // clear RCC reset flags + RCC->CSR = RCC_CSR_RMVF; +} + // machine.info([dump_alloc_table]) // Print out lots of information about the board. STATIC mp_obj_t machine_info(mp_uint_t n_args, const mp_obj_t *args) { @@ -448,13 +491,10 @@ STATIC mp_obj_t machine_deepsleep(void) { } MP_DEFINE_CONST_FUN_OBJ_0(machine_deepsleep_obj, machine_deepsleep); -#if 0 STATIC mp_obj_t machine_reset_cause(void) { - return mp_obj_new_int(0); - //return mp_obj_new_int(pyb_sleep_get_reset_cause()); + return MP_OBJ_NEW_SMALL_INT(reset_cause); } STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_reset_cause_obj, machine_reset_cause); -#endif STATIC const mp_map_elem_t machine_module_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_umachine) }, @@ -469,8 +509,8 @@ STATIC const mp_map_elem_t machine_module_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_idle), (mp_obj_t)&pyb_wfi_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 }, -#if 0 { MP_OBJ_NEW_QSTR(MP_QSTR_reset_cause), (mp_obj_t)&machine_reset_cause_obj }, +#if 0 { MP_OBJ_NEW_QSTR(MP_QSTR_wake_reason), (mp_obj_t)&machine_wake_reason_obj }, #endif @@ -502,11 +542,13 @@ STATIC const mp_map_elem_t machine_module_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_IDLE), MP_OBJ_NEW_SMALL_INT(PYB_PWR_MODE_ACTIVE) }, { MP_OBJ_NEW_QSTR(MP_QSTR_SLEEP), MP_OBJ_NEW_SMALL_INT(PYB_PWR_MODE_LPDS) }, { MP_OBJ_NEW_QSTR(MP_QSTR_DEEPSLEEP), MP_OBJ_NEW_SMALL_INT(PYB_PWR_MODE_HIBERNATE) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_POWER_ON), MP_OBJ_NEW_SMALL_INT(PYB_SLP_PWRON_RESET) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_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) }, +#endif + { MP_OBJ_NEW_QSTR(MP_QSTR_POWER_ON), MP_OBJ_NEW_SMALL_INT(PYB_RESET_POWER_ON) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_HARD_RESET), MP_OBJ_NEW_SMALL_INT(PYB_RESET_HARD) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_WDT_RESET), MP_OBJ_NEW_SMALL_INT(PYB_RESET_WDT) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_DEEPSLEEP_RESET), MP_OBJ_NEW_SMALL_INT(PYB_RESET_DEEPSLEEP) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_SOFT_RESET), MP_OBJ_NEW_SMALL_INT(PYB_RESET_SOFT) }, +#if 0 { 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) }, diff --git a/stmhal/modmachine.h b/stmhal/modmachine.h index 981728c272..042afb850c 100644 --- a/stmhal/modmachine.h +++ b/stmhal/modmachine.h @@ -31,6 +31,8 @@ #include "py/nlr.h" #include "py/obj.h" +void machine_init(void); + MP_DECLARE_CONST_FUN_OBJ(machine_info_obj); MP_DECLARE_CONST_FUN_OBJ(machine_unique_id_obj); MP_DECLARE_CONST_FUN_OBJ(machine_reset_obj); From 4a9542c0c0319ac268d227ea8daf4c36ac7e870d Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 6 Sep 2016 14:20:52 +1000 Subject: [PATCH 123/129] docs/library/machine.WDT: Add that WDT is available on pyboard. --- docs/library/machine.WDT.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/library/machine.WDT.rst b/docs/library/machine.WDT.rst index ff534fd9b4..1d79b4c4ed 100644 --- a/docs/library/machine.WDT.rst +++ b/docs/library/machine.WDT.rst @@ -14,7 +14,7 @@ Example usage:: wdt = WDT(timeout=2000) # enable it with a timeout of 2s wdt.feed() -Availability of this class: WiPy. +Availability of this class: pyboard, WiPy. Constructors ------------ From b4be5a8f3499ca19bdc9ac3ef94625529141b0ff Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 6 Sep 2016 15:30:39 +1000 Subject: [PATCH 124/129] esp8266/modnetwork: Fix wlan.scan() method so it returns all networks. According to the Arduino ESP8266 implementation the first argument to the wifi scan callback is actually a bss_info pointer. This patch fixes the iteration over this data so the first 2 entries are no longer skipped. Fixes issue #2372. --- esp8266/modnetwork.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/esp8266/modnetwork.c b/esp8266/modnetwork.c index 7cfa3ff77a..7031197fa5 100644 --- a/esp8266/modnetwork.c +++ b/esp8266/modnetwork.c @@ -130,17 +130,16 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_status_obj, esp_status); STATIC mp_obj_t *esp_scan_list = NULL; -STATIC void esp_scan_cb(scaninfo *si, STATUS status) { +STATIC void esp_scan_cb(void *result, STATUS status) { if (esp_scan_list == NULL) { // called unexpectedly return; } - if (si->pbss && status == 0) { + if (result && status == 0) { // we need to catch any memory errors nlr_buf_t nlr; if (nlr_push(&nlr) == 0) { - struct bss_info *bs; - STAILQ_FOREACH(bs, si->pbss, next) { + for (struct bss_info *bs = result; bs; bs = STAILQ_NEXT(bs, next)) { mp_obj_tuple_t *t = mp_obj_new_tuple(6, NULL); #if 1 // struct bss_info::ssid_len is not documented in SDK API Guide, From 742d8bdbe46274401aa261881d14dee50a7618d5 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Wed, 7 Sep 2016 00:59:02 +0300 Subject: [PATCH 125/129] esp8266/modmachine: Map PWR_ON_RESET to vendor's REASON_DEFAULT_RST. When dealing with a board which controls chip reset with UART's DTR/RTS, we never see REASON_DEFAULT_RST (0), only REASON_EXT_SYS_RST (6). However, trying a "raw" module with with just TXD/RXD UART connection, on power up it has REASON_DEFAULT_RST as a reset reason. --- esp8266/modmachine.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esp8266/modmachine.c b/esp8266/modmachine.c index df1ae0fcf6..a8d2de8bb8 100644 --- a/esp8266/modmachine.c +++ b/esp8266/modmachine.c @@ -260,7 +260,7 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_DEEPSLEEP), MP_ROM_INT(MACHINE_WAKE_DEEPSLEEP) }, // reset causes - { MP_ROM_QSTR(MP_QSTR_PWR_ON_RESET), MP_ROM_INT(REASON_EXT_SYS_RST) }, + { MP_ROM_QSTR(MP_QSTR_PWR_ON_RESET), MP_ROM_INT(REASON_DEFAULT_RST) }, { MP_ROM_QSTR(MP_QSTR_HARD_RESET), MP_ROM_INT(REASON_EXT_SYS_RST) }, { MP_ROM_QSTR(MP_QSTR_DEEPSLEEP_RESET), MP_ROM_INT(REASON_DEEP_SLEEP_AWAKE) }, { MP_ROM_QSTR(MP_QSTR_WDT_RESET), MP_ROM_INT(REASON_WDT_RST) }, From dab0f316d26f4c77c94d9e51c35d5f63ed118d3c Mon Sep 17 00:00:00 2001 From: Peter Hinch Date: Tue, 6 Sep 2016 11:20:22 +0100 Subject: [PATCH 126/129] docs/reference/isr_rules.rst: Two minor additions to docs for using ISR. - Refers to the technique of instantiating an object for use in an ISR by specifying it as a default argument. - Footnote detailing the fact that interrupt handlers continue to be executed at the REPL. --- docs/reference/isr_rules.rst | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/docs/reference/isr_rules.rst b/docs/reference/isr_rules.rst index b33e4dd6f2..23dcfd01f4 100644 --- a/docs/reference/isr_rules.rst +++ b/docs/reference/isr_rules.rst @@ -110,6 +110,19 @@ the flag. The memory allocation occurs in the main program code when the object The MicroPython library I/O methods usually provide an option to use a pre-allocated buffer. For example ``pyb.i2c.recv()`` can accept a mutable buffer as its first argument: this enables its use in an ISR. +A means of creating an object without employing a class or globals is as follows: + +.. code:: python + + def set_volume(t, buf=bytearray(3)): + buf[0] = 0xa5 + buf[1] = t >> 4 + buf[2] = 0x5a + return buf + +The compiler instantiates the default ``buf`` argument when the function is +loaded for the first time (usually when the module it's in is imported). + Use of Python objects ~~~~~~~~~~~~~~~~~~~~~ @@ -300,3 +313,20 @@ that access to the critical variables is denied. A simple example of a mutex may but only for the duration of eight machine instructions: the benefit of this approach is that other interrupts are virtually unaffected. +Interrupts and the REPL +~~~~~~~~~~~~~~~~~~~~~~~ + +Interrupt handlers, such as those associated with timers, can continue to run +after a program terminates. This may produce unexpected results where you might +have expected the object raising the callback to have gone out of scope. For +example on the Pyboard: + +.. code:: python + + def bar(): + foo = pyb.Timer(2, freq=4, callback=lambda t: print('.', end='')) + + bar() + +This continues to run until the timer is explicitly disabled or the board is +reset with ``ctrl D``. From f3b5480be7243684e31e4631e3da49c725fa7234 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 8 Sep 2016 12:50:38 +1000 Subject: [PATCH 127/129] stmhal,cc3200,esp8266: Consistently use PWRON_RESET constant. machine.POWER_ON is renamed to machine.PWRON_RESET to match other reset-cause constants that all end in _RESET. The cc3200 port keeps a legacy definition of POWER_ON for backwards compatibility. --- cc3200/mods/modmachine.c | 3 ++- docs/library/machine.rst | 2 +- esp8266/modmachine.c | 2 +- stmhal/modmachine.c | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/cc3200/mods/modmachine.c b/cc3200/mods/modmachine.c index 704defb337..410d5b944c 100644 --- a/cc3200/mods/modmachine.c +++ b/cc3200/mods/modmachine.c @@ -198,7 +198,8 @@ STATIC const mp_map_elem_t machine_module_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_IDLE), MP_OBJ_NEW_SMALL_INT(PYB_PWR_MODE_ACTIVE) }, { MP_OBJ_NEW_QSTR(MP_QSTR_SLEEP), MP_OBJ_NEW_SMALL_INT(PYB_PWR_MODE_LPDS) }, { MP_OBJ_NEW_QSTR(MP_QSTR_DEEPSLEEP), MP_OBJ_NEW_SMALL_INT(PYB_PWR_MODE_HIBERNATE) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_POWER_ON), MP_OBJ_NEW_SMALL_INT(PYB_SLP_PWRON_RESET) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_POWER_ON), MP_OBJ_NEW_SMALL_INT(PYB_SLP_PWRON_RESET) }, // legacy constant + { MP_OBJ_NEW_QSTR(MP_QSTR_PWRON_RESET), MP_OBJ_NEW_SMALL_INT(PYB_SLP_PWRON_RESET) }, { MP_OBJ_NEW_QSTR(MP_QSTR_HARD_RESET), MP_OBJ_NEW_SMALL_INT(PYB_SLP_HARD_RESET) }, { MP_OBJ_NEW_QSTR(MP_QSTR_WDT_RESET), MP_OBJ_NEW_SMALL_INT(PYB_SLP_WDT_RESET) }, { MP_OBJ_NEW_QSTR(MP_QSTR_DEEPSLEEP_RESET), MP_OBJ_NEW_SMALL_INT(PYB_SLP_HIB_RESET) }, diff --git a/docs/library/machine.rst b/docs/library/machine.rst index 0f361a7cb7..46d8eea71f 100644 --- a/docs/library/machine.rst +++ b/docs/library/machine.rst @@ -125,7 +125,7 @@ Constants irq wake values -.. data:: machine.POWER_ON +.. data:: machine.PWRON_RESET .. data:: machine.HARD_RESET .. data:: machine.WDT_RESET .. data:: machine.DEEPSLEEP_RESET diff --git a/esp8266/modmachine.c b/esp8266/modmachine.c index a8d2de8bb8..b0b7f3a1a3 100644 --- a/esp8266/modmachine.c +++ b/esp8266/modmachine.c @@ -260,7 +260,7 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_DEEPSLEEP), MP_ROM_INT(MACHINE_WAKE_DEEPSLEEP) }, // reset causes - { MP_ROM_QSTR(MP_QSTR_PWR_ON_RESET), MP_ROM_INT(REASON_DEFAULT_RST) }, + { MP_ROM_QSTR(MP_QSTR_PWRON_RESET), MP_ROM_INT(REASON_DEFAULT_RST) }, { MP_ROM_QSTR(MP_QSTR_HARD_RESET), MP_ROM_INT(REASON_EXT_SYS_RST) }, { MP_ROM_QSTR(MP_QSTR_DEEPSLEEP_RESET), MP_ROM_INT(REASON_DEEP_SLEEP_AWAKE) }, { MP_ROM_QSTR(MP_QSTR_WDT_RESET), MP_ROM_INT(REASON_WDT_RST) }, diff --git a/stmhal/modmachine.c b/stmhal/modmachine.c index dbeabec55b..ca17eff807 100644 --- a/stmhal/modmachine.c +++ b/stmhal/modmachine.c @@ -543,7 +543,7 @@ STATIC const mp_map_elem_t machine_module_globals_table[] = { { 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) }, #endif - { MP_OBJ_NEW_QSTR(MP_QSTR_POWER_ON), MP_OBJ_NEW_SMALL_INT(PYB_RESET_POWER_ON) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_PWRON_RESET), MP_OBJ_NEW_SMALL_INT(PYB_RESET_POWER_ON) }, { MP_OBJ_NEW_QSTR(MP_QSTR_HARD_RESET), MP_OBJ_NEW_SMALL_INT(PYB_RESET_HARD) }, { MP_OBJ_NEW_QSTR(MP_QSTR_WDT_RESET), MP_OBJ_NEW_SMALL_INT(PYB_RESET_WDT) }, { MP_OBJ_NEW_QSTR(MP_QSTR_DEEPSLEEP_RESET), MP_OBJ_NEW_SMALL_INT(PYB_RESET_DEEPSLEEP) }, From 763e04bba57c45589b75bc9210fbb8272d358c89 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 8 Sep 2016 13:06:29 +1000 Subject: [PATCH 128/129] tests/run-tests: Disable thread/stress_recurse.py test on Travis. It has reliability issues (cause unknown at this time). --- tests/run-tests | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/run-tests b/tests/run-tests index 5e8819729e..059e4e910f 100755 --- a/tests/run-tests +++ b/tests/run-tests @@ -203,6 +203,7 @@ def run_tests(pyb, tests, args): skip_tests.add('thread/thread_gc1.py') # has reliability issues skip_tests.add('thread/thread_lock4.py') # has reliability issues skip_tests.add('thread/stress_heap.py') # has reliability issues + skip_tests.add('thread/stress_recurse.py') # has reliability issues if not has_complex: skip_tests.add('float/complex1.py') From 3611dcc260cef08eaa497cea4e3ca17977848b6c Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 9 Sep 2016 14:07:09 +1000 Subject: [PATCH 129/129] docs: Bump version to 1.8.4. --- docs/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index fbc89afc6a..a737e43ef1 100755 --- a/docs/conf.py +++ b/docs/conf.py @@ -99,7 +99,7 @@ copyright = '2014-2016, Damien P. George and contributors' # The short X.Y version. version = '1.8' # The full version, including alpha/beta/rc tags. -release = '1.8.3' +release = '1.8.4' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages.