본문 바로가기

언어/라즈베리파이

C언어로 Raspberry pi 2의 GPIO 레지스터 접근하여 LED켜보기

출처:  


ps.

raspberry pi 3에서도 동일하게 동작합니다.


복잡하게 디바이스 드라이버까지 작성하지 않고 간단하게 mmap을 사용하여 레지스터에 접근하여 LED를 제어해보려고 합니다. 아래는 라즈베리파이2의 핀 배열입니다. 보드상에 1번핀의 위치가 표기 안되어 있어서 아래 그림으로는 판단이 안서네요..

 

그래서 다른 이미지를 하나 더 찾아봤습니다. 빨간색 LED와 초록색 LED가 있는 곳 옆이 1번입니다..

 

위 이미지대로라면 핀번호 2번이 5V이고 핀번호 6번이 그라운드입니다. 혹시나해서 LED를 극성에 맞게 연결해주니 불이 켜지네요.

 

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

 

 

BCM2835 데이터 시트에 따르면 LED를 켜고 끄는 데에는 다음 레지스터들을 사용하면 됩니다. 라즈베리파이2에선 BCM2836이 사용되었지만 일단 해봅니다.

 

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이 되는 것입니다. 아래에 LED를 제어하는데 사용할 3가지 레지스터의 메모리 주소들을 보여주고 있습니다.

 

GPIO18번은 GPF_SEL1레지스터에 해당 항목이 있습니다. 24번째 비트부터 26번째 비트까지의 값을 001로 바꾸어주면 GPIO18번을 출력모드가 되게 됩니다.

   

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

   

 

전체 소스코드입니다. LED가 5번 깜빡이게 됩니다.





#include     
#include     
#include     
#include     
#include     
#include     
        
        
#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;    
}