Welcome to the Pycom forum Forum
    • \[\[global:header.categories\]\]
    • \[\[global:header.recent\]\]
    • \[\[global:header.tags\]\]
    • \[\[global:header.popular\]\]
    • Login

    Explore Pybytes | Official Documentation | Report a Firmware Bug/Issue | GitHub

    What do I misunderstand about rgbled()?

    Scheduled Pinned Locked Moved Discussion
    26 Posts 5 Posters 160 Views 5 Watching
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • P Offline
      Paul Holthuizen
      last edited by

      I'm new to Python and new to Pycom (lopy4) so this might turn out to be a silly question, but if I run this code fragment (LoRa init taken care of in boot.py and working)

      red=0x330000
      green=0x003300
      blue=0x000033
      
      senddata = 0xaa
      switch = Pin('P10', mode = Pin.IN)
      
      while True:  
          if(switch() == 0):
              rgbled(red+green+blue)  # white    
              #print("Button pressed")
              retdata=loraSendReceive(senddata)
              print("Data transmitted: ", senddata)
              if(len(retdata) != 0):
                  print("Data received: ", retdata)
              time.sleep(1)
          #print("Button not pressed")
          rgbled(green)  # Green
      

      I would expect the rgb led to turn green immediately and white for as long as it takes to send a byte plus the 1 sec sleep as soon as the button is pressed. That does not happen. The led turns green and stays green after the first button press. Messages are sent and received via LoRaWan.

      If I uncomment the 'button' print statements those are working as expected. It makes a mess for printing a lot of messages but at least the program shows it is going where it is expected to go. The led stays green.

      What am I missing in turning on the rgb led?

      T 1 Reply Last reply Reply Quote 0
      • T Offline
        tuftec @Paul Holthuizen
        last edited by

        @Paul-Holthuizen you may need to disable the pycom hearbeat function first.

        1 Reply Last reply Reply Quote 2
        • G Offline
          Gijs
          last edited by

          Indeed, using

          import pycom
          pycom.heartbeat(False) #use this everytime
          # or
          pycom.heartbeat_on_boot(False) #always disable the heartbeat
          

          You will disable the heartbeat functionality and be able to control the rgb led yourself

          P 1 Reply Last reply Reply Quote 0
          • P Offline
            Paul Holthuizen @Gijs
            last edited by

            @Gijs

            I tried both suggestions (temporary and permanent disable) and both do not seem to work; Still the LED turns only green after pressing the button.

            To make sure that the heartbeat led was indeed disabled during runtime I printed its status with

            print("Heartbeat: ", pycom.heartbeat())
            

            and that output looks good: Heartbeat: False.

            Where can I find what code runs if the rgbled() statement is executed?
            Coming from Microchip and C I would like to see what machine code is generated from the statements I enter, to prevent me from flying totally blind when stuff like this happens. And also to prevent me bugging people on this forum.

            1 Reply Last reply Reply Quote 0
            • G Offline
              Gijs
              last edited by

              Right, so the heartbeat setting is correct then, as you are able to change the LED color, so it seems there is an error in your code.
              In the firmware source, in modpycom.c, we have the rgbled function: https://github.com/pycom/pycom-micropython-sigfox/blob/Dev/esp32/mods/modpycom.c#L159

              I believe your function rgbled(red+green+blue) should work and am a bit puzzled here as well..

              P 1 Reply Last reply Reply Quote 0
              • P Offline
                Paul Holthuizen @Gijs
                last edited by

                @Gijs

                The problem has probably something to do with my understanding of the if statement

                If I run :

                while(True):  
                    if(switch() == 0):
                        rgbled(white)
                        retdata=loraSendReceive(senddata)
                        print("Data verzonden: ", senddata)
                        if(len(retdata) != 0):
                            print("Data ontvangen: ", retdata)
                        rgbled(green)
                

                the led comes on white when I press the switch. A couple of seconds later the "Data verzonden" message is printed and the led goes green. As excpected.

                However, if I run:

                while(True):  
                    if(switch() == 0):
                        rgbled(white)
                        retdata=loraSendReceive(senddata)
                        print("Data verzonden: ", senddata)
                        if(len(retdata) != 0):
                            print("Data ontvangen: ", retdata)
                    rgbled(green)
                

                the led comes on green. When I press the switch the led stays green, but the "Data verzonden" message is printed.

                The only thing I can imagine is that running "rgbled(green)" many times (as happens whenever the switch is not activated) breaks something. Maybe the calls to rgbled() are buffered?

                There are many ways I can solve this but I would like to understand why I am not allowed to do it like this.

                J 1 Reply Last reply Reply Quote 0
                • J Offline
                  jcaron @Paul Holthuizen
                  last edited by

                  @Paul-Holthuizen in this case (which is different from your original code which had a sleep), if your socket is set to non-blocking then when you press the button, it will set to white, send data, then immediately set to green so you won’t see the white at all.

                  But in the original case with the sleep it should have stayed white at least for the duration of the sleep.

                  If your socket is set to blocking then things will depend on the data rate and amount of data. In the best cases it could take only a few ms or tens of ms so you won’t see a thing. In the worst cases it could take seconds.

                  P 1 Reply Last reply Reply Quote 1
                  • P Offline
                    Paul Holthuizen @jcaron
                    last edited by Paul Holthuizen

                    @jcaron said in What do I misunderstand about rgbled()?:

                    .

                    The socket is set to blocking right before sending off the data and reset to non-blocking right after.

                    Data sent is only one byte; this takes ~50ms airtime but a lot longer in the Pycom code; measuring it with Timer I found it takes 2135 ms to execute the retdata=loraSendReceive(senddata) statement.

                    What I do not understand is that my first snippet

                    while(True):  
                        if(switch() == 0):
                            rgbled(white)
                            retdata=loraSendReceive(senddata)
                            print("Data verzonden: ", senddata)
                            if(len(retdata) != 0):
                                print("Data ontvangen: ", retdata)
                            rgbled(green)
                    

                    works as expected, while the second

                    while(True):  
                        if(switch() == 0):
                            rgbled(white)
                            retdata=loraSendReceive(senddata)
                            print("Data verzonden: ", senddata)
                            if(len(retdata) != 0):
                                print("Data ontvangen: ", retdata)
                        rgbled(green)
                    

                    does not.

                    In both snippets the program should show a white led while waiting for the data being sent off. But in the second snippet it looks like the if(switch() == 0): statement continues before the program returns from sending the data.

                    Either something in Pycom is broken or I completely miss the way IF statements are handled in Python / Pycom :-)

                    J 1 Reply Last reply Reply Quote 0
                    • J Offline
                      jcaron @Paul Holthuizen
                      last edited by

                      @Paul-Holthuizen that is indeed weird. I wondered if maybe you had an issue mixing spaces and tabs which could have caused the indentation to not be what you thought, but I don’t think you could get that result in that case anyway (you should probably still double-check, just in case).

                      Do you use any threads? Are there any callbacks/triggers?

                      Can you try using two other colours there just to be sure it isn’t something else changing the LED colour?

                      P 1 Reply Last reply Reply Quote 0
                      • P Offline
                        Paul Holthuizen @jcaron
                        last edited by Paul Holthuizen

                        @jcaron

                        No threads, callbacks or triggers, at least not that I am aware of. And I changed the led colors as part of the debugging, no changes.

                        There is one thing that strikes me as odd. If I upload the code as per sample 1 (the working one) everything works fine. I press the button, the led lights white, the message gets sent, the led lights green again.

                        Now, if I remove the USB cable and attach a LiPo battery the Lopy 4 reboots, the led lights white once, then goes and stays green. All the while messages are sent every couple of seconds, as if the switch is held in (which it is not).

                        Remove the battery, reconnect the USB, and after the boot (without me uploading anything) everything works as expected again. This is reproducibly.

                        I am starting to wonder if I might have a defective device. Or if the firmware upgrade I did upon receiving the lopy went south somehow. There were a couple of choices that did not make much sense at the time, e.g. the 'type' parameter (which I set to 'development')

                        I will re-program the fw and see if that somehowmakes a difference.

                        robert-hhR 3 Replies Last reply Reply Quote 0
                        • robert-hhR Offline
                          robert-hh @Paul Holthuizen
                          last edited by robert-hh

                          @Paul-Holthuizen I woudl not expect the MicroPython core to be have wrong. It has been thoroughly tested. I never ran into an error at that program logic level.
                          Two seconds it the time LoRaWAN waits for a downlink packet from the host. So it could be that sometimes the send in loraSendReceive() blocks for the 2 + x seconds, and sometimes it returns immediately. That may be related to timing differences between the MicroPython task and the LoRa task.
                          If you have a logic analyzer, you could set and clear a GPIO pin immediately before and after the loraSendReceive() call. You could also connect a LED to it. A simple LED may work better than the RGB led, which requires a complex message. I do not know if this message is sent immediately or e.g. upon the next tick of a timer

                          1 Reply Last reply Reply Quote 0
                          • robert-hhR Offline
                            robert-hh @Paul Holthuizen
                            last edited by

                            @Paul-Holthuizen I wrote a little program to test wioth the RGB led, how short can pulses be made such that they can still be seen.

                            • If it is just a on/off pulse, it can go down to 100µs and may less
                            • if it is a switch between green and short white, it requires about 20 ms and more to be clearly noticeable.

                            BUT. There is an interesting phenomenon. If the time between two RGB Led calls is very short, like 20µ or less, the LED may stick in one state and requires a long on/of cycle to recover.
                            Test code below. I borrowed the color names & values from your code.

                            import pycom
                            pycom.heartbeat(False)
                            import time
                            red=0x330000
                            green=0x003300
                            blue=0x000033
                            white = red + green + blue
                            black = 0
                            
                            pycom.rgbled(black)
                            
                            while True:
                                q = input("Time")
                                if q == "q": break
                                t = int(q)
                                pycom.rgbled(white)
                                time.sleep_us(t)
                                pycom.rgbled(black)
                            
                            P 1 Reply Last reply Reply Quote 1
                            • P Offline
                              Paul Holthuizen @robert-hh
                              last edited by

                              @robert-hh

                              Interesting, and thanks for thinking along on this!

                              However, in my case the time between setting the led white and then setting it back to green again is always at least 2135 ms or the time it takes loraSendReceive() to finish. This time is timed using Timer.chrono().

                              So I do not think I simply color switch the led too fast to be seen or to be executed by rgbled() unless something weird happens (like subsequent code executing before loraSendReceive() is finished.

                              Furthermore it is weird that the place of rgbled(green) seems to have an impact; when placed under if(len(retdata) != 0): it functions, and when placed under if(switch() == 0): it does not. Not even when I insert a time.sleep(1) right before it to prevent rgbled(green) from being called too often. In the latter case I have to hold the switch for at least a second, after which it does send the message, but still refuses to set the led to white.

                              1 Reply Last reply Reply Quote 0
                              • robert-hhR Offline
                                robert-hh @Paul Holthuizen
                                last edited by

                                @Paul-Holthuizen Another question: do you debounce the switch reading in the function switch(). And is there a code path by which the function loraSendReceive() return very fast?

                                P 1 Reply Last reply Reply Quote 0
                                • P Offline
                                  Paul Holthuizen @robert-hh
                                  last edited by Paul Holthuizen

                                  @robert-hh

                                  No, I do not debounce the switch at all. For the loraSendReceive() takes always the same 2135 ms to finish which is a debounce in itself.
                                  I also see only one print statement on the console after pressing the switch, and only one message gets sent out.

                                  robert-hhR 1 Reply Last reply Reply Quote 0
                                  • robert-hhR Offline
                                    robert-hh @Paul Holthuizen
                                    last edited by robert-hh

                                    @Paul-Holthuizen I have an possible reason. In this version of the code:

                                    while(True):  
                                        if(switch() == 0):
                                            rgbled(white)
                                            retdata=loraSendReceive(senddata)
                                            print("Data verzonden: ", senddata)
                                            if(len(retdata) != 0):
                                                print("Data ontvangen: ", retdata)
                                        rgbled(green)
                                    

                                    You are sending rgbled(green) very fast, when the button is NOT pressed. That may lock up the RGB, such that other calls to rgbled(white) are ignore. You could try to insert a small delay, like 1 ms, into the while(True) loop, just to give rgbled(green) time to complete.
                                    Note: The signal pattern for the RGB led is created by the RMT unit. You load it once with a bit pattern, and then the transmission is done while the calling code can already return. So it's asynchronous to the code, which makes this kind interference possible.

                                    1 Reply Last reply Reply Quote 1
                                    • T Offline
                                      tuftec
                                      last edited by

                                      I have been following this thread as it could explain some issues I have been chasing in other areas. If the rgb led is in fact controlled by the underlying RTOS then that would explain a lot. You can not just simply look at your python code and work out what is happening. Calls to the led function could get queued or dropped without you knowing. I have observed strange timing behaviour when dealing with the LTE component on the FiPy which is handled by a totally seperate processor/modem. Am I correct in reading somewhere that some of the pycom modules (like LoRa) run on the second core, which call also introducing timing issues, particularly when not blocking.
                                      Peter.

                                      robert-hhR 1 Reply Last reply Reply Quote 0
                                      • robert-hhR Offline
                                        robert-hh @tuftec
                                        last edited by robert-hh

                                        @tuftec The calls to the led function are pretty simple. The function mod_pycom_rgb_led() in modpycom.c calls
                                        bool led_set_color() in modled.c, which then calls rmt_write_items() to transfer the data bit pattern to the RGB led, AFTER waiting that the previous transmission has finished. Maybe the wait time is too short. The WS2812 requires reset time of 50µs between two transmissions. I see no wait period for that in the code, but in the actual timing on P2 I see that delay.
                                        But it still only works with my test code, if I increase the delay to 200µs.

                                        Edit: Making a few trials it turns out, that up to a time gap of about 125µs between two commands to the RGB led, the second command is ignored. From about 150µs on, the second command will be executed. I do not know which RGB led is on the board. The OEM baseboard schematics show the WS2812B which is specified for 3.5V min, and I replaced once successfully a defective RGB led with a WS2812B. So it might work to some extend. But the mandatory reset time may be longer than 50 µs in that case.

                                        P 1 Reply Last reply Reply Quote 0
                                        • P Offline
                                          Paul Holthuizen @robert-hh
                                          last edited by

                                          @robert-hh

                                          This seems a reasonable explanation. And it gives me an idea of how to handle this particular problem. However, it also gives me something to think about. How do I know what functions are executed asynchronously?

                                          This is by no means meant to be disapproving but how am I going to use inputs and outputs if I do not know beforehand how these are being handled by Pycom? Are these handled by an (interrupt driven) RTOS or not? If so, is there a description of the RTOS that handles all of this?

                                          I am really impressed with the ability to make a solid network connection with only a couple of lines of code, but I still struggle with the connect-to-hardware side of things with the Lopy device. No doubt a learning curve.

                                          robert-hhR 1 Reply Last reply Reply Quote 0
                                          • robert-hhR Offline
                                            robert-hh @Paul Holthuizen
                                            last edited by robert-hh

                                            @Paul-Holthuizen Adding a small sleep time into a busy loop is anyhow recommended.
                                            In this case, pycom.rgbled() does not execute asynchronously as a function. It's the sending process that is started. I'm not sure if it is operating in hardware of software. Maybe similar to the UART, where a 128 byte queue is located in the UART hardware, which can be sent or received w/o any software/firmware interaction.
                                            The RTOS is documented on the espressif web pages. https://docs.espressif.com/projects/esp-idf/en/release-v4.1/ The only complication may be, that Pycom does not use the latest release, and also a tailored version. But the previous versions should be available to at espressif.

                                            Edit: I also use a small test script along your code for verification:

                                            import pycom
                                            import time
                                            from machine import Pin
                                            pycom.heartbeat(False)
                                            white=0x333333
                                            green=0x003300
                                            p = Pin("P9", Pin.IN, Pin.PULL_UP)
                                            time.sleep(0.5)
                                            
                                            while(True):
                                                if(p() == 0):
                                                    pycom.rgbled(white)
                                                    print("Data verzonden: ")
                                                    time.sleep(1)
                                                pycom.rgbled(green)
                                                time.sleep_us(200)
                                            
                                            1 Reply Last reply Reply Quote 0

                                            Hello! It looks like you're interested in this conversation, but you don't have an account yet.

                                            Getting fed up of having to scroll through the same posts each visit? When you register for an account, you'll always come back to exactly where you were before, and choose to be notified of new replies (either via email, or push notification). You'll also be able to save bookmarks and upvote posts to show your appreciation to other community members.

                                            With your input, this post could be even better 💗

                                            Register Login
                                            • 1
                                            • 2
                                            • 1 / 2
                                            • First post
                                              Last post

                                            Pycom on Twitter

                                            Pycom