티스토리 뷰

ARM Cortex-M

I2C

Just4Fun 2017. 4. 22. 09:16

이번 글에서는 stm32f103에 있는 I2C를 동작시키는 방법에 대해서 설명하겠다.

I2C는 TWI 혹은 TWSI라고 불리기도 하는데 AVR 입문과정중 TWI(I2C)에서 I2C에 대한 동작 원리는 이미 설명하였으므로 이번 글에서는 stm32f103에 있는 I2C를 통해서 데이터를 송수신하는 방법에 대해서만 설명할 예정이다.

stm32f103 reference manualAN2824 STM32F10xxx I2C optimized examples라는 문서를 참고하면 I2C가 어떻게 동작되는지 자세한 내용을 살펴 볼 수 있다.

먼저 블럭도를 보고 i2c 블럭에는 어떤것들이 어떻게 연결되어 있는지 전체적으로 분석해 본다.

stm32f103의 i2c는 크게 세 부분으로 구성되어 있다고 볼 수 있다.

데이터 송수신을 제어하기 위한 control logic이 있고, 데이터 송수신 속도를 조정하기 위한 Clock control 부분과 데이터를 내 보내고 수신한 데이터가 저장되는 data control 부분이 있다.

특히, i2c 수신 절차를 이해하기 위해서는 Data shift register라는 것이 무엇인지 알아야 한다.

I2C 통신은 하나의 신호선을 이용한 serial 통신이므로 비트 단위로 데이터를 전송하게 된다.  이런 방식으로 들어오는 serial 데이터는 data shift register에서 차례로 모아서 1바이트의 데이터로 만든다.  이렇게 만들어진 1바이트 데이터는 data register로 보내져서 CPU가 읽어 갈 수 있도록 해준다.  그러나 만약 CPU가 data register에 있는 값을 읽어 가지 않으면 그 data는 계속 data register에 남아 있게 되고, data shift register 또한 data register에 값을 넘겨 줄 수 없게 되므로 계속 같은 데이터가 머물러 있게 된다.

비로소 CPU가 data register에서 값을 읽어 가는 순간 data register가 비워지게 되고, shift register에 있던 data가 data register로 이동하게 된다.

stm32f103의 i2c 블럭은 CPU가 모든것을 제어하는 polling 모드가 있고, DMA를 이용하는 DMA모드, 그리고 interrrupt를 이용하는 interrupt 모드가 있다.

여기에서는 polling 모드에 대해서만 설명하겠고, stm32f103에 있는 두개의 I2C 블럭중 I2C1 만을 사용하는 코드를 만드는 방법에 대해서 설명하도록 하겠다.  또한 stm32f103이 master로 동작하고 7bit 모드로 동작한다는 조건으로만 설명한다.


그럼, 먼저 비교적 쉬운 master transmitter부터 설명하도록 하겠다.

위의 그림이 master에서 data를 송신하는 절차에 대해서 설명하는 그림이다.

CR1에 있는 "START" 비트를 1로 만들면 master 모드로 자동으로 절체되고 i2c로 start 신호가 나가게 된다.  start 신호가 정상적으로 나가게 되면 SR1 레지스터의 "SB" 비트가 1로 변하게 되므로 이 값을 polling 한 후 다음 단계로 넘어간다.

DR 레지스터에 slave address를 써주면 i2c로 slave address 값이 나가게 되고, 정상적으로 내 보내게 되면 SR1레지스터의 "ADDR" 비트값이 1이 된다.

Address data가 모두 나가게 되면 data register와 shift register 모두 empty 상태가 되므로 그 상황에서 첫번째 data를 data register에 써주게 된다.  그러나 실제 코드에서는 shift register가 not empty 상태가 되면 data register는 empty 상태가 되었다는 의미가 되므로 즉시 data register에 새로운 값을 써주도록 하고 있다.

모든 data를 내 보내면 CR1에 "STOP" 비트를 설정해 주어 송신 절차를 끝내게 된다.

송신 신호가 i2c를 통해서 정상적으로 나가게 되면 STOP 비트 값이 clear 된다.

Flow chart로 표시하면 위의 그림과 같이 되고, 이를 참고하여 i2c_tx 함수를 만들면 다음과 같이 된다.

7번 줄에서 start 신호와 더불어 slave address를 송신한다.

10번 줄에서 slave에 있는 register 번호를 송신한다.

12~17까지 buf에 있는 데이터를 차례로 내 보내는 동작을 수행한다.

19~20에서 마지막으로 stop 신호를 내보내고 완료되는 것을 확인한 후 write 기능을 끝마치게 된다.

위의 코드가 start 신호와 slave address를 내 보내 주는 코드이다.


master receiver 동작은 조금 복잡한데, 수신하고자 하는 데이터의 크기가 1바이트인 경우와 2바이트인 경우 그리고 3바이트 이상인 경우에 따라 조금씩 다르기 때문이다.

위의 그림이 1바이트 데이터를 수신하기 위한 동작이다.  Slave로 부터 데이터를 수신하게 되면 정상적으로 수신했다는것을 알려주기 위하여 ACK신호를 보내주도록 되어 있는데, 수신을 종료하고자 할때에는 NACK신호를 주어 slave가 더이상 데이터를 보내주지 않도록 해 주어야 한다.

1바이트 수신의 경우 데이터 수신과 동시에 NACK 신호를 주어야 하기 때문에 slave address 데이터를 내 보낸 즉시 CR1에 있는 "ACK"비트 값을 0으로 만들어 주어야 한다.

또한, 그 다음에 바로 STOP 신호도 내 보내도록 설정한다.  이렇게 하더라도 하나의 데이터는 DR 레지스터에 들어와 있게 되므로 "RXNE" 비트값이 설정될때까지 기다리다가 RXNE비트 값이 설정되면 data register에 값이 들어와 있으므로 읽어 오면 되는 것이다.


위의 그림이 2바이트 값을 slave로 부터 읽어 오는 절차를 설명하고 있다.

slave address를 내 보내는 동작이 완료 된 것을 확인한 다음 ACK 비트를 clear 한다.  그리고 난 다음 2개의 데이터를 수신하는 동작을 수행해야 하는데, 첫번째 데이터가 들어올 때에는 ACK 신호를 내 보내 줘야 하고 두번째 데이터에서는 NACK 신호를 내 보내 주어야 한다.  그러나 이렇게 짧은 시간동안 이러한 동작을 수행하기가 어려우므로 이러한 특별한 상황을 처리하기 위하여 start 신호를 내 보내기 이전에 CR1레지스터에 있는 "POS" 비트값을 1로 설정해 준다.  그러면 하드웨어적으로 ACK와 NACK신호를 순차적으로 내 보내 줄수 있게 해준다.

첫번째 데이터는 data register에 들어가고 두번째 데이터가 shfit register에 들어온것을 확인한 후 stop 신호를 내 보내도록 하고, 그 이후에 data register에서 두번의 읽기 동작을 수행하게 되면 차례로 2개의 데이터를 읽어 올 수 있게 된다.

1바이트와 2바이트 값을 수신하기 위한 절차를 위의 그림처럼 flow chart로 표시할 수 있다.


3바이트 이상인 값을 수신하기 위한 절차는 다음과 같다.

데이터를 정상적으로 수신하는 절차를 수행하다가 3바이트의 데이터만 남아 있게 되는 경우, 이미 마지막 세번째 데이터는 data register에 있고 마지막 두번째 데이터는 shfit register에 있게 되는데 이때 ACK 비트를 0으로 만든다.

그 다음에 일단 data register에서 1바이트 값을 읽어 온 후 stop 신호를 내 보낸다.

그렇게 되면 마지막 두번째 데이터가 data register로 옮겨가 있으므로 data register에서 읽어 오면 되고, 마지막 데이터마저 data register에 들어온 것을 확인 한 후 읽어 오면 된다.

i2c_read 함수 코드는 다음과 같이 만들 수 있겠다.

7~12까지는 slave의 어떤 레지스터에서부터 데이터를 읽어 올 것인지를 알려주기 위하여 slave register 번호를 보내 주는 코드이다.

16~20은 repeated start 신호를 내 보내어 본격적인 읽기 동작을 시작하는 코드이다.

22~29까지가 1바이트 데이터를 수신하기 위한 코드이다.

30~42까지가 2바이트 데이터를 수신하기 위한 코드이다.

44~70까지가 3바이트 이상의 데이터를 수신하기 위한 코드이다.


AVR 입문과정에서 TWI 글에서 사용하였던 PCF8563 모듈을 사용하여 i2c 기능을 확인해 보도록 하겠다.

15~17은 I2C의 신호선인 SDA, SCL을 alternate I/O로 설정해주는 코드이다.

20~21은 I2C에 클럭을 제공한 후 i2c 데이터 속도를 400khz로 설정해 주는 코드이다.  i2c_init() 함수는 첨부된 파일과 reference manual을 분석하면 된다.

23~24는 PCF8563의 초기값을 설정해 주기 위한 코드이다.

28번 줄은 pcf8563에서 데이터를 읽어 오는 코드이다.

35~43은 초단위 값이 변경된 경우 콘솔 화면에 출력해 주는 코드이다.

프로그램을 컴파일 한 다음 보드에서 실행하여 정상적으로 동작되는지 확인해 본다.



i2c.zip


'ARM Cortex-M' 카테고리의 다른 글

DMA  (2) 2017.05.13
SPI  (3) 2017.05.03
시스템 클럭 72MHz로 동작 시키는 방법  (0) 2017.04.19
ADC  (3) 2017.04.15
ST-Link/V2 SWD 연결 문제 해결  (4) 2017.04.15
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2024/05   »
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
글 보관함