포스트

7. Device Control and System Architecture

Embedded Recipes

목차


ⓐ Device를 control 한다는 것


흔히 말하는 Device란, MCU 외부에 달려있는 외부 IC를 말함

interface 보통 다음과 같은 인터페이스들이 존재

  • CS/ 혹은 CE/ : Chip Selection. Chip Enable
    • 평소에 Pull up 되어있는 핀. Low로 만들면 이 칩을 사용하겠다는 의미
  • Data : 양방향 pin. 명령어, 상태 등을 MCU와 pin이 서로 전달 받는 통로
    • 병렬 BUS로 여러 가닥이거나, I2C나 PSI등으로 한가닥일 수 있음
  • CLK : 클럭
  • 이 외에도 OE/ AVD/ 등 부가적인 핀들

외부 I/C에 명령을 내리는 과정

1
2
3
4
5
1. CE/ CS/를 LOW로 설정
2. Device에 명령어 binary sequence를 data line을 통해 전송
3. Device에 명령어가 전달 되었는지 잠시 대기
4. Device가 명령어를 제대로 처리했는지 Data Line을 통해 상태를 전달 받음 (ACK)
5. CE/ CS/를 다시 HIGH로 설정

디바이스들 마다 다른 시퀸스가 추가되거나 변경 될 수 있음

중요한 것은 Timing Specification. 최소 대기 시간, 최대 대기 시간 등

spec

CLK 2개 주기 동안 일어나는 일을 예시로 듬

  • CS_N (CE/)가 MCLK(메인 CLK)이 High end일때 LOW로 같이 떨어짐

  • t(ard)이후 OE_N을 LOW로 떨어트리면, DATA가 NOR Memory로 부터 출력됨

    • t(rds1)시간 만큼 data가 유지 되어야 MCU가 DATA를 capture 할 수 있음

ⓑ Register를 Setting 한다는 것과 Memory Mapped IO


Register를 세팅한다는 건 무슨 말일까

Device들의 User Manual이나 Data sheet를 보면, Software interface로 Register book을 제공함

엄청나게 많은 Register들과 그것들의 주소, 각 bit들의 의미를 나열해 둠

mcu

PWR_CFG라는 레지스터를 예시로 설명

  • 주소는 0x7E00F804
  • R/W 가능
  • 처음 리셋 되었을 때 value는 0x00000001
  • 32bit

pwg_CFG

각 비트에 대한 설명. 이런식으로 각 비트가 어떤식으로 사용되는지 표기됨

즉, Register를 설정한다는 것은 1) 설정하고자 하는 Register의 주소에 2) 설정하고자 하는 값을 쓰는 것

1
2
3
4
5
6
7
8
9
10
typedef long unsigned int dword  
volatile dword *pwr_cfg;  
pwr_cfg = (volatile dword *)0x7E00F804  
  
void set_pwr_cfg(dword value)  
{  
	*pwr_cfg = value  
}

set_pwr_cfg(0x800);

주의. Register의 크기만큼씩 Access 가능함

ⓒ Memory Device를 Control 한다는 것


메모리 디바이스를 컨트롤 한다는 것은, 양방향 디바이스를 컨트롤 한다는 것과 같음

device

RAM 의 기본 모양. 24개의 Address line, 16개의 Data line, CS/ OE/(output enable)

  • 16개의 data line -> 한번에 16bit씩 읽을 수 있음
  • 24개의 address line -> 2^24 만큼의 주소 구별
  • 총 16MB의 크기
  • OE/(output enable) : Output 설정시, 메모리 입장에서는 출력(Output). Input설정 시 쓰기(Write)

메모리 읽기

1
2
3
4
5
1. CE/를 LOW로 설정
2. OE를 High로 설정 
3. Address Line에 읽기 원하는 주소를 binary 형태로 설정
4. Data line에 뜬 16bit data를 읽어감
5. CE/를 High로 설정

메모리 쓰기

1
2
3
4
5
1. CE/를 LOW로 설정
2. OE를 LOW로 설정
3. Address Line에 읽기 원하는 주소를 binary 형태로 설정
4. Data Line에 16bit Data 쓰기
5. CE/를 HIGH로 설정

ⓓ Bus Sizer Register와 Memory Controller - 메모리 확장구성과 CS와의 관계


기본적인 메모리 시스템 구조는 MCU 내부에 CPU core, 이를 위한 Memory controller가 있고, 이를 통해 외부의 메모리에 접근, 읽기/ 쓰기 동작 수행함

