SPI의 개요

SPI (Serial Peripheral Interconnect) 버스는 Motorola에 의해 개발된 전이중 (full duplex) 통신이 가능한 동기 통신 규격이다. I2C와 마찬가지로 매스터 슬레이브 방식으로 동작하며 매스터가 동기를 위한 클럭을 출력한다각 SPI 슬레이브 장치는 chip enable (/CE) 입력을 가지고 있으며 이 입력이 활성화되었을 때에만 동작한다따라서 매스터는 여러 개의 slave select (SS) 선을 슬레이브들의 /CE에 연결하고 한 순간에 하나의 슬레이브만 선택하는 방법을 사용하여 두 개 이상의 슬레이브 장치들을 구동할 수 있다. SPI의 통신 속도는 최고 70 MHz에 이르기 때문에I2C에 비해 훨씬 빠르다.

 

다음 그림은 SPI 버스를 통해 매스터가 한 개의 슬레이브와 일대일로 연결된 상황을 보여준다.

 

 

그림에 표시된 4 개의 신호는 SPI 버스에서 정의된 신호이다.

 

● SCLK : Serial Clock. 매스터가 출력하는 동기용 클럭

● MOSI : Master Output Slave Input. 매스터의 출력이며 슬레이브에게는 입력

● MISO : Master Input Slave Output. 슬레이브의 출력이며 매스터에게는 입력

● SS : Slave Select. 매스터의 출력으로 슬레이브를 선택하기 위한 신호

 

SCLK는 매스터가 출력하는 클럭 신호이다. SCLK를 기준으로 매스터와 슬레이브 사이의 데이터 교환이 진행된다. MOSI는 매스터의 출력으로 슬레이브로 정보를 보내기 위한 선이다반대로 MISO는 슬레이브의 출력으로 매스터가 슬레이브의 정보를 받기 위한 선이다앞의 그림에서 보듯이 매스터와 슬레이브의 MOSI끼리 서로 연결되며 MISO끼리 서로 연결된다. SS는 매스터가 슬레이브를 선택하기 위한 매스터의 출력으로 슬레이브의 /CE 입력에 연결된다슬레이브는 /CE 입력이 ‘0’인 동안에만 활성화된다.

 

통신을 진행하기 위해서 매스터는 우선 SS로 ‘0’을 출력하여 해당 슬레이브를 활성화시킨다그런 다음 매스터는 SLCK로 동기를 위한 클럭을 출력하는데 이 클럭에 맞추어 MOSI로 데이터를 한 비트씩 내보낸다이와 동시에 매스터는 자신이 출력하는 클럭에 맞추어 MISO를 한 비트씩 읽는다다시 말해서 SPI 매스터는 자신의 출력인 SCLK에 맞추어 MOSI로 데이터를 내보내며 동시에 MISO로는 데이터를 수신한다. SPI 버스는 언제나 양방향 통신을 진행한다. SCLK에 맞추어 MOSI로 데이터를 출력하는 동안 MISO로는 데이터가 수신된다수신되는 데이터는 상황에 따라 의미가 있는 값일 수도 있고 쓰레기 값일 수도 있다마찬가지로 슬레이브의 데이터를 읽기 위하여 SLCK에 맞추어 MISO로 입력을 받는 동안 MOSI로는 데이터가 출력된다.

 

보통 SPI 통신은 8 비트 단위로 진행되지만 12 비트나 16 비트 또는 그 이상의 길이가 한 단위가 될 수도 있다비트 전송 순서에 대한 규정은 없다데이터의 전송은 MSB부터 시작될 수도 있고 LSB부터 시작될 수도 있다데이터를 연속 전송하는 경우 한 단위의 데이터를 보낼 때마다SS 신호를 매번 인가할 수도 있지만 SS 신호를 ‘0’으로 설정한 후 모든 데이터를 다 보낼 때까지 이 상태를 유지하고 있다가 데이터의 전송이 끝났을 때 SS를 ‘1’로 바꿀 수도 있다. SPI 규격은 이런 부분까지 규정하고 있지 않으며 매스터와 슬레이브 사이의 약속에 따라 결정된다. SPI슬레이브 장치의 용도와 특성에 따라 사용 방법이 다르므로 슬레이브 장치의 데이터쉬트를 반드시 확인해야 한다.

 

