2015년 2월 17일 화요일

ESP8266 동작시키기 3

먼저 자신의 PC에서 ip주소를 확인하고 ESP8266을 PC와 동일한 무선 네트웍에 연결시켜 준다.

맥 터미널에서 ifconfig 명령으로 자신의 IP를 확인. (여기서는 192.168.1.5임)

$ ifconfig
lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 16384
....
en0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500 ether 20:c9:d0:80:91:19
inet 192.168.1.5 netmask 0xffffff00 broadcast 192.168.1.255
nd6 options=1<PERFORMNUD>
...


시리얼 터미널에서 ESP8266을 맥이 연결된 공유기에 연결 (ESP8266의 IP는 192.168.1.6)

AT

OK
AT+CWMODE=3

OK
AT+CWLAP
...
+CWLAP:(0,"ollehWiFi",-84,"00:1d:93:23:d6:2e",1)
+CWLAP:(0,"TESTAP",-89,"00:08:5b:77:e8:da",3)
+CWLAP:(3,"starbucks_ap_2.4g",-70,"30:52:5a:11:2d:43",3)
...
OK
AT+CWJAP="TESTAP","testpassword"

OK
AT+CIFSR
+CIFSR:APIP,"192.168.4.1"
+CIFSR:APMAC,"1a:fe:34:98:83:3b"
+CIFSR:STAIP,"192.168.1.6"
+CIFSR:STAMAC,"18:fe:34:98:83:3b"

OK

1. TCP 클라이언트로 동작하기


먼저 맥에서 nc(netcat)를 사용해 TCP 서버를 실행시켜 논다.

$ nc -l 8000

그 다음 시리얼 터미널에서 ESP8266을 클라이언트로 동작시킨다.

AT+CIPMUX=1          multiple connection이 가능하도록 설정

OK
AT+CIPSTART=4,"TCP","192.168.1.5",8000      192.168.1.5의 8000번 포트로 TCP 커넥션을 연결. connection 번호는 4
4,CONNECT

OK
AT+CIPSEND=4,5     4번 connection으로 5바이트의 데이터를 전송
> hello                         전송할 데이터 입력

SEND OK

hello의 마지막 'o'를 누르는 순간 hello라는 5바이트의 데이터가 전송되고 맥의 화면에 hello라는 글자가 찍히게 된다.

$ nc -l 8000
hello

이제 맥의 화면에서 엔터를 누르면 시리얼 터미널 화면에 수신된 데이터가 표시된다.

+IPD,4,1:         4번 connection으로 1 바이트 데이터가 수신되었음. 내용은 엔터라 화면에는 따로 표시된 내용은 없음

OK

맥에서 welcome을 입력하고 엔터를 누르면 시리얼 터미널 화면에 8 바이트 데이터가 수신되었다는 표시와 함께 수신된 데이터(welcome)이 표시된다.

+IPD,4,8:welcome

OK

맥에서 Ctrl-C를 눌러 nc를 종료시키면 connection이 종료된다.

4,CLOSED

OK

2. TCP 서버로 동작하기


기본적으로 클라이언트로 동작하기와 동일하게 공유기에 연결한 후 시리얼 터미널에서 명령을 입력한다.


AT+CIPMUX=1
          
multiple connection이 가능하도록 설정

OK
AT+CIPSERVER=1,5000

OK

5000번 포트에 TCP서버를 오픈해서 연결을 기다리는 상태 (첫번째 파라미터는 모드로 1로 해 줌) 이제 맥에서 netcat을 이용해 ESP8266의 서버에 연결한다.

$ nc 192.168.1.6 5000

시리얼 터미널에 클라이언트(맥)와 연결이 되었음을 알려준다.

0,CONNECT

이제 맥에서 보내고 싶은 데이터를 입력한 후 엔터를 입력

nc 192.168.1.6 5000
hello from mac

시리얼 터미널에 0번 connection으로 15바이트의 데이터가 수신되었고 내용은 'hello from mac'임이 표시됨

+IPD,0,15:hello from mac

OK

서버(ESP8266)에서 클라이언트로 데이터를 보내기 위해서 시리얼 터미널에서 다음과 같이 입력

AT+CIPSEND=0,8
> welcome
SEND OK

맥 화면에 수신된 데이터가 표시됨

nc 192.168.1.6 5000
hello from mac
welcome

이런식으로 데이터를 송수신하면 된다. 맥에서 Ctrl-C를 눌러 nc를 종료하면 connection이 종료된다.

0,CLOSED


3. Wifi Access Point로 동작하기

AP에 필요한 설정을 해 준다.

AT+CWSAP="myesp8266","testpassword",3,0

OK

첫번째 myesp8266은 무선랜의 SSID이고 두번째 파라미터 testpassword는 암호, 세번째 파라미터는 무선랜 채널(여기서는 채널 3), 마지막 파라미터는 암호화 방법이다. 0은 암호화를 하지 않는것이다. 다만 아직까지의 펌웨어에서는 암호화를 지원하지 않는다.

AT+CWMODE=3

OK

CWMODE는 2 또는 3으로 설정. 이제 컴퓨터나 스마트폰에서 무선랜을 검색해 보면 myesp8266이라는 SSID의 무선랜이 보이게 된다.

AT+CWLIF

OK

AT+CWLIF는 현재 AP에 연결된 디바이스의 목록을 보여준다. 위에서는 아직 하나도 연결한 디바이스가 없어 빈칸이 출력되었다.  장치가 연결되면 위의 서버 예제나 클라이언트 예제를 사용해 연결된 디바이스와 통신을 할 수 있다.

그리고 ESP8266이 AP로 동작하는 경우 ESP8266의 IP는 항상 192.168.4.1 이다.




ESP8266 펌웨어 업데이트 하기

ESP8266의 펌웨어를 업데이트 하려면 GPIO0가 GND에 연결된 상태로 전원이 켜져 UART UPGRADE 모드가 되어야 한다. 이 상태에서 컴퓨터에서 업데이트 프로그램을 실행하면 된다. 현재 GUI로 동작하는 툴은 윈도우용만 나와있다. 
하지만 커맨드라인에서 사용할 수 있는 esptool을 사용하면 맥이나 리눅스에서도 문제없이 펌웨어 업데이트가 가능하다. 

esptool은 GitHub에서 다운받을 수 있다. esptool을 사용하려면 pyserial이 미리 설치되어 있어야만 한다.

설치가 되었고 ESP8266이 UART UPGRADE 모드인 경우 다음과 같이 명령을 주면 된다.

./esptool.py --port [Serial port] write_flash [address] [filename]

[Serial port]에는 ESP8266이 연결되어 있는 시리얼 포트 디바이스 이름을 써주면 된다. 디폴트는 /dev/ttyUSB0로 되어 있다. 
[filename]이 지정한 바이너리 파일의 내용을 ESP8266의 [address]가 가르키는 주소에 기록을 하게 된다.

아래는 맥에서 0.95 펌웨어로 업데이트 하는 예제이다.

$ ./esptool.py /dev/tty.usbserial-A4013ESQ write_flash 0x00000 AI-v0.9.5.0\ AT\ Firmware\ \(1\).bin
Connecting...
Erasing flash...
Writing at 0x0007ec00... (100 %)

Leaving...

위와 같이 되면 업데이트가 끝난 것이다. 이제 다시 부팅해서 시리얼 터미널을 열고 아래 명령을 입력해보면 새로운 펌웨어로 동작하는걸 확인할 수 있다.

AT+GMR
00200.9.5(b1)
compiled @ Dec 25 2014 21:40:28
AI-THINKER Dec 25 2014

OK

바이너리 파일이 여러개로 되어 있는 경우는 write_flash 뒤의 [address] [filename] 부분을 반복적으로 써 주면 된다. 즉 file1.bin은 0x00000 번지에 쓰고, file2.bin은 0x40000 번지에 쓰고 싶으면 esptool.py --port /dev/ttyusbserial-A4013ESQ write_flash 0x0000 file1.bin 0x40000 file2.bin 으로 하면 된다.



2015년 2월 13일 금요일

nodemcu - Lua on ESP8266

ESP8266은 단순히 아두이노에 붙여 Wifi-to-serial 모듈로 사용하기에는 아까울 정도로 더 많은 기능을 가지고 있다. 80MHz로 동작하는 Tensilica Xtensa LX3 라는 32-bit 프로세서가 들어있고, 이 코어용 펌웨어를 개발하는데 필요한 개발용 툴체인이 모두 오픈소스로 공개되어 있다.
크로스 컴파일 툴체인을 빌드하는 방법부터 예제 코드까지 인터넷을 찾아보면 꽤 많은 자료가 이미 공개되어 있다.



