Interfacing Peripherals

I/O Devices

device는 digital/non-digital component를 가지고 있을 수 있다.

UART device를 생각해보자.
CPU와 register는 상호 간에 read, write를 하고 I/O mechanism이 CPU에게 투명하게 보인다.

Interfacing Peripherals

  • Port-mapped I/O
    special CPU instruction을 사용한다. special_instruction Reg, Port의 형태이다.

  • Memory-mapped I/O
    I/O deivce를 interface하기 위해 port-mapped I/O와 비슷하지만 더 편리한 방법을 사용한다.
    각 device register는 microprocessor의 address space에 있는 memory address에 할당된다.
    native CPU load/store instruction을 사용한다. LDR/STR Reg, [Reg, #imm].

(memory-mapped, port-mapped I/O 참고)

ARM Memory-Mapped I/O

device를 위한 location(address)가 정의되어 있다.

.equ	DEV1, 0x40010000

read/write assembly code를 사용한다.

LDR		r1, =DEV1		; set up device address
LDRB	r0, [r1]		; read byte from DEV1
MOV		r0, #8			; set up value to write
STRB	r0, [r1]		; write value to device

위의 과정은 아래의 C code와 동일한 역할을 한다.

Var1 = *(char*)DEV1;	// read from DEV1 to variable
*(char*)DEV1 = Var1;	// write variable to DEV1

Timer

timer은 free-run counter이다. 즉, processor와 독립적으로 동작한다.
input capture, output compare, pulse-width modulation(PWM) generation 기능을 가지고 있다.

Clock

1초를 세려면 원래 세야 할 clock의 개수를 나타내는 원래 진동수를 f_(CL_PSC)라고 한다.
하지만 이 수는 너무 큰 수여서 불편함이 많기 때문에 이를 피하고자 prescaler로 주기를 나눠서 prescaler마다 한 clock을 세도록 바꿀 수 있다 (참조).

Reload Value를 조정하면 timer interrupt가 발생하는 주기를 조정할 수 있다.
reload value는 Cortex-M3 기준으로 0x00000001-0x00FFFFFF가 될 수 있다. 0도 넣을 수 있긴 하지만 의미가 없다. 동작하는 방식을 보면 이해가 된다.

만약 어떤 prcessor가 100의 clock cycle마다 timer interrupt가 발생하게 만들고 싶으면 RELOAD를 (100-1)인 99 로 만들어주면 된다 (ARM 문서 참조).

위에서 RELOAD의 최대가 0x00FFFFFF라는 것은 timer의 최댓값임을 의미한다. 여기서 timer의 clock이 0x01000000이 되면 overflow가 발생하면서 timer interrupt가 발생하게 되는 구조이다.

따라서 RELOAD에 99를 넣으면, timer의 초기값이 0x00FFFFFF - 99 가 되면서 매 clock이 지날 때마다 0x00FFFFFF - 98, 0x00FFFFFF - 97... 이렇게 되다가 100번째 clock이 발생하면 0x00FFFFFF - (-1) = 0x01000000이 되면서 interrupt가 발생하는 것이다 (참조).

Input Capture

별거 없다. 외부에서 들어오는 신호를 자신의 timer와 비교해서 주기 및 주파수를 파악하는 것.

Output Compare

Output Compare은 counter값이 CCR값과 동일할 때 interrupt를 발생시킨다.
comparator에 OCM을 설정하면 그것에 맞게 다룰 수 있는듯.

PWM (Pulse-Width Modulation) Generation

그림이랑 표 보면 대충 어떤 느낌인지 이해가 간다.
reference signal 기준으로 counter의 값이 작을 때 true이거나 클 때 true가 되는 것.

PWM Mode 1 (Low-True)

counter가 ARR에 도달하면 counter값이 0이 된다.

1 clock 당 counter의 값이 1 씩 증가한다.

PWM mode 1에서는 low-true이기 때문에, counter의 값이 CCR보다 작을 때 true이다.
따라서 OCREF(CCR을 통해 결정된 timer값)는 counter가 CCR보다 작을 때 high, 클 때 low를 갖게 된다.

duty cycle은 신호의 한 주기에서 신호가 켜져 있는 비율이다.
counter가 0부터 시작하기 때문에 ARR에 1을 더해주면, 총 counter가 7번 증가할 동안 3번이 high였으므로 3/7 이 된다.

PWM Mode 2 (High-True)

PWM mode 2에서는 mode 1과는 다르게 high-true이기 때문에 counter의 값이 CCR보다 클 때 true이다.
따라서 OCREF의 결과가 mode 1의 결과에서 반전된다.

counter가 0부터 시작하기 때문에 ARR에 1을 더해주면, 총 counter가 7번 증가할 동안 4번이 high였으므로 duty cycle은 4/7 이 된다.

General Purpose Input / Output (GPIO)

GPIO port는 A, B, C, D, E, F, G, H로 총 8개가 있고 각 port마다 16개의 pin이 있다.

Red LED (PB.2)

GPIO Ports

Basic Structure of an I/O Port bit: Output

GPIO Memory Map (STM32L4)

STM32L4에서 peripheral이 사용하는 memory 영역은 0x40000000부터 0.5GB인데 이 때 GPIO A0x40000000에서 바로 시작하는 것이 아니라 0x48000000부터 시작함에 유의하자.

GPIO Mode Register (MODER)

GPIO Output Type Register (OTYPE)

OTy가 0일 때 push-pull을 사용하고 1일 때 open-drain을 사용한다.

GPIO Output

Push-Pull

양쪽에 스위치가 2개 달린 형태이다.
CPU로부터 GPIO output bit 1이 써지면 PMOS 스위치가 on되고 NMOS 스위치가 off되면서 내부의 VccGPIO output pin에 걸려 외부로 출력된다.
CPU로부터 GPIO output bit 0이 써지면 PMOS 스위치가 off되고 NMOS 스위치가 on되면서 외부의 전류가 ground로 흘러 들어와 전압이 0V가 된다.

Open-Drain

push-pull과는 달리 스위치가 하나만 달린 형태이다.
불완전한 형태이기 때문에 출력을 high/low로 설정해주기 위해서는 외부의 도움이 필요하다.
CPU로부터 GPIO output bit 0이 써지면 NMOS 스위치가 on되면서 output pin이 ground와 연결되어 0V가 된다.
CPU로부터 GPIO output bit 1이 써지면 NMOS 스위치가 off되면서 연결된 곳이 없어 output이 floating state가 된다.

그 상태에서 외부에 pull-up 저항을 달면 floating state를 통해 저항에 맞는 원하는 전압의 high signal을 사용할 수 있다.

GPIO Output Data Register (ODR)

Basic Structure of an I/O Port bit: Input

Schmitt Trigger

신호는 analog로 들어오지만 결국 이걸 digital로 바꿔서 사용을 해야한다.

analog 신호는 noisy하고 rise와 fall이 천천히 일어난다는 특징이 있다.
이걸 digital form으로 바꾸기 위해서는 naive하게 threshold를 설정해주는 방법이 있다. threshold 아래이면 0, 위면 1로 설정하는 것이다.

하지만 그렇게 설정하면 신호가 너무 unstable해진다. 아래의 그림을 보자.
simple comparator 부분을 보면, threshold를 기준으로 아주 살짝만 올라가거나 내려도 신호가 바뀌어버리기 때문에 상당히 불안정하다.
schmitt trigger은 immunity band를 이용해서 threshold를 그냥 적용했을 때보다 더 안정적인 신호를 얻을 수 있다.

immunity band는 V_TLV_TH가 있다.
V_TL은 trigger low를 의미하고 V_TH는 trigger high를 의미한다.

schmitt trigger은 신호가 trigger high(V_TH)에 도달하기 전까지 low 상태를 유지한다.
그리고 신호가 trigger low(V_TL)에 도달하기 전까지 high 상태를 유지한다.

GPIO Mode Register (MODER)

GPIO Pull-up / Pull-down Register (PUPDR)

GPIO Input: Pull Up and Pull down

GPIO Data Register (IDR)

Serial Communications

Universal Asynchronous Receiver and Transmitter (UART)

UART는 asynchronous하다. 즉, sender가 receiver에게 clock signal을 제공하지 않는다.

Data Frame

sender와 receiver는 같은 transmission speed를 사용한다.

data frame에는

  • 1 start bit
  • data (LSB first of MSB, 7~9 bits)
  • parity bit (optional)
  • 1 혹은 2 stop bit
    이 들어있다.

Baud Rate

원래는 전화와 관련해서 매 초 물리적으로 transfer되는 pulse의 개수를 나타냈다.
하지만 digital communication에서는 매 초 물리적으로 transfer되는 bit 수를 나타낸다.

Serial Peripheral Interface (SPI)

Data Exchange

SPI의 master와 slave는 large circular queue의 형태로 1 bit씩 data를 주고받는다.
master가 clock(SCLK)를 제공하기 때문에 clock에 맞춰 synchronous exchange를 한다.

Inter-Integrated Circuit (I2C)

open-drain이 각 device간의 충돌을 피할 수 있게 해준다.
만약 위의 세 node가 전부 master라고 가정했을 때, 모든 node가 SDA를 ground로 바꾸고 싶다면 전체 SDA는 0이 될 것이다.

하지만 만약 세 master 중 두 master는 SDA를 1로 만들고 싶은데 한 master는 0으로 만들고 싶다면 전체 SDA는 0으로 취급된다 (wired-AND bus).
high impedance state(floating state)는 실제 voltage level을 표현할 수 없기 때문이다.

Timing Diagram

0개의 댓글