mc

코어에서 메모리를 제어하기 위해 발생시킬 수 있는 신호 존재

A[31:0]: 32 bit짜리 Address

D[31:0]: WORD 사이즈 데이터

nRD : OE에 관계된 Read하겠다는 신호

nWR : 마찬가지로 Write하겠다는 신호

nWait : 외부 메모리가 Processor보다 느릴 경우, 프로세서를 대기시키는 신호

한번에 16bit Data Access 가능. Address의 경우, 4GB를 만들어 낼 수 있음

  • 2byte의 칸이 2^32개 존재 -> 2^33 byte -> 2^30 바이트는 1GB이므로, 총 8GB

실제 메모리가 64MB 짜리가 달려있다면, Address line은 26개, Data line은 8개로 바꿔주는 회로가 별도로 필요

이게 Memory Controller, Bus Sizer임

ⓔ 특이한 Device Interface의 CS와 Address의 이용 - LCD


LCD 또한 Interface를 가지고 있음 LCD의 메모리맵 예시

1
2
3
4
0x00000000 SDRAM_CS0_N 32MB
0x08000000 SDRAM_CS1_N 32MB
...
0x20000000 LCD_CD_N 3MB
  • SDRAM 사용. 32MB까지 Access 가능. Chipselect 는 Low Active 등
  • LCD는 0x2000000번지에 3MB만큼의 address 영역을 가지고 있음
    • 0x20000000 번지부터 3MB 사이의 주소를 Access 하면, LCD의 chip select를 사용할 수 있음

lcd

LCD Controller는 3개의 Input을 가짐. CS/, ADS, Data

  • CS/ : Chip Select. LCD 사용 시 LOW
  • ADS : 현재 데이터가 command인지, data인지 여부
  • Data : 0x20000000 ~ 0x202FFFF 사이의 주소를 Access하면, 자동으로 LCD_CS_N이 LOW로 떨어짐. Command를 주고 싶을 때는 LCD Controller의 ADS에 High를, Data를 주고 싶을 때는 Low를 주면 됨
1
2
3
4
5
#define Main_LCD_Write_cmd (cmd)   (*(volatile word *)(0x200000080) = cmd  
#define Main_LCD_Write_data (data)   (*(volatile word *)(0x200000000) = data  
   
Main_LCD_Write_cmd (0xABCD);  
Main_LCD_Write_data (0x1234);

LCD Controller 내부의 RAM을 GRAM이라 부름

ⓕ Shadow의 개념과 Bit operation


  • Shadow : 쓰기만 가능한 레지스터들을 전역변수에 backup해 두고, 읽을 수 있게 하는 개념
    • 대부분 Register에 많이 사용함.
  • Register는 Bit별로 설정이 가능한 Latch이므로, Bit 연산자를 주로 사용함
  • LSB로부터 6번째 bit가 어떤 값인지 확인하고 싶다면
    1. if(reg_data & 0x20)로 6번째 값을 확인 가능.
      • 이런 0x20값을 Mask라고 함
    2. 혹은 Shift 연산자를 이용해 원하는 bit 값을 빼냄. if(reg_data >> 6 & 0x1) 혹은 if(reg_data & (1<<6))
  • 반대로 값을 설정하거나, Clear 하거나, 반전 시키는것도 가능
  • 설정할 때는
    • reg_data = reg_data | 0x80 혹은 reg_data = reg_data = reg_data | (0x1 << 3)
  • clear할 때는
    • reg_data &= ~(1<<3)
  • 반전 시킬때는 XOR을 이용
    • reg_data ^= (1<<3)
  • 비트 필드를 사용하여 bit 단위로 관리 가능
1
2
3
4
5
typedef struct {  
	int32 flag : 3;   /* flag 3 bit */  
    data_1 : 20 ;  /* data_1 : 20 bit */  
    data_2 : 9 ;   /* data_2 : 9 bit */  
} REGISTER_SHADOW;

ⓖ C의 조미료 MACRO Technics


  • Register 설정 등을 Macro를 통해 쉽게 관리 가능

  • 여러줄을 매크로로 설정하는법

1
2
3
4
#define CRITICAL_IO_IN() \  
critical_section_in(); \  
ret = io_read (); \  
critical_section_out();
  • Macro도 인자를 받을 수 있음
