Skip to content
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

Fix timing issues with UART communication #75

Merged
merged 7 commits into from
Jul 2, 2023

Conversation

wpyoga
Copy link

@wpyoga wpyoga commented Jun 29, 2023

This pull request fixes timing issues when sending a command and receiving a response:

  • Sometimes the initial bytes are garbled and truncated Handle control pin timing #73
  • When reading a long response, sometimes the end of the response is truncated

The missing initial bytes issue is apparent when we use a TTL-to-RS485 converter board that does not have automatic flow control. This is usually in the form of an EN pin, or DE & ~RE pin jumpered together. They are equivalent. This can be seen in the extremely popular MAX485 chip. This is caused by disabling the EN pin too late -- thus messing up the initial slave response.

The fix for the issue with receiving long slave responses is not perfect, but should be good enough for now. I was able to consistently trigger this issue by reading many (64, 96, and even 125) registers at once. An ideal solution would involve letting the user/caller specify the timeout value for reading a response.

P.S. Apologies to @brainelectronics , I did not see your PR #73 before going with this approach. However, I believe this solution will fix both your problem (ticks rollover) and the initial bytes being truncated.

P.P.S. This pull request should (may) also fix these issues:

@beyonlo
Copy link

beyonlo commented Jun 29, 2023

@wpyoga Thank you very much for this PR 🥳

I will test it as soon is possible with the MAX485 using control pin, and I will report the result tests here!

@beyonlo
Copy link

beyonlo commented Jun 30, 2023

@wpyoga Works like a charm with the MAX485 using control pin 🥳

I'm using the semi official examples to run Slave RTU (rtu_client_example.py) and Master RTU (rtu_host_example.py) and I have no CRC errors anymore. Ps: I call semi official examples because we (@brainelectronics) is waiting the PR #56 be merged to merge that examples (sync and async) too. Follow the tests:

Slave RTU (sync):

$ mpremote run rtu_client_example.py 
MicroPython infos: (sysname='esp32', nodename='esp32', release='1.20.0', version='v1.20.0 on 2023-04-26', machine='ESP32S3 module (spiram) with ESP32S3')
Used micropthon-modbus version: 0.0.0
Using pins (17, 18) with UART ID 1
Setting up registers ...
Register setup done
Serving as RTU client on address 10 at 115200 baud
my_coil_get_cb, called on getting COILS at 123, currently: [1, False, False, False, False, False, False, False, False, False, False, False]
my_coil_set_cb, called on setting COILS at 123 to: [False]
my_coil_get_cb, called on getting COILS at 123, currently: [False, False, False, False, False, False, False, False, False, False, False, False]
my_hr_get_cb, called on getting HREGS at 93, currently: [19]
my_hr_set_sb, called on setting HREGS at 93 to: [44]
my_hr_get_cb, called on getting HREGS at 93, currently: [44]
my_di_get_cb, called on getting ISTS at 67, currently: [0]
my_ir_get_cb, called on getting IREGS at 10, currently: [60001]
Incremented current value by +1 before sending response
Resetting register data to default values ...
Default values restored

Master RTU (sync):

$ mpremote run rtu_host_example.py 
MicroPython infos: (sysname='esp32', nodename='esp32', release='1.20.0', version='v1.20.0 on 2023-04-26', machine='ESP32S3 module (spiram) with ESP32S3')
Used micropthon-modbus version: 0.0.0
Using pins (17, 18) with UART ID 1
Requesting and updating data on RTU client at address 10 with 115200 baud

Status of COIL 123: [True, False, False, False, False, False, False, False, False, False, False, False]
Result of setting COIL 123 to True
Status of COIL 123: [False, False, False, False, False, False, False, False, False, False, False, False]

Status of HREG 93: (19,)
Result of setting HREG 93 to True
Status of HREG 93: (44,)

Status of IST 67: [False]

Status of IREG 10: (60002,)

Resetting register data to default values...
Result of setting COIL 42: True

Finished requesting/setting data on client

@brainelectronics
Copy link
Owner

So nice! Great work @wpyoga. Big thank you again to @beyonlo for testing. Will merge and release this tomorrow.

@wpyoga
Copy link
Author

wpyoga commented Jun 30, 2023

Thanks guys! I'm glad I could help, I was intially only trying to fix issues I saw on my end :)

@brainelectronics
Copy link
Owner

@beyonlo could you re-do your tests? I had to add support for MicroPython v1.19.1 and earlier as UART.flush() got introduced in 1.20.0, but some of my products are running on MicroPython v1.18. I did some quick tests locally with my setups at 9600, 57600 and 115200 baud which look good, see screenshots. The changes of @wpyoga are not affected by my additions

9600 57600 115200

@beyonlo
Copy link

beyonlo commented Jul 3, 2023

@brainelectronics As requested, I re-do the tests using the release https://github.com/brainelectronics/micropython-modbus/archive/refs/tags/2.3.5.tar.gz but the version do not show 2.3.5, it show 0.0.0 - why? I tested in 9600, 57600 and 115200 and all works, but here I will paste just using the 115200:

Slave RTU (sync) - (rtu_client_example.py):

$ mpremote run rtu_client_example.py 
MicroPython infos: (sysname='esp32', nodename='esp32', release='1.20.0', version='v1.20.0 on 2023-04-26', machine='ESP32S3 module (spiram) with ESP32S3')
Used micropthon-modbus version: 0.0.0
Using pins (37, 38) with UART ID 1
Setting up registers ...
Register setup done
Serving as RTU client on address 10 at 115200 baud
my_coil_get_cb, called on getting COILS at 123, currently: [1, False, False, False, False, False, False, False, False, False, False, False]
my_coil_set_cb, called on setting COILS at 123 to: [False]
my_coil_get_cb, called on getting COILS at 123, currently: [False, False, False, False, False, False, False, False, False, False, False, False]
my_hr_get_cb, called on getting HREGS at 93, currently: [19]
my_hr_set_sb, called on setting HREGS at 93 to: [44]
my_hr_get_cb, called on getting HREGS at 93, currently: [44]
my_di_get_cb, called on getting ISTS at 67, currently: [0]
my_ir_get_cb, called on getting IREGS at 10, currently: [60001]
Incremented current value by +1 before sending response
Resetting register data to default values ...
Default values restored

Master RTU (sync) - (rtu_host_example.py):

$ mpremote run rtu_host_example.py 
MicroPython infos: (sysname='esp32', nodename='esp32', release='1.20.0', version='v1.20.0 on 2023-04-26', machine='ESP32S3 module (spiram) with ESP32S3')
Used micropthon-modbus version: 0.0.0
Using pins (17, 18) with UART ID 1
Requesting and updating data on RTU client at address 10 with 115200 baud

Status of COIL 123: [True, False, False, False, False, False, False, False, False, False, False, False]
Result of setting COIL 123 to True
Status of COIL 123: [False, False, False, False, False, False, False, False, False, False, False, False]

Status of HREG 93: (19,)
Result of setting HREG 93 to True
Status of HREG 93: (44,)

Status of IST 67: [False]

Status of IREG 10: (60002,)

Resetting register data to default values...
Result of setting COIL 42: True

Finished requesting/setting data on client

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants