10000 displayio ParallelBus is not supported in the ESP32-S2 port · Issue #3600 · adafruit/circuitpython · GitHub
[go: up one dir, main page]

Skip to content

displayio ParallelBus is not supported in the ESP32-S2 port #3600

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
kmatch98 opened this issue Oct 23, 2020 · 6 comments
Closed

displayio ParallelBus is not supported in the ESP32-S2 port #3600

kmatch98 opened this issue Oct 23, 2020 · 6 comments
Labels
displayio espressif applies to multiple Espressif chips
Milestone

Comments

@kmatch98
Copy link

Currently the ESP32-S2 port does not support displayio ParallelBus, giving an error:
NotImplementedError: ParallelBus not yet supported

https://github.com/adafruit/circuitpython/blob/main/ports/esp32s2/common-hal/displayio/ParallelBus.c

Comparing the atmel-samd and nrf ports, it seems most of the required updates are in the ParallelBus constructor.

Use of the ParallelBus for displays will be useful in an PyPortal-like device (currently the fastest display speed in the line of Adafruit products). The ESP32-S2 datasheet indicates it has parallel display support of 8/16/24 bit transfers.

-snip-

3.4.3 LCD Interface

The LCD interface supports 8-bit serial RGB, 8080 and 6800 modes. It is implemented using the hardware resources of SPI2. The LCD interface can also support 8/16/24-bit parallel interface (8080), implemented using the hardware resources of I2S.

-/snip-

I think this fits in the long term tasks for whenever new hardware comes along.

@tannewt tannewt added displayio espressif applies to multiple Espressif chips labels Oct 26, 2020
@tannewt tannewt added this to the Long term milestone Oct 26, 2020
@tannewt
Copy link
Member
tannewt commented Oct 26, 2020

@kmatch98 I think the first step would be to bitbang it like SAMD and nRF ports do. I2S allows for DMA but we don't need it at the start.

@kmatch98
Copy link
Author

Thanks @tannewt. I did some reading about your comment. Seems like bitbanging will likely get the best performance, but at the expense of tying up the cpu to do the work, while DMA frees up the cpu but may not be as fast. Since there aren’t yet a lot of hooks for task management I see your point about using a similar approach as the other two ports.

