레이블이 IF-MODBUS인 게시물을 표시합니다. 모든 게시물 표시
레이블이 IF-MODBUS인 게시물을 표시합니다. 모든 게시물 표시

6/21/2023

RS485 Modbus-RTU 의 OTA 구현

1. Modbus-RTU 와 SCADA 시스템 

RS485 기반의 Modbus RTU 구조는 이전의 문서들을 참조 하도록 하자. 

RS485 Modbus 와 SCADA 시스템1

RS485 Modbus 와 SCADA 시스템2

Modbus-RTU 기반으로 각 Device들을 구현하면, 최종적으로 이 기반으로 OTA도 별도로 구현을 하고 싶어할 것이다. 
하지만, 안타깝게도, 이것으로, OTA를 해주는 기능은 없으며, 별도로 본인 Protocol 정의해서 구현을 해야한다. 


1.1 Modbus-RTU Memory Map 

우선 Modbus-RTU는 Device에게 Data Read only 와 Read/Write만 제공하는 단순한 Protocol이다. 
이를 좀 더 세부적으로 제어하기 위해서는 별도 Protocol 정의하고 부족한 부분을 채워 각 기능을 보완을 해야한다. 

예를들면, OTA 구현이라든지, Device 세부제어라든지, 이런 요소들을 위해서 각 Memory Map 정의하도록 하자 
  1. Input Register  (Read only 2byte)
    1. Modbus RTU Status 
    2. System Status
    3. Each Event 
    4. System Information 
  2. Holding Register  (Read/Write 2byte)
    1. Modbus RTU Command
    2. Modbus RTU Status 
    3. Modbus RTU Error 
    4. Modbus RTU Argument 
    5. Modbus RTU Buffer
    6. 이외 System Setup 

내가 생각한 것은 간단하게 Command 기반으로 각 상태를 만들어 Device를 구동시키는 방법이다. 
상위와 같이 각 Modbus RTU Command를 각 만들어 Command Driven 방식으로 간단히 device driver를 보완하여 만들어 보자.
유사하다면, MMC가 될 수도 있겟으며, 상위처럼 구현할 경우, 반드시 Master에서 구현하고 테스트를 해봐야 한다. 

  • eMMC/SDCard Interface 
MMC Spec 세부적으로 보면, 각 CMD 의 상태도가 있으며, 이부분과 비슷하다. 


1.2 Modbus-RTU 기반 OTA 

Modbus 가 기본적으로 Request/Response 기반이므로, SCADA(Master), 특정 Register를 Command 기반으로 변경하여 진행하도록 한다.
이에 대한 반응 항상 특정 Resiter를 통해, Deivce Status 체크하는 구조이다.

상위에서 언급한 MMC가 이런 방식으로 동작하며, 다양한 Device Driver들이 이와 유사한다. 
그리고, 각 Command마다 Flow 및 Status가 본인 알아서 정의하도록 하자.  

  • OTA 구현시 문제사항 
OTA를 진행할 경우, Modbus-RTU 에서는 많은 Data를 전송하기 때문에, 여기에도 좀 문제가 발생하는데, 
주로 Cache(CPU Cache가 아니며, Buffer)로 인하여, 중복되는 문제 부분일 것 같다.
이 부분은, OTA 진행 할 경우, 
RS232의 Flow Control 이 존재하지만, RS485에서 크게 의미가 없어서, 별도로, S/W Flow Control Header 정의해서, 이 부분을 보완하였다. 
테스트를 해봤지만, RS232 Flow Control이 RS485로 되면서 별의미가 없고, Modbus-RTU(RS485)는 내부적으로 Flow Control이 없는걸로 생각되어짐 

이 부분은 간단히 정의해서 이 부분을 보완하여 넣도록하자.
예를들면, 각 Offset 과 Size 정의하고, 이를 Master 와 Slave가 각각 확인하는 구조이며, 이외 Buffer 성능 및 에러문제등을 개선하여 만들어 보도록하자. 
이외 다양한 문제가 발생할 수 있으며, 각 상황에 맞추어 본인이 세부적으로 분석해서 대응하자.  

  • 나의 경우는 HW적으로 다음과 같은 문제가 발생 
  1. RS485 Tranceiver 의 오동작 ( Reset 후 발생 문제가 발생)
  2. Master에서 Response를 제대로 못가져오는 문제 
    1. 이 문제가 발생하여 상위 Flow Control 기능추가 
  3. ESP32의 FreeRTOS 문제 및 성능문제 
    1. 이 문제는 S/W 문제가 다양하며, Serial 부분과 많이 연관되어짐
    2. Serial Buffer 이외 FreeRTOS Buffer도 별도로 존재 

일단 나의 경우는 각 OTA Command 와 Status를 별도로 정의하여 구현했으며, 테스트 결과 별 이상이 없다.

더불어, 좀 더 세부적으로 성능 및 OTA 테스트 분석하기 위해서 Python 기반으로 이를 OTA 테스트 하는 Program을 작성하였다. 
또한 Modbus RTU 기능을 간단히 Profiling (RS485 버스 점유율 및 속도)해주는 Program도 별도 추가구현 하였다.

만약, 이를 상용으로 동작되는 프로그램있다면,이를 적극 이용하거나, 그 Tool에 맞게 제작 하도록하자.
구지, 나처럼 다 일일이 만들지 말도록 하자. 

주로 Profiling 하는 부분은 ESP32의 RS485/Modbus-RTU 성능이므로, 이 Bus 점유율(Share-rate)를 각 속도별로 비교해보면 되겠다.
그리고, 각 에러율도 좀 비교해보면 더욱 좋겠다. (이 부분은 만들었지만, 비교하지 않았다)

참고로, ESP32의 경우, 속도가 높아질수록 성능 많이 부족해지는데, 다른 곳에 많은 리소스를 사용해서 그런건지,(아마 이쪽이 가능성이 높다) 
아님 ESP32 문제인지는 나도 아직 세부적으로 분석하지 않았다. 


2. SCADA 에 Modbus RTU 적용문제 

나 역시, 정확한 SCADA를 실제로 접해 본적이 없기에, 이에 적용하는 방법은 본인 정한 Protocol Flow와 Memory Map 을 알려주는 방법 밖에는 없는 거 같다.
나의 경우, Python 기반으로 나만의 Master기반으로 직접 테스트하며 구현했기 때문에, 이 부분은 나중에 한 번 다시 한번 생각해봐야겠다. 


2.1 Python 기반 Unit 테스트 

Modbus 역시, Python 과 NodeJS도 지원해주기 때문에, 본인 작성하기 쉬운 걸로 선택해서 각 테스트 프로그램들을 작성하도록 하자. 
상위에 이미 설명을 했으며, 각 OTA 성능 및 Profile을 위해서 가 부분을 비교 분석하도록 하였다. 

내가 TEST Program을 작성하면서, 어려움이라고 하면, 각 Python Library 찾는 법? 
나머지는, 구글링하면, Python은 대충 작성이 가능한 것 같다.
(다만 본인이 동작하는 원리와 프로토콜 설계를 이해를 해야 하겠지만)

참고로, 최근에 상위처럼 5대가 아니라, RS485로 현재 8대까지 40 meter로 테스트 했을 때도 OTA와 다른 Control 크게 문제가 되지 않았다.





2.2 VS Code 의 Unit TEST (Automated)

외부 DevOps 처럼, 완전히 Cloud 내부에서 하는 것은 아니지만, 본인 개발환경에서 쉽게 가능하다. 
나의 경우, Github에서는 CircleCI를 이용하지만, VS Code Manaul보면, 외부에서도 아래와 같이 쉽게 본인 마음대로 Power Shell Script 기반으로 구성가능하다. 


VS Code를 이용하여 자동화 
완벽히 Jenkins는 아니여도, 얼추 Jenkins 느낌처럼 구성가능하다. 

1/10/2023

RS485 Modbus 와 SCADA 시스템2

1. ESP32 회로구성 

이전에 ESP32 Modbus 관련하여 정리한 것이 그림 때문에 너무 긴거 같아, 다시 두개로 나누어 정리한다. 
더불어,RS485 와 Modbus를 분리하여, 잘못 안 부분이 있다면, 수정하도록 하겠다. 

RS232 와 RS485 회로구성 (ESP32 회로도 참조)


1.1 RS232 와 RS485 회로구성 

ESP32는 RS232만 지원가능하며, RS232는 Full Duplex이며, RS485는 Half Duplex 이다. 
Modbus를 구성하려면 두가지 방법이 있는데, ESP32에서만 제공하는 회로도만 보고, 이해했다가, 
현재 사용하고 USB제품을 통해 Echo/Non Echo 모드를 알게되었다. 


  • RS485 Mod 구성 (회로도)
  1. Echo Mode: 이전 ESP32 Sample 회로도 with CD(Collision Detection)기능 
  2. Non-Echo Mode: 이전 ESP32 Sample 회로도  without CD(Collision Detection) 기능 

Echo/Non-Echo Mode 관련내용 

문제는 CD(Collision Detection)기능이 있는 Echo Mode를 ESP32에서 완전히 제공하고 있지 않으므로, 주의해햐한다.
동작은 되지만, 멈추는 현상이 발생하며, ESP-IDF를 업그레이드 하면 추후에 제공될 것이겠지만, 현재 내 버전은 그렇지 않다. 


1.2 RS485 Bus 와 다른 Bus 구성 비교  

  • RS485의 Tranceiver 간의 비교 
RS485 Tranceiver VCC마다 다 다를수 있으며, VCC의 Range 정해져 있지, 동일한 Volatage로 사용여부는 정해져 있지 않다. 
이는 아래의 CSMA/CD에서 CD부분에서 자세히 설명하겠다. 

  • Ethernet 와 RS485 Tranceiver 비교  
Etherent과 비교하면, 구성면에서 있어서 비슷한 구성, VCC가 다 동일하며, Volatage 기반으로 Collision Detection이 가능하다  

  • USB 와 RS485 Tranceiver 비교  
USB과 비교하면, USB Master에서 VCC/VDD 나오며 전력도 제어하는 구조로 상위와 완전다르다. 
USB는 Power만 가지고도, 끝도 없이 이야기 할수 있으므로, USB 세부사항들은 아래참고 


1.3 RS485 의 CD(Collision Detection) 기능 

CSMA/CD or CSMA/CA는 대부분 Bus의 Layer 2에서 제공을 해주는 기능이며, 공용 Bus를 같이 사용하기 위해서 사용되는 기술이다.
간단하게 말해, 공용 Bus에서 TX를 하기전에, CS(Carrier Sense) 즉, Bus 이용중인지 확인하고, TX를 하고, 
Collision을 어떻게 감지(Detection)하는지 혹은 피하는 기능(Avoid)이며, 이로 인하여, 여러 Device들이 MA(Multiple Access)하여 같이 통신하는 것이다. 


Layer 2의 CSMA/CD(유선) 와 CSMA/CA(무선) 차이
CSMA/CD(유선): 대표적인 것이 Ehternet 
CSMA/CA(무선):  대표적인 것이 WIFI 

Ethernet과 비교하면, 예전의 Dummy Hub를 사용할때의 구성과 현재 RS485 구성 얼추 비슷하게 보인다. 
RS485는 CSMA/CD를  Layer2 즉, RS485 Tranceiver에서 처리못하고, 이를 RS232를 걸쳐 SW로 처리 해야한다. 

  • Ethernet의 CD(Collision Detection)
Ethernet의 경우, 예전에 Dummy Hub에 Station을 연결하면 할 수록 속도는 떨어진다.
이유는 Station들간에  충돌나면, Volatage 변경되어 CD(Collision Detection)발생하고, 이 때문에, 
JAM 신호를 보내어 모든 Device를 멈추게 한다. 
그리고, 이런일이 반복되어지면, Backoff Time이 더 늘어난다.  
결론적으로 Station을 추가하면 추가할수록 Bus 속도는 기하급수적으로 늦어진다. 

  • RS485의 CD(Collision Detection) 다른이유 
RS485와 Ethernet 의 비슷하지만, Voltage기반으로는 Collision Detection을 하기가 힘들다 .(이유는 간단하다.)
RS485 Tranceiver Differential Range가 넓어서, Bus에서 각 Device 의 RS485 Tranceiver 마다 구동되는 VCC가 다를수 있다.
예를들면, 같은 RS485 Bus 내에서도, 어떤 Device는 Voltage 3.3v 사용하고, 어떤 Device Voltage 5v를 사용가능하다.
이를 특정 Voltage Thrshold Level 정해서 Collision Detection으로 하기가 힘든 구조이다. 
(물론 HW 보완해서 하면 얼마든지 가능하다)

  • RS485 와 Volatage Range(-12v/+12V)
RS485의 Differential Voltage Range가 넓은 이유는 거리때문일 것이라고 생각한다.
간단히 생각해보면, 거리가 길어질 수록 선로는 길어지며, 선로 저항값이 점점 늘어난다. 


2. ESP32 Modbus 구성 

  • Modbus 협회 사이트 
Modbus Main 협회사이트인 것 같은데, 주요 볼 것은 검색해서 나오는 링크일 것 같으며, Member로는 등록을 안했다. 
 
  • ESP32의 Modbus 관련정보 
ESP32의 Modbus 지원내용과 API 관련내용을 자세히 설명 


2.1  Modbus의 기본구성 

Modbus를 검색만 해도 너무 많은 자료가 나오는데, 검색된 블로그 들어가서 글을 읽으면, 
아래내용과 틀린부분이 있어, 아래의 2개의 링크를 추천 

  • Modbus의 Protocol 관련 링크 
Modbus의 Protocol 설명과 실제 예제 및 분석과 비교 까지 해주어서 괜찮음 

Modbus 기본적인 설명이 잘 정리되어있으나, 상위와 용어가 조금씩 다름 주의 


  • Modbus의 Object(Data) Types
Modbus는 아래의 4가지 Type으로 Data접근가능.
2byte 전송형태와 1bit 전송형태 구분
이는 Read Only 와 Read Write 로 나뉨
Object typeAccessSizeAddress Space
CoilRead-write1 bit0x0000 – 0xFFFF
Discrete inputRead-only1 bit0x0000 – 0xFFFF
Input registerRead-only16 bits0x0000 – 0xFFFF
Holding registerRead-write16 bits0x0000 – 0xFFFF

Modbus를 하기위해서는 상위 각 Object Type Address Map을 정의해야하며, 이기반으로 통신 
Modbus RTU/ASCII 이건 둘 다 Function Code 기본으로 상위 Read/Write  넣음 

Input register/ Holding Register Map 구현예제 


  • Modbus Frame Format
