<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Correct Modbus slave response]]></title><description><![CDATA[<p dir="auto">Hello, currently I am working with the core V2.7 with a COM module. I want to establish a Modbus Slave on the M5Stack by using the library "modbus.slave.rtu" directly available in M5Flow. Although I do not find any good documentation, I was able to realize a simple Modbus Slave with a holding register and and a coil register. I can receive data in LabVIEW and I can also write data (from LabVIEW to the M5Stack). But when writing I receive Error 538172 in LabVIEW (The data returned did not match the data sent for that function), although I try to generate an echo. Probably one parameter (function, address, length?) does not fit. Perhaps the solution is the application of the "Update function", but it works only for the reading functions. I also tried to init different functions (I do not know the exact purpose of the command), but it does not help either.</p>
<p dir="auto">Has anyone an idea how to generate the correct answer for the writing functions (also for changing addresses and lengths)? Here you find the current Micropython code that works except for the answer:</p>
<p dir="auto">from m5stack import *<br />
from m5ui import *<br />
from uiflow import *<br />
from modbus.slave.rtu import ModbusSlave<br />
import nvs<br />
import time<br />
import i2c_bus<br />
import machine</p>
<p dir="auto">setScreenColor(0xFFFFFF)</p>
<p dir="auto">Label0 = M5TextBox(20, 80, "Holding Register", lcd.FONT_DejaVu18, 0xFF0000, rotate=0)<br />
Label1 = M5TextBox(20, 120, "Coil Register", lcd.FONT_DejaVu18, 0xFF0000, rotate=0)</p>
<p dir="auto">Register_h = [4, 5, 6, 7, 8]<br />
Register_c = [False, True]<br />
i = 0</p>
<p dir="auto">modbus_s = ModbusSlave(1, tx=17, rx=16, baudrate=9600, data_bits=8, stop_bits=1, parity=0, slaveID=1)<br />
modbus_s.function_init(3, 0, 5)<br />
modbus_s.function_init(1, 0, 2)<br />
modbus_s.function_init(6, 0, 1)<br />
modbus_s.function_init(16, 0, 5)</p>
<p dir="auto">while(True):<br />
__buffer = modbus_s.receive_req_create_pdu()<br />
__function = modbus_s.find_function<br />
__address = modbus_s.find_address<br />
__quantity = modbus_s.find_quantity</p>
<p dir="auto">__# Read holding register values<br />
__if function == 3:<br />
____if address &gt;= 0 and (address + quantity &lt;= 5):<br />
______modbus_s.create_slave_response(Register_h[address : address + quantity])<br />
__# Read coils<br />
__elif function == 1:<br />
____if address &gt;= 0 and (address + quantity &lt;= 2):<br />
______modbus_s.create_slave_response(Register_c[address : address + quantity])<br />
__# Write single holding register value<br />
__elif function == 6:<br />
____if address &gt;= 0 and address &lt;= 5:<br />
______Register_h[address] = buffer<br />
______modbus_s.create_slave_response(buffer)<br />
__<em>Write holding register values</em><br />
__elif function == 16:<br />
____if address &gt;= 0 and (address + quantity &lt;= 5):<br />
______for i in range (address, address + quantity):<br />
________Register_h[i] = buffer[i - address]<br />
______pass<br />
______modbus_s.create_slave_response(buffer)<br />
__Label0.setText(str(Register_h))<br />
__Label1.setText(str(Register_c))<br />
__wait_ms(10)***</p>
]]></description><link>https://community.m5stack.com/topic/5901/correct-modbus-slave-response</link><generator>RSS for Node</generator><lastBuildDate>Wed, 29 Apr 2026 00:35:23 GMT</lastBuildDate><atom:link href="https://community.m5stack.com/topic/5901.rss" rel="self" type="application/rss+xml"/><pubDate>Tue, 19 Dec 2023 08:46:41 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to Correct Modbus slave response on Fri, 12 Jan 2024 01:14:51 GMT]]></title><description><![CDATA[<p dir="auto">Hi <a class="plugin-mentions-user plugin-mentions-a" href="/user/dennis78ac" aria-label="Profile: dennis78ac">@<bdi>dennis78ac</bdi></a><br />
Happy new year and thanks for your suggestion, we will check and test and after add your code to uiflow</p>
]]></description><link>https://community.m5stack.com/post/23290</link><guid isPermaLink="true">https://community.m5stack.com/post/23290</guid><dc:creator><![CDATA[pandian.nano]]></dc:creator><pubDate>Fri, 12 Jan 2024 01:14:51 GMT</pubDate></item><item><title><![CDATA[Reply to Correct Modbus slave response on Tue, 09 Jan 2024 17:23:06 GMT]]></title><description><![CDATA[<p dir="auto">Hello and a happy new year!</p>
<p dir="auto">As I had some difficulties with the given Modbus library, I have a little present for you: I had some time to program an own code based on the "Modbus application protocol specification V1.1b". Of course, I cannot guarantee that everything is conform to the specification, but I seems to work. The current example can read and write on holding and coil registers an is easily adaptable. You can also extend it with an input register or take of the write rights for special addresses by changing the if cases. I tested it on the M5Stack core V2.7 with a COMMU module (M011) and I was able to communicate with “LabVIEW 2023 Q3 32 bit” using the NI Modbus library.</p>
<pre><code>  1  from m5stack import *
  2  from m5ui import *
  3  from uiflow import *
  4
  5  setScreenColor(0xFFFFFF)
  6
  7  Label0 = M5TextBox(20, 80, "Holding Register", lcd.FONT_DejaVu18, 0xFF0000, rotate=0)
  8  Label1 = M5TextBox(20, 140, "Coil Register", lcd.FONT_DejaVu18, 0xFF0000, rotate=0)
  9  
 10  def Modbus_CRC(data):
 11    i0 = 0
 12    i1 = 1
 13    crc = 0xFFFF  
 14    for i0 in range(len(data)):
 15      crc ^= (data[i0])
 16      for i1 in range(8):
 17        if (crc &amp; 0x0001) == 0x0000:
 18          crc &gt;&gt;= 1
 19        else:
 20          crc &gt;&gt;= 1
 21          crc ^= 0xA001
 22        pass
 23      pass
 24    return [(crc &amp; 0xFF00) &gt;&gt; 8, crc &amp; 0x00FF]
 25
 26  def GenerateErrorMessage(ID, function, code):
 27    message = [ID, 0x80 + function, code, 0, 0]
 28    CRC = Modbus_CRC(message[0 : 3])
 29    message[3] = CRC[1]
 30    message[4] = CRC[0]
 31    message = bytes(message)
 32    return(message)
 33  
 34  @timerSch.event('ModbusSlave')
 35  def tModbusSlave():
 36    global uart1, RegisterH, RegisterHStart, RegisterHSize, RegisterC, RegisterCStart, RegisterCSize, SlaveID
 37    message = uart1.read()
 38    if message != None:
 39      CRC = Modbus_CRC(message[0 : len(message) - 2])
 40      if (CRC[0] == message[len(message) - 1] and CRC[1] == message[len(message) - 2] and SlaveID == message[0]):
 41        function = message[1]
 42        address = (message[2] &lt;&lt; 8) + message[3]
 43        # Read multiple coils
 44        if function == 1:
 45          quantity = (message[4] &lt;&lt; 8) + message[5]        
 46          if quantity &gt;= 0x01 and quantity &lt;= 0x07CD0:
 47            if address &gt;= RegisterCStart and address + quantity &lt;= RegisterCStart + RegisterCSize:          
 48              message = [0] * (int((7 + quantity) / 8) + 5)
 49              message[0] = SlaveID
 50              message[1] = function
 51              message[2] = int((7 + quantity) / 8)
 52              i0 = 0           
 53              for i1 in range(message[2]):
 54                message[3 + i1] = 0
 55                for i2 in range(8):
 56                  if i0 &lt; quantity:
 57                    if RegisterC[address - RegisterCStart + i0]:
 58                      message[3 + i1] += (1 &lt;&lt; i2)
 59                    i0 += 1
 60                  else:
 61                    break  
 62              CRC = Modbus_CRC(message[0 : len(message) - 2])
 63              message[len(message) - 1] = CRC[0]
 64              message[len(message) - 2] = CRC[1]
 65              message = bytes(message)            
 66            else:                
 67              message = GenerateErrorMessage(SlaveID, function, 2)
 68          else:
 69            message = GenerateErrorMessage(SlaveID, function, 3)        
 70        # Read multiple holding registers
 71        elif function == 3:
 72          quantity = (message[4] &lt;&lt; 8) + message[5]
 73          if quantity &gt;= 0x01 and quantity &lt;= 0x7D:
 74            if address &gt;= RegisterHStart and address + quantity &lt;= RegisterHStart + RegisterHSize:
 75              message = [0] * (quantity * 2 + 5)
 76              message[0] = SlaveID
 77              message[1] = function
 78              message[2] = 2 * quantity
 79              for i0 in range(quantity):
 80                message[3 + 2*i0] = (RegisterH[address + i0 - RegisterHStart] &amp; 0xFF00) &gt;&gt; 8
 81                message[4 + 2*i0] = RegisterH[address + i0 - RegisterHStart] &amp; 0xFF
 82              CRC = Modbus_CRC(message[0 : len(message) - 2])
 83              message[len(message) - 1] = CRC[0]
 84              message[len(message) - 2] = CRC[1]
 85              message = bytes(message)
 86            else:
 87              message = GenerateErrorMessage(SlaveID, function, 2)
 88          else:
 89            message = GenerateErrorMessage(SlaveID, function, 3)     
 90        # Write single coil
 91        elif function == 5:        
 92          if (message[4] == 0x00 or message[4] == 0xFF) and message[5] == 0x00:
 93            if address &gt;= RegisterCStart and address &lt; RegisterCStart + RegisterCSize:
 94              RegisterC[address - RegisterCStart] = (message[4] == 0xFF)
 95            else:
 96              message = GenerateErrorMessage(SlaveID, function, 2)
 97          else:
 98            message = GenerateErrorMessage(SlaveID, function, 3)
 99        # Write single holding register
