* 코드

-o : 출력 파일명을 정하는 옵션

예) test.c 를 컴파일 하여 execute 실행 파일로 만든다.

$ gcc -o execute test.c

-c : 컴파일만 하는 옵션

예) test.c를 컴파일 한다. (test.o 오브젝트 파일 생성)

$ gcc –c test.c

-I : 소스에서 include 하는 헤더의 위치를 지정한다.

예) 위 소스에서 lib.h 파일이 /home/test/include 에 존재 시.

$ gcc –o execute test.c –I/home/test/include

-L  : 소스에서 사용하는 라이브러리 파일이 있는 위치를 지정한다.

예) 위 소스에서 libtest.a 파일이 /home/test/lib 에 존재 시

$ gcc –o execute test.c –I/home/test/include –L/home/test/lib

-l(소문자 L): 소스에서 사용하는 라이브러리 파일을 명시.

예) 위 소스에서 libtest.a 파일을 명시한다. 이때 lib 와 .a 는 생략한다.

$ gcc –o execute test.c –I/home/test/include –L/home/test/lib –ltest


'프로그래밍 > 리눅스 드라이버' 카테고리의 다른 글

쓰레드 동기화(synchronization)  (0) 2013.08.14
make 간단 설명  (0) 2013.08.14
모듈 프로그래밍 #2  (0) 2013.08.14
모듈 프로그래밍 #1  (0) 2013.08.14
I/O Method  (0) 2013.08.14

모듈을 커널에 올릴때 insmod 명령어를 사용한다고 앞 모듈 프로그래밍 #1 문서에서 간략하게 설명했다. (솔직히 부실하다.. 추후 좀더 자세하게 모듈이 커널에 올라가는 원리에 대해서 커널 소스를 분석해서 설명해 봐야 겠다)

insmod 명령어가 실행되면 커널은 해당 모듈의 초기화 함수를 호출한다. 또한 rmmod 로 커널에서 모듈을 삭제시는 모듈 삭제 함수가 호출된다.

초기화 함수, 삭제 함수는 모듈 소스에서

module_init

module_exit

이 두 매크로 함수에 정의해준다. 매크로 함수명을 보면 대충 이해갈수 있겠지만 module_init은 초기화 함수, module_exit는 모듈을 커널에서 삭제시 호출된다.

static int hello_module_init(void) 
{ 
	printk("hi~\n"); 
	return 0; 
} 

static int hello_module__exit(void) 
{ 
	printk("I'm exit\n"); 
} 

module_init(hello_init); 
module_exit(hello_exit); 
	

위와 같은 방법으로 매크로 함수에 init 함수와 exit 함수를 등록한다.

'프로그래밍 > 리눅스 드라이버' 카테고리의 다른 글

쓰레드 동기화(synchronization)  (0) 2013.08.14
make 간단 설명  (0) 2013.08.14
GCC 옵션 간단하게 정리하기  (0) 2013.08.14
모듈 프로그래밍 #1  (0) 2013.08.14
I/O Method  (0) 2013.08.14

  커널의 모듈(Module)은 리눅스 커널안에 포함되지 않고 필요시 동적으로 커널과 결합해서 사용하는 커널 프로그램이다. 이 말은 커널을 동적으로 변경으로 필요시 바꿀수 있다는 말과 일치하게 되며, 메모리의 공간적 여유도 확보에 유리할수 있다. (필요 없는 것들은 동작안시키면 되니깐...) 하지만 동적으로 커널과 연결되다 보니 초기 연결시 시간이 오래 걸리고 , 커널 모드 프로그램이므로 잘못된 모듈일 경우 심각한 오류를 발생시킬수 있다.

  모듈을 커널에서 올리고 내리는 명령어는 각각 insmod 와 rmmod 이다. 뭐 리눅스 명령어다 보니 manpage 나 이런거 참조하면 사용방법에 대해서 알수 있을것이다. 모듈이 커널에 올라가게 되면 모듈에서 다른 커널이나 모듈에 제공하는 함수들을 등록한다. 모듈이나 커널에서 제공하는 모든 함수 리스트는 /proc/kallsyms 에서 확인하면 된다.

cat /proc/kallsyms
[함수주소] [함수종류] [함수이름]
0xFFFC420 T Register_Driver

위와 같은 형태로 출력된다.

'프로그래밍 > 리눅스 드라이버' 카테고리의 다른 글

쓰레드 동기화(synchronization)  (0) 2013.08.14
make 간단 설명  (0) 2013.08.14
GCC 옵션 간단하게 정리하기  (0) 2013.08.14
모듈 프로그래밍 #2  (0) 2013.08.14
I/O Method  (0) 2013.08.14

디바이스 레지스터(Device Register)들에 대한 접근 방법은 Memory-Mapped I/OI/O Mapped I/O 가 있다.

Memory-Mapped I/O : 메모리의 일부 공간을 디바이스의 레지스터 공간으로 mapping 한다.

I/O mapped I/O: 메모리와 I/O 영역이 별도의 공간의 저장되어 Memory-Mapped I/O처럼 메모리 용량이 줄어드는 문제는 없어진다. 메모리에 대한 데이터 Access는 Load, Store 로 이뤄지며, I/O 입출력은 Input, Output 으로 이뤄진다.


Memory-Mapped I/O의 레지스터 접근 예)

violatile dword *PMM;
PMM = (volatile dword *)0x000111F3

I/O Mapped I/O 레지스터 접근 )

unsigned inb( unsigned port);
void outb(unsigned char byte, unsigned port);

 

'프로그래밍 > 리눅스 드라이버' 카테고리의 다른 글

쓰레드 동기화(synchronization)  (0) 2013.08.14
make 간단 설명  (0) 2013.08.14
GCC 옵션 간단하게 정리하기  (0) 2013.08.14
모듈 프로그래밍 #2  (0) 2013.08.14
모듈 프로그래밍 #1  (0) 2013.08.14

ATMEGA32L은 3개의 외부 인터럽트(INT0,INT1,INT2)가 존재한다. 위 인터럽트 발생 조건은 다음과 같다.

  1. 하강 엣지
  2. 상승 엣지
  3. 로우레벨
  4. 논리적인 변화

*엣지(edge) : 뭐 내가 하드웨어적인 이해가 부족한 가운데 이 용어에 대해서 이해한 바로는 “어떤 신호가 변화되는 시점”이라 생각한다. 다시 풀이하자면 어떤 신호가 HIGH 레벨( 이진세계에서는 1 )로 계속 발생되고 있는 가운데 변화가 이루어지는 순간 이라고 할수 있다. (이진 세계에서는 1의 변화는 0 이다 ).

3번 로우 레벨 조건은 대충 신호가 일정시간 Low 레벨로 발생 되었을 때 발생한다고 한다. 그 일정시간 수치는 어디에서 어떻게 측정하는지는 모르겠다. 4번 같은 경우는 이건 모르겠다. 인터럽트 발생조건에서 INT2 는 1번과 2번의 엣지에 관련한 조건으로만 인터럽트가 발생한다.

MCUCR 레지스터는 인터럽트 발생조건을 이 레지스터에서 지정할 수 있다. 이 레지스터의 3,2,1,0비트에서 조건을 지정할수 있다.( 0 base ) 이 3,2비트는 INT1 에 관한 조건을 설정을 하고, 1, 0비트는 INT0 에 관해 조건을 설정한다.

  • 0  0 : 로우레벨
  • 0  1 : 논리조건
  • 1  0 : 하강엣지
  • 1  1 : 상승엣지

MCUCRS 레지스터에서는 INT2 인터럽트 조건을 지정한다. 이 레지스터의 6비트에 조건을 설정한다.

  • 0 : 하강엣지
  • 1 : 상승엣지

GICR 레지스터는 INT0, INT1, INT2 레지스터 중 사용할 레지스터를 선택할 수 있는 레지스터이다. 각 7,6,5비트에 INT1, INT0, INT2 순서대로 설정(1)할 경우 각 인터럽트들을 사용할 수 있다.

GIFR 레지스터 각 인터럽트가 발생했을 경우 각 비트에 1로 셋 된다고 하는데 그냥 패쓰…

SREG 레지스터의 7비트는 Global Interrupt 를 사용할 건지 안할건 지 설정하는 부분이 이 부분을 설정해줘야 인터럽트가 발생할 수 있다.

(……..여기까지 이해한 부분……)



'프로그래밍 > 마이컴' 카테고리의 다른 글

I2C 통신  (0) 2013.08.14


I2C가 뭔지 헤메다가 몇자 적는다.

용어적 설명부터

I²C  는 필립스에서 개발한 직렬 컴퓨터 버스이며 마더보드, 임베디드 시스템, 휴대전화등에 저속의 주변 기기를 연결하기 위해 사용된다. I²C 라는 이름은 $2의 약자이며 아이-스퀘어-씨 라고 발음한다.