하지만 새로운 프로세서를 사용한다는건 즉 '공부해야 할 내용이 엄청 많다'와 동의어이다. 그리고 디버깅을 해서 새로 컴파일 할 때 마다 펌웨어를 다시 굽는것도 귀찮은 일이 된다.
그래서 이런 문제들을 대부분 해결할 수 있게 lua라는 언어의 인터프리터가 nodemcu라는 이름으로 ESP8266에 올라갔다.



Lua 5.1.4 기반 (단 io, math, debug, os 모듈은 제외)이고 인터프리터 방식이기 때문에 시리얼 터미널에서 직접 코드를 입력해서 별도 컴파일 과정 없이 바로 실행을 해 볼 수 있다.
JavaScript와 유사하게 event-driven 방식의 프로그래밍 모델을 사용해서 쉽게 프로그램을 만들 수 있다. (물론 기존에 C를 사용해 임베디드 프로그래밍을 하던 프로그래머 입장에선 처음에 좀 생소할 수 있긴 하다)
추가적인 장점으로는 file, timer, pwm, i2c, spi, 1 wire, net, mqtt, gpio, wifi, adc, uart 드라이버가 기본적으로 built-in 되어 있어 하드웨어를 제어하기 위해 복잡한 레지스터들을 따로 공부할 필요 없이 아두이노에서처럼 쉽게 사용할 수 있다.
GPIO핀은 아래와 같이 매핑되어 있다.

IO indexESP8266 pinIO indexESP8266 pin
0 [*]GPIO168GPIO15
1GPIO59GPIO3
2GPIO410GPIO1
3GPIO011GPIO9
4GPIO212GPIO10
5GPIO14
6GPIO12
7GPIO13
즉 GPIO0에 연결된 LED를 켜 주려면 다음과 같이 하면 된다.

gpio.mode(3, gpio.OUTPUT)      
gpio.write(3, gpio.HIGH)            

nodemcu 역시 오픈소스로 전부 공개되어 있지만 빌드하려면 크로스 툴체인부터 빌드해야 하기 때문에 C로 직접 코딩을 할 생각이 없으면 간단하게 pre-built binary를 받아 ESP8266에 써 주면 바로 lua를 사용할 수 있다.

https://github.com/nodemcu/nodemcu-firmware

위의 주소에서 소스코드와 바이너리를 모두 구할 수 있다. 하지만 저 사이트에 있는 바이너리 파일의 경우 디폴트 시리얼 통신속도가 9600bps로 되어 있다.

