본문 바로가기
Study/nRF51xxx(BLE)

nRF51 DK 예제 9 - PPI

by Answer Choi 2015. 3. 4.
반응형


PPI는 GPIOTE 예제때 한번 나왔던 Programmable Peripheral Interconnect 를 말합니다.


GPIOTE예제때는 타이머를 EEP로 LED토글(GPIOTE TASK)을 TEP로 해서 테스트를 했었습니다.


이번 예제에서는 타이머 3가지를 이용한 예제입니다.


타이머0은 카운터로 설정하고, 타이머1과 타이머2를 사용하여, 타이머1일때는 타이머0이 멈추고,


타이머 2일때는 타이머0이 동작해서 매 200ms마다 타이머0을 카운터하는 예제입니다.


먼저 main함수부터 보겠습니다.


main.c


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
int main(void)
{
    timer0_init(); // Timer used to blink the LEDs.
    timer1_init(); // Timer to generate events on even number of seconds.
    timer2_init(); // Timer to generate events on odd number of seconds.
    ppi_init();    // PPI to redirect the event to timer start/stop tasks.
 
    APP_GPIOTE_INIT(1);
    uint32_t err_code;
    const app_uart_comm_params_t comm_params =
     {
         RX_PIN_NUMBER,
         TX_PIN_NUMBER,
         RTS_PIN_NUMBER,
         CTS_PIN_NUMBER,
         APP_UART_FLOW_CONTROL_ENABLED,
         false,
         UART_BAUDRATE_BAUDRATE_Baud38400
     };
 
    APP_UART_FIFO_INIT(&comm_params,
                    UART_RX_BUF_SIZE,
                    UART_TX_BUF_SIZE,
                    uart_error_handle,
                    APP_IRQ_PRIORITY_LOW,
                    err_code);
 
    APP_ERROR_CHECK(err_code);
 
    
    NRF_POWER->TASKS_CONSTLAT = 1;
       // Start clock.
    NRF_TIMER1->TASKS_START = 1;
    NRF_TIMER2->TASKS_START = 1;
 
    while (true)
    {
        NRF_TIMER0->TASKS_CAPTURE[0= 1;
 
        printf("Current cout: %d\n\r", (uint8_t)NRF_TIMER0->CC[0]);
 
        /* increment the counter */
        NRF_TIMER0->TASKS_COUNT = 1;
 
        nrf_delay_ms(200);
    }
}
cs


Line 3 : Timer 0 초기화입니다.


1
2
3
4
5
static void timer0_init(void)
{
    NRF_TIMER0->MODE    = TIMER_MODE_MODE_Counter;                   // Set the timer in counter Mode.
    NRF_TIMER0->BITMODE = (TIMER_BITMODE_BITMODE_24Bit << TIMER_BITMODE_BITMODE_Pos); // 24-bit mode.
}
cs


Timer0은 24bit의 카운터모드로 초기화합니다.


24bit이니 대략 16777216-1까지 카운트 되겠네요.


Line 4 : Timer 1 초기화 입니다.


1
2
3
4
5
6
7
8
9
static void timer1_init(void)
{
    NRF_TIMER1->BITMODE   = (TIMER_BITMODE_BITMODE_16Bit << TIMER_BITMODE_BITMODE_Pos);
    NRF_TIMER1->PRESCALER = 9;
    NRF_TIMER1->SHORTS    =
        (TIMER_SHORTS_COMPARE0_CLEAR_Enabled << TIMER_SHORTS_COMPARE0_CLEAR_Pos);
     NRF_TIMER1->MODE  = TIMER_MODE_MODE_Timer;
    NRF_TIMER1->CC[0= 0xFFFFUL; 
}
cs


Timer 1은 16bit모드이며 prescaler가 9입니다.


계산을 해보면 16M/₂9=31250, Timer값이 0xFFFF일때 인터럽트가 발생하니깐 


65535(0xFFFF)/31250=2.09712초가 나옵니다. 대략 2.1초마다 인터럽트가 발생하네요.


Line 5 : Timer 2 초기화입니다.


  1. static void timer2_init(void)
  2. {
  3.     NRF_TIMER2->BITMODE   = (TIMER_BITMODE_BITMODE_16Bit << TIMER_BITMODE_BITMODE_Pos);
  4.     NRF_TIMER2->PRESCALER = 9;
  5.     NRF_TIMER2->SHORTS    =
  6.         (TIMER_SHORTS_COMPARE0_CLEAR_Enabled << TIMER_SHORTS_COMPARE0_CLEAR_Pos);
  7.      NRF_TIMER2->MODE  = TIMER_MODE_MODE_Timer;
  8.     NRF_TIMER2->CC[0] = 0x7FFFUL; 
  9. }

Timer 2역시 16bit이고 prescaler가 9이므로 1초에 31250번 카운트를합니다.


CC값이 0x7FFF이므로 32767, 따라서 32767(0x7FFF)/31250=1.048544초 


대략 1.05초마다 인터럽트가 발생하네요.



Line 6 : 이 예제에서 제일 중요한 PPI 초기화입니다.


PPI는 서로다른 Peripheral을 연결해주는 역할을 합니다.


위 그림에서 EEP는 Event End Point로 원인이고, TEP는 Task End Point로 결과입니다.


어떠한 Event발생시 연결해 놓은 Task가 실행된다고 생각하시면 됩니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
static void ppi_init(void)
{
    NRF_PPI->CH[0].EEP = (uint32_t)(&NRF_TIMER1->EVENTS_COMPARE[0]);
    NRF_PPI->CH[0].TEP = (uint32_t)(&NRF_TIMER0->TASKS_STOP);
 
    NRF_PPI->CH[1].EEP = (uint32_t)(&NRF_TIMER1->EVENTS_COMPARE[0]);
    NRF_PPI->CH[1].TEP = (uint32_t)(&NRF_TIMER0->TASKS_STOP);
 
    NRF_PPI->CH[2].EEP = (uint32_t)(&NRF_TIMER2->EVENTS_COMPARE[0]);
    NRF_PPI->CH[2].TEP = (uint32_t)(&NRF_TIMER0->TASKS_START);
    NRF_PPI->CHEN =(PPI_CHEN_CH0_Enabled <<PPI_CHEN_CH0_Pos) |
        (PPI_CHEN_CH1_Enabled << PPI_CHEN_CH1_Pos) | (PPI_CHEN_CH2_Enabled << PPI_CHEN_CH2_Pos);
}
cs


위 코드에서 6~73~4의 중복인데 실수한게 아닌가 싶습니다;;


3~4 : 보시면, PPI channel 0번에 Timer1 이벤트가 발생하면 Timer0을 stop시킵니다.


9~10 : PPI channel 2번에 Timer2 이벤트가 발생하면 Timer0을 start 시킵니다.


11~12 : PPI channel을 enable 시키는 코드입니다.


즉 PPI로 2초마다 Timer0 카운터를 stop시키고, 1초마다 Timer0 카운터를 start시키는 코드입니다.


다시 main함수로 돌아와서 


Line 8~28 : 예제마다 나왔던 초기화입니다.(GPIOTE, UART등)


Line 31 : Sub power mode로 constant Latency mode입니다. low power mode와 반대입니다.


Line 33~34 : Timer 1과 Timer2를 실행시킵니다.


Line 36~46 : 200ms 마다 Timer0의 count값을 읽어와서 Uart로 뿌려주는 부분입니다.


Line 38 : Timer0의 현재 count값을 CC로 복사합니다.


Line 40 : 복사된 Timer0의 count값인 CC를 uart로 출력합니다.


Line 43 : Timer0의 count값을 1 증가시킵니다.



결과화면입니다.



요런식으로 Timer1에 의해 Timer0 이 멈추면 숫자가 증가하지않고, 다시 Timer2에 의해 Timer0이


동작하면 카운트가 증가하게 됩니다.


또 계속보다보면 의문이 생길수도 있는게 위에서 Timer0이 24bit라서 1600만이 넘는 숫자까지 


증가해야하는데 255에서 끝나버립니다.



요렇게요..


왜그럴까요?


그건 uart로 뿌려줄때 8bit로 뿌려줘서 255가 넘는순간 overflow가 발생합니다.


이부분을 32bit로 뿌려주게되면 아래와 같이 계속해서 증가합니다^^



반응형

'Study > nRF51xxx(BLE)' 카테고리의 다른 글

nRF51 DK 예제 11 - radiotest (1)  (0) 2015.03.05
nRF51 DK 예제 10 - PWM  (2) 2015.03.04
nRF51 DK 예제 8 - Pin change interrupt  (0) 2015.03.03
nRF51 DK 예제 7 -Radio Receiver  (0) 2015.03.03
nRF51 DK 예제 6 -Radio Transmitter  (0) 2015.03.03

인기글