ports/esp32:a bug with Hardware SPI Initialize on ESP32-S3
Hi,all:
Problem description and analysis
- Hardware: ESP32S3
- Firmware version: esp32/GENERIC_S3 v1.19.1 (2022-06-18) or master branch
- Abstract: SPI(1) and SPI(2) need two initializations to work perfectly in each operation. If two initializations of different Baudrates are not carried out, SPI may not work.
code and pictures
- Initialize with different baudrates()
self.spi = SPI(2,baudrate=4_000_000,polarity=0, phase=0,sck=Pin(SCK,Pin.OUT),mosi=Pin(MOSI,Pin.OUT))
self.spi = SPI(2,baudrate=8_000_000,polarity=0, phase=0,sck=Pin(SCK,Pin.OUT),mosi=Pin(MOSI,Pin.OUT))

- Initialize with same baudrates(In order to reproduce the problem 100%, you also can initialize it once and run it again)
self.spi = SPI(2,baudrate=8_000_000,polarity=0, phase=0,sck=Pin(SCK,Pin.OUT),mosi=Pin(MOSI,Pin.OUT))
self.spi = SPI(2,baudrate=8_000_000,polarity=0, phase=0,sck=Pin(SCK,Pin.OUT),mosi=Pin(MOSI,Pin.OUT))

details
First time
I used the firmware V1.91.1 and found that SPI (1) initialization was abnormal. SPI(2) can work normally.
However, when I tried for the second time (after stop), I found that it could not work.
I tried to restart it and it could work again, but it still couldn't work the second time.
Then I tried various methods and accidentally found that baudrate could work after modification. So I conducted two initializations,The baudrate needs of the first initialization were different from that of the second initialization,The program could run perfectly, no matter whether it was STOP or not.
- like
self.spi = SPI(2,baudrate=4_000_000,polarity=0, phase=0,sck=Pin(SCK,Pin.OUT),mosi=Pin(MOSI,Pin.OUT))
self.spi = SPI(2,baudrate=8_000_000,polarity=0, phase=0,sck=Pin(SCK,Pin.OUT),mosi=Pin(MOSI,Pin.OUT))
I found out that lssues #8634 suffers from a similar problem and saw the initialization issue solved in #9498
The second time
I tried to use the master branch to build a new firmware to try,
and then I found that SPI(1) and SPI(2) can be initialized normally and work, but the problem still exists that the initialization needs to be twice.
Esp32s2 changes
HW SPI did not work on esp32-s2:
MicroPython v1.15-74-gfb631644e on 2021-05-04; ESP32S2 module with ESP32S2
Type "help()" for more information.
>>> esp.osdebug(0,esp.LOG_DEBUG)
>>> from machine import SPI
>>> spi1=SPI(1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: SPI(1) doesn't exist
>>> spi2=SPI(2)
E (128705) spi: spi_bus_initialize(632): invalid dma channel
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
OSError: invalid configuration
The problem is caused by different SPI_HOST aliases for CONFIG_IDF_TARGET_ESP32S2
in esp-idf/components/hal/include/hal/spi_types.h:
#define FSPI_HOST SPI2_HOST
#define HSPI_HOST SPI3_HOST
There is no VSPI_HOST so SPI(1) does not exist.
HSPI_HOST moved from SPI2 to SPI3. That's why SPI(2) tried wrong DMA channel.
MicroPython v1.15 is no longer compatible with IDF 3.x so we can avoid [HVF]SPI_HOST
aliases and use SPI[123]_HOST directly. Also from IDF 4.3 we can use SPI_DMA_CH_AUTO
instead of selecting proper channel number.
The commit "esp32-s2: set default SPI pins for GENERIC_S2 board" sets proper default pins
for SPI(1) and SPI(2). The question is if we should not change the default pin definitions
MICROPY_HW_SPI1_SCK... based on CONFIG_IDF_TARGET_ESP32S2
The last commit "esp32-s2: make GPIO 26 usable if SPIRAM is not configured"
is not related to SPI - just adds GPIO 26 if not used as SPIRAM CS