CLIEN

본문 바로가기 메뉴 바로가기 보기설정 테마설정
톺아보기 공감글
커뮤니티 커뮤니티전체 C 모두의광장 F 모두의공원 I 사진게시판 Q 아무거나질문 D 정보와자료 N 새로운소식 T 유용한사이트 P 자료실 E 강좌/사용기 L 팁과강좌 U 사용기 · 체험단사용기 W 사고팔고 J 알뜰구매 S 회원중고장터 B 직접홍보 · 보험상담실 H 클리앙홈
소모임 소모임전체 ·굴러간당 ·주식한당 ·아이포니앙 ·MaClien ·일본산당 ·방탄소년당 ·개발한당 ·자전거당 ·안드로메당 ·이륜차당 ·소셜게임한당 ·육아당 ·AI당 ·나스당 ·소시당 ·가상화폐당 ·디아블로당 ·골프당 ·클다방 ·야구당 ·걸그룹당 ·젬워한당 ·리눅서당 ·영화본당 ·사과시계당 ·캠핑간당 ·패셔니앙 ·맛있겠당 ·IoT당 ·키보드당 ·라즈베리파이당 ·3D메이킹 ·X세대당 ·ADHD당 ·AI그림당 ·날아간당 ·배드민턴당 ·농구당 ·블랙베리당 ·곰돌이당 ·비어있당 ·FM당구당 ·블록체인당 ·보드게임당 ·활자중독당 ·볼링친당 ·냐옹이당 ·문명하셨당 ·클래시앙 ·콘솔한당 ·요리한당 ·쿠키런당 ·대구당 ·DANGER당 ·뚝딱뚝당 ·개판이당 ·동숲한당 ·날아올랑 ·전기자전거당 ·e북본당 ·갖고다닌당 ·이브한당 ·물고기당 ·도시어부당 ·FM한당 ·포뮬러당 ·안경쓴당 ·차턴당 ·총쏜당 ·땀흘린당 ·하스스톤한당 ·히어로즈한당 ·인스타한당 ·KARA당 ·꼬들한당 ·덕질한당 ·어학당 ·가죽당 ·레고당 ·LOLien ·Mabinogien ·임시소모임 ·미드당 ·밀리터리당 ·땅판당 ·헌팅한당 ·오른당 ·MTG한당 ·소리당 ·노키앙 ·적는당 ·방송한당 ·바다건너당 ·PC튜닝한당 ·찰칵찍당 ·그림그린당 ·소풍간당 ·심는당 ·패스오브엑자일당 ·품앱이당 ·리듬탄당 ·노젓는당 ·달린당 ·Sea마당 ·SimSim하당 ·심야식당 ·윈태블릿당 ·미끄러진당 ·축구당 ·나혼자산당 ·스타한당 ·스팀한당 ·파도탄당 ·퐁당퐁당 ·테니스친당 ·테스트당 ·빨콩이당 ·공대시계당 ·여행을떠난당 ·터치패드당 ·트윗당 ·창업한당 ·VR당 ·시계찬당 ·WebOs당 ·위스키당 ·와인마신당 ·WOW당 ·윈폰이당
임시소모임
고객지원
  • 게시물 삭제 요청
  • 불법촬영물등 신고
  • 쪽지 신고
  • 닉네임 신고
  • 제보 및 기타 제안
© CLIEN.NET
공지[점검] 잠시후 서비스 점검을 위해 약 30분간 접속이 차단됩니다. (금일 18:15 ~ 18:45)

팁과강좌

취미/음식 PCB떠서 키보드 만들어 보기 (펌웨어) (6) 3

11
2021-09-06 16:45:01 73.♡.253.152
skqlffpfk

1편 : https://www.clien.net/service/board/lecture/16405159?od=T31&po=0&category=0&groupCd=CLIEN
2편 : https://www.clien.net/service/board/lecture/16405208?od=T31&po=0&category=0&groupCd=CLIEN
3편 : https://www.clien.net/service/board/lecture/16408035?od=T31&po=0&category=0&groupCd=CLIEN
4편 : https://www.clien.net/service/board/lecture/16408079?od=T31&po=1&category=0&groupCd=CLIEN
5편 : https://www.clien.net/service/board/lecture/16439190?od=T31&po=2&category=0&groupCd=CLIEN


스위치를 알리익스프레스에서 주문했습니다. 2주가 지났는데 안오네요. 언젠간 오겠죠. (안오면 어쩌지…) 원래 생각은 스위치 올 때까지 기다렸다가 스위치 납땜 과정하고 동시에 펌웨어 작업 과정을 대충 때우고 넘어가려고 했습니다. 이 글 목적이 펌웨어를 설명하는 것은 아니니까요.



그런데 스위치가 함흥차사 오질 않으니, 심심해서 펌웨어 작업을 먼저 조금 해 두려고 합니다. 펌웨어 작업은 스위치가 없어도 할 수 있어요. 스위치 누르는 대신 전기가 통하는 아무 물건이든 가지고 스위치가 꼽히는 PCB 구멍을 연결해서 쇼트시키면 되거든요.



그래도 펌웨어 관련 내용은 대충 쓰겠습니다. 재미없거든요. 일단 펌웨어는 아래 링크에서 다운받습니다.



https://github.com/navilera/Gosu



stm32 보드에서 동작하는 키보드 펌웨어입니다.



USB HID 키보드 펌웨어의 필수 요소는 매우 간단합니다. 아래 두 가지만 구현하면 충분히 키보드 펌웨어로 기능할 수 있습니다.



1. 어느 스위치가 눌렸는지 확인

2. USB HID keyboard 스팩에 맞춰서 호스트로 keyscan code report를 보냄



어느 스위치가 눌렸는지 확인 하는 방법은 PCB에 스위치가 매트리스로 연결되어 있으므로 순서대로 row에 신호를 쏴서 col에서 읽어보면 됩니다.



01.png



회로도를 다시 소환해 보죠. Row0에 신호를 쏘고 Col0부터 Col6까지 신호가 들어왔는지 확인해 보는 겁니다. 신호가 들어온 스위치가 닫힌것이지요. 그리고 순서대로 Row1에 신호를 쏘고 다시 Col0부터 Col6까지 또 읽습니다.



이게 전부입니다.



Row0부터 Row4에 연결한 GPIO를 output으로 설정하고 Col0부터 Col6에 연결한 GPIO를 input으로 설정해서 Row 쪽 GPIO 신호를 순서대로 high로 올리고 Col쪽 GPIO 신호를 읽어보면 되지요.



수도코드는 대충 이러합니다.



row_gpio = [GPIO 포트 5개 지정]

col_gpio = [GPIO 포트 7개 지정]


for row in row_gpio {

    set_gpio_output(row)

}

for col in col_gpio {

    set_gpio_input(col)

}


while(true) {

    for row in row_gpio {

        set_gpio_high(row)

            for col in col_gpio {

                if get_gpio_input(col) == 1 {

                    눌림!! : (row, col)

                 }// if

            } // for col

        set_gpio_low(row)

    } // for row

} // while



그냥 아주 전형적이고 초보적인 폴링입니다. 그래서 각 폴링 루프 사이에 delay를 조금 넣어서 GPIO 신호 레벨이 올라갔다가 완전히 내려가는 시간을 주어야 하는 등 부가적인 작업이 필요하지만 수도코드에는 표현하지 않았습니다.


02.png


왜냐면 논리적으로는 GPIO 신호 레벨이 high로 갔다가 low로 내려가는건 위 그림처럼 동작하는거로 이해합니다. 그러나 실제로 전압 레벨이 저렇게 딱딱 90도로 꺽이면서 high, low로 올라갔다 떨어졌다 하지 않거든요.



03.png


그림이 좀 부정확하군요. 커브가 저 모양이 아닌데... 아무튼 실제로는 대충 위 그림처럼 완만하게 전압이 올라갔다가 내려갑니다. 대충 완만하다는 것을 표현한 그림이라고 이해해 주세요. 설정에 따라 위 그림에 전압레벨이 변하는 구간 T의 시간을 어느정도 짧게 할 수 있긴한데 아무튼 0은 아니기 때문에 적당한 delay는 필요합니다. 만약 코어가 충분히 느려서 GPIO 전압 레벨 변화 속도보다 펌웨어 실행이 느리다면 delay가 필요 없을 수도 있습니다.


04.png


다시 회로도를 보면 blackpill 보드 핀 번호 기준으로 8번부터 12번을 row에 연결했고 1번부터 7번을 col에 연결했습니다.

이걸 실제 GPIO 포트 번호랑 매칭해 보면…


05.png


요렇게 됩니다. 그래서 row, col은 아래처럼 매칭됩니다.

Row0 : PA4

Row1 : PA3

Row2 : PA2

Row3 : PA1

Row4 : PA0



Col0 : PA5

Col1 : PA6

Col2 : PA7

Col3 : PB0

Col4 : PB1

Col5 : PB10

Col6 : PB11



실제 펌웨어 코드에서 위 매칭을 코딩한 코드는 아래와 같습니다.


06.png


그래서 정리하면 GPIO PA7에서 신호를 쏴서 GPIO PA6에서 신호를 받았다면 gRowPin[2]에서 신호를 쏴서 gColPin[1]에서 신호를 받은 것이기 때문에 (2,1) 에 있는 스위치가 눌렸다고 펌웨어는 알게되는 겁니다. 그러면 (2, 1) 위치에 있는 keycode를 찾아서 HID keyboard report 프로토콜에 실어서 호스트(운영체제)로 보내면 됩니다.



