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를 아주 알차게 쓰고 있는듯 하다.


[최종 완성]

S3C2440A에 Embedded Linux-Xenomai 포팅

  예전에 PXA270에 Embedded Linux-Xenomai를 포팅하여 휴머노이드로봇의 주 제어용으로 사용했었고, Ethernet용 RTDM을 제작하여 Ethernet을 이용한 실시간 제어 가능성 확인용으로도 활용해 봤었다.
  이번엔 안쓰는 구형 네이비게이터에 장착된 S3C2440A(400MHz)에 Embedded Linux-Xenomai를 포팅해봤다. 궁금해서 기기를 까보니 S3C2440A이 보이길레 한번 올려본 것이다.
  사용한 네비게이터는 엠텍반도체라는 곳에서 2006년에 만든 CARON FDN4000모델이다
[CARON FDN4000]

  뚜껑을 따보니 메인기판 1개와 LCD로 구성된 아주 깔끔한 구조였다.
[분해]


[기판 부품면]

[기판 반대면]
  우선 기본적인 외부 I/O를 확인한다. 다행이 UART가 2.5mm 마이크로 폰잭으로 나와 있었다. 터미널을 연결해 뭐라는지 들어보니 E-Boot와 WinCE 조합이었다.
  시리얼 부팅등 간단한 방법이나 사용 가능한 툴등이 있는지 메뉴얼, 인터넷등을 뒤져 봤는데 없다. JTAG을 붙여서 바닥부터 시작해야 할 듯 하다. JTAG 디버그 포트를 찾아 봤으나 핀헤더나 핀헤더가 있었을 법한 껀덕지는 아무데도 없었다. 여기저기 유심히 보던중 아래 그림처럼 SD카드 슬롯이 있는, 보드 끝자락에 뭔가 컨텍이 있을법한 곳이 눈에 띤다.
  맞다. JTAG디버그 포트가 맞다. 나만의 나름(?) 노하우로 JTAG포트임을 확인하고 TMS, TCK, TDO, TDI등 핀배열을 찾아 냈다. 난 역시 대단해 움하하... 이 때도 역시 일전에 만들어 쓰고있는 나의 보물 USB-JTAG이 아주 큰 도움이 되었다.
  S3C2440A는 ARM9TDMI코어로 JTAG 연동을 위해 Embedded ICE를 구현하면 메모리 읽기 쓰기등이 가능해 진다. 일전에 같은 ARM9TDMI 기반인 KS8695보드 리버스 엔지니어링을 위해 구현했던 코드를 그대로 활용해 S3C2440A용을 만들어 USB-JTAG에 심어 주었다.
[디버깅을 위해 JTAG단자 인출]
  아래와 같이 H/W 개발 환경을 꾸며주었다. 우선 기본 내장된 펌웨어를 모조리 읽어 파일로 저장해 놓은 다음 플래시 메모리를 깨끗하게 지우고 시작 한다.
  부트로더 만들어 올리고, 리눅스 커널 부팅을 위한 ATAG도 만들어 주고, 이더넷 포트가 없으니 커널/램디스크 다운로드용 USB포트도 뚫어 주고, 호스트PC용 USB 디바이스 드라이버도 만들어 주고, 커널 패치하고, 커널 설정 하고, 빌드하고, BusyBox 구성해 주고, 램디스크 만들어주고 보드에 올리면 된다. 참 쉽죠?
[H/W 개발환경]
  사용한 커널 조합은 linux-2.6.28.8과 xenomai-2.6.0-rc이다. ramdisk 마운트 하는데 애를 좀 먹었다. crosstool-ng로 툴체인을 만들어 쓰고 있는데 요놈에 버그가 있었다. 툴체인 버그로 생긴 문제는 도무지 찾기가 힘들다...
  Xenomai가 패치된 커널 메시지는 아래와 같다.
