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

    two uart.readline() statements give interchanged data in threaded function

    Scheduled Pinned Locked Moved LoPy
    3 Posts 2 Posters 50 Views 2 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.
    • M Offline
      mbyamukama
      last edited by mbyamukama

      I have shown at the end of this post a code excerpt that shows the function I am asking about. The global variables have already been defined somewhere above, I just removed them to shorten it.
      This is a LoPy4 communicating with an STM32 microcontroller in a power electronics application.
      The line

      uart.write("rim_?\r")
      

      returns a string of this form

      5: 0d00h45m03.424s,5, 413,9928,0,0x000394000000, 755,9922,0,0x0003B6000000, 1058,9934,0,0x00038B000000, 3047,9929,0,0x000375000002, 3646,9947,2,0x0003A1000742
      

      This command runs once and is necessary to get the id of the box which is previously unknown. I then split the string and extract the "5" which is an id of the microcontroller, after which I construct two further strings/commands using this id. These constructed commands are necessary because exactly the same commands are sent over the air from another LoPy4 and the receiving LoPy4 only responds if received command is the same as the constructed expected command. There are 2 lines that cause the STM32 to return data over the serial port.

      The line

      uart.write(exp_dmp_cmd)
      

      when called ALONE returns a string with 47 parts, separated by a comma, such as

      5: 0d00h45m03.394s,4,0,35.5, 14.617,3.605,3.616,3.601,3.782,9.16,27.2, 0,-0.278,-0.15,nan, 1,12.51,133.9, 0,nan,nan, 0,nan,nan,nan,nan,nan,0.000,0,0, 0,0,0,nan,nan,nan,nan, +0x22E844DBF,+0x1C12333835CB, +0x6E011DF,-0xB875CA77, -0x23066,-0x13497C4D, -0x18AAB4,-0x14E8E0D2E, +0x23CA6,+0x1DF7E31F
      

      and

      uart.write(exp_rim_cmd)
      

      WHEN CALLED ALONE (i.e with the uart.write(exp_dmp_cmd) commented out) returns the same string I showed earlier with 22 parts.

      My issue is:
      with both these lines in the function, the responses to these write statements are interchanged over 90% of the time! The read operation after the first write statement uart.write(exp_dmp_cmd) largely gives the 22 part response and the response after uart.write(exp_rim_cmd) largely gives the 47 part response. Sometimes, the responses are as expected but this happens randomly. I am 100% sure the issue is not with the STM32, which responds the expected way always using other platforms (e.g. PuTTY over a USB-serial connection). Moreover, it responds the expected way when we call only one of these write commands without calling the other.

      You will see a work around in the code. Because I must store a response in the proper variable, dmp_resp or rim_resp, what I currently doing is to count how may parts the response I got back (either 47 or 22) and then save that response in the proper variable.
      But the code defeats all logic. Not sure if it being in a threaded function has something to do with it.
      I am looking forward to possible reasons why this is happening.

      def uart_tx_rx():
          global dmp_resp, rim_resp,exp_dmp_cmd,exp_rim_cmd,id, new_dmp_data, new_rim_data
          dmp_resp, rim_resp, exp_dmp_cmd, exp_rim_cmd,id="","","","",""
          new_dmp_data,new_dmp_data=False,False
          led_count=0;
          id_obtained=False
      
          while True:
              try:
                  if not uart_locked:  #only run code inside when this flag is true
      
                      while id=="": #box has not yet been identified
                          uart.write("rim_?\r") #this returns an id in the first 1 or 2 bytes followed by a ":"
                          if(uart.any()>0):
                              resp=uart.readline().decode('ascii','ignore')
                              id=resp.split(':')[0]
                          exp_dmp_cmd = "dmp_?"+id+"\r"
                          exp_rim_cmd = "rim_?"+id+"\r"
                          id_obtained=True
                          time.sleep(1)
      
                      if id_obtained:
                          led_count+=1
                          if led_count%2==0:
                              toggleRGB(5,0xFF69B4,1) #led flash means we got a homebox id
                              led_count=0;
      
                      res1,res2="",""
                      uart.write(exp_dmp_cmd)
                      if (uart.any()>0):
                          res1=uart.readline().decode('ascii','ignore')
                      uart.write(exp_rim_cmd)
                      if (uart.any()>0):
                          res2=uart.readline().decode('ascii','ignore')
      
                      col_cnt1=len(res1.split(','))
                      col_cnt2=len(res2.split(','))
                      if col_cnt1==47: #this is a dmp response
                          dmp_resp=res1
                      if col_cnt1==22:
                          rim_resp=res1
                      if col_cnt2==47:
                          dmp_resp=res2
                      if col_cnt2==22:
                          rim_resp=res2
      
                      if dmp_resp:
                          new_dmp_data=True
                      if rim_resp:
                          new_rim_data=True
              except:
                  pass
              time.sleep_ms(2000)
      
      _thread.start_new_thread(uart_tx_rx, ())
      
      
      J 1 Reply Last reply Reply Quote 0
      • J Offline
        jcaron @mbyamukama
        last edited by

        @mbyamukama add traces (logs) to your code. You’ll find out it’s not doing what you expect it to do in the order you want.

        The root cause is the any test. It probably comes too early (the STM32 hasn’t had time to answer yet, or not enough). The you send the other command and by then you get the response to the first command. And then you loop back and get the answer to the second command after sending (again) the first command.

        Since you are running on a thread the any is probably not needed anyway. If you want or need to keep it you will probably need a state machine.

        1 Reply Last reply Reply Quote 0
        • M Offline
          mbyamukama
          last edited by

          Thank you for your help. I will come back after trying this.

          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 / 1
          • First post
            Last post

          Pycom on Twitter

          Pycom