이 글에는 좀 정식으로 HID keycode를 스펙에서 찾아보려고 했는데 못 찾았네요… 대체 어디에 있는걸까요? 저는 그냥 아래 링크에서 가져다 썼습니다.



https://gist.github.com/MightyPork/6da26e382a7ad91b5496ee55fdc73db2



뭐가 됐든 동작만 잘하면 되죠.


07.png


그래서 키 맵 배치는 이렇게 됩니다. Layer 0은 그냥 쓸 때고요, Layer 1은 Fn 키를 눌렀을 때입니다. 저렇게 배치한 키에 해당하는 keycode로 2차원 배열 두 개를 만들면 됩니다.


08.png


이렇게요.


그러면 위에서 언급한 예를 다시 가져와서, (2, 1)에 키가 눌린것을 펌웨어가 알았으면 Fn도 눌린건지 확인합니다. Fn 이 안눌렸으면 gKeymap_buffer_layer0에서 찾고 Fn이 눌렸으면 gKeymap_buffer_layer1에서 찾습니다. 안눌렸다고 치고, gKeymap_buffer_layer0[2][1]이면 kA 이고 이 값은 키보드 A에 해당하는 키코드입니다.



키 스위치 매트리스에서 어떤 스위치가 눌려서 그 스위치에 해당하는 키코드가 뭔지 찾는 과정은 이 과정의 반복입니다. 동시 입력이면 이 과정을 7번 모아서 한 번에 호스트로 레포트하는 것이지요.



다음은 USB HID가 되게 끔 펌웨어를 만들어야 합니다. 방법은 USB 장치를 등록할 때 USB descriptor를 HID 스팩에 맞춰서 보내는 겁니다. 그러면 운영체제가 HID로 인식하고 어떤 HID인지 본 다음 keyboard이면 keyboard로 등록해서 keycode report를 입력으로 처리하는 겁니다.



사실 이 과정이 키보드 펌웨어 만드는 과정 중에 제일 어려운 부분입니다. 대충 있는 코드 재활용한다고 해도 USB 스펙에 대해서 겉핥기식으로도 알아야 하기 때문이죠.



대부분은 stm32의 샘플 프로젝트 코드에 다 구현되어 있기 때문에 그대로 가져다가 디스크립터만 수정하면 됩니다. 그래서 샘플 코드를 보고 대충 필요한 위치에 값만 바꾸면 되는데요. 그래도 어떤 순서로 디스크립터가 구성되는지는 알아두면 좋습니다.


09.png


USB 디스크립터는 이 그림처럼 계층 구조로 되어 있습니다. Device Descriptor를 먼저 보내고 그 다음에 Configuration Descriptor를 보내고 Interface, Endpoint 디스크립터를 이어서 보내면 됩니다.



디스크립터가 어떻게 구성되어야 하는지는 HID 스펙 문서에 샘플로 나와 있습니다. 친절하죠?


10.png


이렇게 샘플이 있어서, 요 샘플 그대로 디스크립터를 작성해도 됩니다.


11.png



대부분은 stm32의 샘플 프로젝트에 있는 코드를 그대로 썼고 몇 개 값만 바꿨습니다. HID 스펙 버전을 1.0에서 2.0으로 바꿨습니다. 최종 동작에는 어떤 차이가 있는지 모르겠네요… 마지막 필드인 Number of possible configurations가 1이므로 이 디바이스 디스크립터는 Configuration descriptor를 1개 가집니다.



이런식으로 순서대로 config, interface, HID, endpoint 디스크립터를 하나씩 수정합니다. 하나씩 다 나열해봐야 알아보기 힘든 코드 나열일 뿐이니까 디스크립터 설명은 여백이 모자라 더 이상 적지 않겠습니다.



12.png



키보드 키를 누르면 펌웨어가 어떤 키가 눌렸는지 확인해서 호스트(운영체제)에 뭐가 눌렸는지 알려줘야 합니다. 위 표가 어떻게 보내라고 스펙에서 설명하고 있는 표입니다. 간단히 말해 8바이트 배열로 보내는 거고 0번 바이트에 Modifier Keys (Alt, Ctrl, Shift 같은 애들입니다.) 에 대한 내용을 넣고 1번 바이트는 0으로 채우고 2번부터 7번까지 동시 입력된 애들을 기록해서 보내라는 겁니다. HID 스펙에 따르면 키보드가 한 번에 동시 입력으로 처리해서 호스트에 보낼 수 있는 키는 최대 6개입니다. 키보드 광고에 나오는 무한 동시 입력이라는 건 대체 뭔지 모르겠습니다. 스펙에 6개라고 정해 놨는데…. 아마 어딘가에 저 길이를 조정할 수 있는 설정이 있을 텐데… 귀찮아서 찾지 않았습니다. 6개도 충분하니까요.


