라즈베리 파이에는 디버그 콘솔용 또는 시리얼 통신을 위한 핀이 40핀 커넥터에 나와 있다.
위의 그림에서 처럼 8/10번 핀이 각각 TxD, RxD가 된다.
위의 사진과 같은 USB-to-Serial(TTL level) converter를 사용해 PC와 연결해서 시리얼 통신을 할 수 있다.
이렇게 연결해 주면 된다.
컴퓨터에서 시리얼 에뮬레이터를 실행하고 통신속도를 115200bps로 맞춰 준 다음 라즈베리 파이에 전원을 공급하면 시리얼 에뮬레이터 화면에 이런 내용들이 출력되게 된다.
그런데 라즈베리 파이 2까지는 아무 문제가 없었던 것이 라즈베리 파이 3를 동일하게 연결하면 위와 같은 내용이 나오지 않고 이상하게 깨진 글자가 나오게 된다.
저렇게 깨진 글자가 나오게 되는 이유는 통신 속도가 틀려서이다.
원인을 이해하기 위해 라즈베리 파이의 내부 구조를 살펴보겠다.
라즈베리 파이 1B/B+는 BCM2835, 2는 BCM2836 SoC를 사용하고 있는데 여기에는 각각 2개의 UART가 들어 있는데 UART0는 Full UART, UART1은 mini UART이다. 여기서 UART0는 /dev/ttyAMA0로 사용되고 UART1은 /dev/ttyS0로 사용된다.
위의 그림처럼 mini UART는 몇가지 제약이 있지만, 40핀 커넥터의 8/10번 핀은 full UART의 Tx/Rx로 연결되어 있으므로 아무 문제가 없다.
하지만 라즈베리 파이 3로 오면서 블루투스가 추가되는 바람에 문제가 복잡해졌다.
먼저 하드웨어 구조를 살펴 보자.
위의 사진이 라즈베리 파이 1/2의 구조이다. 시리얼 포트 핀이 UART0에 연결되어 있다.
라즈베리 파이 3로 오면서 무선랜/블루투스 기능 추가를 위해 Broadcom의 BCM43438 칩을 사용하고 있는데 무선랜 기능은 SDIO로 연결하지만 블루투스 기능은 UART0으로 연결을 하고 시리얼 포트 핀은 UART1에 연결되도록 구조가 변경되었다. 그러므로 그 동안 아무 문제 없이 시리얼 포트를 사용하던 프로그램이 라즈베리 파이 3로 오면서 블루투스를 사용하게 되면 제대로 동작을 할 수 없게 되어 버린 것이다.
또한 코드의 /dev/ttyAMA0를 /dev/ttyS0로 변경한다고 해도 문제가 남는다.
UART1의 통신 속도는 다음 공식에 의해 결정된다.
라즈베리 파이 3의 경우 부팅시의 코어 동작 주파수는 400MHz이고 디폴트 baud rate는 115200 bps이다. 즉 위의 공식은...
이 된다. 여기서 baudRateReg는 부팅시에 코어 동작 주파수에 의해 계산된다.
그런데 전력소비를 줄이기 위해 frequency scaling 기능을 사용하고 있기 때문에 시스템 로드가 작은 경우 코어 동작 주파수를 250MHz로 줄일 수 있다. baudRateReg 값은 고정되어 있는데 시스템 클럭 주파수가 변동되기 때문에 결과적으로 baudrate도 따라서 바뀌게 되어 버린다.
즉 코어가 400MHz로 동작할 때는 115200bps로 동작하던 시리얼 포트가 코어 동작 속도가 250MHz가 되면 시리얼 포트 통신속도가 72004 bps로 바뀌어 버리기 때문에 위쪽의 그림처럼 깨진 글자가 나오게 되는 것이다.
그러므로 headless system (모니터 없이 사용하는 경우)에서 시리얼 디버그 콘솔을 사용하거나, UART를 사용하는 RPi shield(GPS/GSM, RS232 등등)를 사용하거나, 시리얼 포트로 다른 프로세서와 통신을 하는 경우 등에는 치명적인 문제가 될 수 있다.
이 문제의 해결책으로는 먼저 부팅시 코어 동작 속도를 고정해 버리는 것이다.
예전 펌웨어를 사용하는 경우
/etc/config.txt 파일에 "
core_freq=250" 또는 "
force_turbo=1"을 추가해 주는 것이다. 이렇게 하면 코어 동작 속도를 각각 최소 또는 최대(400MHz)로 고정시켜 버리게 된다. 최소로 고정시키면 RPi3의 성능에 영향을 미치게 되고, 최대로 고정시키면 방열대책을 신경 써 줘야 한다. 하지만 최대로 고정시켰다 하더라도 전압이 떨어지거나 코어 온도가 매우 높게 올라가면 250MHz로 쓰로틀링 될 수 있다는걸 주의해야 한다.
새 펌웨어의 경우에는
/boot/config.txt 파일에 "
enable_uart=1"을 추가해주면 된다. 앞으로 모든 RPi distribution은 이 옵션을 다 지원하게 될 것이다. 이는 "
core_freq=250"과 유사하지만 좀 더 명확한 의도를 표현한다. 이 옵션을 지원하는 distros인 경우 "
enable_uart=1"이 활성화 되지 않으면 디버그 콘솔을 비활성화 시켜 놓는다. "
enable_uart=1"에 대해 Raspberry Pi Foundation의 엔지니어 Phil Elwell이 상세히 설명 해 놓았다.
https://github.com/raspberrypi/firmware/issues/553#issuecomment-199486644
두번째 방법으로는 디바이스 트리 오버레이로 40핀 헤더의 핀 매핑을 바꿔 Full UART를 사용하게 해 주는 것이다.
원래는 위의 사진에서 왼쪽같이 되어 있는데 오른쪽같이 되도록 변경하는 것이다. 이를 위해서는 '
/boot/config.txt'에 '
dtoverlay=pi3-disable-bt'를 추가해 주거나, '
/boot/config.txt'에 '
dtoverlay=pi3-miniuart-bt'를 추가해 주면 된다.
'
dtoverlay=pi3-disable-bt'를 추가해주면 UART1을 사용하지 않는걸로 해서 블루투스를 비활성화 시킨다. 이 경우 라즈비안에서는 "
sudo systemctl disable hciuart" 명령을 추가로 실행해 줘야 한다.
'
dtoverlay=pi3-miniuart-bt'를 추가해 주는 경우는 블루투스가 mini-UART를 사용한다. 이를 위해 '
/boot/config.txt'에 '
core_freq=250' 또는 '
force_turbo=1'이 들어가 있어야 한다. 또한 라즈비안의 경우 '
/lib/systemd/system/hciuart.service'의 ttyAMA0를 ttyS0로 수정해 줘야 한다. 그리고 이 때는 블루투스의 성능에 제한이 생길 수 있기 때문에 저속 BLE만 실질적으로 사용하는데 문제가 없다.
위의 어떤 옵션을 사용하건 '
enable_uart=0'을 넣어주지 않는 한 시리얼 콘솔은 활성화 되어 있다.
즉 위의 설명을 요약하자면 다음과 같다.
* 시리얼 콘솔과 일반적인 블루투스를 사용하고 싶은 경우 (/boot/config.txt 파일을 수정)
- 코어 주파수를 고정
- "
core_freq=250" 또는 "
force_turbo=1"을 추가 (old 펌웨어인 경우)
- "
enable_uart=1" (만일 동작 주파수를 고속으로 고정하고 싶으면 "force_turbo=1"을 추가)
* 고속 시리얼을 사용하고 싶은 경우
- UART0와 UART1 핀을 교체
- 블루투스를 사용할 수 없는 경우
+ "
dtoverlay=pi3-disable-bt"
+ (라즈비안) "
sudo systemctl disable hciuart"를 실행
- 저속 블루투스 클래식 또는 BLE
+ "
dtoverlay=pi3-miniuart-bt" 와 "
core_freq=250" 또는 "
force_turbo=1"중의 하나를 추가
+ (라즈비안) "
/lib/systemd/system/hciuart.service" 파일의 "
ttyAMA0"를 "
ttyS0"로 수정
- 디버그 콘솔을 비활성화 시키려면 "
disable_uart=0" 추가
* Mini UART를 사용하려면 항상 코어 주파수를 고정할 필요가 있음