duff2013 / Snooze

Teensy Low Power Library
MIT License
132 stars 37 forks source link

T4.x SPI and Hibernate #85

Closed KurtE closed 2 years ago

KurtE commented 4 years ago

@duff2013 - Sorry this is out of my knowledge base here, There is a thread up on the forum: https://forum.pjrc.com/threads/61433-T4-SPI-port-register-how-to-reset-it

Where a member(rezo) reported issues using SPI after doing a hibernate. So since I have done a reasonable amount of work on the SPI support for T4, I thought I would take a look.

But I have not found anything obvious. And my only normal way for low power mode is to unplug ;) So I know there is probably some subtle setting I am missing somewhere.

What I found is that everything appears to setup properly, but nothing gets out of the TX FIFO queue, including writes to the TCR (Transmit Control Register). And then when his test sketch then calls SPI.transfer(...) it hangs waiting for a response back...

I have hacked up his sketch plus added debug outputs in SPI. Also have an out standing PR for SPI.end() to turn off SPI....

But again more of the details are up on the mentioned thread.

I Thought Rezo had opened an issue on this, but don't see it. If so sorry...

duff2013 commented 4 years ago

Hi Kurt, I'm looking into this, there is something funky going on with SPI library and Snooze not sure whats going on.

duff2013 commented 4 years ago

Do you know where port() is defined as used in SPI.h beginTransaction function? The code I'm looking at is below.

port().CR = 0;
port().CFGR1 = LPSPI_CFGR1_MASTER | LPSPI_CFGR1_SAMPLE;
port().CCR = _ccr;
port().TCR = settings.tcr;
port().CR = LPSPI_CR_MEN;
KurtE commented 4 years ago

The port() stuff was defined earlier by Paul, that simply casts some data that we passed into the constructor of the SPIClass, which is a pointer to the hardware SPI port associated with that SPI object.

We pass it in as a uintptr_t value instead of the actual hardware pointer as this allows the constructor to work when it was defined as constexpr and as such there is no actual constructor code called, but it is simply in memory with the right settings...

For T4 in my SPI files it is at line 1121 for the T4.x

The actual define for port() is at line 1348, which returns a reference value... We do similar stuff for the hardware data we pass in with another structure.

    IMXRT_LPSPI_t & port() { return *(IMXRT_LPSPI_t *)port_addr; }
    const SPI_Hardware_t & hardware() { return *(const SPI_Hardware_t *)hardware_addr; }

The actual SPI object is defined in the SPI.cpp at line 1552... Where you can see we cast to uintptr_t

SPIClass SPI((uintptr_t)&IMXRT_LPSPI4_S, (uintptr_t)&SPIClass::spiclass_lpspi4_hardware);

Hope that makes sense

duff2013 commented 4 years ago

Yes that helps I think I got it working at least with my setup, need to work on how I want to implement it in Snooze and test more. I'll release something soon, basically you need to disable the SPI interface before sleeping and clear the IOMUXC's in the startup early hook function Teensyduino provides after reset wakeup. There could be more issues with non-standard SPI setups but the ILI9341_t3 library that ships with Teensyduino examples work so far.

david-res commented 4 years ago

Thanks for sorting this out Duff! Happy to test when you're ready to release.

KurtE commented 4 years ago

Yes that helps I think I got it working at least with my setup, need to work on how I want to implement it in Snooze and test more. I'll release something soon, basically you need to disable the SPI interface before sleeping and clear the IOMUXC's in the startup early hook function Teensyduino provides after reset wakeup. There could be more issues with non-standard SPI setups but the ILI9341_t3 library that ships with Teensyduino examples work so far.

Sounds good. Which IOMUXC values did you need to clear out? In the upcoming release of Teensyduino, the SPI.end() function disables SPI and sets the Three pins to INPUT_DISABLE. Which did not help on the wakeup side as mentioned on the thread with the test case.

duff2013 commented 4 years ago

IOMUXC_GPR_GPR4 IOMUXC_GPR_GPR7 IOMUXC_GPR_GPR8 IOMUXC_GPR_GPR12 For some reason if I didn't zero those IOMUXC_GPRx registers out the SPI fifo would not behave right,port().RDR register would alway read zero when transmitting.

Disabling the SPI pins would be to lower the current draw and should not matter with with Snooze's operation as far as I can tell. On a side note, from my testing what really lowers the current is not disabling the SCK pin but making it an INPUT. The rest of the pins you can disable. Something about making the SCK pin HIGH Z state makes it draw excess current.

david-res commented 4 years ago

IOMUXC_GPR_GPR4 IOMUXC_GPR_GPR7 IOMUXC_GPR_GPR8 IOMUXC_GPR_GPR12 For some reason if I didn't zero those IOMUXC_GPRx registers out the SPI fifo would not behave right,port().RDR register would alway read zero when transmitting.

Disabling the SPI pins would be to lower the current draw and should not matter with with Snooze's operation as far as I can tell. On a side note, from my testing what really lowers the current is not disabling the SCK pin but making it an INPUT. The rest of the pins you can disable. Something about making the SCK pin HIGH Z state makes it draw excess current.

Are the same registers used on the T4.1? Or would we require more modifications to get that to work too?

duff2013 commented 4 years ago

@david-res Not sure, haven't looked at the T4.1 yet, but since it's the same silicon I'm assuming yes.

david-res commented 4 years ago

@duff2013 have you been able to make any progress on this? Does it require the SPI library to be modified as well?

duff2013 commented 4 years ago

Yep, got side tracked in finally designing a low power test jig pcb so I don't have to re-setup a breadboard with all the wakeup modules every time I work on Snooze :)

The update you are looking for will be in the SPI branch that I will merge with the master branch once I feel the SPI issues are addressed. So check that branch for the next update which should have a fix for this specific problem.

david-res commented 4 years ago

Thanks, I added myself as a watcher on that branch. Looking forward to the release :)

david-res commented 4 years ago

@duff2013 any update on this? Sorry to be bugging you about this. Thx

duff2013 commented 4 years ago

Ya I need to get this done, been dealing with covid things for the last month, (I don't have it) but someone close does so I have not done anything for awhile now. If I get some time I'll try to update Snooze with what I have so far but I really have not tested it at all so can't guarantee I works but hopefully it helps.

david-res commented 4 years ago

Health before anything - I hope your loved ones make a quick&full recovery!

Looking forward to testing the next release, I hope it plays well with the QSPI PSRAM on the T4.1 as well :)

david-res commented 3 years ago

@duff2013 @KurtE

For what it's worth - I finally came back to this after months and months. In order to get Snooze to play well with SPI, from my testing, one should call

SPI.endTransaction();
SPI.end();
....
Snooze.hibernate(config);

Before calling the sleep/deepsleep/hibrnate Snooze function, otherwise it goes into an infinite sleep-wake up loop or just sleeps without being woken up at all.