출처 : http://blog.aiui.com/13
이번 글에서는 BBB에서 GPIO를 다루는 방법을 정리해 두려고 합니다.
BBB에서 GPIO를 다루는 방법은 여러가지가 있으나 본 글에서는 디바이스 트리 오버레이와 sys 가상 디렉토리를 이용해 원하는 핀을 GPIO용으로 설정하고 테스트 하는 가장 기본적인 방법을 설명합니다.
이 글의 내용들은 제가 완전히 이해하고 자신있게 강좌의 개념으로 정리했다기 보다는 '이렇게 사용해 봤습니다' 라는 정도의 수준이고, 제 자신의 정리로써의 의미가 더 강하므로 그저 참고만 하시기 바랍니다.
이 글을 보시려는 대부분의 분들이 GPIO에 대해 잘 아시겠으나 혹여라도 생소한 분들을 위해 간단하게만 언급을 하면, 설정에 따라 입력/출력으로 사용할 수 있도록 구성된 IO를 말합니다. 그리고 출력의 경우는 마지막 값을 계속 유지(latch)하고 입력으로 설정하는 경우는 밖으로 부터 주어진 값을 그대로 받아들이기 위해 하이임피던스 상태가 된다고 합니다.
모든 GPIO가 만족하는 것인지는 모르겠으나, BBB의 경우 게다가 각 IO에 Pullup/Pulldown의 종류와 사용 여부도 설정할 수 있습니다.
한마디로 말해서 외부의 센서에서 값을 읽거나 장치를 제어하기 위해 다목적으로 설계된 IO를 말합니다.
좀 더 쉽고 정확한 설명을 위해 참고자료에 링크를 추가했습니다.
GPIO의 개념은 차이가 있을 수 없겠으나, BBB에서는 한 가지 언급하고 넘어가야 하는 문제가 있습니다.
BBB의 보드 위에는 세로로 좌우에 46핀 구성의 확장용 핀 헤더 들이 있습니다. 이 헤더들을 보통 P8(우측), P9(좌측)라고 부릅니다. 각 핀은 설정에 따라 8가지 기능을 가지는 구조입니다. 모드0 부터 모드7까지 8가지 모드에 따라 그 기능이 다릅니다. 모든 핀이 GPIO에 사용될 수 있는 것은 아니며 가능한 핀들의 경우도 모드7에서 GPIO로 사용할 수 있습니다. 각 핀이 기본으로 어떤 모드로 설정되어 있는지는 모르겠으나 원하는 핀을 GPIO로 사용하려면 해당 핀을 모드7로 변경해 주어야 합니다.
다음 표는 모드7로 설정했을 때의 P8 헤더의 핀 기능 중 일부입니다.
P8 헤더Mode7 | # | Offset | Name | Pin | Pin | Name | Offset | # | Mode7 |
---|
| | | DGND | 1 | 2 | DGND | | | |
gpio1[6] | 6 | 0x018 | GPIO1_6 | 3 | 4 | GPIO1_7 | 0x01c | 7 | gpio1[7] |
gpio1[2] | 2 | 0x008 | GPIO1_2 | 5 | 6 | GPIO1_3 | 0x00c | 3 | gpio1[3] |
gpio2[2] | 66 | 0x090 | TIMER4 | 7 | 8 | TIMER7 | 0x094 | 67 | gpio2[3] |
gpio2[5] | 69 | 0x09c | TIMER5 | 9 | 10 | TIMER6 | 0x098 | 68 | gpio2[4] |
gpio1[13] | 45 | 0x034 | GPIO1_13 | 11 | 12 | GPIO1_12 | 0x030 | 44 | gpio1[12] |
gpio0[23] | 23 | 0x024 | EHRPWM2B | 13 | 14 | GPIO0_26 | 0x028 | 26 | gpio0[26] |
gpio1[15] | 47 | 0x03c | GPIO1_15 | 15 | 16 | GPIO1_14 | 0x038 | 46 | gpio1[14] |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
(완전한 테이블은 글 마지막에 [부록]을 참고 하세요)
이 글에서는, 위의 표에서 초록색으로 표시한 11번 핀을 사용해서 GPIO 테스트를 합니다.
그런데 최근의 리눅스 커널에서 그 '모드 변경'이라는 일을 하기가 간단하지 않아졌습니다. 커널 버전 2.6에선가 부터 등장한 디바이스 트리(Device Tree)라는 개념 때문입니다. 원하는 핀의 모드 변경을 하려면 디바이스 트리 오버레이(Device Tree Overlay)라는 작업을 해야 합니다. 그래서 이 글에서는 디바이스 트리의 개념과 다루는 방법도 간략하게나마 설명합니다.
최근의 소형 하드웨어 플랫폼들이 고성능화 되면서 I/O에 3.3V의 전압 레벨을 사용하는 방향으로 변하고 있는 것 같습니다. 아마도 메인 칩의 저전력 설계로 동작 전압이 낮아진 것이 이유라고 생각합니다. BBB의 경우도 3.3V I/O 신호 레벨을 사용합니다. GPIO로 제어하는 장치가 3.3V 로 동작 가능하면 상관 없지만 5V를 필요로 하면 중간에 레벨 컨버터(3.3V <=> 5V 변환기)를 사용해야 합니다.
제가 테스트 한 경우도 5V 장치라 레벨 컨버터를 사용했습니다. 저는 Rorze 사의 2상 스테퍼 모터 드라이버를 사용해야 했기에 불가피한 경우가 되겠습니다.
몇 개월 전에 구입해 두었던 'NS-LS4' 라는 모델명의 4채널 양방향 레벨 컨버터 모듈을 이용했습니다.
잘못된 전압 레벨을 사용하는 경우, 출력의 경우엔 장치가 제대로 동작하지 않는 정도로 끝날 수 있으나, 입력의 경우는 BBB의 메인 칩이 손상될 수도 있다는 경고가 있으므로 절대 주의해야 합니다.
내용이 방대해서 완전한 이해에 이르기까지는 상당한 시간이 필요하고 이런 단편적인 글 하나로 불가능할지도 모르겠습니다.
따라서 여기서는 대략적인 개념과 다음 진행을 위해 필요한 구조만 설명하고 넘어 가려 합니다.
공통적으로 하고있는 설명들을 토대로 정리해 보면 다양한 장치들에 대한 정보을 명시하기 위한 자료 구조라고 합니다.
분위기를 보아하니 임베디드 장치들이 늘어나면서 각 장치들을 운영체제에서 지원하도록 하기 위한 드라이버 제작이 점점 부담스러워졌고 이를 해결하기 위한 방안으로 자연스레 채택을 하게 된 것 같습니다.
예전에는 특정 장치를 지원하기 위한 드라이버를 각 운영체제에 맞게 제작해서 장치와 같이 배포하는 구조였다면, 디바이스 트리 구조에서는 프로그램 코드를 제공하지 않고 장치를 잘 설명하는 자료 구조를 작성해서 이를 지원(이해)하는 운영체제에 전달해 운영체제 기동 시 이를 읽어 설정하는 구조로 바꾸려는 것으로 이해했습니다.
결국 운영체제에 범용적인 코드를 작성해 놓고 장치의 정보에 대해 일반화를 잘해서 체계화 된 자료 구조를 전달하는 것으로 보입니다.
먼저, 앞서 말씀드린 것 처럼 운영체제가 장치를 지원하도록 하기 위해 텍스트 문서(.dts)를 사용해 장치에 대한 정보를 기술합니다.
그리고 이 파일을 디바이스 트리 컴파일러(dtc)라고 부르는 툴로 컴파일을 해서 바이너리 파일(.dtb)로 변환합니다.
그렇게 준비된 바이너리 파일을 운영체제에 전달합니다.
스크립트 작성(.dts) => 컴파일(dtc) => 바이너리 파일(.dtb)
.dtb 파일을 운영체제에 알려주면 부팅 시 적용하는 개념이지만, Linux에서는 .dtbo 파일로 만들어 /lib/firmware 디렉토리에 모아 놓고 운영중에 아무 때나 적용 및 해제가 가능한 구조입니다.
자세한 방법은 아래 설명합니다.
디바이스 트리는 장치를 설명하는 자료구조라고 했습니다. 실제로 어떻게 설명을 하는 것일까요?
'디바이스 트리 스크립트(Device Tree Script)' 또는 '디바이스 트리 소스(Device Tree Source)' 라고 일컫는 텍스트 형식의 문서에 정해진 문법으로 기술합니다. 일반적으로 .dts 라는 확장자의 파일로 저장합니다.
문법 구조나 명칭들이 상당히 방대해서 규격을 다 봐야 알겠지만, 우선은 BBB의 GPIO를 다루는 데 필수적인 내용만으로 작성된 DTS를 예로 보입니다.
p8_11_out.dts |
---|
/dts-v1/;
/plugin/;
/{
compatible = "ti,beaglebone", "ti,beaglebone-black";
part-number = "p8_11_out";
version = "00A0";
fragment@0 {
target = <&am33xx_pinmux>;
__overlay__ {
pinctrl_test: p8_11_pins {
pinctrl-single,pins = <
0x034 0x37
>;
};
};
};
fragment@1 {
target = <&ocp>;
__overlay__ {
test_helper: helper {
compatible = "bone-pinmux-helper";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_test>;
status = "okay";
};
};
};
};
|
.dts 문법에 대해서는 본인도 잘 모르므로 질문하셔도 답변 못 드릴 겁니다. 보다 깊은 내용은 마지막 부분의 참고자료를 보시기 바랍니다.ㅠㅠ
다만, 중요한 내용은 중간 부분의 0x034 0x37 가 되겠습니다.
Linux kernel 내부에서 am33xx_pinmux가 0x44e10800 값을 가지기 때문에 P8_11을 지정하기 위해 그 offset 주소인 0x034를 사용해야 하며,
저 두 숫자가 핀헤더 P8의 11번 핀을 GPIO로 사용하겠다라는 의미를 가지고 있습니다.
컴파일은 super user가 아니어도 되긴 합니다만, 나머지 과정이 모두 권한을 요구하므로 미리 super user로 전환해 둡니다.
슈퍼 유저 전환 |
---|
ubuntu@arm:~$ sudo su
root@arm:/home/ubuntu#
|
|
---|
root@arm:/home/ubuntu# wget -c https://raw.github.com/RobertCNelson/tools/master/pkgs/dtc.sh
root@arm:/home/ubuntu# chmod +x dtc.sh
root@arm:/home/ubuntu# ./dtc.sh
|
주의 |
단순히 apt-get install device-tree-compiler 로 설치를 해도 dtc 가 준비는 됩니다. 이 경우는 일반 ubuntu 버전이 설치되어 BBB용 dts 를 컴파일 할 때 오류가 납니다. 따라서 위의 방법으로 설치를 하셔야 합니다.
|
.dts 를 컴파일해서 .dtbo로 만드는 과정은 다음과 같습니다.
컴파일 |
---|
root@arm:/home/ubuntu# dtc -I dts -O dtb -o p8_11_out-00A0.dtbo -@ p8_11_out.dts
|
간단하니 별다른 설명은 필요 없을 것 같지만, 위 예를 보면 .dts와 .dtbo 파일의 이름이 다르게 지정되어 있습니다.
"-00A0" 을 더 붙여서 결과 파일을 만듭니다만, 버전 관리 차원에서 하는 것으로 이해하면 되겠습니다.
주의: .dtbo 파일에 버전(00A0)을 붙일 때 반드시 '-'로 붙여야 합니다. '_' 같은 글자로 붙이면 슬롯에 올릴 때 오류 납니다.
컴파일된 .dtbo 는 운영체제의 특별한 위치로 복사해 줍니다.
DTB 복사 |
---|
root@arm:/home/ubuntu# cp p8_11_out-00A0.dtbo /lib/firmware
|
자, 그럼 이제 준비는 끝났습니다. 앞으로는 다음 단계부터 진행해 주면 됩니다.
준비된 .dtbo 를 적용시키는 과정을 디바이스 트리 오버레이(Device Tree Overlay) 라고 하는 데, 이름에서 알 수 있듯이 커널 내부의 기존 디바이스 트리 위에 새로운 .dtbo를 중첩시켜서 새로운 하드웨어를 추가하거나 기능을 변경하는 것이 아닌가 싶습니다. 정확한 메커니즘은 커널 내부를 확인해야 알 것 같습니다. 여기서는 동작하는 데 의의를 두고 그냥 넘어갑니다.
아무튼, 이 동작을 마치 케이프를 올렸다 내렸다 하는 것에 대응해서 추상화 해 놓았더군요. 위에서 만든 p8_11 핀을 출력용 gpio 핀으로 동작시키는 가상 케이프를 BBB에 장착 시키는 것 같은 개념입니다.
케이프란? |
케이프는 비글본 시리즈 보드에 추가로 장착해서 원하는 특정 기능을 하는 보드를 말합니다. 아두이노의 쉴드에 대응한다고 볼 수 있습니다. 아직은 아두이노 만큼 풍부한 기능의 케이프 들이 있지는 않지만 점점 새로운 케이프들이 개발되고 있더군요.
|
준비된 .dtbo 파일을 운영체제에 적용하도록 해 줍니다.
슬롯에 장착 |
---|
root@arm:/home/ubuntu# echo p8_11_out > /sys/devices/bone_capemgr.*/slots
|
리눅스에서는 /proc 과 마찬가지로 /sys 뒤의 파일들은 디스크 상의 실제 파일이 아니라 커널 내부의 자료 구조를 파일로 가상화 한 것으로 보입니다. 그 중 /sys/devices/bone_capemgr.*/slots 부분이 이름처럼 케이프 매니저의 슬롯 개념으로 보이는데, 물리적으로 케이프를 장착시켜 주는 것처럼 .dtbo 파일을 비슷하게 다룰 수 있게 되어 있습니다.
위의 'echo' 명령 1줄은 'p8_11_out 이란 가상 케이프를 BBB에 장착하라'라는 의미로 이해하면 될 듯 합니다.
잘 장착(?) 되었는지 확인하는 방법은
슬롯 상황 확인 |
---|
root@arm:/home/ubuntu# cat /sys/devices/bone_capemgr.*/slots
0: 54:PF---
1: 55:PF---
2: 56:PF---
3: 57:PF---
4: ff:P-O-L Bone-LT-eMMC-2G,00A0,Texas Instrument,BB-BONE-EMMC-2G
5: ff:P-O-L Bone-Black-HDMI,00A0,Texas Instrument,BB-BONELT-HDMI
6: ff:P-O-L Override Board Name,00A0,Override Manuf,p8_11_out
|
마지막 줄에 보이는 것처럼 슬롯 6에 p8_11_out 이 장착되어 있습니다.
여기까지 하면 P8_11 을 접근할 수 있는 상태가 됩니다.
그러면 실제로 P8_11 을 설정해 줘야 GPIO로 다룰 수 있습니다.
현재의 GPIO 핀 설정이 어떻게 되어 있는 지 확인을 해 봅니다.
GPIO 상황 확인 |
---|
root@arm:/home/ubuntu# ls /sys/class/gpio/
export gpiochip0 gpiochip32 gpiochip64 gpiochip96 unexport
|
위에 보시는 것처럼 기존에 사용하고 있는 핀 목록이 나타납니다.
각자 사용하시는 상황에 따라 조금씩 달라질 수 있을 겁니다.
위에서 export 와 unexport 는 특별한 의미가 있는 파일입니다. 바로 아래 설명이 나옵니다.
P8_11핀을 GPIO로 사용하겠다고 설정하려면 다음과 같이 합니다.
핀 활성화 |
---|
root@arm:/home/ubuntu# echo 45 > /sys/class/gpio/export
|
위에서 언급한 'export'라는 특별한 파일에 gpio번호를 출력해 주면 됩니다.
GPIO 상황 확인 |
---|
root@arm:/home/ubuntu# ls /sys/class/gpio/
export gpio45 gpiochip0 gpiochip32 gpiochip64 gpiochip96 unexport
|
자 위의 결과처럼 'gpio45' 가 추가되어 있음을 확인할 수 있습니다. gpio45는 파일이 아니라 폴더처럼 동작합니다.
그 내부에는 다음과 같은 파일들이 있습니다.
GPIO 폴더 내부 |
---|
root@arm:/home/ubuntu# ls /sys/class/gpio/gpio45/
active_low direction edge power subsystem uevent value
|
역시 실제 파일은 아니며, 저 중에서 'direction'과 'value'를 사용해서 출력으로의 설정과 실제 데이터 출력을 하게 됩니다.
gpio의 입/출력 설정은 gpio45/direction 파일에 'out' 을 출력해 주면 됩니다.
핀의 출력 설정 |
---|
root@arm:/home/ubuntu# echo out > /sys/class/gpio/gpio45/direction
|
이제 gpio45를 출력용으로 사용할 수 있게 준비되었습니다.
핀에 출력 |
---|
root@arm:/home/ubuntu# echo 1 > /sys/class/gpio/gpio45/value
|
사용이 끝나면 gpio를 다음과 같이 비활성화 해 줄 수 있습니다.
gpio #45를 비활성하는 예 |
---|
root@arm:/home/ubuntu# echo 45 > /sys/class/gpio/unexport
|
슬롯에서 제거하기 위해서는
슬롯에서 제거하는 예 |
---|
$ echo -6 > /sys/devices/bone_capemgr.*/slots
|
'echo' 명령으로 '-'가 붙은 슬롯 번호를 슬롯에 보내면 됩니다.
예에서는 슬롯 번호가 6이지만 실제 슬롯 번호는 cat /sys/devices/bone_capemgr.*/slots 명령을 사용해서 확인해야 합니다.
이상으로 gpio 사용 설명을 정리합니다만, 최대한 짧게 설명한다고 했는데도 장황해진 것 같아 다시 한번 요약합니다.
구분 | 명령 예) |
---|
슬롯 장착 | echo p8_11_out > /sys/devices/bone_capemgr.*/slots |
슬롯 상황 확인 | cat /sys/devices/bone_capemgr.*/slots |
핀 활성화 | echo 45 > /sys/class/gpio/export |
핀 상황 확인 | ls /sys/class/gpio/ |
핀 출력 설정 | echo out > /sys/class/gpio/gpio45/direction |
데이터(High) 출력 | echo 1 > /sys/class/gpio/gpio45/value |
핀 비활성화 | echo 45 > /sys/class/gpio/unexport |
슬롯 제거 | echo -6 > /sys/devices/bone_capemgr.*/slots
|
다음 사진에 이 글에서 사용하는 핀들을 표시해 봤습니다.
그리고 다음 사진에서는 레벨 컨버터(NS-LS4)를 사용하기 위한 선 연결을 보였습니다.
위 사진의 우측 하단의 5V Circuit 에 원하는 5V 회로를 구성해 주면 됩니다.
그럼 실제 테스트를 하기 위해 선 연결한 모습을 보시죠.
BBB와 레벨 컨버터 부분만 확대한 모습입니다.
워낙 간단한 것이라 별 달리 설명할 만한 건 없네요.
(가능하면 위의 그림과 같은 색의 점퍼 선을 사용하려고 노력했습니다.)
자, 그리고는 테스트를 위한 프로그램을 간단하게 C언어로 작성했습니다.
다음 프로그램은 단순히 스테퍼 모터를 1회전(Revolution, 360도) 시키는 코드가 되겠습니다.
for문에서 200*50 번 반복하면서 gpio45에 '1'과 '0'을 출력하는 것입니다.
200*50에서 200은 360도 회전하기 위한 모터 자체의 스텝 수 이고, 50은 마이크로스텝 설정 값 입니다.
c_stepper.c |
---|
#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(void)
{
int fd = open("/sys/class/gpio/gpio45/value", O_WRONLY, S_IWRITE);
if (fd>0) {
int i;
for (i=0; i<200*50; i++) {
write(fd, "1", 1);
write(fd, "0", 1);
}
close(fd);
}
return 0;
}
|
|
---|
root@arm:/home/ubuntu# gcc -o c_stepper c_stepper.c
root@arm:/home/ubuntu# ./c_stepper
root@arm:/home/ubuntu#
|
위 코드의 실행으로 모터가 회전하는 것을 확인 했으며, 테스트 자체는 워낙 단순한 것이라 동영상 같은 것이 의미가 없다고 판단하고 생략합니다.
사실 알고 나면 너무나 간단한 것일테지만, 제가 원하는 전체 과정이 일목 요연하게 정리된 정보를 찾을 수가 없었기에 나름 많은 곳을 방문해서 읽어보고 시행착오도 많았습니다.
저 스스로의 정리도 하고, 또 저와 같은 목적의 정보를 원하시는 분께 조금이라도 도움이 될까 싶어서 정리를 해 봤습니다만, 부족한 부분이 많을 것이라고 생각됩니다. 조금씩 더 제대로 알아가면서 수정 보완하려고 합니다.
이 글에서 설명한 테스트는 사실 문제가 있습니다. 전반적인 개념과 구조가 이렇다라는 것을 보이기 위해 이런 예를 들어 정리했지만, 실제로 스테퍼 모터를 제어하는 데 사용하기에는 부족한 점이 있다는 것이죠.
1) 효율적인 제어가 어렵다.
2) 실시간 제어를 만족 못할 수도 있다.
위와 같은 문제점을 해결하기 위해 다음 단계로 넘어가야 합니다. 스테퍼 모터의 핵심 제어를 메인 프로세서에서 하지 않고 AM335x 내부에 탑재된 PRU 라는 보조 프로세서(?) 를 사용해서 어셈블리로 제어하는 방법인 PRUSS 라는 기술을 사용해야 합니다. 이 기술을 사용하면 고효율과 실시간 처리 두 가지를 모두 얻을 수 있을 것 같습니다. 제가 여러 고성능 오픈 하드웨어 플랫폼을 찾다가 BBB를 본격적으로 보게 된 이유가 PRUSS 라는 기술 때문이었습니다.
언제가 될 지 모르겠으나 조만간 PRUSS 에 대해서도 정리를 해 볼 예정입니다.
P8 헤더Mode7 | # | Offset | Name | Pin | Pin | Name | Offset | # | Mode7 |
---|
| | | DGND | 1 | 2 | DGND | | | |
gpio1[6] | 6 | 0x018 | GPIO1_6 | 3 | 4 | GPIO1_7 | 0x01c | 7 | gpio1[7] |
gpio1[2] | 2 | 0x008 | GPIO1_2 | 5 | 6 | GPIO1_3 | 0x00c | 3 | gpio1[3] |
gpio2[2] | 66 | 0x090 | TIMER4 | 7 | 8 | TIMER7 | 0x094 | 67 | gpio2[3] |
gpio2[5] | 69 | 0x09c | TIMER5 | 9 | 10 | TIMER6 | 0x098 | 68 | gpio2[4] |
gpio1[13] | 45 | 0x034 | GPIO1_13 | 11 | 12 | GPIO1_12 | 0x030 | 44 | gpio1[12] |
gpio0[23] | 23 | 0x024 | EHRPWM2B | 13 | 14 | GPIO0_26 | 0x028 | 26 | gpio0[26] |
gpio1[15] | 47 | 0x03c | GPIO1_15 | 15 | 16 | GPIO1_14 | 0x038 | 46 | gpio1[14] |
gpio0[27] | 27 | 0x02c | GPIO0_27 | 17 | 18 | GPIO2_1 | 0x08c | 65 | gpio2[1] |
gpio0[22] | 22 | 0x020 | EHRPWM2A | 19 | 20 | GPIO2_31 | 0x084 | 63 | gpio1[31] |
gpio1[30] | 62 | 0x080 | GPIO1_30 | 21 | 22 | GPIO1_5 | 0x014 | 37 | gpio1[5] |
gpio1[4] | 36 | 0x010 | GPIO1_4 | 23 | 24 | GPIO1_1 | 0x004 | 33 | gpio1[1] |
gpio1[0] | 1 | 0x000 | GPIO1_0 | 25 | 26 | GPIO1_29 | 0x07c | 61 | gpio1[29] |
gpio2[22] | 86 | 0x0e0 | GPIO2_22 | 27 | 28 | GPIO2_24 | 0x0e8 | 88 | gpio2[24] |
gpio2[23] | 87 | 0x0e4 | GPIO2_23 | 29 | 30 | GPIO2_25 | 0x0ec | 89 | gpio2[25] |
gpio0[10] | 10 | 0x0d8 | UART5_CTSN | 31 | 32 | UART5_RTSN | 0x0dc | 11 | gpio0[11] |
gpio0[9] | 9 | 0x0d4 | UART4_RTSN | 33 | 34 | UART3_RTSN | 0x0cc | 81 | gpio2[17] |
gpio0[8] | 8 | 0x0d0 | UART4_CTSN | 35 | 36 | UART3_CTSN | 0x0c8 | 80 | gpio2[16] |
gpio2[14] | 78 | 0x0c0 | UART5_TXD | 37 | 38 | UART5_RXD | 0x0c4 | 79 | gpio2[15] |
gpio2[12] | 76 | 0x0b8 | GPIO2_12 | 39 | 40 | GPIO2_13 | 0x0bc | 77 | gpio2[13] |
gpio2[10] | 74 | 0x0b0 | GPIO2_10 | 41 | 42 | GPIO2_11 | 0x0b4 | 75 | gpio2[11] |
gpio2[8] | 72 | 0x0a8 | GPIO2_8 | 43 | 44 | GPIO2_9 | 0x0ac | 73 | gpio2[9] |
gpio2[6] | 70 | 0x0a0 | GPIO2_6 | 45 | 46 | GPIO2_7 | 0x0a4 | 71 | gpio2[7] |
P9 헤더Mode7 | # | Offset | Name | Pin | Pin | Name | Offset | # | Mode7 |
---|
| | | GND | 1 | 2 | GND | | | |
| | | DC_3.3V | 3 | 4 | DC_3.3V | | | |
| | | VDD_5V | 5 | 6 | VDD_5V | | | |
| | | SYS_5V | 7 | 8 | SYS_5V | | | |
| | | PWR_BUT | 9 | 10 | SYS_RSTn | | | |
gpio0[30] | 30 | 0x070 | UART4_RXD | 11 | 12 | GPIO1_28 | 0x078 | 60 | gpio1[28] |
gpio0[31] | 31 | 0x074 | UART4_TXD | 13 | 14 | EHRPWM1A | 0x048 | 50 | gpio1[18] |
gpio1[16] | 48 | 0x040 | GPIO1_16 | 15 | 16 | EHRPWM1B | 0x04c | 51 | gpio1[19] |
gpio0[5] | 5 | 0x15c | I2C1_SCL | 17 | 18 | I2C1_SDA | 0x158 | 4 | gpio0[4] |
gpio0[13] | 13 | 0x17c | I2C2_SCL | 19 | 20 | I2C2_SDA | 0x178 | 12 | gpio0[12] |
gpio0[3] | 3 | 0x154 | UART2_TXD | 21 | 22 | UART2_RXD | 0x150 | 2 | gpio0[2] |
gpio1[17] | 49 | 0x044 | GPIO1_17 | 23 | 24 | UART1_TXD | 0x184 | 15 | gpio0[15] |
gpio3[21] | 117 | 0x1ac | GPIO3_21 | 25 | 26 | UART1_RXD | 0x180 | 14 | gpio0[14] |
gpio3[19] | 115 | 0x1a4 | GPIO3_19 | 27 | 28 | SPI1_CS0 | 0x19c | 113 | gpio3[17] |
gpio3[15] | 111 | 0x194 | SPI1_D0 | 29 | 30 | SPI1_D1 | 0x198 | 112 | gpio3[16] |
gpio3[14] | 110 | 0x190 | SPI1_SCLK | 31 | 32 | VADC | | | |
| | | AIN4 | 33 | 34 | AGND | | | |
| | | AIN6 | 35 | 36 | AIN5 | | | |
| | | AIN2 | 37 | 38 | AIN3 | | | |
| | | AIN0 | 39 | 40 | AIN1 | | | |
gpio0[20] | 20 | 0x1b4 | CLKOUT2 | 41A | 42A | GPIO0_7 | 0x164 | 7 | gpio0[7] |
gpio3[20] | 116 | 0x1a8 | GPIO3_20 | 41B | 42B | GPIO3_18 | 0x1a0 | 114 | gpio3[18] |
| | | GND | 43 | 44 | GND | | | |
| | | GND | 45 | 46 | GND | | |