이 주소(http://dangerousprototypes.com/forum/download/file.php?id=11403&sid=dd89b3a2ef2524b5739e17e2f46d35d8)에 있는 파일을 받으면 시리얼 통신속도가 115200bps로 되어있는 펌웨어 바이너리 파일을 구할 수 있다.

위의 zip 파일을 받아 압축을 풀어보면 firmware 디렉토리에 0x00000.bin, 0x10000.bin 이렇게 2개의 bin 파일이 들어있다. 이 두 파일을 ESP8266에 써 줘야 한다.

펌웨어를 구울때는 nodemcu-flasher를 사용한다. 차기 버젼은 Qt를 사용해 크로스 플랫폼에서 동작할거라고 하는데 아직까지는 아쉽게도 윈도우용밖에 없다.

펌웨어를 업데이트 하려면 ESP8266에 전원을 넣기 전에 GPIO0가 LOW로 (즉 GND에 연결) 되어 있어야 한다. GPIO0가 LOW인 상태에서 모듈에 전원이 들어오면 UART BOOT 모드로 동작하게 되어 펌웨어 업데이트가 가능해진다.



위의 사진처럼 daughter board를 만들고 점퍼를 사용해 GPIO0를 Vcc(3.3V)에 연결할지 GND에 연결할지 선택할 수 있게 해 놓았다. 여기서는 펌웨어 업데이트를 할 것이므로 점퍼를 오른쪽으로 옮겨놓으면 된다.

그리고 USB-to-Serial adapter (여기서는 FTDI 232R을 사용)를 사용해 PC와 연결해준다. 시리얼포트가 정상적으로 보이면 자신의 OS에 맞는 ESP8266Flasher.exe를 실행시킨다.


먼저 COM Port를 설정해준다. 그리고 나서 Config를 눌러 플래쉬에 기록할 파일을 지정한다.


동시에 여러 파일을 라이팅 할 수 있지만 여기서는 두개의 파일만 기록하면 되기 때문에 위와 같이 두개의 파일만 X로 체크해주고 파일 위치를 선택한 후 각 파일을 기록할 주소를 지정해 준다. 0x00000.bin은 0x00000에, 0x10000.bin은 0x10000으로 해 주면 된다. 설정이 끝났으면 다시 이전 화면으로 돌아가 Flash(F) 버튼을 눌러준다.


그러면 AP MAC과 STA MAC에 값이 표시되며 라이팅이 진행된다. 만일 MAC 값들이 표시되지 않는다면 PC가 ESP8266과 정상적으로 통신이 되고 있지 않다는 것이고 그러면 라이팅도 진행되지 못한다. 그 경우 일단 멈춘 후 초기 화면에서 Advanced로 가서 설정을 변경해 본다.


Baudrate이 맞지 않는 경우가 가장 많다.

정상적으로 진행되면 프로그레스바가 진행되고 라이팅이 끝나면 화면 아래쪽에 녹색 표시가 나타나게 된다.


이제 펌웨어 업데이트가 끝난 것이다. 프로그램을 종료하고 ESP8266 보드에 연결된 케이블을 분리하면 된다. 그리고 점퍼를 다시 왼쪽으로 돌려놓고 전원을 연결하면 이제 방금 업데이트한 펌웨어가 실행된다.

시리얼 터미널을 실행해 연결시키면 프롬프트가 바뀌게 되고 이제부터는 AT 명령어는 더 이상 동작하지 않는다.

 다음 포스트에서는 lua를 이용해 ESP8266에서 여러가지 예제를 실행시켜 보겠다.

2015년 2월 12일 목요일

초소형 아두이노 호환 보드 8pino

Arduino Pro Mini

Arduino Micro


Femtoduino

Digi Spark

Lilypad Arduino

Olimexino


Arduino mini나 arduino micro, 또는 Femtoduino, Digi Spark, Lilypad같이 작은 크기의 아두이노 호환 보드들이 많은데 최근에 그 보다도 더 작은 보드가 나왔다.

8pino라는 이름의 보드로 프로세서로는 ATTiny85를 사용하기 때문에 IO핀이 많지는 않아도 웨어러블 디바이스같은걸 만들 때 적합하다.



사진에서 볼 수 있는것처럼 보드를 Micro USB 커넥터에 직접 꽂을 수 있다. 그리고 보드 전체의 크기가 DIP 8핀과 동일하기 때문에 브레드보드에 ATTiny85 대신 8pino로 대신 꽂을수도 있다.
아두이노와 호환되기 때문에 Arduino IDE를 사용할 수도 있고, USB에 연결하면 USB Tiny ISP로 인식하기 때문에 avr-gcc나 AVR Studio를 사용해 컴파일 한 바이너리를 직접 플래쉬에 구울수도 있다.



회로도 및 gerber 파일까지 다 공개되어 있고 아직 제품으로 판매하는곳은 없는 상태이다.
조만간 Seeedstudio에서 판매를 시작할 예정이고 가격은 대략 $8 정도가 될 듯 하다.

2015년 2월 10일 화요일

Beacon의 이해



비이컨 기술의 가장 기본적인 사용법은 모바일 디바이스에서 비이컨까지의 거리를 측정하는 것이다. 하지만 비이컨으로 거리를 측정하는걸 해 본 사람들은 누구나 알고 있는 것처럼 거리 추정은 상당히 오차가 크다. 5미터 떨어진 비이컨의 경우 추정 거리는 2미터에서 10미터까지 왔다갔다 한다. 

이렇게 추정 거리가 변하는 이유와 이런 오차를 줄이기 위한 방법은 비이컨에 관해 가장 흔한 질문이다. 추정에 영향을 미치는 요인은 전파 신호의 난반사, 장애물, 휴대폰과 비이컨의 방향등 매우 다양하다. 

하지만 거리 추정에 무었보다 가장 큰 요인은 전파 노이즈이다. 백그라운드 전파 노이즈는 어디에건 존재한다. 강한 전파(즉, SNR이 큰)의 경우 약한전파보다 노이즈는 별로 문제가 되지 않는다. 이런 이유 때문에 비이컨에서 10미터 이상 떨어진 경우보다는 가까운 거리에서는 좀 더 정확한 거리 추정이 가능하다. 

Apple의 권장사항




애플이 iOS7에서 iBeacon 기술을 소개했을 때, 애플의 문서는 거리 추정치를 직접 사용하지 않는걸 권장했다. 비이컨 범위 정보를 제공하는 CLBeacon 클래스는 비이컨과의 거리 추정치를 미터 단위로 제공하는 필드를 가지고 있다. 하지만 이 속성을 distance라고 부르는 대신 애플은 accuracy라고 이름붙였다. 권장하는 사용법은 이 값을 여러 비이컨들 중에 어느것이 가장 가까운가 비교하는 용도로만 사용하는 것이다. 또한 CLBeacon 클래스는 proximity라는 속성을 제공해 거리 추정치를 “immediate”, “near”, “far”로 그룹핑 한다. 이 각 그룹의 정의는 명확하지 않지만, 실험 결과 0.5미터 이내의 거리는 “immediate”, 0.5~3m 정도는 “near”, 그 이상은 “far”로 구분한다고 볼 수 있다.



이런 내용이 비이컨을 사용해 직접적으로 거리를 측정할 수 없다는걸 의미하지는 않는다. 단지 비이컨의 동작 원리와 결과값의 품질에 어떤 한계가 있는지를 먼저 이해할 필요가 있다는걸 의미한다.

Reference Transmitter Power


비이컨 전송은 transmitter power 필드를 포함하고 있어 특정 거리에서 신호 세기가 얼마의 세기가 되어야 하는가를 나타낸다. 예를들어 iBeacon 기술을 사용할 때, 표준 측정값은 비이컨에서 1미터 떨어진 곳에서 iPhone 5S(iOS7이 발표되었을 때 최신 모델)이 측정한 것이다. 비이컨은 표준거리에서 신호레벨(RSSI)을 측정한 후 비이컨이 표준값을 송신하도록 calibrate되어야만 한다.  RSSI 값은 dBm 단위를 사용하고 1미터 거리에서 calibrate 된 비이컨의 통상 RSSI 값은 -59 dBm이다. 각 송신기와 안테나는 서로 다른 세기의 전파를 송신하기 때문에 여러 비이컨의 실제 calibration 값은 서로 다르다. Radius Network의 RadBeacon같은 일부 제품은 출력파워를 조정할 수 있다.

How distance estimates work


모바일 디바이스는 비이컨의 신호레벨을 레퍼런스 신호레벨과 비교함으로서 비이컨과의 거리를 추정할 수 있다. 비이컨이 adv한 패킷이 수신될 때 마다 블루투스 칩은 비이컨의 신호레벨 측정값을 RSSI로 제공한다. 각 비이컨 전송은 위에서 언급한 calibration 값을 포함하고 있기 때문에, 실제 시그널 레벨을 1머터에서 기대되는 시그널 레벨과 비교해서 거리를 추정할 수 있다. 예를들어 비이컨 adv 패킷이 -65 dBm 시그널 레벨로 수신되었고 송신기의 출력 calibration값은 -59 dBm이라고 해 보자. -65 dBm은 -59dBm보다 약한 신호레벨이므로, 즉 비이컨은 1미터보다 먼 거리에 있을 가능성이 크다는걸 의미한다.

거리를 추정하기 위해 이 두 숫자를 공식에 집어넣을 수 있다. 아래 공식은 Android Beacon Library에 사용한 것이다. 공식의 3개의 상수(0.89976, 7.7095, 0.111)는 여러 정해진 거리에서 넥서스4를 사용해 측정한 신호 세기에 기반해 best fit으로 계산한 값이다. 


protected static double calculateDistance(int txPower, double rssi) {
  if (rssi == 0) {
    return -1.0; // if we cannot determine distance, return -1.
  }

  double ratio = rssi*1.0/txPower;
  if (ratio < 1.0) {
    return Math.pow(ratio,10);
  }
  else {
    double accuracy =  (0.89976)*Math.pow(ratio,7.7095) + 0.111;    
    return accuracy;
  }
} 


위의 예제의 경우 txPower에 -65를, rssi에 -59를 넣으면 거리 추정치는 2미터가 된다.

Filtering for noise


신호 노이즈때문에 RSSI 측정치만으로 거리를 추정하는것은 좋은 생각이 아니다. 비이컨 패캣의 RSSI 측정값을 보면 신호 레벨은 여러 곳에서 갑자기 점프하는걸 볼 수 있다. 이 노이즈를 제거하는 가장 간단한 방법은 RSSI 측정치의 running average를 사용해서 노이즈를 부드럽게 변하도록 해 주는 것이다. 또한 데이터 셋에서 이상하게 높거나, 이상하게 낮은 값은 제외해 버리는것도 일반적이다. Android Beacon Library에서 사용한 알고리즘은 20초 샘플링 구간 측정치의 상위 및 하위 10%를 버리고 나머지를 평균한다. 

이 방법의 장점은 거리 추정이 좀 더 정확하고 안정적이라는 것이다. 단점은 모바일 디바이스가 움직이면 거리 추정치가 움직인 위치를 정확히 따라잡는데 20초의 시간이 걸린다는 것이다.

20초 샘플링 구간은 iOS에서 사용하는 방법과 유사하다. 아래 그래프는 아이폰4S가 비이컨에서부터 0.5미터 거리에서 3미터로 빠르게 이동했을 때 (빨간선)  CLBeacon 클래스의 accuracy 필드가 어떻게 변하는가를 보여준다. 그래프에서 볼 수 있는것처럼 디바이스가 이동한 후 거리 추정치(파란선)이 안정화되는데 약 20초가 걸린다.


Device Variations


아이폰 4S, 5, 5S, 6 모델들의 블루투스 회로, 안테나, 케이스 디자인은 큰 변동이 없기 때문에 비이컨 거리 추정은 대부분의 iOS 디바이스에서 일관되게 동작한다. 하지만 항상 그런것은 아니다. 아이팟 터치에서의 거리 추정치는 블루투스 신호 수신 감도를 높이기 위해 안테나를 다른 식으로 배치했기 때문에 일반적으로 좀 더 가깝게  추정된다.

디바이스간의 variation은 안드로이드에서 훨씬 더 큰 문제이다. 각 안드로이드 모델은 완전히 다른 블루투스 칩셋, 안테나, 케이스 디자인을 가질 수 있기 때문이다. 이 모든 요인이 신호 수신 레벨에 영향을 미치므로 거리 추정치에도 영향을 미치게 된다. 넥서스4, 넥서스5와 갤럭시S4 모델은 비이컨과 같은 거리에서 상당히 크게 다른 신호 레벨로 받는다. 이런 이유때문에 Radius Networks는 다양한 안드로이드 디바이스에 대해 거리 공식 DB를 구축하기 시작했다.

Setting Expectations


비이컨에서의 거리를 추정하는게 가능하지만 이 측정치는 말 그대로 ‘추정’치라는걸 잊으면 안된다. 디비아스가 비이컨에서 더 멀어질수록, 이 추정치는 점점 더 정확하지 않게 된다. 비이컨에서 20미터 떨어진 디바이스는 거리 추정치에 +-10미터의 오차를 가지게 된다. 폰이 주머니에 들어있는가 여부, 어느 방향으로 놓여있는가, 간판 뒤쪽에 있는가, 또는 많은 사람들 무리에 막혀있는가등에 따라 비이컨과의 거리 추정치는 크게 영향을 받게 된다. 

그러므로 어떤걸 할 수 없는가를 인식하는게 중요하다.

  • 비이컨이 1미터 떨어져 있는지 아니면 10미터 떨어져 있는지는 쉽게 말할 수 있어도, 10미터 떨어져 있는지 아니면 20미터 떨어져 있는지는 말할 수 있을거라고 기대하면 안된다.
  • 노이즈를 제거하기 위해 running average를 사용하기 때문에 사용자가 움직이면 움직임을 거의 리얼타임으로 추정할 수 있을거라고 생각하면 안된다.
  • 비이컨이 있는 방향을 결정할 수 있을거라고 생각하면 안된다. 비이컨은 보통 전방향 송신기이기 때문에 거리를 추정할 수는 있어도 방향은 추정할 수 없다.
  • 비이컨과의 거리를 추정할 수 있다는것이 모바일 디바이스가 방 안에 정확히 어느 위치에 있는지 결정할 수 없다는걸 이해해야 한다. 비이컨이 실내 위치 시스템에서 구성요소로 사용될 수는 있어도 비이컨 거리 추정만으로는 문제를 해결할 수 없다.
  • 몇개의 비이컨으로 삼각측량법을 사용해 간단한 실내 위치 시스템을 만들수 있을거라고 기대하면 안된다. 거리 추정의 정확도는 거리가 멀어질수록 나뻐지기 때문에 실내에서 위치를 알기 위해 삼각측량을 사용하는건 정확한 위치 추정을 할 수 없다.

하지만 비이컨 거리 추정으로 할 수 있는 유용한 어플리케이션도 많다. 예를 들자면

  • 비이컨이 매우 가까워(5미터 이내)질 때 어떤 동작을 시작
  • 수미터 이내에 있어 신호를 수신할 수 있는 여러 비이컨들중에 어느것이 가장 가까운가를 결정하기 
  • 특정 위치를 찾는 사용자에게 거리 피드백을 제공 (예: 보물찾기)

Best Practices


최대한 정확한 거리 추정치를 얻기 위해서 Radius Networks는 다음의 내용을 권장한다.

  • 비이컨에서 가능한 최대 출력의 송신 레벨을 사용한다. 강한 시그널 레벨은 높은 SNR을 의미하기 때문에 좀 더 정확한 거리 추정이 가능하다.
  • 비이컨의 송신 빈도를 최대한 높여준다. 모바일 디바이스에 advertising 패킷이 더 많이 수신될수록, 노이즈를 제거하기 위해 평균해야 하는 샘플이 많아진다. 
  • 가능한 Radius Networks의 RadBeacon USB같이 외부에서 전원을 공급받는 비이컨을 사용한다. 그래야 배터리 수명을 걱정할 필요 없이 가장 고출력과 빠른 송신 빈도로 패킷을 advertising 할 수 있다.
  • 비이컨을 제대로 보정한다.
  • 명확하게 시야에 들어오는 장소에 비이컨을 설치한다. 사람들이 붐비는 장소라면 바닥보다는 높은 곳에 설치하는게 더 좋다.
  • 특정 안드로이드 모델을 위한 앱을 계획하거나 설치하려고 하면 거리 추정 공식이 해당 모델에 최적화 되어 있는가 확인해야 한다. Radius Networks의 Android Beacon Library는 다양한 안드로이드 모델을 위해 확장 가능한 거리 추정 공식 DB를 제공한다. 

원문은 http://developer.radiusnetworks.com/2014/12/04/fundamentals-of-beacon-ranging.html








2015년 2월 5일 목요일

Blue Basic...CC2540/2541을 쉽게 사용하기

Bluetooth Low Energy (BLE)에서 가장 많이 사용되는 칩들중에 하나가 TI의 CC2540/2541이다. 이 SoC에는 BLE관련 회로 뿐 아니고 8051 코어도 같이 들어있어 단순히 BLE 통신용 모듈로서만 사용하는게 아니고 추가로 자신의 어플리케이션 코드를 집어넣어 별도의 추가 프로세서 없이 standalone으로 사용할수도 있다. 


개발을 위한 툴들도 거의 다 무료로 구할 수 있지만 문제는 개발을 위해 공부해야 하는 것이 상당히 많다는 것이다. 



그래서 이 CC2540/2541 환경에서 개발을 쉽게 할 수 있도록 나온것이 Blue Basic이다. Blue Basic은 CC2540/2541에서 실행되는 BASIC 인터프리터로 별도의 추가 툴 없이 쉽게 프로그램을 만들 수가 있다. 

기본적으로 BASIC 언어를 사용하지만 실제 프로그램을 만들려면 블루투스 스택 뿐 아니고 CC254x 칩의 하드웨어들(UART, SPI, I2C, 타이머 등)을 쉽게 사용할 수 있는게 필수적이다. 그래서 이 목적을 위해 BASIC언어를 약간 확장했고, 가능한 최대로 아두이노의 표기를 따르려고 노력했다. 예를들어 P0(0)을 입력으로 사용하려고 하면 아두이노에서 'pinMode(A0, INPUT)' 을 사용하는것 처럼 BASIC 명령 'PINMODE P(0) INPUT' 을 사용하면 된다. 블루투스 키워드는 쉽게 서비스를 만들어 다른 하드웨어에 쉽게 연결할 수 있게 되어 있다. 

간단한 서비스는 다음과 같이 만들 수 있다.

10 ADVERT GENERAL
20 ADVERT "25FB9E91-1616-448D-B5A3-F70A64BDA73A"
30 ADVERT END
40 GATT SERVICE "25FB9E91-1616-448D-B5A3-F70A64BDA73A"
50 GATT CHARACTERISTIC "D8ABBBE7-F10B-4EC3-B781-DBCBD2334400" "On/Off"
60 GATT READ WRITE A ONWRITE GOSUB 200
70 GATT END
80 PINMODE P0(0) OUTPUT
90 GOSUB 200
100 END
200 P0(0) = A
210 RETURN
BASIC을 처음 보는 사람이라고 해도 대강의 내용은 이해가 될 것이다. 물론 설명해야 할 부분은 많이 있지만 기본적으로 한개의 컨트롤을 on/off하는 서비스를 advertise하고, 이 서비스 값을 출력해 외부 장치를 제어한다. 예제 보드에서는 이 출력이 LED에 연결되어 있다.

Blue Basic을 사용하려면 CC254x를 사용한 BLE 모듈의 펌웨어를 교체해야 한다. 모듈은 aliexpress에서 $5~7정도에 구할 수 있고, 펌웨어를 업데이트 하기 위해서는 TI CC Debugger가 필요하다. 


일단 Blue Basic 펌웨어가 올라가면 그 이후는 PC/Mac/iPhone/Android용 콘솔 프로그램을 사용해 코드를 입력하면서 바로 실행시켜 볼 수가 있다.



Blue Basic을 이용해 iBeacon을 만드는 코드 예제이다.

10 // "A Simple iBeacon service"
20 DIM M(5)
30 // "Major (0-65535)"
40 M(0) = 0
41 M(1) = 2
50 // "Minor (0-65535)"
60 M(2) = 0
61 M(3) = 4
70 // "Power"
80 M(4) = 0xC8
90 ADVERT GENERAL
100 ADVERT CUSTOM "FF 4C 00 02 15" "74 27 8B DA B6 44 45 20 8F 0C 72 0E AF 05 99 35" M "00"
110 ADVERT END
120 // SET A NAME IN THE SCAN RESPONSE
130 SCAN NAME "iBeacon"
140 SCAN END
AUTORUN ON

좀 더 상세한 설명은 github를 참조하면 된다.


2015년 2월 4일 수요일

라즈베리 파이 2에서 Windows 10 지원 발표

오늘 받아본 메일에 놀라운 내용이 들어있었다.
MS가 Raspberry Pi 2에서도 Windows 10을 지원한다는 것이다.


기존의 라즈베리는 성능이 딸려 힘들텐데...라는 생각을 하고 있었는데 확인해보니 라즈베리 파이 2라는 보드가 새로 나왔다.


사진으로 봐서는 기존의 B+ 모델과 거의 동일한 형태인데 사양은 많이 좋아졌다.

기존 모델은 BMC2835 SoC를 장착해 700MHz ARM 11 코어를 사용했는데 비해 새 모델은 BCM2836 SoC를 장착해 900MHz quad-core ARM Cortex A7을 사용하기 때문에 기존 모델에 비해 대략 6배 정도의 속도 향상이 있다고 한다. 메모리도 1GB로 이전 모델에 비해 두배가 되었다.

그럼에도 불구하고 가격은 이전 모델과 동일하게 $35라고 한다.

라즈베리 파이 2에서 사용될 윈도우 10은 개발자 커뮤니티에 무료로 제공한다고 하니 앞으로는 DIY에도 윈도우를 사용한 작품들도 늘어날 듯 하다.

윈도우 10 지원은 오늘 발표된 것이고 다음달쯤 상세 사항을 공개한다고 한다.

Can not wait to see Windows 10 working on Raspberry pi 2!!!

2015년 2월 3일 화요일

에디슨 GPIO 핀 설정 가이드

Introduction


Intel Edison 플랫폼은 GPIO, PWM, SPI, I2C, ADC등의 다양한 인터페이스 모드로 사용될 수 있도록 설정할 수 있는 외부 input/output핀을 가지고 있다. 여기서는 핀에서 사용할 수 있는 기능, 핀 제어와 I/O를 위한 상세한 GPIO 핀 매핑, 외부 I/O핀 기능을 원하는 모드로 설정하기 위해 사용하는 리눅스 명령 툴에 대해 설명한다.

GPIO allocation and shield pin control


에디슨 보드에 있는 20개의 아두이노 호환 쉴드 I/O핀은 IO0~IO19로 번호가 붙어 있다. (아래 그림 1 참조) 모든 핀은 기본 GPIO 기능을 지원한다. 일부 핀들은 PWM, ADC, SPI, I2C 기능도 지원한다. 에디슨에서 핀의 다른 기능을 선택하는건 SoC 핀 제어 인터페이스와 멀티플렉싱 제어를 위해 할당된 GPIO 출력 신호를 통해 이루어진다. 다음 장은 에디슨 플랫폼에서 각각의 GPIO핀에 가능한 기능들에 대한 매핑을 상세히 설명하는데, 이것들은 크게 다음의 카테고리로 분류된다.


  • 외부 GPIO - 외부 쉴드 핀을 통해 디지털 신호 입출력에 사용
  • Pin multiplexing 제어 - 해당 쉴드 핀에서 가능한 다른 기능을 선택
  • Pin buffer (level-shifter) direction 제어 - 입출력을 위한 해당 쉴드 핀의 버퍼를 설정하는데 사용
  • Pin pull-up resistor 제어 - 쉴드핀의 풀업저항을 활성화/비활성화하는데 사용
  • 기타

쉴드핀에 대해 제공되는 어떤 기능이건 사용하려면, 해당 핀에 대한 multiplexing, buffer direction, pull-up resistor를 먼저 설정해야 한다.

그림1. 인텔 에디슨 아두이노 보드


Shield pin GPIO mapping


다음 표는 리눅스에서 GPIO와 PWM 핀 번호와 쉴드 I/O핀에 대한 매핑을 보여준다.

  • Shield pin - 아두이노 우노 핀 번호체계에서의 digital I/O 핀 번호
  • Linux - 리눅스에서 할당된 핀 번호
  • Muxed functions - 쉴드핀에 가능한 다른 기능

  • ShieldGPIOPWMMuxed functionsNotes
    PinLinux PinLinux Pin
    IO0130 UART1_RXD 
    IO1131 UART1_TXD 
    IO2128 UART1_CTS* 
    IO3120PWM0Depends on PWM Swizzler**
    IO4129 UART1_RTS* 
    IO5131PWM1Depends on PWM Swizzler**
    IO61822PWM2Depends on PWM Swizzler**
    IO748 - 
    IO849 - 
    IO91833PWM3Depends on PWM Swizzler**
    IO1041SwizSPI_2_SS1 
    I2S_2_FS* 
    PWM4_OUTDepends on PWM Swizzler**
    IO1143SwizSPI_2_TXD 
    I2S_2_TXD* 
    PWM5_OUTDepends on PWM Swizzler**
    IO1242 SPI_2_RXD 
    I2S_2_RXD*
    IO1340 SPI_2_CLK 
    I2S_2_CLK*
    IO1444 AIN0 
    IO1545 AIN1 
    IO1646 AIN2 
    IO1747 AIN3 
    IO1814 AIN4 
    I2C_6_SDA
    IO19165 AIN5 
표1. 쉴드 핀 GPIO 매핑

* 일부 SoC핀에는 I2C나 UART flow control같은 추가 기능을 가지고 있지만, 현재 아두이노 라이브러리에서는 지원할 계획이 없음. 하지만 Linux에서는 이 기능들을 사용할수도 있다.
** SoC는 4개의 PWM핀만을 제공한다. 베이스 보드에 "PWM swizzler"라고 라벨이 붙어있는 점퍼핀들은 이 4핀이 아두이노에서 일반적으로 PWM으로 사용되는 6개의 쉴드 헤더핀중에 어디에 연결될지를 결정하는데 사용된다. 초기 설정은 IO3, IO5, IO6, IO9가 SoC의 4개의 PWM핀에 연결되도록 셋팅되어 있다. 이 설정은 점퍼핀을 바꿔 IO10이나 IO11에 연결되게 할 수 있다.

Summary Pin Function Multiplexing Control


아두이노 헤더에 있는 모든 GPIO핀은 핀을 사용할수 있게 되기 전에 내부 GPIO를 설정해 줄 필요가 있다. 일반적으로는 output enable, pull-up enable과 모드 설정 정도가 된다. 하지만 일부 핀은 SPI, PWM, I2C같은 추가 기능들을 가지고 있기 때문에, 이런 핀들을 사용하려면 추가적으로 multiplexing에 대한 설정이 필요하다.

아래 표는 이런 설정을 최대한 간단하게 정리하여 프로그래머가 아두이노 헤더핀에 영향을 미치는 모든 muxing 핀들을 쉽게 알수 있도록 한 것이다.

이 표는 아래에 있는 회로도 핀 번호등의 추가 정보를 가지고 있는 더 상세한 표와 동일한 내용이다. 대부분의 경우는 이 표면 충분할 것이다.

 Linux GPIO PinGPIO Pin MuxSoC Pin ModesOutput Enable * (high = output)Pull-up Enable**
  Linux Pin0 (low)1 (high)01LinuxLinux
IO0130   GPIOUART248216
IO1131   GPIOUART249217
IO2128   GPIOUART250218
IO312   GPIOPWM251219
IO4129   GPIOUART252220
IO513   GPIOPWM253221
IO6182   GPIOPWM254222
IO748   GPIO 255223
IO849   GPIO 256224
IO9183   GPIOPWM257225
IO1041263PWMsee 240GPIOI2S or SPI258226
240GPIO or I2SGPIO or SPI_FS
IO1143262PWMsee 241GPIOI2S or SPI259227
241GPIO or I2SGPIO or SPI TXD
IO1242242GPIO or I2SGPIO or SPI RXDGPIOI2S or SPI260228
IO1340243GPIO or I2SGPIO or SPI CLKGPIOI2S or SPI261229
IO14  (A0)44200GPIOA0GPIO 232208
IO15  (A1)45201GPIOA1GPIO 233209
IO16  (A2)46202GPIOA2GPIO 234210
IO17  (A3)47203GPIOA3GPIO 235211
IO18  (A4)14204GPIO or I2C SDAA4GPIOI2C-6236212
IO19  (A5)165205GPIO or I2C SCLA5GPIOI2C-6237213


주: Muxing을 설정하기 전에 pin 214(TRI_STATE_ALL)을 LOW로 설정하는걸 권장한다. 이 핀을 LOW로 한 후 설정을 변경하고 나서 pin 214를 다시 HIGH로 하면 된다.

예1) IO0을 출력으로 설정
  Pin 0는 muxing이 없으므로 단순히 output을 활성화 시키고 pull-up을 enable하면 됨
