device는 digital/non-digital component를 가지고 있을 수 있다.
UART
device를 생각해보자.
CPU와 register는 상호 간에 read, write를 하고 I/O mechanism이 CPU에게 투명하게 보인다.
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 참고)
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은 free-run counter이다. 즉, processor와 독립적으로 동작한다.
input capture, output compare, pulse-width modulation(PWM
) generation 기능을 가지고 있다.
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가 발생하는 것이다 (참조).
별거 없다. 외부에서 들어오는 신호를 자신의 timer와 비교해서 주기 및 주파수를 파악하는 것.
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 이 된다.
GPIO
)GPIO
port는 A
, B
, C
, D
, E
, F
, G
, H
로 총 8개가 있고 각 port마다 16개의 pin이 있다.
PB.2
)GPIO
PortsGPIO
Memory Map (STM32L4
)STM32L4에서 peripheral이 사용하는 memory 영역은 0x40000000
부터 0.5GB인데 이 때 GPIO A
가 0x40000000
에서 바로 시작하는 것이 아니라 0x48000000
부터 시작함에 유의하자.
GPIO
Mode Register (MODER
)GPIO
Output Type Register (OTYPE
)OTy
가 0일 때 push-pull을 사용하고 1일 때 open-drain을 사용한다.
GPIO
Output양쪽에 스위치가 2개 달린 형태이다.
CPU로부터 GPIO output bit
1이 써지면 PMOS
스위치가 on되고 NMOS
스위치가 off되면서 내부의 Vcc
가 GPIO output pin
에 걸려 외부로 출력된다.
CPU로부터 GPIO output bit
0이 써지면 PMOS
스위치가 off되고 NMOS
스위치가 on되면서 외부의 전류가 ground로 흘러 들어와 전압이 0V가 된다.
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
)신호는 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_TL
과 V_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 downGPIO
Data Register (IDR
)UART
)UART
는 asynchronous하다. 즉, sender가 receiver에게 clock signal을 제공하지 않는다.
sender와 receiver는 같은 transmission speed를 사용한다.
data frame에는
원래는 전화와 관련해서 매 초 물리적으로 transfer되는 pulse의 개수를 나타냈다.
하지만 digital communication에서는 매 초 물리적으로 transfer되는 bit 수를 나타낸다.
SPI
)SPI
의 master와 slave는 large circular queue의 형태로 1 bit씩 data를 주고받는다.
master가 clock(SCLK
)를 제공하기 때문에 clock에 맞춰 synchronous exchange를 한다.
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을 표현할 수 없기 때문이다.