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



  • 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, ())
    
    


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



  • @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.


Log in to reply
 

Pycom on Twitter