From ccaa5f5b0bad69f0f0ea81151e34c218fe13ce66 Mon Sep 17 00:00:00 2001 From: Peter Hinch Date: Sun, 15 Oct 2017 18:26:58 +0100 Subject: drivers/nrf24l01: Make driver and test run on pyboard, ESP8266, ESP32. --- drivers/nrf24l01/nrf24l01.py | 9 +++---- drivers/nrf24l01/nrf24l01test.py | 53 +++++++++++++++++++++++++++++++--------- 2 files changed, 46 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/nrf24l01/nrf24l01.py b/drivers/nrf24l01/nrf24l01.py index 7274a7927..a95d2b5ca 100644 --- a/drivers/nrf24l01/nrf24l01.py +++ b/drivers/nrf24l01/nrf24l01.py @@ -62,12 +62,11 @@ class NRF24L01: # init the SPI bus and pins self.init_spi(4000000) - cs.init(cs.OUT, value=1) - ce.init(ce.OUT, value=0) # reset everything - self.ce(0) - self.cs(1) + ce.init(ce.OUT, value=0) + cs.init(cs.OUT, value=1) + self.payload_size = payload_size self.pipe0_read_addr = None utime.sleep_ms(5) @@ -215,7 +214,7 @@ class NRF24L01: # blocking wait for tx complete def send(self, buf, timeout=500): - send_nonblock = self.send_start(buf) + self.send_start(buf) start = utime.ticks_ms() result = None while result is None and utime.ticks_diff(utime.ticks_ms(), start) < timeout: diff --git a/drivers/nrf24l01/nrf24l01test.py b/drivers/nrf24l01/nrf24l01test.py index 5413511c3..876b2bbfa 100644 --- a/drivers/nrf24l01/nrf24l01test.py +++ b/drivers/nrf24l01/nrf24l01test.py @@ -1,14 +1,38 @@ -"""Test for nrf24l01 module.""" +"""Test for nrf24l01 module. Portable between MicroPython targets.""" -import struct +import sys +import ustruct as struct import utime from machine import Pin, SPI from nrf24l01 import NRF24L01 +from micropython import const + +# Slave pause between receiving data and checking for further packets. +_RX_POLL_DELAY = const(15) +# Slave pauses an additional _SLAVE_SEND_DELAY ms after receiving data and before +# transmitting to allow the (remote) master time to get into receive mode. The +# master may be a slow device. Value tested with Pyboard, ESP32 and ESP8266. +_SLAVE_SEND_DELAY = const(10) + +if sys.platform == 'pyboard': + cfg = {'spi': 2, 'miso': 'Y7', 'mosi': 'Y8', 'sck': 'Y6', 'csn': 'Y5', 'ce': 'Y4'} +elif sys.platform == 'esp8266': # Hardware SPI + cfg = {'spi': 1, 'miso': 12, 'mosi': 13, 'sck': 14, 'csn': 4, 'ce': 5} +elif sys.platform == 'esp32': # Software SPI + cfg = {'spi': -1, 'miso': 32, 'mosi': 33, 'sck': 25, 'csn': 26, 'ce': 27} +else: + raise ValueError('Unsupported platform {}'.format(sys.platform)) pipes = (b'\xf0\xf0\xf0\xf0\xe1', b'\xf0\xf0\xf0\xf0\xd2') def master(): - nrf = NRF24L01(SPI(2), Pin('Y5'), Pin('Y4'), payload_size=8) + csn = Pin(cfg['csn'], mode=Pin.OUT, value=1) + ce = Pin(cfg['ce'], mode=Pin.OUT, value=0) + if cfg['spi'] == -1: + spi = SPI(-1, sck=Pin(cfg['sck']), mosi=Pin(cfg['mosi']), miso=Pin(cfg['miso'])) + nrf = NRF24L01(spi, csn, ce, payload_size=8) + else: + nrf = NRF24L01(SPI(cfg['spi']), csn, ce, payload_size=8) nrf.open_tx_pipe(pipes[0]) nrf.open_rx_pipe(1, pipes[1]) @@ -60,7 +84,13 @@ def master(): print('master finished sending; successes=%d, failures=%d' % (num_successes, num_failures)) def slave(): - nrf = NRF24L01(SPI(2), Pin('Y5'), Pin('Y4'), payload_size=8) + csn = Pin(cfg['csn'], mode=Pin.OUT, value=1) + ce = Pin(cfg['ce'], mode=Pin.OUT, value=0) + if cfg['spi'] == -1: + spi = SPI(-1, sck=Pin(cfg['sck']), mosi=Pin(cfg['mosi']), miso=Pin(cfg['miso'])) + nrf = NRF24L01(spi, csn, ce, payload_size=8) + else: + nrf = NRF24L01(SPI(cfg['spi']), csn, ce, payload_size=8) nrf.open_tx_pipe(pipes[1]) nrf.open_rx_pipe(1, pipes[0]) @@ -69,7 +99,6 @@ def slave(): print('NRF24L01 slave mode, waiting for packets... (ctrl-C to stop)') while True: - machine.idle() if nrf.any(): while nrf.any(): buf = nrf.recv() @@ -81,8 +110,10 @@ def slave(): else: led.off() led_state >>= 1 - utime.sleep_ms(15) + utime.sleep_ms(_RX_POLL_DELAY) + # Give master time to get into receive mode. + utime.sleep_ms(_SLAVE_SEND_DELAY) nrf.stop_listening() try: nrf.send(struct.pack('i', millis)) @@ -99,9 +130,9 @@ except: print('NRF24L01 test module loaded') print('NRF24L01 pinout for test:') -print(' CE on Y4') -print(' CSN on Y5') -print(' SCK on Y6') -print(' MISO on Y7') -print(' MOSI on Y8') +print(' CE on', cfg['ce']) +print(' CSN on', cfg['csn']) +print(' SCK on', cfg['sck']) +print(' MISO on', cfg['miso']) +print(' MOSI on', cfg['mosi']) print('run nrf24l01test.slave() on slave, then nrf24l01test.master() on master') -- cgit v1.2.3 From 479392a56e6edd8449e594c0e5c1e8f5176411ab Mon Sep 17 00:00:00 2001 From: Peter Hinch Date: Tue, 12 Dec 2017 08:13:48 +0000 Subject: drivers/display/ssd1306: Make SSD1306 class inherit from FrameBuffer. --- drivers/display/ssd1306.py | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/display/ssd1306.py b/drivers/display/ssd1306.py index cd358d00e..cebe10e67 100644 --- a/drivers/display/ssd1306.py +++ b/drivers/display/ssd1306.py @@ -23,29 +23,16 @@ SET_PRECHARGE = const(0xd9) SET_VCOM_DESEL = const(0xdb) SET_CHARGE_PUMP = const(0x8d) - -class SSD1306: +# Subclassing FrameBuffer provides support for graphics primitives +# http://docs.micropython.org/en/latest/pyboard/library/framebuf.html +class SSD1306(framebuf.FrameBuffer): def __init__(self, width, height, external_vcc): self.width = width self.height = height self.external_vcc = external_vcc self.pages = self.height // 8 self.buffer = bytearray(self.pages * self.width) - fb = framebuf.FrameBuffer(self.buffer, self.width, self.height, framebuf.MONO_VLSB) - self.framebuf = fb - # Provide methods for accessing FrameBuffer graphics primitives. This is a - # workround because inheritance from a native class is currently unsupported. - # http://docs.micropython.org/en/latest/pyboard/library/framebuf.html - self.fill = fb.fill - self.pixel = fb.pixel - self.hline = fb.hline - self.vline = fb.vline - self.line = fb.line - self.rect = fb.rect - self.fill_rect = fb.fill_rect - self.text = fb.text - self.scroll = fb.scroll - self.blit = fb.blit + super.__init__(self.buffer, self.width, self.height, framebuf.MONO_VLSB) self.init_display() def init_display(self): -- cgit v1.2.3 From b90f51f86a0824d646131538320d0405ab3d0187 Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Wed, 20 Dec 2017 01:15:26 +0100 Subject: drivers/sdcard: Support old SD cards (<=2GB). --- drivers/sdcard/sdcard.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/sdcard/sdcard.py b/drivers/sdcard/sdcard.py index 75a0c501e..fedb76f02 100644 --- a/drivers/sdcard/sdcard.py +++ b/drivers/sdcard/sdcard.py @@ -96,9 +96,14 @@ class SDCard: raise OSError("no response from SD card") csd = bytearray(16) self.readinto(csd) - if csd[0] & 0xc0 != 0x40: + if csd[0] & 0xc0 == 0x40: # CSD version 2.0 + self.sectors = ((csd[8] << 8 | csd[9]) + 1) * 2014 + elif csd[0] & 0xc0 == 0x00: # CSD version 1.0 (old, <=2GB) + c_size = csd[6] & 0b11 | csd[7] << 2 | (csd[8] & 0b11000000) << 4 + c_size_mult = ((csd[9] & 0b11) << 1) | csd[10] >> 7 + self.sectors = (c_size + 1) * (2 ** (c_size_mult + 2)) + else: raise OSError("SD card CSD format not supported") - self.sectors = ((csd[8] << 8 | csd[9]) + 1) * 2014 #print('sectors', self.sectors) # CMD16: set block length to 512 bytes -- cgit v1.2.3 From bb3412291a0f88cb958852b268d5dc43db23d4fb Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Tue, 2 Jan 2018 21:36:46 +1100 Subject: drivers/display/ssd1306: Fix super() call in SSD1306 driver. --- drivers/display/ssd1306.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/display/ssd1306.py b/drivers/display/ssd1306.py index cebe10e67..178b4911d 100644 --- a/drivers/display/ssd1306.py +++ b/drivers/display/ssd1306.py @@ -32,7 +32,7 @@ class SSD1306(framebuf.FrameBuffer): self.external_vcc = external_vcc self.pages = self.height // 8 self.buffer = bytearray(self.pages * self.width) - super.__init__(self.buffer, self.width, self.height, framebuf.MONO_VLSB) + super().__init__(self.buffer, self.width, self.height, framebuf.MONO_VLSB) self.init_display() def init_display(self): -- cgit v1.2.3 From a275cb0f487cd6517760271dc01d369c32600c63 Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Tue, 19 Dec 2017 23:54:24 +0100 Subject: drivers/sdcard: Avoid allocation on the heap. This commit fixes two things: 1. Do not allocate on the heap in readblocks() - unless the block size is bigger than 512 bytes. 2. Raise an error instead of returning 1 to indicate an error: the FAT block device layer does not check the return value. And other backends (e.g. esp32 blockdev) also raise an error instead of returning non-zero. --- drivers/sdcard/sdcard.py | 48 ++++++++++++++++++++++-------------------------- 1 file changed, 22 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/sdcard/sdcard.py b/drivers/sdcard/sdcard.py index fedb76f02..815631cae 100644 --- a/drivers/sdcard/sdcard.py +++ b/drivers/sdcard/sdcard.py @@ -46,6 +46,7 @@ class SDCard: self.cmdbuf = bytearray(6) self.dummybuf = bytearray(512) + self.tokenbuf = bytearray(1) for i in range(512): self.dummybuf[i] = 0xff self.dummybuf_memoryview = memoryview(self.dummybuf) @@ -134,7 +135,7 @@ class SDCard: return raise OSError("timeout waiting for v2 card") - def cmd(self, cmd, arg, crc, final=0, release=True): + def cmd(self, cmd, arg, crc, final=0, release=True, skip1=False): self.cs(0) # create and send the command @@ -147,9 +148,13 @@ class SDCard: buf[5] = crc self.spi.write(buf) + if skip1: + self.spi.readinto(self.tokenbuf, 0xff) + # wait for the response (response[7] == 0) for i in range(_CMD_TIMEOUT): - response = self.spi.read(1, 0xff)[0] + self.spi.readinto(self.tokenbuf, 0xff) + response = self.tokenbuf[0] if not (response & 0x80): # this could be a big-endian integer that we are getting here for j in range(final): @@ -164,27 +169,19 @@ class SDCard: self.spi.write(b'\xff') return -1 - def cmd_nodata(self, cmd): - 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(1) - self.spi.write(b'\xff') - return 0 # OK - self.cs(1) - self.spi.write(b'\xff') - return 1 # timeout - def readinto(self, buf): self.cs(0) # read until start byte (0xff) - while self.spi.read(1, 0xff)[0] != 0xfe: - pass + while True: + self.spi.readinto(self.tokenbuf, 0xff) + if self.tokenbuf[0] == 0xfe: + break # read data - mv = self.dummybuf_memoryview[:len(buf)] + mv = self.dummybuf_memoryview + if len(buf) != len(mv): + mv = mv[:len(buf)] self.spi.write_readinto(mv, buf) # read checksum @@ -231,26 +228,26 @@ class SDCard: return self.sectors def readblocks(self, block_num, buf): - nblocks, err = divmod(len(buf), 512) - assert nblocks and not err, 'Buffer length is invalid' + nblocks = len(buf) // 512 + assert nblocks and not len(buf) % 512, 'Buffer length is invalid' if nblocks == 1: # CMD17: set read address for single block if self.cmd(17, block_num * self.cdv, 0) != 0: - return 1 + raise OSError(5) # EIO # receive the data self.readinto(buf) else: # CMD18: set read address for multiple blocks if self.cmd(18, block_num * self.cdv, 0) != 0: - return 1 + raise OSError(5) # EIO offset = 0 mv = memoryview(buf) while nblocks: self.readinto(mv[offset : offset + 512]) offset += 512 nblocks -= 1 - return self.cmd_nodata(b'\x0c') # cmd 12 - return 0 + if self.cmd(12, 0, 0xff, skip1=True): + raise OSError(5) # EIO def writeblocks(self, block_num, buf): nblocks, err = divmod(len(buf), 512) @@ -258,14 +255,14 @@ class SDCard: if nblocks == 1: # CMD24: set write address for single block if self.cmd(24, block_num * self.cdv, 0) != 0: - return 1 + raise OSError(5) # EIO # send the data self.write(_TOKEN_DATA, buf) else: # CMD25: set write address for first block if self.cmd(25, block_num * self.cdv, 0) != 0: - return 1 + raise OSError(5) # EIO # send the data offset = 0 mv = memoryview(buf) @@ -274,4 +271,3 @@ class SDCard: offset += 512 nblocks -= 1 self.write_token(_TOKEN_STOP_TRAN) - return 0 -- cgit v1.2.3 From a40ce1d829eca6fe0fad0b7f4478a6651903dd2a Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 31 Jan 2018 18:11:06 +1100 Subject: esp8266/modules: Move dht.py driver to drivers/dht directory. --- drivers/dht/dht.py | 32 ++++++++++++++++++++++++++++++++ ports/esp32/modules/dht.py | 2 +- ports/esp8266/modules/dht.py | 33 +-------------------------------- 3 files changed, 34 insertions(+), 33 deletions(-) create mode 100644 drivers/dht/dht.py mode change 100644 => 120000 ports/esp8266/modules/dht.py (limited to 'drivers') diff --git a/drivers/dht/dht.py b/drivers/dht/dht.py new file mode 100644 index 000000000..9a69e7e07 --- /dev/null +++ b/drivers/dht/dht.py @@ -0,0 +1,32 @@ +# DHT11/DHT22 driver for MicroPython on ESP8266 +# MIT license; Copyright (c) 2016 Damien P. George + +import esp + +class DHTBase: + def __init__(self, pin): + self.pin = pin + self.buf = bytearray(5) + + def measure(self): + buf = self.buf + esp.dht_readinto(self.pin, buf) + if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xff != buf[4]: + raise Exception("checksum error") + +class DHT11(DHTBase): + def humidity(self): + return self.buf[0] + + def temperature(self): + return self.buf[2] + +class DHT22(DHTBase): + def humidity(self): + return (self.buf[0] << 8 | self.buf[1]) * 0.1 + + def temperature(self): + t = ((self.buf[2] & 0x7f) << 8 | self.buf[3]) * 0.1 + if self.buf[2] & 0x80: + t = -t + return t diff --git a/ports/esp32/modules/dht.py b/ports/esp32/modules/dht.py index b6acf2853..2aa2f5cbf 120000 --- a/ports/esp32/modules/dht.py +++ b/ports/esp32/modules/dht.py @@ -1 +1 @@ -../../esp8266/modules/dht.py \ No newline at end of file +../../../drivers/dht/dht.py \ No newline at end of file diff --git a/ports/esp8266/modules/dht.py b/ports/esp8266/modules/dht.py deleted file mode 100644 index 9a69e7e07..000000000 --- a/ports/esp8266/modules/dht.py +++ /dev/null @@ -1,32 +0,0 @@ -# DHT11/DHT22 driver for MicroPython on ESP8266 -# MIT license; Copyright (c) 2016 Damien P. George - -import esp - -class DHTBase: - def __init__(self, pin): - self.pin = pin - self.buf = bytearray(5) - - def measure(self): - buf = self.buf - esp.dht_readinto(self.pin, buf) - if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xff != buf[4]: - raise Exception("checksum error") - -class DHT11(DHTBase): - def humidity(self): - return self.buf[0] - - def temperature(self): - return self.buf[2] - -class DHT22(DHTBase): - def humidity(self): - return (self.buf[0] << 8 | self.buf[1]) * 0.1 - - def temperature(self): - t = ((self.buf[2] & 0x7f) << 8 | self.buf[3]) * 0.1 - if self.buf[2] & 0x80: - t = -t - return t diff --git a/ports/esp8266/modules/dht.py b/ports/esp8266/modules/dht.py new file mode 120000 index 000000000..2aa2f5cbf --- /dev/null +++ b/ports/esp8266/modules/dht.py @@ -0,0 +1 @@ +../../../drivers/dht/dht.py \ No newline at end of file -- cgit v1.2.3 From efdda2c62deba4f4f24672e441cffe496158bb35 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 31 Jan 2018 18:12:53 +1100 Subject: stm32: Add support for DHT11/DHT22 sensors. --- drivers/dht/dht.py | 7 +++++-- ports/stm32/Makefile | 1 + ports/stm32/modpyb.c | 4 ++++ ports/stm32/modules/dht.py | 1 + 4 files changed, 11 insertions(+), 2 deletions(-) create mode 120000 ports/stm32/modules/dht.py (limited to 'drivers') diff --git a/drivers/dht/dht.py b/drivers/dht/dht.py index 9a69e7e07..eed61df7c 100644 --- a/drivers/dht/dht.py +++ b/drivers/dht/dht.py @@ -1,7 +1,10 @@ # DHT11/DHT22 driver for MicroPython on ESP8266 # MIT license; Copyright (c) 2016 Damien P. George -import esp +try: + from esp import dht_readinto +except: + from pyb import dht_readinto class DHTBase: def __init__(self, pin): @@ -10,7 +13,7 @@ class DHTBase: def measure(self): buf = self.buf - esp.dht_readinto(self.pin, buf) + dht_readinto(self.pin, buf) if (buf[0] + buf[1] + buf[2] + buf[3]) & 0xff != buf[4]: raise Exception("checksum error") diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index 68b007471..65962bea6 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -186,6 +186,7 @@ EXTMOD_SRC_C = $(addprefix extmod/,\ DRIVERS_SRC_C = $(addprefix drivers/,\ memory/spiflash.c \ + dht/dht.c \ ) SRC_C = \ diff --git a/ports/stm32/modpyb.c b/ports/stm32/modpyb.c index 4d186e278..970b5b954 100644 --- a/ports/stm32/modpyb.c +++ b/ports/stm32/modpyb.c @@ -34,6 +34,7 @@ #include "lib/utils/pyexec.h" #include "lib/oofatfs/ff.h" #include "lib/oofatfs/diskio.h" +#include "drivers/dht/dht.h" #include "gccollect.h" #include "stm32_it.h" #include "irq.h" @@ -168,6 +169,9 @@ STATIC const mp_rom_map_elem_t pyb_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_sync), MP_ROM_PTR(&mod_os_sync_obj) }, { MP_ROM_QSTR(MP_QSTR_mount), MP_ROM_PTR(&mp_vfs_mount_obj) }, + // This function is not intended to be public and may be moved elsewhere + { MP_ROM_QSTR(MP_QSTR_dht_readinto), MP_ROM_PTR(&dht_readinto_obj) }, + { MP_ROM_QSTR(MP_QSTR_Timer), MP_ROM_PTR(&pyb_timer_type) }, #if MICROPY_HW_ENABLE_RNG diff --git a/ports/stm32/modules/dht.py b/ports/stm32/modules/dht.py new file mode 120000 index 000000000..2aa2f5cbf --- /dev/null +++ b/ports/stm32/modules/dht.py @@ -0,0 +1 @@ +../../../drivers/dht/dht.py \ No newline at end of file -- cgit v1.2.3 From a44892dd0d79e039b4a4d1ec3ec7b9a6ed829ee6 Mon Sep 17 00:00:00 2001 From: Hemanth kumar Date: Wed, 17 Jan 2018 01:46:25 +0530 Subject: drivers/sdcard: Update doc for ESP8266 to use correct SPI number. machine.SPI(0) results in ValueError on ESP8266. SPI(1) is the user hardware SPI port (or use SPI(-1) for software SPI). --- drivers/sdcard/sdcard.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/sdcard/sdcard.py b/drivers/sdcard/sdcard.py index 815631cae..719eb982e 100644 --- a/drivers/sdcard/sdcard.py +++ b/drivers/sdcard/sdcard.py @@ -14,7 +14,7 @@ Example usage on pyboard: Example usage on ESP8266: import machine, sdcard, os - sd = sdcard.SDCard(machine.SPI(0), machine.Pin(15)) + sd = sdcard.SDCard(machine.SPI(1), machine.Pin(15)) os.umount() os.VfsFat(sd, "") os.listdir() -- cgit v1.2.3 From 93d5c9e1c4cb2850dc04abc0fa78e9b4c159747c Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 5 Feb 2018 13:45:50 +1100 Subject: drivers/cc3200: Update to work with new stm32 SPI API. --- drivers/cc3000/src/ccspi.c | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/cc3000/src/ccspi.c b/drivers/cc3000/src/ccspi.c index 820be809b..1dcd61884 100644 --- a/drivers/cc3000/src/ccspi.c +++ b/drivers/cc3000/src/ccspi.c @@ -50,7 +50,7 @@ #endif // these need to be set to valid values before anything in this file will work -STATIC SPI_HandleTypeDef *SPI_HANDLE = NULL; +STATIC const spi_t *SPI_HANDLE = NULL; STATIC const pin_obj_t *PIN_CS = NULL; STATIC const pin_obj_t *PIN_EN = NULL; STATIC const pin_obj_t *PIN_IRQ = NULL; @@ -134,17 +134,18 @@ void SpiOpen(gcSpiHandleRx pfRxHandler) wlan_tx_buffer[CC3000_TX_BUFFER_SIZE - 1] = CC3000_BUFFER_MAGIC_NUMBER; /* SPI configuration */ - SPI_HANDLE->Init.Mode = SPI_MODE_MASTER; - SPI_HANDLE->Init.Direction = SPI_DIRECTION_2LINES; - SPI_HANDLE->Init.DataSize = SPI_DATASIZE_8BIT; - SPI_HANDLE->Init.CLKPolarity = SPI_POLARITY_LOW; - SPI_HANDLE->Init.CLKPhase = SPI_PHASE_2EDGE; - SPI_HANDLE->Init.NSS = SPI_NSS_SOFT; - SPI_HANDLE->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8; - SPI_HANDLE->Init.FirstBit = SPI_FIRSTBIT_MSB; - SPI_HANDLE->Init.TIMode = SPI_TIMODE_DISABLED; - SPI_HANDLE->Init.CRCCalculation = SPI_CRCCALCULATION_DISABLED; - SPI_HANDLE->Init.CRCPolynomial = 7; + SPI_InitTypeDef *init = &SPI_HANDLE->spi->Init; + init->Mode = SPI_MODE_MASTER; + init->Direction = SPI_DIRECTION_2LINES; + init->DataSize = SPI_DATASIZE_8BIT; + init->CLKPolarity = SPI_POLARITY_LOW; + init->CLKPhase = SPI_PHASE_2EDGE; + init->NSS = SPI_NSS_SOFT; + init->BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8; + init->FirstBit = SPI_FIRSTBIT_MSB; + init->TIMode = SPI_TIMODE_DISABLED; + init->CRCCalculation = SPI_CRCCALCULATION_DISABLED; + init->CRCPolynomial = 7; spi_init(SPI_HANDLE, false); // configure wlan CS and EN pins @@ -167,7 +168,7 @@ void SpiOpen(gcSpiHandleRx pfRxHandler) actual communications start, it might be required */ CS_LOW(); uint8_t buf[1]; - HAL_SPI_Receive(SPI_HANDLE, buf, sizeof(buf), SPI_TIMEOUT); + HAL_SPI_Receive(SPI_HANDLE->spi, buf, sizeof(buf), SPI_TIMEOUT); CS_HIGH(); // register EXTI @@ -192,7 +193,7 @@ STATIC void SpiWriteDataSynchronous(unsigned char *data, unsigned short size) { DEBUG_printf("SpiWriteDataSynchronous(data=%p [%x %x %x %x], size=%u)\n", data, data[0], data[1], data[2], data[3], size); __disable_irq(); - if (HAL_SPI_TransmitReceive(SPI_HANDLE, data, data, size, SPI_TIMEOUT) != HAL_OK) { + if (HAL_SPI_TransmitReceive(SPI_HANDLE->spi, data, data, size, SPI_TIMEOUT) != HAL_OK) { //BREAK(); } __enable_irq(); @@ -203,7 +204,7 @@ STATIC void SpiReadDataSynchronous(unsigned char *data, unsigned short size) { memset(data, READ, size); __disable_irq(); - if (HAL_SPI_TransmitReceive(SPI_HANDLE, data, data, size, SPI_TIMEOUT) != HAL_OK) { + if (HAL_SPI_TransmitReceive(SPI_HANDLE->spi, data, data, size, SPI_TIMEOUT) != HAL_OK) { //BREAK(); } __enable_irq(); -- cgit v1.2.3 From 3759aa2cc98c96b869f3db5c4ac51778d3726669 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sun, 18 Feb 2018 23:40:54 +1100 Subject: drivers/sdcard: Update SD mounting example code for ESP8266. --- drivers/sdcard/sdcard.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/sdcard/sdcard.py b/drivers/sdcard/sdcard.py index 719eb982e..8f28b476e 100644 --- a/drivers/sdcard/sdcard.py +++ b/drivers/sdcard/sdcard.py @@ -15,9 +15,8 @@ Example usage on ESP8266: import machine, sdcard, os sd = sdcard.SDCard(machine.SPI(1), machine.Pin(15)) - os.umount() - os.VfsFat(sd, "") - os.listdir() + os.mount(sd, '/sd') + os.listdir('/') """ -- cgit v1.2.3 From 1da2d45de6363d4014d379b78f114cd3d1649d7b Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 2 Mar 2018 10:44:38 +1100 Subject: drivers/bus: Add QSPI abstract type with software QSPI implementation. A new directory drivers/bus/ is introduced, which can hold implementations of bus drivers. A software QSPI implementation is added. --- drivers/bus/qspi.h | 57 ++++++++++++++ drivers/bus/softqspi.c | 203 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 260 insertions(+) create mode 100644 drivers/bus/qspi.h create mode 100644 drivers/bus/softqspi.c (limited to 'drivers') diff --git a/drivers/bus/qspi.h b/drivers/bus/qspi.h new file mode 100644 index 000000000..31c9d14fc --- /dev/null +++ b/drivers/bus/qspi.h @@ -0,0 +1,57 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017-2018 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_DRIVERS_BUS_QSPI_H +#define MICROPY_INCLUDED_DRIVERS_BUS_QSPI_H + +#include "py/mphal.h" + +enum { + MP_QSPI_IOCTL_INIT, + MP_QSPI_IOCTL_DEINIT, + MP_QSPI_IOCTL_BUS_ACQUIRE, + MP_QSPI_IOCTL_BUS_RELEASE, +}; + +typedef struct _mp_qspi_proto_t { + int (*ioctl)(void *self, uint32_t cmd); + void (*write_cmd_data)(void *self, uint8_t cmd, size_t len, uint32_t data); + void (*write_cmd_addr_data)(void *self, uint8_t cmd, uint32_t addr, size_t len, const uint8_t *src); + uint32_t (*read_cmd)(void *self, uint8_t cmd, size_t len); + void (*read_cmd_qaddr_qdata)(void *self, uint8_t cmd, uint32_t addr, size_t len, uint8_t *dest); +} mp_qspi_proto_t; + +typedef struct _mp_soft_qspi_obj_t { + mp_hal_pin_obj_t cs; + mp_hal_pin_obj_t clk; + mp_hal_pin_obj_t io0; + mp_hal_pin_obj_t io1; + mp_hal_pin_obj_t io2; + mp_hal_pin_obj_t io3; +} mp_soft_qspi_obj_t; + +extern const mp_qspi_proto_t mp_soft_qspi_proto; + +#endif // MICROPY_INCLUDED_DRIVERS_BUS_QSPI_H diff --git a/drivers/bus/softqspi.c b/drivers/bus/softqspi.c new file mode 100644 index 000000000..10c599246 --- /dev/null +++ b/drivers/bus/softqspi.c @@ -0,0 +1,203 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017-2018 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 "drivers/bus/qspi.h" + +#define CS_LOW(self) mp_hal_pin_write(self->cs, 0) +#define CS_HIGH(self) mp_hal_pin_write(self->cs, 1) + +#ifdef MICROPY_HW_SOFTQSPI_SCK_LOW + +// Use externally provided functions for SCK control and IO reading +#define SCK_LOW(self) MICROPY_HW_SOFTQSPI_SCK_LOW(self) +#define SCK_HIGH(self) MICROPY_HW_SOFTQSPI_SCK_HIGH(self) +#define NIBBLE_READ(self) MICROPY_HW_SOFTQSPI_NIBBLE_READ(self) + +#else + +// Use generic pin functions for SCK control and IO reading +#define SCK_LOW(self) mp_hal_pin_write(self->clk, 0) +#define SCK_HIGH(self) mp_hal_pin_write(self->clk, 1) +#define NIBBLE_READ(self) ( \ + mp_hal_pin_read(self->io0) \ + | (mp_hal_pin_read(self->io1) << 1) \ + | (mp_hal_pin_read(self->io2) << 2) \ + | (mp_hal_pin_read(self->io3) << 3)) + +#endif + +STATIC void nibble_write(mp_soft_qspi_obj_t *self, uint8_t v) { + mp_hal_pin_write(self->io0, v & 1); + mp_hal_pin_write(self->io1, (v >> 1) & 1); + mp_hal_pin_write(self->io2, (v >> 2) & 1); + mp_hal_pin_write(self->io3, (v >> 3) & 1); +} + +STATIC int mp_soft_qspi_ioctl(void *self_in, uint32_t cmd) { + mp_soft_qspi_obj_t *self = (mp_soft_qspi_obj_t*)self_in; + + switch (cmd) { + case MP_QSPI_IOCTL_INIT: + mp_hal_pin_high(self->cs); + mp_hal_pin_output(self->cs); + + // Configure pins + mp_hal_pin_write(self->clk, 0); + mp_hal_pin_output(self->clk); + //mp_hal_pin_write(self->clk, 1); + mp_hal_pin_output(self->io0); + mp_hal_pin_input(self->io1); + mp_hal_pin_write(self->io2, 1); + mp_hal_pin_output(self->io2); + mp_hal_pin_write(self->io3, 1); + mp_hal_pin_output(self->io3); + break; + } + + return 0; // success +} + +STATIC void mp_soft_qspi_transfer(mp_soft_qspi_obj_t *self, size_t len, const uint8_t *src, uint8_t *dest) { + // Will run as fast as possible, limited only by CPU speed and GPIO time + mp_hal_pin_input(self->io1); + mp_hal_pin_output(self->io0); + if (self->io3) { + mp_hal_pin_write(self->io2, 1); + mp_hal_pin_output(self->io2); + mp_hal_pin_write(self->io3, 1); + mp_hal_pin_output(self->io3); + } + if (src) { + for (size_t i = 0; i < len; ++i) { + uint8_t data_out = src[i]; + uint8_t data_in = 0; + for (int j = 0; j < 8; ++j, data_out <<= 1) { + mp_hal_pin_write(self->io0, (data_out >> 7) & 1); + mp_hal_pin_write(self->clk, 1); + data_in = (data_in << 1) | mp_hal_pin_read(self->io1); + mp_hal_pin_write(self->clk, 0); + } + if (dest != NULL) { + dest[i] = data_in; + } + } + } else { + for (size_t i = 0; i < len; ++i) { + uint8_t data_in = 0; + for (int j = 0; j < 8; ++j) { + mp_hal_pin_write(self->clk, 1); + data_in = (data_in << 1) | mp_hal_pin_read(self->io1); + mp_hal_pin_write(self->clk, 0); + } + if (dest != NULL) { + dest[i] = data_in; + } + } + } +} + +STATIC void mp_soft_qspi_qread(mp_soft_qspi_obj_t *self, size_t len, uint8_t *buf) { + // Make all IO lines input + mp_hal_pin_input(self->io2); + mp_hal_pin_input(self->io3); + mp_hal_pin_input(self->io0); + mp_hal_pin_input(self->io1); + + // Will run as fast as possible, limited only by CPU speed and GPIO time + while (len--) { + SCK_HIGH(self); + uint8_t data_in = NIBBLE_READ(self); + SCK_LOW(self); + SCK_HIGH(self); + *buf++ = (data_in << 4) | NIBBLE_READ(self); + SCK_LOW(self); + } +} + +STATIC void mp_soft_qspi_qwrite(mp_soft_qspi_obj_t *self, size_t len, const uint8_t *buf) { + // Make all IO lines output + mp_hal_pin_output(self->io2); + mp_hal_pin_output(self->io3); + mp_hal_pin_output(self->io0); + mp_hal_pin_output(self->io1); + + // Will run as fast as possible, limited only by CPU speed and GPIO time + for (size_t i = 0; i < len; ++i) { + nibble_write(self, buf[i] >> 4); + SCK_HIGH(self); + SCK_LOW(self); + + nibble_write(self, buf[i]); + SCK_HIGH(self); + SCK_LOW(self); + } + + //mp_hal_pin_input(self->io1); +} + +STATIC void mp_soft_qspi_write_cmd_data(void *self_in, uint8_t cmd, size_t len, uint32_t data) { + mp_soft_qspi_obj_t *self = (mp_soft_qspi_obj_t*)self_in; + uint32_t cmd_buf = cmd | data << 8; + CS_LOW(self); + mp_soft_qspi_transfer(self, 1 + len, (uint8_t*)&cmd_buf, NULL); + CS_HIGH(self); +} + +STATIC void mp_soft_qspi_write_cmd_addr_data(void *self_in, uint8_t cmd, uint32_t addr, size_t len, const uint8_t *src) { + mp_soft_qspi_obj_t *self = (mp_soft_qspi_obj_t*)self_in; + uint8_t cmd_buf[4] = {cmd, addr >> 16, addr >> 8, addr}; + CS_LOW(self); + mp_soft_qspi_transfer(self, 4, cmd_buf, NULL); + mp_soft_qspi_transfer(self, len, src, NULL); + CS_HIGH(self); +} + +STATIC uint32_t mp_soft_qspi_read_cmd(void *self_in, uint8_t cmd, size_t len) { + mp_soft_qspi_obj_t *self = (mp_soft_qspi_obj_t*)self_in; + uint32_t cmd_buf = cmd; + CS_LOW(self); + mp_soft_qspi_transfer(self, 1 + len, (uint8_t*)&cmd_buf, (uint8_t*)&cmd_buf); + CS_HIGH(self); + return cmd_buf >> 8; +} + +STATIC void mp_soft_qspi_read_cmd_qaddr_qdata(void *self_in, uint8_t cmd, uint32_t addr, size_t len, uint8_t *dest) { + mp_soft_qspi_obj_t *self = (mp_soft_qspi_obj_t*)self_in; + uint8_t cmd_buf[7] = {cmd, addr >> 16, addr >> 8, addr}; + CS_LOW(self); + mp_soft_qspi_transfer(self, 1, cmd_buf, NULL); + mp_soft_qspi_qwrite(self, 6, &cmd_buf[1]); // 3 addr bytes, 1 extra byte (0), 2 dummy bytes (4 dummy cycles) + mp_soft_qspi_qread(self, len, dest); + CS_HIGH(self); +} + +const mp_qspi_proto_t mp_soft_qspi_proto = { + .ioctl = mp_soft_qspi_ioctl, + .write_cmd_data = mp_soft_qspi_write_cmd_data, + .write_cmd_addr_data = mp_soft_qspi_write_cmd_addr_data, + .read_cmd = mp_soft_qspi_read_cmd, + .read_cmd_qaddr_qdata = mp_soft_qspi_read_cmd_qaddr_qdata, +}; -- cgit v1.2.3 From 4e48700f9a284ab73fc199610314f2f6484adbfc Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 2 Mar 2018 16:01:18 +1100 Subject: drivers/memory/spiflash: Add support for QSPI interface. The spiflash memory driver is reworked to allow the underlying bus to be either normal SPI or QSPI. In both cases the bus can be implemented in software or hardware, as long as the spiflash driver is passed the correct configuration structure. --- drivers/memory/spiflash.c | 407 +++++++++++++++++++++++++++++++++++++--------- drivers/memory/spiflash.h | 28 +++- 2 files changed, 358 insertions(+), 77 deletions(-) (limited to 'drivers') diff --git a/drivers/memory/spiflash.c b/drivers/memory/spiflash.c index 08564d054..ea0fef805 100644 --- a/drivers/memory/spiflash.c +++ b/drivers/memory/spiflash.c @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2016-2017 Damien P. George + * Copyright (c) 2016-2018 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 @@ -29,57 +29,117 @@ #include "py/mperrno.h" #include "py/mphal.h" -#include "extmod/machine_spi.h" #include "drivers/memory/spiflash.h" -#define CMD_WRITE (0x02) -#define CMD_READ (0x03) -#define CMD_WRDI (0x04) -#define CMD_RDSR (0x05) -#define CMD_WREN (0x06) -#define CMD_SEC_ERASE (0x20) +#define QSPI_QE_MASK (0x02) +#define USE_WR_DELAY (1) + +#define CMD_WRSR (0x01) +#define CMD_WRITE (0x02) +#define CMD_READ (0x03) +#define CMD_RDSR (0x05) +#define CMD_WREN (0x06) +#define CMD_SEC_ERASE (0x20) +#define CMD_RDCR (0x35) +#define CMD_RD_DEVID (0x9f) +#define CMD_CHIP_ERASE (0xc7) +#define CMD_C4READ (0xeb) + #define WAIT_SR_TIMEOUT (1000000) #define PAGE_SIZE (256) // maximum bytes we can write in one SPI transfer #define SECTOR_SIZE (4096) // size of erase sector // Note: this code is not reentrant with this shared buffer -STATIC uint8_t buf[SECTOR_SIZE]; - -void mp_spiflash_init(mp_spiflash_t *self) { - mp_hal_pin_write(self->cs, 1); - mp_hal_pin_output(self->cs); - const mp_machine_spi_p_t *protocol = self->spi->type->protocol; - protocol->init(self->spi, 0, NULL, (mp_map_t*)&mp_const_empty_map); -} +STATIC uint8_t buf[SECTOR_SIZE] __attribute__((aligned(4))); +STATIC mp_spiflash_t *bufuser; // current user of buf +STATIC uint32_t bufsec; // current sector stored in buf; 0xffffffff if invalid STATIC void mp_spiflash_acquire_bus(mp_spiflash_t *self) { - // can be used for actions needed to acquire bus - (void)self; + const mp_spiflash_config_t *c = self->config; + if (c->bus_kind == MP_SPIFLASH_BUS_QSPI) { + c->bus.u_qspi.proto->ioctl(c->bus.u_qspi.data, MP_QSPI_IOCTL_BUS_ACQUIRE); + } } STATIC void mp_spiflash_release_bus(mp_spiflash_t *self) { - // can be used for actions needed to release bus - (void)self; + const mp_spiflash_config_t *c = self->config; + if (c->bus_kind == MP_SPIFLASH_BUS_QSPI) { + c->bus.u_qspi.proto->ioctl(c->bus.u_qspi.data, MP_QSPI_IOCTL_BUS_RELEASE); + } } -STATIC void mp_spiflash_transfer(mp_spiflash_t *self, size_t len, const uint8_t *src, uint8_t *dest) { - const mp_machine_spi_p_t *protocol = self->spi->type->protocol; - protocol->transfer(self->spi, len, src, dest); +STATIC void mp_spiflash_write_cmd_data(mp_spiflash_t *self, uint8_t cmd, size_t len, uint32_t data) { + const mp_spiflash_config_t *c = self->config; + if (c->bus_kind == MP_SPIFLASH_BUS_SPI) { + // Note: len/data are unused for standard SPI + mp_hal_pin_write(c->bus.u_spi.cs, 0); + c->bus.u_spi.proto->transfer(c->bus.u_spi.data, 1, &cmd, NULL); + mp_hal_pin_write(c->bus.u_spi.cs, 1); + } else { + c->bus.u_qspi.proto->write_cmd_data(c->bus.u_qspi.data, cmd, len, data); + } +} + +STATIC void mp_spiflash_write_cmd_addr_data(mp_spiflash_t *self, uint8_t cmd, uint32_t addr, size_t len, const uint8_t *src) { + const mp_spiflash_config_t *c = self->config; + if (c->bus_kind == MP_SPIFLASH_BUS_SPI) { + uint8_t buf[4] = {cmd, addr >> 16, addr >> 8, addr}; + mp_hal_pin_write(c->bus.u_spi.cs, 0); + c->bus.u_spi.proto->transfer(c->bus.u_spi.data, 4, buf, NULL); + if (len) { + c->bus.u_spi.proto->transfer(c->bus.u_spi.data, len, src, NULL); + } + mp_hal_pin_write(c->bus.u_spi.cs, 1); + } else { + c->bus.u_qspi.proto->write_cmd_addr_data(c->bus.u_qspi.data, cmd, addr, len, src); + } +} + +STATIC uint32_t mp_spiflash_read_cmd(mp_spiflash_t *self, uint8_t cmd, size_t len) { + const mp_spiflash_config_t *c = self->config; + if (c->bus_kind == MP_SPIFLASH_BUS_SPI) { + uint32_t buf; + mp_hal_pin_write(c->bus.u_spi.cs, 0); + c->bus.u_spi.proto->transfer(c->bus.u_spi.data, 1, &cmd, NULL); + c->bus.u_spi.proto->transfer(c->bus.u_spi.data, len, (void*)&buf, (void*)&buf); + mp_hal_pin_write(c->bus.u_spi.cs, 1); + return buf; + } else { + return c->bus.u_qspi.proto->read_cmd(c->bus.u_qspi.data, cmd, len); + } +} + +STATIC void mp_spiflash_read_data(mp_spiflash_t *self, uint32_t addr, size_t len, uint8_t *dest) { + const mp_spiflash_config_t *c = self->config; + if (c->bus_kind == MP_SPIFLASH_BUS_SPI) { + uint8_t buf[4] = {CMD_READ, addr >> 16, addr >> 8, addr}; + mp_hal_pin_write(c->bus.u_spi.cs, 0); + c->bus.u_spi.proto->transfer(c->bus.u_spi.data, 4, buf, NULL); + c->bus.u_spi.proto->transfer(c->bus.u_spi.data, len, dest, dest); + mp_hal_pin_write(c->bus.u_spi.cs, 1); + } else { + c->bus.u_qspi.proto->read_cmd_qaddr_qdata(c->bus.u_qspi.data, CMD_C4READ, addr, len, dest); + } +} + +STATIC void mp_spiflash_write_cmd(mp_spiflash_t *self, uint8_t cmd) { + mp_spiflash_write_cmd_data(self, cmd, 0, 0); +} + +STATIC void mp_spiflash_write_cmd_addr(mp_spiflash_t *self, uint8_t cmd, uint32_t addr) { + mp_spiflash_write_cmd_addr_data(self, cmd, addr, 0, NULL); } STATIC int mp_spiflash_wait_sr(mp_spiflash_t *self, uint8_t mask, uint8_t val, uint32_t timeout) { - uint8_t cmd[1] = {CMD_RDSR}; - mp_hal_pin_write(self->cs, 0); - mp_spiflash_transfer(self, 1, cmd, NULL); + uint8_t sr; for (; timeout; --timeout) { - mp_spiflash_transfer(self, 1, cmd, cmd); - if ((cmd[0] & mask) == val) { + sr = mp_spiflash_read_cmd(self, CMD_RDSR, 1); + if ((sr & mask) == val) { break; } } - mp_hal_pin_write(self->cs, 1); - if ((cmd[0] & mask) == val) { + if ((sr & mask) == val) { return 0; // success } else if (timeout == 0) { return -MP_ETIMEDOUT; @@ -96,10 +156,40 @@ STATIC int mp_spiflash_wait_wip0(mp_spiflash_t *self) { return mp_spiflash_wait_sr(self, 1, 0, WAIT_SR_TIMEOUT); } -STATIC void mp_spiflash_write_cmd(mp_spiflash_t *self, uint8_t cmd) { - mp_hal_pin_write(self->cs, 0); - mp_spiflash_transfer(self, 1, &cmd, NULL); - mp_hal_pin_write(self->cs, 1); +void mp_spiflash_init(mp_spiflash_t *self) { + self->flags = 0; + + if (self->config->bus_kind == MP_SPIFLASH_BUS_SPI) { + mp_hal_pin_write(self->config->bus.u_spi.cs, 1); + mp_hal_pin_output(self->config->bus.u_spi.cs); + self->config->bus.u_spi.proto->init(self->config->bus.u_spi.data, 0, NULL, (mp_map_t*)&mp_const_empty_map); + } else { + self->config->bus.u_qspi.proto->ioctl(self->config->bus.u_qspi.data, MP_QSPI_IOCTL_INIT); + } + + mp_spiflash_acquire_bus(self); + + #if defined(CHECK_DEVID) + // Validate device id + uint32_t devid = mp_spiflash_read_cmd(self, CMD_RD_DEVID, 3); + if (devid != CHECK_DEVID) { + return 0; + } + #endif + + if (self->config->bus_kind == MP_SPIFLASH_BUS_QSPI) { + // Set QE bit + uint32_t data = (mp_spiflash_read_cmd(self, CMD_RDSR, 1) & 0xff) + | (mp_spiflash_read_cmd(self, CMD_RDCR, 1) & 0xff) << 8; + if (!(data & (QSPI_QE_MASK << 16))) { + data |= QSPI_QE_MASK << 16; + mp_spiflash_write_cmd(self, CMD_WREN); + mp_spiflash_write_cmd_data(self, CMD_WRSR, 2, data); + mp_spiflash_wait_wip0(self); + } + } + + mp_spiflash_release_bus(self); } STATIC int mp_spiflash_erase_sector(mp_spiflash_t *self, uint32_t addr) { @@ -113,10 +203,7 @@ STATIC int mp_spiflash_erase_sector(mp_spiflash_t *self, uint32_t addr) { } // erase the sector - mp_hal_pin_write(self->cs, 0); - uint8_t cmd[4] = {CMD_SEC_ERASE, addr >> 16, addr >> 8, addr}; - mp_spiflash_transfer(self, 4, cmd, NULL); - mp_hal_pin_write(self->cs, 1); + mp_spiflash_write_cmd_addr(self, CMD_SEC_ERASE, addr); // wait WIP=0 return mp_spiflash_wait_wip0(self); @@ -133,67 +220,239 @@ STATIC int mp_spiflash_write_page(mp_spiflash_t *self, uint32_t addr, const uint } // write the page - mp_hal_pin_write(self->cs, 0); - uint8_t cmd[4] = {CMD_WRITE, addr >> 16, addr >> 8, addr}; - mp_spiflash_transfer(self, 4, cmd, NULL); - mp_spiflash_transfer(self, PAGE_SIZE, src, NULL); - mp_hal_pin_write(self->cs, 1); + mp_spiflash_write_cmd_addr_data(self, CMD_WRITE, addr, PAGE_SIZE, src); // wait WIP=0 return mp_spiflash_wait_wip0(self); } void mp_spiflash_read(mp_spiflash_t *self, uint32_t addr, size_t len, uint8_t *dest) { + if (len == 0) { + return; + } mp_spiflash_acquire_bus(self); - uint8_t cmd[4] = {CMD_READ, addr >> 16, addr >> 8, addr}; - mp_hal_pin_write(self->cs, 0); - mp_spiflash_transfer(self, 4, cmd, NULL); - mp_spiflash_transfer(self, len, dest, dest); - mp_hal_pin_write(self->cs, 1); + if (bufuser == self && bufsec != 0xffffffff) { + uint32_t bis = addr / SECTOR_SIZE; + int rest = 0; + if (bis < bufsec) { + rest = bufsec * SECTOR_SIZE - addr; + if (rest > len) { + rest = len; + } + mp_spiflash_read_data(self, addr, rest, dest); + len -= rest; + if (len <= 0) { + mp_spiflash_release_bus(self); + return; + } else { + // Something from buffer... + addr = bufsec * SECTOR_SIZE; + dest += rest; + if (len > SECTOR_SIZE) { + rest = SECTOR_SIZE; + } else { + rest = len; + } + memcpy(dest, buf, rest); + len -= rest; + if (len <= 0) { + mp_spiflash_release_bus(self); + return; + } + dest += rest; + addr += rest; + } + } else if (bis == bufsec) { + uint32_t offset = addr & (SECTOR_SIZE-1); + rest = SECTOR_SIZE - offset; + if (rest > len) { + rest = len; + } + memcpy(dest, &buf[offset], rest); + len -= rest; + if (len <= 0) { + mp_spiflash_release_bus(self); + return; + } + } + dest += rest; + addr += rest; + } + // Read rest direct from flash + mp_spiflash_read_data(self, addr, len, dest); mp_spiflash_release_bus(self); } -int mp_spiflash_write(mp_spiflash_t *self, uint32_t addr, size_t len, const uint8_t *src) { - // TODO optimise so we don't need to erase multiple times for successive writes to a sector +STATIC void mp_spiflash_flush_internal(mp_spiflash_t *self) { + #if USE_WR_DELAY + if (!(self->flags & 1)) { + return; + } + + self->flags &= ~1; + + // Erase sector + int ret = mp_spiflash_erase_sector(self, bufsec * SECTOR_SIZE); + if (ret != 0) { + return; + } + + // Write + for (int i = 0; i < 16; i += 1) { + int ret = mp_spiflash_write_page(self, bufsec * SECTOR_SIZE + i * PAGE_SIZE, buf + i * PAGE_SIZE); + if (ret != 0) { + return; + } + } + #endif +} - // align to 4096 sector +void mp_spiflash_flush(mp_spiflash_t *self) { + mp_spiflash_acquire_bus(self); + mp_spiflash_flush_internal(self); + mp_spiflash_release_bus(self); +} + +STATIC int mp_spiflash_write_part(mp_spiflash_t *self, uint32_t addr, size_t len, const uint8_t *src) { + // Align to 4096 sector uint32_t offset = addr & 0xfff; - addr = (addr >> 12) << 12; + uint32_t sec = addr >> 12; + addr = sec << 12; - // restriction for now, so we don't need to erase multiple pages + // Restriction for now, so we don't need to erase multiple pages if (offset + len > sizeof(buf)) { - printf("mp_spiflash_write: len is too large\n"); + printf("mp_spiflash_write_part: len is too large\n"); return -MP_EIO; } - mp_spiflash_acquire_bus(self); + // Acquire the sector buffer + if (bufuser != self) { + if (bufuser != NULL) { + mp_spiflash_flush(bufuser); + } + bufuser = self; + bufsec = 0xffffffff; + } - // read sector - uint8_t cmd[4] = {CMD_READ, addr >> 16, addr >> 8, addr}; - mp_hal_pin_write(self->cs, 0); - mp_spiflash_transfer(self, 4, cmd, NULL); - mp_spiflash_transfer(self, SECTOR_SIZE, buf, buf); - mp_hal_pin_write(self->cs, 1); + if (bufsec != sec) { + // Read sector + #if USE_WR_DELAY + if (bufsec != 0xffffffff) { + mp_spiflash_flush_internal(self); + } + #endif + mp_spiflash_read_data(self, addr, SECTOR_SIZE, buf); + } - // erase sector - int ret = mp_spiflash_erase_sector(self, addr); - if (ret != 0) { - mp_spiflash_release_bus(self); - return ret; + #if USE_WR_DELAY + + bufsec = sec; + // Just copy to buffer + memcpy(buf + offset, src, len); + // And mark dirty + self->flags |= 1; + + #else + + uint32_t dirty = 0; + for (size_t i = 0; i < len; ++i) { + if (buf[offset + i] != src[i]) { + if (buf[offset + i] != 0xff) { + // Erase sector + int ret = mp_spiflash_erase_sector(self, addr); + if (ret != 0) { + return ret; + } + dirty = 0xffff; + break; + } else { + dirty |= (1 << ((offset + i) >> 8)); + } + } } - // copy new block into buffer + bufsec = sec; + // Copy new block into buffer memcpy(buf + offset, src, len); - // write sector in pages of 256 bytes - for (int i = 0; i < SECTOR_SIZE; i += 256) { - ret = mp_spiflash_write_page(self, addr + i, buf + i); - if (ret != 0) { - mp_spiflash_release_bus(self); - return ret; + // Write sector in pages of 256 bytes + for (size_t i = 0; i < 16; ++i) { + if (dirty & (1 << i)) { + int ret = mp_spiflash_write_page(self, addr + i * PAGE_SIZE, buf + i * PAGE_SIZE); + if (ret != 0) { + return ret; + } } } - mp_spiflash_release_bus(self); + #endif + return 0; // success } + +int mp_spiflash_write(mp_spiflash_t *self, uint32_t addr, size_t len, const uint8_t *src) { + uint32_t bis = addr / SECTOR_SIZE; + uint32_t bie = (addr + len - 1) / SECTOR_SIZE; + + mp_spiflash_acquire_bus(self); + if (bufuser == self && bis <= bufsec && bie >= bufsec) { + // Current buffer affected, handle this part first + uint32_t taddr = (bufsec + 1) * SECTOR_SIZE; + int32_t offset = addr - bufsec * SECTOR_SIZE; + int32_t pre = bufsec * SECTOR_SIZE - addr; + if (offset < 0) { + offset = 0; + } else { + pre = 0; + } + int32_t rest = len - pre; + int32_t trail = 0; + if (rest > SECTOR_SIZE - offset) { + trail = rest - (SECTOR_SIZE - offset); + rest = SECTOR_SIZE - offset; + } + memcpy(&buf[offset], &src[pre], rest); + self->flags |= 1; // Mark dirty + if ((pre | trail) == 0) { + mp_spiflash_release_bus(self); + return 0; + } + const uint8_t *p = src; + while (pre) { + int rest = pre & (SECTOR_SIZE - 1); + if (rest == 0) { + rest = SECTOR_SIZE; + } + mp_spiflash_write_part(self, addr, rest, p); + p += rest; + addr += rest; + pre -= rest; + } + while (trail) { + int rest = trail; + if (rest > SECTOR_SIZE) { + rest = SECTOR_SIZE; + } + mp_spiflash_write_part(self, taddr, rest, src); + src += rest; + taddr += rest; + trail -= rest; + } + } else { + // Current buffer not affected, business as usual + uint32_t offset = addr & (SECTOR_SIZE - 1); + while (len) { + int rest = SECTOR_SIZE - offset; + if (rest > len) { + rest = len; + } + mp_spiflash_write_part(self, addr, rest, src); + len -= rest; + addr += rest; + src += rest; + offset = 0; + } + } + mp_spiflash_release_bus(self); + return 0; +} diff --git a/drivers/memory/spiflash.h b/drivers/memory/spiflash.h index cd96b16f3..79ba5490b 100644 --- a/drivers/memory/spiflash.h +++ b/drivers/memory/spiflash.h @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2016 Damien P. George + * Copyright (c) 2016-2018 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 @@ -26,14 +26,36 @@ #ifndef MICROPY_INCLUDED_DRIVERS_MEMORY_SPIFLASH_H #define MICROPY_INCLUDED_DRIVERS_MEMORY_SPIFLASH_H +#include "drivers/bus/qspi.h" #include "extmod/machine_spi.h" +enum { + MP_SPIFLASH_BUS_SPI, + MP_SPIFLASH_BUS_QSPI, +}; + +typedef struct _mp_spiflash_config_t { + uint32_t bus_kind; + union { + struct { + mp_hal_pin_obj_t cs; + void *data; + const mp_machine_spi_p_t *proto; + } u_spi; + struct { + void *data; + const mp_qspi_proto_t *proto; + } u_qspi; + } bus; +} mp_spiflash_config_t; + typedef struct _mp_spiflash_t { - mp_hal_pin_obj_t cs; - mp_obj_base_t *spi; // object must have protocol pointing to mp_machine_spi_p_t struct + const mp_spiflash_config_t *config; + volatile uint32_t flags; } mp_spiflash_t; void mp_spiflash_init(mp_spiflash_t *self); +void mp_spiflash_flush(mp_spiflash_t *self); void mp_spiflash_read(mp_spiflash_t *self, uint32_t addr, size_t len, uint8_t *dest); int mp_spiflash_write(mp_spiflash_t *self, uint32_t addr, size_t len, const uint8_t *src); -- cgit v1.2.3 From 58ebeca6a9a172a35b9298a911d450722797c409 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 9 Mar 2018 17:25:58 +1100 Subject: drivers/bus: Pull out software SPI implementation to dedicated driver. This patch takes the software SPI implementation from extmod/machine_spi.c and moves it to a dedicated file in drivers/bus/softspi.c. This allows the SPI driver to be used independently of the uPy runtime, making it a more general component. --- drivers/bus/softspi.c | 105 ++++++++++++++++++++++++++++++++++++ drivers/bus/spi.h | 55 +++++++++++++++++++ extmod/machine_spi.c | 114 ++++++++++------------------------------ extmod/machine_spi.h | 10 +--- ports/esp32/Makefile | 1 + ports/esp32/mpconfigport.h | 4 +- ports/esp8266/Makefile | 1 + ports/esp8266/esp8266_common.ld | 1 + ports/stm32/Makefile | 1 + ports/stm32/mpconfigport.h | 4 +- ports/stm32/spibdev.c | 4 +- 11 files changed, 202 insertions(+), 98 deletions(-) create mode 100644 drivers/bus/softspi.c create mode 100644 drivers/bus/spi.h (limited to 'drivers') diff --git a/drivers/bus/softspi.c b/drivers/bus/softspi.c new file mode 100644 index 000000000..bc12d89d3 --- /dev/null +++ b/drivers/bus/softspi.c @@ -0,0 +1,105 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016-2018 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 "drivers/bus/spi.h" + +int mp_soft_spi_ioctl(void *self_in, uint32_t cmd) { + mp_soft_spi_obj_t *self = (mp_soft_spi_obj_t*)self_in; + + switch (cmd) { + case MP_SPI_IOCTL_INIT: + mp_hal_pin_write(self->sck, self->polarity); + mp_hal_pin_output(self->sck); + mp_hal_pin_output(self->mosi); + mp_hal_pin_input(self->miso); + break; + + case MP_SPI_IOCTL_DEINIT: + break; + } + + return 0; +} + +void mp_soft_spi_transfer(void *self_in, size_t len, const uint8_t *src, uint8_t *dest) { + mp_soft_spi_obj_t *self = (mp_soft_spi_obj_t*)self_in; + uint32_t delay_half = self->delay_half; + + // only MSB transfer is implemented + + // If a port defines MICROPY_HW_SOFTSPI_MIN_DELAY, and the configured + // delay_half is equal to this value, then the software SPI implementation + // will run as fast as possible, limited only by CPU speed and GPIO time. + #ifdef MICROPY_HW_SOFTSPI_MIN_DELAY + if (delay_half == MICROPY_HW_SOFTSPI_MIN_DELAY) { + for (size_t i = 0; i < len; ++i) { + uint8_t data_out = src[i]; + uint8_t data_in = 0; + for (int j = 0; j < 8; ++j, data_out <<= 1) { + mp_hal_pin_write(self->mosi, (data_out >> 7) & 1); + mp_hal_pin_write(self->sck, 1 - self->polarity); + data_in = (data_in << 1) | mp_hal_pin_read(self->miso); + mp_hal_pin_write(self->sck, self->polarity); + } + if (dest != NULL) { + dest[i] = data_in; + } + } + return; + } + #endif + + for (size_t i = 0; i < len; ++i) { + uint8_t data_out = src[i]; + uint8_t data_in = 0; + for (int j = 0; j < 8; ++j, data_out <<= 1) { + mp_hal_pin_write(self->mosi, (data_out >> 7) & 1); + if (self->phase == 0) { + mp_hal_delay_us_fast(delay_half); + mp_hal_pin_write(self->sck, 1 - self->polarity); + } else { + mp_hal_pin_write(self->sck, 1 - self->polarity); + mp_hal_delay_us_fast(delay_half); + } + data_in = (data_in << 1) | mp_hal_pin_read(self->miso); + if (self->phase == 0) { + mp_hal_delay_us_fast(delay_half); + mp_hal_pin_write(self->sck, self->polarity); + } else { + mp_hal_pin_write(self->sck, self->polarity); + mp_hal_delay_us_fast(delay_half); + } + } + if (dest != NULL) { + dest[i] = data_in; + } + } +} + +const mp_spi_proto_t mp_soft_spi_proto = { + .ioctl = mp_soft_spi_ioctl, + .transfer = mp_soft_spi_transfer, +}; diff --git a/drivers/bus/spi.h b/drivers/bus/spi.h new file mode 100644 index 000000000..6d1b9c2f8 --- /dev/null +++ b/drivers/bus/spi.h @@ -0,0 +1,55 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016-2018 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_DRIVERS_BUS_SPI_H +#define MICROPY_INCLUDED_DRIVERS_BUS_SPI_H + +#include "py/mphal.h" + +enum { + MP_SPI_IOCTL_INIT, + MP_SPI_IOCTL_DEINIT, +}; + +typedef struct _mp_spi_proto_t { + int (*ioctl)(void *self, uint32_t cmd); + void (*transfer)(void *self, size_t len, const uint8_t *src, uint8_t *dest); +} mp_spi_proto_t; + +typedef struct _mp_soft_spi_obj_t { + uint32_t delay_half; // microsecond delay for half SCK period + uint8_t polarity; + uint8_t phase; + mp_hal_pin_obj_t sck; + mp_hal_pin_obj_t mosi; + mp_hal_pin_obj_t miso; +} mp_soft_spi_obj_t; + +extern const mp_spi_proto_t mp_soft_spi_proto; + +int mp_soft_spi_ioctl(void *self, uint32_t cmd); +void mp_soft_spi_transfer(void *self, size_t len, const uint8_t *src, uint8_t *dest); + +#endif // MICROPY_INCLUDED_DRIVERS_BUS_SPI_H diff --git a/extmod/machine_spi.c b/extmod/machine_spi.c index cfd94fcef..f0c4896c2 100644 --- a/extmod/machine_spi.c +++ b/extmod/machine_spi.c @@ -38,61 +38,6 @@ #define MICROPY_PY_MACHINE_SPI_LSB (1) #endif -void mp_machine_soft_spi_transfer(mp_obj_base_t *self_in, size_t len, const uint8_t *src, uint8_t *dest) { - mp_machine_soft_spi_obj_t *self = (mp_machine_soft_spi_obj_t*)self_in; - uint32_t delay_half = self->delay_half; - - // only MSB transfer is implemented - - // If a port defines MICROPY_PY_MACHINE_SPI_MIN_DELAY, and the configured - // delay_half is equal to this value, then the software SPI implementation - // will run as fast as possible, limited only by CPU speed and GPIO time. - #ifdef MICROPY_PY_MACHINE_SPI_MIN_DELAY - if (delay_half == MICROPY_PY_MACHINE_SPI_MIN_DELAY) { - for (size_t i = 0; i < len; ++i) { - uint8_t data_out = src[i]; - uint8_t data_in = 0; - for (int j = 0; j < 8; ++j, data_out <<= 1) { - mp_hal_pin_write(self->mosi, (data_out >> 7) & 1); - mp_hal_pin_write(self->sck, 1 - self->polarity); - data_in = (data_in << 1) | mp_hal_pin_read(self->miso); - mp_hal_pin_write(self->sck, self->polarity); - } - if (dest != NULL) { - dest[i] = data_in; - } - } - return; - } - #endif - - for (size_t i = 0; i < len; ++i) { - uint8_t data_out = src[i]; - uint8_t data_in = 0; - for (int j = 0; j < 8; ++j, data_out <<= 1) { - mp_hal_pin_write(self->mosi, (data_out >> 7) & 1); - if (self->phase == 0) { - mp_hal_delay_us_fast(delay_half); - mp_hal_pin_write(self->sck, 1 - self->polarity); - } else { - mp_hal_pin_write(self->sck, 1 - self->polarity); - mp_hal_delay_us_fast(delay_half); - } - data_in = (data_in << 1) | mp_hal_pin_read(self->miso); - if (self->phase == 0) { - mp_hal_delay_us_fast(delay_half); - mp_hal_pin_write(self->sck, self->polarity); - } else { - mp_hal_pin_write(self->sck, self->polarity); - mp_hal_delay_us_fast(delay_half); - } - } - if (dest != NULL) { - dest[i] = data_in; - } - } -} - /******************************************************************************/ // MicroPython bindings for generic machine.SPI @@ -199,9 +144,9 @@ MP_DEFINE_CONST_DICT(mp_machine_spi_locals_dict, machine_spi_locals_dict_table); // Implementation of soft SPI STATIC uint32_t baudrate_from_delay_half(uint32_t delay_half) { - #ifdef MICROPY_PY_MACHINE_SPI_MIN_DELAY - if (delay_half == MICROPY_PY_MACHINE_SPI_MIN_DELAY) { - return MICROPY_PY_MACHINE_SPI_MAX_BAUDRATE; + #ifdef MICROPY_HW_SOFTSPI_MIN_DELAY + if (delay_half == MICROPY_HW_SOFTSPI_MIN_DELAY) { + return MICROPY_HW_SOFTSPI_MAX_BAUDRATE; } else #endif { @@ -210,9 +155,9 @@ STATIC uint32_t baudrate_from_delay_half(uint32_t delay_half) { } STATIC uint32_t baudrate_to_delay_half(uint32_t baudrate) { - #ifdef MICROPY_PY_MACHINE_SPI_MIN_DELAY - if (baudrate >= MICROPY_PY_MACHINE_SPI_MAX_BAUDRATE) { - return MICROPY_PY_MACHINE_SPI_MIN_DELAY; + #ifdef MICROPY_HW_SOFTSPI_MIN_DELAY + if (baudrate >= MICROPY_HW_SOFTSPI_MAX_BAUDRATE) { + return MICROPY_HW_SOFTSPI_MIN_DELAY; } else #endif { @@ -229,8 +174,8 @@ STATIC void mp_machine_soft_spi_print(const mp_print_t *print, mp_obj_t self_in, mp_machine_soft_spi_obj_t *self = MP_OBJ_TO_PTR(self_in); mp_printf(print, "SoftSPI(baudrate=%u, polarity=%u, phase=%u," " sck=" MP_HAL_PIN_FMT ", mosi=" MP_HAL_PIN_FMT ", miso=" MP_HAL_PIN_FMT ")", - baudrate_from_delay_half(self->delay_half), self->polarity, self->phase, - mp_hal_pin_name(self->sck), mp_hal_pin_name(self->mosi), mp_hal_pin_name(self->miso)); + baudrate_from_delay_half(self->spi.delay_half), self->spi.polarity, self->spi.phase, + mp_hal_pin_name(self->spi.sck), mp_hal_pin_name(self->spi.mosi), mp_hal_pin_name(self->spi.miso)); } STATIC mp_obj_t mp_machine_soft_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { @@ -253,9 +198,9 @@ STATIC mp_obj_t mp_machine_soft_spi_make_new(const mp_obj_type_t *type, size_t n self->base.type = &mp_machine_soft_spi_type; // set parameters - self->delay_half = baudrate_to_delay_half(args[ARG_baudrate].u_int); - self->polarity = args[ARG_polarity].u_int; - self->phase = args[ARG_phase].u_int; + self->spi.delay_half = baudrate_to_delay_half(args[ARG_baudrate].u_int); + self->spi.polarity = args[ARG_polarity].u_int; + self->spi.phase = args[ARG_phase].u_int; if (args[ARG_bits].u_int != 8) { mp_raise_ValueError("bits must be 8"); } @@ -267,15 +212,12 @@ STATIC mp_obj_t mp_machine_soft_spi_make_new(const mp_obj_type_t *type, size_t n || args[ARG_miso].u_obj == MP_OBJ_NULL) { mp_raise_ValueError("must specify all of sck/mosi/miso"); } - self->sck = mp_hal_get_pin_obj(args[ARG_sck].u_obj); - self->mosi = mp_hal_get_pin_obj(args[ARG_mosi].u_obj); - self->miso = mp_hal_get_pin_obj(args[ARG_miso].u_obj); + self->spi.sck = mp_hal_get_pin_obj(args[ARG_sck].u_obj); + self->spi.mosi = mp_hal_get_pin_obj(args[ARG_mosi].u_obj); + self->spi.miso = mp_hal_get_pin_obj(args[ARG_miso].u_obj); - // configure pins - mp_hal_pin_write(self->sck, self->polarity); - mp_hal_pin_output(self->sck); - mp_hal_pin_output(self->mosi); - mp_hal_pin_input(self->miso); + // configure bus + mp_soft_spi_ioctl(&self->spi, MP_SPI_IOCTL_INIT); return MP_OBJ_FROM_PTR(self); } @@ -296,29 +238,31 @@ STATIC void mp_machine_soft_spi_init(mp_obj_base_t *self_in, size_t n_args, cons 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->delay_half = baudrate_to_delay_half(args[ARG_baudrate].u_int); + self->spi.delay_half = baudrate_to_delay_half(args[ARG_baudrate].u_int); } if (args[ARG_polarity].u_int != -1) { - self->polarity = args[ARG_polarity].u_int; + self->spi.polarity = args[ARG_polarity].u_int; } if (args[ARG_phase].u_int != -1) { - self->phase = args[ARG_phase].u_int; + self->spi.phase = args[ARG_phase].u_int; } if (args[ARG_sck].u_obj != MP_OBJ_NULL) { - self->sck = mp_hal_get_pin_obj(args[ARG_sck].u_obj); + self->spi.sck = mp_hal_get_pin_obj(args[ARG_sck].u_obj); } if (args[ARG_mosi].u_obj != MP_OBJ_NULL) { - self->mosi = mp_hal_get_pin_obj(args[ARG_mosi].u_obj); + self->spi.mosi = mp_hal_get_pin_obj(args[ARG_mosi].u_obj); } if (args[ARG_miso].u_obj != MP_OBJ_NULL) { - self->miso = mp_hal_get_pin_obj(args[ARG_miso].u_obj); + self->spi.miso = mp_hal_get_pin_obj(args[ARG_miso].u_obj); } - // configure pins - mp_hal_pin_write(self->sck, self->polarity); - mp_hal_pin_output(self->sck); - mp_hal_pin_output(self->mosi); - mp_hal_pin_input(self->miso); + // configure bus + mp_soft_spi_ioctl(&self->spi, MP_SPI_IOCTL_INIT); +} + +STATIC void mp_machine_soft_spi_transfer(mp_obj_base_t *self_in, size_t len, const uint8_t *src, uint8_t *dest) { + mp_machine_soft_spi_obj_t *self = (mp_machine_soft_spi_obj_t*)self_in; + mp_soft_spi_transfer(&self->spi, len, src, dest); } const mp_machine_spi_p_t mp_machine_soft_spi_p = { diff --git a/extmod/machine_spi.h b/extmod/machine_spi.h index 3ee1b241f..db21e1cd3 100644 --- a/extmod/machine_spi.h +++ b/extmod/machine_spi.h @@ -28,6 +28,7 @@ #include "py/obj.h" #include "py/mphal.h" +#include "drivers/bus/spi.h" // SPI protocol typedef struct _mp_machine_spi_p_t { @@ -38,20 +39,13 @@ typedef struct _mp_machine_spi_p_t { typedef struct _mp_machine_soft_spi_obj_t { mp_obj_base_t base; - uint32_t delay_half; // microsecond delay for half SCK period - uint8_t polarity; - uint8_t phase; - mp_hal_pin_obj_t sck; - mp_hal_pin_obj_t mosi; - mp_hal_pin_obj_t miso; + mp_soft_spi_obj_t spi; } mp_machine_soft_spi_obj_t; extern const mp_machine_spi_p_t mp_machine_soft_spi_p; extern const mp_obj_type_t mp_machine_soft_spi_type; extern const mp_obj_dict_t mp_machine_spi_locals_dict; -void mp_machine_soft_spi_transfer(mp_obj_base_t *self, size_t len, const uint8_t *src, uint8_t *dest); - mp_obj_t mp_machine_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_machine_spi_read_obj); diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile index eb0a3be24..d2d6192b5 100644 --- a/ports/esp32/Makefile +++ b/ports/esp32/Makefile @@ -195,6 +195,7 @@ LIB_SRC_C += \ endif DRIVERS_SRC_C = $(addprefix drivers/,\ + bus/softspi.c \ dht/dht.c \ ) diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h index bf027f1c5..80594b114 100644 --- a/ports/esp32/mpconfigport.h +++ b/ports/esp32/mpconfigport.h @@ -135,8 +135,8 @@ #define MICROPY_PY_MACHINE_SPI_MSB (0) #define MICROPY_PY_MACHINE_SPI_LSB (1) #define MICROPY_PY_MACHINE_SPI_MAKE_NEW machine_hw_spi_make_new -#define MICROPY_PY_MACHINE_SPI_MIN_DELAY (0) -#define MICROPY_PY_MACHINE_SPI_MAX_BAUDRATE (ets_get_cpu_frequency() * 1000000 / 200) // roughly +#define MICROPY_HW_SOFTSPI_MIN_DELAY (0) +#define MICROPY_HW_SOFTSPI_MAX_BAUDRATE (ets_get_cpu_frequency() * 1000000 / 200) // roughly #define MICROPY_PY_USSL (1) #define MICROPY_SSL_MBEDTLS (1) #define MICROPY_PY_USSL_FINALISER (1) diff --git a/ports/esp8266/Makefile b/ports/esp8266/Makefile index 9d6e502c7..716f18d6a 100644 --- a/ports/esp8266/Makefile +++ b/ports/esp8266/Makefile @@ -130,6 +130,7 @@ LIB_SRC_C += \ endif DRIVERS_SRC_C = $(addprefix drivers/,\ + bus/softspi.c \ dht/dht.c \ ) diff --git a/ports/esp8266/esp8266_common.ld b/ports/esp8266/esp8266_common.ld index 08da02869..6b7eba56a 100644 --- a/ports/esp8266/esp8266_common.ld +++ b/ports/esp8266/esp8266_common.ld @@ -135,6 +135,7 @@ SECTIONS *lib/netutils/*.o*(.literal*, .text*) *lib/timeutils/*.o*(.literal*, .text*) *lib/utils/*.o*(.literal*, .text*) + *drivers/bus/*.o(.literal* .text*) build/main.o(.literal* .text*) *gccollect.o(.literal* .text*) diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index 112093f84..765c55a35 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -187,6 +187,7 @@ EXTMOD_SRC_C = $(addprefix extmod/,\ ) DRIVERS_SRC_C = $(addprefix drivers/,\ + bus/softspi.c \ bus/softqspi.c \ memory/spiflash.c \ dht/dht.c \ diff --git a/ports/stm32/mpconfigport.h b/ports/stm32/mpconfigport.h index 35b59cbfd..a0a67e95f 100644 --- a/ports/stm32/mpconfigport.h +++ b/ports/stm32/mpconfigport.h @@ -140,8 +140,8 @@ #define MICROPY_PY_MACHINE_SPI_MSB (SPI_FIRSTBIT_MSB) #define MICROPY_PY_MACHINE_SPI_LSB (SPI_FIRSTBIT_LSB) #define MICROPY_PY_MACHINE_SPI_MAKE_NEW machine_hard_spi_make_new -#define MICROPY_PY_MACHINE_SPI_MIN_DELAY (0) -#define MICROPY_PY_MACHINE_SPI_MAX_BAUDRATE (HAL_RCC_GetSysClockFreq() / 48) +#define MICROPY_HW_SOFTSPI_MIN_DELAY (0) +#define MICROPY_HW_SOFTSPI_MAX_BAUDRATE (HAL_RCC_GetSysClockFreq() / 48) #define MICROPY_PY_FRAMEBUF (1) #ifndef MICROPY_PY_USOCKET #define MICROPY_PY_USOCKET (1) diff --git a/ports/stm32/spibdev.c b/ports/stm32/spibdev.c index 3eadb995d..846b29d1f 100644 --- a/ports/stm32/spibdev.c +++ b/ports/stm32/spibdev.c @@ -42,12 +42,14 @@ static uint32_t flash_tick_counter_last_write; STATIC const mp_machine_soft_spi_obj_t spiflash_spi_bus = { .base = {&mp_machine_soft_spi_type}, - .delay_half = MICROPY_PY_MACHINE_SPI_MIN_DELAY, + .spi = { + .delay_half = MICROPY_HW_SOFTSPI_MIN_DELAY, .polarity = 0, .phase = 0, .sck = &MICROPY_HW_SPIFLASH_SCK, .mosi = &MICROPY_HW_SPIFLASH_MOSI, .miso = &MICROPY_HW_SPIFLASH_MISO, + } }; STATIC const mp_spiflash_config_t spiflash_config = { -- cgit v1.2.3 From a739b35a9618c2dd2d25c9ef4d076eeffddbb399 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 9 Mar 2018 17:32:28 +1100 Subject: drivers/memory/spiflash: Change to use low-level SPI object not uPy one. This patch alters the SPI-flash memory driver so that it uses the new low-level C SPI protocol (from drivers/bus/spi.h) instead of the uPy SPI protocol (from extmod/machine_spi.h). This allows the SPI-flash driver to be used independently from the uPy runtime. --- drivers/memory/spiflash.c | 2 +- drivers/memory/spiflash.h | 4 ++-- ports/stm32/spibdev.c | 9 +++------ 3 files changed, 6 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/memory/spiflash.c b/drivers/memory/spiflash.c index ea0fef805..ad451f2c5 100644 --- a/drivers/memory/spiflash.c +++ b/drivers/memory/spiflash.c @@ -162,7 +162,7 @@ void mp_spiflash_init(mp_spiflash_t *self) { if (self->config->bus_kind == MP_SPIFLASH_BUS_SPI) { mp_hal_pin_write(self->config->bus.u_spi.cs, 1); mp_hal_pin_output(self->config->bus.u_spi.cs); - self->config->bus.u_spi.proto->init(self->config->bus.u_spi.data, 0, NULL, (mp_map_t*)&mp_const_empty_map); + self->config->bus.u_spi.proto->ioctl(self->config->bus.u_spi.data, MP_SPI_IOCTL_INIT); } else { self->config->bus.u_qspi.proto->ioctl(self->config->bus.u_qspi.data, MP_QSPI_IOCTL_INIT); } diff --git a/drivers/memory/spiflash.h b/drivers/memory/spiflash.h index 79ba5490b..03bad5296 100644 --- a/drivers/memory/spiflash.h +++ b/drivers/memory/spiflash.h @@ -26,8 +26,8 @@ #ifndef MICROPY_INCLUDED_DRIVERS_MEMORY_SPIFLASH_H #define MICROPY_INCLUDED_DRIVERS_MEMORY_SPIFLASH_H +#include "drivers/bus/spi.h" #include "drivers/bus/qspi.h" -#include "extmod/machine_spi.h" enum { MP_SPIFLASH_BUS_SPI, @@ -40,7 +40,7 @@ typedef struct _mp_spiflash_config_t { struct { mp_hal_pin_obj_t cs; void *data; - const mp_machine_spi_p_t *proto; + const mp_spi_proto_t *proto; } u_spi; struct { void *data; diff --git a/ports/stm32/spibdev.c b/ports/stm32/spibdev.c index 846b29d1f..0e47a8189 100644 --- a/ports/stm32/spibdev.c +++ b/ports/stm32/spibdev.c @@ -40,23 +40,20 @@ static uint32_t flash_tick_counter_last_write; // External SPI flash uses standard SPI interface -STATIC const mp_machine_soft_spi_obj_t spiflash_spi_bus = { - .base = {&mp_machine_soft_spi_type}, - .spi = { +STATIC const mp_soft_spi_obj_t soft_spi_bus = { .delay_half = MICROPY_HW_SOFTSPI_MIN_DELAY, .polarity = 0, .phase = 0, .sck = &MICROPY_HW_SPIFLASH_SCK, .mosi = &MICROPY_HW_SPIFLASH_MOSI, .miso = &MICROPY_HW_SPIFLASH_MISO, - } }; STATIC const mp_spiflash_config_t spiflash_config = { .bus_kind = MP_SPIFLASH_BUS_SPI, .bus.u_spi.cs = &MICROPY_HW_SPIFLASH_CS, - .bus.u_spi.data = (void*)&spiflash_spi_bus, - .bus.u_spi.proto = &mp_machine_soft_spi_p, + .bus.u_spi.data = (void*)&soft_spi_bus, + .bus.u_spi.proto = &mp_soft_spi_proto, }; #elif defined(MICROPY_HW_SPIFLASH_IO0) -- cgit v1.2.3 From cc34b087f0fe121afb03dcfe99180737ab925372 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sun, 11 Mar 2018 11:25:38 +1100 Subject: drivers/memory/spiflash: Fix setting of QE bit in flash register. --- drivers/memory/spiflash.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/memory/spiflash.c b/drivers/memory/spiflash.c index ad451f2c5..c7f333044 100644 --- a/drivers/memory/spiflash.c +++ b/drivers/memory/spiflash.c @@ -181,8 +181,8 @@ void mp_spiflash_init(mp_spiflash_t *self) { // Set QE bit uint32_t data = (mp_spiflash_read_cmd(self, CMD_RDSR, 1) & 0xff) | (mp_spiflash_read_cmd(self, CMD_RDCR, 1) & 0xff) << 8; - if (!(data & (QSPI_QE_MASK << 16))) { - data |= QSPI_QE_MASK << 16; + if (!(data & (QSPI_QE_MASK << 8))) { + data |= QSPI_QE_MASK << 8; mp_spiflash_write_cmd(self, CMD_WREN); mp_spiflash_write_cmd_data(self, CMD_WRSR, 2, data); mp_spiflash_wait_wip0(self); -- cgit v1.2.3 From bdc875e602f687bf0fb28c3a18565ffec4157f59 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 13 Mar 2018 14:13:30 +1100 Subject: drivers/memory/spiflash: Fix bugs in and clean up read/write functions. mp_spiflash_read had a bug in it where "dest" and "addr" were incremented twice for a certain special case. This was fixed, which then allowed the function to be simplified to reduce code size. mp_spiflash_write had a bug in it where "src" was not incremented correctly for the case where the data to be written included the caching buffer as well as some bytes after this buffer. This was fixed and the resulting code simplified. --- drivers/memory/spiflash.c | 125 ++++++++++++++++++++-------------------------- 1 file changed, 55 insertions(+), 70 deletions(-) (limited to 'drivers') diff --git a/drivers/memory/spiflash.c b/drivers/memory/spiflash.c index c7f333044..d72603f64 100644 --- a/drivers/memory/spiflash.c +++ b/drivers/memory/spiflash.c @@ -233,50 +233,32 @@ void mp_spiflash_read(mp_spiflash_t *self, uint32_t addr, size_t len, uint8_t *d mp_spiflash_acquire_bus(self); if (bufuser == self && bufsec != 0xffffffff) { uint32_t bis = addr / SECTOR_SIZE; - int rest = 0; - if (bis < bufsec) { - rest = bufsec * SECTOR_SIZE - addr; - if (rest > len) { - rest = len; - } - mp_spiflash_read_data(self, addr, rest, dest); - len -= rest; - if (len <= 0) { - mp_spiflash_release_bus(self); - return; - } else { - // Something from buffer... - addr = bufsec * SECTOR_SIZE; - dest += rest; - if (len > SECTOR_SIZE) { - rest = SECTOR_SIZE; - } else { - rest = len; - } - memcpy(dest, buf, rest); + uint32_t bie = (addr + len - 1) / SECTOR_SIZE; + if (bis <= bufsec && bufsec <= bie) { + // Read straddles current buffer + size_t rest = 0; + if (bis < bufsec) { + // Read direct from flash for first part + rest = bufsec * SECTOR_SIZE - addr; + mp_spiflash_read_data(self, addr, rest, dest); len -= rest; - if (len <= 0) { - mp_spiflash_release_bus(self); - return; - } dest += rest; addr += rest; } - } else if (bis == bufsec) { - uint32_t offset = addr & (SECTOR_SIZE-1); + uint32_t offset = addr & (SECTOR_SIZE - 1); rest = SECTOR_SIZE - offset; if (rest > len) { rest = len; } memcpy(dest, &buf[offset], rest); len -= rest; - if (len <= 0) { + if (len == 0) { mp_spiflash_release_bus(self); return; } + dest += rest; + addr += rest; } - dest += rest; - addr += rest; } // Read rest direct from flash mp_spiflash_read_data(self, addr, len, dest); @@ -395,64 +377,67 @@ int mp_spiflash_write(mp_spiflash_t *self, uint32_t addr, size_t len, const uint uint32_t bie = (addr + len - 1) / SECTOR_SIZE; mp_spiflash_acquire_bus(self); + if (bufuser == self && bis <= bufsec && bie >= bufsec) { - // Current buffer affected, handle this part first - uint32_t taddr = (bufsec + 1) * SECTOR_SIZE; - int32_t offset = addr - bufsec * SECTOR_SIZE; - int32_t pre = bufsec * SECTOR_SIZE - addr; - if (offset < 0) { + // Write straddles current buffer + uint32_t pre; + uint32_t offset; + if (bufsec * SECTOR_SIZE >= addr) { + pre = bufsec * SECTOR_SIZE - addr; offset = 0; } else { pre = 0; + offset = addr - bufsec * SECTOR_SIZE; } - int32_t rest = len - pre; - int32_t trail = 0; - if (rest > SECTOR_SIZE - offset) { - trail = rest - (SECTOR_SIZE - offset); - rest = SECTOR_SIZE - offset; + + // Write buffered part first + uint32_t len_in_buf = len - pre; + len = 0; + if (len_in_buf > SECTOR_SIZE - offset) { + len = len_in_buf - (SECTOR_SIZE - offset); + len_in_buf = SECTOR_SIZE - offset; } - memcpy(&buf[offset], &src[pre], rest); + memcpy(&buf[offset], &src[pre], len_in_buf); self->flags |= 1; // Mark dirty - if ((pre | trail) == 0) { - mp_spiflash_release_bus(self); - return 0; - } - const uint8_t *p = src; + + // Write part before buffer sector while (pre) { int rest = pre & (SECTOR_SIZE - 1); if (rest == 0) { rest = SECTOR_SIZE; } - mp_spiflash_write_part(self, addr, rest, p); - p += rest; + int ret = mp_spiflash_write_part(self, addr, rest, src); + if (ret != 0) { + mp_spiflash_release_bus(self); + return ret; + } + src += rest; addr += rest; pre -= rest; } - while (trail) { - int rest = trail; - if (rest > SECTOR_SIZE) { - rest = SECTOR_SIZE; - } - mp_spiflash_write_part(self, taddr, rest, src); - src += rest; - taddr += rest; - trail -= rest; + src += len_in_buf; + addr += len_in_buf; + + // Fall through to write remaining part + } + + uint32_t offset = addr & (SECTOR_SIZE - 1); + while (len) { + int rest = SECTOR_SIZE - offset; + if (rest > len) { + rest = len; } - } else { - // Current buffer not affected, business as usual - uint32_t offset = addr & (SECTOR_SIZE - 1); - while (len) { - int rest = SECTOR_SIZE - offset; - if (rest > len) { - rest = len; - } - mp_spiflash_write_part(self, addr, rest, src); - len -= rest; - addr += rest; - src += rest; - offset = 0; + int ret = mp_spiflash_write_part(self, addr, rest, src); + if (ret != 0) { + mp_spiflash_release_bus(self); + return ret; } + len -= rest; + addr += rest; + src += rest; + offset = 0; } + mp_spiflash_release_bus(self); return 0; } -- cgit v1.2.3 From 5a5bc4a61f660829b8f57c297ff90ec43f86b173 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 1 Jun 2018 13:44:09 +1000 Subject: drivers/wiznet5k: Fix bug with MACRAW socket calculating packet size. --- drivers/wiznet5k/ethernet/socket.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/wiznet5k/ethernet/socket.c b/drivers/wiznet5k/ethernet/socket.c index ec25fcc79..3ffda3a72 100644 --- a/drivers/wiznet5k/ethernet/socket.c +++ b/drivers/wiznet5k/ethernet/socket.c @@ -525,6 +525,7 @@ int32_t WIZCHIP_EXPORT(recvfrom)(uint8_t sn, uint8_t * buf, uint16_t len, uint8_ // read peer's IP address, port number & packet length sock_remained_size[sn] = head[0]; sock_remained_size[sn] = (sock_remained_size[sn] <<8) + head[1]; + sock_remained_size[sn] -= 2; // len includes 2 len bytes if(sock_remained_size[sn] > 1514) { WIZCHIP_EXPORT(close)(sn); -- cgit v1.2.3 From 86fe73beb99686ea15787f0603ad6f10a642054c Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 7 Jun 2018 14:09:10 +1000 Subject: drivers/memory/spiflash: Move cache buffer to user-provided config. This patch removes the global cache variables from the SPI flash driver and now requires the user to provide the cache memory themselves, via the SPI flash configuration struct. This allows to either have a shared cache for multiple SPI flash devices (by sharing a mp_spiflash_cache_t struct), or have a single cache per device (or a mix of these options). To configure the cache use: mp_spiflash_cache_t spi_bdev_cache; const mp_spiflash_config_t spiflash_config = // any bus options .cache = &spi_bdev_cache, }; --- drivers/memory/spiflash.c | 69 ++++++++++++++++++++++++----------------------- drivers/memory/spiflash.h | 13 +++++++++ 2 files changed, 48 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/memory/spiflash.c b/drivers/memory/spiflash.c index d72603f64..0cc926b79 100644 --- a/drivers/memory/spiflash.c +++ b/drivers/memory/spiflash.c @@ -48,12 +48,7 @@ #define WAIT_SR_TIMEOUT (1000000) #define PAGE_SIZE (256) // maximum bytes we can write in one SPI transfer -#define SECTOR_SIZE (4096) // size of erase sector - -// Note: this code is not reentrant with this shared buffer -STATIC uint8_t buf[SECTOR_SIZE] __attribute__((aligned(4))); -STATIC mp_spiflash_t *bufuser; // current user of buf -STATIC uint32_t bufsec; // current sector stored in buf; 0xffffffff if invalid +#define SECTOR_SIZE MP_SPIFLASH_ERASE_BLOCK_SIZE STATIC void mp_spiflash_acquire_bus(mp_spiflash_t *self) { const mp_spiflash_config_t *c = self->config; @@ -231,15 +226,16 @@ void mp_spiflash_read(mp_spiflash_t *self, uint32_t addr, size_t len, uint8_t *d return; } mp_spiflash_acquire_bus(self); - if (bufuser == self && bufsec != 0xffffffff) { + mp_spiflash_cache_t *cache = self->config->cache; + if (cache->user == self && cache->block != 0xffffffff) { uint32_t bis = addr / SECTOR_SIZE; uint32_t bie = (addr + len - 1) / SECTOR_SIZE; - if (bis <= bufsec && bufsec <= bie) { + if (bis <= cache->block && cache->block <= bie) { // Read straddles current buffer size_t rest = 0; - if (bis < bufsec) { + if (bis < cache->block) { // Read direct from flash for first part - rest = bufsec * SECTOR_SIZE - addr; + rest = cache->block * SECTOR_SIZE - addr; mp_spiflash_read_data(self, addr, rest, dest); len -= rest; dest += rest; @@ -250,7 +246,7 @@ void mp_spiflash_read(mp_spiflash_t *self, uint32_t addr, size_t len, uint8_t *d if (rest > len) { rest = len; } - memcpy(dest, &buf[offset], rest); + memcpy(dest, &cache->buf[offset], rest); len -= rest; if (len == 0) { mp_spiflash_release_bus(self); @@ -273,15 +269,17 @@ STATIC void mp_spiflash_flush_internal(mp_spiflash_t *self) { self->flags &= ~1; + mp_spiflash_cache_t *cache = self->config->cache; + // Erase sector - int ret = mp_spiflash_erase_sector(self, bufsec * SECTOR_SIZE); + int ret = mp_spiflash_erase_sector(self, cache->block * SECTOR_SIZE); if (ret != 0) { return; } // Write for (int i = 0; i < 16; i += 1) { - int ret = mp_spiflash_write_page(self, bufsec * SECTOR_SIZE + i * PAGE_SIZE, buf + i * PAGE_SIZE); + int ret = mp_spiflash_write_page(self, cache->block * SECTOR_SIZE + i * PAGE_SIZE, cache->buf + i * PAGE_SIZE); if (ret != 0) { return; } @@ -302,35 +300,37 @@ STATIC int mp_spiflash_write_part(mp_spiflash_t *self, uint32_t addr, size_t len addr = sec << 12; // Restriction for now, so we don't need to erase multiple pages - if (offset + len > sizeof(buf)) { + if (offset + len > SECTOR_SIZE) { printf("mp_spiflash_write_part: len is too large\n"); return -MP_EIO; } + mp_spiflash_cache_t *cache = self->config->cache; + // Acquire the sector buffer - if (bufuser != self) { - if (bufuser != NULL) { - mp_spiflash_flush(bufuser); + if (cache->user != self) { + if (cache->user != NULL) { + mp_spiflash_flush(cache->user); } - bufuser = self; - bufsec = 0xffffffff; + cache->user = self; + cache->block = 0xffffffff; } - if (bufsec != sec) { + if (cache->block != sec) { // Read sector #if USE_WR_DELAY - if (bufsec != 0xffffffff) { + if (cache->block != 0xffffffff) { mp_spiflash_flush_internal(self); } #endif - mp_spiflash_read_data(self, addr, SECTOR_SIZE, buf); + mp_spiflash_read_data(self, addr, SECTOR_SIZE, cache->buf); } #if USE_WR_DELAY - bufsec = sec; + cache->block = sec; // Just copy to buffer - memcpy(buf + offset, src, len); + memcpy(cache->buf + offset, src, len); // And mark dirty self->flags |= 1; @@ -338,8 +338,8 @@ STATIC int mp_spiflash_write_part(mp_spiflash_t *self, uint32_t addr, size_t len uint32_t dirty = 0; for (size_t i = 0; i < len; ++i) { - if (buf[offset + i] != src[i]) { - if (buf[offset + i] != 0xff) { + if (cache->buf[offset + i] != src[i]) { + if (cache->buf[offset + i] != 0xff) { // Erase sector int ret = mp_spiflash_erase_sector(self, addr); if (ret != 0) { @@ -353,14 +353,14 @@ STATIC int mp_spiflash_write_part(mp_spiflash_t *self, uint32_t addr, size_t len } } - bufsec = sec; + cache->block = sec; // Copy new block into buffer - memcpy(buf + offset, src, len); + memcpy(cache->buf + offset, src, len); // Write sector in pages of 256 bytes for (size_t i = 0; i < 16; ++i) { if (dirty & (1 << i)) { - int ret = mp_spiflash_write_page(self, addr + i * PAGE_SIZE, buf + i * PAGE_SIZE); + int ret = mp_spiflash_write_page(self, addr + i * PAGE_SIZE, cache->buf + i * PAGE_SIZE); if (ret != 0) { return ret; } @@ -378,16 +378,17 @@ int mp_spiflash_write(mp_spiflash_t *self, uint32_t addr, size_t len, const uint mp_spiflash_acquire_bus(self); - if (bufuser == self && bis <= bufsec && bie >= bufsec) { + mp_spiflash_cache_t *cache = self->config->cache; + if (cache->user == self && bis <= cache->block && bie >= cache->block) { // Write straddles current buffer uint32_t pre; uint32_t offset; - if (bufsec * SECTOR_SIZE >= addr) { - pre = bufsec * SECTOR_SIZE - addr; + if (cache->block * SECTOR_SIZE >= addr) { + pre = cache->block * SECTOR_SIZE - addr; offset = 0; } else { pre = 0; - offset = addr - bufsec * SECTOR_SIZE; + offset = addr - cache->block * SECTOR_SIZE; } // Write buffered part first @@ -397,7 +398,7 @@ int mp_spiflash_write(mp_spiflash_t *self, uint32_t addr, size_t len, const uint len = len_in_buf - (SECTOR_SIZE - offset); len_in_buf = SECTOR_SIZE - offset; } - memcpy(&buf[offset], &src[pre], len_in_buf); + memcpy(&cache->buf[offset], &src[pre], len_in_buf); self->flags |= 1; // Mark dirty // Write part before buffer sector diff --git a/drivers/memory/spiflash.h b/drivers/memory/spiflash.h index 03bad5296..66e7906cc 100644 --- a/drivers/memory/spiflash.h +++ b/drivers/memory/spiflash.h @@ -29,11 +29,23 @@ #include "drivers/bus/spi.h" #include "drivers/bus/qspi.h" +#define MP_SPIFLASH_ERASE_BLOCK_SIZE (4096) // must be a power of 2 + enum { MP_SPIFLASH_BUS_SPI, MP_SPIFLASH_BUS_QSPI, }; +struct _mp_spiflash_t; + +// A cache must be provided by the user in the config struct. The same cache +// struct can be shared by multiple SPI flash instances. +typedef struct _mp_spiflash_cache_t { + uint8_t buf[MP_SPIFLASH_ERASE_BLOCK_SIZE] __attribute__((aligned(4))); + struct _mp_spiflash_t *user; // current user of buf, for shared use + uint32_t block; // current block stored in buf; 0xffffffff if invalid +} mp_spiflash_cache_t; + typedef struct _mp_spiflash_config_t { uint32_t bus_kind; union { @@ -47,6 +59,7 @@ typedef struct _mp_spiflash_config_t { const mp_qspi_proto_t *proto; } u_qspi; } bus; + mp_spiflash_cache_t *cache; } mp_spiflash_config_t; typedef struct _mp_spiflash_t { -- cgit v1.2.3 From cc5a94044a670f5acccefa8e04a38e81d882e087 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 7 Jun 2018 15:36:27 +1000 Subject: drivers/memory/spiflash: Rename functions to indicate they use cache. This patch renames the existing SPI flash API functions to reflect the fact that the go through the cache: mp_spiflash_flush -> mp_spiflash_cache_flush mp_spiflash_read -> mp_spiflash_cached_read mp_spiflash_write -> mp_spiflash_cached_write --- drivers/memory/spiflash.c | 25 ++++++++++++++----------- drivers/memory/spiflash.h | 8 +++++--- ports/stm32/spibdev.c | 8 ++++---- 3 files changed, 23 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/memory/spiflash.c b/drivers/memory/spiflash.c index 0cc926b79..d750d87be 100644 --- a/drivers/memory/spiflash.c +++ b/drivers/memory/spiflash.c @@ -221,7 +221,10 @@ STATIC int mp_spiflash_write_page(mp_spiflash_t *self, uint32_t addr, const uint return mp_spiflash_wait_wip0(self); } -void mp_spiflash_read(mp_spiflash_t *self, uint32_t addr, size_t len, uint8_t *dest) { +/******************************************************************************/ +// Interface functions that use the cache + +void mp_spiflash_cached_read(mp_spiflash_t *self, uint32_t addr, size_t len, uint8_t *dest) { if (len == 0) { return; } @@ -261,7 +264,7 @@ void mp_spiflash_read(mp_spiflash_t *self, uint32_t addr, size_t len, uint8_t *d mp_spiflash_release_bus(self); } -STATIC void mp_spiflash_flush_internal(mp_spiflash_t *self) { +STATIC void mp_spiflash_cache_flush_internal(mp_spiflash_t *self) { #if USE_WR_DELAY if (!(self->flags & 1)) { return; @@ -287,13 +290,13 @@ STATIC void mp_spiflash_flush_internal(mp_spiflash_t *self) { #endif } -void mp_spiflash_flush(mp_spiflash_t *self) { +void mp_spiflash_cache_flush(mp_spiflash_t *self) { mp_spiflash_acquire_bus(self); - mp_spiflash_flush_internal(self); + mp_spiflash_cache_flush_internal(self); mp_spiflash_release_bus(self); } -STATIC int mp_spiflash_write_part(mp_spiflash_t *self, uint32_t addr, size_t len, const uint8_t *src) { +STATIC int mp_spiflash_cached_write_part(mp_spiflash_t *self, uint32_t addr, size_t len, const uint8_t *src) { // Align to 4096 sector uint32_t offset = addr & 0xfff; uint32_t sec = addr >> 12; @@ -301,7 +304,7 @@ STATIC int mp_spiflash_write_part(mp_spiflash_t *self, uint32_t addr, size_t len // Restriction for now, so we don't need to erase multiple pages if (offset + len > SECTOR_SIZE) { - printf("mp_spiflash_write_part: len is too large\n"); + printf("mp_spiflash_cached_write_part: len is too large\n"); return -MP_EIO; } @@ -310,7 +313,7 @@ STATIC int mp_spiflash_write_part(mp_spiflash_t *self, uint32_t addr, size_t len // Acquire the sector buffer if (cache->user != self) { if (cache->user != NULL) { - mp_spiflash_flush(cache->user); + mp_spiflash_cache_flush(cache->user); } cache->user = self; cache->block = 0xffffffff; @@ -320,7 +323,7 @@ STATIC int mp_spiflash_write_part(mp_spiflash_t *self, uint32_t addr, size_t len // Read sector #if USE_WR_DELAY if (cache->block != 0xffffffff) { - mp_spiflash_flush_internal(self); + mp_spiflash_cache_flush_internal(self); } #endif mp_spiflash_read_data(self, addr, SECTOR_SIZE, cache->buf); @@ -372,7 +375,7 @@ STATIC int mp_spiflash_write_part(mp_spiflash_t *self, uint32_t addr, size_t len return 0; // success } -int mp_spiflash_write(mp_spiflash_t *self, uint32_t addr, size_t len, const uint8_t *src) { +int mp_spiflash_cached_write(mp_spiflash_t *self, uint32_t addr, size_t len, const uint8_t *src) { uint32_t bis = addr / SECTOR_SIZE; uint32_t bie = (addr + len - 1) / SECTOR_SIZE; @@ -407,7 +410,7 @@ int mp_spiflash_write(mp_spiflash_t *self, uint32_t addr, size_t len, const uint if (rest == 0) { rest = SECTOR_SIZE; } - int ret = mp_spiflash_write_part(self, addr, rest, src); + int ret = mp_spiflash_cached_write_part(self, addr, rest, src); if (ret != 0) { mp_spiflash_release_bus(self); return ret; @@ -428,7 +431,7 @@ int mp_spiflash_write(mp_spiflash_t *self, uint32_t addr, size_t len, const uint if (rest > len) { rest = len; } - int ret = mp_spiflash_write_part(self, addr, rest, src); + int ret = mp_spiflash_cached_write_part(self, addr, rest, src); if (ret != 0) { mp_spiflash_release_bus(self); return ret; diff --git a/drivers/memory/spiflash.h b/drivers/memory/spiflash.h index 66e7906cc..4837fe3f9 100644 --- a/drivers/memory/spiflash.h +++ b/drivers/memory/spiflash.h @@ -68,8 +68,10 @@ typedef struct _mp_spiflash_t { } mp_spiflash_t; void mp_spiflash_init(mp_spiflash_t *self); -void mp_spiflash_flush(mp_spiflash_t *self); -void mp_spiflash_read(mp_spiflash_t *self, uint32_t addr, size_t len, uint8_t *dest); -int mp_spiflash_write(mp_spiflash_t *self, uint32_t addr, size_t len, const uint8_t *src); + +// These functions use the cache (which must already be configured) +void mp_spiflash_cache_flush(mp_spiflash_t *self); +void mp_spiflash_cached_read(mp_spiflash_t *self, uint32_t addr, size_t len, uint8_t *dest); +int mp_spiflash_cached_write(mp_spiflash_t *self, uint32_t addr, size_t len, const uint8_t *src); #endif // MICROPY_INCLUDED_DRIVERS_MEMORY_SPIFLASH_H diff --git a/ports/stm32/spibdev.c b/ports/stm32/spibdev.c index b73058c6a..368e63966 100644 --- a/ports/stm32/spibdev.c +++ b/ports/stm32/spibdev.c @@ -42,7 +42,7 @@ int32_t spi_bdev_ioctl(spi_bdev_t *bdev, uint32_t op, uint32_t arg) { case BDEV_IOCTL_IRQ_HANDLER: if ((bdev->spiflash.flags & 1) && HAL_GetTick() - bdev->flash_tick_counter_last_write >= 1000) { - mp_spiflash_flush(&bdev->spiflash); + mp_spiflash_cache_flush(&bdev->spiflash); led_state(PYB_LED_RED, 0); // indicate a clean cache with LED off } return 0; @@ -51,7 +51,7 @@ int32_t spi_bdev_ioctl(spi_bdev_t *bdev, uint32_t op, uint32_t arg) { if (bdev->spiflash.flags & 1) { // we must disable USB irqs to prevent MSC contention with SPI flash uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS); - mp_spiflash_flush(&bdev->spiflash); + mp_spiflash_cache_flush(&bdev->spiflash); led_state(PYB_LED_RED, 0); // indicate a clean cache with LED off restore_irq_pri(basepri); } @@ -63,7 +63,7 @@ int32_t spi_bdev_ioctl(spi_bdev_t *bdev, uint32_t op, uint32_t arg) { int spi_bdev_readblocks(spi_bdev_t *bdev, uint8_t *dest, uint32_t block_num, uint32_t num_blocks) { // we must disable USB irqs to prevent MSC contention with SPI flash uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS); - mp_spiflash_read(&bdev->spiflash, block_num * FLASH_BLOCK_SIZE, num_blocks * FLASH_BLOCK_SIZE, dest); + mp_spiflash_cached_read(&bdev->spiflash, block_num * FLASH_BLOCK_SIZE, num_blocks * FLASH_BLOCK_SIZE, dest); restore_irq_pri(basepri); return 0; @@ -72,7 +72,7 @@ int spi_bdev_readblocks(spi_bdev_t *bdev, uint8_t *dest, uint32_t block_num, uin int spi_bdev_writeblocks(spi_bdev_t *bdev, const uint8_t *src, uint32_t block_num, uint32_t num_blocks) { // we must disable USB irqs to prevent MSC contention with SPI flash uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS); - int ret = mp_spiflash_write(&bdev->spiflash, block_num * FLASH_BLOCK_SIZE, num_blocks * FLASH_BLOCK_SIZE, src); + int ret = mp_spiflash_cached_write(&bdev->spiflash, block_num * FLASH_BLOCK_SIZE, num_blocks * FLASH_BLOCK_SIZE, src); if (bdev->spiflash.flags & 1) { led_state(PYB_LED_RED, 1); // indicate a dirty cache with LED on bdev->flash_tick_counter_last_write = HAL_GetTick(); -- cgit v1.2.3 From b78ca32476ba666412a9ec44a5453094fbf0dbd7 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 7 Jun 2018 15:39:46 +1000 Subject: drivers/memory/spiflash: Add functions for direct erase/read/write. These new API functions do not use the cache. --- drivers/memory/spiflash.c | 56 +++++++++++++++++++++++++++++++++++++++++------ drivers/memory/spiflash.h | 7 +++++- 2 files changed, 55 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/memory/spiflash.c b/drivers/memory/spiflash.c index d750d87be..c0b55591b 100644 --- a/drivers/memory/spiflash.c +++ b/drivers/memory/spiflash.c @@ -187,7 +187,7 @@ void mp_spiflash_init(mp_spiflash_t *self) { mp_spiflash_release_bus(self); } -STATIC int mp_spiflash_erase_sector(mp_spiflash_t *self, uint32_t addr) { +STATIC int mp_spiflash_erase_block_internal(mp_spiflash_t *self, uint32_t addr) { // enable writes mp_spiflash_write_cmd(self, CMD_WREN); @@ -204,7 +204,7 @@ STATIC int mp_spiflash_erase_sector(mp_spiflash_t *self, uint32_t addr) { return mp_spiflash_wait_wip0(self); } -STATIC int mp_spiflash_write_page(mp_spiflash_t *self, uint32_t addr, const uint8_t *src) { +STATIC int mp_spiflash_write_page(mp_spiflash_t *self, uint32_t addr, size_t len, const uint8_t *src) { // enable writes mp_spiflash_write_cmd(self, CMD_WREN); @@ -215,12 +215,53 @@ STATIC int mp_spiflash_write_page(mp_spiflash_t *self, uint32_t addr, const uint } // write the page - mp_spiflash_write_cmd_addr_data(self, CMD_WRITE, addr, PAGE_SIZE, src); + mp_spiflash_write_cmd_addr_data(self, CMD_WRITE, addr, len, src); // wait WIP=0 return mp_spiflash_wait_wip0(self); } +/******************************************************************************/ +// Interface functions that go direct to the SPI flash device + +int mp_spiflash_erase_block(mp_spiflash_t *self, uint32_t addr) { + mp_spiflash_acquire_bus(self); + int ret = mp_spiflash_erase_block_internal(self, addr); + mp_spiflash_release_bus(self); + return ret; +} + +void mp_spiflash_read(mp_spiflash_t *self, uint32_t addr, size_t len, uint8_t *dest) { + if (len == 0) { + return; + } + mp_spiflash_acquire_bus(self); + mp_spiflash_read_data(self, addr, len, dest); + mp_spiflash_release_bus(self); +} + +int mp_spiflash_write(mp_spiflash_t *self, uint32_t addr, size_t len, const uint8_t *src) { + mp_spiflash_acquire_bus(self); + int ret = 0; + uint32_t offset = addr & (PAGE_SIZE - 1); + while (len) { + size_t rest = PAGE_SIZE - offset; + if (rest > len) { + rest = len; + } + ret = mp_spiflash_write_page(self, addr, rest, src); + if (ret != 0) { + break; + } + len -= rest; + addr += rest; + src += rest; + offset = 0; + } + mp_spiflash_release_bus(self); + return ret; +} + /******************************************************************************/ // Interface functions that use the cache @@ -275,14 +316,15 @@ STATIC void mp_spiflash_cache_flush_internal(mp_spiflash_t *self) { mp_spiflash_cache_t *cache = self->config->cache; // Erase sector - int ret = mp_spiflash_erase_sector(self, cache->block * SECTOR_SIZE); + int ret = mp_spiflash_erase_block_internal(self, cache->block * SECTOR_SIZE); if (ret != 0) { return; } // Write for (int i = 0; i < 16; i += 1) { - int ret = mp_spiflash_write_page(self, cache->block * SECTOR_SIZE + i * PAGE_SIZE, cache->buf + i * PAGE_SIZE); + uint32_t addr = cache->block * SECTOR_SIZE + i * PAGE_SIZE; + int ret = mp_spiflash_write_page(self, addr, PAGE_SIZE, cache->buf + i * PAGE_SIZE); if (ret != 0) { return; } @@ -344,7 +386,7 @@ STATIC int mp_spiflash_cached_write_part(mp_spiflash_t *self, uint32_t addr, siz if (cache->buf[offset + i] != src[i]) { if (cache->buf[offset + i] != 0xff) { // Erase sector - int ret = mp_spiflash_erase_sector(self, addr); + int ret = mp_spiflash_erase_block_internal(self, addr); if (ret != 0) { return ret; } @@ -363,7 +405,7 @@ STATIC int mp_spiflash_cached_write_part(mp_spiflash_t *self, uint32_t addr, siz // Write sector in pages of 256 bytes for (size_t i = 0; i < 16; ++i) { if (dirty & (1 << i)) { - int ret = mp_spiflash_write_page(self, addr + i * PAGE_SIZE, cache->buf + i * PAGE_SIZE); + int ret = mp_spiflash_write_page(self, addr + i * PAGE_SIZE, PAGE_SIZE, cache->buf + i * PAGE_SIZE); if (ret != 0) { return ret; } diff --git a/drivers/memory/spiflash.h b/drivers/memory/spiflash.h index 4837fe3f9..a5b8a1dca 100644 --- a/drivers/memory/spiflash.h +++ b/drivers/memory/spiflash.h @@ -59,7 +59,7 @@ typedef struct _mp_spiflash_config_t { const mp_qspi_proto_t *proto; } u_qspi; } bus; - mp_spiflash_cache_t *cache; + mp_spiflash_cache_t *cache; // can be NULL if cache functions not used } mp_spiflash_config_t; typedef struct _mp_spiflash_t { @@ -69,6 +69,11 @@ typedef struct _mp_spiflash_t { void mp_spiflash_init(mp_spiflash_t *self); +// These functions go direct to the SPI flash device +int mp_spiflash_erase_block(mp_spiflash_t *self, uint32_t addr); +void mp_spiflash_read(mp_spiflash_t *self, uint32_t addr, size_t len, uint8_t *dest); +int mp_spiflash_write(mp_spiflash_t *self, uint32_t addr, size_t len, const uint8_t *src); + // These functions use the cache (which must already be configured) void mp_spiflash_cache_flush(mp_spiflash_t *self); void mp_spiflash_cached_read(mp_spiflash_t *self, uint32_t addr, size_t len, uint8_t *dest); -- cgit v1.2.3 From 8b8c083625b15ae9e3560b96ee98408c4810544d Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 15 Jun 2018 18:01:36 +1000 Subject: drivers/sdcard: Change driver to use new block-device protocol. --- drivers/sdcard/sdcard.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/sdcard/sdcard.py b/drivers/sdcard/sdcard.py index 8f28b476e..89d5d13ab 100644 --- a/drivers/sdcard/sdcard.py +++ b/drivers/sdcard/sdcard.py @@ -223,9 +223,6 @@ class SDCard: self.cs(1) self.spi.write(b'\xff') - def count(self): - return self.sectors - def readblocks(self, block_num, buf): nblocks = len(buf) // 512 assert nblocks and not len(buf) % 512, 'Buffer length is invalid' @@ -270,3 +267,8 @@ class SDCard: offset += 512 nblocks -= 1 self.write_token(_TOKEN_STOP_TRAN) + + def ioctl(self, op, arg): + print('ioctl', op, arg) + if op == 4: # get number of blocks + return self.sectors -- cgit v1.2.3 From 1747d15c3afa12672d156664eabb29e3ba3b17d7 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 15 Jun 2018 18:02:40 +1000 Subject: drivers/sdcard: Fix bug in computing number of sectors on SD Card. This was a typo from the very first commit of this file. --- drivers/sdcard/sdcard.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/sdcard/sdcard.py b/drivers/sdcard/sdcard.py index 89d5d13ab..fe402f745 100644 --- a/drivers/sdcard/sdcard.py +++ b/drivers/sdcard/sdcard.py @@ -97,7 +97,7 @@ class SDCard: csd = bytearray(16) self.readinto(csd) if csd[0] & 0xc0 == 0x40: # CSD version 2.0 - self.sectors = ((csd[8] << 8 | csd[9]) + 1) * 2014 + self.sectors = ((csd[8] << 8 | csd[9]) + 1) * 1024 elif csd[0] & 0xc0 == 0x00: # CSD version 1.0 (old, <=2GB) c_size = csd[6] & 0b11 | csd[7] << 2 | (csd[8] & 0b11000000) << 4 c_size_mult = ((csd[9] & 0b11) << 1) | csd[10] >> 7 -- cgit v1.2.3