어떤 마이크로컨트롤러는 설정된 전송 단위에 맞추어 데이터 전송 때마다 자동으로 SS 신호를 출력해 주는 기능을 가지고 있다. ATMEL사의ARM7 기반 AT91SAM7S 계열 마이크로컨트롤러가 그 예이다데이터 전송 단위를 16 비트로 설정했다면 SPI 매스터가 SCLK 신호를 출력하기 전에 자동으로 SS 신호를 ‘0’으로 내리고 데이터가 출력되는 동안 이 상태를 유지하다 전송이 끝나면 이 신호를 다시 ‘1’로 올려준다이런 용도로 사용할 수 있는 SS 핀이 여러 개 있어서 사용자가 선택할 수 있다이런 기능이 있으면 정해진 길이의 데이터를 반복해서 출력하는 경우예를 들면 주기적으로 DAC에 값을 전송하는 경우에 매우 편리하다이런 기능이 없는 마이크로컨트롤러의 경우에는 사용자가 프로그램을 통해 수동으로 SS 신호를 제어해야 한다. AVR 마이크로컨트롤러는 이 기능을 지원하지 않으므로 GPIO 핀을 슬레이브 선택용으로 정하고 수동으로 그 신호를 제어해야 한다.

 

SPI 모드 (mode)

SPI 매스터와 슬레이브는 매스터의 출력인 SCLK에 맞추어 데이터를 한 비트씩 교환한다그런데 클럭에 동기를 맞추는 방법은 한 가지만 있는 것이 아니다클럭이 출력되고 있지 않은 상황에서 클럭의 기본 값은 ‘0’일 수도 있고 ‘1’일 수도 있다그리고 매스터와 슬레이브가 매 클럭의 첫 번째 에지에서 데이터를 읽을 수도 있고 매 클럭의 두 번째 에지에서 데이터를 읽을 수도 있다앞의 특성을 클럭의 극성 (polarity)이라고 하고 뒤의 특성을 클럭의 위상 (phase)이라고 한다클럭의 극성과 위상의 조합에 따라 모두 4 가지 방법이 사용 가능하다. SPI 슬레이브는 4가지 가능한 방법 중 한 가지를 사용하도록 만들어지고 매스터는 4 가지 방법을 모두 지원해야 한다.

 

AVR 마이크로컨트롤러의 SPI 제어 레지스터에는 CPOL CPHA라는 비트가 있는데 이 비트의 설정에 따라 출력되는 클럭의 극성과 위상이 달라진다다른 마이크로컨트롤러도 이와 같거나 비슷한 이름의 비트를 가지고 있다. CPOL 비트가 0이면 클럭의 기본 상태가 ‘0’이며 이 비트가 1이면 클럭의 기본 상태는 ‘1’이다그리고 CPHA 비트가 0이면 매 클럭의 첫 번째 에지에서 데이터가 샘플되며 이 값이 1이면 두 번째 에지에서 데이터가 샘플된다.

 

다음 그림은 CPHA 비트가 0일 때의 타이밍을 설명하고 있다.

  

 

CPHA 값이 0이므로 클럭의 극성에 상관없이 매스터와 슬레이브는 모두 매 클럭의 첫 번째 에지에서 데이터를 샘플한다따라서 매 클럭의 두 번째 에지에서 비트 전환이 일어난다.

 

다음은 CPHA 비트가 1일 때의 타이밍을 설명한다.

  

 

클럭의 극성에 상관없이 매 클럭의 두 번째 에지가 데이터 샘플에 사용되며 따라서 매 클럭의 첫 번째 에지에서 비트 전환이 일어난다.


위의 4 가지 극성과 위상 조합에 0에서 3까지의 숫자를 부여하여 이를 SPI 모드라고 부른다.


SPI mode

CPOL

CPHA

0

0

0

1

0

1

2

1

0

3

1

1

 

두 개 이상의 SPI 슬레이브 연결

I2버스처럼 SPI 버스에서도 한 개의 매스터가 두 개 이상의 슬레이브와 연결될 수 있다. I2슬레이브가 고유한 주소를 가지고 있는 것처럼 각각의 SPI 슬레이브는 chip enable (/CE) 신호를 가지고 있다. SPI 매스터는 각 슬레이브의 /CE 신호를 제어하여 원하는 슬레이브를 선택한다.다음 그림은 한 개의 SPI 매스터에 두 개의 슬레이브들을 연결하는 방법을 설명한다.

 

 

세 장치의 SCLK, MOSI, MISO는 각각 서로 연결되어 있지만 슬레이브의 /CE 신호들은 서로 묶이지 않고 매스터의 다른 핀들로 연결된다슬레이브의 수에 상관없이 한 순간에는 하나의 슬레이브만 매스터와 통신할 수 있다두 슬레이브가 모두 활성화되면 슬레이브의 출력인 MISO에서 데이터의 충돌이 일어난다그래서 매스터는 자신이 원하는 슬레이브의 /CE 신호만 ‘0’으로 설정하여 활성화시키고 나머지 슬레이브의/CE는 ‘1’로 두어야 한다. /CE 입력이 ‘1’인 슬레이브는 선택되지 않았기 때문에 자신의 MISO 출력을 hi-Z 상태로 만들어 선택된 슬레이브와 매스터 간의 통신에 영향을 주지 않는다따라서 모든 SPI 슬레이브의 MISO 출력은 3 상태를 지원한다. /CE 입력이 ‘1’인 슬레이브는 당연히 매스터가 출력한 SCLK와 MOSI 신호를 무시한다.

 

세 개 이상의 슬레이브도 같은 방법으로 매스터와 연결할 수 있다슬레이브의 수가 하나씩 늘어날 때마다 새로운 슬레이브를 위한 /CE 신호만 하나 더 필요할 뿐이다그런데 이 때 매스터에 연결된 슬레이브들이 사용하는 SPI 모드가 한 가지가 아니거나 비트 전송 순서가 다를 수 있는데 이런 경우에는 통신의 효율이 많이 낮아진다가령 어떤 슬레이브는 모드 0을 사용하고 또 다른 슬레이브는 모드 1을 사용한다면 매스터가 슬레이브를 바꿀 때마다 동작 모드를 매번 다시 설정해야 한다또한 동작 모드가 같아도 비트 전송 순서가 다르다면 마찬가지 문제가 생긴다.

 

매스터가 하나의 슬레이브만 구동한다면 슬레이브의 /CE 신호를 GND로 고정시켜 두어도 상관없다어차피 SCLK, MOSI, MISO를 공유할 다른 슬레이브가 없기 때문에 이 선들은 하나뿐인 슬레이브 전용으로 사용된다그렇기 때문에 슬레이브를 항상 활성화시켜 둬도 기능상의 문제는 생기지는 않는다.

 

SPI 통신의 예

AT45DB161D은 SPI 인터페이스를 사용하는 16 Mbit 직렬 플래쉬 메모리이다이 플래쉬 메모리에 정보를 기록하거나 저장된 정보를 읽기 위한 여러 방법 중 다음 그림은 main memory page read 명령을 설명하고 있다이 그림에서 데이터는 바이트 단위로 표시되어 있다.

 

 

main memory page read 명령은 AT45DB161D 내부의 특정 페이지의 내용을 연속으로 읽기 위한 것이다이 플래쉬 메모리의 용량은 2 Mbytes이므로 주소를 지정하기 위해서 21 비트가 필요하다매스터는 가장 먼저 AT45DB161D /CE 신호를 ‘0’으로 만든 다음 main memory page read를 위한 비트 명령을 출력하고 이어서 읽기를 원하는 주소 바이트를 출력한다. (AT45DB161D MSB 우선의 비트 전송 순서를 사용한다.) main memory page read 명령과 바이트 주소를 받으면 AT45DB161D는 저장된 데이터를 읽어서 출력할 준비를 하는데 이 과정에 시간이 필요하다이를 위해 매스터는 4 바이트를 더 출력한다매스터가 추가로 전송하는 4 바이트를 전송하는 것은 SLCK를 출력하기 위한 동작이므로 출력하는 데이터는 어떤 값이든 상관없다.

 

이렇게 8 바이트를 MOSI로 출력하는 동안 계속해서 매스터의 MISO AT45DB161D의 출력이 들어오지만 이 값은 아무런 의미가 없는 쓰레기 값이다. AT45DB161D의 데이터 전송은 9 번째 바이트부터 시작된다. AT45DB161D 9 번째 바이트에서 매스터가 지정한 주소의 내용을MISO로 출력한 후 내부 카운터를 사용하여 주소를 1 증가시킨다이 후 매스터가 MOSI로 한 바이트씩 출력할 때마다 AT45DB161D는 데이터를 출력하고 주소를 1 증가시키는 과정을 계속 되풀이한다이런 과정을 통해 매스터는 AT45DB161D의 데이터를 필요한 만큼 연속해서 읽고 마지막으로 AT45DB161D /CE 신호를 ‘1’로 만들어 통신을 끝낸다. 9 번째 바이트부터 매스터가 SCLK를 출력할 뿐 MOSI로 출력해야 하는 데이터는 없으므로 어떤 값을 보내도 상관 없다.

 

이 명령 외에도 AT45DB161D을 사용에 필요한 다른 많은 명령들이 더 있다각 명령마다 위 그림과 비슷한 타이밍도를 가지고 있으므로 각 명령의 쓰임새와 사용법을 알려면 AT45DB161D의 데이터쉬트를 참고해야 한다.

 

SPI의 장·단점

SPI 버스의 가장 큰 장점으로는 최고 70 MHz에 이르는 빠른 통신 속도와 동시 양방향 통신이 가능하다는 점을 들 수 있다전송 데이터 단위에 대한 제약이 없어서 8 비트, 16 비트, 24 비트 등 원하는 길이를 한 워드로 설정할 수 있다비트 순서에 대한 제약도 없으므로 필요에 따라MSB부터 전송할 수도 있고 LSB부터 전송할 수도 있다. I2슬레이브와 달리 SPI 슬레이브는 자체 주소를 가지고 있지 않으므로 주소 충돌의 문제도 발생하지 않는다.

 

I2버스와 달리 SPI 버스에는 한 개의 버스 매스터만 있을 수 있으며 I2버스에 비해 필요한 핀의 수가 더 많다. SPI 버스는 기본적으로 4 가닥의 선을 사용하며 매스터에 연결된 슬레이브의 숫자가 많아질수록 슬레이브를 선택하기 위한 SS 핀의 수 역시 슬레이브 수에 비례해서 늘어난다또한 I2버스의 ACK와 같은 메커니즘이 없어서 매스터는 자신이 통신하고 있는 장치가 실제 존재하는지 여부를 확인할 수 없다.

출 처 :  
http://eslectures.blog.me/80137862792



1. 기능 : 리눅스 기본 명령어들의 심볼릭 링크를 관리

2. option
-- config : 현재 심볼릭 링크를 변경하고자 할 때
-- list : 입력한 명령어 대신에 쓸 수 있는 다른 명령어들을 찾아준다.

3. 활용 예

# update-alternatives --config gcc


출 처 : http://blog.naver.com/yukino4u?Redirect=Log&logNo=98940260

from : http://ubuntuguide.net/how-to-install-and-setup-gcc-4-1g4-1-in-ubuntu-10-0410-10


The default gcc version in Ubuntu 10.04 LTS and 10.10 is gcc 4.4. However some programs depend on gcc 4.1.1 or gcc 4.1.2. Here’s how to install and setup gcc 4.1.3 in Ubuntu 10.04/10.10 which also works if one program need gcc 4.1.1/4.1.2 to run.

Install Gcc 4.1

gcc 4.1.3 is available default in Ubuntu 10.04/10.10 official repository, just run the command in Applications -> Accessories -> Terminal:


sudo
apt-get install gcc-4.1
 

If you absolutely want gcc 4.1.1, refer to ubuntuforums.org.

Set gcc 4.1 as default version

After that, use this command to list installed gcc in your Ubuntu:


ls /usr/bin/gcc*


and use this command to check which is default:


gcc -v


1.)
 Now, add alternatives for gcc:


sudo
update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.4 40 sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.1 30


run this command which lists available versions, then type a number to set default.


sudo update-alternatives --config gcc
 

There are 2 choices for the alternative gcc (providing /usr/bin/gcc).

Selection Path Priority Status
————————————————————
0 /usr/bin/gcc-4.4 40 auto mode
* 1 /usr/bin/gcc-4.1 30 manual mode
2 /usr/bin/gcc-4.4 40 manual mode


2.)
 add alternatives for g++, i486-linux-gnu-gcc, and i486-linux-gnu-g++ and set 4.1 as default:


update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.4 40 update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.1 30 update-alternatives --config g++

update-alternatives --install /usr/bin/i486-linux-gnu-gcc i486-linux-gnu-gcc /usr/bin/i486-linux-gnu-gcc-4.4 40 update-alternatives --install /usr/bin/i486-linux-gnu-gcc i486-linux-gnu-gcc /usr/bin/i486-linux-gnu-gcc-4.1 30 update-alternatives --config i486-linux-gnu-gcc

update-alternatives --install /usr/bin/i486-linux-gnu-g++ i486-linux-gnu-g++ /usr/bin/i486-linux-gnu-g++-4.4 40 update-alternatives --install /usr/bin/i486-linux-gnu-g++ i486-linux-gnu-g++ /usr/bin/i486-linux-gnu-g++-4.1 30 update-alternatives --config i486-linux-gnu-g++
sudo 명령어에 대한 설정을 하려면 /etc/sudoers 파일을 수정 하면 된다. 이 파일은 기본적으로 read-only 파일이며, root로 접속해서 수정 시에도 강제로 write 해야만 된다.

#

# This file MUST be edited with the 'visudo' command as root.

#

# Please consider adding local content in /etc/sudoers.d/ instead of

# directly modifying this file.

#

# See the man page for details on how to write a sudoers file.

#

Defaults    env_reset


# Host alias specification


# User alias specification


# Cmnd alias specification


# User privilege specification

root    ALL=(ALL:ALL) ALL


# Members of the admin group may gain root privileges

%admin ALL=(ALL) ALL


# Allow members of group sudo to execute any command

%sudo   ALL=(ALL:ALL) ALL


#includedir /etc/sudoers.d




이 설정은 root 유저에게 모든 호스트에서 모든 유저의 권한을 모든 명령어를 실행시킬 수 있다는 뜻이다.

root ALL=(ALL) ALL



sudo 명령어를 사용할 때 특정 사용자에게는 비밀번호를 묻지 않도록 한다.
/etc/sudoers에 아래와 같은 문구를 추가한다.

userID ALL=(ALL)NOPASSWD: ALL














typeof 는 gcc의 확장된 기능으로, 해당 변수의 타입을 반환하는 역할을 하는 매크로 함수이다.

예제 코드)
#include <stdio.h>

int main()
{
    char s1;
    typeof(s1) s2;

    unsigned char u1;
    typeof(u1) u2;

    s2 = 0xff;
    u2 = 0xff;

    printf("s2 = %d\n", s2);
    printf("u2 = %d\n", u2);
    return 0;
}

결과)
s2 = -1
u2 = 255


container_of(ptr, type, member)

원형은 다음과 같다.
#define offsetof(type, member) ((size_t) &((type *)0)->member)
#define container_of(ptr, type, member) ({	\
		const typeof( ((type *)0)->member ) *__mptr = (ptr);	\
		(type *)( (char *)__mptr - offsetof(type,member) );})

ptr : 멤버의 포인터
type : 이 멤버를 포함하고 있는 컨테이너 스트럭쳐의 타입
member : type structure에 안에서 존재하는 멤버의 이름

