반년쯤 전에 기차를 이용해 레이스 컨디션을 극복하는 방법을 생각한 적이 있는데

최근에 기차의 힘을 빌리지 않고도 기깔나게 이 문제를 해결할 수 있는 방법이 생각이 나서 한번 만들어 보았다




각 마스터들은 각자 고유의 ID값을 가지고 있음

이건 뭐 수동으로 지정해주든 전역 네트워크로 잘 할당을 하든 아니면 기차의 고유ID값을 끌어다 쓰든 여러가지 방법이 있을 수 있는데 이건 이 글에서 다루고자 하는 주제와는 멀기 때문에 자세한 설명은 생략

위 영상에서는 6개의 마스터에 1~6의 고유 아이디를 수동으로 할당해 줬음


고유 ID를 지정해서 레이스 컨디션을 해결하는 방안은 예전에도 있었는데 ,

여러개의 마스터가 동시에 전역네트워크(이하 버스라고 표현함)를 사용하고자 하면 일단 전역네트워크에 내가 버스를 점유를 내보내고 싶다는 신호를 1 보내고

이 신호값을 다시 읽어서 값이 1이라면 버스 할당을 요청하는것이 자신 혼자이므로 버스를 그냥 사용하면 되고

만약 값이 2이상이라면 다른 누군가가 동시에 버스를 사용하고자 하는것이므로 자신이 포기하거나 아니면 다른 마스터가 포기할 때 까지 대기하다가 값이 1이 되면 그때 버스를 점유하고 사용하는 방식을 사용할 수 있음


문제는 버스를 포기하는 조건이 무엇인가 인데, 그냥 일정한 상수틱만큼 대기하고 포기하는 식으로 한다면 여러개의 마스터가 동시에 요청-동시에 포기-동시에 요청- 동시에 포기를 반복하는 불상사가 있을 수 있기 때문에 각 마스터는 서로 포기하는 시점이 달라야만 이런 현상을 회피할 수 있음

그래서 고유ID가 나오는 것이고 자신의 고유 ID에 해당하는 tick수를 대기한 후에 포기하면 이러한 현상을 벗어날 수 있다

다만 단점이 있다면 고유 ID값이 132,752,233 이런식의 큰 값이라면 이 포기하는 시간이 밑도 끝도 없이 늘어난다는 점이다


위 내용은 이전 글에서도 쓴 내용이고 이 글에서도 버스를 사용하는게 혼자인지 확인하는 부분이라던지, ID를 이용해서 적절한 타이밍에 버스를 포기한다던지 한다는 점은 위에서 설명한것과 같음

차이점은 버스를 포기하는 타이밍인데, ID값을 어떤 것을 사용하든지간에 O(1)의 시간, 좀 더 구체적으로는 1.5초 안에 위 동작을 수행할 수 있는 방법임




버스 획득의 승자를 판별하기 위해서 각 마스터는 매 클럭마다 자신의 ID 값을 2진법으로 바꿔서 1bit씩 출력을 하고 있는 모습임

ID가 6인 마스터는 자신의 아이디가 이진법으로 0110때문에 출력으로 0 1 1 0 을 여러 클럭에 걸쳐서 내보내고 있고 다른 마스터도 이와 동일함

그럼 버스에는 각 마스터가 1을 출력으로 내보낸 애들을 모아 이걸 더한 값이 회로에 올라가게 된다(Bus-numeric 참고)


각 마스터는 이렇게 1비트씩 값을 출력하고 그와 동시에 현재 버스에 올라간 값이 무엇인지 다시 읽어보게 되는데 이때는 bus의 수치값이 중요한게 아니라 논리값이 중요함

버스의 값이 0이면 false인거고 0이 아닌 무언가라면(1이든 2든 3이든...) true인 것이다


버스의 값을 읽을 때는 아래와 같은 4가지 상황이 발생할 수 있음

1. 만약 내가 1을 내보내고 있는데 버스의 값이 false이다 -> 내가 값을 출력하고 있는데 이런일은 절대 발생하지 않으니 pass

2. 만약 내가 1을 내보내고 있는데 버스의 값이 true이다 -> pass

3. 만약 내가 0을 내보내고 있는데 버스의 값이 fasle이다 -> pass

4. 만약 내가 0을 내보내고 있는데 버스의 값이 true이다 -> 이 경우는 나 말고 누군가가 버스 권한 획득을 시도하고 있는 것이다


만약 2,3번 상황이라면 계속 해서 ID를 1bit씩 출력하는 작업을 지속하면 됨

근데 4번 상황이라면 그 마스터는 버스 권한 획득 경쟁에서 패배한 것이라고 보면 된다.

이 경우에는 ID 1bit씩 출력하는 작업을 포기한다(남은 ID의 비트들이 1이든 0이든 출력을 0으로 고정)


이렇게 동작 메커니즘을 규정하고 타이밍 다이어그램을 다시 그리면 아래와 같음




Time:1일 때 모두가 0을 내보내고 있고 Bus(logical)값도 false이기 때문에 다음 비트로 넘어감

Time:2일 때 ID가 1,2,3인 애들은 자기 자신이 출력을 0으로 내보내고 있음에도 불구하고 Bus(logical)값은 true인 것을 확인하게 되고 버스에서 손을 놓음

Time:3일 때 ID가 4,5인 애들은 자기 자신이 출력을 0으로 내보내고 있음에도 불구하고 Bus(logical)값은 true인 것을 확인하게 되고 버스에서 손을 놓음

Time:4일 때 ID가 6인 애는 자기 자신 출력을 0으로 내보내고 있고 Bus(logical)값도 false임. 다음으로 넘어가

Time:5일 때 ID가 6인 애는 자기 자신 ID를 모두 출력할 동안 단 한번의 에러도 발생하지 않았기 때문에 최종승자가 되고 버스 권한을 획득함


나중에 버스 권한을 획득한 ID 6 마스터가 모든 볼일을 끝마치고 버스에서 손을 때면 다시 위와 같은 과정을 반복하여 새롭게 권한을 획득할 마스터를 선출하는 작업을 반복한다.


이 싸움은 모두가 동등한 조건으로 하는 것이 아닌 ID값이 큰 애들일 수록 우선권을 가진다는 특징이 있는데

이를 활용하면 LTN 네트워크에서 우선순위를 지정하는 것과 유사한 동작을 할 수도 있을 것으로 보임


위와 같은 방식으로 멀티 마스터 환경에서 단 하나의 마스터만 동작을 하게 하는 것은 I2C 프로토콜이라는 것에서 사용하는 것을 볼 수 있는데 이건 링크로 대체함


https://igotit.tistory.com/entry/I2C-Bus-%EA%B8%B0%EB%B3%B8%EA%B0%9C%EB%85%90

I2C Bus 기본개념.I2C 개요 I2C Bus 양방향 2선통신 규격. 2선의 구성 : SDA 데이터, SCL 클럭. 2선은 풀업저항으로 VDD에 연결되어야 한다. 데이터 전송은 bus 상태가 busy가 아닐때 시작가능하며, non busy 상태란 SCL, SDA 모두 High 인경우다. I2C 규격문서 : UM10204 I2C-bus specification and User Manual from http://nxp.com/ I2C Bus 결선 예. I2C Bus 풀업저항 결정. 위 그림의 I2C 버스의 풀업저항 Rp 값을 결정하기 위해서는 VDD, bus speed, bus capacitance 3가지 변수에 의하여 결정되어야한다. 이에 대한 완전한 설명과 계산식을 구할려면 UM10204 I2C bus specificati..igotit.tistory.com

https://blog.naver.com/specialist0/220645221966

I2C 통신 프로토콜I2C(IIC, TWI) 통신 프로토콜(protocol)에 대해 알아보겠습니다. I2C 버스는 SDA(Serial Da...blog.naver.com


이 글의 아이디어도 저 프로토콜에서 따온거고 차이점이 있다면 I2C는 아무도 출력을 안할때 기본값이 1이고, 팩토리오에서는 0이라는점. 이것 빼고는 그냥 똑같은 원리라고 봐도 무방하다



그래서 이걸 팩토리오로 구현한게 아래의 회로


전체 전경





하나의 마스터의 모습

좀 복잡해 보일 수 있는데 이건 시각적인 요소를 위한 회로 때문에 그렇고 진짜 필요한 부분만 남기면 아래와 같음




이번 글에는 회로를 디테일하게 설명할 자신이 없어서 좀 간략하게 설명하려고 함

Latch는 S 신호가 들어오면 권한 요청을 시작하고, G신호(버스쪽에서 들어옴)가 들어오면 권한을 획득하고 동작을 시작한다음, 동작이 끝나서 R신호가 나오면 버스 쪽 점유를 푸는 회로임


ID할당은 각 마스터마다 고유 ID값을 입력해주고 있음

옆에 있는 비교기에서는 S가 1일 때만 ID값을 통과시켜줌


ID sync는 버스 획득 경기를 시작할 때 ID값을 갱신시켜주는 역할임. 만약 한창 버스 경쟁을 하고 있는데 새로운 선수 마스터가 생기면 꼬일 수 있기 때문에 이를 방지해줌


ID shifter는 ID의 값을 가장 높은 자리수의 비트부터 1bit씩 차례대로 추출해줌


1bit 출력은 전역 버스쪽으로 ID 1bit값을 내보내주고 있는데 지금까지 fault가 단 한번도 발생하지 않았을 때만 버스로 내보낼 수 있도록 F=0 조건이 걸려있음


Fault detector는 만약 내가 0을 내보냈는데 버스에서 읽은 값은 true일 경우, 이를 fault로 간주하고 F값을 늘려줌


Grant는 모든 bit 전송이 끝난 후 전역 버스 쪽에서 G 신호가 들어오는데 이 값을 F=0일 때만 통과시켜줌




Arbiter의 모습

버스를 획득하고자 하는 마스터가 있을 경우

그리고 아무도 버스를 점유하고있지 않을 경우

그리고 아비터 상태가 IDLE한 경우

이 3가지 조건을 만족할 경우 동작하기 시작하는데, 버스에 N이라는 신호를 공급해주는 회로임

여기서 나오는 N값을 보고 각 마스터는 이 신호에 동기화 되어 N비트 자리에 해당하는 ID bit를 내보내 준다

모든 비트 출력이 끝나고 G 신호를 내보내 주는 것도 이쪽


지금 위 움짤에서는 N이 0~71까지 가는데 실제로는 이걸 절반으로 나눠서 0~31까지의 신호가 버스로 나감

아까 위에서 각 마스터는 버스로 출력을 내보내고 이 값이 유효한지 검사하는 과정을 거친다고 했는데 이게 1tick만에 수행할 수는 없고 2tick은 걸리는 작업이라 N도 2tick 마다 1씩 증가함

0 0 1 1 2 2 .... 31 31 이렇게

ID가 32bit이기 때문에 ID 체크에만 32*2=64tick이 소요되고, 안정성을 위해 좀 더 기타 등등 마진을 준 것도 있어서 한번 동작에 72tick을 소요함. 1.5초 이내 컷




위의 마스터 설명에서 생략됐던 부분인데

Status monitor는 권한 요청을 시작해서 S=1 상태면 빨간불을 띄우고 권한을 획득해서 G=1상태면 초록불을 띄워줌

Auto resetter는 일일히 권한해제 하기 귀찮아서 임시로 달아둔 회로임. 권한 획득하고 32틱정도 지나면 스스로 권한 해제(R=1)를 시켜줌

bit viewer는 여러 틱에 걸쳐 출력 bit가 변화하는걸 시각화하기 달아둔 회로



버스쪽에도 모니터가 달려있는데

B는 권한을 획득한 마스터가 있다는 뜻

A는 마스터들의 출력하는 ID bit의 합. 0이면 false 0이 아니면 true

S는 권한획득을 요청하고 있는 마스터들의 수

N는 아비터에서 나오는 싱크 제어용 값(0~31)

G는 아비터에서 나오는 권한 부여 신호(N이 한바퀴 돌고 난 후 단 1tick만 뜨는 신호)





문자열 : https://factoriobin.com/post/md373x_x

Nixie tube, Connection box, Push button 모드 있어야 함




이제 이걸로 바닐라LTN 만들다가 유기하다가 만들다가 유기하다가 반복하던거 마저 해보고는 싶은데 그게 언제가 될지는 모르겠다