Modbus Frame은 아래 ADU(Application Data Unit)로 구성되며, 다시 PDU(Protocol Data Unit)구성형태이다.
  1. ADU = Address + PDU + Error check
  2. PDU = Function code + Data

2.2 Modbus Frame 종류

Modbus Frame 종류와 각 Physical Interface 관계는 아래와 같으며, 이를 기반으로 연결되어 통신을 한다.
주로 가장 많이 사용되어지는 것이 Modbus RTU 와 Modbus TCP 인 것으로 보이며, 
이 두 개를 연결 Mapping하여 Serial <-> Ethernet에서도 Control 할 수 있는 구조로 확장해서 사용하기도 한다. 

  • Modbus Frame 종류
  1. Modbus RTU : Serial (RS232/RS485) Binary 목적으로 개발 
  2. Modbus ASCII : Serial (RS232/RS485) ASCII 을 이용  
  3. Modbus TCP:  TCP Protocol이 지원되며, 이는 Modbus RTU와 연결도 가능 

상위 내용을 보면, Modbus ASCII 보다는 RTU가 더 효율적으로 보이며, Modbus TCP 호환으로 보아도 
Modbus RTU를 사용해야 할 것 같다. 
** 상위 링크에서 Modbus RTU 와 ASCII를 비교가능 



Modbus RTU와 구조는 유사하지만, Binary용 전송이아니라, 세부사항들이 조금씩 다르며, DATA 기본단위도 2byte단위
  1. Start는 0x3A End는 0x0D,0x0A 로 감지목적사용 
  2. Address는 Station Address로 2byte 사용하여 총 247까지 사용가능
  3. Function는  2byte Object Type 방식을 선택되어지는 것으로 각 Function에 따라 동작 
  4. 상위 Object Type 방식에 Address Space는 DATA에 포함되며 세부사항은 Format 참조

주의: Modbus RTU 와 동일한 Data를 전송할 경우, 항상 2배의 Data 량을 소비

Unit Address (PLC Address): 2byte
  1. Address: 0  Broadcast 목적
  2. Address: 1 ~247, 각 Station의 Address로 이며 Unit Address 이라고도 함  (1byte)
Modbus PDUMax 253x2 = 506bytes
  1. Function:  아래 Wiki 참조 
  2. Data: Function에서 결정되며, 2byte 단위로 Encode 되어진다고 한다.
LRC: 2byte Checksum 이며, CRC가 아님 