I²C 는 풀업 저항이 연결된 직렬 데이터(SDA)와 직렬 클럭(SCL)이라는 두 개의 양 방향 오픈 컬렉터 라인을 사용한다. 최대 전압은 +5 V 이며, 일반적으로 +3.3V 시스템이 사용되지만 다른 전압도 가능하다.

I²C 레퍼런스 디자인은 7 비트의 주소 공간을 가지며, 이 중 16개는 예약되어 있으므로, 동일한 버스에 최대 112개의 노드를 연결할 수 있다. 가장 일반적으로 사용되는 I²C 버스의 모드는 표준 모드인 100 kbit/s와, 저속 모드인 10 kbit/s 가 사용된다. 최신 리비전의 I²C 는 보다 빠르게 동작하며, 패스트(fast) 모드인 400 kbit/s와 고속(high-speed) 모드인 3.4 Mbit/s를 지원한다. 최대 1008 노드까지 연결 가능한 10 비트 주소 지정 등의 확장된 기능들을 지원한다.

란다.. 휴!!~~ 처음엔 이 용어 부터도 너무 어려웠다.
우선 용어부터 풀어보자면 필립스에서 개발한 직렬 통신 프로토콜이다?? 뭐 그다지 풀어야 할 내용은 없는데 필립스 에서 개발했다는것만 기억할련다 ^^ 또한 I2C (아이 투 씨), 아이-스퀘어-씨 라고 발음 한다고 한다. 또한 위에서 언급되었듯이 직렬 데이터(SDA)와 직렬 클럭(SCL)이라는 라인을 이용해 통신을 하게 된다. 전압으로 최대 5V 를 이용될수 있으며 3.3V이 보통 사용되지만 다른 전압도 가능하다고 되어 있다. 뭐 SDA 와 SCL 이라는 두 라인으로 I2C 통신을 한다는 말이다.

"SDA라 읽컫는 라인과 SCL 이라 일컫는 라인을 통해 통신을 한다."

또한 I2C는 마스터 모드와 슬레이브 모드 두개가 존재하며 마스터가 슬레이브를 호출하는 형태의 통신이다.

각 슬레이브는 각각 주소(7비트)로 구분되어 지며 112개의 슬레이브가 존재할수 있다.














 I2C 데이터 전송

I2C 데이터 전송 방법은

  • 데이터 전송 시작 : START
  • 데이터 전송지 주소 : Address
  • 데이터 속성 (읽기/쓰기) : R/W
  • 데이터 : Data
  • 데이터 수신 여부 : Ack
  • 데이터 전송 종료 : STOP


즉 데이터 전송시작(START) -> 주소(Address) -> 읽기 또는 쓰기(R/W) ->상대편 수신여부->데이터 -> 상대편 수신여부(Ack) -> 종료 (STOP ) 형태로 데이터를 보내주면 되는 것이다.






 시작 : 1비트
 주소 : 7비트
 읽기 또는 쓰기 : 1비트
 데이터 : 8비트
 수신 여부 : 1비트
 종료 : 1비트

뭐 이런 형태라고 책에는 나와 있는데 처음에는 많이 헤멨다. 저게 무슨 말인지 ㅡㅡ;;;
START와 STOP 은 어떻게 구분하지 라는 의문도 들었다.

뭐 찾아보니 HIGH, LOW 변화로 START 와 STOP 을 구분하게 된다는 설명이다.
START는 SCL 선이 HIGH를 유지하는 상태에서 SDA선이 HIGH에서 LOW으로 변화되는 시점을 시작 이라는 시점으로 판단한다는 거다.
STOP은 SCL선이 HIGH일때, SDA선이 LOW에서 HIGH로 올라가는 시점을 중지 라는 시점으로 판단한다.
그럼 데이터는 ??? 데이터는 SCL이 HIGH에서 LOW로 떨어지는 순간 SDA의 상태(HIGH인지, LOW인지)를 판단하여 1, 0 으로 판단한다고 한다. 모르겠다 ㅡㅡ;;; 그림을 보자.

















자, 그림으로 보면 SCL이 HIGH인 순간 SDA의 상태를 보고 1, 0을 판단하고 있다.
비트전환 이라고 해서 SDA의 값의 전환을 주기 위한 시간도 있다. ㅋㅋㅋ 뭐 대충 알았다. 아니 그냥 알아 들었다고 하고 그냥 어떻게 코드로 표현하는지 보자.

#define SDA_IN          PINC_Bit4
#define SDA_OUT         PORTC_Bit4
#define SDA             PORTC_Bit4
#define SCL             PORTC_Bit5

/*------------------------------------------------------------------------------------------------*/
/*      I2CStart                                                                  */
/*              _____         ________                                                              */
/*      SDA:       |_______|                                                                      */
/*                  ___     ___                                                                     */
/*      SCL:  ___|   |___|   |______                                                              */
/*------------------------------------------------------------------------------------------------*/
void I2CStart(void)
{
    DDRC = 0xFC; // SDA OUTPUT MODE
    SDA_OUT=1;
    USEC_Delay(1);
    SCL=0; USEC_Delay(2);
    SCL=1; USEC_Delay(1);
    SDA_OUT=0; USEC_Delay(1);
    SCL=0; USEC_Delay(2);
    SCL=1; USEC_Delay(1);
    SDA_OUT=1; USEC_Delay(1);
    SCL=0; USEC_Delay(2);
}

위 코드는 I2C 통신을 하기 위해서 START를 보내는 부분이다. START의 판단 조건은 SCL이 HIGH인 상태에서 SDA가 HIGH에서 LOW로 내려가는 시점이라고 했다.
SDA_OUT=1 // SDA가 HIGH 유지
Delay(1)
SCL=0 ; Delay(2); // SCL이 LOW
SCL=1; Delay(1); // SCL을 HIGH로 변환

SDA_OUT=0; Delay(1); // SDA를 HIGH에서 LOW로 변환
SCL=0; Delay(2); // SCL을 LOW로
SCL=1; Delay(1); // SCL을 HIGH로 변경
SDA_OUT=1; Delay(1) // SDA를 HIGH
SCL=0;Delay(2); // SCL을 LOW로..

BYTE I2CWrite_Data(BYTE val)
{
    BYTE i = 0;
    BYTE error = 0;
    DDRC = 0xFC;
    USEC_Delay(1);
    for(i=0x80; i>0; i/=2)
    {
        if (i & val) SDA_OUT = 1;      
        else SDA_OUT = 0;
        USEC_Delay(1);
        SCL = 1; USEC_Delay(1);
        SCL = 0; USEC_Delay(1);
    }
    SDA_OUT = 0; USEC_Delay(1);
    SCL = 1;
    error = SDA_IN; USEC_Delay(1);
    SCL = 0; USEC_Delay(1);
    SDA_OUT = 1; USEC_Delay(1);
    return error;
}
BYTE I2CRead_Data(BYTE ACKn)
{
    BYTE i,val=0;
    DDRC = 0xEC;
    for (i=0x80;i>0;i/=2)
    {
        SCL=1;
        if (SDA_IN) val=(val | i); USEC_Delay(1);
        SCL=0; USEC_Delay(1);
    }
    DDRC = 0xFC;
    SDA_OUT=!ACKn;
    SCL=1; USEC_Delay(1);
    SCL=0; USEC_Delay(1);
    SDA_OUT=1;
    return val;
}
void I2CStart(void)
{
    DDRC = 0xFC; // SDA OUTPUT MODE
    SDA_OUT=1;
    USEC_Delay(1);
    SCL=0; USEC_Delay(2);
    SCL=1; USEC_Delay(1);
    SDA_OUT=0; USEC_Delay(1);
    SCL=0; USEC_Delay(2);
    SCL=1; USEC_Delay(1);
    SDA_OUT=1; USEC_Delay(1);
    SCL=0; USEC_Delay(2);
}
void I2CStop(void)
{
    DDRC = 0xFC; // SDA OUTPUT MODE
    SDA_OUT=0;
    USEC_Delay(1);
    SCL=0; USEC_Delay(2);
    SCL=1; USEC_Delay(1);
    SDA_OUT=1; USEC_Delay(1);
    SCL=0; USEC_Delay(2);
}
void main()
{
 Data = 0x40;
 I2CStart();      // START
 I2CWrite_Data( 0x07 ) // Address (3)
 I2CRead_Data(1)    // ACK
 I2CWrite_Data(Data); // Data
 I2CRead_Data(1);   // ACK
 I2CStop();      // STOP
 
}


위 코드는 슬레이브(0x03, 000 0011) 에게 쓰기 모드로 데이터 0x40을 전송하는 코드이다.

부랴부랴 이해했던 내용을 작성하려다 보니 내용상 허술하기도 하고 부실하기도 하다.

'프로그래밍 > 마이컴' 카테고리의 다른 글

ATMEGA32L External Interrupt  (0) 2013.08.14

+ Recent posts