예2) IO10을 SPI로 설정
  non-PWM 기능을 활성화 시키기 위해 263를 HIGH로 설정할 필요가 있다. non-PWM기능이 활성화 되면 240에 의해 제어되게 된다. 그 후 240을 HIGH로 해 SoC 핀 모드를 1로 설정해 SPI 기능을 선택한다.
이 문서 마지막에 여러가지 세부 설정에 대한 예제들을 볼 수 있다.

GPIO Interrupt support


에디슨의 모든 GPIO 입력은 인터럽트를 사용할 수 있고, 모든 타입의 인터럽트를 지원한다. 다음 표는 각 핀에서 지원하는 에지트리거, 레벨트리거 인터럽트 타입을 보여준다.


ShieldPinGPIOEdge-TriggeredLevel-Triggered*
SourcePinLinuxRisingFallingBothLowHigh
IO0SoCGP130_UART1_RXD130YYYYY
IO1SoCGP131_UART1_TXD131YYYYY
IO2IO3SoCGP128_UART1_CTS128YYYYY
SoCGP12_PWM012YYYYY
IO4IO5SoCGP129129YYYYY
SoCGP13_PWM113YYYYY
IO6SoCGP182_PWM2182YYYYY
IO7SoCGP4848YYYYY
IO8SoCGP4949YYYYY
IO9SoCGP183_PWM3183YYYYY
IO10SoCGP4141YYYYY
IO11SoCGP4343YYYYY
IO12SoCGP4242YYYYY
IO13SoCGP4040YYYYY
IO14SoCGP4444YYYYY
IO15SoCGP4545YYYYY
IO16SoCGP4646YYYYY
IO17SoCGP4747YYYYY
IO18SoCGP1414YYYYY
IO19SoCGP165165YYYYY

