2013년 9월 30일 월요일

stack frame 해석하기

GDB에서 출력되는 frame 정보 해석

Sample Program
------------------------------------------------------------------------------------------------------
1  #include <stdio.h>
2
3  int func1(int arg1, int arg2);
4  int func2(int a1,int a2);
5
6  int func1(int arg1, int arg2)   //시작주소는 0x804841C, gdb에서 x func1명령으로 확인 가능
7  {
8      int temp=3;
9      temp = func2(arg1, arg2); // 이 명령 위치는 0x0804843b, 본문 참조
10    return temp;
11 }
12
13
14 int func2(int a1, int a2)   //시작주소는 0x8048443, gdb에서 x func2명령으로 확인 가능
15 {
16     int tmp=9;
17     return a1+a2+tmp;
18 }
19
20 int main(void)   //시작주소는 0x804845f, gdb에서 x main명령으로 확인 가능
21 {
22     int a=10, b=40,c=0;
23  
24     c = func1 (a,b); //이 명령의 위치는  0x08048494, 본문 참조
25
26     printf(" c = %d\n");
27
28     return 0;
29 }
30
------------------------------------------------------------------------------------------------------
(gdb) bt
#0 func2 (a1=10,a2=40) at a.c:17
#1 0x0804843b in func1 (arg1=10,arg2=40) at a.c:9
#2 0x08048494 in main ( ) at a.c:24
------------------------------------------------------------------------------------------------------

#0 func2 (a1=10,a2=40) at a.c:17 
   - 현재 sample program의 파일 이름이 a.c
   - program이 a.c파일의 17번째 라인이 실행 될 차례임.
   - func2가 호출될 때 a1=10, a2=40으로 호출되었음  위 내용은 frame 명령으로 재확인 가능
----------------------------------------------
(gdb) frame
 #0 func2(a1=10, a2=40) at a.c:17
17                       return a1+a2+tmp;
----------------------------------------------

#1 0x0804843b in func1 (arg1=10,arg2=40) at a.c:9
   - func2는 func1에서 호출되었고 이는 a.c파일 Line 9에서 호출됨

#2 0x08048494 in main ( ) at a.c:24
   - func1은 a.c파일에 있는 main 함수의 Line 24 에서 호출됨

------------------------------------------------------------------------------------------------------
(gdb) info frame 1
Stack frame at 0xbffff160
  eip = 0x804843b in func1 (a.c:9); saved eip 0x8048494
  called by frame at 0xbffff190, caller of frame at 0xbffff130
  source language c.
  Arglist at 0xbffff158, args: arg1=10, arg2=40
  Locals at 0xbffff158, Previous frame's sp is 0xbffff160
  Saved registers:
    ebp at 0xbffff158, eip at 0xbffff15c
------------------------------------------------------------------------------------------------------

(gdb) info frame 1
   - func1번의 stack frame 정보 요청

Stack frame at 0xbffff160
   - func1의 stack frame은 0xbffff160부터 아래쪽(낮은 주소)임.
   - 0xbffff160 - 4 부터 낮은 주소쪽으로 func1의 stack frame임.  (stack은 높은 주소에서 낮은 주소 방향으로 자라남)

eip = 0x804843b in func1 (a.c:9); saved eip 0x8048494
   - func1에서 func2를 호출한 func1의 코드 위치는 a.c파일의 9라인이며 이 주소는 0x0804843b(eip)임.  stack frame상의 최하위 프레임(주소가 낮은)의 경우 이 값이 현재의 cpu의 instruction pointer값임.
   - saved eip는 func1이 호출된 후 실행되어야 할 명령이 있는 main함수상에서 func1호출 다음에 있는 명령의 주소임.

called by frame at 0xbffff190, caller of frame at 0xbffff130
   - func1를 호출한 함수(main)의 stack frame은 0xbffff190이며, func1이 호출한 함수(func2)의 stack fame은 0xbffff130임.  호출할수록 stack frame의 주소가 작아짐.

source language c.
    
Arglist at 0xbffff158, args: arg1=10, arg2=40
    - func2의 argument는 2개 이며 각각 10, 40의 값을 가지고 호출 되었음.
    - 0xbffff158은 func2의 bp이며 arg1은 bp +8, arg2는 bp+12
    - bp(base pointer)과 arg1사이(bf+4)에는 return address가 있음.

Locals at 0xbffff158, Previous frame's sp is 0xbffff160
     
Saved registers:
    ebp at 0xbffff158, eip at 0xbffff15c
   - func2의 ebp는 0xbffff158임.  ebp의 역할은 해당k 함수에서 기준 위치로 첫번째 변수는 ebp-4, 두번째 변수는 ebp-8등으로 stack상의 지역변수를 ebp로 부터의 offset으로 표시함.  (꼭 첫번째 변수가 ebp - 4가 되는 것은 아님)
   - func2의 eip는 0xbffff15C에  저장되어있으며 이는 func1에서 func2를 호출한 다음 명령의 주소임. 이 값은 위에 saved eip값으로 확인 할 수 있음.
    