100        elif function == 6:
101          if address &gt;= 0 and address &lt;= 0xFFFF:
102            if address &gt;= RegisterHStart and address &lt; RegisterHStart + RegisterHSize:
103              RegisterH[address - RegisterHStart] = (message[4] &lt;&lt; 8) + message[5]
104            else:
105              message = GenerateErrorMessage(SlaveID, function, 2)
106          else:
107            message = GenerateErrorMessage(SlaveID, function, 3)
108        # Write multiple coils
109        elif function == 15:
110          quantity = (message[4] &lt;&lt; 8) + message[5]         
111          if (quantity &gt;= 1 and quantity &lt;= 0x07B0 and message[6] == int((quantity + 7) / 8)):
112            if address &gt;= RegisterCStart and address + quantity &lt;= RegisterCStart + RegisterCSize:
113              i0 = 0
114              for i1 in range(message[6]):
115                for i2 in range(8):
116                  if i0 &lt; quantity:
117                    RegisterC[address + i0 - RegisterCStart] = (message[7 + i1] &amp; (1 &lt;&lt; i2) &gt; 0)
118                    i0 += 1
119                  else:
120                    break
121              message = [0] * 8
122              message[0] = SlaveID
123              message[1] = function 
124              message[2] = address &gt;&gt; 8
125              message[3] = 0xFF &amp; address
126              message[4] = quantity &gt;&gt; 8
127              message[5] = 0xFF &amp; quantity
128              CRC = Modbus_CRC(message[0 : 6])
129              message[6] = CRC[1]
130              message[7] = CRC[0]
131              message = bytes(message)
132            else:
133              message = GenerateErrorMessage(SlaveID, function, 2)
134          else:
135            message = GenerateErrorMessage(SlaveID, function, 3)          
136        # Write multiple holding registers
137        elif function == 16:
138          quantity = (message[4] &lt;&lt; 8) + message[5]
139          if quantity &gt;= 0x01 and quantity &lt;= 0x7B and message[6] == 2 * quantity:
140            if address &gt;= RegisterHStart and address + quantity &lt;= RegisterHStart + RegisterHSize:
141              for i0 in range(quantity):
142                RegisterH[address + i0 - RegisterHStart] = (message[7 + 2 * i0] &lt;&lt; 8) + message[8 + 2 * i0]        
143            else:
144              message = GenerateErrorMessage(SlaveID, function, 2)
145          else:
146            message = GenerateErrorMessage(SlaveID, function, 3)
147        uart1.write(message) 
148      Label0.setText(str(RegisterH))
149      text = "["
150      for i0 in range(len(RegisterC) - 1):      
151        if RegisterC[i0]:
152          text += "1, "
153        else:
154          text += "0, "
155      if RegisterC[len(RegisterC) - 1]:
156        Label1.setText(text + "1]")
157      else:
158        Label1.setText(text + "0]") 
159      pass
160  
161  # Start values of holding and coil registers
162  RegisterH = [10, 568, 65534, 21]
163  RegisterHStart = 0x10
164  RegisterHSize = len(RegisterH)
165  RegisterC = [False, True, False, False, True, False, True, True, False]
166  RegisterCStart = 0x20
167  RegisterCSize = len(RegisterC)
168  SlaveID = 0x11
169
170  function = 0
171  address = 0
172  quantity = 0
173  message = None
174  i = 0
175  data = None
176  CRC = None
177
178  uart1 = machine.UART(1, tx=17, rx=16)
179  uart1.init(9600, bits=8, parity=0, stop=1)
180  timerSch.run('ModbusSlave', 100, 0x00)
</code></pre>
]]></description><link>https://community.m5stack.com/post/23285</link><guid isPermaLink="true">https://community.m5stack.com/post/23285</guid><dc:creator><![CDATA[dennis78ac]]></dc:creator><pubDate>Tue, 09 Jan 2024 17:23:06 GMT</pubDate></item><item><title><![CDATA[Reply to Correct Modbus slave response on Thu, 21 Dec 2023 10:24:10 GMT]]></title><description><![CDATA[<p dir="auto">Thank you for your help. Your example works well if using only one coil. Nevertheless I could at first not solve the problem as LabVIEW still claimed a false response, if I change the coils the registers to write.</p>
<p dir="auto">For this reason I displayed the response in LabVIEW in detail. The problem are changing addresses if writing on different coils or holding registers. In your example, the write function is initiated with address 0x00ac. So if you always write on 0x00ac it works fine. But if you write in a second process on 0x00ad, for instance, the M5Stack will nevertheless answer with 0x00ac as address, which is claimed by LabVIEW. Unfortunately the initiated function cannot be upated to the new address, as the update command only works for the reading functions.</p>
<p dir="auto">As solution that seems to work I initiated now each function at the beginning, covering the complete address area for multiple read/write and indicating the last address for single read/write. Otherwise the M5Stack produces an error, if you want to write on a coil with an address higher the initially indicated. Then I reinitiate after each the buffer read once again the particular function with the current address and quantity and it seems wo work. I just hope not to generate each time a new variable (function) within the M5Stack, but I have the impression that I am just overwriting the old function values. By reinitiating the function address and quantity are adapted for the "Send ADU response buffer" command.</p>
<p dir="auto">from m5stack import *<br />
from m5ui import *<br />
from uiflow import *<br />
from modbus.slave.rtu import ModbusSlave<br />
import nvs<br />
import time<br />
import i2c_bus<br />
import machine</p>
<p dir="auto">setScreenColor(0xFFFFFF)</p>
<p dir="auto">Label0 = M5TextBox(20, 80, "Holding Register", lcd.FONT_DejaVu18, 0xFF0000, rotate=0)<br />
Label1 = M5TextBox(20, 120, "Coil Register", lcd.FONT_DejaVu18, 0xFF0000, rotate=0)<br />
Label2 = M5TextBox(20, 160, "Buffer", lcd.FONT_DejaVu18, 0xFF0000, rotate=0)<br />
Register_h = [4, 5, 6, 7, 8]<br />
Register_c = [False, True]<br />
i = 0</p>
<p dir="auto">modbus_s = ModbusSlave(1, tx=17, rx=16, baudrate=9600, data_bits=8, stop_bits=1, parity=0, slaveID=0x11)<br />
# Initiate each function with maximum quantity / maximum address<br />
modbus_s.function_init(3, 0, 5)<br />
modbus_s.function_init(1, 0, 2)<br />
modbus_s.function_init(6, 4, 1)<br />
modbus_s.function_init(16, 0, 5)<br />
modbus_s.function_init(5, 1, 1)<br />
modbus_s.function_init(15, 0, 2)<br />
while(True):<br />
__buffer = modbus_s.receive_req_create_pdu() # Read buffer<br />
__function = modbus_s.find_function<br />
__address = modbus_s.find_address<br />
__quantity = modbus_s.find_quantity<br />
__modbus_s.function_init(function, address, quantity) # (Re)initiate specific function with current address and quantity<br />
__if function &gt; 0:<br />
____Label2.setText(str(buffer))<br />
__# Read holding register values<br />
__if function == 3:<br />
____if address &gt;= 0 and (address + quantity &lt;= 5):<br />
______modbus_s.create_slave_response(Register_h[address : address + quantity])<br />
__# Read coils<br />
__elif function == 1:<br />
____if address &gt;= 0 and (address + quantity &lt;= 2):<br />
______modbus_s.create_slave_response(Register_c[address : address + quantity])<br />
__# Write single holding register value<br />
__elif function == 6:<br />
____if address &gt;= 0 and address &lt;= 5:<br />
______Register_h[address] = buffer<br />
______modbus_s.create_slave_response(buffer)<br />
__# Write holding register values<br />
__elif function == 16:<br />
____if address &gt;= 0 and (address + quantity &lt;= 5):<br />
______for i in range (address, address + quantity):<br />
________Register_h[i] = buffer[i - address]<br />
______pass<br />
______modbus_s.create_slave_response(buffer)<br />
__elif function == 5:<br />
____if address &gt;= 0 and address &lt;= 1:<br />
______Register_c[address] = buffer &gt; 0<br />
______modbus_s.create_slave_response(buffer)<br />
__elif function == 15:<br />
____if address &gt;= 0 and address + quantity &lt;= 2:<br />
______for i in range (address, address + quantity):<br />
________Register_c[i] = buffer[i - address]<br />
______pass<br />
______modbus_s.create_slave_response(buffer)</p>
<p dir="auto">__Label0.setText(str(Register_h))<br />
__Label1.setText(str(Register_c))<br />
__wait_ms(10)</p>
]]></description><link>https://community.m5stack.com/post/23107</link><guid isPermaLink="true">https://community.m5stack.com/post/23107</guid><dc:creator><![CDATA[dennis78ac]]></dc:creator><pubDate>Thu, 21 Dec 2023 10:24:10 GMT</pubDate></item><item><title><![CDATA[Reply to Correct Modbus slave response on Thu, 21 Dec 2023 02:11:09 GMT]]></title><description><![CDATA[<p dir="auto">Hi <a class="plugin-mentions-user plugin-mentions-a" href="/user/dennis78ac" aria-label="Profile: dennis78ac">@<bdi>dennis78ac</bdi></a> ,<br />
This is "write single coil" example</p>
<p dir="auto"><img src="/assets/uploads/files/1703123948037-d6c44f86-0c89-492c-967d-695403586345-image-resized.png" alt="0_1703123947895_d6c44f86-0c89-492c-967d-695403586345-image.png" class=" img-fluid img-markdown" /></p>
<p dir="auto"><img src="/assets/uploads/files/1703123768564-aa266d4b-66ac-46a6-85a6-cbcc170cdb99-image.png" alt="0_1703123768462_aa266d4b-66ac-46a6-85a6-cbcc170cdb99-image.png" class=" img-fluid img-markdown" /></p>
<p dir="auto">The "Send ADU Response Buffer" block should add buffer data(All read and all write function is required)</p>
<p dir="auto"><img src="/assets/uploads/files/1703124472682-ead8b77c-f388-4f02-ba35-eeca37d9abd5-image.png" alt="0_1703124472585_ead8b77c-f388-4f02-ba35-eeca37d9abd5-image.png" class=" img-fluid img-markdown" /></p>
]]></description><link>https://community.m5stack.com/post/23106</link><guid isPermaLink="true">https://community.m5stack.com/post/23106</guid><dc:creator><![CDATA[pandian.nano]]></dc:creator><pubDate>Thu, 21 Dec 2023 02:11:09 GMT</pubDate></item><item><title><![CDATA[Reply to Correct Modbus slave response on Wed, 20 Dec 2023 10:03:40 GMT]]></title><description><![CDATA[<p dir="auto">Thank you for your answer. Nevertheless I already implied these two commands with:</p>
<ul>
<li>buffer = modbus_s.receive_req_create_pdu() --- line after "while(True)"</li>
<li>modbus_s.create_slave_response(buffer) --- for example in "elif function == 16" at the end</li>
</ul>
<p dir="auto">As I already explained LabVIEW receives the answer, but not as expected. As the response does not only contain the data itself (saved in buffer), but also function no., address etc. I think the difference has to be searched within these parameters. Unfortunately I do not find any possibility to adapt the response, especially as the update command for the function only works for the reading functions, but not for the writing functions. So I do not know how to update function no, address and quantity for the response (or just generate the echo as expected)</p>
]]></description><link>https://community.m5stack.com/post/23100</link><guid isPermaLink="true">https://community.m5stack.com/post/23100</guid><dc:creator><![CDATA[dennis78ac]]></dc:creator><pubDate>Wed, 20 Dec 2023 10:03:40 GMT</pubDate></item><item><title><![CDATA[Reply to Correct Modbus slave response on Wed, 20 Dec 2023 02:08:25 GMT]]></title><description><![CDATA[<p dir="auto">Hi <a class="plugin-mentions-user plugin-mentions-a" href="/user/dennis78ac" aria-label="Profile: dennis78ac">@<bdi>dennis78ac</bdi></a> ,<br />
please refer to the example code<br />
<img src="/assets/uploads/files/1703037122429-1dcffd6d-ca31-479c-b248-93b82c360bd9-image-resized.png" alt="0_1703037122278_1dcffd6d-ca31-479c-b248-93b82c360bd9-image.png" class=" img-fluid img-markdown" /><br />
received the buffer from "receive ADU request" that same buffer is added to the "send ADU response buffer" and If you need to update the value, use "update function" the block<br />
<img src="/assets/uploads/files/1703037024175-b1df53e2-f25e-4b7f-8ec2-fa2caf961bfb-image-resized.png" alt="0_1703037023969_b1df53e2-f25e-4b7f-8ec2-fa2caf961bfb-image.png" class=" img-fluid img-markdown" /></p>
]]></description><link>https://community.m5stack.com/post/23093</link><guid isPermaLink="true">https://community.m5stack.com/post/23093</guid><dc:creator><![CDATA[pandian.nano]]></dc:creator><pubDate>Wed, 20 Dec 2023 02:08:25 GMT</pubDate></item></channel></rss>