표2. GPIO Interupt Support

* 아두이노 라이브러리에서는 레벨트리거 인터럽트를 지원하지 않는다.

Detailed Pin Function Multiplexing Control


다음 표는 pin multiplexing 제어를 위해 할당된 GPIO 출력 목록이다. 이 GPIO 출력을 0/1 (LOW/HIGH)로 설정하는 것으로 특정 쉴드 I/O핀이 다른 기능을 사용하도록 선택해 줄 수 있다. 또한 SoC의 일부 GPIO핀은 내부 mux 옵션을 가지고 있기도 하다. 이런 것들은 "SoC Pin Modes"에 표시되어 있다. 현재 이들은 해당 SoC GPIO 핀 번호 N에 대한 핀 모드를 지정(/sys/kernel/debug/gpio_debug/gpioN/current_pinmux에 원하는 모드 "0/1/2/..."를 써 줌)하는것으로 설정할 수 있다.

ShieldPinGPIO Pin MuxSoC Pin Modes
PinLinux0 (low)1 (high)Power-on defaultPinLinux012
IO0-    GP130130GPIOUART 
IO1-    GP131131GPIOUART 
IO2-    GP128128GPIOUART 
IO3-    GP1212GPIOPWM 
IO4-    GP129129GPIOUART 
IO5-    GP1313GPIOPWM 
IO6-    GP182182GPIOPWM 
IO7-    GP4848GPIO  
IO8-    GP4949GPIO  
IO9-    GP183183GPIOPWM 
IO10U34_ IO1.7263PWM4_OUTGP41 SSP5_FS_1Pulled-down inputGP41 GP11141 111GPIO GPIOI2SSPI 
U16_ IO1.0240GP41SSP5_FS_1Pulled-up input* 
IO11U34_ IO1.6262PWM5_OUTGP43 SSP5_TXDPulled-down inputGP43 GP11543 115GPIO GPIOI2SSPI 
U16_ IO1.1241GP43SSP5_TXDPulled-up input* 
IO12U16_ IO1.2242GP42SSP5_RXDPulled-up input*GP42 GP11442 114GPIO GPIOI2SSPI 
IO13U16_ IO1.3243GP40SSP5_CLKPulled-up input*GP40 GP10940 109GPIO GPIOI2SSPI 
IO14U17_ IO0.0200GP44A0Pulled-up input*GP4444GPIO  
IO15U17_ IO0.1201GP45A1Pulled-up input*GP4545GPIO  
IO16U17_ IO0.2202GP46A2Pulled-up input*GP4646GPIO  
IO17U17_ IO0.3203GP47A3Pulled-up input*GP4747GPIO  
IO18U17_ IO0.4204GP14 I2C6_SDAA4Pulled-up input*GP14 GP2714 27GPIOGPIOI2C-6I2C-8
IO19U17_ IO0.5205GP165 I2C6_SCLA5Pulled-up input*GP165 GP28165 28GPIO GPIOI2C-6I2C-8

