[nRF51822] 8、基礎實驗代碼解析大全 · 實驗11 - PPI


 

前一篇分析了前十個基礎實驗的代碼,從這里開始分析后十個~

 

一、PPI原理:

PPI(Programmable Peripheral Interconnect),中文翻譯為可編程外設互連。

在nRF51822 內部設置了PPI 方式,可以通過任務和事件讓不同外設之間進行互連,而不需要CPU 進行參與。

PPI 通過通道讓任務和事件連接在一起。PPI 通道由兩個端點組成:

  • 任務端點:Task End-Point (TEP)。
  • 事件端點:Event End-Point (EEP)。

所謂的互聯就是將任務端點寫入需要連接的任務寄存器地址,事件端點寫入需要連接事件寄存器地址,之后,使能該PPI 通道,即實現了任務和事件的互聯。

可以通過如下兩種方式使能和關閉PPI 通道:

  • 1) 通過獨立設置CHEN,CHENSET 和CHENCLR 寄存器。
  • 2) 通過PPI 通道組的使能和關閉任務。使用這種方式,在觸發任務之前,需要先配置好哪些PPI 通道屬於哪個組。

 

二、運行邏輯:

實驗中,用到了3 個定時器:Timer 0、Timer 1 和Timer 2。

1) Timer 0 配置為計數器,在主循環中每100ms 被觸發一次,並通過串口打印出計數值。
2) Timer 1 每個偶數秒(2、4、6、8……)產生一次比較匹配事件,該事件通過PPI通道0 和Timer 0 的STOP Task 互聯,互聯后通過該事件觸發Timer 0 的STOP Task。
3) Timer 2 每個奇數秒(1、3、5、7……)產生一次比較匹配事件,該事件通過PPI通道1 和Timer 0 的START Task 互聯,互聯后通過該事件觸發Timer 0 的START Task。

實驗原理框圖如圖1 所示:

 

三、核心代碼分析

系統運行后,在循環中Timer 0 計數器的計數值每100ms 增加一次,在偶數秒時,Timer2 產生比較匹配事件,通過PPI 觸發Timer 0 的STOP Task,Timer 0 停止計數。此時,盡管主循環中每隔100ms 觸發一次Timer 0 計數,但是由於Timer 0 已經停止,所以,計數值不會增加。每個奇數秒,Timer2 產生比較匹配事件,通過PPI 觸發Timer 0 的START Task,Timer 0 恢復計數。

main函數部分:

 1 int main(void)
 2 {
 3     timer0_init(); // Timer used to blink the LEDs.
 4     timer1_init(); // Timer to generate events on even number of seconds.
 5     timer2_init(); // Timer to generate events on odd number of seconds.
 6     ppi_init();    // PPI to redirect the event to timer start/stop tasks.
 7 
       串口初始化(略)
28 
29     // Enabling constant latency as indicated by PAN 11 "HFCLK: Base current with HFCLK 
30     // running is too high" found at Product Anomaly document found at
31     // https://www.nordicsemi.com/eng/Products/Bluetooth-R-low-energy/nRF51822/#Downloads
32     //
33     // @note This example does not go to low power mode therefore constant latency is not needed.
34     //       However this setting will ensure correct behaviour when routing TIMER events through 
35     //       PPI (shown in this example) and low power mode simultaneously.
36     NRF_POWER->TASKS_CONSTLAT = 1;
37     
38     // Start clock.
39     nrf_drv_timer_enable(&timer0);
40     nrf_drv_timer_enable(&timer1);
41     nrf_drv_timer_enable(&timer2);
42 
43     // Loop and increment the timer count value and capture value into LEDs. @note counter is only incremented between TASK_START and TASK_STOP.
44     while (true)
45     {
46 
47         printf("Current cout: %d\r\n", (int)nrf_drv_timer_capture(&timer0,NRF_TIMER_CC_CHANNEL0));
48 
49         /* increment the counter */
50         nrf_drv_timer_increment(&timer0);
51 
52         nrf_delay_ms(100);
53     }
54 }

 

