2017년 2월 28일 화요일
BeagleBone Green Wireless
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이라 불리는 렌즈 왜곡 해결 알고리즘
[참고자료]
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 설정하기
다음의 바이너리이미지를 다운로드한다.
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에 저항(R)과 캐패시터(C)에 의해 결정되는 시간 이후에 555타이머의 출력이 발생되게 하는 것이다. 로직은 555타이머가 담당하고 있지만, 실제로 전원연결이나 스피커 신호를 연결하는 것은 Relay가 맏고 있다. Relay는 전기 신호로 유도되는 전자기힘으로 동작하는 물리적인 스위치이다. 그래서 전기신호가 인가 되었을때 스위치가 켜지게 설정할 것인지 아니면 전기 신호가 인가 되었을때 스위치가 단선 되도록 할 것인지는 용도에 따라 고민해 보아야 하는 문제이다. 각각 장단점을 가지고 있다.
Relay에 전원이 인가 되었을때 스위치가 연결되도록 한 설정에서는 회로에 전원이 혹은 스피커에 음성 신호가 연결되어 정상 동작하는 동안 Relay에는 항상 전원을 공급해 주어야 한다. 이 경우에 원래의 회로에서 소모되는 전력 이외에 추가적인 전력 소비가 아무래도 발생한다. 그리고 반대의 경우 전원이 인가 되지 않을때 스위치가 연결되도록 한 설정에서는 회로가 정상 동작할때 발생하는 추가적인 전력 소비가 없다 하지만, 다음과 같은 단점이 존재한다. relay 전원이 인가 되지 않을때 심지어는 전체 전원이 인가되지 않았을 경우에도 스위치는 연결된 상태로 남아 있게 된다. 그러다 전체 전원이 인가될 때 relay에 동시에 전원이 인가되어 순식간에 스위치가 단선되고 일정 시간이 지난 후에 다시 스위치가 연결되는 과정을 거친다. 요약 하자면 스위치는 연결된 상태 였다가 전원이 인가되면 단선되고 일정 시간이 지난 후에 다시 연결된다. 이 상태에서 불가피하게 초기에 전원이 인가된 동안 순간적인 스위치 연결은 피할 수 없다. 이 부분은 적당한 용량의 캐패시터를 사용해서 해결 가능하지만, 아무래도 순간적인 오작동에도 민감한 회로의 경우 특히 명심해 두어야 한다.
아래는 555타이머를 이용한 시지연 회로이다.
![]() |
| 렐리이에 전원이 인가 될 시 동작하는 회로 |
![]() |
| 렐리에 전원이 인가 되지 않을 때 동작하는 회로 |
2014년 2월 13일 목요일
[작업중] Swing Arm 방식의 노트북 스탠드
인터넷에서 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의 두 개의 비교를 이용해서 빠떼리 전압 감시 회로로 이용하는 방법에 대해서 살펴보자.
2013년 12월 22일 일요일
[작업중] 무료 공개용 PCB 설계 프로그램 Kicad 사용하기 (도면 라이브리 생성하기)
아래의 그림에서 보듯이 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 파일 명령어) 설명서.
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에 기반한 정전류 자동차용 배터리 충전기 제작하기
555 칩에 기반한 새롭게 개선된 배터리 충전기
햇빛과 풍력 발전 시스템을 위한 간단한 충전기
개선 사항
나는 R8*과 R9*의 추가적인 저항을 추가해서 위의 회로를 수정하였다. 이 330Ohm의 저항들은 회로가 실제로 동작하는데 필요하지는 않다. 그러나 만약 가변 저항들이 잘못해서 한계치에 도달하게 되거나 잘못해서 버튼이 눌려지거나, 두 버튼이 동시에 눌려 졌을때 회로가 단선되거나하는 사고를 예방하기 위해서 도움이 된다. 나의 디자인은 시중하게 최소한으로 이루어 졌고 나의 초기에 사용했던 약간 복잡한 디자인에 사용된 이 안정용 저항들을 사용하였다. 그러나, 이 디자인을 공표한 후 나는 예상치 못한 사고를 예방하기 위해서 이들을 다시 되돌려 놓은 것은 아마도 좋은 생각이라고 판단했다. 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
여기에 옆면 사진있다. 이 사진은 외부에서 전선을 연결할 수 있는 모든 커넥터를 보여주고 있다. 각각의 커넥터는 배터리의 양극과, 태양열 집전기혹은 풍력 발전을 위한 터빈의 양극 입력, 옵션 사항인 dummy load의 양극, 그리고 세 개의 그라운드와 연결되도록 되어 있다.
충전기를 설정할 때 먼저 배터리 부터 연결해야 한다. 이렇게 해야만 전기가 안정적인 전력으로 사용 되어 질 수 있다. 만약 태양열 집전기나 풍력 터빈이 먼저 연결되면 제어기는 이 상태 저 상태 사이를 심하게 유동칠 수 있다.
이제 나는 dummy load에 대해서 설명해야 겠다. 내가 만든 풍력 터빈 같은 것은 강한 바람에 대한
................................ 번역중 ..............................
2013년 11월 11일 월요일
[작업중] stm32f405rg를 위한 startup code 와 링커 스크립트 분석
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" 는 설명이 된 것 같다.
![]() |
| stm32f405rg의 내부 블럭 다이어 그램 |
ccm (rw) : ORIGIN = 0x10000000, LENGTH = 64K
그리고 마지막으로 SRAM은 하드웨어적으로 두 개로 구분되어 있지만 두 SRAM이 연속된 메모리 공간에 위치해 있기때문에 하나의 SRAM으로 간주하여 지정되어 있다.
하지만, 위의 메모리 구성 그림에는 있으나, 스크립트에서는 제외된 Flash 메모리가 존재한다. 위치는 0x00800000에서 0x008fffff에 해당하는 1024Kbyte용량의 메모리이다. 추정해 보건데 아마도 BOOT 핀들의 구성에 따라 Flash가 재 배치되는 공간인 것 같다. 광고에도 없는 메모리를 보너스를 넣어 줄 만큼 STMicrosystem이 훈훈하지는 않을 것이다. 아무리 선진국 프랑스의 회사라고 해도 말이다.
바이너리 코드의 섹션 배치용 변수 지정
__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 음원(고품질 음원)의 다운로드...
[출처] 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(고품질 음원)으로 추출될때 우리는 어떤 실제적인 개선을 느끼지 못하게 될 것이다.
먼저, 나쁜 소식들.
나는 또한 어떤 동기에 의해서 이런 고품질(high-rate)의 디지털 음원을 옹호하는 분위기가 되었는지에 흥미를 가지고 있었다.그에 대한응답들은 몇몇 사람들이 기본적인 신호 이론과 샘플링 원리를 심하게 놀라운것으로 이해하고 있는 것을 보여준다.수학적, 기술적, 그리고 생리학적인 부분에서 잘못이해하고 있는 것들이 대화에서 많이 나타났고, 자주 중요한 오디오 전문 기술을 가지고 있는 전문가에 의해서도 주장되어 진다. 몇 사람은 샘플링 이론은 디지털 오디오가 실제로 어떻게 작동하는지를 잘 설명하지 못한다고 주장한다.
잘못된 정보와 미신은 단지 허풍선이만 만들어 낸다. 그래서, 실제로 적용되는 몇가지 개선점을 제안하기 이전에 24bit/192 kHz(고품질 음원)의 배포는 왜 쓸떼없는 짓인지에 대한 약간의 기본지식을 다루도록 하자.
여러분, 당신의 귀를 살펴봅시다.
귀는 달팽이관의 공진 기저막에 있는 모(발)세포(hair cell)를 통해서 듣는 기능을 수행한다.각각의 모세포는 효과적으로 세포의 각각의 위치에 해당하는 좁은 파장대역으로 조절한다. 감지되는 파장대의 피크는 맨 중앙에 있고 인접하고 있는 모세포 간에 약간의 겹치는 파장이 존재하면서 꼬깔콘 모양을 이루면서 양쪽으로 갈수록 줄어 들게 된다.위의 왼쪽 그림: 기저막이 베이지색으로 표현된 인간의 달팽이과늬 해부학적 단면도. 각 세포는 그것의 길이에 따라서 서로 다른 주파수에서 공진하도록 되어 있다. 외각에 가까운 곳은 높은 주파수에서 그리고 꼭대기 부분으로 갈수록 낮은 주파수에서 공진하는 세포로 되어 있다. 몇가지 공진 주파수에 대한 추정치들이 표시되어 있다.
위의 오른쪽 그림: 겹치는 필터의 뱅크처럼 보이는 기저막 세포에 해당하는 모세포의 응답 특성을 보여주는 개념도.
이것은 튜너가 설정된 곳에 가까운 강한 양의 주파수를 취득하는 아날로그 라디오와 유사하다. 중앙의 주파수에서 더 멀어지게 될 수록 (완벽히 사라지게 될때까지) 점증적으로 더 약해지고 왜곡되게 된다. 마지막 모세포의 감도가 0으로 떨어지게되고 들을 수 없게 되는 시점 이전인 상한 (하한) 가청 주파수 한계점이 있다.
샘플링 주파수와 가청 스펙트럼
여러분이 이러한 말들을 많이 반복적으로 들었을 것으로 확신한다: 인간의 가청 범위는 20Hz에서 20kHz에 걸쳐있다. 연구자들이 어떻게 이런 특정 숫자를 지정하게 되었는지 아는 것은 중요한 문제이다.그리고 나서 우리는 다른 극한점인 '고통 한계점'에 대한 자료를 수집한다. 이러한 작업은 소리의 크기가 귀의 물리적, 신경계적인 체계가 가해진 소리에 의해서 완벽히 압도되지 않을 만큼 그러나 물리적인 고통은 경험할 만큼 높아지게 되는 지점이다. 이러한 자료의 수집은 약간 사기성이 있다. 여러분들은 어떤 사람도 이 과정에서 청음을 통해 영구적인 피해를 입게 되기 원치 않는다.
인간의 청음 범위의 상한은 청음 그래프의 절대치가 고통 한계치와 만나는 지점이 되도록 정의되어 진다. 이 지점에서 혹은 그 아래에서 소리를 희미하게 나마 인지하기 위해선 동시에 참을 수 없을 정도로 크게되어야만 한다.
낮은 주파수에서 달팽이관은 저음 반사 모음집(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의 샘플링 주파수.
- 여러분이 듣을 수 없는 초음파를 분리해서 독립적으로 재생산하는 전용 초음파 스피커, 증폭기, 그리고 교차형 중간체,등은 그져 여러분이 만드는 소리를 어지럽히지 않는다.
- 증폭기와 변환기는 더 넓은 주파수의 재생산을 위해 디자인 되었다, 그래서 초음파는 소리의 상호변환을 잃으키지 않는다. 같은 양의 비용과 복잡성이 주어진다면, 이 추가적인 추파수 범위는 스펙트럼의 가청 대역에서의 어떤 성능 개선의 비용을 발생 시키게 될 것이다.
- 스피커와 증폭기는 어쨋든 초음파를 발생시키지 않도록 디자인되어야 한다.
- 시작 단계에서 넓은 대역을 포함하는 인코딩은 하지 말아야 한다. 초음파를 포함한 컨텐츠가 아니라면 여러분은 가청 대역에서 초음파 상호면환 왜곡을 만들거나 만들 수 없다.
- 상호변환 테스트:
샘플링에 대해 잘못 알려진 오류 그리고 오해
보이는 것은 현혹적인 것이다. 이러한 믿음들은 잘못된 것이다!
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 filter를 거친후, 여분의 대역에 있는 샘플들은 그져 사라져 버린다. 과도하게 샘플링된 음원을 플레이하는 과정은 이와의 반대의 과정으로 대부분 이루어 진다.
이것은 우리가 192kHz나 더 높은 샘플링이 갖는 모든 고음질의 이득들을(자연스러운 주파수 응답, 낮은 aliasing) 가지고 44.1KHz나 48kHz등의 낮은 샘플링 주파수를 사용할 수 있고 단점은 전혀 없다 (복원 과정의 왜곡을 일의키는 초음파는 쓸모없는 것이다.). 거의 모든 오늘날의 ADC와 DAC들은 매우 높은 주파수의 과도한 샘플링으로 이루어진다. 몇몇의 사람들은 이것이 순전히 자동적으로 인지하지 못하게 이루어지기 때문에 잃어나는 현상이라는 것을 알고 있다.
ADC와 DAC는 항상 눈에 보이게 과도한 샘플링을 하지 않는다. 30년전에 어떤 녹음 기기들은 단지 아날로그 필터만을 이용해서 높은 샘플링 주파수로 녹음하였고, 결과물과 mastering은 단순히 그 높은 주파수의 신호를 사용하였다. 디지털 anti-aliasing과 decimation 과정들은 (CD 나 DAT를 위해 낮은 주파수로 다시 샘플링하는 작업) matering의 마지막 단계에서 이루어졌다. 이것이 아마도 96kHz와 192kHz가 전문적인 음악 산업과 관련이 있게 되게된 초기의 이유 중 하나일 것이다.

















