표3. Pin Function Multiplexing Control
* 이 핀들은 전원이 켜지면 디폴트로 pull-up 입력 상태임. 그러므로 실제적으로 Mux 스위치를 활성화 시킴(즉 Mux function 1이 선택됨)

Pin direction and pull-up control


에디슨의 대부분의 쉴드핀들에는 buffer/level-shifter가 있어 입력 또는 출력 방향으로 설정되어야 하고, 외부 47K 풀업/풀다운 저항을 활설화 시킬 수 있다. 둘 다 아래 표에 나와 있는 전용 GPIO 출력에 의해 구동된다. 쉴드핀을 출력으로 설정할 때, SoC GPIO핀의 direction을 출력으로 설정하기 전에 버퍼를 출력으로 설정하는걸 권장한다. 외부 풀업/풀다운 저항에 연결을 끊으려면 그 핀을 구동하고 있는 GPIO를 high-Z 입력으로 설정할 필요가 있다. 또한 PCAL9555A GPIO expander에서의 GPIO신호들은 내부 100K 풀업저항을 가지고 있고 디폴트로 GPIO핀에 연결되어 있다. 많은 경우 이 핀들을 high-Z 입력으로 설정해 이것들을 비활성화 시킬 필요가 있다.

Shield pinOutput Enable GPIO (high = output)Pull-up Enable GPIO
PinLinuxPower-on defaultPinLinuxPower-on default
IO0U34_ IO0.0248Pulled-down*U39_IO0.0216Pulled-up input**
IO1U34_ IO0.1249Pulled-down*U39_IO0.0217Pulled-up input**
IO2U34_ IO0.2250Pulled-down*U39_IO0.0218Pulled-up input**
IO3U34_ IO0.3251Pulled-down*U39_IO0.0219Pulled-up input**
IO4U34_ IO0.4252Pulled-down*U39_IO0.0220Pulled-up input**
IO5U34_ IO0.5253Pulled-down*U39_IO0.0221Pulled-up input**
IO6U34_ IO0.6254Pulled-down*U39_IO0.0222Pulled-up input**
IO7U34_ IO0.7255Pulled-down*U39_IO0.7223Pulled-up input**
IO8U34_ IO1.0256Pulled-down*U39_IO0.7224Pulled-up input**
IO9U34_ IO1.1257Pulled-down*U39_IO0.7225Pulled-up input**
IO10U34_ IO1.2258Pulled-down*U39_IO0.7226Pulled-up input**
IO11U34_ IO1.3259Pulled-down*U39_IO0.7227Pulled-up input**
IO12U34_ IO1.4260Pulled-down*U39_IO0.7228Pulled-up input**
IO13U34_ IO1.5261Pulled-down*U39_IO0.7229Pulled-up input**
IO14U16_ IO0.0232Pulled-down*U17_ IO1.0208Pulled-up input**
IO15U16_ IO0.1233Pulled-down*U17_ IO1.1209Pulled-up input**
IO16U16_ IO0.2234Pulled-down*U17_ IO1.2210Pulled-up input**
IO17U16_ IO0.3235Pulled-down*U17_ IO1.3211Pulled-up input**
IO18U16_ IO0.4236Pulled-down*U17_ IO1.4212Pulled-up input**
IO19U16_ IO0.5237Pulled-down*U17_ IO1.5213Pulled-up input**

표4. Pin direction and pull-up control
* 이 핀들은 전원이 켜질 때 디폴트로 외부 풀다운 입력임. 그러므로 level shifter는 실질적으로 input direction이 선택되어 있음
** 이 핀들은 전원이 켜질 때 디폴트로 내부 풀업 입력임. 그러므로 실질적으로 풀업(100K+47K 저항이 직렬로)이 활성화 되어 있음

Miscellaneous GPIOs


다음의 GPIO는 다른 플랫폼 기능과 아두이노 쉴드 호환성을 위해 사용된다.
FunctionGPIODirectionPower-on defaultInitial setup
PinLinux
TRI_STATE_ALLU17_IO1.6214OutputPulled-down 
SHLD_RESETU17_IO1.7215OutputPulled-up input* 
SHLD_RESETU17_IO0.7207InputPulled-up input* 






표5. 기타 GPIO
* 이 핀들은 전원이 켜질 때 디폴트로 풀업 입력 상태임. 이 상태는 출력이 high로 설정된 경우와 동일한 효과를 가짐


Shield pin configuration guide




  1. 사용하고자 하는 아두이노 쉴드의 핀 번호(IO0~IO19)를 확인한다. 
  2. 해당 핀에서 사용할 수 있는 기능들을 확인하고, 그 중 사용하길 원하는 기능을 선택한다.
  3. 원하는 기능을 위한 pin muxing 옵션을 선택하기 위해 어떤 GPIO 신호가 설정이 필요한지 결정한다. 일부 핀은 한가지 기능만 가지고 있거나, mux control이 필요없는 경우도 있다.
  4. 핀의 buffer direction을 입력 또는 출력으로 선택하기 위해 어떤 GPIO 신호를 설정할 필요가 있는지 결정한다. 또한 필요한 direction을 결정한다.
  5. 풀업 저항 control을 선택하기 위해 어떤 GPIO 신호를 설정할 필요가 있는지, 풀업저항을 활성화 또는 비활성화 시킬지를 결정한다. 일반적으로 대부분의 핀 기능에 대해 풀업저항은 비활성화 되어야 한다. GPIO 입력 기능에서는 풀업저항이 사용자의 필요에 따라 활성화 또는 비활성화 될 수 있다. 
  6. Linux user-space 환경(즉 명령어 쉘)에서 억세스하기 위해 위의 GPIO 번호를 export한다.
  7. 위의 GPIO 번호를 출력으로 설정한다.
  8. TRI_STATE_ALL 신호를 LOW로 해서 쉴드 핀의 연결을 끊어준다.
  9. 출력 로직 레벨을 HIGH 또는 LOW로 해주기 위해 위의 GPIO를 설정한다.
  10.  SoC GPIO 핀 모드를 원하는 기능으로 설정한다.
  11. TRI_STATE_ALL 신호를 다시 HIGH로 바꿔서 쉴드 핀을 연결시켜 준다.