NameLength (bytes)Function
Start1Starts with colon : (ASCII hex value is 3A)
Address2Station address
Function2Indicates the function codes like read coils / inputs
Datan × 2Data + length will be filled depending on the message type
LRC2Checksum (Longitudinal redundancy check)
End2Carriage return – line feed (CR/LF) pair (ASCII values of 0D0A


  1. Start/End는 0으로 RTU Packet의 감지목적으로 사용 
  2. Address는 Modbus RTU Slave의 Station Address로 1byte허용하여 총 247까지 사용가능
  3. Function는 상위 Object Type 방식을 선택되어지는 것으로 각 Function에 따라 동작 
  4. 상위 Object Type 방식에 Address Space는 DATA에 포함되며 세부사항은 Format 참조

Unit Address (PLC Address): 1byte
  1. Address: 0  Broadcast 목적
  2. Address: 1 ~247, 각 Station의 Address로 이며 Unit Address 이라고도 함  (1byte)
Modbus PDUMax 253 bytes
  1. Function:  아래 Wiki 참조 
  2. Data: Function에서 결정
CRC: 2bytes

총 256 Bytes

NameLength (bits)Function
Start28[citation needed]At least 3½ character times of silence (mark condition)
Address8Station address
Function8Indicates the function code; e.g., read coils/holding registers
Datan × 8Data + length will be filled depending on the message type
CRC16Cyclic redundancy check
End28[citation needed]At least 3½ character times of silence between frames

** 주의 : 상위 Length는 Bits 단위


상위 Frame과 호환성을 가지기 위해서 Function code와 Unit Identifier로 구성되며, 이는 Modbus RTU와 쉽게 호환 
  1. Transaction ID는 상위 Start/End 목적처럼 Sync를 위한 감지목적 
  2. Protocol ID는 Modbus TCP는 0 
  3. Unit ID는 기존의 Stations Adddress
  4. Function는 상위 Object Type 방식을 선택되어지는 것으로 각 Function에 따라 동작 
  5. 상위 Object Type 방식에 Address Space는 DATA에 포함되며 세부사항은 Format 참조
  6. Modbus RTU over TCP의 경우, 아래의 CRC가 추가. 

Unit Identifier (PLC Address): 1byte
  1. Address: 0  Broadcast 목적
  2. Address: 1 ~247, 각 Station의 Address로 이며 Unit Address 이라고도 함  (1byte)
Modbus PDUMax 253 bytes
  1. Function:  아래 Wiki 참조 
  2. Data: Function에서 결정
CRC:  Modbus RTU over TCP에서 사용 

NameLength (bytes)Function
Transaction identifier2For synchronization between messages of server and client
Protocol identifier20 for Modbus/TCP
Length field2Number of remaining bytes in this frame
Unit identifier1Server address (255 if not used)
Function code1Function codes as in other variants
Data bytesnData as response or commands

* Modbus RTU over TCP의 경우 상위 끝에 CRC추가되어 Modbus RTU와 호환가능 

  • 상위 모든 정보는 Wiki기반으로 가져온것이며 세부내용은 아래 참조 
세부내용은 특히 Function 및 동작순서는 아래 Wiki에 너무 자세히 잘 나옴 


2.3 Modbus Request /Response  분석 

아래는 동일한 Station Address / Function / Data 이용하여 각 Frame 마다 전송비교 분석이며, 이를 쉽게 이해 할 수 있다. 

  • Read Input Register 예제 분석 
1. Request: Address 200 의 Size 2개의 Data 요청
2. Response : Size:4 byte 와 Data 2개 (0x2710, 0xC350) 

-------------------------------------------------------------------------------------------------------------------------------------
                Request	                                              |  Response
-------------------------------------------------------------------------------------------------------------------------------------                 
Modbus ASCII    3A                                                    | 3A                                                             // MODBUS ASCII START
                30 31                                                 | 30 31                         (ASCII:01)                      // Station Address 0 1 
                30 34                                                 | 30 34                         (ASCII:04)                      // Function  0 4  
                30 30 43 38 30 30 30 32 (ASCII:00C80002)              | 30 34 32 37 31 30 43 33 35 30 (ASCII:04 27 10 C3 50 )       // Data x 2byte 
                33 31                                                 | 41 44                                                          // LRC (Checksum)
                0D 0A	                                              | 0D 0A                                                          // END (CR/LF)
--------------------------------------------------------------------------------------------------------------------------------------
Modbus RTU	01 	                                              | 01                                                             // MODBUS RTU: Station Address(Unit) 1 
                04                  	                              | 04                                                             // Function 4 Read Input Register 
        	00 C8 00 02        Address: 200  Size:2x2             | 04 27 10 C3 50           (Byte:4, Data:2 words)                // Data x 1byte  (Size, Data 2 Words)
        	F0 35	                                              | A0 39                                                          // CRC
--------------------------------------------------------------------------------------------------------------------------------------
Modbus TCP	00 14                                                 | 00 14                                                          // MODBUS TCP: Transaction ID 2byte
          	00 00                                                 | 00 00                                                          // Protocol ID 2byte 
          	00 06                                                 | 00 07                                                          // Length  2byte 
                01                                                    | 01                                                             // Station Address(Unit) 1
                04          	                                      | 04                                                             // Function 4
                00 C8 00 02	   Address: 200  Size:2x2             | 04 27 10 C3 50                                                 // Data x 1 byte
---------------------------------------------------------------------------------------------------------------------------------------

상위예제는 Station(Unit) 1 주소로 Function 4의 Request/Resonse 구조로 보내는 Data는 동일하다. 
간단히 보면, ASCII로 보낼 경우, Packet Size가 두 배가 되어진다. 
Protocol을 보면, RTU 와 TCP는 쉽게 호환되어지는 구조이다. 


  • Modbus-RTU Write 와 Exception 확인
상위와 동일하게 아래를 참조하여 분석하면 된다.
Slave에서 에러가 발생하면, Response에서 Function Code 90h 과 함께 Exception Code가 별도로 존재 


3. Modbus TEST 방법 

다양한 Tool이 존재하지만 유료도 존재하여 나의 경우 Python 기반으로 테스트를 진행하였다.
  • libmodbus 와 PyModbus 이용


3.1 Python 기반의 Pymodbus TEST 방법 및 분석  

Python Pymodbus Manual
현재 나도 이기반으로 TEST Program들을 작성했으며, 다양한 예제가 있어 편하다.

  • PC에서 ModbusTCP/RTU/ASCII Slave 테스트
PC가 Modbus Master가 되어 IOT (Modbus Slave) 테스트 할 경우 소스이며 각 Function에 관련된 함수에 따라 각각의 테스트 가능 
  1. 상위 read/write coill 및 read only discreate input 테스트 가능 (1bit)
  2. 상위 read/write holding register 및 read only input register 테스트 가능 (2byte)

보통의 경우, sync용 예제를 봐야하며, async의 경우는 빠르게 보내는 경우에 사용되어진다고 보면될꺼 같다.
내 생각으로는 sync 와 async의 차이는 아래라고 하는데 추후 다시 확인해야하겠지만, blocking 과  non-blocking 의 차이라고 생각되어짐 
기본적으로 Unix System programing or network programing 알면 대충 이해가 되실듯함 
  1. sync : request 와 responce를  각 확인 인 되어 동작 (blocking mode) 일 것 같음 
  2. async: request하고 response는  그냥 blocking 없이 동작 (non blocking mode) 일 것 같음 

# 간단하게 이런식으로 연결후 원하는 정보를 읽어서 확인하면 된다 
# pip install pymodbus 

from pymodbus.client.sync import ModbusSerialClient

def run_sync_client():
    
    client = ModbusSerialClient(
        method='rtu',
        port=Port,
        baudrate=Baud,
        timeout=3,
        parity='N',
        stopbits=1,
        bytesize=8
    )
    if client.connect(): 
        print('connected to Modbus Slave UNIT=',UNIT)
    else:
        print('failed to connect to the Modbus Slave UNIT=',UNIT)
    


  • PC의 PayloadBuilder 와 PayloadDecoder 사용 및 확인이유  
Holding Register와 Input Register는 기본적으로 2byte 통신이므로 Byte Order과 Word Order가 따라 결과 값이 달라질 수 있다. 
  1. Byte Order: BigEndian/ Little Endian : CPU에 종속됨 (Word의 저장되는 순서)
  2. Word Order: Big Endian / Little Endian:  소스에서 확인해봐야함
PayloadBuild의 경우 Slave도 Write를 할 경우가 발생하는데, 이때 Holding Register를 이용하여 Write할 때 필요 
PayloadDecoder의 경우 이를 다시 Decode를 할 경우 사용 

PayloadBuilder 예제 (주로 write시 사용)
2byte단위 통신이므로 다양한 포맷으로 변경 및 추가하여 이를 Packet 생성 

PayloadDecoder 예제 (주로 read시 사용)
2byte 단위 통신이므로 다른 포맷으로 변환시 사용 


ESP32의 내부 Ordering 확인사항 
사실 Word Order는 u16을 u32로 확장할 경우, 문제가 발생하는 것으로 보인다. (기본 32bit CPU의 word는 4byte)
예를들면 struct로 u16로 두개로 잡은 후에 이를 u16 pointer에서 u32로 변경할 경우 u16의 두개가 위치, 즉 address를  확인해야함
modbus 내부 api에서 변경할 가능성도 있으므로 이는 상위 wiki 세부확인

ESP32의 경우 내부적으로 분석해보면, ESP32의 경우 Bigendian 혹 정확히 말하며 Binary로 보내는게 맞다.   
이는 아래와 같이 Data 영역에 Byte Align으로 Data를 저장하여 이를 Memory 접근한다.

Byte Align 방법 
아래의 preprocessor로 1 byte align을 하여 byte ordering에 상관없이 사용하고 있다. 
#pragma pack(push, 1)
typedef struct
{
...
}...
#pragma pack(pop)

  • PC의 PayloadDecoder 결론사항 
PyModbus에서 입장에서 Byte OderBigEndian Word OrderLittel Endian으로 해야 Float32가 제대로 보인다 
개인생각으로는 PyModbus가 받은 Data를 함수내에 Stack영역에 저장하여 발생되어지는 문제로 생각되어진다.
u16->f32을 확장할 경우 PC(Program Counter) 의 Address 가 위로 증가 할지, 아래로 증가할지는 각 영역(Stack/BSS/Init)에 따라 달라진다 

현재 이 부분은 현재 PyModbus가 Data 저장을 Stack영역에 저장하여 상위와 같은 현상이 발생되어지는 것으로 생각되어진다. 


TEST Program 확인사항
상위를 먼저확인 후 Builder를 이용하여 u32으로 register를 write 한 후 decoder로 이를 재확인필요


ESP32의 Core Cadence의 Tensilica (Xtensa LX6) 


Xtensa 의 ABI (너무 간단하게만 나오며, 함수와 ELF 관련내용)
혹시 몰라 Xtensa의 ABI도 링크함, 
ARM이나, Power PC에 비해 너무 간단하게 나오며, 아마 다른문서가 있을 거라고 생각됨
일단, 간단하게만 알고나 있도록하자.  

8/30/2021

RS485 Modbus 와 SCADA 시스템

1. Modbus 와 SCADA 시스템

Modbus는 Modicon에서 처음 개발한 Protocol로 주로 Serial (RS485/RS232/RS422)와 TCP를 이용하여 사용되어지는 Protcol 이다. 
대체적으로 보면 Modbus의 이용은 SCADA(Supervisory control and data acquisition)기반의 Platform 동작되는 것으로 보인다.

물론 유저에 따라 다르게 사용가능 할 것이며, 일단 SCADA의 기본구조부터 알아보자. 
Serial (RS485/RS232/RS422)기반으로 Modbus를 처음 사용해보며, 
주로 SCADA에서 쓰임새를 보니, PLC를 제어하기 위해서 사용하는 것 같다. 

  • SCADA의 시스템구조 
중앙 컴퓨터에서 명령을 내리고 DATA를 얻어오는 구조이며, 각각의 Level을 부여하여 동작되어진다.
이곳에서는 Modbus이외 MQTT를 비롯하여, TCP/IP기반의 Protocol도 지원이 된다. 
Modbus 관점에서 보면, Modbus의 기본구조는 Master / Slave 구조이기 때문에, 
상위 Layer가 Master가 되고 하위 Layer가 Slave가 되는 구조인 것 같다. 

https://en.wikipedia.org/wiki/SCADA

중간 Level 2~3의 경우 경우에 따라 생략가능하며, 최종 Center 시스템으로도 Control이 가능할 것 같으며 상위 구조는 대규모 Control를 위한 구조 
상위 Level 1이 실제 Modbus RTU로 IoT 혹은 최종 Device로 구성 

SCADA

  • SCADA의 구성 예제 
실제 SCADA의 내부 세부 구성을 비롯하여, 관련부분을 이해하기에 너무 좋은 사이트 인 것 같다.
SCADA 솔루션을 제공하는 것으로 보이며, Modbus ,MQTT 관련 설명 Index


1.1 SCADA의 실제 Modbus 구성 

상위 구성처럼 상위 Center Computer가 존재하며, 이를 Modbus TCP로 쉽게 제어를 하려고 한다.
중앙컴퓨터는 Modbus TCP Slave 와 통신하며, 중간 Bridge Device는 이를 Modbus RTU로 변경하여 보내준다.

  • SCADA (중앙시스템)
  • Modbus RTU Slave (RS485/RS232로 연결)
  • Modbus TCP Master
  • Modbus TCP Slave
  • Modbus RTU Master
  • Modbus RTU Slave (각 장비)


http://www.epnc.co.kr/news/articleView.html?idxno=73320


  • Gateway의 동작 - Modbus TCP와 Modbus RTU의 Portmapping 
각 Gateway역할은 Modbus RTU Master 와  Modbus TCP Slave와 Port Map이 되어 동작 
http://www.epnc.co.kr/news/articleView.html?idxno=73320


  • Gateway의 구성 및 문제사항
아래와 같이 직접 Portmapping 후 구현이 되면, Gateway는 각 Message를 Forward만 하면 되지만, 문제가 발생하는데, 바로 Timeout 과 수신여부 일 것 같다.

https://www.epnc.co.kr/news/articleView.html?idxno=73320


상위와 다르게 Gateway에 내부 메모리가 존재하며, TCP로 받아서 Gateway에 지속적으로 쿼리하는 방식이라고 한다.
https://www.epnc.co.kr/news/articleView.html?idxno=73320


SCADA의 Modbus구조 및 시스템설계방법
상위그림 및 내용은 아래 글에서 가져왔으며, 자세한 설명이 되어있어 너무 감사하다.


2. ESP32 RS485 와 Modbus 

ESP32에서 아래와 같이 Modbus RTU의 Master 와 Slave를 지원해주고 있으며, 관련 회로도 구성 및 Example들을 제공해주고 있다. 



2.1 RS232 와 FlowControl 

ESP32에서 RS232만 지원하므로, 일단 RS232에서 기본 동작들을 알아보자. 
RS232 RTS 정보와 동작만 알면될 것 같다. 

  • RS232 RTS/CTS (Flow Control, 수신버퍼)
  1. RTS (Request to Send): Output, 본인의 수신버퍼의 상태
  2. CTS (Clear to Send): Input, 상대방의 수신버퍼의 상태 
Serial 통신이나보니, Flow Control에서 주요한게 Buffer이며, 본인의 수신버퍼의 상태를 확인한다. 

  • RS232 DRT/DSR (Flow Control, 송신버퍼)
  1. DTR (Data Terminal Ready), Output, 나의 통신준비 확인 
  2. DSR (Data Set Ready), Input, 상대방 통신준비 확인

RS232 FlowControl 및 관련자료 
RS232의 Flow Control에 대해 너무 잘 설명해주고 있어 감사하다

RS485 diffrential 파형 과 IC의 구조 
RS455 Transceiver 구조와 differential 나가는 신호 처리 부분과 Noise 처리부분 (Refection/Terminal Registor) 


2.2 RS232 와 RS485 연결구성  

ESP32와 RS485로 구성시 RS232와 RS485의 Transeiver를 구성회로도는 아래와 같이 2가지로 제공되며,
기본으로 연결방법-A 기반으로 상위 Example을 제공하고 있다. 
그 구성에 대해 간단히 알아보도록 하자. 

  • RS232-RS485 연결방법-A  
출력은 일반적인 Differential 로 나가는것로 확인되며 관련 회로도 및 관련내용 참조 
  

         VCC ---------------+                               +--------------- VCC
                            |                               |
                    +-------x-------+               +-------x-------+
         RXD <------| RO            | DIFFERENTIAL  |             RO|-----> RXD
                    |              B|---------------|B              |
         TXD ------>| DI   MAX485   |    \  /       |    MAX485   DI|<----- TXD
ESP32 WROVER KIT 1  |               |   RS-485 side |               |    Modbus master
         RTS --+--->| DE            |    /  \       |             DE|---+       
               |    |              A|---------------|A              |   |
               +----| /RE           |    PAIR       |            /RE|---+-- RTS
                    +-------x--------+              +-------x-------+
                            |                               |
                           ---                             --- 


** UART 와 RS485 Transeiver 연결 
RTS(Request To Send)  - DE  (Driver  Enable)  (TX 할 경우)
                       /RE  (Reciver Enable)  (RX 할 경우)  

RTS에 신호에 따라 DE 와 /RE 중 하나만 Enable되는 구조이며, CD를 못한다고 한다.

ESP32의 RS485관련 내부설정 
RS232 register로 설정하여 동작되는걸로 확인

ESP32의 RS232 와 RS485 Transeiver 충돌감지(CD) 없음 
정상적인 RS485의 Half duplex 구조로 TX or RX만 둘 중 하나만 ON되며, RTS는 ESP32의 상위 RS485 설정에서조절 (상위 회로도와 동일) 



  • RS232->RS485 연결방법-B 
현재 이 부분은 ESP32에서 테스트용(only TEST)으로만 지원하며, CD(Collision Dection)이 가능하다고 한다. 
  
        VCC ---------------+
                           |
                   +-------x-------+
        RXD <------| R             |
                   |              B|----------<> B
        TXD ------>| D    ADM483   |
ESP                |               |     RS485 bus side
        RTS ------>| DE            |
                   |              A|----------<> A
              +----| /RE           |
              |    +-------x-------+
              |            |
             GND          GND             
** UART 와 RS485 Transeiver 연결 
RTS(Request To Send)  - DE  (Driver  Enable)  (TX 할 경우)
                       /RE  (Reciver Enable)  (RX는 항상 on)  

ESP32의 RS232 와 RS485 Transeiver 충돌감지(CD) 존재
현재 이방법을 왜 사용하는지 정확히 이해를 못하지만, Receive는 항상 On이 되므로, 
Half duplex의 경우 문제 발생요지가 있을지도 모르겠다. (Data가 TX or RX 만되어야 하므로) 
하지만 결론적으로 RS485 Transeiver 자체가 Half duplex이므로, TX 와 RX 동시 껴질경우에 Master가 아닌 다른 Device 가 통신 중 일때가 궁금하다. 
즉, 각 Device들이 RS485 Transeiver를 통해 CS(Carrier Sense)가 되는지가 궁금하다. 

RS485의 충돌감지(CD)에 대해 아래링크에서 간단히 설명해주고 있는데, 원리는 다음과 같다고 한다. 
  1. Device가 TX로 보낸 Data도 RX를 On하여 받아서 DATA 동일하면, 정상동작
  2. Device가 TX로 보낸 Data도 RX를 On하여 받지 못할 경우는 충돌이라고 생각 
가만히 생각해보면, Ethernet의 JAM 과 거의 유사할 것 같으며, Voltage 변화로 인해 충돌을 감지할 걸로 예상하지만, RS485는 이를 SW로 구현해야함
상위 궁금증은 기본적으로 해결되어진 것 같으나, 문제는 이를 Ethernet 처럼 HW가 아닌 SW로 해야한다는 것이다.
이런식이면, Ethernet 처럼 CSMA/CD도 RS485에서 SW로 충분히 구현가능할 것 같기도 하지만 골치아프다. 
예를들면, RS232 Reciver가 Data가 들어오면, CS(Carreir Sense)를 기능이 되어 TX를 멈추고,대기, CD는 상위와 같이 SW로 DATA를 비교하면 될 것 같다. 

현재 ESP32의 RS485 SW는 충돌감지(CD)의 경우 오직 테스트용만 지원 (주의) 


2.3 RS232/RS485  통신속도 와 에러율 

일단 RS232 기준으로 Baudrate 와 Bps는 동일하지만 UART에는 Start/Stop Bit가 존재한다.
옵션에 따라 Parity Bit도 존재하지만 잘 사용하지 않는다. (UART Protocol 참조)

좀 더 나아가 RS232 와 RS485는 거의 Async 기반으로 사용하므로 에러율이 좀 더 많아진다.
이유는 내부 Clock과 실제 Data 받은 것과 Timing 오차가 시간이 지나면서 발생하다.

  • Baudrate 의 통신속도 차이발생(Actual Speed)   
Baudrate 와 Bps(Bit Per Second) 와 일치하지만, 실제 전송속도와는 일치하지 않으므로 주의
아래의 기반으로 Bandwith 점유율(Share Rate)를 본인 직접 만들어서 확인가능하다.


  • RS232/RS485 의 통신 에러율(Error rate)  
HW 통신에서 항상 나중에 확인해야 할 것이 에러율이라고 봐야할 것 같다.  
Ethernet도 통신에러율이 존재하며, 관련부분은 검색하면 알수 있다. 
Async 기반의 Serial 통신이므로, 기본적으로 Sync 통신보다 에러율이 높을 수 밖에 없다.

ESP32도 아래와 같이 Baudrate가 딱 떨어지지 않을 것이므로, 간단히 계산가능하다.

각 Baudrate와 Clock 부분관련한 통신에러율 과 Baudrate 설정 부분관련사항이다.