결론적으로 얘기하자면 container_of 매크로는 구조체 멤버의 포인터를 이용하여 구조체의 시작 주소를 찾는 역할을 한다.

예제 코드)
#include <stdio.h>

#define offsetof(type, member) ((size_t) &((type *)0)->member)

#define container_of(ptr, type, member) ({      \
    const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
    (type *)( (char *)__mptr - offsetof(type,member) );})

struct type
{
    char ttt;
    int *member;
} con;

int main()
{
    printf("%p\n", &con);
    printf("%p\n", container_of(&(con.member), struct type, member));

    return 0;
}

결과)
0x80496ec
0x80496ec





strlen 함수를 사용시 인자로 NULL 포인터를 넘기면 segmentation fault 가 발생한다.
이는 0 번지로 가서 문자 개수를 세는 것으로 생각되며, 0번지를 참조 하려고 하기 때문에 segmentation fault가 발생하는 것 같다.




////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

"\0" 문자열로 바꿔주면 segmentation fault가 발생하지 않는다.



 
1. nand scrub

 - nand 의 모든 영역을 지우는 명령어


2. nand erase 'start_address' 'end_address'

 - nand 의 특정 영역을 지우는 명령어.
 - 'start_address'와 'end_address' 영역의 nand 내용을 지운다.
 - 'start_address'와 'end_address'에는 16진수를 써 넣는다. 단 0x는 붙이지 않는다.

 ex) # nand erase 0 8000


3. printenv

 - 환경 설정값을 읽어오는 명령어


4. setenv '환경변수'

 - u-boot에서 사용하는 환경변수를 설정하는 명령어

 ex) # setenv ipaddr 192.168.1.3
      # setenv bootargs "rootfstype=jffs2 root=/dev/mtdblock2 init=/init console=ttySAC1,115200"


5. saveenv

 - 설정 변경된 값을 저장하는 명령어
 - setenv 명령 후, 반드시 save를 해야 적용 됨


6. nand read [to:ram addr] [from:rom addr] [image size]

 - rom에 있는 image를 size 만큼 읽어, ram에 올리는 명령어

 ex) # nand read 30008000 40000 300000


7. nand write [from: ram addr] [to: rom addr] [image size]

 - ram에 있는 image를, rom에 size만큼 올리는 명령어

 ex) nand write 30008000 40000 300000


8. bootm [ram addr]

 - ram addr로 이동하여 image를 수행하는 명령어

 ex) bootm 30008000














 
error: call to '__open_missing_mode' declared with attribute error: open with O_CREAT in second argument needs 3 arguments

 이 오류는 GCC 4.3.2 버전 이상의 GCC 컴파일러를 사용할 때 나타납니다.

 GCC 4.3.2 버전 이상에서는 open() 함수의 인자(argument) 가 2 개에서 3 개로 늘어나게 되었고, 이로 인해 GCC 4.3.2 이전 버전에서 잘 빌드되던 코드들이 GCC 4.3.2 이상 버전에서 오류를 토해내게 됩니다.

 해결 방법은 코드상에 open() 함수를 모두 찾아 수정해 주는 수 밖에 없습니다만.... GCC 컴파일러는 친절하게 오류가 난 파일을 저 오류메세지 바로 위에 알려줍니다. 물론 몇번째 줄인지도 나옵니다만 한 소스 안에서 open 함수를 여러 곳에서 사용했다면 하나만 지적해 줄 것입니다.

 찾기를 통해 open() 함수를 쥐잡듯이 뒤져서 추가된 인자를 기입해 주도록 합니다.

예시 :
 오류 상태의 코드 : open(redir, O_WRONLY | O_TRUNC | O_CREAT);
 수정한 코드 : open(redir, O_WRONLY | O_TRUNC | O_CREAT, 644);

 추가된 부분은 권한입니다.  적당한 권한을 주면 되며 644 가 적당할 것입니다.(필요에 따라서 권한을 주면 됩니다.)

 어때요? 참 쉽죠~~

출 처 :  
http://www.tylorstyle.net/191

+ Recent posts