From 2146cdab5e276f9c1fc26156579491d3d3a2c3ac Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Tue, 9 Aug 2016 21:13:27 +0300 Subject: 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(-) (limited to 'docs/esp8266') 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. -- cgit v1.2.3 From 5e01fb01b3b04bc86e0c1f14063b3f956ed58661 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Wed, 10 Aug 2016 21:39:23 +0300 Subject: 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(+) (limited to 'docs/esp8266') 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. -- cgit v1.2.3 From 8e7dfea803f618beaa2ad976dff0b196e449d5d9 Mon Sep 17 00:00:00 2001 From: Radomir Dopieralski Date: Tue, 7 Jun 2016 21:40:56 +0200 Subject: 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 (limited to 'docs/esp8266') 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, +}; -- cgit v1.2.3 From ed0a06a93fc275e4f3980b81e4e5314ed63279c6 Mon Sep 17 00:00:00 2001 From: Radomir Dopieralski Date: Sat, 27 Aug 2016 19:07:14 +0200 Subject: 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(-) (limited to 'docs/esp8266') 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 -- cgit v1.2.3 From 13c5a228c9ec9881087bdddd162f3b633edc3aa5 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 29 Aug 2016 12:52:50 +1000 Subject: 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(-) (limited to 'docs/esp8266') 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() -- cgit v1.2.3 From 76dcaddc0f647bd597013980108b0b28bb6eb1c9 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 29 Aug 2016 17:40:36 +1000 Subject: docs/esp8266/quickref: Add internal links to docs for some modules. --- docs/esp8266/quickref.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'docs/esp8266') 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 -- cgit v1.2.3 From 20da9064d7492b2f37a2140c17e468fb5785a593 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sun, 4 Sep 2016 21:13:55 +0300 Subject: 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(-) (limited to 'docs/esp8266') 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 ------- -- cgit v1.2.3 From b4df3e74e15ac1658c125b13bbaca5203bab5505 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sun, 4 Sep 2016 23:31:05 +0300 Subject: docs/esp8266/quickref: Further improvements for SPI subsections. Consistency and formatting. --- docs/esp8266/quickref.rst | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'docs/esp8266') 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 ------- -- cgit v1.2.3