-------------------------------------------------------------------
Uncompressing Linux... done, booting the kernel.
Linux version 2.6.38.8-xenokang (root@localhost.localdomain) (gcc version 4.7.3 (crosstool-NG 1.19.0) ) #1 PREEMPT Wed Nov 19 16:23:11 KST 2014
CPU: ARM920T [41129200] revision 0 (ARMv4T), cr=c0007177
CPU: VIVT data cache, VIVT instruction cache
Machine: FDN4000
Memory policy: ECC disabled, Data cache writeback
[FDN4000] fdn4000_map_io()
CPU S3C2440A (id 0x32440001)
S3C24XX Clocks, Copyright 2004 Simtec Electronics
S3C244X: core 400.000 MHz, memory 133.333 MHz, peripheral 66.666 MHz
CLOCK: Slow mode (1.500 MHz), fast, MPLL on, UPLL on
Built 1 zonelists in Zone order, mobility grouping on.  Total pages: 16256
Kernel command line: console=ttySAC1,57600 initrd=0x32200000,5M ramdisk=16384 root=/dev/ram0
PID hash table entries: 256 (order: -2, 1024 bytes)
Dentry cache hash table entries: 8192 (order: 3, 32768 bytes)
Inode-cache hash table entries: 4096 (order: 2, 16384 bytes)
Memory: 64MB = 64MB total
Memory: 57636k/57636k available, 7900k reserved, 0K highmem
Virtual kernel memory layout:
    vector  : 0xffff0000 - 0xffff1000   (   4 kB)
    fixmap  : 0xfff00000 - 0xfffe0000   ( 896 kB)
    DMA     : 0xffc00000 - 0xffe00000   (   2 MB)
    vmalloc : 0xc4800000 - 0xf6000000   ( 792 MB)
    lowmem  : 0xc0000000 - 0xc4000000   (  64 MB)
    modules : 0xbf000000 - 0xc0000000   (  16 MB)
      .init : 0xc0008000 - 0xc001f000   (  92 kB)
      .text : 0xc001f000 - 0xc01e0000   (1796 kB)
      .data : 0xc01e0000 - 0xc01f2e00   (  76 kB)
SLUB: Genslabs=13, HWalign=32, Order=0-3, MinObjects=0, CPUs=1, Nodes=1
Preemptable hierarchical RCU implementation.
        RCU-based detection of stalled CPUs is disabled.
        Verbose stalled-CPUs detection is disabled.
NR_IRQS:85
irq: clearing subpending status 000000d2
I-pipe, 11.111 MHz clocksource
I-pipe 1.18-09: pipeline enabled.
Console: colour dummy device 80x30
console [ttySAC1] enabled
Calibrating delay loop... 199.06 BogoMIPS (lpj=497664)
pid_max: default: 32768 minimum: 301
Mount-cache hash table entries: 512
CPU: Testing write buffer coherency: ok
gpiochip_add: gpios 288..303 (GPIOK) failed to register
gpiochip_add: gpios 320..334 (GPIOL) failed to register
gpiochip_add: gpios 352..353 (GPIOM) failed to register
[FDN4000] fdn4000_init()
S3C2440: Initialising architecture
S3C2440: IRQ Support
S3C244X: Clock Support, DVS off
bio: create slab at 0
Trying to unpack rootfs image as initramfs...
rootfs image is not initramfs (no cpio magic); looks like an initrd
Freeing initrd memory: 5120K
I-pipe: Domain Xenomai registered.
Xenomai: hal/arm started.
Xenomai: scheduling class idle registered.
Xenomai: scheduling class rt registered.
Xenomai: real-time nucleus v2.6.0-rc5 (head) loaded.
Xenomai: starting native API services.
Xenomai: starting RTDM services.
io scheduler noop registered
io scheduler deadline registered
io scheduler cfq registered (default)
s3c2440-uart.0: ttySAC0 at MMIO 0x50000000 (irq = 70) is a S3C2440
s3c2440-uart.1: ttySAC1 at MMIO 0x50004000 (irq = 73) is a S3C2440
s3c2440-uart.2: ttySAC2 at MMIO 0x50008000 (irq = 76) is a S3C2440
brd: module loaded
mousedev: PS/2 mouse device common for all mice
RAMDISK: gzip image found at block 0
VFS: Mounted root (ext2 filesystem) on device 1:0.
Freeing init memory: 92K
init started: BusyBox v1.22.1 (2014-11-28 14:19:48 KST)
starting pid 24, tty '': '/etc/init.d/rcS'