定時器初始化部分:

 1 // Timer even handler. Not used since timer is used only for PPI.
 2 void timer_event_handler(nrf_timer_event_t event_type, void * p_context){}
 3 
 4 /** @brief Function for Timer 0 initialization, which will be started and stopped by timer1 and timer2 using PPI.
 5 */
 6 static void timer0_init(void)
 7 {
 8     ret_code_t err_code = nrf_drv_timer_init(&timer0, NULL, timer_event_handler);
 9     APP_ERROR_CHECK(err_code);
10 }
11 
12 /** @brief Function for Timer 1 initialization.
13  *  @details Initializes Timer 1 peripheral, creates event and interrupt every 2 seconds,
14  *           by configuring CC[0] to timer overflow value, we create events at even number of seconds
15  *           for example, events are created at 2,4,6 ... seconds. This event can be used to stop Timer 0
16  *           with Timer1->Event_Compare[0] triggering Timer 0 TASK_STOP through PPI.
17 */
18 static void timer1_init(void)
19 {
20     // Configure Timer 1 to overflow every 2 seconds. Check TIMER1 configuration for details
21     // The overflow occurs every 0xFFFF/(SysClk/2^PRESCALER).
22     // = 65535/31250 = 2.097 sec
23     ret_code_t err_code = nrf_drv_timer_init(&timer1, NULL, timer_event_handler);
24     APP_ERROR_CHECK(err_code);
25 
26     nrf_drv_timer_extended_compare(&timer1, NRF_TIMER_CC_CHANNEL0, 0xFFFFUL, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, false);//比較模式,Timer 1 每個偶數秒(2、4、6、8……)產生一次比較匹配事件,該事件通過PPI通道0 和Timer 0 的STOP Task 互聯,互聯后通過該事件觸發Timer 0 的STOP Task。 27 }
28 
29 /** @brief Function for Timer 2 initialization.
30  *  @details Initializes Timer 2 peripheral, creates event and interrupt every 2 seconds
31  *           by configuring CC[0] to half of timer overflow value. Events are created at odd number of seconds.
32  *           For example, events are created at 1,3,5,... seconds. This event can be used to start Timer 0
33  *           with Timer2->Event_Compare[0] triggering Timer 0 TASK_START through PPI.
34 */
35 static void timer2_init(void)
36 {
37     // Generate interrupt/event when half of time before the timer overflows has past, that is at 1,3,5,7... seconds from start.
38     // Check TIMER1 configuration for details
39     // now the overflow occurs every 0xFFFF/(SysClk/2^PRESCALER)
40     // = 65535/31250 = 2.097 sec */
41     ret_code_t err_code = nrf_drv_timer_init(&timer2, NULL, timer_event_handler);
42     APP_ERROR_CHECK(err_code);
43 
44     nrf_drv_timer_extended_compare(&timer2, NRF_TIMER_CC_CHANNEL0, 0x7FFFUL, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, false);//Timer 2 每個奇數秒(1、3、5、7……)產生一次比較匹配事件,該事件通過PPI通道1 和Timer 0 的START Task 互聯,互聯后通過該事件觸發Timer 0 的START Task。 45 }

 

PPI連接事件部分:

 1 /** @brief Function for initializing the PPI peripheral.
 2 */
 3 static void ppi_init(void)
 4 {
 5     uint32_t err_code = NRF_SUCCESS;
 6 
 7     err_code = nrf_drv_ppi_init();
 8     APP_ERROR_CHECK(err_code);
 9 
10     // Configure 1st available PPI channel to stop TIMER0 counter on TIMER1 COMPARE[0] match, which is every even number of seconds.
11     err_code = nrf_drv_ppi_channel_alloc(&ppi_channel1);
12     APP_ERROR_CHECK(err_code);
13 err_code = nrf_drv_ppi_channel_assign(ppi_channel1,//PPI連接事件 14 nrf_drv_timer_event_address_get(&timer1, NRF_TIMER_EVENT_COMPARE0), 15 nrf_drv_timer_task_address_get(&timer0, NRF_TIMER_TASK_STOP)); 16     APP_ERROR_CHECK(err_code);
17 
18     // Configure 2nd available PPI channel to start timer0 counter at TIMER2 COMPARE[0] match, which is every odd number of seconds.
19     err_code = nrf_drv_ppi_channel_alloc(&ppi_channel2);
20     APP_ERROR_CHECK(err_code);
21 err_code = nrf_drv_ppi_channel_assign(ppi_channel2, 22 nrf_drv_timer_event_address_get(&timer2, NRF_TIMER_EVENT_COMPARE0), 23 nrf_drv_timer_task_address_get(&timer0, NRF_TIMER_TASK_START)); 24     APP_ERROR_CHECK(err_code);
25 
26     // Enable both configured PPI channels
27     err_code = nrf_drv_ppi_channel_enable(ppi_channel1);
28     APP_ERROR_CHECK(err_code);
29     err_code = nrf_drv_ppi_channel_enable(ppi_channel2);
30     APP_ERROR_CHECK(err_code);
31 }

 

 

 

@beautifulzzzz - 物聯網&普適計算實踐者
e-mail:beautifulzzzz@qq.com 
i-blog:blog.beautifulzzzz.com 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM