-
Notifications
You must be signed in to change notification settings - Fork 25
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
Still Struggling #70
Comments
For 99% of things you don't need any setup in the main program, because the ULP can also do that. Most of the The main thing you would want to do is to set the GPIO pin into RTC mode (so it can be read from the ULP) and to set it into input mode. The
With regards to "variable passing", you can hard code the GPIO pin number, debounce info, etc into the ULP assembler code. In the example you referenced, they simply reference memory locations from C that are in the RTC memory as set up by the assembler code (e.g. |
I had a red hot go at counting lows on gpio4
but the counter isn't incrementing with the gpio4 pin connected to gnd, just stuck on 0x1000 all I've got to show for my day with ulp assembler is my brain hurts. Also how did you know that gpio4 is RTC_IO_TOUCH_PAD0_REG ? |
Had another go at incrementing a counter each time I find a lo on gpio4(rtc ch10)
Still not incrementing sadly |
Why does it always have to be a feast or a famine in this life?
Got it counting again by knobbling line22 (line 22 inhibits any counting whatsoever). Unfortunately it counts continuously without reference to the state of gpio4(channel10) |
Today I gave up on counting & tried my luck reading the staus of gpio4
No joy, I can toggle gpio4 input hi/lo as much as I like, the register is always 4096. If it was easy everyone would be doing it, right? |
Trial & error, story of my programming life.
Still not seeing the gpio4 input level in data |
It looks like you have been inching closer and closer with each attempt. Great persistence there! What I think was missing in your earlier attempts was this line:
This connects the GPIO to the RTC subsystem and is needed for the ULP to read the GPIO. Your latest code has this line now, so now it should work! ButBut... your code is likely crashing the ULP. To explain, If we remove all "non-code" lines (such as
The ULP runs instructions sequentially, but line 3 is not an instruction, and should crash the ULP. Also So, you need to move all instructions after the variable and ensure the Easier GPIO readingI see you can simplify reading the GPIO value. I notice you are reading 16 bits with this instruction:
and then doing bit operations afterwards the get one bit that you want. But the READ_RTC_REG function takes a "starting bit" and a "number-of-bits-to-read" as arg 2 and 3 respectively, so you can read just 1 bit like this:
That will get you exactly GPIO4's value into r0. Putting it togetherSo putting that all together, I think this should work:
|
Could you try
on your esp32 please? Mine is showing
regardless of the voltage present on the gpio4 input. |
It works correctly (as expected) on my ESP32. When I have GPIO4 connected to VCC (3V3) I see I wonder if there might be something wrong with your GPIO pin? Perhaps try read GPIO4 from MicroPython normally to test that the input works as expected:
This should print lines with 0 or 1 depending on the current state of GPIO4. |
Yeah I did that already Wilko, that's why I was keen to see your results. On my ESP32 the python works but the ULP always reports 0. What a bugger! |
I've discovered that the ulp will read gpio4 correctly if cause!=wakeup but not otherwise. Also if I remove the deepsleep (so that the cause is always hardreset) then the ulp reports gpio4 correctly on the first cycle then 4096 subsequently. I'm sure the universe is shouting at me but I'm not getting the message. Do these results give you any clues as to what's going on? |
The 4096 will be the 0x1000 you are setting just before Or that something overwrote the data variable with 0x1000 again, but in your last code the setting of 0x1000 always happens before the So I wonder if this is a timing issue. Maybe the main processor manages to read the memory already before the ULP started properly and ran its code. What if you add a sleep of a few milliseconds (>50ms to be sure) after the This is only a guess and I'm not very sure of it because a by the time the first deepsleep ends the ULP must have definitely started, but might be worth trying anyway. |
Btw when you say
what is a cycle? Do you let it start (which assembles and loads the ULP code) and see the output of the print statements and then you manually press reset each time to start the next cycle? If so, I fid it very surprising that you get the correct GPIO value on the first cycle and not afterwards. Because all hard resets should be the same. Or is the first cycle actually a power up? It would also surprise me that the power up and hard reset behave differently in this case - but something must be different between your first cycle and subsequent ones. Or did you add some kind of loop around part of the code and cycles refer to the iterations of the loop? |
The delay didn't help, I didn't think it would since it's in the code that runs when cause!=wakeup & the failure to update the gpio4 input value is when the cause==wakeup. Rather than download the code into the esp32 after each change I just run it from the repl, so a cycle is each time I run it again. I've checked & the behaviour is the same as if I'd downloaded & let it run repeatedly. The only difference is a download runs automatically but with the repl the next cycle occurs when I get a new idea to try out & click 'run' again. My first cycle is always after a powerup (which is reported as a hardreset). I've been removing/reapplying power because pressing the reset button causes the board to behave the same as pressing the boot button (ie it goes into flashing mode). Which upython are you running & on what board? I'm running release='1.17.0' on a devkit1 (110k ram, 2m flash). Maybe if I try the same upython version & board as you I can get your results? |
I am also using MicroPython 1.17.0. I am using a Lolin32 clone with the following specs (as per
But I have previously run this type of code (read GPIO from ULP during deepsleep) on 2 other of my ESP32's (this one and this one), without any problems. All of them use the "original ESP32", not the newer (and different) ESP32 s2, s3, c3, etc models (note that our assembler does not support the S and C models - the ULP machine code is different). So if you are using a "normal" ESP32 (perhaps you can also run |
Despair creeping up on me now squire. Ran
|
Just a quick random idea: can you try add a |
Hallelujah! load_addr, entry_addr = 0, 4 causes={2:'reset', 1:'hardreset', 3:'wdt', 4:'wakeup', 5:'pwrup'}; cause=causes[reset_cause()]; print(), print('pwrup cause', cause) data: .long 0 binary = src_to_binary(source) print('gpio4', mem32[ULP_MEM_BASE+load_addr] & ULP_DATA_MASK) Hey, quick question for ya. I've been wondering about this for ages. Why does the gpio have so many different names? When we're setting up we refer to it by it's touch alias then later we read it by referencing it's channel alias. Just wondering why so many AKAs? |
Great! Well done. That Regarding the naming of GPIOs - I don't know why they have so many different names. The GPIO numbers vs RTC channels somewhat makes sense because the RTC subsystem has it's own set of "channels" to which the real GPIOs are routed - it would have been quite convenient if the GPIO and channel numbers had been the same, but I guess convenience is not an embedded device designer's first priority (especially for a device that's designed to be super cheap). Regarding the TOUCH naming, I admit being somewhat frustrated by that at times, because there is no logic in the mapping, e.g. GPIO4 maps to PAD0 but GPIO2 maps to PAD2, while GPIO0 maps to PAD1. I assume they designated some GPIOs to have touch capability and then named those sequentially relative to something (maybe some location in the IC design? where touch capable GPIOs are located near each other? ... pure speculation of course). The best place I found to rely on is the mapping table at the bottom of this file: https://github.com/espressif/esp-idf/blob/4bf67afd0a5a4183f225e0678a38296cbd194291/components/soc/esp32/rtc_io_periph.c - the "real" GPIO numbers for each line are on the far right of each line as comments. The ESP32 Technical Reference manual also has a good table (table 19 under section 4.11) but I find the code file to be faster/easier to open than the PDF. |
I just added an example for reading a GPIO to the repo: #73 - so there's an easier way to get started for others down the line. Could I ask you to please test it on your ESP32(s)? Just upload the file, run |
I haven't been able to figure out how to download code from github, I find the platform beginner unfriendly. I normally copy & paste. Sadly, copy & paste doesn't work with code that has + signs at the front of each line like a1241c9 does. Could you explain how to download to save me typing it in manually? Also I have some more questions.
|
Let me start by answering the first question, I'll answer the "some more questions" a bit later. To download the PR page #73, then choose the "Files changes" tab at the top, and then for the "readgpio.py" file, choose the "the dots icon" in the top right of the "header" of that file. That opens a menu from which you can choose "View file" and then you have the file itself (not the patch). That should work for copying, but if you want you can also then click the "Raw" button in the "header" for that file, to get the raw text. |
Answering the other 4 questions:
|
The #73 demo program works great, displays 0x0 (gpio4 not connected to anything) or 0x1(gpio4 bridged to 3v3). Re your answer to my Q1 about connecting a gpio to digital or analog rtc and that 1,1 means digital. https://github.com/micropython/micropython-esp32-ulp/blob/master/examples/blink.py#L63 says (0: GPIO connected to digital GPIO module, 1: GPIO connected to analog RTC module) but the ref you gave says description: Ò1Ó select the digital function Ó0Óslection the rtc function. Aren't we trying to conect it to the rtc domain for it to be accessible to the ulp? You mention in #73 you have a TBRG counter for ULP already? That's exactly what I'm working towards. Any chance a glimpse of your code? |
Thank you for testing #73! About Q1 earlier - I believe I answered wrong. The 1 that we're setting with MUX_SEL is actually connecting the GPIO to the RTC module (which seems to often be referred to as "analog RTC module"). Digital does mean the "normal GPIO". Internally it basically means whether the pin is connected to the IO_MUX or the RTC_MUX. The confusing thing is that the place I referenced is actually wrong. the 0 and 1 are the wrong way around. 0 is digital and 1 is RTC I confirmed this two two ways: a) Using example code in the ESP-IDF (here) then looking at what the b) Looking at the ESP32 Technical Reference Manual and looking at the example on page 80, where the register for configuring the ADC pads if explained, and RTCIO_ADC_ADCn_MUX_SEL takes 0 for "route to IO_MUX" and 1 for "route to RTC block". Compare that with the description of the same in the setting here, to see that the two places dont agree. Searching that rtc_io_reg.h file for all other references of So the Reference Manual and the "real" code agree, while the comments in the code file(s) disagree. 2 against 1 :) -- |
Nice edge counter Wilko. Curious about the add r0, r0, 0 instruction after you read the gpio state into r0, I can't work out how it changes anything? |
I think you are right - it doesnt do anything. It would be a leftover code from earlier iterations of the code - before using a reed switch via the GPIO, I actually used the ESP32's built-in hall effect sensor ... but it was just too unstable - it was heavily influenced by Wifi transmitting. And because the hall sensor returns a range of values, there was a lot more code to test whether we're in the desired range, oversampling and smoothing the signal over time, etc. And this "no-op" So it's essentially a test for whether |
Can we consider this issue closed now? |
One last question. Given Count is 16 bit (presumably signed) does that mean it will roll over at 32768 edges? |
Yes. Adding to the counter will be the same whether you treat the number as signed or unsigned, and it will be up to your program reading the value to interpret it as signed or unsigned. Since you most likely only count upwards, interpreting it as unsigned will mean you get possible values from 0-32767 (0x0 - 0xffff) and after that it will roll over to 0x0 again. If you wanted to represent a larger range, I guess you could use one more variable and increment that every time the ADD resulted in an overflow (which the JUMP instruction can test for). |
To my delight the counter still works from a .mpy file so I'm a very happy camper. Thnx for all the hand holding, good to close. |
Glad to have helped. Thanks for your questions and challenging my answers where they didn't make sense. Also as a result of this issue we now have one more example in the repo. Thanks for testing it. |
I ran the TBRG counter on gpio35 where I get the count first thing before I connect the wifi. I don't know what wifi uses ADC2 for but whatever it is it doesn't stop gpio35 from continuing to count edges through the rest of the program & the subsequent deepsleep.. |
From what I can see GPIO35 connects to ADC1 not ADC2. Also I assume, when you read it as a digital pin, the ADC is not actually triggered. Also, for reading the ADC from ULP code there is a dedicated |
I got confused by it's input enable name (RTC_IO_ADC2_FUN_IE_M), but you're right gpio35 belongs to ADC1 group. So the wifi ADC2 conflict is only an issue if I'm trying to use an ADC2 pin as an analog input? |
I have never tried to use ADC2 together with Wifi. Looking at the Technical Ref Manual page 623 (Figure 146), I have a hunch it is used for "power and peak detection" (see also the text and diagram before Figure 146) as part of the Wifi implementation. The description above Figure 145 shows that there are different ADC controllers, and since the Power/Peak detection controller is separate from the others, I assume the ADC2 is only ever connected to one of the controllers, and thus: if used for Wifi, the others get no reading. It's all guessing on my part though. |
Welcome to my world. |
The https://github.com/micropython/micropython-esp32-ulp/blob/master/examples/counter.py I think shows how to get the count from the ulp into the .py program. However to setup a ULP counter that counts pulses from a gpio pin (eg the ulp assembler code at https://esp32.com/viewtopic.php?t=12454 it looks like the .py program has to send some values (like gpio pin number & debounce info) to the ULP? Could we maybe have another example for us novices on how to do that?
The text was updated successfully, but these errors were encountered: