Open Source 기반 FLCC-HILS 환경 구축

  간만의 글이다.
  이번엔 오픈소스기반의 소프트웨어들을 이용해 FLCC (Flight Control Computer) 하드웨어를 적용한 HILS (Hardware In the Loop Simulation) 환경을 구축해 간단한 항공기 제어를 해봤다.
용어가 생소한 분을 위해 간략히 소개를 하자면 FLCC는 조종사의 스틱 명령을 전달 받아 Actuator를 이용해 항공기의 조종면을 움직이는 명령을 생성하고 때에 따라서는 Autopilot 기능을 수행하거나 항공기의 안정적인 자세제어를 위한 역할을 수행하기도 한다. 컴퓨터로 제어하는 요즘 항공기에는 대부분 들어가게 되며 Fly-By-Wire 시스템을 위한 중요한 요소이다.
HILS는 시뮬레이션 환경을 말한다. 시뮬레이션이라면 소프트웨어 기반으로만 생각 할 수 있으나 실제 장착되는 장비를 시뮬레이션 루프안에 포함시켜 실제 하드웨어 장비의 동작을 검증하기 위한 목적으로 수행하기도 하는데  이를 HILS라 부른다.
  우선 사용한 오픈소스 및 적용 하드웨어는 다음과 같다.

  - FDM         : JSBSim
  - Visualizer  : FlightGear
  - Application : QT
  - FLCC RTOS   : Embedded Linux-Xenomai
  - FLCC H/W    : PXA270 (ARMv5, 520MHz)
  - Comm.       : Realtime Ethernet (UDP/IP)

  각 부분별 소프트웨어 소개를 잠깐 하자면 JSBSim은 항공기 공력 시뮬레이션을 위한 물리엔진이다. 흔히 FDM (Flight Dynamic Model)이라고 하는데 항공기의 공력 파라미터인 무게, 관성, 양력계수, 항력계수 등을 xml형태로 전달 하고 항공기 제어 파라미터인 엔진 추력, 조종면 위치 각등을 입력하면 항공기의 속도, 위치, 고도, 자세등을 알려주는 오픈소스 기반 소프트웨어 이다.
  FlightGear는 3D 가시화 툴로 JSBSim에서 출력된 비행체 정보를 바탕으로 지리정보 (GIS - Geographic Information System)와 함께 지형지물과 항공기, HUD등을 그려주는 역할을 한다. JSBSim 자체는 이런 가시화 툴을 제공하지 않기에 항공기 제어 결과를 3D 그래픽으로 확인 하고자 한다면 필요한 툴이다. 역시 오픈소스이며 전세계 공항 정보와 많은 항공기 모델을 가지고 있다.
FlightGear를 설치하면 JSBSim도 같이 설치되며 별도 지정을 하지 않으면 JSBSim을 기본 FDM으로 사용하게 된다. FlightGear와 연동하여 사용 가능한 FDM은 JSBSim 말고도 YASim이 있는데 둘의 차이라면 JSBSim은 항공기의 양력계수, 항력계수등 공력 파라미터를 입력 받는 반면 YASim은 항공기의 기하학 (Geometric) 정보인 날개 면적, 코드 길이, 조종면 면적, 동체 길이등을 직접 입력 받아 공력 물리엔진 연산을 수행한다.
  QT는 그래픽 어플리케이션 개발용 라이브러리이며 역시 오픈소스이다. IDE 기능까지 포함하고 있어 MS의 비주얼 스튜디오와 같다고 보면 된다. 그러나 윈도우즈 뿐만 아니라 리눅스나 맥 OS에서도 사용 가능하며 심지어 리눅스기반의 임베디드 시스템에도 포팅하여 사용 가능하다. 꼭 그랙픽 관련 어플리케이션 뿐만 아니라 콘솔 기반 응용 프로그램도 작성 가능하다. 그래픽관련 라이브러리 뿐만 아니라 Multi-thread, Network등 많은, 그리고 유용한 라이브러리도 제공한다.
QT를 소개하는 이유는 FLCC측 비행 제어 어플리케이션 개발시 처음부터 FLCC하드웨어를 사용하지 않고 FlightGear가 동작하는 호스트 PC에서 Native 개발 환경으로 빠르게 동작 확인을 해볼 수 있다는 점 때문이다.
Native 개발 환경에서 동작이 확인 되면 별다른 소스 수정없이 바로 FLCC 타겟에 사용 가능 하다. 물론 Native OS가 비실시간 운영체제라면 실시간 태스크 관련 코드는 수정이 좀 필요할 것이다.
  마지막으로 FLCC 하드웨어에서 사용할 RTOS인 Xenomai이다.
리눅스 기반의 실시간 커널 패치로 이전 글에서 많이 소개 되었다.
항공기 실시간 제어를 위해 FLCC 하드웨어에는 Embedded Linux-Xenomai를 사용했다.

  항공기를 제어 시뮬레이션을 수행 하려면 FDM으로 부터 계산된(시뮬레이션된) 항공기 자세정보가 필요하며 제어 루프에 의해 계산된 출력물인 엔진 추력, 조종면 각도값은 다시 FDM으로 주입하여 일련의 되먹임 (Feedback) 제어루프가 형성 되어야 한다.
다행히 FlightGear에는 UDP/IP 및 RS-232통신라인을 이용해 이런 일련의 데이터 흐름을 만들 수 있는 기능이 있다.
해외 자료들 뒤져 보니 실 기체 개발시 HILS용으로 FlightGear를 많이 사용하는가 보다.
제어 루프는 RTOS기반의 FLCC 하드웨어에서 수행 하도록 구성하면 된다.
  전체 시스템 구성을 보자면 아래 그림과 같다.

[그림 1] Native 시뮬레이션 환경


[그림 2] FLCC-HILS 환경

  사용한 FLCC 하드웨어는 일전에 EtherCONN 개발시 사용한 PXA270기반 보드를 사용했다 (링크참조).
Linux-Xenomai가 이미 포팅되어 있고 UDP/IP 통신을 위한 Ethernet용 실시간 디바이스 드라이버 (RTDM)가 만들어져 있으니 바로 활용 가능 하였다.
  개발시에는 [그림 1]과 같이 Native 환경에서 개발을 진행 하고 얼추 결과가 나오면 [그림 2]와 같이 실제 FLCC 하드웨어에 제어 코드를 이식해 사용 하면 된다.
  HILS 환경을 구축하고 간단하게 항공기의 롤 및 피치 제어용 Auto-pilot을 구현해 돌려 봤다. 아래 동영상 결과는 실제 FLCC 하드웨어로 제어하는 모습이다.




[영상 1] Roll/Pitch Auto-pilot Off


[영상 2] Roll/Pitch Auto-pilot On


[영상 3] Roll/Pitch Auto-pilot Off/On

  [영상 1]은 롤/피치 제어용 Auto-pilot기능이 없는 순수 비행 화면이다.
비행 조종은 게임 패드의 조이스틱을 사용했으며 트림을 사용하지 않고 조종하는 모습이다.
조종사가 아니다 보니 항공기 조종하는게 생각 보다 어렵다.
  [영상 2]는 롤/피치 제어용 Auto-pilot의 도움을 받아 비행하는 모습니다. 아케이드 게임하는 것처럼 조종하기가 참 수월해진다.
  [영상 3]은 롤/피치 제어용 Auto-pilot 기능을 on/off를 반복하면서 동작 상태를 관찰하는 모습이다.

2015/06/21~06/24 괌여행

메르스를 피해 괌으로 도피했다.
리티디안 해변은 지금까지 본 바다중에 가장 인상 깊은 곳이었다.











자작 USB-JTAG과 OpenOCD 연동

  상용품 보드 리버스 엔지니어링시 JTAG 연결이 필요한데 자작한 USB-JTAG을 주로 사용한다.
  두개를 만들었었는데 첫번째 USB-JTAG은 USB 클라이언트 칩을 이용해 윈도우즈용 디바이스 드라이버까지 제작해 사용 했었다. 단점이라면 USB 1.1을 사용해 속도가 느리고 OS가 바뀔때마다 디바이스 드라이버를 다시 만들어야 한다. 그 때는 32비트 Windows XP용으로 드라이버를 만들어 사용했는데 운영체제를 64bit Windows 7으로 바꾸면서 무용지물이 되었다.
Windows 7에서는 디바이스 드라이버를 만들어 정식으로 사용하려면 M$에 돈을 내야 된다나 뭐라나... 요놈은 Linux용 드라이버 만들어서 Linux에서만 사용해야 겠다.

[첫번째 자작 USB-JTAG]

[두번째 자작 USB-JTAG]

  두번째 USB-JTAG은 USB-RS232 컨버터를 내장시켜 해당 USB 컨버터 회사에서 제공하는 드라이버를 사용하고 운영체제에서는 시리얼 터미널로 연결해 사용했다. 속도 증대를 위해 TMS320F2812를 적용했는데 내장된 SPI엔진을 JTAG용으로 사용하면서 속도가 무지 빨라졌었다. 원래 SPI 통신과 JTAG 통신은 다르지만 어느 속도 까지는 사용이 가능하다.
  SoC마다 차이가 좀 있지만 ARM9TDMI와 EJTAG에서는 TCK 속도를 무려 8MHz까지 올릴 수 있었다. 덕분에 30KB정도 되는 부트로더가 JTAG으로 불과 수~수십초 만에 프로그래밍이 된다.
  요놈의 단점이라면 새로운 디바이스를 지원하려면 그때 마다 해당 디바이스에 맞게 JTAG 코딩을 해줘야 한다. ARM계열이라면 ARM7TDMI, ARM9TDMI등에 맞게 Embedded-ICE 기능을 넣어 줘야 하고, MIPS는 EJTAG을 버전 별로 구현해 줘야 한다.
EXTEST를 이용하는 디바이스라면 해당 칩의 BSDL자료를 구해 만들어 줘야 한다. 때문에 해당 메뉴얼들을 다 찾아보고 정독하고 구현하고 안되면 다른 예제 구해다 분석해서 만들어 써야 했다. 요짓을 한 열댓번 하니 토나올 정도로 어렵고 구찮다.
  그래서 이번엔 두번째 만든 USB-JTAG을 OpenOCD라는 아주 훌륭한 툴과 연동 시켜봤다.
OpenOCD의 기본 연결은 병렬포트이나 지금은 병렬포트가 달린 PC를 보기 힘들다. USB기반의 다양한 JTAG 하드웨어들이 OpenOCD와 연동이 가능한데 연동 되는 칩셋이 주로 FTDI사의 것들이다. 내가 갖고 있는 보드중 가능한게 있나 찾아 봤으나 없다.
  자작한 USB-JTAG은 타겟과 호스트측이 완전히 isolation 되어 있고 타켓측 JTAG TTL전압이 3.3V, 5V둘다 사용가능해 나름(?) 훌륭하게 잘 만들었다고 혼자 생각한다. 그래서 OpenOCD와 연동시켰다.
  우선 OpenOCD 소스를 구해 분석을 시작 한다. 남이 짜놓은 수십메가바이트 소스를 보자니 가슴이 답답하고 속이 울렁 거린다. 처음 Embedded Linux 커널 포팅 할 때 500MB 커널 소스 풀어 놓고 느꼈던 까마득함을 간만에 느꼈다.
  처음부터 욕심을 내어 FTDI 칩셋에서 지원하는 MPSSE기능을 에뮬레이션 해보려고 했으나 찾아봐야 할게 너무 많아 우선 쉽게 병렬포트 디바이스를 에뮬레이션하는 방향으로 잡고 시작 했다. OpenOCD 소스에서 parport.c 디바이스 핸들링 하는 부분을 다 뜯어 고쳐 자작한 USB-JTAG에 물려 주었다.
  속도는 일반 병렬포트의 반밖에 안된다. 정말 느리다. 8MHz TCK를 사용하다 500KHz도 채 안되는 속도를 사용하려니 답답하다. 그러나 OpenOCD에서 지원하는 모든 디바이스를 아주 쉽게 사용 할 수 있다는 장점이 속도 문제를 덮어 버렸다.
  OpenOCD 연동 작업후 처음 적용해본게 S3C6410이다. ARM11코어 인데 ARM11용 JTAG 디버그 프로토콜 메뉴얼 보면서 구현 하려다 OpenOCD와 연동 시키니 환상이다. 수천만원 빚을 바로 갚아야 하는데 빌려준사람이 '그거 그냥 너 가져!' 라고 하는 소리를 들었다고나 할까?
  JTAG속도가 느리므로 다음과 같은 과정으로 개발을 진행 하였다.
  S3C6410내부에 8KB 정도 되는 SRAM이 있는데 여기에 PLL, UART, DDR 초기화 및 NAND 플래시 프로그래밍 기능만 넣어 부팅 시킨다. 그러면 OpenOCD에서는 최대 8KB만 써넣으면 되므로 저속 TCK는 문제가 되지 않는다.
  실제 위 코드를 구현해 빌드해 보니 약 4KB, OpenOCD로 SRAM에 다운로드하는데 약 30초 걸린다. 나머지 수십KB 본래의 부트로더 바이너리는 UART를 이용해 DDR에 다운로드후 NAND에 쓰면 끝. 이후 펌웨어 업데이트는 부트로더 기능을 사용하면 되므로 대용량 데이터 전송에 JTAG은 더이상 쓰지 않아도 된다.
  좋은 툴을 사용하니 손발 고생이 줄어들었다. 움하하....


<> 2015/07/02 내용 추가
  위에서 설명 한 것 처럼 UART를 이용한 병렬포트 모사 방식은 일단 좀 느리다. 속도 증대를 위해 처음엔 FTDI의 MPSSE 기능을 모사 하려고 했으나 자료들 뒤져 보니 복잡하다.
  OpenOCD 소스를 이리저리 뒤져 보던중 Altera의 USB-Blaster라는 하드웨어용 드라이버 소스가 눈에 들어 온다. 잠깐 뒤적 거려 보니 USB-Blaster라는 하드웨어를 리버스엔지니어링으로 동작을 분석해 UrJTAG에 붙여 놓은걸 OpenOCD에 적용 시켜 놓은 것이 었다.
  소스를 보니 하드웨어 동작에 대한 비교적 자세한 설명이 소스안에 주석으로 표기되어 있었다.
  USB-Blaster동작을 자작한 첫번째 및 두번째 USB-JTAG 하드웨어에 펌웨어로 기능을 모사해 넣었다. 그리고 OpenOCD의 usb_blaster.c 드라이버 파일중 USB bulk 전송 부분을 모두 다시 코딩하여 자작한 2개 USB-JTAG 하드웨어와 연동 되도록 만들었다.
잘 된다. 움하하... 난 역시 대단해...

  속도 비교를 해봤다. S3C6410의 내부 SRAM에 다운로드하는 전송 속도이다.

 - 첫번째 USB-JTAG (병렬 포트 모사): 구현 하지 않음
 - 두번째 USB-JTAG (병렬 포트 모사): 약 140[byte/s]
 - 첫번째 USB-JTAG (USB-Blaster 모사): 약 330[byte/s]
 - 두번째 USB-JTAG (USB-Blaster 모사): 약 3790[byte/s]

TCK 속도를 추정해 보자면 위에서 부터 200~300KHz, 500~700KHz, 6~7MHz 정도 되는듯 하다. USB-Blaster 모사로 구현한 첫번째 USB-JTAG은 실제 병렬 포트를 사용할 때와 비슷한 환경이 되고, 두번째 USB-JTAG은 6MHz로 고정된 Altera USB-Blaster와 비슷한 환경이 될 듯 하다.
덕분에 OpenOCD 연동 작업이 상당히 쾌적해 졌다.

JTAG 핀 탐색 및 I2C 분석기 (JTAG pin identifier & I2C sniffer)

  이번엔 리버스 엔지니어링시 있으면 상당히 도움이 되는 툴을 하나 만들었다.
오래전에 만들어 쓰고 있었으나 얼기설기 대충 만들어 쓰다 이번에 케이스와 USB 인터페이스까지 짜넣어 쓸만하게 만들었다.
  주변 칩 제어에 많이 사용되는 I2C 통신 분석기 (I2C sniffer)와 JTAG 핀 구성이 어떻게 되는지 핀 맵을 찾아주는 JTAG 핀 탐색기 (JTAG pin identifier)이다.
한 개에 두가지 기능을 넣었다.
  메인보드는 흑백 LCD가 부착된 무선 전화기 보드를 사용했는데 ATMEGA128기반에 32KB SRAM이 외부에 부착되어 있어 작은 데이터 로깅용도로 훌륭했다.

  리버스 엔지니어링을 시작 하려면 CPU의 부트 시퀸스를 가로채야 한다.
CPU 부트 모드에 따라 많이 다르게 접근을 해야 하지만 JTAG을 지원 한다면 JTAG을 이용해 좀더 쉽고 빠르게 접근할 수 있다.
  이미 만들어진 보드에서 JTAG핀을 찾기란 쉬울 수 도, 어려울 수 도, 아니면 아예 불가능 할 수 도 있다.
보드에 JTAG 핀으로 의심해 볼 만한 핀들을 이용해 TRS, TMS, TCK, TDI, TDO등 JTAG 핀을 자동으로 찾아 주면 얼마나 좋을까? 그래서 만들었다.

  일전엔 자동차용 네비게이터로 디지털 오실로스코프를 만든적이 있다 (링크).
해당 모델을 리버스 엔지니어링 할 때 아주 막막했던게 LCD 디스플레이 부분이었다. 다른 네비게이터와 좀 다르게 BT1611AG라는 별도 대만산 LCD 컨트롤러를 쓴 모델이었는데 I2C 통신으로 초기화를 하는듯 하였다. 어떻게 초기화를 해야 하는지 자료가 없어 I2C sniffer가 필요한 상황에 이번에 만든 I2C sniffer가 아주 중요한 역할을 해주었다.

  우선 만들어 놓은 작품(?)을 보면 아래 사진과 같다.


[케이스에 우겨 넣은 모습]

  위 사진의 녹색 기판이 무전 전화기 보드이다. 그 위에 작은 청색 보드는 USB-RS232 컨버터이다. USB로 부터 나오는 5V전원을 사용하고 운영체제에서는 RS232 시리얼 포트 (COMx)로 인식된다. 시리얼 터미널을 이용해 접속한다음, 명령을 입력하는 방식으로 사용하면 된다.
  그 아래 길게 누워있는 똥색 기판은 아주 오래전 마이크로마우스 만들때 쓰던 RS232 transceiver 보드 이다. 무선전화기 보드의 UART 전압 레벨은 3.3V인데 USB-RS232 컨버터의 TTL 레벨은 5V라 TTL끼리 접속하려면 레벨 쉬프팅을 해야하는데 귀찮아서 RS232 버스라인을 그대로 쓰기 위해 우겨 넣었다.
케이스는 새로텍이라는 회사에서 만든 각종 메모리 카드 백업용 외장하드(?)를 사용했다.


[완성]

  S3C2440 CPU에서 BT1611AG로 전송되는 I2C 명령을 I2C sniffer로 잡아낸 결과는 아래와 같다.


[I2C sniffing 결과]

  'S'는 START, 'A'는 ACK, 'N'는 NACK를 의미하고 [xx]는 I2C 버스라인에 뜨는 16진수 8비트 데이터 이다. 위 이미지 예시처럼 I2C 클럭 속도는 약 66KHz정도 되고 뿌려지는 데이터들을 볼 수가 있다.
잡힌 데이터를 모아 사용하여 정상적으로  LCD 사용이 가능해졌다. 움하하...

  다음은 JTAG 핀 탐색 기능.
최근 S3C6410 보드의 JTAG 핀 맵 찾을 때 썼는데 수초 이내로 TRS, TMS, TCK, TDI, TDO 5개 핀 배열을 찾아 주었다.


[S3C6410보드와 연결]

[S3C6410의 JTAG 핀맵 찾기 결과]

  S3C6410의 경우 내부에 ARM11 core와 ETM모듈, 2개 디바이스가 daisy chain으로 연결되어 있어 각각 2개 ID 검색이 가능하다. 위 이미지를 보면 CPU ID는 0x07b76f0f, ETM ID는 0x2b900f0f가 TMS-TDI-TDO-TRS-TCK 조합으로 검색 되었다.
  위와 같이 모든 조합에 대해 ID 검색과 10101010 비트 배열로 bypass 테스트를 수행하여 모두 1이거나 모두 0인 결과를 제외한 리턴값을 도시해 주고 그 때 JTAG 핀 배열 값을 표기해 준다. 덤으로 몇 개 디바이스가 daisy chain으로 연결되어 있는지 갯수까지 표기해 준다.
누가 만들었는지 프로그램을 기똥차게 잘 짰다. 크크크...

12.5MSPS 자작 디지털 오실로스코프

  2000년즘 아르바이트해서 모은 돈으로 청계상가에서 40MHz 아날로그 오실로스코프를 하나 샀었다. 그때 2족 보행 로봇이나 마이크로마우스, 라인트레이서 등등 만들면서 8051, 80C196, AMD188 보드 만든거 디버깅 할 때 아주 요긴하게 잘 썼었다.
요놈은 아직도 내 작업실에서 잘 쓰고 있다. 다만 아쉬운건 저렴한 아날로그 스코프이다 보니 저장 기능이 없고 one-shot 트리거가 안된다.
  요새 갖고 있는 구형 네비게이션 reverse engineering 재미에 빠져 있던 지라 이참에 디지털 오실로스코프를 만들어 보기로 했다.


[XROAD Z3300]

  우선 타겟이 될 네비게이션은 위 사진의 모델이다. XROAD사의 Z3300모델인데 삼성 S3C2410 기반으로 만들어 진거다.
  늘 그렇듯, 배따고 어찌어찌 JTAG 핀 찾아 내고, 기본 펌웨어는 백업 해놓고, 자작한 부트로더를 포팅한 후 시작 한다. 근데 요놈은 LCD 구동을 기본 CPU를 사용하지 않고 BIT1611AG라는 LCD 전용 제어 칩을 사용한다. 인터넷 뒤져봐도 자료가 없다. 젠장...
S3C2410 LCD 출력 데이터 받아서 패널에 뿌려주는듯 한데 칩 제어는 IIC로 하는듯 하다. 데이터 시트가 없으니 이거 뭐 할 수가 없다. 그래서 어쩔수 없이 무선전화기에서 뜯어 놓은 ATMEGA128 기반 보드를 이용해 IIC 버스 모니터(sniffer)를 급하게 만들었다. 16KB SRAM이 같이 붙어 있어 패킷 로깅하기에 아주 용이하다.
  백업 받아 두었던 S3C2410의 원래 바이너리를 다시 주입한다음 LCD가 정상 동작 할 때까지 IIC 모니터로 모든 패킷을 저장한다. 저장된 데이터는 간단하게 분석해서 똑같이 주입 시켜준다. 다행이 잘 되는군. 움하하...

  오실로스코프 디스플레이 파트는 얼추 이걸로 하면 되고, 데이터 취득을 해야 하는데 S3C2410의 ADC는 터치용으로 아예 할당되어 버려 일반 ADC용도로는 사용이 불가능하다. 또한, 속도도 500KSPS 밖에 되지 않아 오실로스코프용으론 좀 부족하다. 그래서 외부에 데이터 취득용으로 TMS320F28335를 추가로 장착 하였다.
  요놈은 내장 ADC가 1채널 일때는 최대 12.5MSPS, 2채널 일때는 8.33MSPS로 동작 가능하다.
  그런데 문제가 하나 있다. F28335에서 12bit 12.5MSPS로 취득되는 데이터량이 어마어마(?)하다. 초당 25MB나 된다. 이걸 어떻게 S3C2410에 전달을 하지?...
  USB를 쓸까 SPI를 쓸까 하다 F28335에서 트리거 찾아내고 디스플레이만 되는 영역 데이터를 뽑아내는 후처리까지 다 하고난 다음 S3C2410에 넘겨주기로 했다. 대충 계산해보니 약 900Kbps만 넘겨도 전체 동작에 무리가 없어 보였다.
  요 F28335와 S3C2410간 데이터 전송은 UART를 적용 했다. 실험해 보니 최대 1.5625Mbps까지 통신이 가능하였다 (S3C2410에서 최대 설정 가능한 수치임).
  원래는 Linux-Xenomai를 기반으로 사용하려고 OS포팅하고 UI까지 다 꾸며 놨는데 결정적으로 OS 오버헤드인지 뭔지 1.5625Mbps로 통신을 하면 뭔가 불안정 해진다. 데이터를 놓치는거 같다. 그래서 OSless 펌웨어로 다시 구현했다. OS가 없으니 그래픽 구현부터 해서 완전히 밑바닥 부터 짜야 했다. 아.. 피곤...
  아주 손쉽게(?) F28335와 S3C2410 코드를 만들어 얼추 돌아가도록 해봤다.


[0.5Vp-p 1KHz 측정 3us/div]


[0.5Vp-p 1KHz 측정 2ms/div]


[프로브 연결부 및 입력 전압 분압용 가변 저항부]


[최종 완성]

<> 사양
  - 주 제어기 (LCD 디스플레이 및 UI): S3C2410 200MHz
  - 보조 제어기 (ADC): TMS320F28335 150MHz
  - 입력 채널: 2채널
  - 속도: 12.5MSPS(1채널), 8.33MSPS(2채널)
  - 트리거 모드: Hold-Off, One-Shot, Run/Stop
  - 트리거 엣지(상승/하강) 선택 및 트리거 레벨 조절 가능
  - 시간축 설정(/div): 3/5/10/20/50us, 0.1/0.2/0.5/1/2/5/10/20/50ms, 0.1/0.2/0.5s
  - 디스플레이: 480x234

