SW 개발자를 위한 하드웨어의 이해. 두번째
마이크로 콘트롤러의 이해
2019년
http://goo.gl/zo4018
넷째날 시간표
- ADC
- 태스크 스케쥴러
- IC간 통신: I2C
- IC간 통신: SPI
- 시한폭탄 만들기
- 데모
- 회고
Analog to Digital Converter
- 아날로그 신호를 디지털로 변환
- 스펙: 분해능(resolution), 샘플링 처리속도
- 처리속도: 입력신호의 최고 주파수 2배이상은 샘플링 해야 입력 신호를 제대로 읽을 수 있다. 그래서 샘플링 처리속도를 아는게 중요. (Nyquist 정리)
- Opamp와 같이 사용하여 신호 흐름을 좋게 하거나, 증폭, 잡음제거할 수 있다.
- 구현방법: 병렬비교 ADC 구현, 계수형 ADC 구현, …
참고:
Analog to Digital Converter
Stellaris LM4F MCU는 2개의 ADC 모듈이 있다. ADC0, ADC1
특징
- 12-bit resolution
- sample rate: 1초당 백만(1MSPS)
- ADC 끝나면 인터럽트나 트리거 발생
ADC code
칩 내부의 온도 센서 읽기.
http://gist.github.com/donghee/886adc391ab984756edb
ADC Control Sequence
- ADC sequence를 세팅하기 전에, 사용할 Sample Sequencer레지스터를 비활성화 한다. 우리는 3번.
- 원하는 Sample Sequencer를 고른다.
- 읽을 센서(채널)을 선택하고 ADC가 완료 되었을때 인터럽트 방법 지정
- 1번에서 비활성화한 Sample Sequencer를 다시 활성화!
온도센서를 읽을려면?
- ADC_CTL_TS
다른센서를 읽을려면?
- ADC_CTL_CH0~ADC_CTL_CH11 을 선택하면 해당 포트의 센서를 읽을 수 있다.
해보기
- A11(PB5)에 빛센서를 연결하여 ADC 값을 읽어 보자.
- ADC_CTL_TS -> ADC_CTL_CH11
- 어두워지면 LED가 켜지도록 만들어 보자.
임베디드 소프트웨어의 특징
- 이벤트 중심 프로그램.
- 반응이 일정 시간안에 실행 되도록 보장되어야 한다. (Real Time)
- Delay를 쓰는 폴링 구조는 이벤트에 반응 하기 어렴다.
- RTOS (시간으로 스케쥴링)
- State Machine
임베디드 소프트웨어 스케쥴링 문제
질문:
- 그동안 사용한 방법(Super loop, Interrupt)으로는 스케쥴링에 무슨 문제가 있을까?
- 또는 구현하기 어려운것은?
임베디드 소프트웨어 스케쥴링: 여러개일
여러개일을 동시에 처리할때 고려해야 내용.
- 하나의 일(thread)을 처리하는 동안 다른 일이 처리 안되지 않나?
- 각각 일(thread)은 어떻게 스케쥴링 하나?
- 일의 우선 순위가 있다면?
스케쥴링 방법
- Super loop
- Timer based Interrupts
- Timer based Interrupts with (NESTED) priorities
- ISR에서 데이터 처리 분리
- *State Machine
- *RTOS
이벤트 구조 : State Machine을 Switch/Case로 구성하기
Timer Boom State Machine을 Switch/Case로 구성하기
상태(STATE)
이벤트(SIGNAL)
..
enum BombSignal {
UP_SIG,
DOWN_SIG,
START_SIG,
TICK_SIG,
};
enum BombState {
SETTING_STATE,
TIMING_STATE
};
uint8_t bomb_state;
#define TRANS(target_) (bomb_state = (uint8_t) target_)
void Bomb_init() {
TRANS(SETTING_STATE);
bomb_counter = 10; //default is 10
}
void Bomb_dispatch(BombSignal sig)
{
switch (bomb_state) {
case SETTING_STATE:
switch(sig) {
case UP_SIG:
if (bomb_counter < 60) // MAX
bomb_counter++;
break;
case DOWN_SIG:
if (bomb_counter > 1)
bomb_counter--;
break;
case START_SIG:
TRANS(TIMING_STATE)
break;
}
break;
case TIMING_STATE:
switch(sig) {
case TICK_SIG:
if (is_tick_updatable()) {
make_beep();
bomb_counter--;
UARTprintf("BOMB COUNTER: %d\n", bomb_counter);
if (bomb_counter == 0)
UARTprintf("BOMB!");
else
TRANS(TIMING_STATE);
}
break;
}
}
}
상태 머신 구현
Switch-case
typedef enum states { STATE_A, STATE_B, STATE_C, STATE_D } state_type;
state_type StateA(void);
state_type StateB(void);
state_type StateC(void);
state_type StateD(void);
(void) State_Machine(void) {
static state_type state=StateA, last_state=StateA;
switch (state) {
case STATE_A: last_state=state; state = StateA(); break;
case STATE_B: last_state=state; state = StateB(); break;
case STATE_C: last_state=state; state = StateC(); break;
case STATE_D: last_state=state; state = StateD(); break;
default: Panic(last_state, state); break;
}
}
참고: http://www.edn.com/electronics-blogs/embedded-basics/4406821/Function-pointers—Part–3–State-machines
상태 머신 구현
Function pointer
typedef void (*state_handler)(void);
state_handler state;
void Sm_StateA(void);
void Sm_StateB(void);
void Sm_StateC(void);
void Sm_StateD(void);
void Sm_StateA(void) {
// run state code
state = Sm_StateB; // transition
}
void Sm_StateB(void) {
// run state code
state = Sm_StateD; // transition
}
void Sm_StateD(void) {
// run state code
state = Sm_StateC;
}
void Sm_StateD(void) {
// run state code
state = Sm_StateA;
}
(void) State_Machine(void) {
state();
}
상태머신
- 장점: non-blocking
- 단점: 코드 복잡도가 높아진다.
RTOS
- 멀티태스킹 기능 지원
- 태스킹 스케쥴링 (우선순위, 태스크간 통신(Queue))
- 우선순위
- 태스크 통신(Queue)
- 태스크간 리소스 관리(Semaphore)
- Context Change(CPU, 스택 관리 도구)
RealTime (일정한 시간안에는 테스크가 실행 되는것을 보장!)
Toyoda killer’s firmware
https://youtu.be/NGe3EOJ-CMY?t=58
https://www.slideshare.net/PhilipKoopman/toyota-unintended-acceleration
https://goo.gl/el8bmo
https://barrgroup.com/sites/default/files/KillerApps_Barr_OFFICIAL.pdf
FreeRTOS
http://freertos.org
- modified GPL. 상용으로 제약없이 쓸 수 있다.
태스크 관리
- 우선 순위 높은 태스크를 실행!
- 같은 우선 순위의 태스크면 시분할을 통해서 CPU를 공유 (왔다갔다)
- xTaskCreate() // 테스크 생성
- vTaskStartScheduler() //스케쥴러 실행
- vTaskDelay() // 입력 tick동안 Sleep
- xQueueSend() // Queue가 꽉찰때까지 Sleep
- xQueueReceive() // Queue가 비어있으면 Sleep
- xSemaphoreTake() // 다른 태스크가 세마포어를 가지고 있으면 Sleep
태스크 만들기
#include "FreeRTOS.h"
#include "task.h"
void blink_task(void* p)
{
while(1) {
vTaskDelay(1000);
}
}
int main()
{
xTaskCreate(blink_task, (signed char*)"task_name", 128, NULL, 1, NULL);
vTaskStartScheduler();
return -1;
}
void vApplicationStackOverflowHook(xTaskHandle *pxTask, signed char *pcTaskName)
{
while(1) {}
}
해보기
- 빨간색 LED를 깜박이게 하는 태스크를 추가하자.
태스크간 통신
Queue
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
xQueueHandle qh = 0;
void send_task(void* p)
{
int i;
while(1) {
i++;
if(!xQueueSend(qh, &i, 500)) {
UARTprintf("Failed to send item to queue within 500ms");
}
vTaskDelay(1000);
}
}
void receive_task(void* p)
{
int i = 0;
while(1) {
if(xQueueReceive(qh, &i, 1000)) {
UARTprintf("Received: %u\n", i);
}
}
}
int main()
{
qh = xQueueCreate(1, sizeof(int));
xTaskCreate(send_task, (signed char*)"send_task_name", 128, NULL, 1, NULL);
xTaskCreate(receive_task, (signed char*)"receive_task_name", 128, NULL, 1, NULL);
vTaskStartScheduler();
return -1;
}
코드: FreeRTOS Queue
해보기 -
Semaphore
세마포어: 여러 테스크가 공유된 자원을 접근할때 레이스 컨디션 문제가 발생한다. 공유된 자원을 사용할대 일종의 ’키’를 주어서 한번에 하나의 태스크 자원에 접근 할 수 있도록 한다.
#include "semphr.h"
xSemaphoreHandle sh;
sh = xSemaphoreCreateMutex();
xSemaphoreTake(sh, portMAX_DELAY);
UARTprintf("Button is pressed.\n");
xSemaphoreGive(sh);
해보기:
- Semaphore 사용하여, 위 코드에서 발생한 레이스 컨디션 문제를 해결해보자. (5분)
Log 만들기
header
typedef enum {
I2C_SERVICE = 0,
ADC_SERVICE = 1,
LOG_SERVICE = 2,
RTC_SERVICE = 3
} system_t;
typedef enum {
NONE_LEVEL = 0,
NOTICE_LEVEL = 1,
WARNING_LEVEL = 2,
ERROR_LEVEL = 3
} logLevel_t;
void Log_init();
void Log(system_t s, logLevel_t level, char* msg);
void Log_withNum(system_t s, logLevel_t level, char* msg, int number);
void Log_setOutputLevel(system_t sys, logLevel_t level);
<!-- void Log_setOutputLevel(ADC_SERVICE, WARNING_LEVEL); -->
// turn on/ turn off log
void Log_globalOn();
void Log_globalOff();
사용 예제
// setup
Log_init();
Log_setOutputLevel(ADC_SERVICE, WARNING_LEVEL);
Log_globalOn();
//usage
Log(ADC_SERVICE, WARNING_LEVEL, "Cannot Read ADC");
//00:00:05, ADC, WARNING, Cannot Read ADC
Log_withNum(ADC_SERVICE, NOTICE_LEVEL, "ADC Value:", 500);
//00:00:06, ADC, NOTICE, ADC Value: 500
해보기:
- UART를 통해서 로그 모듈을 구현해 보자.
I2C
I2C는 필립스사에서 고안한 방식, MCU와 주변장치의 시리얼통신 하는데 사용.
두선 사용. 여러개의 마스터 지원.
I2C 연결
특징, 통신선로 pull-up
I2C 데이터 타임차트
I2C 통신 포멧
I2C: Tmp102
Tmp102 모듈
https://www.sparkfun.com/products/retired/9418
Tmp102 데이터 쉬트 읽기
- 동작전압
- 각 핀의 설명
- I2C 주소
- 온도를 읽는 방법 (데이터 주고 받는 방법)
Tmp102 신호 분석/디버깅
I2C module Control Sequence
- Peripheral Enable
- GPIO Pin muxing
- I2C Clock Setting
- I2C Master/Slave Enable
해보기
- 로직분석기를 이용하여 tmp102의 신호를 분석하고 온도가 읽히도록 코드를 디버깅을 해보자.
- 로직분석기 소프트웨어 다운로드
Logic analyser debug setup/capture
I2C Analyser setup

