Avoiding allocating MISO Pin in Software SPI

All ESP8266 boards running MicroPython.
Official boards are the Adafruit Huzzah and Feather boards.
Target audience: MicroPython users with an ESP8266 board.
Post Reply
cefn
Posts: 230
Joined: Tue Aug 09, 2016 10:58 am

Avoiding allocating MISO Pin in Software SPI

Post by cefn » Fri Jun 09, 2017 10:24 pm

Hi all,

THE ISSUE

Because of some unfortunate SPI-compliance issues with an ST7920 LCD screen, (which seems not to fully respect slave select, and hence won't ignore crosstalk from other SPI devices) I've had to dedicate a software SPI connection on the following GPIO pins, in parallel with the Hardware SPI to drive an RFID reader...

Code: Select all

{
"miso":16,
"mosi":5
"sck":4,
"ss":15
}
However, because the screen doesn't use the MISO line at all (the screen doesn't send anything back and doesn't even have a physical pin for it), I'd like to omit the miso pin from the SPI configuration as I am just one pin short of completing my project.

FIXING THE ISSUE?

The issue at https://github.com/micropython/micropython/issues/2986 suggests it might be possible to omit the Mosi pin from the SPI declaration for devices with no actual MISO, but this is apparently not possible even in micropython 1.9 ( esp8266-20170526-v1.9.bin ). If I fail to set miso in the SPI function, I get...

Code: Select all

>>> from machine import SPI
>>> from machine import Pin
>>> screenMosi = Pin(5)
>>> screenSck = Pin(4)
>>> screenSpi = SPI(-1, baudrate=1800000, polarity=0, phase=0, mosi=screenMosi, sck=screenSck)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: must specify all of sck/mosi/miso
Using the only free pin - GPIO16 - for the unnecessary MISO for the screen has left my project with no pins at all, since ideally each device needs MISO, MOSI, SCK, SLAVE and RESET, a total of 10 pins. I've already hard-wired the screen's reset pin straight to 5V to get things working within the 9 pins available (labelled D0-D8 on a NodeMCU). However, I really need at least one more pin free so the device can power itself down through a power control module.

Is there any official way to set up a Software SPI without allocating MISO?

WORKAROUNDS FOR THE ISSUE?

Are there any other pins on a NodeMCUv2 that I can 'attach' to the Screen SPI MISO, especially given it doesn't even need to be broken out or wired to anything.

I have proven using GPIO1 or GPIO3 for MISO but using either of these kills my serial connection, so makes debugging very hard.

Are some of the flash pins free, if the NodeMCU uses dual IO for flash control, perhaps one of GPIO6-11 can be assigned to MISO without future impact.

Equally, since the screen and reader are both used at different times, the code is single threaded and 'guarded' by slaveselect, perhaps I can reuse some pins already in use for the Hardware SPI within the SoftwareSPI, wiring some subset of the SPI pins in parallel, but not so many that there is crosstalk (e.g. avoid sharing SCK so no clocking happens in the idle SPI). However, so far any attempt to share MISO,MOSI,SCK between software SPI and hardware SPI has been a failure. Perhaps it only works with certain pins. I've tried some different configurations, but so far all my experiments with sharing pins between Software and Hardware SPI have caused the reader's Hardware SPI to be non-responsive. Given the number of combinations I probably haven't tried all, but maybe someone can suggest likely-compatible configurations.

Welcome thoughts for other workaround pin specifications I can use to keep the SPI declaration happy, without actually sacrificing GPIO16 for no reason.

User avatar
pythoncoder
Posts: 5956
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: Avoiding allocating MISO Pin in Software SPI

Post by pythoncoder » Sat Jun 10, 2017 5:43 am

You've probably tried this already but is it possible to re-purpose the pin, perhaps as an output, after using it in the software SPI instantiation?

If you find no solution to this it might be worth raising as a GitHub issue. It would be a worthwhile enhancement to the software SPI to allow unidirectional implementations.
Peter Hinch
Index to my micropython libraries.

cefn
Posts: 230
Joined: Tue Aug 09, 2016 10:58 am

Re: Avoiding allocating MISO Pin in Software SPI

Post by cefn » Sat Jun 10, 2017 10:08 am

Thanks, Peter.

My concern has been that if I do repurpose the pin, there's still no way to prevent the Software SPI object from still treating it as MISO. Perhaps there's no cost from the SoftwareSPI still retaining the reference in the case that it's trying to read ignored data from it, and not to write to it.

With a bit of luck, changing the pin mode with another init() will reliably prevent problem behaviours. I will try this if I need to get that pin back.

However, as a workaround, I have adopted the (in retrospect rather obvious) intervention. Now that the pins for hardware and software SPI have no intersection at all, then the slaveSelect pins should be able to be hard-wired.

So I have now retired both device reset pins (hard-wired), and retired the screen slaveSelect pin too (trying to operate the MFRC522 reader without slaveSelect caused it not to initialise properly, so I had no choice but to keep that one). It means we have to sacrifice some robustness (e.g. we can't rely on a software-triggered device reset for any issues) but that's livable.

I'll look into raising the issue on github after preparing the final images for this deployment.

User avatar
Roberthh
Posts: 3667
Joined: Sat May 09, 2015 4:13 pm
Location: Rhineland, Europe

Re: Avoiding allocating MISO Pin in Software SPI

Post by Roberthh » Sat Jun 10, 2017 11:16 am

I did not follow fully how you assigned the Pins but in a similar situation I used some workaround when low at input pins:
Like you. I had attached screen to the device which does not need MISO. Since MISO is configured by SPI as an input pin, I can still read the value at that Pin with pin.value(). So for a simple polled input that works. You can also use the analog input as an polled input pin.
GPIO0 may be used a an output, if not pulled low at boot time. It may also be assigned as MISO, if left open
GPIO2 may be used as an output, if not pulled low at boot time. It may also be assigned as MISO, if left open. . Or you use it for reset of the screen.

cefn
Posts: 230
Joined: Tue Aug 09, 2016 10:58 am

Re: Avoiding allocating MISO Pin in Software SPI

Post by cefn » Sun Jun 11, 2017 7:21 am

What are the consequences of simply violating the assumptions of the SPI 'contract' and repurposing a MISO pin as an output after initialising SPI (which must establish on initialisation, but maybe doesn't enforce later, that it's an input)? Is there a difference in the consequences between hardware vs. software SPI?

I was surprised to find that Software SPI couldn't work on the same pins as the Hardware SPI leading to a silent failure, given that they must be configured as inputs/outputs respectively. From my attempts it seemed the Hardware SPI stopped functioning when I used the Software SPI on the same pins, even though Send/Receive and SlaveSelect was used in a strictly interleaved manner between them - and never invoked "simultaneously". Can I temporarily un-init an SPI to prevent it e.g. continuing to pull down a pin when the other SPI wants to pull it up? (though perhaps the failure mode is different than this).

Thanks for suggestions, Robert. When you say 'if left open', I guess you mean open-circuit and unwired to anything, presumably because of the active-low detection on boot on GPIO0 and GPIO2.

Post Reply