Please press Enter to activate this console.
starting pid 30, tty '': '-/bin/sh'
[root@s3c2440 /]#
[root@s3c2440 /]#
[root@s3c2440 /]# ./xenomai/bin/latency
== Sampling period: 1000 us
== Test mode: periodic user-mode task
== All results in microseconds
warming up...
RTT|  00:00:01  (periodic user-mode task, 1000 us period, priority 99)
RTH|----lat min|----lat avg|----lat max|-overrun|---msw|---lat best|--lat worst
RTD|     -4.681|      3.510|     36.090|       0|     0|     -4.681|     36.090
RTD|     -4.681|      3.600|     40.230|       0|     0|     -4.681|     40.230
RTD|     -4.681|      3.600|     42.930|       0|     0|     -4.681|     42.930
RTD|     -4.681|      3.600|     42.660|       0|     0|     -4.681|     42.930
RTD|     -4.681|      3.600|     42.480|       0|     0|     -4.681|     42.930
RTD|     -4.681|      3.600|     43.920|       0|     0|     -4.681|     43.920
RTD|     -4.681|      3.600|     42.480|       0|     0|     -4.681|     43.920
RTD|     -4.681|      3.690|     47.250|       0|     0|     -4.681|     47.250
RTD|     -4.681|      3.600|     42.660|       0|     0|     -4.681|     47.250
RTD|     -4.681|      3.600|     41.760|       0|     0|     -4.681|     47.250
RTD|     -4.681|      3.600|     42.030|       0|     0|     -4.681|     47.250
RTD|     -4.681|      3.600|     42.660|       0|     0|     -4.681|     47.250
RTD|     -4.681|      3.600|     43.830|       0|     0|     -4.681|     47.250
RTD|     -4.681|      3.600|     42.390|       0|     0|     -4.681|     47.250
RTD|     -4.681|      3.600|     42.660|       0|     0|     -4.681|     47.250
RTD|     -4.681|      3.600|     42.930|       0|     0|     -4.681|     47.250
RTD|     -4.681|      3.600|     43.200|       0|     0|     -4.681|     47.250
RTD|     -4.681|      3.600|     43.110|       0|     0|     -4.681|     47.250
RTD|     -4.681|      3.600|     41.580|       0|     0|     -4.681|     47.250
RTD|     -4.681|      3.600|     42.390|       0|     0|     -4.681|     47.250
RTD|     -4.681|      3.600|     44.280|       0|     0|     -4.681|     47.250
RTT|  00:00:22  (periodic user-mode task, 1000 us period, priority 99)
RTH|----lat min|----lat avg|----lat max|-overrun|---msw|---lat best|--lat worst
RTD|     -4.681|      3.600|     42.840|       0|     0|     -4.681|     47.250
RTD|     -4.681|      3.600|     42.030|       0|     0|     -4.681|     47.250
^C---|-----------|-----------|-----------|--------|------|-------------------------
RTS|     -4.681|      3.600|     47.250|       0|     0|    00:00:23/00:00:23
[root@s3c2440 /]#
[root@s3c2440 /]#
-------------------------------------------------------------------

  실시간 태스크 어플리케이션 동작이 확인되고 커널과 램디스크만 올라간 상태라 이제 시작이긴하다. fb붙여서 LCD도 돌려보고, 주변에 덕지덕지 붙어있는 터치판넬, 오디오, 비디오, GPS, FM 송신칩 등등도 해보면 재미질것 같다. 데이터 시트나 메뉴얼을 구할 수 없는 칩들이 몇 개 있어 좀 제한적이긴 하겠다.
  요놈은 하우징이 깔끔한 완제품이라 어디 좋은데 쓸수 있게 만들면 훌륭할거 같으다.

2014/08/31~09/04 터키여행

이번엔 터키를 다녀 왔다.
원래 파리를 가기로 했으나 당일 터키로 갑자기 변경해 출발한 여행이라 아무런 정보가 없어 거의 패닉 상태로 개고생 했다.
일정 때문에 24시간을 깨어 있었던적도 있었다.
말이 안통해 새벽 5시즘엔 앙카라에서 미아가 될뻔도 했다.
그래도 참 재밌었던 여행이다.
외국사람이 한국말로 자기나라를 소개하는 가이드 투어라는것도 처음 해봤다.
노란 풍선을 타고 하늘도 날았다.