반응형


복잡하게 디바이스 드라이버까지 작성하지 않고 간단하게 mmap을 사용하여 레지스터에 접근하여 LED를 제어해보려고 합니다.

핀번호 6번 그라운드와 핀번호 12번 GPIO18에 LED를 연결해주었습니다.



BCM2835 데이터 시트에 따르면 LED를 켜고 끄는 데에는 다음 레지스터들을 사용하면 됩니다.

라즈베리파이3에선 BCM2837이지만 동일하게 동작했습니다.


  • GPFSELx – GPIO핀을 Input 또는 Ouput으로 사용할지 결정.

  • GPSETx – GPIO핀을 하이레벨로 만들어줌. Led가 켜진 상태.

  • GPCLRx – GPIO핀을 로우 레벨로 만들어줌. Led가 꺼지는 상태.



GPIO Base Address가 아래처럼 0x 7E20 0000으로 나와 있지만 BCM2835 데이터시트의 1.2.3 ARM physical addresses에 따르면 실제로 접근 시에는 0x 2020 0000부터 시작하는 걸로 생각하면 됩니다.

하지만 이건 라즈베리파이 1 기준입니다. (http://www.raspberrypi.org/forums/viewtopic.php?f=6&t=5982 )




https://www.raspberrypi.org/forums/viewtopic.php?f=33&t=98740  에 따르면 라즈베리파이2에서는 0x3F20 0000으로 바꾸어서 적용시키면 된다고 합니다. 따라서 GPFSEL0의 시작 주소가 0x7E20 0000이 아니라 0x3F20 0000이 되는 것입니다.

라즈베리파이3에서도 테스트해보니 동일하게 동작합니다.


아래에 LED를 제어하는데 사용할 3가지 레지스터의 메모리 주소들을 보여주고 있습니다.




GPIO18번은 GPF_SEL1레지스터에 해당 항목이 있습니다.

24번째 비트부터 26번째 비트까지의 값을 001로 바꾸어주면 GPIO18번는 출력모드가 되게 됩니다.


   //gpio[GPFSEL1/4] = 0b00000001000000000000000000000000;    
   gpio[GPFSEL1/4] |= (1<<24);    



그리고 다음 레지스터들에서 GPIO18번의 위치에 해당되는 비트를 세팅 해주면 LED가 켜지고 꺼지게 할 수 있습니다.



       //gpio[GPSET0/4] = 0b00000000000001000000000000000000;    
       gpio[GPSET0/4] |= (1<<18);   





       //gpio[GPCLR0/4] = 0b00000000000001000000000000000000;   
       gpio[GPCLR0/4] |= (1<<18);




실행시켜보면 LED가 5번 깜빡이게 됩니다.


pi@raspberrypi:~ $ g++ led.c -o led

pi@raspberrypi:~ $ sudo ./led



#include <stdlib.h>    
#include <stdio.h>
#include <unistd.h>    
#include <sys/types.h>    
#include <sys/stat.h>    
#include <fcntl.h>    
#include <sys/mman.h>    
       
       
#define GPIO_BASE 0x3F200000    
#define GPFSEL1   0x04
#define GPSET0    0x1C
#define GPCLR0    0x28
       
       
int main()    
{    
   int fd = open( "/dev/mem", O_RDWR|O_SYNC );    
   if ( fd < 0 ){    
       printf( "can't open /dev/mem \n" );    
       exit(-1);    
   }
       
       
   char *gpio_memory_map = (char *)mmap( 0, 4096, PROT_READ|PROT_WRITE,    
       MAP_SHARED, fd, GPIO_BASE );    
       
   if ( gpio_memory_map == MAP_FAILED )    
   {
       printf( " Error : mmap \n" );    
       exit(-1);    
   }
       
           
   volatile unsigned int* gpio = (volatile unsigned int*)gpio_memory_map;    
   //gpio[GPFSEL1/4] = 0b00000001000000000000000000000000;    
   gpio[GPFSEL1/4] |= (1<<24);    
       
   int i;    
   for ( i=0; i<5; i++ )    
   {
       //gpio[GPSET0/4] = 0b00000000000001000000000000000000;    
       gpio[GPSET0/4] |= (1<<18);   
       sleep(1);    
       
       //gpio[GPCLR0/4] = 0b00000000000001000000000000000000;   
       gpio[GPCLR0/4] |= (1<<18);  
       sleep(1);    
   }
       
    munmap( gpio_memory_map, 4096);    
   
   return 0;    
}    



마지막 업데이트 2019. 2. 18


반응형

포스트 작성시에는 문제 없었지만 이후 문제가 생길 수 있습니다.
질문을 남겨주면 가능한 빨리 답변드립니다.

여러분의 응원으로 좋은 컨텐츠가 만들어집니다.
지금 본 내용이 도움이 되었다면 유튜브 구독 부탁드립니다. 감사합니다 ~~

유튜브 구독하기


제가 쓴 책도 한번 검토해보세요 ^^

  1. 판다를판다안판다 2016.04.17 20:58

    우아 ㅠㅠㅠ 감사합니다.. 정말 감사해요 ㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠ 이런자료를찾고있었는데. 혹시 라즈베리파이3 는 사용 안하시는지요 ???
    ihjo2063@gmail.com 이 제 이메일인데.. 혹시 자료같은거 공유가능하신가요 ?

  2. 판다를판다안판다 2016.04.17 20:58

    우아 ㅠㅠㅠ 감사합니다.. 정말 감사해요 ㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠ 이런자료를찾고있었는데. 혹시 라즈베리파이3 는 사용 안하시는지요 ???
    ihjo2063@gmail.com 이 제 이메일인데.. 혹시 자료같은거 공유가능하신가요 ?

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2016.04.17 21:18 신고

      가지고 있긴한데 라즈베리파이3에서는 안해봤습니다..^^;

  3. 행인 2016.05.22 01:03

    안녕하세요! 많은 도움이 되었습니다!
    질문이 있는데 gpio[]에 접근할 때 왜 4를 나눠주는것이죠?

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2016.05.22 01:38 신고

      레지스터에 접근하기 위해 사용하는 변수인 gpio의 크기가 4바이트 이기 때문입니다.

+ Recent posts