I compared those two ports and it looks like the main changes need to be how to define the following items (see the samd port: https://github.com/adafruit/circuitpython/blob/main/ports/atmel-samd/common-hal/displayio/ParallelBus.c)

self->bus
self->write_group
self->write_mask

The samd port references a PortGroup type called &PORT And does some bitmath to define self->bus.
The nrf port references a NRF_GPIO_Type and a few constants called names such as NRF_P0 along with some bitshifting math to define self->bus.

Can you point out where to look to help figure out how to write these definitions for the ESP32-S2?

@tannewt
Copy link
Member
tannewt commented Oct 30, 2020

I think you want these definitions: https://github.com/espressif/esp-idf/blob/8bc19ba893e5544d571a753d82b44a84799b94b1/components/soc/soc/esp32s2/include/soc/gpio_struct.h

They should match the register names in the technical reference manual for the -S2.

@kmatch98
Copy link
Author

@tannewt Thanks for the additional detail. I'm still trying to make it up the learning curve on setting up these IO pins, so thank you for point me in the right direction.

I still am trying to figure out how to setup these registers to connect everything for the ParallelBus. If possible, I'd appreciate a few minutes of description at your famous Deep Dive Live Stream.

I'm fumbling through the documentation, so I wanted to capture what I found and request your feedback on which is the right direction to proceed. The question I have right now are what is the right configuration of GPIOs to pursue. After that is figured out I'll have to figure out how to translate that into the ParallelBus.c code.


Existing ports of ParallelBus for comparison:

Here's the ESP32-S2 Technical Reference Manual

I'm looking through the sections related to configuring the Inputs/Output (IO) of the general purpose IO (GPIO) in the Technical Reference Manual. Here's what I've found so far.

Here is the introduction to section 19 "IO MUX and GPIO Matrix (GPIO, IO_MUX)":

The ESP32-S2 chip features 43 physical GPIO pads. Each pad can be used as a general-purpose I/O, or be connected to an internal peripheral signal. The IO MUX, RTC IO MUX and the GPIO matrix are responsible for routing signals from the peripherals to GPIO pads. Together these modules provide highly configurable I/O.
Note that the GPIO pads are numbered from 0 ~ 21 and 26 ~ 46, while GPIO46 is input-only.
This chapter describes the selection and connection of the internal signals for the 43 digital pads and control
signals: FUN_SEL, IE, OE, WPU, WPD, etc. These internal signals include:
• 116 digital peripheral input signals, control signals: SIG_IN_SEL, SIG_OUT_SEL, IE, OE, etc.
• 182 digital peripheral output signals, control signals: SIG_IN_SEL, SIG_OUT_SEL, IE, OE, etc.
• fast peripheral input and output signals, control signals: IE, OE, etc.
• 22 RTC GPIO signals

In looking through the technical manual, there is a complicated diagram (Figure 19-1) :
image

In order to setup parallelBus, I assume that the GPIO matrix and IO MUX need to be configured properly to configure the internal IOs to the physical pins through the proper multiplexors, and then to write the ParallelBus.c code to define how CircuitPython display code will write to the correct IOs to communicate to the display.

From section 19.3 "Peripheral Output via GPIO Matrix":

To output a signal from a peripheral via GPIO matrix, the matrix is configured to route peripheral output signals (0 ~11, 14~18, and etc.) to one of the 42 GPIOs (0~21, 26~45). See Table 93.
The output signal is routed from the peripheral into GPIO matrix and then into IO MUX. IO MUX must be configured to set the chosen pad to GPIO function. This causes the output GPIO signal to be connected to the pad.

Section 19.3.2 "Function Description" describes the steps to connect an output signal to a physical pin (also called a "pad").

However, in Section 19.3.3 "Simple GPIO Output" seems like a simpler way to directly change the GPIO pad output. It seems like this may be the way to go?

Regarding "Simple GPIO Output" there is a cryptic suggestion:

Recommended operation: use corresponding W1TS and W1TC registers, such as GPIO_OUT_W1TS/GPIO_OUT_W1TC to set or clear the registers GPIO_OUT_REG/GPIO_OUT1_REG.

One more option is the "Dedicated GPIO" see section 19.4.

The dedicated GPIO module, consisting of eight input/output channels, is specially designed for CPU interaction with GPIO matrix and IO MUX. Peripheral input/output signals for input/output channels both are indexed from 235 to 242. By default, the output is enabled for output channels.

I'm not sure the difference of the "Dedicated GPIO" versus the other methods shown above.

Summary:

From my rudimentary understanding, it seems like the "Simple GPIO Output" configuration may be the easiest way to go, but not sure if it is the most efficient. To do this, it looks relatively simple to configure and write to the outputs, following section 19.3.3 "Simple GPIO Output":

GPIO matrix can also be used for simple GPIO output. This can be done as below:
• Set GPIO matrix GPIO_FUNCn_OUT_SEL with a special peripheral index 256 (0x100);
• Set the corresponding bit in GPIO_OUT_REG[31:0] or GPIO_OUT1_REG[21:0] register to the desired GPIO output value.

With the following special notes to consider:

Note:
• GPIO_OUT_REG[0] ~ GPIO_OUT_REG[31] correspond to GPIO0 ~ GPIO31, and GPIO_OUT_REG[25:22] are invalid.
• GPIO_OUT1_REG[0] ~ GPIO_OUT1_REG[13] correspond to GPIO32~GPIO45,and GPIO_OUT1_REG[21:14] are invalid.
• Recommended operation: use corresponding W1TS and W1TC registers, such as GPIO_OUT_W1TS/GPIO_OUT_W1TC to set or clear the registers GPIO_OUT_REG/GPIO_OUT1_REG.

@kmatch98
Copy link
Author

Thanks to @tannewt, he verified that the "Simple GPIO output" method is the way to proceed. Here is a link to a video of @tannewt's deep dive with related commentary on ParallelBus.

Also, in writing this code, I discovered a possible limitation of the ESP32-S2. It seems that the ESP32-S2 does not allow writes to the registers with data sizes < 32 bits. In section 10.3.3 of the technical reference manual, it indicates that the register that I am writing may cause an interrupt when trying to write single bytes (8-bits).

The register for the GPIO is right in the middle of this address location that is mentioned in this table (I'm trying to access address 0x3F404004, right in the middle of this section that may cause an interrupt or exception.)

I actually tried writing and reading single bytes fr 9AC8 om the register and all I got was junk data. I could not actually change the register when writing only a single byte. Perhaps this triggered a process interrupt and it returned some error codes that weren't properly handled.

So, I had to modify the code to write full 32-bits into the registers. I am issuing a PR with several questions due to the initial pin limitations.

@kmatch98
Copy link
Author
kmatch98 commented Feb 1, 2021

Closed with #4047

@kmatch98 kmatch98 closed this as completed Feb 1, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
displayio espressif applies to multiple Espressif chips
Projects
None yet
Development

No branches or pull requests

2 participants
0