예제1: IO5를 풀업저항이 비활성화 된 GPIO input으로 설정


  1. 쉴드 번호는 IO5이다. 표1에 의하면 GPIO 번호는 13이 된다.
  2. 필요한 기능은 GPIO이다. 표1에 의하면 이 쉴드핀에서 사용할 수 있는 다른 기능들은 PWM이 있다.
  3. 표3에 의하면 GPIO를 선택하기 위해서는 GPIO43 pin mux가 mode0로 설정되어야만 한다. 표4에 의하면 IO5의 output direction을 비활성화 시키기 위해 GPIO253은 0으로 설정되어야만 한다.
  4. 표4에 의하면 IO5의 외부 풀업저항을 비활성화 시키기 위해 GPIO221은 high-Z input으로 설정되어야만 한다. 
  5. 표5에 의하면 TRI_STATE_ALL 신호는 GPIO214에 의해 제어된다. 

그러므로 리눅스에서의 명령은 다음과 같다.

# echo 13 > /sys/class/gpio/export 
# echo 253 > /sys/class/gpio/export 
# echo 221 > /sys/class/gpio/export 
# echo 214 > /sys/class/gpio/export 
# echo low > /sys/class/gpio/gpio214/direction 
# echo low > /sys/class/gpio/gpio253/direction 
# echo in > /sys/class/gpio/gpio221/direction 
# echo mode0 > /sys/kernel/debug/gpio_debug/gpio13/current_pinmux 
# echo in > /sys/class/gpio/gpio13/direction 
# echo high > /sys/class/gpio/gpio214/direction

설정이 끝나면 이제 IO5를 GPIO input으로 사용하면 된다.

# cat /sys/class/gpio/gpio13/value  

예제2:  IO11을 풀업저항이 비활성화 된 GPIO input으로 설정

  1. 쉴드의 핀 번호는 IO11이다. 표1에 의하면 GPIO 번호는 43이다.
  2. 필요한 기능은 GPIO이다. 표1에 의하면 이 쉴드핀에서 사용할 수 있는 다른 기능들은 PWM, SPI, I2S가 있다.
  3. 표3에 의하면 GPIO/SPI를 선택하기 위해서는 GPIO262가 1로 설정되어야만 한다. GPIO를 선택하려면 GPIO241은 0으로 설정되어야만 하고 GPIO43 pin mux는 'mode0'로 설정되어야만 한다.
  4. 표4에 의하면 IO11의 output direction을 비활성화 시키기 위해 GPIO259가 0으로 설정되어야만 한다. 
  5. 표4에 의하면 IO11의 외부 풀업저항을 비활성화 시키기 위해 GPIO227은 high-Z input으로 설정되어야만 한다. 
  6. 표5에 의하면 TRI_STATE_ALL 신호는 GPIO214에 의해 제어된다. 
그러므로 리눅스에서의 명령은 다음과 같다. 

# echo 43 > /sys/class/gpio/export 
# echo 262 > /sys/class/gpio/export 
# echo 241 > /sys/class/gpio/export 
# echo 259 > /sys/class/gpio/export 
# echo 227 > /sys/class/gpio/export 
# echo 214 > /sys/class/gpio/export 
# echo low > /sys/class/gpio/gpio214/direction 
# echo high > /sys/class/gpio/gpio262/direction 
# echo low > /sys/class/gpio/gpio241/direction 
# echo mode0 > /sys/kernel/debug/gpio_debug/gpio43/current_pinmux 
# echo low > /sys/class/gpio/gpio259/direction 
# echo in > /sys/class/gpio/gpio227/direction 
# echo in > /sys/class/gpio/gpio43/direction 
# echo high > /sys/class/gpio/gpio214/direction

설정이 끝나면 이제 IO11을 GPIO input으로 사용하면 된다.

# cat /sys/class/gpio/gpio43/value    

예제3: IO7을 풀업저항이 활성화 된 GPIO input으로 설정

  1. 쉴드의 핀 번호는 IO7이다. 표1에 의하면 GPIO 번호는 48이다.
  2. 필요한 기능은 GPIO이다. 표1에 의하면 이 쉴드핀에는 다른 기능은 없다.
  3. 표3에 의하면 IO7은 필요한 mux option이 없다.
  4. 표4에 의하면 IO7의 output direction을 비활성화 시키기 위해 GPIO255가 0으로 설정되어야만 한다. 
  5. 표4에 의하면 IO7의 외부 풀업저항을 활성화 시키기 위해 GPIO223은 HIGH로 설정되어야만 한다. 
  6. 표5에 의하면 TRI_STATE_ALL 신호는 GPIO214에 의해 제어된다. 
# echo 48 > /sys/class/gpio/export 
# echo 255 > /sys/class/gpio/export 
# echo 223 > /sys/class/gpio/export 
# echo 214 > /sys/class/gpio/export 
# echo low > /sys/class/gpio/gpio214/direction 
# echo low > /sys/class/gpio/gpio255/direction 
# echo high > /sys/class/gpio/gpio223/direction 
# echo in > /sys/class/gpio/gpio48/direction 
# echo high > /sys/class/gpio/gpio214/direction

설정이 끝나면 이제 IO7을 GPIO input으로 사용하면 된다.

# cat /sys/class/gpio/gpio48/value    

예제4: IO6을 PWM 출력으로 설정


  1. 쉴드의 핀 번호는 IO6이다. 표1에 의하면 GPIO 번호는 182이다.
  2. 필요한 기능은 PWM이다. 표1에 의하면 이 쉴드핀에서 사용할 수 있는 다른 기능들은 GPIO가 있다.
  3. 표3에 의하면 PWM을 선택하기 위해서는 GPIO182가 'mode1'로 설정되어야만 한다.
  4. 표4에 의하면 IO6의 output direction을 활성화 시키기 위해 GPIO254가 1로 설정되어야만 한다. 
  5. 표4에 의하면 IO6의 외부 풀업저항을 비활성화 시키기 위해 GPIO222는 high-Z 입력으로 설정되어야만 한다. 
  6. 표5에 의하면 TRI_STATE_ALL 신호는 GPIO214에 의해 제어된다. 
# echo 254 > /sys/class/gpio/export 
# echo 222 > /sys/class/gpio/export 
# echo 214 > /sys/class/gpio/export 
# echo low > /sys/class/gpio/gpio214/direction 
# echo high > /sys/class/gpio/gpio254/direction 
# echo in > /sys/class/gpio/gpio222/direction 
# echo mode1 > /sys/kernel/debug/gpio_debug/gpio182/current_pinmux 
# echo high > /sys/class/gpio/gpio214/direction

이제 IO6를 PWM 출력으로 사용할 수 있다.

# echo 2 > /sys/class/pwm/pwmchip0/export 
# echo 2000000 > /sys/class/pwm/pwmchip0/pwm2/duty_cycle 
# echo 1 > /sys/class/pwm/pwmchip0/pwm2/enable  


예제5: IO14를 ADC 입력으로 설정


ADC 사용시 주의사항: ADC는 SPI버스에 연결되어 있기 때문에 (콜드부팅 후) ADC가 사용되기 전에 SPI핀이 먼저 설정되어야만 한다. Pin 10~13을 입력으로 설정하는것 만으로도 IO14~19를 ADC로 사용할 수 있다.


  1. 쉴드의 핀 번호는 IO14이다. 표1에 의하면 GPIO 번호는 44이다.
  2. 필요한 기능은 ADC이다. 표1에 의하면 이 쉴드핀에서 사용할 수 있는 다른 기능들은 GPIO가 있다.
  3. 표3에 의하면 ADC를 선택하기 위해서는 GPIO200가 1로 설정되어야만 한다.
  4. 표4에 의하면 IO14의 output direction을 비활성화 시키기 위해 GPIO232가 0으로 설정되어야만 한다. 
  5. IO14에 직접 연결된 모든 GPIO 라인은 current leakage를 방지하기 위해 high-Z 입력으로 설정되어야 한다. 표4에 의하면 GPIO208이 IO14의 풀업저항을 활성화 시키는데 사용된다.
  6. 표5에 의하면 TRI_STATE_ALL 신호는 GPIO214에 의해 제어된다. 

