SW 개발자를 위한 하드웨어의 이해. 두번째

마이크로 콘트롤러의 이해



2019년
http://goo.gl/zo4018


넷째날 시간표


Analog to Digital Converter

참고:


Analog to Digital Converter

Stellaris LM4F MCU는 2개의 ADC 모듈이 있다. ADC0, ADC1

특징


ADC code

칩 내부의 온도 센서 읽기.

http://gist.github.com/donghee/886adc391ab984756edb

ADC Control Sequence

  1. ADC sequence를 세팅하기 전에, 사용할 Sample Sequencer레지스터를 비활성화 한다. 우리는 3번.
  2. 원하는 Sample Sequencer를 고른다.
  3. 읽을 센서(채널)을 선택하고 ADC가 완료 되었을때 인터럽트 방법 지정
  4. 1번에서 비활성화한 Sample Sequencer를 다시 활성화!

온도센서를 읽을려면?

다른센서를 읽을려면?

해보기

핀매핑

배선

코드


임베디드 소프트웨어의 특징


임베디드 소프트웨어 스케쥴링 문제

질문:


임베디드 소프트웨어 스케쥴링: 여러개일

여러개일을 동시에 처리할때 고려해야 내용.


스케쥴링 방법


이벤트 구조 : State Machine을 Switch/Case로 구성하기

..

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();
}

상태머신


RTOS

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

태스크 관리


태스크 만들기

#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) {}
}

코드: FreeRTOS Two Blink Task

해보기


태스크간 통신

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);

코드: FreeRTOS Semaphore

해보기:


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

해보기:


I2C

I2C는 필립스사에서 고안한 방식, MCU와 주변장치의 시리얼통신 하는데 사용.

두선 사용. 여러개의 마스터 지원.


I2C 연결

특징, 통신선로 pull-up


I2C 데이터 타임차트


I2C 통신 포멧


I2C: Tmp102

Tmp102 모듈

https://www.sparkfun.com/products/retired/9418

Tmp102 데이터 쉬트 읽기


Tmp102 신호 분석/디버깅

I2C module Control Sequence

코드

해보기


Logic analyser debug setup/capture

I2C Analyser setup


I2C: 8x2 LCD ST7032

코드

화면이 안보이면 명도를 바꾸기.

해보기

AQM0802A I2C Data sequence


I2C: DS3231 RTC

코드


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)

NRF8001 데이터쉬트

선 연결

SCK -> PA2
MISO -> PA4
MOSI -> PA5
REQ -> PA6
RDY -> PA7
ACT -> PE1
RST -> PE2

VIN -> 3.3V
GND -> GND

코드:

App: BLE P Click in Playstore

해보기:


SPI: GoTenna Teardown

nrf8001사용

Youtube: GoTenna Teardown

https://learn.adafruit.com/gotenna-teardown?embeds=allow


SPI: 가속도 센서

ADXL345 튜토리얼

해보기


실습: Time Boom


Embedded Development and Debugging Tips

보이지 않는 적(버그)과 싸움!!!

하드웨어, 소프트웨어 둘다 해당

하드웨어:


참고