0xBFFFF190 : 이 아래부터 main의 stack frame
------------------------------------------------------------
0xBFFFF18C : main의 return address
0xBFFFF188 : main의 bp
...
0xBFFFF17C : main의 변수 c  =>  -12(%ebp)와 같이 표시됨 bp로 부터 12바이트 아래 있음.
0xBFFFF178  : main의 변수 b =>  -16(%ebp)
0xBFFFF174  : main의 변수 a
...
0xBFFFF164  : arg2 = 40
0xBFFFF160  : arg1 = 10  : 이 아래부터 func1의 stack frame
------------------------------------------------------------
0xBFFFF15C : func1의 return address : main함수에서 func1이 return되면 다음에 실행할 명령의 주소(ip:instruction pointer)
0xBFFFF158 : func1의 bp
...
0xBFFFF14c : func1의 변수 temp  => -12(%ebp)와 같이 표시됨 bp로 부터 12바이트 아래 있음.
..
0xBFFFF134 : a2 = 40
0xBFFFF130 : a1 = 10 : 이 아래부터 func2의 stack frame
------------------------------------------------------------
0xBFFFF12C: func2의 return address
0xBFFFF128: func2의 bp
0xBFFFF124: func2의 첫번째 변수 tmp  -4(%ebp)k


각 함수의 시작 주소는 아래와 같이 확인 가능
------------------------------------------------------------------------------------------------------
(gdb) x func1
0x804841C
(gdb) x func2
0x8048443
(gdb) x main
0x804845f

------------------------------------------------------------------------------------------------------
(gdb) x/20i func2
  ==>  func2시작부터 20줄의 역어셈블 코드가 출력됨  i는 역 어셈블하라는 뜻

2013년 7월 1일 월요일

printf와 시스템 성능 그리고 UART baud rate

CPU 사용율이 높지 않음에도 불구하고 이유없이 프로그램 수행 속도가 극도로 느려지는 문제가 발생. 예상되는 원인은 과다한 로그 출력. 임베디드 환경에서는 로그 출력이 UART를 통하여 이루어 지는 경우가 많은데, 이 때 UART의 baud rate이 프로그램 동작의 병목으로 작용하는 것이다. 비록 버퍼가 있다고 하지만, 로그양이 버퍼양을 넘어서면 printf등의 함수도 바로 리턴하지 못하고, 대기할 수 밖에 없을 것이다.  하지만 로그가 많다고 무턱대도 이를 줄이는 것도 쉽지 않은 일이다. 각각의 로그는 각 개발자들이 문제 발생을 확인하고 해결하기 위하여 최적화하여 넣어놓은 것으로 이를 제거하면 나중에 디버깅이 어려워지거나 불가능해 지기 때문이다.

가설 검증을 위해 로그 출력에 사용되는 stderr/stdout용 serial(UART)장치 즉 /dev/ser1의 baud rate을 올려보았다. 문제 해결!!!  수정된 이미지를 배포하지만 얼마 지나지 않아서 생산기술에서 연락이 온다. Baud rate 변경으로 인해 생산 테스트 장비를 모두 바꿔야하고, Baud rate 상승으로 인한 통신 에러 증가가 예상되어 절대로 Baud rate를 변경하면 안된단다.   다시 원점.

Baud rate이 115200 bps라면 대충 계산해도 115,200/8=14,400 character 이상의 로그는 (1초에)출력이 불가능하다. 실제로는 UART 전송 시 설정에 따라  Start/Stop bit 및 1 char당 bit수 그리고 char간 delay 등을 고려해야하고 이 경우 실제 전송 가능한 char수는 14,400보다 훨씬 적어지게 된다.

따라서 Baud rate을 올리는 방법으로 문제 개선이 가능하지만, 예상치 못한 문제로 인하여 Baud rate는 올리지 못하는 것으로 결론.

어림 계산으로 1초에 10,000 글자가 전송 가능하다고 하고, 라인당 100글자를 넘지 않는다고 하면, 1초에 100줄 정도의 로그가 출력 가능. 로그가  1초에 100줄이 넘지 않는다는 가정하에 로그 출력을 담당하는 전담 thread를 만든다면 다른 thread는 baud rate과 상관 없이 동작 가능할 것 이다.

로그를 출력하는 매크로를 사용하여 printf 대신 매크로를 사용하여 메모리에 로그를 기록하고, 메모리는 mutex로 보호한다.  로그 출력 thread에서는 계속해서 메모리에서 로그를 읽어와 puts로 출력하도록 하여 문제 해결. (단 1초에 100줄 이상의 로그가 지속적으로 발생한다면, 로그용 메모리 버퍼가 full나면서 mutex block이 걸리는 시간이 늘어나 다시 시스템 성능이 느려질 수 있다. )


Linux Vs QNX Neutrino 파일 디스크립터 관련