S3C2440A Embedded Linux-Xenomai with Realtime CAN (USB-host RTDM)

이번에도 글 제목이 아주 거창하다.
일전에 400MHz짜리 S3C2440A 컨트롤러가 내장된 네비게이터에 Linux-Xenomai를 포팅했었다(글보기).
껍데기도 깨끗하니 어디 좋은데 쓸데가 없을까 하다가 마침 8축 Actuator 구동 시험을 할 일이 있어 구현해 봤다.
제어 대상은 독일 Dunker motor라는 회사에서 만든 제어기 일체형 서보모터이고 CANopen 방식 인터페이스를 사용한다.


[CANopen 인터페이스 방식 Servo Actuator]

문제는 네비게이터에 CAN 포트가 당연히 없다는 것이다.

다행이 여러모로 확장 가능한 USB 호스트 포트가 있어 요놈을 활용해 보기로 했다.
아주 쉽다. 네비게이터에 달린 USB호스트에 USB to CAN 컨버터를 그냥 낑구면 되는 것이다!!! 정말 쉽지 않은가?

그러나 진짜 문제는 여기서 부터다.

Linux기반 USB 호스트측 SW(USB OHCI) 소스는 쉽게 구할 수 있으나 당연히 RTDM(Realtime Driver Module)을 필요로 하는 실시간 운영체제에는 쓸 수가 없다. 엄연히 이야기 하자면 사용은 가능하나 언제 실시간이 깨질지 모른다. 힘들게 실시간 운영체제를 쓰는 의미가 없다.
USB 호스트측 SW를 RTDM으로 처음부터 다시 만들어야 한다.

다음 문제가 또 있다. USB to CAN 컨버터다.

'디바이스 드라이버는 이렇게 저렇게 만드시오, 어플리케이션 API는 이러쿵 저러쿵 만드시오' 하는 메뉴얼따윈 당연히 없다. 드라이버 소스도 못 구한다.
그런데 USB to CAN 컨버터의 디바이스 드라이버도 RTDM용으로 다시 짜야한다.

그리고 또...

CAN 패킷 I/O를 위한 User level의 API 라이브러리도 실시간용으로 다시 만들어야 한다!!!

음... 머리가 아프군...

USB 호스트용 OHCI소스를 분석한다.
control pipe, bulk-in pipe, bulk-out pipe 등등 low level 제어 코드를 뽑아내 RTDM용으로 디바이스 드라이버를 완전히 다시 만든다.
OHCI 기능과는 무관한 오직 USB-CAN만을 위한 디바이스 드라이버를 만들었다.
USB to CAN 컨버터 드라이버는 소스를 구할 수 없으니 WireShark의 USB sniffing기능을 이용해 드라이버 동작을 reverse engineering한다.
User level API동작 분석은 API Monitor라는 툴을 이용해 관련 DLL에 접근하는 모든 API함수들의 동작 시퀸스와 완벽하지는 않지만 매개 변수 값들을 확인하고 알 수 없는 값들은 추정한다.
이렇게 간단한 방법으로 구현했다. 움하하...


[리눅스 부팅 및 Linux Framebuffer 동작 확인]


[SDL을 이용한 GUI구성 - 버튼, 텍스트 박스등 제작 테스트]

400MHz ARM9 코어에 USB호스트측 5ms짜리 실시간 태스크와 CANopen 패킷 제어를 위한 50Hz용 실시간 태스크를 만들었다.

8개 Actuator를 20ms주기로 동시에 제어 하도록 구성했다.
GUI는 SDL을 이용해 구현하고 8개 Actuator의 동시 제어를 좀더 직관적으로 하기위해 IIC 통신으로 사용이 가능한 Wii Nunchuk이라는 조이스틱 비스므레한걸 달아 줬다.
8축 CANopen I/O용 5ms/20ms 실시간 태스크 2개, GUI용 Thread 1개, Nunchuk 인터페이스용 Thread 1개, 전체 시스템 서비스 구성용 Thread 1개, 그리고 마지막으로 콘솔 제어 및 모니터링용 main() 루프 한개... CPU를 아주 알차게 쓰고 있는듯 하다.


[최종 완성]