ESP32 <---> P2 SPI Code (runs at 2.4MBytes/sec)

RJSMRJSM Posts: 64
edited 2020-07-24 - 07:16:14 in Propeller 2
A number of posts on the forums have expressed interest in connecting the P2 to an ESP32, thereby giving the P2 access to the outside world. I’ve developed some code to do this as part of a larger project and thought I’d share it for others to use and improve upon. The 2 programs here will allow you to connect a P2-EVALB and an ESP32 module via an SPI link (here the ESP32 is the master running a 20 MHz SPI clock - and the P2 is the slave). The actual data transfer rate you'll achieve (measured for a 32k data transfer in either direction) is ~ 2.4 Mbytes/sec. An Adafruit (or similar) NeoPixel (8 x WS2812) strip connected to the P2 provides lots of visual feedback as the code runs.

My ESP32 code was developed using the Arduino IDE. I found and made use of an ESP32 DMA SPI library that was essential in getting this working without too much complexity on the P2 end – the relevant link to that is mentioned in the code comments.

To do this work I made a small PCB that has an ESP32 module riding piggyback on my P2-EVALB (the DipTrace schematic pdf shows the connections). The photo here is rather old – in current testing I’ve got the breakout PCB plugged into the P31..P16 headers on a P2-EVALB board, but just P19..16 are used for the 4 wire SPI bus and P20 for the LED string.

You’ll find lots of comments to explain what’s going on at either end of this SPI link. Once data is moved over to the ESP32 then you can send it off to the cloud or whatever else you so desire. The world literally is your oyster then !

I’ve been talking to this P2/ESP32 combo by sending messages from another ESP chip (an 8266) located over 1 km away – all just using the Espressif radios - but that’s another story….

