반응형

라즈베리파이에서 디폴트로 SPI가 비활성화 되어있기 때문에 활성화 시켜주는 작업이 필요합니다. 다음 포스팅을 참고하세요..

[임베디드/Raspberry Pi] - Raspberry Pi 2/3에서 SPI 사용하기


라즈베리파이 보드와 아두이노를 다음처럼 연결해줍니다.

Raspberry Pi 2/3          Arduino UNO 

(MOSI)  19       ------   11(MOSI)

(MISO)  21      ------   12(MISO)

(SCK)   23       ------   13(SCK)

     GND 6       ------    GND


아두이노 IDE에 다음 코드를 복사한 후,  아두이노에 업로드 시켜줍니다. 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include <SPI.h>  
   
char buf [100];  
volatile byte pos = 0;  
volatile boolean printIt = false;  
#define   spi_enable()   (SPCR |= _BV(SPE))  
  
  
void setup (void)  
{  
  //시리얼 통신 초기화  
  Serial.begin (9600);  
   
  //Master Input Slave Output 12번핀을 출력으로 설정  
  pinMode(MISO, OUTPUT);  
    
  //slave 모드로 SPI 시작   
  spi_enable();  
   
  //인터럽트 시작  
  SPI.setClockDivider(SPI_CLOCK_DIV64); //250kHz   
  SPI.setDataMode(SPI_MODE0);  
  SPI.attachInterrupt();  
   
}   
   
   
// SPI 인터럽트 루틴  
ISR (SPI_STC_vect)  
{  
  // SPI 데이터 레지스터로부터 한바이트 가져옴  
  byte c = SPDR;    
    
  //버퍼에 자리가 있다면...  
  if (pos < sizeof buf)  
  {  
    buf[pos++= c;  
      
    // 출력을 진행한다.   
     if (c == '\0')  
      printIt = true;        
   }   
}    
   
  
void loop (void)  
{  
  if (printIt)  
    {  
        buf[pos] = 0;    
        Serial.println (buf);  
        pos = 0;  
        printIt = false;  
    }    
      
}  
cs


라즈베리파이에서 다음 코드를 컴파일 시켜 줍니다. 

1
pi@raspberrypi:~ $ gcc spi_test.c -o spi_test
cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
#include <stdint.h>  
#include <unistd.h>  
#include <stdio.h>  
#include <stdlib.h>  
#include <getopt.h>  
#include <fcntl.h>  
#include <sys/ioctl.h>  
#include <linux/types.h>  
#include <linux/spi/spidev.h>  
  
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))  
  
static void pabort(const char *s)  
{  
    perror(s);  
    abort();  
}  
  
static const char *device = "/dev/spidev0.0";  
static uint8_t mode;  
static uint8_t bits = 8;  
static uint32_t speed = 250000;  
static uint16_t delay;  
  
static void transfer(int fd, char* tx, int len)  
{  
    int ret;  
    uint8_t rx[256];  
    struct spi_ioc_transfer tr = {  
        .tx_buf = (unsigned long)tx,  
        .rx_buf = (unsigned long)rx,  
        .len = len,  
        .delay_usecs = delay,  
        .speed_hz = speed,  
        .bits_per_word = bits,  
    };  
  
    ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);  
    if (ret < 1)  
        pabort("can't send spi message");  
 
    for (ret = 0; ret < len; ret++)   
        printf("%c", rx[ret]);  
    puts("\n");  
}  
  
  
int main(int argc, char *argv[])  
{  
    int ret = 0;  
    int fd;  
  
  
    fd = open(device, O_RDWR);  
    if (fd < 0)  
        pabort("can't open device");  
  
    /* 
     * spi mode 
     */  
    ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);  
    if (ret == -1)  
        pabort("can't set spi mode");  
  
    ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);  
    if (ret == -1)  
        pabort("can't get spi mode");  
  
    /* 
     * bits per word 
     */  
    ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);  
    if (ret == -1)  
        pabort("can't set bits per word");  
  
    ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);  
    if (ret == -1)  
        pabort("can't get bits per word");  
  
    /* 
     * max speed hz 
     */  
    ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);  
    if (ret == -1)  
        pabort("can't set max speed hz");  
  
    ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);  
    if (ret == -1)  
        pabort("can't get max speed hz");  
  
    printf("spi mode: %d\n", mode);  
    printf("bits per word: %d\n", bits);  
    printf("max speed: %d Hz (%d KHz)\n", speed, speed/1000);  
 
    char buf[]="echo test";  
    transfer(fd, buf, ARRAY_SIZE(buf));  
  
    close(fd);  
  
    return ret;  
}
cs


아두이노 IDE의 메뉴에서 도구 - 시리얼 모니터를 선택하여 시리얼 모니터를 실행시켜 놓고 라즈베리파이에서 컴파일한 프로그램을 실행시켜줍니다. 

라즈베리파이에서 실행한 프로그램은  "echo test" 문자열을 spi를 이용해 아두이노로 전송 후, 종료합니다.


시리얼 모니터를 보면 "echo test" 문자열이 출력된 걸 볼 수 있습니다.


라즈베리 파이에서  "echo test" 문자열을 SPI를 이용해서 아두이노로 보내면 ,  아두이노는 해당 문자열을  받아 시리얼로 보내어 시리얼 모니터에 "echo test"가 출력되게 됩니다. 


반응형

포스트 작성시에는 문제 없었지만 이후 문제가 생길 수 있습니다.
댓글로 알려주시면 빠른 시일내에 답변을 드리겠습니다.

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

유튜브 구독하기


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

  1. kim 2016.08.15 01:49

    안녕하세요. SPI 통신을 처음으로 공부하는 초보입니다.
    SPI통신을 직접해보고 싶어 님 블로그를 참고하게 됬는데,
    아두이노가 슬레이브고, 라즈베리파이가 마스터인 상황에서 echo test를 아두이노 에서 잘 받는 것은 확인했습니다.
    그 반대로 아두이노에서 라즈베리파이로 echo 되는 echo test말고 다른 문자열 데이터를 보내고 싶은데 어떻게 해야하는지 도움을 구합니다 ㅠㅠ 어떤 식으로 구현해도 안되네요.. 부탁드립니다

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2016.08.15 21:45 신고

      SPI보단 I2C를 사용하는게 쉬울듯합니다..

      http://webnautes.tistory.com/759

  2. name 2017.12.19 13:35

    감사합니다...! 천재신듯

  3. ww 2019.11.26 19:12

    안녕하세요. 포스팅 감사합니다. 덕분에 많은 도움이 되었습니다.
    버퍼 사이즈를 256으로 변경하면 시리얼 모니터에 값이 뜨지 않던데.. SPI로 값이 전달이 안된걸까요?

  4. ww 2019.11.27 10:19

    답변 감사드립니다. 다시 해보니 정상 출력되는걸 확인했습니다.

  5. LLMUS 2020.10.09 12:08

    전압 문제를 해결하지 않으셨다면 5V의 UNO와 3.3V의 RPI를 직접 연결하는 것은 위험할 수 있습니다! 라즈베리파이에 심각한 손상을 입힐 수 있기 때문에 중간에 Level shifter가 필요할 수 있어요.

+ Recent posts