레이블이 작업중인 게시물을 표시합니다. 모든 게시물 표시
레이블이 작업중인 게시물을 표시합니다. 모든 게시물 표시

2017년 2월 28일 화요일

BeagleBone Green Wireless

Preparing external SD Card

Install udev rule

Connect to the board

Plug in USB port of host PC

Using ssh terminal, connect to the board

WiFi connection

Update Debian packages


2015년 11월 19일 목요일

[번역] 옷 카피하기.

바느질은 배우기 매우 쉬운 것이지만, 패턴 만들기는 완벽히 배우는데 평생이 걸릴 수 도 있는 기술이다. 여러분이 초보자 이든 경험많은 숙련자이든, 초안에서 패턴을 만드는 것은 시간이 많이 걸리고 때때로 놀랄만한 노력이 필요하다. 초안에서 패턴을 만드는 데 수일을 소요하는 것 보다, 여러분이 이미 가지고 있는 옷들을 카피하여 시간과 노력을 절약하자.

이것은 니트나 스트래치 옷의 경우 맞춤 과정이 여유를 허용하고 여러분이 성공하는데 100%의 정확성을 필요로 하지 않기 때문에 특히나 쉬운 것이다. 나는 한 예로써 니트 스웨터를 자르고 꼬매는 데 사용하고 있다. 그러나, 옷이면 어는 것이나 카피 될 수 있다.

소개해 보자면 이러한 프로젝트를 위해 나는 속도감 있게 진행 있었고, 그래서 나중에 다시 사용할 수 있는 종이로 된 패턴을 실제로 만들지 않았다. 대신 최종 옷감에 직접 그리고 garment(가봉?)을 조립했다. 종이 패턴을 만들기에 앞서 소비되는 약간의 시간은 물론 내가 한 이 작업 후에 시간이 절약될지도 모른다. 그러나 이 작업은 가봉을 카피하는데 정밀한 작업인 snazzybot의 실제 great instructable의 (특히나 정밀한 사안인  짜인 옷을 카피할 경우 유용하다.)속성의 엉성한 버전으로 생각하기 바란다.

준비 됐으면 가보자 !

1 단계: 필요한 것들


- 카피에 알맞은 가봉. 정확한 가봉이 이어야만 하는 것은 아니다. 그져 여러분이 필요한 부분을 복사할 수 있으면 된다. 예를 들면 내가 카피하고 있는 스웨터는 가벼운 웃옷이지만, 나는 단지 상반 부분만 카피하고 있다.

- 여러분의 새로운 가봉을 위한 직물의 선택, 그리고 완성하는데 필요한 (지퍼나, 장식 등등의) 필요한 어떤 것들.

- 숙련자용 초크나 초크펜

- 바느질 기계/기본적인 바느질 보조품들

2 단계; 카피 시작하기


시작할 패턴 조각을 선택하고 따라 그리기를 시작하자. 나는 팔쪽부터 시작했다.

시작하면서, 나는 조심스럽게 옷감의 팔 부분을 눕혀 놓고 평평하고 주름이 없도록 만들었다.

