Raspberry Pi のGPIOでLEDを点灯させてみた

久しぶりにRaspberryPiを触ってみました。

Broadcom社のBCM2835というPeripheralチップが搭載されており、その一部の端子がヘッダピンに結線されています。ADC端子が無いのは非常に残念ですが、GPIO、UART、I2Cでハードウェア拡張が可能になっています。


手始めとして、GPIOにLEDを接続してC言語で点滅させてみました。


●回路(僅かこれだけです・・・)


●プログラム概要

gpio_open()
  BCM2835のレジスタへアクセスする準備を行います。
 システムコールopen
 システムコールmmap …BCM2835のGPIOレジスタ群のアドレスは0x20200000番地~です。

main()
  gpio_open()
  LEDを接続したヘッダP1の26番ピン(GPIO7)を出力モードに設定します。
 while(1){
     GPIO7にHighレベルを出力します。
     sleep() 時間待ち
     GPIO7にLowレベルを出力します。
     sleep() 時間待ち
 }

●コンパイル

$gcc gpio1.c

コンパイルが通ると a.out が生成されます。

●実行

$./a.out

と実行すると、システムコールopenでエラーが発生し、「can't open. Permisson denied」と返ってきます。

$sudo ./a.out 

と管理者権限で実行させます。
実行停止はキーボードからCtrl-cです。

=================================================================================
ソースコード gpio1.c

#include <stdio.h>
#include <unistd.h>

#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <stdint.h>

// BCM2835 on Raspberry pi
#define GPIO_REGS 0x20200000

static volatile uint32_t *gpio_regs;

int gpio_open()
{
  int fd;
  void *map;

  if ((fd = open ("/dev/mem", O_RDWR | O_SYNC) ) < 0) {
    printf("can't open. %s\n",strerror(errno));
    return -1;
  }

  map = mmap(0, getpagesize(), PROT_READ|PROT_WRITE, MAP_SHARED, fd, GPIO_REGS);
  if (map == MAP_FAILED) {
    printf("can't mapping. %s\n",strerror(errno));
    return -1;
  }

  close(fd);
  gpio_regs = (volatile uint32_t *)map;
  return 0;
}

int main(int argc, char **argv)
{
  uint i;

  // LED connected port number
  //  available port 2,3,4,7,8,9,10,11,14,15,17,18,22,23,24,25,27  (rev2.0 PCB)
  //
  //  see http://elinux.org/RPI_LOW_level_peripherals/
  uint portnum = 7;

  if( gpio_open() != 0 ){
    printf("error:stopped \n");
    return -1;
  }

  // Port mode settting
  // GPFSELn: Function Select Registers
  //   GPFSEL0: port0  - port9
  //   GPFSEL1: port10 - port19
  //   GPFSEL2: port20 - port29
  // FSELn
  //   000B input mode
  //   001B output mode
  //   others function mode
  //
  // see http://www.raspberrypi.org/wp-content/uploads/2012/02/BCM2835-ARM-Peripherals.pdf
  //
  i = portnum/10;
  *(gpio_regs + i) = (*(gpio_regs + i) & ~(0x7 << ((portnum%10) * 3) )) | (0x1 << ((portnum%10) * 3));

  //LED toggle test loop
  while(1){

    // Output High
    // GPSETn: GPIO Pin Output Set Registers
    //   GPSET0: port0 - port31
    // SETn
    //   0B : no effect
    //   1B : set     // GPSETn: GPIO Pin Output Set Registers
    //
    *(gpio_regs + 0x7) = (0x1 << portnum);
    sleep(1);

    // Output Low
    // GPCLRn: GPIO Pin Output Clear Registers
    //   GPCLR0: port0 - port31
    // CLRn
    //   0B : no effect
    //   1B : clear GPIO output
    //
    *(gpio_regs + 0x0A) = (0x1 << portnum);
    sleep(1);
  }
}

コメント

このブログの人気の投稿

ARM用クロスコンパイラのビルド(Windows8+Cygwin)

Raspberry Pi のsleep時間測定

Quartus2 V13.1 ~エントリー編 HDL回路から回路図用シンボルを作成する~