ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Raspberry PI 2 /3 와 atmega128를 연결하여 SPI 테스트 (문자열 전송)
    Raspberry Pi/Atmega128와 연동 2016. 6. 29. 05:14






    아래 처럼 두 보드를 연결해주었습니다..


    raspberry pi 2/3         Atmega128 

    (MOSI)  19       ------ PB2(MOSI)

    (MISO)  21      ------ PB3(MISO)

    (SCK)   23       ------ PB1(SCK) 

    (CS0)   24        ------ PB0    

          GND 6      ------ GND



    라즈베리파이에서 SPI를 활성화 시키기 위해서는 다음 포스팅을 참고하세요..

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


    라즈베리파이에서 데이터를 보내면... 



    AVR과 연결된 피시의 시리얼 터미널에서 데이터가 들어온 것을 볼 수 있습니다.. 



    다음은 각각 Atmega128을 위한 슬레이브 SPI 코드 및 라즈베리파이에서의 SPI 코드입니다..

    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
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    /*
     * spi_slave.c
     *
     * Created: 2016-06-28
     * Author : webnautes
     */ 
     
     #define F_CPU 16000000UL
     
     //1. baud rate를 선택
     #define USART_BAUDRATE 9600
     
     //2.시스템 클록과 원하는 baud rate를 이용하여 UBRR 값을 계산한다.
     #define UBRR_VALUE (((F_CPU / (USART_BAUDRATE * 16UL))) - 1)
     
    #include <avr/io.h>
    #include <avr/interrupt.h>
     
     
    void usartInit()
    {
        //3. UBRR0은 16비트 레지스터이기 때문에 8비트씩 나누어서 넣어야 한다.
        UBRR0H = (uint8_t)(UBRR_VALUE>>8);
        UBRR0L = (uint8_t) UBRR_VALUE;
        
        //4. USART 설정
        UCSR0C |= (1<<UCSZ00)|(1<<UCSZ01); //Charecter size : 8비트
        UCSR0C &= ~(1<<USBS0); //stop  bit : 1비트
        UCSR0C &= ~((1<<UPM01)|(1<<UPM00)); // no parity mode
        
        //5. 송수신을 가능하게 한다.
        UCSR0B=(1<<RXEN0)|(1<<TXEN0);
    }
     
    void transmitByte(uint8_t data) {
        
        //이전 전송이 끝나기를 기다림
        while(!(UCSR0A&(1<<UDRE0))){};
        
        UDR0 = data;                                            /* send data */
    }
     
    uint8_t receiveByte(void) {
        // 수신 되기를 기다림
        while(!(UCSR0A&(1<<RXC0))){};
        return UDR0;                                /* return register value */
    }
     
     
    void printString(volatile unsigned char str[]) {
        uint8_t i = 0;
        while (str[i]!='\0') {
            transmitByte(str[i]);
            i++;
        }
    }
     
    void readString(char str[], uint8_t maxLength) {
        char response;
        uint8_t i;
        i = 0;
        while (i < (maxLength - 1)) {                   /* prevent over-runs */
            response = receiveByte();
            transmitByte(response);                                    /* echo */
            if (response == '\r') {                     /* enter marks the end */
                break;
            }
            else {
                str[i] = response;                       /* add in a letter */
                i++;
            }
        }
        str[i] = 0;                          /* terminal NULL character */
    }
     
    void  init_SPI( ) {
        
        DDRB &= ~((1<<PB1)|(1<<PB2)|(1<<PB0)); // SCK, MOSI, SS --> inputs
        DDRB |= (1<<PB3);                  // MISO --> output
        
        //slave mode
        SPCR &= ~(1<<MSTR);
        
        //16000KHz / 16 
        SPCR  |= (1<<SPR0);
        
        //enable SPI
        SPCR |= ((1<<SPE)|(1<<SPIE));
     
    }
     
     
     
     
    unsigned char SPI_write(unsigned char cData) {
        SPDR = cData;
        while ( !(SPSR & (1<<SPIF))) ;
        return SPDR;
    }
     
    unsigned char SPI_read( void ) {
        SPDR = 0x0;
        while ( !(SPSR & (1<<SPIF))) ;
        return SPDR;
    }
     
     
     
    volatile unsigned char str[100];
     
     
    ISR(SPI_STC_vect)
    {
        static uint8_t idx=0;
        unsigned char ch = SPDR;
     
        if ( ch == '\0' )
        {
            str[idx]='\0';
            printString(str);
            idx=0;
        }
        else {
                str[idx]=ch;
                idx++;
        }    
     
     
    }
     
    int main (void)
    {
        init_SPI();
        usartInit();
        sei();
        
        while(1)
        {
     
     
        }
    }
     
     
    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
    102
    #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 = 1000000;
    static uint16_t delay=0;
     
    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 test0";
        transfer(fd, buf, ARRAY_SIZE(buf));
     
        close(fd);
     
     
        return ret;
    }
    cs


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

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

    유튜브 구독하기


    댓글 6

    • 1234 2019.05.01 18:23


      안녕하세요
      라즈베리파이와 아트메가의 차이점을 알수있을까요?
      어떤 상황에서는 라즈베리파이를 사용하고 어떤 상황에서는 아트메가를 채택하는지 알고싶습니다.

      • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.05.01 18:41 신고


        라즈베리파이는 CPU를 장착하기 때문에 운영체제가 올라가게되고...

        아트메가는 마이크로컨트롤러를 장착하기 때문에 운영체제를 사용못하고 펌웨어를 올릴 수 있습니다.



        네트워크 관련 응용에 대해서 비교해보면..

        라즈베리파이를 사용한다면 웹서버, 파일서버등을 구축하여 많은 사용자들이 서버에 접속하여 서비스를 이용할 수 있도록 할 수 있습니다.
        물론 PC나 서버 컴퓨터 정도의 성능은 나오지 않지요..

        아트메가의 경우에는 라즈베리파이에 비해 성능이 상대적으로 떨어지기 때문에 많은 사용자가 동시에 접속하는 서버를 구축하기 힘듭니다. 그래서 소규모의 네트워크를 위한 라우터, 인터넷 공유기등을 만드는데 사용합니다.

    • Favicon of https://noel-embedded.tistory.com BlogIcon 수리노을 2019.05.02 02:39 신고


      MCU 마이크로컨트롤러는 CPU를 포함하며 메모리와 여러 모듈이 함께 있는 SoC입니다. 라즈베리파이는 BCM사의 ARM chip으로 아트메가는 atmel사의 atmega chip으로 둘 모두 MCU입니다. 둘 모두 사용하려는 운영체제가 하드웨어를 지원한다면 OS를 올릴 수 있습니다. 단, atmega는 8비트 cpu와 적은 메모리양으로 인해서 올리지 않고 기본 펌웨어로 사용하는 것입니다.

      • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.05.02 05:14 신고


        좋은 답변 감사합니다.

        엄밀히 말하면 Atmega도 OS를 올릴수 있는게 맞습니다. 하지만 Raspberry Pi에 올라가는 Linux와는 기능과 성능 에서 차이가 많이나서 주로 특수한 임베디드 응용에서 사용하지 않나 싶습니다.

        둘 다 코어를 기반으로 주변장치를 연결할때 사용하는 시리얼, I2C 등의 인터페이스를 추가하여 설계했기때문에 soc라 볼수 있을지 모르지만 둘다 마이크로컨트롤러라 부르지는 않나 싶습니다.

        라즈베리파이 공식 홈페이지의 하드웨어 소개에서도 마이크로프로세서라고 언급합니다.

        마이크로컨트롤러라면 독자적으로 동작이 가능해야하는데..
        라즈베리파이에 장착된 브로드컴사의 칩에는 메모리가 포함되어 있지 않아서 이기도합니다..

    • Favicon of https://noel-embedded.tistory.com BlogIcon 수리노을 2019.05.02 14:56 신고


      답 감사합니다

Designed by Tistory.