1
2
3
4
#define CRITICAL_IO_IN (CURRENT, IO, PREVIOUS) \  
critical_section_in(DEVICE_##CURRENT##_BUFFER); \  
ret = io_read (IO_##IO##_NUM); \  
critical_section_out(DEVICE_##PREVIOUS##_BUFFER);

##를 이용해 Argument를 넣을 수 있음

CRITICAL_IO_IN (CURRENT, IO, PREVIOUS); 를 호출하면

1
2
3
critical_section_in(DEVICE_BOOTUP_BUFFER);  
ret = io_read (IO_USB_NUM);  
critical_section_out(DEVICE_STARTUP_BUFFER);

과 같이 자동으로 변환됨

1
2
3
#define DEVICE_BOOTUP_BUFFER 1  
#define DEVICE_STARTUP_BUFFER 3  
#define IO_USB_NUM 2

가 선언되어있다면

1
2
3
critical_section_in(1);  
ret = io_read (2);  
critical_section_out(3);

로 자동으로 변환됨

  • 예시 ) 이를 응용하여 Register control 하는법
    • MUC의 clock을 설정할 수 있는 주소가 0xC000CB00, 32bit reegister. LSB bit 2, 3이 MCU의 Data이고 R/W가 가능한 레지스터.
    • 0x0 : disable, 0x1 : enabble, 0x2 : Clock의 주기를 반으로, 0x3 : Clock의 주기를 두배로
1
2
3
4
5
6
7
8
9
#define HWCIO_MCU_CLK_ADDR 0xC000CB00  // 주소
#define HWCIO_MCU_CLK_MSK 0x3   // 마스킹
#define HWCIO_MCU_CLK_SHIFT 0x2   // 

// 설정 
#define HWCIO_MCU_CLK_DIS_VALUE 0x0  
#define HWCIO_MCU_CLK_EN_VALUE 0x1  
#define HWCIO_MCU_CLK_TWICE_VALUE 0x3  
#define HWCIO_MCU_CLK_HALF_VALUE 0x2  

다음과 같이 매크로 정의 후,

1
2
3
4
#define IO_OUT (target, val) \  
(*((volatile dword *) (HWCIO_##target##_ADDR)) =\  
((dword) (HWCIO_##target##_##val##_VALUE & HWCIO_##target##_MSK\  
)<

IO_OUT(MCU_CLK, MCU_CLK_TWICE);를 호출하면

1
2
3
(*((volatile dword *) (HWCIO_MCU_CLK_ADDR)) =\  
((dword) (HWCIO_MCU_CLK_TWICE_VALUE & HWCIO_MCU_CLK_MSK\  
)<

로 자동으로 MCU_CLK으로 치환되어 호출됨

  • do while을 이용한 MACRO

ⓗ Synchronous와 Asynchronous


  • MCU Clock과 동기가 맞는지 아닌지 여부
  • MCU로 부터 Clock 신호가 붙어있으면 Synchronous, 아니라면 Asynchronous
  • Synchronous는 MCU와 제때 Data를 원할하게 주고 받을 수 있음
  • Asynchronous는 Latency 가 발생할 수 있음

ⓘ Wait State 이야기


  • MCU가 자신보다 느린 메모리 장치를 다룰 때, Wait State라는 방법을 사용함
  • RD/를 구동ㅅ킨 후에 일정 시간이 지나야 제대로 된 Data값을 돌려준다면, 일정시간 대기해야함
    • 제대로 된 값을 돌려주기로 기대하는 시간이 Wait State
  • 보통 Device Specification에 몇 clock 이후 제대로 된 Data가 나온다고 명시되어있음
  • 최소 Wait State를 잘 설정해주어야 메모리가 최대 성능을 낼 수 있음

tce

  • NOR Memory의 Device Spec 예시
    • tCE 가 Low로 설정된 후, 일정 시간 후 DQ에 valid data output이 제공됨

dq

  • tCE Min이 80이라고 서렴ㅇ되어있음. 80ns이후, data가 확실하게 나옴
  • MCU에서 tACSDV 예시
    • tACSDV = (T-21) + WT 라고 설명되어있다면
    • 최소한 80ns를 기다려야하고, (T-21) + WT가 최소한 80ns가 되어야 한다는 뜻
    • T는 CPU Clock의 주파수 주기
      • 시스템이 40MHz짜리 시스템이라면, T = 1/40MHz = 0.25 * 10^-7 = 25ns
      • T-21 + WT > 80ns 에 대해 정리하면,
      • W x 25 > 76
      • Wait State는 정수이므로 3은 fail, 4는 pass

ⓙ PLL과 M/N:D


  • Clock은 PLL이라는 회로를 통해, 일정한 주파수를 생성 함
    • PLL(Phase Locked Loop)
  • 기준 주파수인 TCXO를 통해서 원하는 주파수의 Clock을 생성함

pll

  • 100MHz 주파수를 생성하기 위한 필요 회로
  • VCO : Voltage Controlled Oscillator를 통해 원하는 주파수 전압을 생성함
    • VCO만 쓰면 주위 환경에 대한 변덕이 심해져서, VCO output을 sampling함

ppl2

  • MCU 내부에 안정적인 주파수를 생성해 내는 on-chip PPL이 다수 존재

mnd

  • M:N/D counter를 이용한 clock 구성
    • M배, 1/N배 하여 원하는 clock을 구성함
  • Clock Register 중에서 Source를 여러가지 준비해두어, 고를 수 있도록 제공하는 경우도 있음
  • 이를 다시 M:N/D 할 수 있음

ⓚ GPIO (Tristate Buffer)의 정체와 GPIO ISR


  • GPIO : General Purpose I/O
    • 정해진 기능이 없이, 사용자가 원하는대로 I/O로 사용할 수 있는 pin들
      • 가끔 정해진 기능이 있을때도 있는데, 이를 Alternative Functionality
  • ARM base의 MCU 입장에서의 GPIO는 AMBA bus에 연결된 SOC Peripheral. APB에 연결된 Slave
  • I/O는 3가지 Register를 통해 Programmable함
    1. Pin Mode를 결정
    2. Pin의 상태를 활성화 하면서, Data direction을 결정
    3. READ/WRITE 시작

3buf

  • GPIO는 하드웨어적으로 3상태 버퍼로 구현됨
    • 3상태 버퍼는 (0, 1, High Impedance)의 상태를 가짐
    • Switch 가 1일때는 I가 0에 그대로 전달됨
    • Switch 가 0일 때는 회로가 열려 Open된 것처럼 보임. 이것이 Hi-Impedance.
      • 연결된 부분이 끊어져 서로 연관성이 없어짐

ⓛ DMA (Direct Memory Access) - CPU몰래 영차영차


dma

  • 두 개의 Hardware Device 간의 데이터 블럭을 Transfer 하는 방법

dmac

  • CPU와 상관없이 전송하는 것이 DMA. 실제 CPU는 DMAC(DMA Controller)를 Control함
  • CPU는 DMAC에게 SRC, DST, 전송할 바이트 수를 알려줌
  • DMAC는 이를 수행하고, 완료되면 CPU에 INT로 알려줌

dmac2

  • DMAC는 여러가지 Register들을 가짐
    • Source Register, Destination Register, Counter Register, Control Register, 전송 시작 명령을 내릴 수 있는 bit, 어떤 방식으로 전송할 것인지를 정하는 bit 등
  • 두가지 Transfer Mode

stm

  • Single Transfer Mode : 한번에 읽기 쓰기를 한번씩 수행. Counter를 1씩 줄임

btm

  • Burst Address Mode : 시작하면 끝까지 READ/WRITE를 무한반복
  • 성능은 Burst Address Mode가 더 좋지만, BUS를 계속 장악하는 문제가 있을수도 있어 single Transfer mode를 사용하기도 함

ⓜ Cache, Cash?


  • 소프트웨어의 특성
    1. Temporal Locality : 소프트웨어가 한번 어떤 메모리의 상의 주소를 접근하면, 자주 접근하는 특성
    2. Spatial Locality : 프로그램 실행 시, 접근하는 메모리의 영역은 이미 접근이 이루어진 영역의 근처일 확률이 높다
  • 이 두가지 특성을 이용하여 느린 메모리의 속도를 개선하고자 캐시를 이용함
  • Cache Hit, Cache Miss
    • Hit : 내가 사용하고자 하는 데이터가 캐시에 있는 경우
    • Miss : 반대로 없는 경우
  • Cache Controller가 Hit/ Miss / LRU를 담당
  • Cache Memory가 데이터 저장을 담당함
  • 캐시에 Write buffer를 두어 쓰기 성능을 개선한 캐시도 있음
    • Write Through : 메모리에 뭔가를 쓸 때, 캐시와 메모리 모두 갱신하여 일치시킴
    • Write Back : 메모리에는 쓰지 않고, 캐시에만 업데이트 하는 방법. Inconsistency가 발생하지만, 속도가 빠르다
  • Cache clean, Flush 등을 이용해 Inconsistency가 의심되면 캐시를 비움

ⓝ MMU (Memory Management Unit)


  • Memory Management Unit
    • CPU에게 논리적 주소를 물리적 주소로 변환해줌
    • CPU가 논리적 주소를 발생시키면, MMU가 물리적 메모리의 주소로 바꿔주어 실제 물리적 메모리를 접근함
  • 쓰는 이유?
    1. Task, Program마다 똑같은 주소를 사용하기 위해 사용함
      • 물리적으로 0x3000~0x5FFF에 올라온 Task A나, 0x6000~0x8FFF에 올라온 Task B나, 0x3000~0x5FFF로 논리적으로 사용 가능함
    2. RAM의 물리적 주소가 나뉘어 있어도, 연속적인 것 처럼 보이게 할 수 있음
    3. 물리적 메모리에 남은 조각들을 모아서, 연속적인 Memory처럼 사용 가능
    4. 메모리의 특성을 조작 가능
      • 캐시, 논캐시 영역, Write Bufferable, Non-Write Bufferable, Read-only 등
  • MCU Register 구성 요소
    1. Virtual Addres와 Physical Address를 연결해주는 Table 필요 : Page Table
    2. Table이 존재하는 위치 : Tranlation Table Base Address(TTB)

mmu

  • 과정
    1. CPU에서 어딘가에 접근하기 위해 Virtual Address를 발생
    2. MMU는 이 Virtual Address 를 받아서, Memory의 TTB에서 시작해서 존재하는 Page Table을 Access
    3. 찾아간 Page Table 안에 Physical Address 를 찾아내서 주소 신호를 발생
    4. Memory는 해당 Physical Address 안의 Data를 출력하여 CPU에게 전달

pageTable

  • Page Table의 크기는 얼마나 될까?
    • Virtual Address는 32Bit Address System이므로 2^32 = 4GB를 나타낼 수 있음
    • Page Table역시 4GB를 나타낼 수 있어야 하므로, Page Table 의 한개 Entry(32bit)는 1MB씩을 가리킬 수 있음
    • 이러한 Entry가 4096개 필요하므로, 4096개 * 32bit = 16KB가 테이블의 기본 크기가 됨
    • 이러한 1MB 단위를 Section이라하고, 더 작은 단위로 나눌 수 있는 Fine, Coarse page Table도 존재
  • Virtual Address는 어떻게 Physical Address로 변환되는가?
    • 끝의 2bit에 따라 Page Table Entry 의 종류가 다름
    • 이러한 종류를 보고, 베이스 주소를 따라가보면 물리적 주소가 나온다

ⓞ JTAG Interface를 Control 해 보자


  • JTAG(Joint Test Access Group)
    • Boundary Scan 구조를 통해 모든 핀들의 상태를 조사
      • Boundary : CPU외부와 내부를 구분짓는 곳. 이 경계를 조사하여 상태를 알아냄
    • CPU에서 나오는 모든 핀들의 상태를 알 수 있음
    • 해당 핀에 강제적으로 값을 인가하여 디버깅도 가능함
  • 탄생 배경
    • 하드웨어 집적도가 높아지고, 하드웨어 테스트 중, 핀들의 상태를 조사하는 것이 어려워짐
    • CPU에서 외부로 연결되는 모든 하드웨어 핀들에 상태를 자동으로 조사할 수 있게 만들자는 아이디어에서 탄생
  • JTAG Interface
    • TDI, TDO, TMS, TCK, TRST 다섯개의 핀을 기본으로 가짐
      • Serial 통신
    • TDI, TDO : JTAG interface와 Test Data input과 Test Data Output. Data를 외부와 주고받을 수 있는 통로
    • TMS : Test Mode Select. JTAG Interface의 상태 설정
    • TCK, TRST : Clock, Reset
      • Synchronous 통신
  • IDCODE를 읽어오는 예시
    • 일반적인 Serial Device Control과 유사함
      1. TAP Controller를 소프트웨어적으로 리셋함
      2. TAP Controller에게 명령을 내리겠다고 알려줌
      3. IDCODE를 읽어오겠다는 명령 발생
      4. TAP Controller에게 실행 명령
      5. TAP Controller에게 Data 수신 준비 완료 알림
      6. IDCODE 읽어오기
      7. TAP Controller를 대기상태로 변환
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.