리눅스에서는 한 프로세스에서 파일 디스크립터가 할당 될 때마다 그 값이 증가하게 된다. 예를 들어 어떤 프로세스가 처음으로 파일을 open할 경우 3이 할당되며, 이후 4,5,6 순으로 파일 디스크립터가 할당되어 나간다. (0,1,2는 각각 stdin, stdout, stderr에 할당되어 있다) 프로그램이 실행하여 나가면서 파일이 close되는 경우 해당 파일 디스크립터가 반환되게 되는데, 파일 디스크립터가 할당 될 때에는 값이 항상 증가만 하므로, 중간에 반환된 이러한 파일 디스크립터들은 바로 재사용되지 않게 된다. 계속된 할당으로 파일 디스크립터가 사용 가능한 최대 값에 이르면 비로서 다시 0 부터 시작하여 반환된 파일 디스크립터를 찾아서 할당에 사용하게 된다.

최근에 경험한 바에 의하면, QNX Neutrino OS에서는 파일 디스크립터가 반환되면, 바로 다음 open 요청에 재사용되게 된다. 아마도 파일 디스크립터 할당 시, 항상 가장 작은 사용 가능한 파일 디스크립터를 반환하는 식으로 구현이 되어 있는 것으로 추정된다.  이 경우 user application의 상당한 주의가 요구된다. 만일 어떤 파일 디스크립터를 close 한 후에 실수로 한번 더 close를 할 경우, 두번째 close하는 파일 디스크립터가 이미 다른 thread에서의 open에 재사용되는 경우가 발생할 수 있기 때문이다. 이 경우 영문을 모른채 file이 open되자마자 close되어 버리는 문제가 발생하고, 이는 꽤 원인을 파악하기 어려운 문제가 된다.

리눅스에서는 파일 디스크립터를 계속 증가시키는 방법으로 이러한 문제를 영리하게 피해간 것으로 보이는데, QNX Neutrino에서는 관련해서 수정 계획이 없다고 하니, 계속해서 주의가 필요할 것으로 보인다.


2013년 5월 9일 목요일

ISO26262관련 정리

ISO26262에는 5개의 등급이 있으며, 등급별 FIT(Failure In Time)는 아래와 같다.
즉 1 FIT는 10^9 시간(11만 4155년)동안 에러가 발생하는 횟수를 의미한다.

                 QM         ASIL A       ASIL B       ASIL C       ASIL D
--------------------------------------------------------------------------------------
FIT      1000이상   1000이하   100이하    100이하     10이하
  • FIT = Failure in Time = 1 failure / 10^9 hours
  • 1 year MTTF = 109 / (24 * 365) FIT = 114,155 FIT
  • SER FIT = SDC FIT + DUE FIT               

가령 1000년동안 어떤 HW 장치가 동작중 1번만 failure가 발생하여도 114 FIT이므로, ASIL level B를 만족시키지 못하게 된다.

표에서 알 수 있듯이 ASIL D를 만족시킨다는 것은 10 FIT이하아며 이는 10^8 시간 동안 에러가 한번 이하로 발생하는 것이다. (1만 1415년동안 1회 이하의 에러발생)

추가 정보:
  • SDC = Silent Data Corruption
  • DUE = Detected + Unrecoverable Error
  • SER = Soft Error Rate =  SDC + DUE 
  • MTTF = Mean Time to Failure
  • MTTR = Mean Time to Repair
  • MTBF = Mean Time Between Failures = MTTF + MTTR
  • Availability = MTTF / MTBF

2012년 3월 28일 수요일

최근 6년간 구매한 개발 관련 서적 리스트

교보문고에서 구매한 것만...

구매일자 상품명 주문금액
 