13.png



Modifier는 키가 여러개인데 report 할 수 있는 공간은 8바이트 뿐입니다. 그래서 얘네들은 비트맵으로 레포트합니다. 각 비트의 의미는 위 표와 같습니다.



예를 들어 왼쪽 ctrl과 alt를 동시에 누르고 오른쪽 shift를 누르면 0010_0101 = 0x25 가 되는겁니다. 쉽죠?



그래서 키보드 펌웨어는 운영체제에 인식되고 나면 내부적으로 저 8바이트짜리 report를 계속 호스트에 보내기만 합니다. 물론 받기도 하는데, 컴퓨터에서 임의로 numlock 같은거 켜잖아요. 그럴때는 호스트에서 1바이트 짜리 데이터를 받아서 펌웨어가 정해진 액션을 하는겁니다. 저는 필요없어서 안만들었습니다.



대충 수도코드는 이러합니다.


Idx = 2

for row 전체 {

    for col 전체 {

        if 입력인가() == true {

            keycode = get_keycode(row, col)

            if isModifier(keycode) == true {

                report[0] |= getBitmap(keycode)

                continue

            } else {

                report[idx++] = keycode

                if idx >= 8 {

                    goto exit_loop

                }  // else

            } // if is Modifier

        } // 입력

    } // for col

} // for row

exit_loop:

sort(report)

sendToHost(report)



대충 이러합니다. 실제 코드는 위 과정을 몇 개 함수로 쪼개서 goto는 없습니다. (goto가 뭐가 어때서!!)

skqlffpfk 님의 게시글 댓글
  • 주소복사
  • Facebook
  • X(Twitter)
댓글 • [3]
Nocome
IP 121.♡.81.49
09-06 2021-09-06 18:34:50
·
완결기대하고있습니다 ㅎㅎ
amos
IP 39.♡.139.111
09-06 2021-09-06 22:47:21 / 수정일: 2021-09-06 22:58:04
·
무한 동시 입력이라는 것은 고스트키가 없다라는 의미입니다. 한방에 모든 키를 동시에 팍! 누른다는 의미가 아니라... 키를 누르고 있는 상태에서 추가로 또 누르고 또 누르고 해도... 모든 키를 빠짐 없이 다 인식할 수가 있으면 무한 동시 입력 가능이라고 합니다.
참고로, USB 규격은 특별히 높은 버전의 기능을 쓸 것이 아니라면 가능하다면 낮은 버전을 쓰는 것이 호환성에서 유리합니다. PC의 경우엔 거의 상관 없겠지만, 임베디드 기기 중에 좀 오래 된 것은 최신 버전을 인식 못 할 수도 있습니다.
바위맨
IP 121.♡.188.67
09-10 2021-09-10 14:18:01
·
저도 한번 만들어볼까 하다가 중간에 포기할까 싶어서 그만두었는데 진짜 대단하신거 같습니다!
저는 그냥 3D프린터나 가지고 놀아야 겠네요;; ㅋㅋ
삭제 되었습니다.
새로운 댓글이 없습니다.
이미지 최대 업로드 용량 15 MB / 업로드 가능 확장자 jpg,gif,png,jpeg,webp
지나치게 큰 이미지의 크기는 조정될 수 있습니다.
목록으로
글쓰기
글쓰기
목록으로 댓글보기 이전글 다음글
아이디  ·  비밀번호 찾기 회원가입
이용규칙 운영알림판 운영소통 재검토요청 도움말 버그신고
개인정보처리방침 이용약관 책임의 한계와 법적고지 청소년 보호정책
©   •  CLIEN.NET
보안 강화를 위한 이메일 인증
안전한 서비스 이용을 위해 이메일 인증을 완료해 주세요. 현재 회원님은 이메일 인증이 완료되지 않은 상태입니다.
최근 급증하는 해킹 및 도용 시도로부터 계정을 보호하기 위해 인증 절차가 강화되었습니다.

  • 이메일 미인증 시 글쓰기, 댓글 작성 등 게시판 활동이 제한됩니다.
  • 이후 새로운 기기에서 로그인할 때마다 반드시 이메일 인증을 거쳐야 합니다.
  • 2단계 인증 사용 회원도 최초 1회는 반드시 인증하여야 합니다.
  • 개인정보에서도 이메일 인증을 할 수 있습니다.
지금 이메일 인증하기
등록된 이메일 주소를 확인하고 인증번호를 입력하여
인증을 완료해 주세요.