[출처: http://www.instructables.com/id/Copy-Your-Clothes/?ALLSTEPS]

2015년 7월 9일 목요일

[작업중] Barrel Distortion이라 불리는 렌즈 왜곡 해결 알고리즘

우선 Barrel Distortion이란 무엇인지 다음의 사진을 보면 명확해진다.


[참고자료]
http://www.tannerhelland.com/4743/simple-algorithm-correcting-lens-distortion/
http://sprg.massey.ac.nz/ivcnz/Proceedings/IVCNZ_73.pdf

2015년 7월 1일 수요일

[작업중] TP-LINK WR703N 설정하기

1. OpenWRT의 배포본 설치하기
다음의 바이너리이미지를 다운로드한다.

 https://downloads.openwrt.org/snapshots/trunk/ar71xx/generic/openwrt-ar71xx-generic-tl-wr703n-v1-squashfs-factory.bin

구체적인 설치 방법은 다음의 링크를 통해서 해결하자.

http://wiki.xinchejian.com/wiki/Install_OpenWRT_on_TPlink_WR703N
https://translate.google.com/translate?sl=auto&tl=en&js=y&prev=_t&hl=ko&ie=UTF-8&u=http%3A%2F%2Fwww.geeknimo.com%2F2013%2F10%2F14%2Fopenwrt%25E7%259A%2584%25E7%25A0%2594%25E4%25B9%25A0%25E7%25AC%2594%25E8%25AE%25B0%25E4%25BA%258C%2F&edit-text=

2.WIFI 설정하기
WR703N은 기본적으로 WIFI가 비활성화 되어 있다. 우선 보드에 접속한다. 보드에 접속하는 방법은 이더넷을 연결하거나 보드에서 RS232포트를 집적 뽑아내어 터미널로 로그인하는 방법이다. 자세한 접속 방법은 다음의 링크를 참조하자.

http://www.instructables.com/id/TL-WR703N-serial-port/

보드에 접속하여 /etc/config/network 파일에 다음과 같이 수정한다.

config interface 'wan'
             option ifname 'wlan0'
             option proto 'dhcp'

그리고 구체적인 무선통신 설정은 /etc/config/wireless 파일을 다음과 같이 수정하여 해결한다.

             # REMOVE THIS LINE TO ENABLE WIFI:
config wifi-iface
             option device radio0
             option network wan
             option mode sta
             option ssid '와이파이네트워크이름'
             option encryption psk
             option key '와이파이네트워크암호'


리부팅한다. 참고적으로 위의 와이파이 네트워크는 주변의 사용 가능한 SSID와 암호이어야 한다. 그래야 인터넷에 접속하여 다음의 사항들을 진행할 수 있다.

3. sysupgrade 설치


4. opkg 설치

용량한계에 따른 문제들

tftp 설치

커스텀 롬 설치하기

10. mjpg-streamer 설치하기

http://wiki.openwrt.org/doc/howto/webcam

2014년 2월 28일 금요일

[작업중] 555타이머를 이용한 전원 지연 회로

555타이머를 이용한 전원 지연회로는 진공관 앰프를 제작할때 많이 사용한다. 진공관 앰프는 특성상 예열 과정이 필요하다. 진공관 앰프에 전원을 인가할때 동시에 스피커에도 전원이 인가되면 '퍽 퍽' 하는 굉음이 발생하기도 한다. 이러한 전원 인가시 발생하는 굉음을 차단하기 위해서 전원 지연회로를 사용한다. 일반적으로 전원 지연회로로 알려져 있지만 실제로는 스피커 지연연결회로가 되겠다.

원리는 555에 저항(R)과 캐패시터(C)에 의해 결정되는 시간 이후에 555타이머의 출력이 발생되게 하는 것이다. 로직은 555타이머가 담당하고 있지만, 실제로 전원연결이나 스피커 신호를 연결하는 것은 Relay가 맏고 있다.  Relay는 전기 신호로 유도되는 전자기힘으로 동작하는 물리적인 스위치이다. 그래서 전기신호가 인가 되었을때 스위치가 켜지게 설정할 것인지 아니면 전기 신호가 인가 되었을때 스위치가 단선 되도록 할 것인지는 용도에 따라 고민해 보아야 하는 문제이다. 각각 장단점을 가지고 있다.

Relay에 전원이 인가 되었을때 스위치가 연결되도록 한 설정에서는 회로에 전원이 혹은 스피커에 음성 신호가 연결되어 정상 동작하는 동안 Relay에는 항상 전원을 공급해 주어야 한다. 이 경우에 원래의 회로에서 소모되는 전력 이외에 추가적인 전력 소비가 아무래도 발생한다. 그리고 반대의 경우 전원이 인가 되지 않을때 스위치가 연결되도록 한 설정에서는 회로가 정상 동작할때 발생하는 추가적인 전력 소비가 없다 하지만, 다음과 같은 단점이 존재한다. relay 전원이 인가 되지 않을때 심지어는 전체 전원이 인가되지 않았을 경우에도 스위치는 연결된 상태로 남아 있게 된다. 그러다 전체 전원이 인가될 때 relay에 동시에 전원이 인가되어 순식간에 스위치가 단선되고 일정 시간이 지난 후에 다시 스위치가 연결되는 과정을 거친다. 요약 하자면 스위치는 연결된 상태 였다가 전원이 인가되면 단선되고 일정 시간이 지난 후에 다시 연결된다. 이 상태에서 불가피하게 초기에 전원이 인가된 동안 순간적인 스위치 연결은 피할 수 없다. 이 부분은 적당한 용량의 캐패시터를 사용해서 해결 가능하지만, 아무래도 순간적인 오작동에도 민감한 회로의 경우 특히 명심해 두어야 한다.

아래는 555타이머를 이용한 시지연 회로이다.


렐리이에 전원이 인가 될 시 동작하는 회로

렐리에 전원이 인가 되지 않을 때 동작하는 회로


2014년 2월 13일 목요일

[작업중] Swing Arm 방식의 노트북 스탠드

예전에 탁상용 백열등 스탠드 중에서 스프링으로 지지되는 방식이 있었는데 이것을 활용하면 노트북 스탠드로써 아주 편리할 것 같다는 생각이 문득 들었다(http://www.amazon.com/Boston-Harbor-TL-WK-134E-WH-3L-Swing-White/dp/B0026KLI6C/ref=sr_1_2?s=hi&ie=UTF8&qid=1392230944&sr=1-2&keywords=boston+harbor+architect+swing+arm+desk+lamp). 그리고 Kickstarter에서 한번 본적있는 로봇 팔도 이 생각을 구체화하는데 도움이 될 것 같았다(https://www.kickstarter.com/projects/ufactory/uarm-put-a-miniature-industrial-robot-arm-on-your?ref=live).

인터넷에서 swing arm lamp로 검색을 해보면 많은 것들을 참고 삼아 볼 수 있다. 아마도 스프링 방식으로 되어있는 것들이 여전히 많이 보이는 것이 이방식이 가장 안정 적인 방식이 아닌가 싶다. 다른 기타 방식 베이링 방식이나 각 관절을 조여서 고정하는 방식은 그 수명과 편리성 적인 측면에서 문제가 있어 보인다.


swing arm 방식의 백열등 (출처: www.amazon.com)
 



해당 제품의 구체적인 사진들
 (출처 : http://www.amazon.com/Boston-Harbor-WK-618E-3L-Swing-Holder/dp/B002ZKHZC4/ref=sr_1_7?s=hi&ie=UTF8&qid=1392235016&sr=1-7)




그럼 기본 바탕은 swing arm lamp방식으로 하되  헤드 부분에 노트북 받침이 들어가야 하기 때문에 이 부분에 대한 수정이 이루어 져야 한다. 이 부분에 대한 수정과 위에서 살펴본 로봇 팔의 모터 부분을 자동차 트렁크나 창문 고정에 사용되는 실린더방식을 사용하여도 훌룡한 것이 나올 것 같기도 하다. 문제는 돈이지만 말이다.


네개의 자유도를 가진 로봇팔 (출처: www.kickstarter.com)

이 세상에는 새로운 것이 없는 것 같다. 찾아 보니 이미 이와 같은 개념의 제품이 나왔다(http://www.laptopdesk.net/ipad-swing-arm-mount.html). 항상 이럴때 김이 세지만.  뭐 사람 생각이 거기서 거기라는 생각이 든다. 아래의 그림은 해당 제품의 구체적인 도면쯤 되겠다.

swing arm ipad mount 도면 (출처: http://www.laptopdesk.net/ipad-swing-arm-mount.html)
이렇게 된거 이 제품에서 좀 더 개선할 점이 없는지 살펴 보아야 겠다.



2014년 1월 5일 일요일

[작업중] 9V 타입의 Li-ion 빠떼리를 위한 충전기 개발

여러가지의 충전기를 참고하여 다음의 회로를 그려 보았다. 이전에 태양빛 충전기와 풍력 충전기에 대한 내용도 있지만 이 회로를 그리는데 참고한 내용은 다음의 사이트들이다. 





위의 회로는 기본적으로 정전류회로와 전압 감시 회로의 조합이다. 정전류회로는 LM317과 고와트의 저항으로 이루어져 있고 전압 감시 회로는 NE555를 두 개의 비교기로 사용해서 빠떼리 전압 감시한다.

LM317로 정전류 회로를 구성하는 방법은 많이 찾아 볼 수 있다. 위의 회로는 4옴/1W 저항을 사용하기 때문에 1.25V/4옴=312mA의 정전류를 유지하게된다.

LM317을 이용한 정전류 회로의 구성
출처 : http://diyaudioprojects.com/Technical/Voltage-Regulator/

그런데 한 가지 찝찝한 구석이 있는데 위의 두 회로에서 한가지 차이점이 ADJ 핀에 4.7K옴 짜리 저항이 들어가고 있다는 점이다. 나도 완벽하게 이해되지는 않지만, 참조 사이트의 댓글들을 살펴보니 NPN 트랜지스터의 Pullup저항 정도로만 사용되기 때문에 위의 정전류 회로에 아무런 영향을 주지 않는다고 한다. [The 4.7k resistor back to the ADJ pin is arbitrary, as long as it's high enough resistance to allow the 555 to pull the adj pin low.  The 2N3904 between the 555 and the LM317 is used as a level translator, since the 555 is running on 5V where the ADJ pin will be above 14V. (출처 : http://blog.thelifeofkenneth.com/2013/01/555-constant-current-lead-acid-battery.html)]

이제는 NE555의 두 개의 비교를 이용해서 빠떼리 전압 감시 회로로 이용하는 방법에 대해서 살펴보자.


위의 그림은 NE555의 내부 구조도 이다. 

2013년 12월 22일 일요일

[작업중] 무료 공개용 PCB 설계 프로그램 Kicad 사용하기 (도면 라이브리 생성하기)

이전에 설명하였듯이 Kicad의 도면 그리기 프로그램은 아래의 그림과 같이 구성되어 있다. Kicad에서 도면 라이브러리의 각 부품을 배치와 배선연결은 사용자가 원하는 곳 아무 곳에나 이루어 질 수 없다. 이러한 작업은 기본적으로 그리드라는 단위에서 이루어 진다. 이것은 앞으로 설명할 PCB 배선 작업에서도 동일하게 해당하는 것으로 알아 두어야 할 것 중에 하나이다.

 아래의 그림에서 보듯이 Kicad는 inch와 mm를 동시에 지원한다. 하지만, 워낙에 PCB 제조 분야가 inch에 친숙하다. 그래서 수시로 inch와 mm 단위를 오가는 작업이 빈번하다. 이것은 어디까지나 친숙한 단위를 선택하면된다. 아무튼 여기서의 설명은 inch단위에서 이루어 진다. 도면 그리기 프로그램의 그리드의 기본 설정은 아래의 그림과 같이 50.0mils로 되어 있다. 도면 라이브러리도 50.0mils 그리드에서 작성된 것이 많기 때문에 대부분 50.0mils의 그리드로 작업하는 것을 추천한다.



이제는 도면 라이브러리 편집 프로그램을 실행하자. 실행은 "Tool"메뉴의 "Library Editor"를 실행하거나 툴바에서 직접 Library Editor를 실행하면 된다.




실제로 도면 라이브러리를 생성하는 작업에 앞서 라이브러리가 어떻게 구성되어 있고 Kicad에서 기본적으로 제공하는 라이브러리를 살펴보는 작업은 중요하다. 내가 필요한 부품이 기존의 라이브러리에 존재하는 지 살펴보고 없다면 내가 원하는 부품과 가까운 부품을 찾아 내는 것은 많은 도움이 된다. 왜냐하면 기존 라이브러리에서 약간만 변경해서 새로운 부품으로 저장하면 수고를 많이 덜 수 있기 때문이다.

아무튼 Kicad가 관리하는 도면 라이브러리는 /usr/share/kicad/library에 존재한다. 이전에 설명하였듯이 여기에는 도면 라이브러리와 PCB 라이브러리가 혼재한다. 도면 라이브러리는 *.lib라는 형태의 파일명을 가지고 있고, PCB 라이브러리는 *.dcm 형태의 파일명을 가지고 있다. 이중 아무런 파일을 하나 열어 보면 ASCII 코드로 되어 있다는 것을 확인 할 수 있다. 그래서 조금만 살펴보면 텍스트 에디터로도 새로운 부품을 생성할 수 있다.

Library Editor 프로그램은 아래의 그림과 같다. 먼저 프로그램의 제목란을 살펴보면 no library selected라는 메시지를 살펴볼 수 있다. 부품을 그리기 위해서 가장 먼저해야 하는 작업은 작업라이브러리를 선택해야하는 작업이다.




 선택"아이콘을 실해하여 제작할 부품의 카테고리에 맞는 "라이브러리"를 선정한다. 여기에서는 "cpu"라는 라이브러리에 ATmega16이라는 부품을 제작한다.






부품정보를 입력하면 초기화면은 다음과 같다. 레퍼런스 번호와 이름만 생성된다. 나머지 핀과 형태는 모두 사용자가 만들어 주어야 한다.







작업중....................................

2013년 12월 2일 월요일

[번역중] GCC의 linker를 위한 linker command language(ld 파일 명령어) 설명서.

[출처 : https://web.eecs.umich.edu/~prabal/teaching/eecs373-f11/readings/Linker.pdf]

3. Linker Scripts

모든 link(ld라는 오브젝트 파일 합성 프로그램)는 linker script의 의해서 제어된다. 이 스크립트는 linker command language로 쓰여 진다.

linker script의 주된 목적은 어떻게 입력 파일들(컴파일된 모든 오브젝트 파일)의 모든 섹션들을 출력 파일(컴파일 최종 단계의 실행 파일)에 위치 시켜야 하는지 어떻게 출력 파일의 메모리 구성을 설정해야 하는지에 대해서 설명한다. 대부분의 linker script들은 이것 이상의 아무것도 하지 않는다. 그러나, 필요하다면, linker script는 아래에서 설명할 명령어들을 이용해서 많은 다른 동작을 하도록 linker를 지시할 수 있다.

linker는 항상 linker script를 사용한다. 만약 여러분이 직접 이것을 제공하지 않다면, linker는 실행 가능한 linker로써 컴파일되는 기본 스크립트를 사용할 것이다. 여러분은 기본 linker script를 보기 위해서 '--verbos' 명령행 옵션을 사용할 수 있다. '-r'이나 '-N' 같은 어떤 명령행 옵션들은 이 기본 linker script에 영향을 준다.

여러분은 '-T' 명령행 옵션을 이용해서 여러분 자신의 linker script를 사용할 수 도 있다.
여러분이 이것을 사용할 때, 여러분의 linker script는 이 기본 linker script를 대체할 것이다.

여러분은 또한 linker script가 링크될 파일일 지라도 linker의 입력 파일로서 이름 짓음으로써 암시적으로 사용수도 있다. 섹션 3.11[Implicit Linker Scripts], 페이지 74를 보라.

3.1. 기본적인 linker script의 개념

우리는 linker script 언어를 설명하기 위해서 몇 가지 기본 개념과 문법을 정의 할 필요가 있다. 
linker는 여러 개의 입력 파일을 합성해서 하나의 출력 파일로 만든다. 출력파일과 각각의 입력 파일은 object file format으로 알려진 특수한 데이터 포멧으로 되어 있다. 그리고 각 파일은 object 파일이라고 부르고 출력 파일은 executable(실행파일)이라고 부른다. 그러나 우리의 목적에 따라 우리는 출력파일도 object 파일이라고 부르겠다. 각각의 object 파일은 sections 항목을 가지고 있다. 우리는 앞으로 종종 input section이 입력 파일의 section을 의미하는 것으로 사용할 것이다. 이와 유사하게 출력 파일의 section은 output section으로 ...

object 파일의 각 section은 이름과 크기를 갖는다. 대부분의 section 들은 또한 section contents로 알려진 각 section에 관련된 데이타 블럭을 가지고 있다. section은 loadable로 표시되기도 하는데 이것은 출력 파일이 실행될때 이 section의 내용들이 메모리로 적재되어야 한다는 것을 의미한다. 내용물이 없는 section은 동적할당(allocatable) 으로 표시되기도하는데 이것은 메모리의 한 공간이 사용되지 말고 확보되어져 있어야 하고 특별히 그곳에 어떠한 내용이 적재되어 지지않아야 한다는 것을 의미한다. ( 어떠한 경우에는 이러한 메모리 공간은 '0'으로 채워져야 하는 때도 있다.) loadable혹은 allocatable 둘다 아닌 section은 보통 디버깅정보와 같은 종류의 내용들을 포함하고 있다.

모든 loadable 혹은 allocatable 형태의 output section은 두 개의 address들을 가지고 있다. 하나는 VMA 혹은 가상 메모리 주소(virtual memory address)이다. 이것은 출력 파일이 실행 될때 section이 가지게 될 주소이다. 그리고 다른 하나는 LMA 혹은 적재 메모리 주소(load memory address)라는 것이다. 이것은 section이 적재되어야 하는 주소이다. 대부분의 경우 이 두 주소는 동일하다. 이 둘이 다르게 될때의 예는 data section이 ROM 영역에 적재되고 프로그램이 시작될때 RAM 영역으로 복사되는 경우이다. ( 이러한 기법은 ROM 기반의 시스템에서 전역 변수를 초기화 하고자할 때 자주 사용된다.) 이러한 경우 ROM영역의 주소는 LMA가 되고 RAM영역의 주소는 VMA가 될 것이다.

여러분은 '-h' 옵션을 갖는 objdump 프로그램을 사용해서 object 파일의 모든 sections들을 볼 수 있다. 모든 object 파일은 또한 symbol table이라고 알려진 symbol의 리스트를 가지고 있다. symbol은 정의되어 질 수도 있고 아닐 수 도 있다. 각각의 symbol은 이름을 가지고 있고 각각의 정의된 symbol은 주소를 가지고 있다. 여러분이 C나 C++ 코드를 object 파일로 컴파일 한다면, 모든 정의된 함수화 전역혹은 지역 변수에 대한 정의된 symbol을 갖게 될 것이다. 입력 파일에서 참조 되는 모든 정의되지 않은 함수 혹은 전역 변수는 정의되지 않은 symbol이 될 것이다.

여러분은 nm 프로그램이나 '-t' 옵션을 갖는 objdump 프로그램을 사용해서 object 파일의 symbol들을 살펴 볼 수 있다.

3.2. Linker Script Format

linker scripts는 텍스트 파일이다.

여러분은 여러개의 명령어의 조합으로 linker script를 작성한다. 각각의 명령어는 매개변수에의해서 부차적으로 따라붙는 keyword이거나, symbol의 배치중의 하나일 것이다. 여러분은 ';'을 이용해서 명령어를 구분할 수 있다. whitespace(탭, 스페이스, 등등)는 일반적으로 무시된다.

파일이나 format 명과 같은 문자열은 통상 직접적으로 입력 되어 질 수 있다. 만약 파일 이름이 파일 이름들을 구분하는 용도로 사용되는 ','와 같은 특수 문자를 포함하고 있다면, 여러분은 " " 사이에 파일 이름을 집어 넣어야 한다. 파일이름에 "를 사용하지는 않는다.

여러분은 C 언어에서와 같은 '/*', '*/'로 linker script에 주석을 달수도 있다. C에서 처럼 주석은 문법적으로 whitespace와 같다.

3.3. 간단한 linker script 예제

많은 linker script들은 대체적으로 단순하다.

가장 단순한 가능한 linker script는 단 하나의 명령어:'SECTIONS' 를 갖는다. 여러분은 출력 파일의 메모리 배치를 설명하는데 'SECTIONS' 명령어를 사용한다.

'SECTIONS' 명령어는 강력한 명령어이다. 여기서 우리는 이것의 단순한 사용을 설명할 것이다. 여러분의 프로그램이 code와 초기화된 data, 그리고 초기화 되지 않은 data만 가지고 있다고 가정하자. 그럼 순서에 따라 각각 그에 해당하는  '.text', '.data'그리고 '.bss' section 들이 존재하게 될 것이다. 그럼 여러분의 입력 파일에 나타나는 유일한 sections만 있다고 가정 할 수 있다.

이 예제에서 code는 0x10000에 적재되어야하고 data는 0x8000000에서 시작되어야 한다고 말해보자. 여기에 이것을 수행하는 linker script가 있다.

 SECTIONS  
 {  
 . = 0x10000;  
 .text : { *(.text) }  
 . = 0x8000000;  
 .data : { *(.data) }  
 .bss : { *(.bss) }  
 }  

여러분은 'SECTIONS' 키워드와 symbol 배치와 꼬부라진 괄호로 묶여진 출력 section description들의 나열을 사용해서 'SECTIONS' 명령어를 작성하였다.

위의 예제의 'SECTIONS' 명령어 안의 첫번째 줄은 location counter인 '.'의 특수기호의 값을 설정한다. 만약 여러분이 어떤 다른 방법으로(다른 방법은 나중에 설명할 것이다.) 출력 section의 주소를 지정하지 않는다면, 주소는 location counter의 현재 값으로 지정된다. 그럼 location counter는 출력 section의 크기 만큼 증가된다. 'SECTIONS' 명령어가 시작할때 location counter는 '0' 값을 갖는다.

둘째 줄은 '.text'의 출력 section을 정의하고 있다. ':'은 지금은 내용상 무시해도 되지만 요구되는 문법이다. 출력 section 이름 이후에 꼬부라진 괄호를 가지고 여러분은 이 출력 section에 위치해야할 입력 section의 이름을 나열 할 수 있다. '*(.text)'라는 표현은 모든 입력 파일에 있는 모든 '.text' 입력 section들을 의미한다.

출력 section '.text'가 정의된 곳의 location counter가 '0x10000'이기 때문에 linker는 출력 파일에 있는 '.text' section의 주소가 '0x10000'이 되도록 설정할 것이다.

나머지 줄들은 출력파일의 '.data'와 '.bss' section들을 정의한다. linker는 '.data' section을 '0x8000000'에 위치 시킬 것이다. linker가  '.data' 출력 section을 위치시킨후, location counter의 값은 '0x8000000'에 '.data' section의 크기가 더해진 값이 될 것이다. 그 영향으로 linker는 '.bss' 출력 section을 메모리의 '.data' 출력 section 바로 뒤에 위치 시킬 것이다.

linker는 필요에 따라서 location counter를 증가시면서 각각의 출력 section이 잘 짜여진 배치를 갖도록 할 것이다. 이 예제에서 '.text'와 '.data' section들을 위해 특정 지어진 주소는 아마도 어떤 메모리 배치 요구사항을 만족할 것이다. 그러나 linker는 '.data'와 '.bss' section 사이에 작은 여유 공간을 만들게 될지도 모른다.

이것이 바로 간단하고 완벽한 linker script이다!

3.4. 간단한 linker script 명령어들

이번 절에서는 간단한 linker script 명령어들을 설명한다.

3.4.1. entry point 지정하기

프로그램에서 실행되는 첫 번째 코드(instruction)은 entry point라고 불린다. 여러분은 이 entry point를 지정하는데 ENTRY linker script 명령어를 사용할 수 있다. 그리고 그 매개변수는 symbol 이름이 된다:

 ENTRY(symbol)  

entry point를 지정하는 몇 가지 방법들이 존재한다. linker는 순서대로 다음 방법 중 하나를 시도하여 entry point를 지정하고 그들 중 하나가 성공적일 때 멈출 것이다.

 명령행 에서 '-e'옵션을 지정하기;  
 linker script에서 ENTRY(symbol) 명령어로 지정하기;  
 start symbol의 값을 지정해서 지정하기;  
 '.text' section의 첫 번째 바이트의 주소를 지정하기;  
 주소 '0'을 지정하기;  

3.4.2. 파일들을 다루는 명령어들

파일들을 다루는 몇 가지 linker script 명령어들.

INCLUDE filename

linker script 파일이름을 포함시킨다. 파일은 현재 디렉토리에서 검색되어 지거나 '-L' 옵션으로 지정된 어떤 디렉토리에서도 검색되어 질 것이다. 여러분은 10단계의 까지의 INCLUDE 중첩 호출을 할 수 있다.

여러분은 MEMORY나 SECTIONS 명령어 혹은 출력 section description의 가장 상위 레벨에서 INCLUDE 지시어를 위치 시킬 수 있다.

INPUT(file, file, ...)
INPUT(file file ...)

INPUT 명령어는 명령행에서 파일 이름이 지정되는 것 처럼 link 과정에서 이름 지어진 파일들을 포함하도록 linker에게 지시한다.

예를 들자면, 여러분이 link를 수행할때 언제라도 항상 'subr.o'을 포함하고자 하지만, 매번 link 명령행에 이것을 집어 넣는 것을 성가셔 할 수 있다면(?), 여러분은 여러분의 linker script에 'INPUT(subr.o)'을 추가해서도 같은 효과를 볼 수 있다. 사실 여러분만 좋다면, linker script에 입력 파일 모두를 나열할 수 있고 그렇게 해서 '-T' 옵션만 제외하고 다른 옵션은 전혀 사용하지 않고linker의 기능을 수행할 수 있다. 컴파일러의 sysroot 첨두어가 설정되고 파일 이름이 '/' 문자로 시작 된 경우. 처리되는 script는 sysroot 첨두어로 설정된 경로의 내부에 위치해야 하고, 해당 파일들은 sysroot 첨두어에 설정된 경로에서 찾아 지게 될 것이다. 다른 경우에는 linker는 현재 디렉토리에서 파일을 찾을 것이다. 만약 찾을 수 없다면, linker는 archive library 탐색 경로들에서 이것들을 찾을 것이다. 좀 자세한 것은 section 2.1 [명령행의 옵션]의 세번째 페이지에 있는 '-L' 옵션에 대한 설명을 보기 바란다.

만약 여러분이 'INPUT (-lfile)'형태로 사용한다면, ld는 명령행 옵션 '-l'함께 있는 것처럼 이름을 libfile.a의 형태로 변경할 것이다.

여러분이 암시적인 linker script에서 INPUT 명령어를 사용할 때, 파일들은 linker script 파일이 포함되게 되는 지점에 link에 포함되게 될 것이다. 이것들은 archive(라이브러리 파일)를 탐색하는 것에도 영향을 줄 수 있다.

GROUP(file, file, ...)
GROUP(file file ...)

GROUP 명령어는 파일들이 모두 archives 형태를 가져야 하고 그들은 어떤 새로운 정의 되지 않은 참조사항들이 발생되지 않을때까지 반복적으로 탐색되어 진다는 점을 제외하고 INPUT과 유사하다. 자세한 사항은 section 2.1 [명령행 옵션들]의 세번째 페이지에 있는 '-(' 옵션의 설명을 보기 바란다.

AS_NEEDED(file, file, ...)
AS_NEEDED(file file ...)

This construct can appear only inside of the INPUT or GROUP commands, among
other filenames. The files listed will be handled as if they appear directly in the
INPUT or GROUP commands, with the exception of ELF shared libraries, that
will be added only when they are actually needed. This construct essentially
enables ‘--as-needed’ option for all the files listed inside of it and restores
previous ‘--as-needed’ resp. ‘--no-as-needed’ setting afterwards.

2013년 11월 29일 금요일

[작업중] mjpeg 동영상 압축을 위한 jpeg verilog 코드 개발: 사전 지식

사전지식

 mjpeg은 동영상을 압축하는 표준이지만, 그 내부를 들여다 보면 가장 핵심적인 부분은  사진 압축 방식인 Jpeg이 담당하고 있다. 대표적으로 BeagleBone Black이나 Raspberry Pi에서 많이 사용되고 있는 mjpeg-streamer의 코드를 살펴보면 좀 더 확실해 진다.

 아래의 코드는 mjpeg-streamer/plugins/inputuvc에 있는 inputuvc.c 파일의 쓰레드 함수의 내용이다. 즉, 항시 실행되면서 uvc 방식의 웹캠 드라이버로 부터 영상을 얻어오고(videoIn 구조체) 해당 영상의 형식이 YUYV방식이면 compress_yuyv_to_jpeg()에 videoIn과 압축된 영상을 저장할 버퍼를 넘겨주는 작업을 항상 반복하게된다.

 /******************************************************************************  
 Description.: this thread worker grabs a frame and copies it to the global buffer  
 Input Value.: unused  
 Return Value: unused, always NULL  
 ******************************************************************************/  
 void *cam_thread( void *arg ) {  
 ......  
   /*  
    * If capturing in YUV mode convert to JPEG now.  
    * This compression requires many CPU cycles, so try to avoid YUV format.  
    * Getting JPEGs straight from the webcam, is one of the major advantages of  
    * Linux-UVC compatible devices.  
    */  
   if (videoIn->formatIn == V4L2_PIX_FMT_YUYV) {  
    DBG("compressing frame\n");  
    pglobal->size = compress_yuyv_to_jpeg(videoIn, pglobal->buf, videoIn->framesizeIn, gquality);  
   }  
   else {  
    DBG("copying frame\n");  
    pglobal->size = memcpy_picture(pglobal->buf, videoIn->tmpbuffer, videoIn->buf.bytesused);  
   }  
 .......  
 }  

 mjpeg-streamer/plugins/inputuvc밑의 jpeg_utils.c 파일내에 있는 실제적인 압축과정을 수행하는 compress_yuyv_to_jpeg()함수이다. 전체적인 흐름은 jpeg압축에 필요한 사전작업을 수행하고 struct vdIn *vd로 부터의 yuyv형태의 영상 버퍼를 rgb형태로 변환하여 ptr에 저장한다. 그리고 ptr 버퍼의 내용을 libjpeg을 이용해서 압축을 수행하는 과정이다.

 /******************************************************************************  
 Description.: yuv2jpeg function is based on compress_yuyv_to_jpeg written by  
        Gabriel A. Devenyi.  
        It uses the destination manager implemented above to compress  
        YUYV data to JPEG. Most other implementations use the  
        "jpeg_stdio_dest" from libjpeg, which can not store compressed  
        pictures to memory instead of a file.  
 Input Value.: video structure from v4l2uvc.c/h, destination buffer and buffersize  
        the buffer must be large enough, no error/size checking is done!  
 Return Value: the buffer will contain the compressed data  
 ******************************************************************************/  
 int compress_yuyv_to_jpeg(struct vdIn *vd, unsigned char *buffer, int size, int quality) {  
  struct jpeg_compress_struct cinfo;  
  struct jpeg_error_mgr jerr;  
  JSAMPROW row_pointer[1];  
  unsigned char *line_buffer, *yuyv;  
  int z;  
  static int written;  
  line_buffer = calloc (vd->width * 3, 1);  
  yuyv = vd->framebuffer;  
  cinfo.err = jpeg_std_error (&jerr);  
  jpeg_create_compress (&cinfo);  
  /* jpeg_stdio_dest (&cinfo, file); */  
  dest_buffer(&cinfo, buffer, size, &written);  
  cinfo.image_width = vd->width;  
  cinfo.image_height = vd->height;  
  cinfo.input_components = 3;  
  cinfo.in_color_space = JCS_RGB;  
  jpeg_set_defaults (&cinfo);  
  jpeg_set_quality (&cinfo, quality, TRUE);  
  jpeg_start_compress (&cinfo, TRUE);  
  z = 0;  
  while (cinfo.next_scanline < vd->height) {  
   int x;  
   unsigned char *ptr = line_buffer;  
   for (x = 0; x < vd->width; x++) {  
    int r, g, b;  
    int y, u, v;  
    if (!z)  
     y = yuyv[0] << 8;  
    else  
     y = yuyv[2] << 8;  
    u = yuyv[1] - 128;  
    v = yuyv[3] - 128;  
    r = (y + (359 * v)) >> 8;  
    g = (y - (88 * u) - (183 * v)) >> 8;  
    b = (y + (454 * u)) >> 8;  
    *(ptr++) = (r > 255) ? 255 : ((r < 0) ? 0 : r);  
    *(ptr++) = (g > 255) ? 255 : ((g < 0) ? 0 : g);  
    *(ptr++) = (b > 255) ? 255 : ((b < 0) ? 0 : b);  
    if (z++) {  
     z = 0;  
     yuyv += 4;  
    }  
   }  
   row_pointer[0] = line_buffer;  
   jpeg_write_scanlines (&cinfo, row_pointer, 1);  
  }  
  jpeg_finish_compress (&cinfo);  
  jpeg_destroy_compress (&cinfo);  
  free (line_buffer);  
  return (written);  
 }  

 여러 곳에서 보고 되듯이 BeagleBone과 Raspberry Pi 등의 인기있는 개발 보드는 uvc 드라이버에 의해 구동되는 웹캠의 영상을 위와 같은 과정을 통하여 mjpeg 방식으로 압축한다. 하지만, mjpeg의 초당 압축 성능이 5fps정도로 만족 스럽지 않은 것으로 알려져 있다. 대부분의 시간을 잡아 먹는 과정은 YUV4:2:2를 RGB8:8:8로 변환하는 곳으로 알려져 있다.

 이와 같은 성능 저하 요인을 개선하는 방법으로 좀더 성능이 좋은 cpu를 사용하거나 yuv를 rgb로 변환하는 하드웨어 모듈을 내부에 가지고 있는 cpu를 사용하는 것이다. 가장 확실한 방법은 mjpeg 압축을 수행하는 모듈이 있는 cpu를 사용하는 것이지만, 이 같은 개선책은 어느 하나 쉬운 접근법이 존재하지 않는다. 이와 같은 이유로 mjpeg을 수행하는 독립된 외부 장치를 구성하는 방법이 될 것 같다. 그 가장 쉬운 방법은 FPGA를 활용하는 것이다. 그 이유는 하드웨어 구성에 있어서 신경쓸 것이 없고 그져 소프트웨어 적인 방법으로 모든 것이 해결 가능하기 때문이다.

  앞으로 설명할 내용은 FPGA에서 구현할 mjpeg 압축을 verilog HDL로 코딩하는 과정을 설명하는 것이다. 그 과정은 몇 가지 큰 걸림돌들이 존재하는데 성능을 극대화 하고 소모하는 FPGA의 공간을 줄이기 위해서 부동 소수점 연산의 불가피한 최적화와 이론적인 mjpeg 알고리즘과는 조금 다르게 전개 되는 DCT과정은 이해 하기가 조금 까다롭고 설명이 많이 필요하다. 이후의 내용은 jpeg 압축의 전체적인 설명, 부동 소수점 연산의 최적화, DCT 과정및 최적화, 마지막으로 이 모든 것을 연결하고 그 결과를 살펴보는 과정으로 이루어 질 것이다.

jpeg 압축

 jpeg 압축은 기본적으로 손실 압축이다. 손실 압축임에도 불구하고 jpeg압축 사진을 볼때 압축 이전의 영상과 별다른 차이를 느끼지는 못한다. 그 원인은 사람이 별로 느끼지 못하는 성분만 원래의 영상에서 제거하기 때문이다. 달리 말하면 사람이 차이를 느끼지 못하는 영상의 고주파 성분을 DCT(Discrete Cosine Transform) 통해서 구분해 내고 이진화(Quantization)과정을 통하여 제거하기 때문이다. 이와 같은 과정이 Jpeg 압축이 갖는 핵심 기능이다.

.....................

2013년 11월 21일 목요일

[번역중] 풍력 발전및 태양열 발전을 위한 555에 기반한 정전류 자동차용 배터리 충전기 제작하기

[출처 : http://www.mdpub.com/555Controller/]

555 칩에 기반한 새롭게 개선된 배터리 충전기
햇빛과 풍력 발전 시스템을 위한 간단한 충전기


새로운 소식 : 이 555 칩에 기반한 햇빛 충전기 프로젝트는 555칩 디자인 콘테스트의 Utility Category에서 일등 먹었습니다!!!!! 콘테스트에 대한 좀 더 자세한 내용을 원하시면 이 문서의 맨 아래로.

 몇년 전에 나는 원격에 있어서 전기가 들어오지 않는 나의 소유물에 전력을 제공하기 위해 자체적으로 풍력 발전 터빈햇빛 발전용 판을 만들기 시작했습니다. 충전기는 배터리가 방전되거나 과충전되지 않도록 하기위해서 풍력 혹은 햇빛 충전 시스템의 기본적인 부분이다. 이런 충전기는 배터리의 전압을 항상 감시하고, 배터리가 완전히 충전 되었을때 배터리의 충전을 중단하고 배터리가 사전에 지정된 전하량 밑으로 도달하면 다시 충전을 시작하도록 한다.


 내가 이전의(원래의) 집에서 만든 풍력 터빈, 햇빛 충전판, 그리고 충전기 디자인을 웹에 게시하였을때, 사람들에게 널리 알려지게 되었습니다. 전세계의 많은 사람들이 자신에게 알맞은 형태로 만들어 왔습니다. 그러자 나는 사람들로 부터 질문과 조언에 대한 이메일을 홍수와 같이 받았습니다. 이메일의 매우 많은 부분이 사람들이 원래의 충전기 디자인을 구성하는데 생기는 문제점들에 간한 것이었습니다. 그 디자인은 shop class에 있는 어떤 middle school lesson plans보다 더 발전된것이 확실하기 때문에 이 과정은 잘 숙련된 사람에게 구현될 수 있을 것입니다. 

 원래의 충전기 디자인은 현장에서 사용된지 몇년이 지났어도 여전히 잘 동작합니다. 전 세계의 많은 사람들이 이것의 복사본을 만들어 왔습니다. 이 충전기의 개발에 관한 원래의 이야기는 나의 풍력 터빈 페이지에서 찾아 볼 수 있습니다.

 문제는 전기분야에 대한 경험이 부족한 사람들이 이것을 만들고 동작하게 만드는데 어려움을 겪고 있는 것입니다. 이 회로는 전기 초보자에게는 좀 복잡하고 혼란스럽습니다. 세상과 좀 멀어져 있는 어떤 사람들은 필요한 모든 부품을 구하는 것에 어려움을 겪고 있었습니다. 충전기를 만드는데 도움을 요청하는 일상적인 이메일들은 나에게 이것을 다시 디자인 하도록 부추겼습니다.

 그래서 나는 나의 햇빛/풍력 충전기 회로를 아주 간단히하도록 하고자 하였습니다. 나는 가능하다면 단 하나의 IC로 회로가 이루어지도록 하고 가능한 만큼 부품의 수를 줄이고자 하였습니다. 나는 또한 세계 어느 곳에도 구하기 쉬워 보이는 부품만 포함하도록 하였습니다. 이러한 것들은 더 많은 사람들이 진행하는데 문제없이 만들 수 있도록 할 것입니다.

 나의 친구중 한명은 대중적인 마이크로 컨트롤러 칩중 하나를 사용하도록 전환할 것을 제안하였고, 모든 아날로그 회로들은 하나의 칩으로 대체하였습니다. 이것은 아마도 부품의 수는 줄이는 방법을 찾도록 해줄 겁니다. 그러나, 나는 마이크로 컨트롤러들이 너무 비싸거나 세계의 어떤 곳에서는 구하기 어렵거나, 프로그램 기술이 없는 사람들에게 어려울지도 모른다는 걱정이 있습니다. 이 후에는 마이크로 컨트롤러의 선택의 가능성이 있지만, 나는 당분간은 아날로그 회로에 머물러 있기로 하였습니다. 



여기에 나의 원래의 충전기 회로의 도면이 있습니다. 충전기 회로의 핵심은 voltage divider와 두 개의 comparators, 그리고 S-R 플립플롭으로 구성되어져 있습니다. 나의 원래의 생각은 LM339 Quad Comparator IC를 사용해서 다시 디자인하고자 하였습니다. 나는 이 회로에 두개의 comparators가 필요하였고, 칩에 있는 comparator들 중 다른 두개를 이용해서 S-R 플립플로을 만들 수 있었다. 나는 이러한 생각을 당분간 고려하였습니다. 그리고 몇 개의 테스트 회로를 빵판에 구현해 보았습니다. 나는 하지만 올바르게 동작하도록 하는데 약간의 문제가 있었습니다. 그래서 나는 당분간 이 프로젝트는 보류하고 다른 것을 하였습니다.


내가 작업하였던 다른 프로젝트들중 하나는 gold prospecting을 위해 사용한 나의 recirculating sluice box의 펌프를 위한 PWM 모터 속도 컨트롤러였습니다. 속도 컨트롤러는 555 타이머 칩을 사용합니다. 555 칩의 내부 구조의 다이어그램을 살펴보았을때 나는 나의 원래의 충전기 회로의 아주 많이 닮아 있다는 것에 놀랐습니다. 갑자기 나는 555칩을 이용하여 충전기회로를 다시 디자인하고 아주 간단하면서도 부품수를 줄이게 할 수 있을 것이라는 것을 깨달았습니다.



나의 원래의 충전기 회로와 NE555 타이머 칩의 내부 사이의 유사성을 살펴보기 위해서 왼쪽의 두 다이어 그램을 비교해 보자. 색상으로 표시된 사각형이 유사한 부분을 보여 줍니다. 555 타이머는 원래 회로의 7개의 부품을 대신하고 모든 회로의 복잡성을 아주 많이 줄일 수 있습니다. 나는 555를 타이머로서 전혀 사용하지 않을 것이기 때문에 이것은 매우 비 전통적이고 555의 알려지지 않은 사용법 입니다. 나는 555가 원래 디자인되었던 것보다 완전히 다르게 사용하도록 내부 부분을 활용하고 있습니다.


나는 작업을 시도 하였습니다. 아주 짧은 시간안에 빵판에 작동하는 프로토 타입회로를 만들었습니다. 나에게는 드문 일이지만 첫 시도에 제대로 동작하였습니다. 나는 거의 매번 와이어링 실수를 하곤 합니다. 



여기엔 새로운 충전기 도면이 있습니다. 좀더 크고 분명한 것을 원한다면 클릭을 하시기 바랍니다.

나는 부품을 쉽게 찾는데 주의를 기울였습니다. NE555는 아마도 역사적으로 가장 대중적인 IC입니다. 매년 수조개가 만들어 집니다. 세계 어디에서도 구하기 쉬울 것입니다. 나는 또한 초기 버전에서 사용한 8V 레귤레이터를 5V 레귤레이터로 변경하였습니다. 사람들이 구하기 어렵다고 불평하였거든요. 사용된 트렌지스터는 2N222, NTE123, 2N3904, 혹은 다른 유사한 일반적인 작은 NPN 트렌지스터입니다. 그리고 MOSFET은 IRF540이거나 유사한 파워 MOSFET입니다. 나는 수중에 많은 IRF540을 가지게 되었기 때문에 다른 프로젝트를 위해서 남겨 두었 었습니다. 그래서 나는 다른 것을 새로 사는 것 보다 그져 그 중 하나를 사용하기로 하였습니다. 여러분 들이 구할 수 있을 것들을 사용하시기 바랍니다.

모든 저항은 1/8 와트 용량입니다. 1/8와트 저항이 없다면 1/4와트 혹은 그 이상 용량의 저항으로 대체될 수 있습니다.  두 개의 가변저항 R1과 R2은 여러번 돌려서 설정하는 방식의 것이 이상적일 것입니다. 그러나 조절할때 약간의 정확도의 손실이 있지만 일반적인 한번 돌려서 설정하는 것으로도 대체될 수 있습니다. 나는 10K 가변저항을 많이 가지고 있어서 그것을 사용하였습니다. 10K와 100K 사이의 어떤 값도 잘 동작할 것입니다. 10% 허용오차는 모든 부품에 충분한 정도입니다. 이 회로에 그 이상의 정밀한 부품은 필요하지 않습니다.

개선 사항 

나는 R8*과 R9*의 추가적인 저항을 추가해서 위의 회로를 수정하였다. 이 330Ohm의 저항들은 회로가 실제로 동작하는데 필요하지는 않다. 그러나 만약 가변 저항들이 잘못해서 한계치에 도달하게 되거나 잘못해서 버튼이 눌려지거나, 두 버튼이 동시에 눌려 졌을때 회로가 단선되거나하는 사고를 예방하기 위해서 도움이 된다. 나의 디자인은 시중하게 최소한으로 이루어 졌고 나의 초기에 사용했던 약간 복잡한 디자인에 사용된 이 안정용 저항들을 사용하였다. 그러나, 이 디자인을 공표한 후 나는 예상치 못한 사고를 예방하기 위해서 이들을 다시 되돌려 놓은 것은 아마도 좋은 생각이라고 판단했다.


릴레이는 40A의 용량의 일반 용도의 SPDT 자동차용 릴레이 입니다. 이것은 매우 쉽게 구할 수 있을 것입니다. 자동차 부품 파는 곳이나 폐차장에 버려진 차에서 하나 구할 수 있을 겁니다. 나는 연결의 용이성을 위해서 릴레이의 핀아웃을 포함하여 그려 넣었습니다. 40 A의 용량은 과한 용량인 것 처럼 보이지만 나중을 위한 확장이 될 수 있습니다. 여러분은 아마도 단지 하나의 작은 햇빛 충전판에서 시작할 겁니다. 나중에 더 추가하거나 가능하다면 풍력 터빈으로 혹은 좀더 용량이 큰 배터리로 하게 될 겁니다. 결국은 충전기는 약간 심각한 전류를 다룰 필요가 있을 겁니다. 왜 낮 시간동안의 동작만 고려하여 동작하도록 만들지 않느냐? 다른 모든 부품은 아래에 기입되어져 있습니다.

대부분의 부품들은 여러분 지역의 Radio Shack에서 구입할 수 있습니다. 다른 부품들은 자동차 부품 가게나 Digi-Key, Newark와 같은 온라인 전자 부품 샵에서 구할 수 있습니다. 여러분들은 또한 Amazon.com에서 부품을 찾아 볼 수 도 있습니다. 나는 Ebay에서 자동차의 릴레이를 구입하였습니다. 배송비가 있지만 자동차 부품 가게보다 더 저렴하고 심지어 우체통에 정확하게 배송됩니다. 

 IC1 - 7805 5 Volt positive Voltage Regulator     R3, R4, R5 - 1K Ohm 1/8 Watt 10%  
 IC2 - NE555 Timer Chip     R6 - 330 Ohm 1/8 Watt 10%  
 PB1, PB2 - NO Momentary Contact Push Buttons       R7 - 100 Ohm 1/8 Watt 10%  
 LED1 - Green LED     Q1 - 2N2222 Or Similar NPN Transistor  
 LED2 - Yellow LED     Q2 - IRF540 Or Similar Power MOSFET  
 RLY1 - 40 Amp SPDT Automotive Relay     C1 - 0.33uF 35V 10%  
 D1 - 1N4001 or similar     C2 - 0.1uF 35V 10%  
 R1, R2 - 10K Multi-Turn Trim-Pots  

한번 빵판에 프로토 타입을 동작시켜 본후 실제로 사용하기 위한 목적으로 Radio Shack 프로토보드에 또 다른 유닛을 만들었습니다. 처음에 한 작업을 다시하는데 한 두시간 정도 소요되었습니다. 이 좀 엉성한 버전은 상자에 넣어 지고 현장에서 철저한 테스트를 가해질 겁니다.


주의할 것은 이 보드에서 나는 5V 레귤레이터로 78L05를 사용하도록 선택하였다. 이것은 작은 TO-92 패키지로 2N2222 트렌지스터와 같은 사이즈를 갖는다. 이러한 크기는 보드의 공간을 많이 확보하게 해준다. 그리고 78L05는 100mA의 출력 전류를 보여준다. 그러나 이보드를 구동하기에 충분하다. 여러분이 작은 78L05를 구할 수 없다면, 좀 더 일반적인 크기의 TO-220 패키지의 7805를 사용할 수 도 있다. 뭐 약간 더 많은 보드 공간을 확보해야하는 것 이외에 아무튼 불이익은 없다. 

여러분들이 한번 보드를 만들게 되면 이제는 세부 사항을 조절하고 보정해야할 시간이다. 나는 이 컨트롤러를 위한 하한 및 상한 전압 설정을 11.9V와 14.9V로 하였다. 이러한 설정은 언제 전력 전달을 배터리에서 더미 부하나 그 이외의 것으로 전환해야하는지를 보여준다. (여러분이 풍력 터빈에 사용하고자 한다면 더미 부하만 필요하다. 햇빛 충전판을 사용하고자 한다면, 더미 부하는 연결하지 않아도 된다.)

아마도, 회로를 보정하는 가장 좋은 방법은 배터리 연결단자에 가변 DC 파워 서플라이를 연결하는 것이다. 파워 서플라이를 11.9V로 설정하고 Test Point 1의 전압을 측정한다. 그리고 여러분이 test point 의 전압이 1.667V에 가장 가까이 도달할 수 있는 만큼 R1의 값을 조절하자. 그럼  이제 파워 서플라이를 14.9V로 변경하고 Test Point 2의 전압을 측정하자. 그리고 Test Point 2의 전압이 3.333V에 가장 가까이 도달하도록 R2의 값을 조절하자. 

입력 전압을 11.7V에서 15.1V 사이를 오르락 내리락 하면서 충전기의 동작을 테스트 해보자. 여러분들은 릴레이가 14.9V 근방에서 접촉이 발생하고 11.9V 근방에서 접촉이 해제되는 소리를 들을 수 있을 것이다. 이 두 설정된 지점 사이에서 컨트롤러는 머물러 있어야 한다. Charger와 Dump 버튼은  입력 전압이 이 두 지점 사이에 있을 때 컨트롤러의 상태를 변경하는데 사용되어 질 수 있다. 

여러분들이 나의 하한 전압이 너무 낮고 내가 너무 과 방전을 시키는 것이 아니냐고 알려주거나 나에게 이메일을 쓰고자 하기 이전에 배터리의 전압이 부하가 연결되지 않으면 일반적으로 낮은 상태가 되지 않는 다는 점을 고려해 주기 바란다. 부하가 제거되면 전압은 12V 이상으로 금방 회복 될 것이다. 그래서 여러분 들이 단번에 생각할 수 있듯이 배터리들은 많이 방전되지 말아야 한다.

회로작업이 이루어 지면 이제 생활 방수 수준의 케이스 안에 고정 한다. 릴레이는 왼쪽에 놓았다. 나는 와이어가 쉽게 모든 것에 갈 수 있도록 하기 위해서 barrier strip을 사용하였다. 그리고 높은 전류의 연결도 허용하도록 굵기가 굵은 와이어를 사용하였다. 이 정도는 40A 정도를 허용하도록 디자인 되었다. 또한 solar/wind 입력 라인에 퓨즈를 첨가하였다.


좀 더 큰 사진을 원하시면 그림을 클릭해보시라.

여기에 뚜껑이 있는 다른 사진이 있다. 이 상자는 이 작업에 적합해서 사용한 것이 아니라 내가 이미 가지고 있었기 때문에 그냥 사용하게 되었습니다. 영구적으로 외부에서 사용하고자 한다면 내가 원래 충전기에 사용하였던 것 같은 방수와 튼튼한 상자를 사용하기를 추천한다. 그러나 나는 투명한 뚜껑을 통해서 LED를 확인할 수 있고 간편하게 충전기의 상태를 구분할 수 있다는 사실은 좋다고 생각한다. LED를 위한 추가적인 구멍을 뚤지는 않았고 이 상자는 현장 테스트 목적으로 쓰게 될 것이다.


좀 더 큰 사진을 원하시면 그림을 클릭해보시라.

여기에 옆면 사진있다. 이 사진은 외부에서 전선을 연결할 수 있는 모든 커넥터를 보여주고 있다. 각각의 커넥터는 배터리의 양극과, 태양열 집전기혹은 풍력 발전을 위한 터빈의 양극 입력, 옵션 사항인 dummy load의 양극, 그리고 세 개의 그라운드와 연결되도록 되어 있다.



충전기를 설정할 때 먼저 배터리 부터 연결해야 한다. 이렇게 해야만 전기가 안정적인 전력으로 사용 되어 질 수 있다. 만약 태양열 집전기나 풍력 터빈이 먼저 연결되면 제어기는 이 상태 저 상태 사이를 심하게 유동칠 수 있다.

이제 나는 dummy load에 대해서 설명해야 겠다. 내가 만든 풍력 터빈 같은 것은 강한 바람에 대한














................................ 번역중 ..............................

2013년 11월 11일 월요일

[작업중] stm32f405rg를 위한 startup code 와 링커 스크립트 분석

 임베디드 시스템에서 어셈블리 언어가 아닌 C 언어를 사용하기위해서 사전에 처리해 주어야 하는 작업들이 존재한다. 이 부분에 대해서는 여러가지 복잡한 것들이 많이 존재하지만, 새로운 CPU를 사용하려고 하거나 메모리를 구체적으로 어떻게 관리하는지 알아 보려면 반드시 알아두고 넘어 가야 하는 것이다.

 C언어로 된 바이너리 코드를 실행하려면 이 바이너리 코드가 메모리의 어느 부분에서 실행되는지 그리고 코드에서 사용하는 각종 변수와 스텍 그리고 힙이라고 하는 동적 메모리 할당 영역을 램의 어느 부분에 할당하고 값을 어떻게 초기화 해야하는지 결정해야 한다. 여기에 덧붙여  CPU에서 발생하는 인터럽트를 처리하고자 한다면 인터럽트 벡터의 위치와 각종 인터럽트 벡터의 초기화를 해 주어야한다.

위와 같은 네 가지 과정은 C 언어 코드자체만으로는 구현이 불가능하다. 이 기능들은 원래 시스템 OS에서 관리해 주어야 하지만, 임베디드 시스템의 경우 사용자가 알아서 처리해야한다. 그래서 C언어로 임베디드 시스템 프로그램을 하려고 한다면 불가피하게 startup 코드와 linker script를 작성해야한다. 물론 이런 것을 편리하게 하나의 툴로 판매하는 회사 IAR, Keil 등등이 있지만, 자유소프트웨어인 gcc와 연관된 도구를 사용하고자 한다면 사용자가 작성해야 한다.

 그럼 간단히 startup 코드와 linker script가 하는 일에 대해서 살펴보자. startup 코드는 C 언어를 사용하기 이전에 필요한 스택 레지스터 초기화, 동적할당 영역을 '0'으로 초기화, 클럭 설정, 인터럽트 벡터의 지정 및 cpu에 달려 있는 메모리의 위치지정을 위한 레지스터 설정과 같은 기초적인 cpu의 초기화 작업을 수행한다. 그리고 linker script는 기본적으로 컴파일된 모든 오브젝트 파일들을 하나로 모아서 하나의 실행 가능한 출력파일로 합성하는 기능을 수행한다. 그리고 좀 더 구체적으로는 startup에서 설정한 메모리의 구성에 따라서 컴파일된 모든 오브젝트파일의 각 세그먼트들을 재배치 시키고, 실행 가능한 출력 파일을 어떻게 구성할 것인지에 대한 설정을 수행한다.

 다시 정리해서 위의 과정을 좀 더 기능적으로 구분해 보자면 다음과 같다.

 1. C언어의 바이너리 코드가 적재될 메모리의 위치 지정  
 2. 변수, 스텍, 그리고 동적 메모리 할당 영역의 위치 지정  
 3. 스텍 레지스터 및, 스텍 그리고 동적 메모리 할당 영역의 초기화  
 4. 인터럽트 벡터의 위치 지정  
 5. 인터럽트 벡터 레지스터 초기화 및 인터럽트 벡터의 초기화  


 위의 기능은 컴파일러와 어셈블리 언어에  의존적이기 때문에 이해하기에 쉽지가 않다. 나도 마찬가지이기 때문에 기존에 완성되어 있던 것을 더듬어 가는 방법으로 설명해 보고자 한다. 앞으로 사용할 코드는 gcc 기반의 크로스 컴파일러에 기반하고 그 코드는 다음의 주소에서 가져왔음을 밝혀둔다.

http://git.munts.com/arm-mcu/gcc/stm32f4/

 위의 주소에 있는 파일 중에서 살펴볼 것은 stm32f405rg.S와 stm32f405rg.ld이다. stm32f405rg.S는 소위 말하는 런타임 라이브러리라고 하는 것이고 stm32f405rg.ld는 링크 스크립트라고 하는 바이너리 코드의 코드영역, 데이터 영역, 그리고 스텍영역을 어디에 배치할지를 지정하는 스크립트 코드이다.

stm32f405rg.ld의 분석

 gcc 컴파일러의 링크 기능이 요구하는 기능은 시스템에 메모리의 구성이 어떻게 되며, C언어가 컴파일된후 코드 영역과 데이터 영역, 그리고 스텍 영역그리고 C++언어에서 추가적으로 생성하는 영역을 시스템 메모리의 어느 영역에 배치할 것이지를 요구한다.

메모리의 구성

 먼저, 시스템의 메모리 구성이 어떻게 되는지는 다음과 같이 지정한다.

 MEMORY  
 {  
  flash (rx) : ORIGIN = 0x00000000, LENGTH = 1024K  
  ram (rwx)  : ORIGIN = 0x20000000, LENGTH = 128K  
  ccm (rwx)  : ORIGIN = 0x10000000, LENGTH = 64K  
 }  

 위와 같이 세 종류의 메모리가 지정되고 있다. 각종 메모리를 지정하는 방식은 다음과 같다.

 메모리이름 (특성) : ORIGIN = 시작주소, LENGTH = 메모리의크기  

 메모리 이름은 알아 보기 쉬운 아무 것이든 가능하고 특성은 rwx같은 약자로 지정이 가능하다. 이들은 각각 Readable, Writable, 그리고 eXecutable의 약자로 읽기, 쓰기, 실행가능의 특성을 이야기 한다. 이 부분은 반드시 사용하고자 하는 CPU의 데이터 시트를 살펴보아야 한다.

 stm32f405rg의 데이터 시트를 살펴보면 다음과 같이 메모리의 구성을 알려주고 있다.

STM32F405RG의 내부 메모리 구성

 위의 그림에서 보듯이 stm32f405rg는 32bits로 지정가능한 영역인 4Gbyte영역을 8개의 512Mbyte 단위의 블럭으로 쪼개서 관리한다. 앞의 두 블럭을 제외한 나머지 영역은 외장 메모리 혹은 내장된 모든 주변장치들에 접근하는데 사용된다.

 아무튼 지금 현시점에서 중요한 것은 최하위 주소에 있는 두 블럭이다.

 다시 되돌아 가서 주소 블럭 0의 0x00000000에서 0x000FFFFF에 해당하는 영역은 1024Kbyte의 크기를 가지고 있고 첨삭된 내용을 보자면 Flash로 명칭되고 BOOT 핀을 어떻게 설정하느냐에 따라서 SRAM으로 설정될 수 도 있다고 되어 있다.

 좀 더 자세히 이야기 하자면 기본적으로 해당 영역은 읽고 실행만이 가능한 Flash로 되어 있고 BOOT 핀을 변경하면 SRAM을 위한 영역으로 변경가능하다는 이야기 이다. 이러한 기능이 왜 필요한지는 컴파일과 다운로드로 이어지는 지겨운 개발 과정을 거쳐 보았다면 충분히 이해가 가능할 것이다. 나와 같이 개념없이 개발하는 개발자에게 펌웨어 개발 과정은 컴파일하고 Flash 메모리에 굽는 과정이 솔직히 대부분이라고도 할 수 있다. 그래서 정상적으로 쓰는데 시간이 소요되는 Flash 메모리 보다 SRAM을 위의 위치에 배치 시키면 펌웨어 개발에 많은 도움이 될 수 있다.

 그럼 BOOT 핀들의 기능을 살펴보도록 하자.

stm32f405rg의 데이터 시트에 있는 부트 모드에 대한 설명

잠시 해석을 해보자면,
시작시, BOOT 핀들은 다음의 세 가지 부팅 옵션중 하나를 선택하는데 사용된다.
 * Flash로 부터 부팅하기,  
 * System memory로 부터 부팅하기,  
 * 그리고 마지막으로 내장된 SRAM으로 부터 부팅하기  
부트로더가 system memory에 위치하고 있고 USART1(PA9/PA10 핀), USART3(PC10/PC11 핀 혹은 PB10/PB11 핀), CAN2 (PB5/PB13 핀), 그리고 DFU (device firmware upgrade)를 통한 디바이스 모드의 USB OTG FS (PA11/PA12 핀)을 이용해서 Flash 메모리를 재 프로그래밍하는데 사용된다.

 즉, STmicrosystem에서 제공하는 부트로더가 이미 system memory에 내장되어 있고, 이 부트로더는 USART1, USART3, 그리고 CAN2, 디바이스 모드의 USB OTG FS를 통하여 새로운 펌웨어를 다운로드하여 Flash 메모리에 꿉어 주는 기능을 하고 있다는 이야기 이다.

 해당 system memory는 0x1fff000에서 0x1fff7a0f에 위치한다. 그리고 첨삭 내용을 보자면 OTP방식으로 CPU가 제조될때 한번만 기록이 가능한 것으로 추정된다.

그리고 BOOT 핀들의 설정에 따른 모드 변환은 다음과 같이 할 수 있다.

stm32f405rg의 BOOT 핀 설정에 따른 부트 모드의 변화

 어쨌든, "flash (rx)  : ORIGIN = 0x00000000, LENGTH = 1024K" 는 설명이 된 것 같다.

"ccm (rwx)   : ORIGIN = 0x10000000, LENGTH = 64K"에 해당하는 CCM이라는 처음 들어 보는 메모리를 살펴보도록 하자. CCM 메모리는 기본적으로 SRAM과 많은 부분의 기능들을 공유하고 있는 것으로 보여진다. 하지만 CCM(Core Coupled Memory)이라는 이름에서 보듯이 stm32f405rg의 핵심 부분인 arm cortex-m4와 직접적으로 연결되어 있는 것으로 보인다. 이와 같은 사항은 데이터 시트에서 확인 가능하다.

stm32f405rg의 내부 블럭 다이어 그램
 다른 메모리들(SRAM 112KB, SRAM 16KB, 그리고 Flash)과 다르게 AHB라는 버스 제어 블럭을 거치지 않기 때문에 아마도 CCM을 연산용 메모리를 사용하면 좀 더 빠르게 처리가 가능할 것으로 여겨진다. 하지만, 그림에서도 보듯이 D-BUS만 연결되어 있기 때문에 코드가 직접 실행되는 것을 불가능하고 데이터를 저장하고 읽는 것만 가능한 것 같다. 그럼 CCM의 특성에 해당하는 "x"는 제거하는 것이 마땅할 것으로 여겨진다. 다음과 같이...

 ccm (rw)  : ORIGIN = 0x10000000, LENGTH = 64K  

 그리고 마지막으로 SRAM은 하드웨어적으로 두 개로 구분되어 있지만 두 SRAM이 연속된 메모리 공간에 위치해 있기때문에 하나의 SRAM으로 간주하여 지정되어 있다.

 하지만, 위의 메모리 구성 그림에는 있으나, 스크립트에서는 제외된 Flash 메모리가 존재한다. 위치는 0x00800000에서 0x008fffff에 해당하는 1024Kbyte용량의 메모리이다. 추정해 보건데 아마도 BOOT 핀들의 구성에 따라 Flash가 재 배치되는 공간인 것 같다. 광고에도 없는 메모리를 보너스를 넣어 줄 만큼 STMicrosystem이 훈훈하지는 않을 것이다. 아무리 선진국 프랑스의 회사라고 해도 말이다.

바이너리 코드의 섹션 배치용 변수 지정

 위와 같이 구성된 메모리에 C언어로 컴파일된 바이너리 코드를 배치하기 위해서 링커스크립트는 다음과 같은 참조용 변수를 지정한다. 이것은 어디 까지나 사용자에 따라 무한히 변경이 가능하기 때문에 용도에 따라서 얼마든지 변경 가능하다.

 __rom_start__     = ORIGIN(flash);  
 __rom_size__     = LENGTH(flash);  
 __ram_start__     = ORIGIN(ram);  
 __ram_size__     = LENGTH(ram);  
 __ram_end__     = __ram_start__ + __ram_size__;  
 __stack_end__     = __ram_end__;          /* Top of RAM */  
 __stack_size__     = 16K;  
 __stack_start__     = __stack_end__ - __stack_size__;  
 __heap_start__     = __bss_end__;          /* Between bss and stack */  
 __heap_end__     = __stack_start__;  
 __ccm_start__     = ORIGIN(ccm);  
 __ccm_size__     = LENGTH(ccm);  

 위의 변수들은 이름에서 보듯이 전통적으로 실행 코드만 위치하게 되는 rom 영역의 시작주소와 크기, 데이터만 들어 가게 되는 ram 영역의 시작주소 및 크기, 그리고 램의 마지막주소에서 16Kbyte영역에 해당하는 stack을 위한 영역 시작 주소와 크기, 그리고 마지막 주소에서 부터 사용하는 stack 의 초기 주소를 heap영역을 bss영역의 마지막 주소에서 stack의 시작주소에 해당하는 영역으로 지정한다. 그리고 마지막으로 특수 영역인 ccm의 시작 주소와 크기를 지정한다. 이와 같은 변수들은 startup 코드인 stm32f405rg.S에서 나중에 참조하여 레지스터를 설정하고 영역 초기화하는데 사용할 것이다. 하지만 위의 변수 중 __bss_end__라는 것은 정의 되지 않고 참조만 하고 있다. 이것은 나중에 다시 나올 것이다. 여담 이지만 이와 같은 코드는 상호 참조가 너무 많아서 어디에서 정의 되는지 아니면 컴파일러에서 만들어 주는 것인지 판단하기가 쉽지 않다. 아무튼 어디엔가 있을 것이다.

 SECTIONS  
 {  
  . = 0;  
  .text : {  
  KEEP(*(.startup))               /* Startup code */  
  *(.text*)                    /* Program code */  
  KEEP(*(.rodata*))               /* Read only data */  
  *(.glue_7)  
  *(.glue_7t)  
  *(.eh_frame)  
  . = ALIGN(4);  
  __ctors_start__ = .;  
  KEEP(*(.init_array));               /* C++ constructors */  
  KEEP(*(.ctors));               /* C++ constructors */  
  __ctors_end__ = .;  
  . = ALIGN(16);  
  __text_end__ = .;  
  } >flash  
  .data : ALIGN(16) {  
  __data_beg__ = .;               /* Used in crt0.S */  
  *(.data)                    /* Initialized data */  
  __data_end__ = .;               /* Used in crt0.S */  
  } >ram AT > flash  
  .bss (NOLOAD) : ALIGN(16) {  
  __bss_beg__ = .;               /* Used in crt0.S */  
  *(.bss)                    /* Uninitialized data */  
  *(COMMON)                    /* Common data */  
  __bss_end__ = .;               /* Used in crt0.S */  
  } >ram  
 /* C++ exception unwinding stuff--needed by some toolchains */  
  .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >flash  
  __exidx_start = .;  
  .ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) } >flash  
  __exidx_end = .;  
 }  


 위의 섹션 지정을 이해 하려면 linker command language를 약간 알아 두어야 한다. 먼저 섹션은 크게 3가지로 재배치 되어 진다. text, data 그리고 bss로 관리되며, 그 이름에서도 알 수 있듯이 각각 프로그램 코드, 변수의 데이터, 그리고 동적할당과 Stack을 위한 메모리 공간으로 이름 붙여 졌음을 알 수 있다. 그리고 그 해당 영역은 flash, ram, ram으로 할당되어 있다. 

 

 다음은 C언어를 컴파일러가 메모리 영역을 관리하는 각 섹션에 대한 설명이다.
- Code 섹션: 순수한 실행 코드만 가지고 있는 섹션, 일반적으로 rom과 같은 매체에 위치하게 된다.
- Data 섹션 : 값이 초기화된 전역변수와 값이 초기화된 static 타입의 함수 내에서 정의된 변수를 위해 할당된 메모리 공간
- Bss 섹션 : 값이 초기화 되지 않은 전역변수와 값이 초기화 되지 않은 static 타입의 함수 내에서 정의된 변수를 위해 할당된 메모리 공간
- Heap 섹션 : 동적 메모리 할당(malloc, realloc 등의 기능)을 위해 확보된 메모리 공간
- Stack 섹션 : 말 그대로 스텍 영역 - 함수 호출등으로 발생하는 변수 넘기기 혹은 각 함수의 지역 변수를 위해 확보되는 메모리 공간

 

 text 섹션을 살펴보면, 우선 첫 번째 문장은 location counter를 0으로 설정하는 부분으로 혹시나 해서 넣어 둔 것 같다. 자동적으로 0이 될 것은 자명하기 때문이다(".=0"). 그리고 다음 줄은 출력 파일 즉, 컴파일 과정에서 수집된 모든 실행 파일의 text section을 채워 넣는 부분으로 위치는 위에서 설정한 flash의 영역이 된다(".text : {"). 이 text section에는 순수하게 프로그램을 수행하기 위한 코드들을 위한 메모리 영역이고 프로그램이 수행되는 기간 동안에 내용이 변경될 경우를 고려하지 않는 영역이다.  첫 번째로 채워질 내용은 "KEEP(*(.startup))"으로  startup section의 그 내용이 다른 곳에서 참조되어 지지않거나 사용되지 않아도 강제적으로 넣어 두도록 KEEP 옵션을 추가해 두었다. 그리고 본래의 목적인 프로그램을 수행하는 내용을 담고 있는 text section 을 추가하고 ("*(.text*)"),  통상 인터럽트 테이블 같은 참조 목적으로만 생성된 데이터를 위한 rodata section을 추가한다("KEEP(*(.rodata*))"). 여기까지가 가장 핵심이 되는 재 배치될 text section의 내용이고, 그 내용은 startup 코드 내용, 본래의 프로그램 코드 내용, 그리고 인터럽트 벡터 테이블 같은 참조용 데이터 들이 차지하고 있다. ". = ALIGN(4);"을 통해서 이후의 내용의 경계를 4바이트 단위로 관리한다. .glue_7과 .glue_7t는 각각 Arm 컴파일러가 생성해 내는 중간 코드를 위한 영역으로 glue_7섹션은 ARM Mode에서 동작할때의 중간 코드, glue_7t는 Thumb mode에서 동작할 때의 중간 코드를 가지고 있을 것이라 추정된다. 그리고 나머지 부분들은 C++코드를 수행하는데 필요한 생성자의 시작(__ctors_start), 끝(__ctors_end__)을 지정하는 환경 변수 지정, 그리고 그 안에 생성자(ctor 섹션), 그리고 init_array 색션을 놓아 두게 된다.

  data 섹션은 모든 바이너리 파일들의 data 섹션을 한데 모아 넣어 두고 그 영역의 시작(__data_beg__), 끝(__data_end__)에 해당하는 환경 변수도 잊지 않고 만들어 준다. 그리고 data 섹션의경계는 16바이트 단위로 관리한다("ALIGN(16)"). 이 내용은 모두 ram에 적재되지만, 그 복사본을 flash에 담아 둔다(">ram AT > flash").  이 부분은 코드 내용과 같이 보아야만 이해 할 수 있다.

 마지막으로 bss 섹션은 모든 바이너리 파일의 초기화 되지 않은 데이터를 위한 bss 섹션과 COMMON 섹션을 담아 두고 그 영역의 시작(__bss_beg__)과 끝(__bss_end__)을 환경 변수로 등록한다. 여기서 NOLOAD는 솔직히 나도 정확히 어떤 역할을 하는지 모르겠다.

그럼 위의 각 섹션이 stm32f405rg의 메모리 구성에 비추어 어떻게 배치되는지 그림을 그려보자.


stm32f405rg.S의 분석

해당 코드의 첫 번째 내용은 다음과 같다.

		.syntax 	unified
		.thumb
		.section	.startup, "x"

위에서 보듯이 Thumb  모드에서 동작하는 코드이며, 차지하게될 영역의 센셕을 startup으로 지정한다. "x"는 실행하는 목적으로 생성되는 영역이라는 지시어 같다.

 그리고 다음은 다른 소스코드 파일에서 참조할 수 있도록 전역 변수를 지정하고 있다.

		.global		_start
		.global		_vectors

그 변수는 _start와 _vectors로 초기화 코드 내용의 시작지점 그리고 인터럽트 벡터의 시작 위치를 지정하고 있다.



------------------------------------------------------------------------------------------------------------
참고 사항: FreeRTOS에서는 자체적인 동적 메모리 할당 메카니즘을 가지고 있다. 메모리를 할당하는 기능은 pvPortMalloc()이 하고, vPortFree()로 할당된 메모리를 해제한다. 그리고 내부적으로 할당하는 기능을 여러가지로 지원하는데 ./FreeRTOS/Source/portable/MemMang/ 밑에 총 네 가지의 동적 메모리 관리 기능을 heap_?.c등의 파일로 지원하고 관리하게 될 heap 영역의 크기는 각 Demo 디렉토리 밑에 두어야 할 FreeRTOSConfig.h에 다음과 같이 지정한다.

 #define configMINIMAL_STACK_SIZE          ( ( unsigned short ) 130 )  
 #define configTOTAL_HEAP_SIZE               ( ( size_t ) ( 75 * 1024 ) )  
------------------------------------------------------------------------------------------------------------



............작업중..........

2013년 10월 13일 일요일

[번역중] 쓸떼없는 24bit/192kHz 음원(고품질 음원)의 다운로드...

[원제] 24bit/192kHz 음원(고품질 음원)의 다운로드... 그리고 왜 이것들이 쓸떼없는 짓인지

[출처] http://people.xiph.org/~xiphmont/demo/neil-young.html

이 내용들은 지난달 음악가 Neil Young과 애플사의 Steve Jobs가 압축되지 않은 스튜디오 음질의 디지털 음악 다운로드를 제공하는 것에 대해서 논의하는 내용을 내타내고있다.
많은 문서와 사용자들의 해설은 압축되지 않은 24bit 192kHz의 음원 다운로드에 대한 예측에 대해서 특별히 열정적이다.
24bit/192kHz(고품질 음원)은 Mr. Young's 그룹과 몇 달전에 나눈 나의 대화에서 눈에 띄는 특징이다.

불행하게도, 24bit/192kHz(고품질 음원) 형식으로 음악을 배포할 가치가 없다. 그것의 재생 안정도는 약간 16bit/44.1kHz혹은 16bit/48kHz보다 약간 하위에 있다.
그리고, 6배는 더 저장 공간을 차지한다.

오늘날 디지털방식으로 배포되는 음악의 경험과 음악 품질과 관련된 몇가지 실제적인 문제들이 있다. 24bit/192kHz(고품질 음원)는 이러한 문제점들 중 아무것도 해결하지 못한다. 모든 이들이 만병통치약으로 알려진 24bit/192kHz(고품질 음원)으로 추출될때 우리는 어떤 실제적인 개선을 느끼지 못하게 될 것이다.

먼저, 나쁜 소식들.

몇 주전에 나는 24bit/192kHz의 음원(고품질 음원)을 다운로드하는 것에 확신을 가지고, 어떻게 이러한 사실들을 동의 할 수 없는지를 알고 싶어 하는 지적이고 과학적인 지식을 가지고 있는 개인들과 대화를 가졌었다.그들은 자세한 해답을 요구하는 좋은 질문들을 했다.

나는 또한 어떤 동기에 의해서 이런 고품질(high-rate)의 디지털 음원을 옹호하는 분위기가 되었는지에 흥미를 가지고 있었다.그에 대한응답들은 몇몇 사람들이 기본적인 신호 이론과 샘플링 원리를 심하게 놀라운것으로 이해하고 있는 것을 보여준다.수학적, 기술적, 그리고 생리학적인 부분에서 잘못이해하고 있는 것들이 대화에서 많이 나타났고, 자주 중요한 오디오 전문 기술을 가지고 있는 전문가에 의해서도 주장되어 진다. 몇 사람은 샘플링 이론은 디지털 오디오가 실제로 어떻게 작동하는지를 잘 설명하지 못한다고 주장한다.

잘못된 정보와 미신은 단지 허풍선이만 만들어 낸다. 그래서, 실제로 적용되는 몇가지 개선점을 제안하기 이전에 24bit/192 kHz(고품질 음원)의 배포는 왜 쓸떼없는 짓인지에 대한 약간의 기본지식을 다루도록 하자.

여러분, 당신의 귀를 살펴봅시다.

귀는 달팽이관의 공진 기저막에 있는 모(발)세포(hair cell)를 통해서 듣는 기능을 수행한다.각각의 모세포는 효과적으로 세포의 각각의 위치에 해당하는 좁은 파장대역으로 조절한다. 감지되는 파장대의 피크는 맨 중앙에 있고 인접하고 있는 모세포 간에 약간의 겹치는 파장이 존재하면서 꼬깔콘 모양을 이루면서 양쪽으로 갈수록 줄어 들게 된다.


위의 왼쪽 그림: 기저막이 베이지색으로 표현된 인간의 달팽이과늬 해부학적 단면도. 각 세포는 그것의 길이에 따라서 서로 다른 주파수에서 공진하도록 되어 있다. 외각에 가까운 곳은 높은 주파수에서 그리고  꼭대기 부분으로 갈수록 낮은 주파수에서 공진하는 세포로 되어 있다. 몇가지 공진 주파수에 대한 추정치들이 표시되어 있다.

위의 오른쪽 그림: 겹치는 필터의 뱅크처럼 보이는 기저막 세포에 해당하는 모세포의 응답 특성을 보여주는 개념도.

이것은 튜너가 설정된 곳에 가까운 강한 양의 주파수를 취득하는 아날로그 라디오와 유사하다. 중앙의 주파수에서 더 멀어지게 될 수록 (완벽히 사라지게 될때까지) 점증적으로 더 약해지고 왜곡되게 된다. 마지막 모세포의 감도가 0으로 떨어지게되고 들을 수 없게 되는 시점 이전인 상한 (하한) 가청 주파수 한계점이 있다.

샘플링 주파수와 가청 스펙트럼

 여러분이 이러한 말들을 많이 반복적으로 들었을 것으로 확신한다: 인간의 가청 범위는 20Hz에서 20kHz에 걸쳐있다. 연구자들이 어떻게 이런 특정 숫자를 지정하게 되었는지 아는 것은 중요한 문제이다.

 먼저, 우리는 청음 그룹에 대해서 모든 소리 파장대에 걸쳐서 '청음의 절대적인 한계점'을 측정한다. 이러한 작업은 건강한 귀에 이상적인 환경에서 측정이 이루어져 어떤 주어진 주파수에 대한 인간의 귀가 임지 할 수 있는 매우 미세한 소리를 표현하는 그래프를 우리에게 제공한다. 울림을 막아주는 주변환경, 정교하게 교정된 재생 장치, 그리고 엄격한 통계 분석은 쉬운 부분이다. 귀와 청각의 집중은 둘다 빨리 피로해 진다. 그래서 실험은 청음자가 피로하지 않은 상태에서 이루어져야만 한다. 이러한 점은 많은 휴식과 실험 중단이 이루어진다는 것을 의미한다. 실험은 측정 방법에 따라서 몇 시간에서 몇 일에 걸쳐 어떤 곳에서 이루어진다.

 그리고 나서 우리는 다른 극한점인 '고통 한계점'에 대한 자료를 수집한다. 이러한 작업은 소리의 크기가 귀의 물리적, 신경계적인 체계가 가해진 소리에 의해서 완벽히 압도되지 않을 만큼 그러나 물리적인 고통은 경험할 만큼 높아지게 되는 지점이다. 이러한 자료의 수집은 약간 사기성이 있다. 여러분들은 어떤 사람도 이 과정에서 청음을 통해 영구적인 피해를 입게 되기 원치 않는다.



위의 그림: 16kHz 이상의 주파수에 해당하는 현대적인 음원을 포함한 Flectcher와 Munson (1933)에 의해서 유도된 근사적인 등음량 곡선(equal loudness curve). 절대적인 청음 한계치와 고통 곡선의 한계치는 빨간색으로 표시되어 있다.  이후의 연구자들은 Phon 단위와 ISO 226 표준 등음량 곡선에서의 한계점과 이러한 측정치를 더 정교화 하였다. 현재의 측정치는 귀는 Fletcher와 Munson의 결과보다 낮은 주파수에 대해 분명히 덜 민감하다고 알려주고 있다.

 인간의 청음 범위의 상한은 청음 그래프의 절대치가 고통 한계치와 만나는 지점이 되도록 정의되어 진다. 이 지점에서 혹은 그 아래에서 소리를 희미하게 나마 인지하기 위해선 동시에 참을 수 없을 정도로 크게되어야만 한다.

 낮은 주파수에서 달팽이관은 저음 반사 모음집(bass reflex cabinet)처럼 동작한다. 달팽이관의 구멍은 사람에 따라서 40Hz에서 65Hz사이의 어떤 주파수에 맞춰진 통로로 작동하는 기저막의 꼭지점의 입구이다. 응답특성은 이 주파수 아래에서 가파르게 떨어지게 된다.

 이와같이, 20Hz에서 20kHz는 일반적인 범위이다. 이것은 철저히 가청 스펙트럼을 포함하고 이건 거의 한세기의 걸친 실험 자료에 의해서 증명되는 주장이다.

유전적 축복과 황금귀들.

 나의 서신에 기초해 보면, 많은 사람들이 듣는 기능에 특수한 축복을 가지고 있는 개개인들이 있다고 믿는다. 정말로 '황금귀'같은 것들이 존재하긴 하는 걸까?

 이러한 문제는 여러 분들이 무엇을 황금귀로 부르는가에 따라 다르다.

 젊고, 건강한 사람의 귀는 늙고 아픈 사람의 귀보다 잘 듣는다. 어떤 사람은 대부분의 사람들이 존재 조차 의식하지 못하는 음악과 소리에서 미묘한 차이를 듣도록 예외적으로 잘 훈련된다. 내가 모든 주류 mp3 인코더(과거에는 그들 모든 것들이 아주 좋지 못했다.)를 인지할 수 있었고 이중-맹검법(double-blind testing)에서 믿을 수 있게 이것을 증명할 수 있었을 때는 1990년 대의 어느 시점이었다.

 건강한 귀는 고도로 훈련된 감별능력을 가지고 있을때, 나는 그 사람을 황금귀라고 불렀다. 그렇기는 하지만, 평균 이하의 청력은 비훈련된 청음자를 뛰어 넘는 미세함을 인지하도록 훈련되어 질 수도 있다. 황금귀는 평균적인 사람들의 물리적 능력 이하의 청력보다 좀 더 훈련되어 있다.

 청력 연구자들은 진짜로 예외적인 청력을 갖는 예를 들자면 대단히 확장된 청력 범위를 갖는 개개인들을 찾아내고, 실험하고 문서화하는데 열의를 가지곤 한다. 일반적인 사람들도 훌룡하고 모든 것을 가지고있다. 그러나 모든 이들은 정말로 호감가는 페이퍼를 위해서 유전적인 놀라움을 찾고 싶어 한다. 우리는 과거의 100년간의 실험동안 그러한 어떤 사람도 찾지 못했다. 그래서 그들은 아마도 존재하지 않는다. 미안하다, 우리는 미래에도 계속해서 찾을 것이다.

스렉트럼 애호가들.

 아마도 여러분들은 내가 써놓은 모든 것에 대해서 의심이 많을 것이다; 이것들은 아마도 대부분의 시장의 광고물과는 반대로 가고있다. 대신, 기존의 오디오 분야에서 다루지 않는 가상적인 Wide Spectrum Video 현상을  한번 생각해 보자.

위의 그림: 가시광 대역의 스펙트럼위에 겹쳐서 표현한 사람의 눈의 시세포층의 근사한 log 스케일의 응답 특성이다. 이러한 감지 기관들은 귀의 모세포들이 소리의 겹쳐지는 파장대역에 응답하도록 조절되어 있듯이, 겹쳐진 스펙트럼 대역에서 빛에 응답한다.

 인간의 눈은 가시광 대역의 스펙트럼으로 알려진 빛의 제한된 범위의 주파수만 볼 수 있다. 이와 같은 현상은 소리의 파장의 가청 스펙트럼에 대해서도 동일하게 적용된다. 귀와 같이, 눈은 서로 다른 대역의 그렇지만 서로 겹쳐지는 파장 대역의 빛을 감지하는 감지 세포(시세포층)를 가지고 있다.

 가시광 스펙트럼은 400THz(강한 빨강색)에서 850THz(강한 보라색)까지 걸쳐있다[3]. 인지력은 양쪽 끝에서 급하게 떨어진다. 이런 대략의 제한지점 밑에서, 미세하게나마 감지하기 위해서 요구되는 빛의 파워는 여러분의 망막을 손상시킬 수 있다. 이와 같이, 이러한 사항들은 가청 스펙트럼의 일반적인 제한치로 해석되는, 젊고, 건강하고, 유전적으로 축복받은 개개인들에게 일반적인 범위이다.

 우리의 가상적인 Wide Spectrum Video 현상에서, 이러한 제한치들이 일반적으로 충분하지 않다고 믿는 열렬한 스펙트럼 애호가 그룹을 생각해 보자. 그들은 비디오가 가시광 스펙트럼 뿐만 아니라, 적외선 및 자외선 대역을 표현한다고 주장하는 것과 같다. 대치하여 비교를 계속해 보면, 이런 확장된 범위는 아직도 불충분하다고 주장하고 이런 비디오는 마이크로파와 X-ray 스펙트럼도 포함할때 꽤나 자연스럽게 느겨진다는 좀더 하드코어하고 자랑스러운 사실과 허구의 뒤범벅이 있다. 황금 눈에게 그들은 다른 점은 낮과 밤이다라고 주장한다.

 물론 이러한 것들은 터무늬 없는 일이다.

 아무도 X-ray나 적외선, 자외선, 그리고 마이크로파를 볼 수 없다. 사람들이 그가 얼마나 많이 할 수 있는지를 믿는지는 중요하지 않다. 망막은 간단한 감지 체계를 가지고 있지 않다.

 여기에 어떤이도 할 수 있는 실험이 있다: Apple사의 IR 리모콘을 가져오라. LED는 근적외선 대역인 약 306THz에 해당하는 980nm의 빛을 방출한다. 이 대역은 가시영역에서 그리 멀지 않은 영역이다. 리모콘을 지하실로 가져가거나, 여러분의 집에서 가장 어두운 방으로 가져가라. 그것도 한밤중에 모든 등들은 다끄고. 여러분의 눈을 어둠에 적응 시키자.


위의 사진: 디지털 카메라를 이용해 Apple사의 IR 리모콘을 찍은 사진. 비록 LED가 아주 밝고 가시광 대역의 빨간색 영역에서 멀지 않은 대역의 주파수를 방출할지라도, 이건 눈에 완벽히 보여지지 않는다.

  여러분들은 버튼을 눌렀을때 Apple사의 리모콘의 LED 플레시를 볼 수 있습니까[4]? 아니라구요? 아주 작은 양 조차도 볼 수 없다구요? 몇개의 다른 IR 리모콘도 시도해 봅시다: 많은 것들이 310-350THz에 해당하는 가시광에 아주 근접한 IR 파장을 사용한다. 여러분들은 그들도 마찬가지로 볼 수 없을 겁니다. 나머지 것들은 가시광 대역의 끝자락의 오른쪽에 해당하는 350-380Thz의 빛을 방출할지도 모르고 어둠에 적용된 눈에 완벽히 어둠에서 드물게 볼 수 있게 될지도 모른다[5]. 그들이 가시광대역 안쪽에 있었다면 모두 눈이 부시고 고통스럽게 밝을 것이다.

 이들 근적외선 LED들은 가시 주파수 한계점 밑에서 거의 20% 지점의 해당하는 가시광 영역의 경계지점의 빛을 방출한다. 192kHz 오디오는 가청한계의 400%에 해당한다. 나는 사과와 오렌지를 비교하는 우를 범하지 않기 위해서, 소리와 가시광의 인지가 양 한계점에서 유사하게 감소된다.

  이들 근적외선 LED들은 가시 주파수 한계점 밑에서 거의 20% 지점의 해당하는 가시광 영역의 경계지점의 빛을 방출한다. 192kHz 오디오는 가청한계의 400%에 해당한다. 나는 사과와 오렌지를 비교하는 우를 범하지 않는다, 소리와 가시광의 감지는 인지 한계지점들에서 유사하게 감소된다.

위험하다고 여겨지는 192kHz의 샘플링 주파수.

 192kHz 디지털 음악 파일들은 아무런 이득도 제공하지 않는다. 그런것들은 전혀 중립적이지 못하다; 실제적인 원음 충실도는 약간 나쁘다. 초음파는 재생되는 동안 골칫거리이다.

 소리 변환기와 파워 증폭기 둘다 왜곡이 없는 것은 아니다. 그리고 왜곡은 저주파와 고주파에서 갑작스럽게 증가하게 되어있다. 동일한 변환기가 가청 재생물에서 초음파를 발생시킨다면, 상호변환 디스토션 제품의 제어되지 않은 방출물이 모든 가청 주파수를 덮어 버리듯이 어떤 비선형은 약간의 초음파를 가청 범위의 영역으로 이동시키게 될 것이다. 파워 증폭기의 비선형성도 동일한 현상을 발생 시킨다. 현상은 매우 미약하지만, 청음 실험은 두 현상을 통하여 (초음파와 가청음) 다 듣을 수 있다는 것을 확인해 준다.

위쪽 그림: 약 0.09%정도의 변하지 않는 총 화음 왜곡(THD)을 갖는 이론적인 증폭기에서의 30kHz와 33kHz의 톤을 상호 변환기로 부터 유도된 디스토션 제품의 표현. 디스토션 제품들은 이 두 톤 보다 낮은 주파수를 포함하는 스펙트럼에 걸쳐서 표현된다. 

듣지 못하는 초음파가 상호 변환 디스토션에서 가청영역 (연한 파란색 영역)에 공헌한다. 일반적으로 초음파를 생산하지 않도록 디자인된 시스템은 20kHz이상에서 더 높은 양의 왜곡을 가지고 있다. 많은 공헌을 상호변환기가 하고 있다. 초음파의 발생을 설명하는 디자인된 주파수 대역의 확장은 가청 스펙트럼내의 노이즈와 왜곡의 발생을 감소시키는 타협안을 요구한다. 어느 쪽이든, 초음파의 불필요한 재생산은 성능을 떨어 뜨린다.

 추가적인 왜곡을 회피하는 몇 가지 방법이 있다:

  1. 여러분이 듣을 수 없는 초음파를 분리해서 독립적으로 재생산하는 전용 초음파 스피커, 증폭기, 그리고 교차형 중간체,등은 그져 여러분이 만드는 소리를 어지럽히지 않는다.
  2. 증폭기와 변환기는 더 넓은 주파수의 재생산을 위해 디자인 되었다, 그래서 초음파는 소리의 상호변환을 잃으키지 않는다. 같은 양의 비용과 복잡성이 주어진다면, 이 추가적인 추파수 범위는 스펙트럼의 가청 대역에서의 어떤 성능 개선의 비용을 발생 시키게 될 것이다.
  3. 스피커와 증폭기는 어쨋든 초음파를 발생시키지 않도록 디자인되어야 한다. 
  4. 시작 단계에서 넓은 대역을 포함하는 인코딩은 하지 말아야 한다. 초음파를 포함한 컨텐츠가 아니라면 여러분은 가청 대역에서 초음파 상호면환 왜곡을 만들거나 만들 수 없다.
 위의 것들은 모두는 같은 효과를 갖는 것들이다. 그러나 4번만이 합리성이 갖는다.

 여러분이 여러분 자신의 시스템의 성능에 대해서 의구심을 가지고 있다면, 다음의 샘플들은 30kHz와 33kHz의 톤을 가지고 있는 24bit/96kHz의 WAV 파일과 FLAC으로 된 긴버전과, 어떤 세가지 톤의 신호음 파일이다. 그리고 일반적인 노래 클립은 완벽히 24kHz에서 46kHz의 초음파 영역이 되기 위해서 24kHz로 주파수 상승이 가해졌다.


  • 상호변환 테스트:

30kHz tone + 33kHz tone (24 bit / 96kHz) [5 second WAV] [30 second FLAC]
26kHz - 48kHz warbling tones (24 bit / 96kHz) [10 second WAV]
26kHz - 96kHz warbling tones (24 bit / 192kHz) [10 second WAV]
Song clip shifted up by 24kHz (24 bit / 96kHz WAV) [10 second WAV
    (original version of above clip) (16 bit / 44.1kHz WAV)

 여러분의 시스템은 실제로 완벽한 96kHz 재생이 가능하다고 가정한다면[6], 위의 파일들은 어떤 들리는 노이즈, 톤, 휘파람소리, 클릭음, 혹은 다른 소리들이 없는 완벽히 무음이어야한다. 여러분이 어떤것을 듣게 된다면, 당신의 시스템은 초음파의 가청대역의 상호변환을 일으키는 비선형성을 가지고 있다고 봐야 한다. 소리를 높일때는 주의를 해야한다; 디지털 혹은 아날로그 음성을 가벼운 음성조차도 구동하는것은 갑자기 아주 큰 상호변환 톤을 일으킬 수도 있다.

 요약해 보자면, 초음파의 상호변환은 주어진 시스템에서 듣을 수 있다는 것은 불확실하다. 추가적인 왜곡은 사소한 것일 수도 있고 주의를 요하는 것일 수도 있다. 어느 쪽이든, 초음파는 전혀 이득 될 것이 없다. 그리고 많은 시스템에서 그것은 듣기에 확실히 고통 스러울 것이다. 고통을 주지 않는 시스템에서는 초음파를 다루는데 필요한 비용과 노력은 줄일 수 있고 대신 가청 범위의 성능을 개선하는데 사용되어 질 수 있다. 

샘플링에 대해 잘못 알려진 오류 그리고 오해

 샘플링 이론은 신호처리에 대한 지식이 없다면 대부분 이해하기 어렵다. 대부분의 사람들이 다른 분야의 지식있는 박사들 조차도 반복적으로 잘못 이해하고 있다는 것은 놀랄일이 아니다. 또한 많은 사람들이 그들이 잘못하고 있다는 것을 인지 조차 못하는 것도 놀랄일이 아니다.

위의 그림: 샘플링된 신호들은 자주 미세하지 못한 계단 모습(빨간색)으로 묘사 된다. 이것은 원래의 신호의 잘못된 추정치를 보여준다. 그러나, 이러한 표현은 수학적으로 정확하고 그 신호는 아날로그로 다시 복원되었을 때 원본 신호(파란색)의 정확히 부드러운 모습을 복구한다.

 대부분의 공통적인 오해는 샘플링은 원칙적으로 미세하지 못하고 손실을 발생한다는 것이다. 샘플링된 신호는 원래의 완벽한 부드러운 신호의 들쑥날쑥한, 심하게 꺽인 계단 모양의 복제혀으로 자주 묘사된다. 이것이 여러분이 샘플링이 어떻게 동작하는지 이해하는 이미지라면, 여러분은 아마도 더 빠른 샘플링 비율과 더 많은 샘플링 비트수를 좋은 것으로 여길 것이다. 아마도 그것은 더 미세한 계단 모양과 좀 더 원본에 가까운 추정치가 될 것이다. 디지털 신호는 무한대에 가까운 샘플링 비율로 갈 수록 원래의 아날로그 신호에 더욱 더 가까워지는 소리가 될 것이다. 

 비슷하게, 많은 디지털 신호처리 지식이 없는 사람들은 다음과 같은 사항을 살펴보게 될 것이다:

 그리고 말하자면 "어허!" 이러한 점은 샘플링된 신호는 더 높은 주파수의 아날로그 신호는 엉망으로 표현하게 된다는 점을 이야기 한다. 혹은, 음성 신호의 주파수가 증가함에 따라, 샘플링 품질은 떨어지고 주파수 응답 특성도 엉망이 된다. 즉 입력 신호에 대단히 민감하게 된다.

 보이는 것은 현혹적인 것이다. 이러한 믿음들은 잘못된 것이다!

2013-04-04에 추가된 내용:
디지털 신호와 계단모습에 관해 내가 가졌든 모든 메일에 덧붙여, 나는 여러분이 내 방식대로의 설명의 단순히 받아 들일 필요 없이 우리의 비디오 Digital Show & Tell에서 진짜 장비의 실제 디지털 원리를 보여준다.

과도한 샘플링

 48KHz 이상의 샘플링 레이트는 고음질의 오디오 데이터와 관계없지만, 몇몇 현재의 디지털 오디오 기술에 내제하는 핵심이다. 과도한 샘플링이 이와 가장 관련된 예제이다[7].

 과도한 샘플링은 단순하고 명징하다. 여러분들은 높은 샘플링 레이트가 (샘플링 레이트의 반에 해당하는) Nyquist 주파수와 우리가 듣을 수 있는 최대 주파수인 20Khz 사이의 더 넓은 대역을 아주 잘 다룰 수 있다는 것을 보여주는 나의 A Digital Media Primer for Geeks을 되돌아 보아라.
이것은 더 단순하게, 자연스럽게, 더 신뢰할 만한 아날로그 anti-aliasing 필터를 구성할 수 있게하고 그에 따라서 더 고음질을 갖도록 해준다. 20KHz와 Nyquist 주파수 사이의 이 추가 대역은 본질적으로 그져 아날로그 필터를 위한 스펙트럼의 여유공간이다.

위의 사진: A Digital Media Primer for Geeks으로 부터의 흰 칠판 그림은 48KHz의 ADC/DAC(왼쪽)과 96KHz의 ADC/DAC를 위해 사용되는 변환대역폭을 묘사한다.
 이것은 단지 한면만 이야기하는 것이다. 디지털 필터는 아날로그 필터를 실제적으로 구현하는 제한사항을 몇 가지 가지고 있기 때문에, 우리는 더 훌룡한 효율성과 디지털적으로 정확성을 가지는 anti-aliasing 과정을 완성할 수 있다. 매우 높은 샘플링 레이트의 순수한 디지털 신호가 디지털 anti-aliasing filter를 통과하는 작업은 전송 대역을 빡빡한 대역에 맞추는데 문제가 없다.
이 확장된 디지털 anti-aliasing filter를 거친후, 여분의 대역에 있는 샘플들은 그져 사라져 버린다. 과도하게 샘플링된 음원을 플레이하는 과정은 이와의 반대의 과정으로 대부분 이루어 진다.

 이것은 우리가 192kHz나 더 높은 샘플링이 갖는 모든 고음질의 이득들을(자연스러운 주파수 응답, 낮은 aliasing) 가지고 44.1KHz나 48kHz등의 낮은 샘플링 주파수를 사용할 수 있고 단점은 전혀 없다 (복원 과정의 왜곡을 일의키는 초음파는 쓸모없는 것이다.). 거의 모든 오늘날의 ADC와 DAC들은 매우 높은 주파수의 과도한 샘플링으로 이루어진다. 몇몇의 사람들은 이것이 순전히 자동적으로 인지하지 못하게 이루어지기 때문에 잃어나는 현상이라는 것을 알고 있다.

 ADC와 DAC는 항상 눈에 보이게 과도한 샘플링을 하지 않는다. 30년전에 어떤 녹음 기기들은 단지 아날로그 필터만을 이용해서 높은 샘플링 주파수로 녹음하였고, 결과물과 mastering은 단순히 그 높은 주파수의 신호를 사용하였다. 디지털 anti-aliasing과 decimation 과정들은 (CD 나 DAT를 위해 낮은 주파수로 다시 샘플링하는 작업) matering의 마지막 단계에서 이루어졌다. 이것이 아마도 96kHz와 192kHz가 전문적인 음악 산업과 관련이 있게 되게된 초기의 이유 중 하나일 것이다.

16bit 대 24bit


.............번역중.................