- http://dh8.kr/workshop/hwworkshop_intermediate/note/tmp102_ANALYZERS_SETUP.png
- 에러 http://dh8.kr/workshop/hwworkshop_intermediate/note/tmp102_nak.png
- 수정 http://dh8.kr/workshop/hwworkshop_intermediate/note/tmp102_ack.png
I2C: 8x2 LCD ST7032
화면이 안보이면 명도를 바꾸기.
해보기
- ‘TimerBoom’ 글자를 바꾸고, 로직분석기로 I2C Data를 체크해보자.
- 시작 시퀀스를 로직분석기로 분석해보자. (보드의 리셋을 누르고, Logic 분석기 프로그램의 START를 누룬다. 그리고 보드 리셋을 뗀다)
- (필수 아님)시작 시퀀스 마지막 바이트가 2개씩 보내진다. 이 버그를 해결해보자. (I2C_Write 함수)
- 에러 http://dh8.kr/workshop/hwworkshop_intermediate/note/lcd_I2C_write_error.png
- 수정 http://dh8.kr/workshop/hwworkshop_intermediate/note/lcd_I2C_write_fix.png
AQM0802A I2C Data sequence
I2C: DS3231 RTC
- Real Time Clock
- 시간, 날짜, 두개의 알람. 현재 온도
- 내부에 internal oscillator TCXO
- low power mode: 수명 6\~7년
- Datasheet
SPI (Serial Peripheral Interface)
SPI 는 모토로라에서 만든 통신 방식. 직렬 컴퓨터 버스 주변기기를 연결하기 위해 사용된다.
외부 주변장치와 clock 을 통하여 동기화 하는 동기식 통신 방식이며, 하나의 Master 와 하나 또는 다수의 Slave Device 간의 통신이 가능하다.
4개핀 사용: - MOSI (Master Out Slave Input) - MISO (Master Input Slave Out) - SS (Slave Select) - SCK (Serial Clock)
SPI Bus
SPI MODE
샘플링 위치에 따라 모드가 달라진다.
SPI MODE: CPOL, CPHA
CPOL
동작 안할때 Clock의 상태(HIGH or LOW)
CPOL=0, CPHA=0
CPOL=0, CPHA=1
CPOL=1, CPHA=0
CPOL=1, CPHA=1
SPI: NRF8001
BLUETOOTH 4.0, Bluetooth Smart, Bluetooth Low Energy with iOS or Android (4.3+)
SPI로 통신. Slave Select가 변형됨, 신호처리 추가(REQ, RDY, RST)
선 연결
SCK -> PA2
MISO -> PA4
MOSI -> PA5
REQ -> PA6
RDY -> PA7
ACT -> PE1
RST -> PE2
VIN -> 3.3V
GND -> GND
코드:
- http://okin.cc/~donghee/hw2/nrf8001.zip를 C:\ti\TivaWare_C_Series–2.1.1.71\examples\boards\ek-tm4c123gxl\ 에 위치 압축 해재한다.
- IAR의 Project메뉴에서 Add Existing Project로 ek-tm4c123gxl 아래에 위치한 nrf8001\nrf8001.ewp파일을 추가한다.
App: BLE P Click in Playstore
- http://play.google.com/store/apps/details?id=com.mikroe.blepclick&hl=ko
- App 코드: http://www.libstock.com/projects/view/1065/ble-p-click-android-application
해보기:
- BLE P Click App을 실행하여, nrf8001모듈과 통신하는것 확인.
- 펌웨어에서 SPI 데이터 주고 받는 흐름을읽기.
SPI: GoTenna Teardown
nrf8001사용
https://learn.adafruit.com/gotenna-teardown?embeds=allow
SPI: 가속도 센서
해보기
- ADXL345 드라이버를 만들어 보자. (힌트 ADXL345 튜토리얼 참고)
- 로직분석기를 이용하여 가속도 센서 드라이버를 만들어 보자.
- Mode ?
http://github.com/ograff/ADXL345---SPI
실습: Time Boom
시간: 90분
시한폭탄 요구사항
- 시한폭탄에는 세팅모드와 동작 모드가 있다.
- 세팅 모드에서는 두개의 버튼을 이용하며, 왼쪽 버튼이 눌리면 폭탄 카운트 시간을 증가
- 오른쪽 버튼이 눌렸을때 폭탄 카운트 시간이 감소한다.
- 세번째 버튼을 눌렀을때 세팅모드에서 동작 모드로 전환한다.
- 시간이 카운트 다운 될때 마다 비프음이 들린다.
- 동작모드가 되면 정한 시간 후 폭탄이 터진다.
- 동작모드에서 일정 이상의 빛이나 온도가 변하면 폭탄이 터진다.
- LCD에 카운트값을 표시한다.
- 동작모드에서 일정 이상의 소리가 발생하면 폭탄이 터진다.
- 동작모드에서 일정 이상의 진동이 발생하면 폭탄이 터진다. (추가옵션)
- 오후 4시가 되면 폭탄이 터진다. (추가옵션)
- 외부에서(스마트폰 BLE) 폭탄을 바로 터뜨릴 수 있다. (추가옵션)
Embedded Development and Debugging Tips
보이지 않는 적(버그)과 싸움!!!
하드웨어, 소프트웨어 둘다 해당
- 모듈별로 나눠서 디버깅(한번에 테스트 하지 않기!)
- Baby Step (점점 살붙이기)
- 현상의 시각화(Data logging, Logic analyser, Osciloscope): 장비발
- Read Datasheet!
- 디버깅 노트/저널링
- 가설검증(관찰전에 가정을 세우자. 검증을 위한 실험 고안, 검증 안된건 믿지말자!)
- 리팩토링
- 그리고 기분 좋게. 음악 좀 듣고 간식 좀 먹고…휴식
- 그래도 안되면 다 지우고 다시 시작! 포기!
하드웨어:
- 잘 고장나는 IC가 있다.
참고
- LaunchPad Worshop in TI: http://processors.wiki.ti.com/index.php/Getting_Started_with_the_Stellaris_EK-LM4F120XL_LaunchPad_Workshop
- DDJ 2003: http://www.drdobbs.com/back-to-basics/184401737?pgno=2
- http://www.state-machine.com/quickstart/
- Maxfield, Brown. The Definitive Guide to How Computers Do Math
- Bebop to the Boolean Boogie: An Unconventional Guide to Electronics