# echo 200 > /sys/class/gpio/export 
# echo 232 > /sys/class/gpio/export 
# echo 208 > /sys/class/gpio/export 
# echo 214 > /sys/class/gpio/export 
# echo low > /sys/class/gpio/gpio214/direction 
# echo high > /sys/class/gpio/gpio200/direction 
# echo low > /sys/class/gpio/gpio232/direction 
# echo in > /sys/class/gpio/gpio208/direction 
# echo high > /sys/class/gpio/gpio214/direction



설정이 끝나면 이제 IO14를 ADC input으로 사용하면 된다.

# cat /sys/bus/iio/devices/iio:device1/in_voltage0_raw  


예제6: IO18/IO19를 I2C로 설정


  1. 쉴드의 핀 번호는 IO18과 IO19이다. 각각의 GPIO 번호는 28과 27이 된다.
  2. 필요한 기능은 I2C이다. 표1에 의하면 이 쉴드핀들에서 사용할 수 있는 다른 기능들은 GPIO, ADC가 있다.
  3. 표3에 의하면 GPIO/I2C를 선택하기 위해 GPIO204는 0으로 설정되어야만 하고, IO18에 I2C를 선택하기 위해서는 GPIO28 pin mux가 'mode1'으로 설정되어야만 한다.
  4. 표3에 의하면 GPIO/I2C를 선택하기 위해 GPIO205는 0으로 설정되어야만 하고, IO19에 I2C를 선택하기 위해서는 GPIO27 pin mux가 'mode1'으로 설정되어야만 한다.
  5. GPIO14와 GPIO165도 I2C에 연결되어 있기 때문에 GPIO18/19에서 I2C를 사용하는 경우 이 핀들은 high-Z 입력으로 설정해 이 핀들이 I2C 버스의 신호를 드라이브하는걸 방지해야만 한다.
  6. 표4에 의하면 GPIO14의 output direction을 비활성화 시키기 위해 GPIO236은 0으로 설정되어야만 한다. 그리고 GPIO165의 output direction을 비활성화 시키기 위해 GPIO237은 0으로 설정되어야만 한다.
  7. 표4에 의하면 GPIO212와 213은 각각 IO18과 IO19의 풀업저항을 비활성화 시키기 위해 high-Z 입력으로 설정되어야만 한다.
  8. 표5에 의하면 TRI_STATE_ALL 신호는 GPIO214에 의해 제어된다. 

# echo 28 > /sys/class/gpio/export 
# echo 27 > /sys/class/gpio/export 
# echo 204 > /sys/class/gpio/export 
# echo 205 > /sys/class/gpio/export 
# echo 236 > /sys/class/gpio/export 
# echo 237 > /sys/class/gpio/export 
# echo 14 > /sys/class/gpio/export 
# echo 165 > /sys/class/gpio/export 
# echo 212 > /sys/class/gpio/export 
# echo 213 > /sys/class/gpio/export 
# echo 214 > /sys/class/gpio/export 
# echo low > /sys/class/gpio/gpio214/direction 
# echo low > /sys/class/gpio/gpio204/direction 
# echo low > /sys/class/gpio/gpio205/direction 
# echo in > /sys/class/gpio/gpio14/direction 
# echo in > /sys/class/gpio/gpio165/direction 
# echo low > /sys/class/gpio/gpio236/direction 
# echo low > /sys/class/gpio/gpio237/direction 
# echo in > /sys/class/gpio/gpio212/direction 
# echo in > /sys/class/gpio/gpio213/direction 
# echo mode1 > /sys/kernel/debug/gpio_debug/gpio28/current_pinmux 
# echo mode1 > /sys/kernel/debug/gpio_debug/gpio27/current_pinmux 
# echo high > /sys/class/gpio/gpio214/direction

이제 IO18과 IO19를 사용해 I2C 통신을 할 수 있다.


예제7: IO10~IO13을 SPI로 설정



  1. 쉴드의 핀 번호는 IO10~IO13이다. 각각의 GPIO 번호는 111, 115, 114, 109가 된다.
  2. 필요한 기능은 SPI이다. 표1에 의하면 이 쉴드핀들에서 사용할 수 있는 다른 기능들은 GPIO, PWM이 있다.
  3. 표3에 의하면 GPIO/SPI를 선택하기 위해 GPIO263은 1로 설정되어야만 하고, SPI를 선택하기 위해 GPIO240은 1로, IO10에 SPI를 선택하기 위해서는 GPIO111 pin mux가 'mode1'으로 설정되어야만 한다.
  4. 표3에 의하면 GPIO/SPI를 선택하기 위해 GPIO262는 1로 설정되어야만 하고, SPI를 선택하기 위해 GPIO241은 1로, IO11에 SPI를 선택하기 위해서는 GPIO115 pin mux가 'mode1'으로 설정되어야만 한다.
  5. 표3에 의하면 SPI를 선택하기 위해 GPIO242는 1로, IO12에 SPI를 선택하기 위해서는 GPIO114 pin mux가 'mode1'으로 설정되어야만 한다.
  6. 표3에 의하면 SPI를 선택하기 위해 GPIO243은 1로, IO13에 SPI를 선택하기 위해서는 GPIO109 pin mux가 'mode1'으로 설정되어야만 한다.
  7. 표4에 의하면 IO10의 output direction을 활성화 히기 위해 GPIO258은 1로, IO11의 output direction을 활성화 히기 위해 GPIO259는 1로, IO12의 output direction을 비활성화 히기 위해 GPIO260은 0으로, IO13의 output direction을 활성화 히기 위해 GPIO261은 1로 설정되어야만 한다.
  8. 표4에 의하면 GPIO226~229는 IO10~IO13의 풀업저항을 비활성화 시키기 위해 high-Z 입력으로 설정되어야만 한다.
  9. 표5에 의하면 TRI_STATE_ALL 신호는 GPIO214에 의해 제어된다. 

# echo 111 > /sys/class/gpio/expor
# echo 115 > /sys/class/gpio/export 
# echo 114 > /sys/class/gpio/export 
# echo 109 > /sys/class/gpio/export 
# echo 263 > /sys/class/gpio/export 
# echo 240 > /sys/class/gpio/export 
# echo 262 > /sys/class/gpio/export 
# echo 241 > /sys/class/gpio/export 
# echo 242 > /sys/class/gpio/export 
# echo 243 > /sys/class/gpio/export 
# echo 258 > /sys/class/gpio/export 
# echo 259 > /sys/class/gpio/export 
# echo 260 > /sys/class/gpio/export 
# echo 261 > /sys/class/gpio/export 
# echo 226 > /sys/class/gpio/export 
# echo 227 > /sys/class/gpio/export 
# echo 228 > /sys/class/gpio/export 
# echo 229 > /sys/class/gpio/export 
# echo 214 > /sys/class/gpio/export 
# echo low > /sys/class/gpio/gpio214/direction 
# echo high > /sys/class/gpio/gpio263/direction 
# echo high > /sys/class/gpio/gpio240/direction 
# echo high > /sys/class/gpio/gpio262/direction 
# echo high > /sys/class/gpio/gpio241/direction 
# echo high > /sys/class/gpio/gpio242/direction 
# echo high > /sys/class/gpio/gpio243/direction 
# echo high > /sys/class/gpio/gpio258/direction 
# echo high > /sys/class/gpio/gpio259/direction 
# echo low > /sys/class/gpio/gpio260/direction 
# echo high > /sys/class/gpio/gpio261/direction 
# echo in > /sys/class/gpio/gpio226/direction 
# echo in > /sys/class/gpio/gpio227/direction 
# echo in > /sys/class/gpio/gpio228/direction 
# echo in > /sys/class/gpio/gpio229/direction 
# echo mode1 > /sys/kernel/debug/gpio_debug/gpio111/current_pinmux 
# echo mode1 > /sys/kernel/debug/gpio_debug/gpio115/current_pinmux 
# echo mode1 > /sys/kernel/debug/gpio_debug/gpio114/current_pinmux 
# echo mode1 > /sys/kernel/debug/gpio_debug/gpio109/current_pinmux 
# echo high > /sys/class/gpio/gpio214/direction


원문은 http://www.emutexlabs.com/project/215-intel-edison-gpio-pin-multiplexing-guide 에서 볼 수 있음.