n.b. The forum software did not allow the usual .ino file extension for the ESP32 Arduino IDE code so I've just changed it to .txt !


  • Sorry that should have said ESP32 <---> P2 SPI code !! Can the thread title be changed ??
  • Good timing, I'm finalizing my P2 pcbs including the P2PAL with the ESP-WROOM-32D bare module on it and I've been wondering about how best to connect the two together!
  • roglohrogloh Posts: 2,472
    edited 2020-07-24 - 06:44:20
    Yeah that optional four pin SPI bus connection on P2PAL now looks pretty useful with what RJSM has done.

    He's used VSPI pins for the connection to the P2 while the HSPI pins are physically probably more convenient to wire to port B of the P2D2 but I read both these two ESP32 SPI ports are interchangeable and general purpose and can operate as master or slave so this wiring difference shouldn't matter (in theory).

    Another use of these extra pin connections if SPI is not used, could be for SW controlled flow control between ESP32 and P2. This could become important at higher speeds over serial. I'm trying to figure out how fast the ESP32 serial port can be vs the 20MHz SPI RJSM achieved. UPDATE: UART might just be 5Mbps, so SPI looks quite a bit faster. I also read that SPI can clock up to 80MHz; the board signal integrity might start to become a factor then, maybe some series resistors are required for that performance.
  • rogloh is spot on as to both points re the ESP32 UART max data rate of 5 Mbps and max SPI CLK of 80 MHz, see sections 4.1.10 and 4.1.17 of the attached doc
  • To change the title, edit the first post and then you can change the title while in edit mode.
  • Peter JakackiPeter Jakacki Posts: 9,340
    edited 2020-07-24 - 07:11:09
    I just have to find the schematic for that ESP32 dev module because I use the bare module and the pin names don't match up. Hopefully I'll get it right. The photo is nice and clear so I should be able to work it out.
  • roglohrogloh Posts: 2,472
    edited 2020-07-24 - 07:16:46
    @Peter Jakacki Check figure 1 of this document for pin mapping on the module...also figure 3 for schematic.

    By the way, I was reading about the internal pin muxing capabilities of the ESP32 and it looks useful. You can apparently remap GPIO pins so your might be able to run a second serial port over those same HSPI pins for example, if I read it right.
  • Thanks Cluso99 !
  • Good timing, I'm finalizing my P2 pcbs including the P2PAL with the ESP-WROOM-32D bare module on it and I've been wondering about how best to connect the two together!

    Hi Peter,

    Could these be ordered with the ESP-WROOM-32U? Everything I do involves metal enclosures and so I need the external antenna.
  • One interesting aspect might be to boot the ESP32 code over HSPI from the P2. This appears to be possible via eFuse settings. This may allow faster development/testing of ESP32 code directly from the P2, without needing to flash the module first. Of course how to prepare the ESP32 code from the P2 is another story...a toolchain is required somewhere, but this HSPI connection may still allow interesting capabilities for downloading code.
  • @rogloh - that's the datasheet I have but that is for the bare module, not the dev board with USB that the module is mounted to, that is then mounted onto another adapter that is then mounted to the P2 EVAL :)

    @Mickster - Yes, absolutely as the modules are the same except for the antenna so I am just testing with this type for general dev work but some end use will call for an antenna.

  • @rogloh - that's the datasheet I have but that is for the bare module, not the dev board with USB that the module is mounted to, that is then mounted onto another adapter that is then mounted to the P2 EVAL :)
    Ok, I am under the impression you'll ultimately be taking one of these WROOM-32 module(s) and fitting it to your P2PAL directly, so all those pin locations from that data sheet and schematic would be what you really need to design it. However if you plan to test something out yourself first with either the P2-EVAL or your P2D2 using an off the shelf ESP32 board before you finalize the P2PAL design then I guess that's another story.

    Key will be to wire in the standard serial comm pins, the enable, GPIO0 and an optional SPI bus of which HSPI is likely the easiest, and that extra reset out GPIO pin to reset the P2D2 module. My suggestion in the P2D2 thread should hopefully help.
  • Looks like rjsm is using a ESP32-DevKitC. The trouble is that they don't use the same pin terminology across all the datasheets. The ESP32 chip vs the module vs the devkit, go figure.
  • Peter, I've attached a pin diagram for the specific module that I used for this project, on checking it turns out it's a NODEMCU-32S. Yes - there are a number of variants of these modules out there, which is very confusing.

    Most of the built modules do not expose all of the GPIO's that are available on the ESP-WROOM-32 module from Espressif that I believe you are using for P2D2.

    I used the 4 VSPI pins - but if you'd rather access HSPI then you will use the GPIO's with the SPI labels in this diagram.
    965 x 486 - 521K
  • Thanks Richard, I connected the HSPI pins and I2C but I'm not real sure about the other pins that might be needed to select boot modes. With the devkit this is looked after but I want to make sure I don't paint myself into a corner by not allowing for certain connections.
  • Not quite checked and tweaked but the basic layout with HSPI connected. I will post a schematic later tonight.
    2188 x 1169 - 1M
  • roglohrogloh Posts: 2,472
    edited 2020-07-26 - 05:43:30
    @Peter Jakacki I took a look at this and mapped out your connections to see how you wired this. It's looking very good and offers lots of possible options. I think this is how you wired it:

    Looks like you share the SPI bus CLK and CS for the PSRAM with the ESP32 HSPI bus and have found a way to maintain QuadSPI capabilities to the PSRAM while giving the ESP32 its own data line. Neat. An alternative would be its own chip select and a shared IO pin but that relies on tri-state stuff working nicely. A side effect is the SPI slave in the ESP32 would always see the same data sent to it as the PSRAM, but it would respond if required on its own MISO line back to the P2.

    Not sure why you included GPIO2 connection to the P2 and not just let the internal pulldown remain at logic 0, but there's probably a possibility of mapping ESP GPIO2 to U2RTS internally to this extra pin (assuming the IOMux can do this) which could then hopefully provide an option for the secondary serial interface to support full HW flow control.

    Note : for U2CTS there is a small risk that if a P2D2 user is also using pin 9 of the P2 on their system board then it can prevent the ESP32 from booting via its flash which shares this signal.

    Suggestion for a remote wifi reset control:

    Add a reset output pin from the a free ESP32 GPIO on the ESP32 to the reset pin of the P2D2 via a diode (cathode to ESP). I'd pick one that is a RTC_GPIO as well, in case the board is in a low power mode and the internal ESP state machine controller might want to drive reset to reboot when the system is in a deep sleep state. You obviously shouldn't choose an input only pin from pin 4-7 on the module for this purpose and also not select one that pulls down by default or outputs PWM at startup. Something that either floats or pulls up during ESP reset would be good and the series diode is there to save us.

    I found these links which are handy as they talk about pins you shouldn't use during boot etc.
    891 x 623 - 114K
  • roglohrogloh Posts: 2,472
    edited 2020-07-26 - 05:26:06
    Peter, to get around the potential limitation with U2CTS preventing ESP32 boot I would consider tweaking your P2PAL wiring slightly and do this. Wire 4 pins instead of 5 on port A (ditch U2CTS) and just shift the existing connections along by one P2 pin. This will also prevent always losing special port A pins 0..7 if the Wifi module is fitted (unless the secondary serial is required which is a choice anyway, while GPIO0 is sort of essential). It will also let me keep using my 18 bit parallel LCD module with the P2D2 and the P2 RGB streamer by my skipping of the 2 LSbs of each port A byte, otherwise I'll need to cut and switch some tracks on each P2PAL. :smile:

    Both GPIO0 and GPIO2 can get used later after ESP32 boot for general status/interrupt signalling use (and probably even HW flow control if remapped in the IOMUX to RTS/CTS lines). So you could wire like this for example...

    P6 - U2TXD
    P7 - U2RXD
    P8 - GPIO0
    P9 - GPIO2

  • Peter JakackiPeter Jakacki Posts: 9,340
    edited 2020-07-26 - 08:56:22
    @rogloh - thanks for those info and links, the pinout reference one was particularly useful. I pick GPIO33 as an output for P2 RESET that is wired to the button input which is picked up by the UB3. GPIO33 should either float or go low to reset as I don't really see the need for a diode, especially since it looks a bit crowded on the pcb :)
    I disconnected P8 from GPIO2 although I just left an untented via right next to the header pad.
    I gather your 18-bit LCD would be using P2..P7 then P10..P15 etc. I had left P0..P4 free for VGA but I could wire RXD2/TXD2 to P8,P9 and find another P2 pin for GPIO0 I guess. (Just noticed I hadn't disconnected P9, now that I know it's the internal boot Flash)

    BTW - I forgot to attach the schematic but here it is. I also changed the CS to SRD3 which is normally the hold pin so that the PSRAM won't be affected.
    1975 x 1337 - 188K
  • roglohrogloh Posts: 2,472
    edited 2020-07-26 - 16:05:44
    Yeah MDTO is not actually the SD1 pin (pin 22) on your WROOM32 module, it is actually shared with IO15 (pin 23) and is also used as our HSS (HSPICS0) signal too, so it was mislabeled on your drawing which probably led to the confusion about needing to connect it.

    You are right about the 18 bit LCD panel wiring, I skip the 2 LSBs of the first three bytes of port A, which can then be used for other purposes outside of video. So it would be useful for people who have parallel LCDs like this to keep these bits free, and put your optional second serial channel on P8 and P9 as you mentioned. GPIO0 is important to keep connected for programming, but if you've just remapped your HSS/MISO for the slave ESP32 SPI you could use that now freed pin P54 which would probably make things ideal and in most cases will keep all ESP connections contained on port B unless you choose to make use of an optional second serial channel. With a slave ESP32 SPI capability that channel is less likely to be needed, but people can still use it if desired.
    EDIT: actually this wiring method only works if QSPI is never used with PSRAM when the SPI slave is used. Still okay though for dual/single SPI on PSRAM with an ESP32 SPI slave if it tri-states. It's a good compromise.

    The no-diode reset approach is probably fine as long as we always code the ESP32 to never drive active high but only open drain low (so the reset switch doesn't short the ESP32 output). It just puts a slight software burden on all the future ESP32 developers, that's all. They'll all need to know to never drive it high with their P2D2s. GPIO33 looks okay.

    Update: Actually going without the diode has an advantage in that the ESP32 can also sense the pushbutton switch and could take an action.
  • @Peter Jakacki I just read that ESP32 may not be tri-stating its MISO based on SS input. So something to consider in the SPI bus wiring with the PSRAM sharing. I noticed the Adafruit ESP32 Airlift board had used a separate little logic 74AHC1G125 chip to compensate for this.

  • @rogloh - ahh, you're up late! :smile:
    I probably will need to think about all these signals in the morning but here is what I have at present. BOOT0 is connected to P10 as I'm not sure where else I could connect it yet.
  • roglohrogloh Posts: 2,472
    edited 2020-07-26 - 23:43:03
    @Peter Jakacki Yeah was up late again (lockdown hours). Ok I can see why you might want to combine the three pins on port A in that way to leave 5 spare port A pins from P11-P15 for VGA use, and keeping the 8 lower port bits completely free (good for HDMI etc), I can see this makes sense.

    So if it is not possible to send BOOT0 (GPIO0) back to port B, could the GPIO0 at least be mapped one of the two lower pins of the 8 bit group, that way I can still reprogram the ESP32 if the 18 bit LCD is fitted/operational. Personally I'd give up default secondary serial pins in my own application, which can always be custom remapped in ESP32 code to use GPIO0 for the missing serial pin anyway via the GPIO MUX if I ever need it. So this pin mapping would be far better for me:

    P8 - GPIO0
    P9 - U2TXD
    P10 - U2RXD

    Hopefully your P2PAL bottom layer has a little room for this slight signal order reversal by using a another via or so.

    ps. Speaking of the bottom layer I guess you'll need to shuffle a few power traces/pads outside that diamond heat sink spreading pattern so it can bond to the P2D2 better without a shorting risk. Your gerber looks like it will all be exposed copper there (which will be good for heat spreading with solder paste or thermal compound).
  • @rogloh - Yes, the bottom layer still had to be tweaked to allow some room for bonding to the P2 PAD, but in this case I was able to use the whole area. That's right too, I could just use thermal compound rather than soldering.

    I'm still looking at boot0 (re)mapping and perhaps a diode for the reset.
    I wonder if the HyperRAM footprint pad size is ok? That reminds me, I still have to account for HyperFlash.
  • Actually Peter this diode might be best swapped out for a series resistor if you want the ability to sense the multi-purpose (reset) switch from the ESP32. eg. to wake it from a sleep mode. A diode won't let that type of sensing happen. You probably just need to pick a value that works ok with the pull up used internally in the EFM UB3 chip to be able to read a logic low level, and this series resistor will still protect the ESP32 against direct shorts when the RST button is pressed if the ESP is inadvertently driven high at the same time.

    To @RJSM, I'm sorry we have essentially hijacked your ESP32 software thread here discussing all this P2D2 ESP32 stuff, and I do kind of feel bad about that, but if we manage to get a P2D2 with an ESP32 capable of a SPI link etc out of this it is probably a good thing for everyone. You've already proven how useful this will be for us too with what you are doing.
  • @Peter Jakacki one more possibility for your GPIO0 (BOOT0) connection is to map it to P51 of the P2 (your SRD3), assuming you have P54 used again as the HSPI MISO pin. It would preclude using GPIO0 as an output later from the ESP after boot if QSPI PSRAM is also in use, but at least it would save needing to reserve that pin on port A. Also I read that this GPIO0 signal from the ESP32 will generate some PWM output at ESP32 boot, along with PWM on both IO15 and IO14 (which already share your SRCS and SRCLK pins on the SPI bus), so no we are no worse off there. This PWM during boot will just mean that any PSRAM use will have to wait until the ESP32 has booted and these signals cease before the P2 should drive the pin.

    To keep everything safe it might be nicer to run all these PWM transient signals through a series resnet first before hitting the P2 if you had the space on your board but I can see that could be really tight on your P2PAL unless you fit one just under that PSRAM label somewhere. This might help HSPI operating speeds perhaps too given the ESP32 can have a SPI clock up to 80MHz. So maybe some small series resistors could allow faster bus operation like you already found with the SD cards?
  • Peter JakackiPeter Jakacki Posts: 9,340
    edited 2020-07-27 - 17:01:16
    I ended up putting a resistor in series with the reset line and moving boot0 over to srd2 for starters. I might be able to fit a resnet in between the psram and the headers for some of the signals so that the ESP32 and P2 don't have problems during boot.

    Actually, I might hard-wire one of these modules to a P2D2 to make sure it all works. I just solder short lengths of wire-wrap directly to the pads.
    1652 x 823 - 318K
    1672 x 902 - 771K
  • For sure Peter, wiring an ESP32 module to a real P2D2 for some basic signal compatibility testing is a good idea to make sure P2D2 and ESP32 module can boot up simultaneously without issues and you can then probe the signals for any weird outputs that might be unexpected.

    If you can fit a resnet to stop any boot up PWM on HSPICS and HPSICLK and GPIO0 from messing up the PSRAM SPI bus signals or other shared Prop pin use whenever ESP32 is rebooted that will be nice, but P2 software can possibly try to workaround this if the ESP32 gets restarted while the P2 is already up just by not using PSRAM at this time, or delay using it from boot up until it would know the ESP32 is up.

    If you can pass the two HSPIQ and HSPID signals through another dual resnet too that may allow tuning of performance for higher speed SPI one day like you did with the SPI bus for SD (to reduce reflections etc). I can see it is getting tricker to do this as track placement is tighter now but if it can be done that could be a good thing.

    On the bottom layer, if the power tracks were spread further away from the diamond maybe it will help more heat transfer into your bulk copper plane. Even some extra via stitching up into the top layer bulk ground regions like below the SD card may help heat flow there faster as there appears a fair bit of free copper there (in relative terms anyway) and that MicroSD card shell might be metallic too. Hopefully you might get a little bit of room to play with that bottom layer once all components are positioned. It would be cool :-) if this P2PAL behaves very well as the P2 heatsink.
Sign In or Register to comment.