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.
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.
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
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(':') 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
anytest. 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
anyis probably not needed anyway. If you want or need to keep it you will probably need a state machine.