Appiko
pir_sense.c
1 
19 #include "pir_sense.h"
20 #include "nrf.h"
21 #include "common_util.h"
22 #include "nrf_util.h"
23 
24 #if ISR_MANAGER == 1
25 #include "isr_manager.h"
26 #endif
27 
29 #define PIR_SENSE_RTC_USED RTC_USED_PIR_SENSE
30 
31 #define SAADC_CHANNEL SAADC_CHANNEL_USED_PIR_SENSE
32 
33 #define RTC_ID CONCAT_2(NRF_RTC,RTC_USED_PIR_SENSE)
34 
36 static int16_t saadc_result[1];
37 
39 void (*sense_handler)(int32_t adc_val);
40 
42 #if ISR_MANAGER == 1
43 void pir_sense_saadc_Handler (void)
44 #else
45 void SAADC_IRQHandler(void)
46 #endif
47 {
48 #if ISR_MANAGER == 0
49  NRF_SAADC->EVENTS_CH[SAADC_CHANNEL].LIMITH = 0;
50  (void) NRF_SAADC->EVENTS_CH[SAADC_CHANNEL].LIMITH;
51  NRF_SAADC->EVENTS_CH[SAADC_CHANNEL].LIMITL = 0;
52  (void) NRF_SAADC->EVENTS_CH[SAADC_CHANNEL].LIMITL;
53 #endif
54  sense_handler(saadc_result[0]);
55 }
56 
58 {
59  //Set the handler to be called
60  sense_handler = init->handler;
61 
62  //ADC config: 12 bit, no oversampling, differential inputs, 10 us sampling,
63  //no burst mode, 1.2V internal reference
64  NRF_SAADC->RESOLUTION = SAADC_RESOLUTION_VAL_12bit << SAADC_RESOLUTION_VAL_Pos;
65  NRF_SAADC->OVERSAMPLE = SAADC_OVERSAMPLE_OVERSAMPLE_Bypass;
66  NRF_SAADC->SAMPLERATE = (0 << SAADC_SAMPLERATE_CC_Pos) |
67  (SAADC_SAMPLERATE_MODE_Task << SAADC_SAMPLERATE_MODE_Pos);
68  NRF_SAADC->RESULT.PTR = (uint32_t)saadc_result;
69  NRF_SAADC->RESULT.MAXCNT = ARRAY_SIZE(saadc_result);
70  NRF_SAADC->CH[SAADC_CHANNEL].PSELN = init->pir_offset_analog_in;
71  NRF_SAADC->CH[SAADC_CHANNEL].PSELP = init->pir_signal_analog_in;
72 
73  NRF_SAADC->CH[SAADC_CHANNEL].CONFIG =
74  ((SAADC_CH_CONFIG_RESP_Bypass << SAADC_CH_CONFIG_RESP_Pos) & SAADC_CH_CONFIG_RESP_Msk)
75  | ((SAADC_CH_CONFIG_RESN_Bypass << SAADC_CH_CONFIG_RESN_Pos) & SAADC_CH_CONFIG_RESN_Msk)
76  | ((SAADC_CH_CONFIG_GAIN_Gain1 << SAADC_CH_CONFIG_GAIN_Pos) & SAADC_CH_CONFIG_GAIN_Msk)
77  | ((SAADC_CH_CONFIG_REFSEL_Internal << SAADC_CH_CONFIG_REFSEL_Pos) & SAADC_CH_CONFIG_REFSEL_Msk)
78  | ((SAADC_CH_CONFIG_TACQ_40us << SAADC_CH_CONFIG_TACQ_Pos) & SAADC_CH_CONFIG_TACQ_Msk)
79  | ((SAADC_CH_CONFIG_MODE_Diff << SAADC_CH_CONFIG_MODE_Pos) & SAADC_CH_CONFIG_MODE_Msk)
80  | ((SAADC_CH_CONFIG_BURST_Disabled << SAADC_CH_CONFIG_BURST_Pos) & SAADC_CH_CONFIG_BURST_Msk);
81 
82  NRF_SAADC->CH[SAADC_CHANNEL].LIMIT = (
83  (((-1*((int16_t) init->threshold)) << SAADC_CH_LIMIT_LOW_Pos) & SAADC_CH_LIMIT_LOW_Msk)
84  | (((uint16_t) init->threshold << SAADC_CH_LIMIT_HIGH_Pos) & SAADC_CH_LIMIT_HIGH_Msk));
85 
86  NVIC_SetPriority(SAADC_IRQn, init->irq_priority);
87  NVIC_EnableIRQ(SAADC_IRQn);
88  NVIC_ClearPendingIRQ(SAADC_IRQn);
89 
90  NRF_SAADC->INTENCLR = 0xFFFFFFFF;
91  NRF_SAADC->INTENSET = ((1 << (SAADC_CHANNEL*2 + 6)) | (1 << (SAADC_CHANNEL*2 + 7)));
92 
93  //On ADC start event, trigger the ADC sampling
94  NRF_PPI->CH[PPI_CHANNEL_USED_PIR_SENSE_1].EEP = (uint32_t) &(NRF_SAADC->EVENTS_STARTED);
95  NRF_PPI->CH[PPI_CHANNEL_USED_PIR_SENSE_1].TEP = (uint32_t) &(NRF_SAADC->TASKS_SAMPLE);
96 
97  //On RTC0 Compare0 event, trigger ADC start task and also clear the RTC0 counter
98  NRF_PPI->CH[PPI_CHANNEL_USED_PIR_SENSE_2].EEP = (uint32_t) &(RTC_ID->EVENTS_COMPARE[0]);
99  NRF_PPI->CH[PPI_CHANNEL_USED_PIR_SENSE_2].TEP = (uint32_t) &(NRF_SAADC->TASKS_START);
100  NRF_PPI->FORK[PPI_CHANNEL_USED_PIR_SENSE_2].TEP = (uint32_t) &(RTC_ID->TASKS_CLEAR);
101 
102  //On ADC end event, stop the ADC to disable it and save power
103  NRF_PPI->CH[PPI_CHANNEL_USED_PIR_SENSE_3].EEP = (uint32_t) &(NRF_SAADC->EVENTS_END);
104  NRF_PPI->CH[PPI_CHANNEL_USED_PIR_SENSE_3].TEP = (uint32_t) &(NRF_SAADC->TASKS_STOP);
105 
106  //Enable the above three PPIs
107  NRF_PPI->CHENSET = (1 << PPI_CHANNEL_USED_PIR_SENSE_1) |
108  (1 << PPI_CHANNEL_USED_PIR_SENSE_2) |
109  (1 << PPI_CHANNEL_USED_PIR_SENSE_3);
110 
111  //Start off the ADC with CC0 as the sensing interval
112  RTC_ID->TASKS_STOP = 1;
113  RTC_ID->PRESCALER = 0;
114  RTC_ID->CC[0] = LFCLK_TICKS_MS(init->sense_interval_ms);
115  RTC_ID->EVTENSET = (RTC_EVTENSET_COMPARE0_Enabled << RTC_EVTENSET_COMPARE0_Pos);
116  RTC_ID->EVENTS_COMPARE[0] = 0;
117  RTC_ID->TASKS_START = 1;
118 
119  NRF_SAADC->ENABLE = (SAADC_ENABLE_ENABLE_Enabled << SAADC_ENABLE_ENABLE_Pos);
120 }
121 
125 void pir_sense_stop(void)
126 {
127  NRF_SAADC->ENABLE = (SAADC_ENABLE_ENABLE_Disabled << SAADC_ENABLE_ENABLE_Pos);
128  NVIC_DisableIRQ(SAADC_IRQn);
129 
130  NRF_SAADC->INTENCLR = 0xFFFFFFFF;
131  NRF_SAADC->CH[SAADC_CHANNEL].PSELP = SAADC_CH_PSELP_PSELP_NC;
132 
133  NRF_PPI->CHENCLR = (PPI_CHENCLR_CH0_Clear << PPI_CHANNEL_USED_PIR_SENSE_1) |
134  (PPI_CHENCLR_CH1_Clear << PPI_CHANNEL_USED_PIR_SENSE_2) |
135  (PPI_CHENCLR_CH2_Clear << PPI_CHANNEL_USED_PIR_SENSE_3);
136 
137  RTC_ID->TASKS_CLEAR = 1;
138  RTC_ID->TASKS_STOP = 1;
139 }
uint32_t pir_offset_analog_in
The analog input number of PIR signal.
Definition: pir_sense.h:99
void pir_sense_stop(void)
Disable the peripherals involved - SAADC, PPIs and RTC0.
Definition: pir_sense.c:125
uint32_t pir_signal_analog_in
The sampling interval in ms.
Definition: pir_sense.h:98
#define LFCLK_TICKS_MS(ms)
Definition: nrf_util.h:87
void pir_sense_start(pir_sense_cfg *init)
Definition: pir_sense.c:57
void(* handler)(int32_t adc_val)
The interrupt priority for calling the handler.
Definition: pir_sense.h:103
#define ARRAY_SIZE(arr)
Definition: common_util.h:70
uint32_t threshold
The analog input number of PIR offset.
Definition: pir_sense.h:100
uint32_t irq_priority
Definition: pir_sense.h:102
Stucture for passing the configuration for initializing the PIR Sense module.
Definition: pir_sense.h:96
void SAADC_IRQHandler(void)
Implementation of the SAADC interrupt handler.
Definition: main.c:170