2012-03-27 GoF의 디자인 패턴(개정판)(양장본 HardCover) ₩25,000
2012-03-21 소프트웨어 아키텍처 이론과 실제 ₩36,000
2012-03-21 소프트웨어 아키텍처 문서화 (에이콘 소프트웨어 아키텍처 시리즈 3) ₩36,000
2012-03-04 프로그래머 열정을 말하다 ₩14,000
2012-03-04 프로그래머 그 다음 이야기 (사람과 프로그래머 1) ₩14,800
2012-03-04 애자일 마스터 ₩20,000
2012-03-04 시스코 네트워킹(3RD EDITION)(후니의 쉽게 쓴)(3판)(CD1장포함) ₩32,000
2012-02-18 무선 네트워크 공격과 방어(해킹 초보를 위한) (에이콘 해킹 보안 시리즈 31) ₩20,000
2012-02-18 데이터통신과 컴퓨터 네트워킹(IT Cookbook 한빛교재 시리즈 303) ₩24,000
2012-02-18 인사이드 VMware vSphere 4(비제이퍼블릭 인사이드 시리즈 2) ₩26,000
2012-02-18 커맨드라인 활용 가이드(윈도우 시스템 관리자를 위한) ₩35,000
2012-01-07 개발자를 부탁해 ₩13,000
2012-01-07 차세대통신망의 IMS와 VOIP ₩25,000
2012-01-07 프로세서를 지탱하는 기술 ₩27,000
2011-11-20 통신생활 속이 보인다(유비쿼터스를 겨냥한) (Whats 9) ₩17,000
2011-11-20 차세대 광대역통합망의 이해 ₩28,000
2011-11-20 이동통신 입문(IT Cookbook 한빛교재 시리즈 302) ₩30,000
2011-10-29 손에 잡히는 정규 표현식 ₩14,800
2011-10-29 펄(거침없이 배우는) ₩27,000
2011-10-29 CERT C 프로그래밍(버그 없는 안전한 소프트웨어를 위한) (에이콘 해킹 보안 시리즈 25) ₩40,000
2011-10-29 안드로이드 아나토미 (개발자가 행복한 세상 플랫폼 시리즈 1) ₩40,000
2011-10-01 LTE를 통한 3G 진화(SECOND EDITION) ₩29,000
2011-10-01 3G 4G 이동통신 시스템(쉽게 설명한)(개정판) ₩35,000
2011-09-18 NHN은 이렇게 한다 소프트웨어 품질관리 ₩18,000
2011-09-18 소프트웨어 아키텍트가 알아야 할 97가지 ₩20,000
2011-09-18 데미안의 WI FI ON ₩30,000
2011-09-18 CAN LIN FlexRay를 활용한 차량용 네트워크(에이콘 임베디드 시스템 프로그 ₩40,000
2011-07-17 팀장의 역할 ₩13,000
2011-07-17 그린카 콘서트 (양장본 HardCover) ₩15,000
2011-07-17 시리얼 포트 완전정복 ₩30,000
2011-07-17 안드로이드의 모든 것 분석과 포팅 (한빛미디어 모바일 시리즈 11) ₩40,000
2010-11-27 스타트업 바이블 ₩13,000
2010-11-27 DEBUG HACKS ₩27,000
2010-11-13 허수아비춤 (양장본 HardCover) ₩12,000
2010-11-13 스티브 잡스 이야기(청소년 롤모델 시리즈 5) ₩12,000
2010-11-13 애플 VS 구글 ₩12,000
2010-11-13 고약한 문제 합당한 해결 ₩14,000
2010-11-13 안드로이드 2.2 프로그래밍(프로요)(위키북스 임베디드 모바일 시리즈 7) ₩36,000
2010-09-19 인텔스레딩 빌딩블록 ₩24,000
2010-09-04 유닉스 리눅스 프로그래밍 필수 유틸리티(개정판) ₩34,000
2010-05-30 JAVA가 보이는 그림책(개정증보판) ₩14,000
2010-05-30 성공과 실패를 결정하는 1%의 JAVA 프로그래밍 원리 ₩14,800
2010-05-30 C#이 보이는 그림책 ₩15,000
2010-05-30 멀티코어 CPU 이야기(프로그래머가 몰랐던) (BLOG2BOOK 09) ₩22,000
2010-04-25 GIT 분산 버전 관리 시스템 ₩20,000
2010-04-25 FEDORA LINUX TOOLBOX ₩22,000
2010-04-25 QT 실전 프로그래밍 ₩28,000
2010-04-25 안드로이드: 플랫폼 포팅과 활용 ₩28,000
2010-04-25 리눅스 쉘 스크립트 프로그래밍 입문(김태용의) ₩32,000
2010-04-25 TCP IP 완벽 가이드 ₩50,000
2010-04-10 통쾌한 인간관리 이야기(IT 개발자가 쓴) ₩15,000
2010-04-10 TI CORTEX-M3 펌웨어 개발 ₩25,000
2010-02-16 임베디드 리눅스 입문 ₩23,000
2010-02-16 MORE JOEL ON SOFTWARE(조엘 온 소프트웨어를 넘어서) ₩23,000
2010-02-16 EMBEDED USB INSIDE ₩25,000
2010-02-16 UML로 EMBEDDED SYSTEM 프로그래밍하기 ₩25,000
2010-02-16 ARM CORTEX-M3 완벽가이드 ₩25,000
2010-02-04 임베디드 USB 완벽 마스터 세트 (전2권) ₩59,000
2009-10-16 ADVANCED UNIX PROGRAMMING (제2판) ₩32,000
2009-10-16 MICRO C/OS-2 실시간 커널(보급판)(CD1) ₩35,000
2009-09-05 HARD CODE ₩25,000
2009-09-05 윈도우 프로젝트 필수 유틸리티 (CD1장) ₩26,000
2009-08-08 초난감 기업의 조건 ₩18,000
2009-08-08 소프트웨어 컨플릭트 2.0 (시대를 뛰어넘는 즐거운 논쟁) ₩22,000
2009-08-08 소프트웨어 크리에이티비티 2.0 (위기북스 IT LEADERS 8) ₩25,000
2009-05-31 겸손한 개발자가 만든 거만한 소프트웨어 ₩16,800
2009-05-09 WINDOWS CE 실전 가이드 ₩40,000
2009-03-29 루비(입문자를 위한) ₩18,000
2009-03-29 Programming Perl, 3/E ₩52,000
2009-03-27 언어 자료 처리를 위한 PERL ₩10,000
2009-03-06 C++ 핵심공략(꼭 알아야 할) ₩13,000
2009-03-06 MORE EFFECTIVE C++ ₩20,000
2009-03-06 맨먼스 미신 ₩24,000
2009-03-06 드리밍 인 코드 ₩25,000
2009-03-06 RAPID DEVELOPMENT 프로젝트 쾌속 개발전략 ₩28,000
2008-12-26 임베디드 리눅스 시스템 설계와 개발 ₩25,000
2008-05-24 리팩토링 ₩25,000
2008-05-24 HEAD FIRST DESIGN PATTERNS ₩28,000
2008-05-17 다이어그램으로 쉽게 배우는 UML ₩18,000
2008-05-17 HEAD FIRST OBJECT ORIENTED ANALYSIS DESIGN ₩28,000
2008-05-05 아키텍트 이야기 ₩12,000
2008-05-05 CODE CRAFT: 뛰어난 코드 작성을 위한 실천 지침 ₩28,000
2008-04-26 애자일 프랙티스 (애자일 시리즈 004) ₩18,000
2008-01-09 무선 LAN 보안 프로토콜 ₩28,000
2007-11-10 Fundamentals of Wireless Networking ₩29,000
2007-11-10 Bulletproof Wireless Security(Paperback) ₩35,000
2007-10-20 리눅스 커널 2.6 구조와 원리 ₩28,000
2006-10-14 조엘 온 소프트웨어 ₩22,000
2006-10-14 소프트웨어 블로그 베스트 29선(조엘이 엄선한) ₩22,000
2006-10-14 실용주의 프로그래머 (프로그램 프로그래밍 프로그래머 2)(양장본 HardCover) ₩25,000
₩2,265,200


내가 미쳤지...

2012년 3월 21일 수요일

H4/HCI Protocol 이란 ?

"H4"는 HCI  commnads(Bluetooth chip과 host 사이의 event와 data)를 전송하기 위해 사용되는 UART protocol을 지칭하는 용어이다.

H4는 아주 간단한 프로토콜로 Bluetooth 스펙에 정의되어 있기 때문에 Bluetooth 엔지니어가 아니라면 UART H4란 용어를 만났을 때 뒤에 붙은 "H4"를 이해할 수 없다.  H4라 불리는 이유는 Bluetooth specification의 section 번호가 H4이기 때문이다.

H2는 HCI USB Transport Layer
H3는 HCI RS232 Transport Layer
H4는 HCI UART Transport Layer

H4와 유사한 프로토콜로 CSR사의 BCSP(BlueCore Serial Protocol)등이 있으며, BCSP는 "H4" 프로토콜에 bit error checking, wakeup중 drop된 data를 처리하기 위한 재전송, flow control 등의 기능이 추가 되었다. 즉,  H4는 Bluetooth데이터를 UART로 전송하는 "표준" 방법이고, BCSP는 CSR사가 소유한 기술이다.
BCSP도 기본적으로 UART를 사용하는데, RTS/CTS(HW flow control)은 선택 사양이다.

Bluetooth 스펙의 최신 버전에는, 3-wire 프로토콜 이라고 불리는 Section H5가  추가되었는데, 따라서 이 프로토콜을 "H5"라고도 하며, H4에는 없는 bit errors, overrun errors, burst errors checking등이 추가 되어 있다. 즉, H4와 동일하게 UART를 사용하는데,  3-wire라는 이름에서 알 수 있듯이  TXD/ RXD/ GND 3선만 연결한다.   반면에 "H4" 에서는 TXD/ RXD/ RTS/ CTS/ GND를 연결한다. RTS/ CTS를 연결한다는 것은 UART의 HW flow control을 사용한다는 말씀.

HCI(Host Controller Interface) protocol은 transports 프로토콜(H4,H5, BCSP, USB...) 위에 정의되며, Bluetooth chip과 host사이의 기본적인 commands, events 와 data packets 전송을 위해 사용된다.  HCI 역시 Bluetooth 스펙(Vol 2, Part E in BT4.0)의 일부다.

예를들어 SPP(Serial Port Profile)은 Bluetooth전송을 통하여 기존의 RS-232 serial 전송을 simulation하는 Bluetooth profile이다. 이를 구현하기 위한 프로토콜 계층 구조는 아래와 같다.

RFCOMM
-------------------------
L2CAP
-------------------------
ACL                            :BT chip간 무선으로 전송될 데이터
-------------------------
HCI                             : host와 BT chip사이
-------------------------
H4 or H5 or BCSP...   : host와 BT chip사이
-------------------------
UART ...

HCI protocol을 사용하여 아래 4가지 종류의 데이터가 전달된다.
 - Command packet : host -->  Bluetooth chip . Bluetooth chip 제어용
 - Event packet : Bluetooth chip --> host. 특정 event발생 시 BT chip이 host에 알림.
 - ACL data packet :  실제 무선으로 전송될 user 데이터
 - Synchronous data packet : 무선 으로 전송될 audio data.


참고 자료
- UART HOST transport summary (구글 검색으로 쉽게 찾을 수 있음. )

2011년 11월 21일 월요일

USB 사용하여 시스템 개발하기

USB I/F를 사용할 경우 자신이 개발하려는 디바이스가 USB host 로 동작해야 하는지 USB device로 동작해야 하는지를 결정해야 하고 각각에 맞는 USB controller를 사용하면 된다. 하지만 USB controller가 MPU에 내장된 임베디드 시스템에서는 사용하고자 하는 MPU에 내장된 USB controller가 자신이 원하는 모드(host/device)를 지원하는지 확인하여야 한다. MPU에 USB controller가 없거나 원하는 모드를 지원하지 않을 경우 외부 controller가 필요하다.  보통 임비디드 디바이스용 MPUs는 device용 USB controller를 내장하고 있지만, 최근에는 OTG(On The Go)를 지원하는 장치가 많이 있고, OTG를 지원하는 장치는 host/device 모두 사용이 가능하다.

*Host controller는 OHCI, UHCI, EHCI and xHCI controller가 있고, 이중 EHCI가 USB2.0 high speed까지 지원하는 것으로 가장 널리 사용된다.

*보통 통신 디바이스는 Master/Slave로 표현을 많이 하는데, USB는 Host/Device로 구분한다. Host가 Master,  Device가 Slave라고 생각하면 된다.


간혹 동일기기(동일 보드)안에서 USB를 사용하여 두개의 MPU를 연결해야 할 경우에는 굳이 일반적인 USB 대신 HSIC를 고려해볼 필요가 있다. HSIC는 USB2.0 high speed만 지원 하고, 회로 길이등의 제약(10cm)사항이 있으므로 설계시 주의가 필요하다. SW적으로는 USB용 드라이버를 거의 수정없이 사용할 수 있다.(진짜?)  HSIC는 전송을 위해서 장치 밖 원거리로 데이터를 전송할 필요가 없으므로, 이에 알맞게 Front End HW가 USB와 다르게 설계되어 있다.

USB는 여러가지 종류의 장치를 지원하는데, 이 장치를 기능별로 분류하여 class라고 부르고 class별로 표준 protocol을 정의하여 놓았다. 따라서 각 장치는 이 protocol을 준수하여 동작하여야 한다.

가장 대표적인 class가 CDC(Communication Device Class)이다. 대표적으로 USB2Serial, USB2ethernet등 USB포트에 연결하여 다른 통신 방법을 제공하는 디바이스들이 여기에 속한다.  CDC는 통신 방법에 따라 ECM,EEM, NCM, ACM, OBEX 등등 다양한 SubClass들이 있다.

USB-ACM: USB2Serial장치를 위한 SubClass
USB-EEM(ethernet emulation model): USB2ethernet 장치를 위한 SubClass

ECM(Ethernet networking Control Model), EEM(Ethernet Emulation Model),  NCM(Network Control Model ), MBIM(Mobile Broadband Interface Model)등은 모두 ethenet packet을 전송하기 위한 class들이며 점차 성능이 개선되고 기능이 추가 되면서 ECM->EEM->NCM->MBIM(Mobile Broandband Interface Model) 순서로 표준이 발표되어 왔다. 이중 MBIM은 NCM v2.0이 이름만 바뀐 것으로 단순 ethernet 통신 뿐만 아니라 무선 전화망을 사용한 인터넷 access관련 기능 지원등이 추가된 것으로 보인다. (잘 모르겠음 ㅠㅠ)
EEM은 ECM이 발표된 이후에 ECM의 비 효율적인 부분을 개선하여 발표되었는데, 추후 ECM도 버전업되면서 이러한 부분이 개선되었다고 한다.
(이들 sub-class간에 차이점 및 use-case는 좀더 study가 필요)

USB host쪽을 개발할 경우에는 우선 USB host controller driver가 필요하다. 그 다음으로 host장치에 연결할 device의 class driver가 필요하다(class driver는 host에서 실행된다!!!).  예를들어 USB2Ethernet 장치의 경우, USB CDC 에 속하고 그중에서도 CDC-EEM 을 사용하여 class driver를 구현할 수 있다.

반대로 USB device쪽에서는 device controller driver가 있어야 하고,  host에서의 class driver에 대응하는 USB function 드라이버의 개발이 필요하다.

참조 사이트:
http://www.jungo.com/st/embedded_usb_cdc.html

2011년 5월 21일 토요일

NOR Flash Memory 토막 지식

Flash 메모리의 경우 sector 단위로 erase가 가능하며 Erase 된 섹터는 모든 bit가 1이라는 값을 가지게 된다. Flash 메모리에 write 하는 작업은 각 bit별 값을 1 to 0으로 바꾸는 작업으로 반대로 0 to1로 바꾸는 write는 불가능하다. 즉 한번 0이된 bit를 1로 바꾸기 위한 유일한 방법은 해당 bit가 포함된 sector 전체를 erase하는 방법밖에 없다.

flash 메모리에서 각각의 bit는 (일반적으로)한개의 cell에 저장이 되는데 이 cell에 전하를 모두 잃으면 1(charge loss), 전하가 쌓이면(charge gain) 0으로 해석된다. 즉 flash erase는 해당 sector에 전하를 모두 비우는 과정이 된다.

때때로 flash에 저장된 값이 0 to 1 혹은  1 to 0으로 값이 변하는 오류가 발생하기도 하는데 이와 같은 bit flipping이 발생하는 이유가 flash memory 자체의 문제인지 SW의 오류로 발생하는 문제인지를 판단하기 어려운 경우가 많다.

먼저, 특정 bit의 값이  0 to1로 값이 변경되었다면 이는  아래와 같은 이유로 flash device의 문제일 가능성이 매우 높은다.   
  1. SW적으로 특정 bit만 0 to1로 변경할 수 없다. 앞서 설명한데로 이를 위해서는 해당 sector를 모두 지운 후 해당 bit만 1이되도록 다시 해당 sector 전체를 다시 write를 해야 하는데, 일부러 이렇게 SW를 작성할 이유가 없고, 이러한 버그가 생기기도 거의 불가능하기 때문이다.
  2. 해당 bit 정보를 저장하는 flash cell에 전류 leakage가 발생하여 전하가 방전(charge loss)되면, 값이 0 to1로 바뀔 수 있다. 먼저 flash에 0을 write할 때(Charge Gain) 전하가 충분히 주입되지 못하여 전하량이 0과 1의 경계부분에 있다가 시간이 지나면서 발생하는 미세한 방전으로 0 to 1로 값이 바뀔 수 있으며, 이와 같은 방전은 일반적으로 시간이 지남에 따라 자연스레 발생하며 cell 특성에 따라 특정 cell이 다른 cell보다 더 빠르게 방전 되기도 한다. 또한 X-ray등으로 냉납등을 조사하는 공정이 있다면, X-ray조사로 인하여 방전이 더 빠르게 발생하기도 한다.

만일 bit값이 1 --> 0 (charge gain)으로 변경되었다면 이 경우는 좀 더 골치 아픈 경우다. SW적으로 erase없이 1 --> 0으로 해당 bit값 만 바꿀 수 있으므로  0 --> 1로 바뀌는 경우보다는 SW 버그일 가능성이 조금 더 크다고 할 수 있겠다. HW적으로도 전하 loss가 아닌 전하 충전이 발생하여야 가능한 현상인데, 전하는 자연적으로는 방전되지 충전되지는 않는다. (물론 손상된 장치에서 특정 cell이 충전되지 않는다고 보증할 수는 없겠지만 )

참고 사이트
http://j102.net/lecture/3595


앞서서 한 cell에 한 bit가 저장된다고 했는데, 데이터 용량을 늘리기 위해 한 cell에 여러 bit를 저장하는 MirrorBit기술이나 MBC(Multi-Bit Cell) 기술등이 적용되고 있다. 이는 NAND flash에서의 MLC 기술과 유사한 것으로 이해된다.

NAND flash에서는 device특성상 불가피하게 발생하는  bit값 변경을 막기 위해서 ECC를 사용한 값 보정 기능이 오래전부터 사용되고 있으나 NOR에서는 최근에서야 ECC기능이 포함되고 있다. 특히 MLC 기술을 사용하는 NOR에 ECC 적용이 활발하게 이루어지고 있다

2010년 10월 1일 금요일

UART로 연결된 두 보드에서 PPP 프로토콜 사용하여 통신하기.

일반적으로 PPP은 dial-up connection을 위해서 사용되는 프로토콜로,  가가호호 인터넷 연결을 위한 ADSL이 도입되기 이전인 8-90년대에 가정에서 모뎀과 전화를  사용하여 인터넷에 연결하기 위해서 많이 사용되던 프로토콜이다.

그만큼 오래되고 내용도 자못 복잡하여 해당 기술의 역사와 내용을 완전히 이해하기 쉽지 않지만 (항상 그러하듯) 실제로 사용하기 위해서 모든 것을 알 필요는 없다.

일단 서버와 클라이언트상에 PPP연결은 아래와 같이 이루어진다.

서버-모뎀----------------------------모뎀-클라이언트

여기서 서버는 인터넷 제공업체의 컴퓨터, 클라이언트는 가정집의 컴퓨터라고 생각하면 된다.

모뎀을 외장 모뎀이라고 가정하면, 서버-모뎀 혹은  모뎀-클라이언트는 시리얼 포트(COM포트)를 통하여 연결되어 있을 것이고, 시리얼 포트는 내부적으로 레벨 쉬프터를 거쳐 UART 장치에 연결될 것이다.  즉 아래와 같을 것이란 얘기.

서버의 UART 장치 - 레벨 쉬프터 - COM포트 - 외장 모뎀 ------------------>>>>
>>>>-----------------외장모뎀 - COM포트 - 레벨 쉬프터 - 클라이언트의 UART장치.

먼거리의 서버와 클라이언트를 연결하기 위하여 중간에 여러가지 장치를 거치지만 결국은 서버의 UART 장치와 클라이언트의 UART 장치간의 통신을 위한 프로토콜 되겠다. 뭐가? PPP가.

(참조:
 UART는 3.3V를 사용하는데 컴퓨터 외부의 외장모뎀으로 데이터 전송시 데이터가 확실히 전달되도록 12V로 전압을 높여준다. 바로 레벨 쉬프터는 이때문에 필요하다. 이렇게 12V로 승압된 데이터 신호는 RS232C 라고 불리는 케이블을 통해서 외장 모뎀에 연결된다. )

서버 UART <----->클라이언트 UART

이를 단순화 시키면 결국 두 장치간의 UART 통신이라는 것을 알 수 있다.  UART는 위와 같은 인터넷 연결뿐만 아니라 임베디드 기기안에서 여러 장치간의 통신에  아주 많이 사용되는 방법이다.  (기기안에서의 UART 통신에는 승압이 필요 없으므로 레벨 쉬프터를 사용할 필요가 없다.)

 보통 임베디드 기기 안에서의 UART 통신에서는 대부분의 경우 HDLC라는 프로토콜을 사용하거나 혹은 더 간단하게 개발자들이 자체적으로 프로토콜을  정의하여 사용한다.  사실 PPP도 표준 HDLC 프로토콜이 조금 변형된 형태이며, 여기에 클라이언트가 서버에 접속하기 위한 Authentication, Compression, Error detection, multilink 기능등이 추가된 프로토콜이다. 따라서 임베디드 기기안에서의 UART 통신을 위해서는 굳이 HDLC프로토콜을 놔두고 PPP를 사용할 필요는 없다.

HDLC에 대해서는 아래 사이트를 참조하자.
http://www.interfacebus.com/Design_HDLC.html

하지만 때로는 필요 없을 법 했던 것이 필요해지는 경우도 있는 법. 두 장치가 UART로 연결되어 있는 상황에서 HDLC와 PPP 연결 시 실측 throughput을 비교해 보아야 할 경우가 생겼다.
--- 꼭 이런 상황이 아니라도, UART로 연결 된 두 장치간에 IP를 할당하고 socket프로그래밍을 통해 통신을 하고자 한다면, HDLC대신 PPP를 사용해야 한다.

하여간 이런 경우에 PPP를 쓰는것은 위에서 예로든 인터넷 연결을 위한 Dial up 네트워크 연결 보다 훨씬 간단한데, 이유는 Authenticaiton등을 위한 설정이 필요 없기 때문이다.

아래는 QNX OS상에서 pppd을 실행시켜 연결하는 방법이다. 아마 리눅스나 다른 유닉스에서도 비슷하게 동작이 가능할 것이다.

Receiver(Server) :
 /usr/sbin/pppd debug defaultroute /dev/ser4 updetach -crtscts 1000000 netmask 255.255.255.0 10.10.10.13:10.10.10.12 &

Sender(Client) :
 /usr/sbin/pppt debug defaultroute /dev/ser4 updetach -crtscts 1000000 netmask 255.255.255.0 10.10.10.12:10.10.10.13 &



이와 같이 설정시 PPP의 Throughput 측정 결과는 Baud rate이 1Mbps일 때473Kbps로 측정되었다.
(동일 조건에서 HDLC는 685Kbps가 측정되었다. )

PPP를 사용했을 때는 그 위에 TCP/IP를 거쳐서 사용하게 되므로 HDLC를 사용하였을 때 보다 오버헤드가 클 것이라는 점에서 위 데이터는 쉽게 수긍이 가는 수치인 것 같다.

주의할 것은 UART 디바이스와 UART 디바이스 드라이버의 설정 그리고 HDLC 프로토콜의  구현 방법에 따라 Throughput과 CPU 점유율이 크기 달라질수 있다는 점이다. 보통 UART는 1Mbps와 같이 빠른 속도로는 잘 설정하지 않는데, 이는 UART가 다소 옛 기술이라 이런 고속 동작시 CPU 사용율이 높아지기 때문에다. 특히 CPU 사용율은 데이터를 read하는 횟수와 상관 관계가 큰데 이는 read가 unix시스템에서의 시스템 콜로, 시스템 콜이 불리는 횟수가 CPU 사용율과 관계가 무척 크기 때문이다. -- 시스템 콜이 불리면 user모드에서 kernel모드로 전환하기 위해 CPU가 할 일이 무척 많다.

이 CPU 점유율 문제는 TX쪽 보다 RX쪽에서 크게 발생하는데 이는 보내는 쪽은 보내고 싶은 데이터를 한번에 write로 보낼 수 있지만, read쪽은 보내는쪽에서 한번에 보내는 크기를 모르면 여러차례에 걸쳐 read 시스템 콜을 호출하여야 하기 때문이다.

Read 쪽에서 CPU사용율을 최소화 하기 위해 시스템 콜이 자주 발생하지 않도록 한번에 많은 데이터를 읽는 것이 유리하지만, 이 경우 원하는 만큼의 데이터가 RX되지 않으면 읽기 함수가 Block되어 빠른 데이터 처리가 어렵다. 따라서 보통은 N byte 가 읽혀지거나 N byte가 RX되지 못해도 M msec이후에는 Read 함수가 return되도록 설정하여야 한다. -  readcon() 참조

또한 시스템에 따라 특정 데이터를 검출하여 해당 데이터가 RX될 때 Read함수를 return해주는 기능을 제공하기도 한다.(POSIX 호환은 아님)  이런 경우 보통 0x7E가 HDLC나 PPP에서 frame의 시작과 끝을 나타내는데 사용되므로, 0x7E를 지정하여 read 함수의 호출 횟수를 최적화하면 많은 성능 향상을 가져올 수 있다.