1 /* 2 * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, this 9 * list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * 3. Neither the name of the copyright holder nor the names of its 16 * contributors may be used to endorse or promote products derived from this 17 * software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 #ifndef NRF_PDM_H_ 32 #define NRF_PDM_H_ 33 34 #include <nrfx.h> 35 36 #ifdef __cplusplus 37 extern "C" { 38 #endif 39 40 /** 41 * @defgroup nrf_pdm_hal PDM HAL 42 * @{ 43 * @ingroup nrf_pdm 44 * @brief Hardware access layer for managing the Pulse Density Modulation (PDM) peripheral. 45 */ 46 47 #define NRF_PDM_GAIN_MINIMUM 0x00 48 #define NRF_PDM_GAIN_DEFAULT 0x28 49 #define NRF_PDM_GAIN_MAXIMUM 0x50 50 51 typedef uint8_t nrf_pdm_gain_t; 52 53 54 /** 55 * @brief PDM tasks. 56 */ 57 typedef enum /*lint -save -e30 -esym(628,__INTADDR__) */ 58 { 59 NRF_PDM_TASK_START = offsetof(NRF_PDM_Type, TASKS_START), ///< Starts continuous PDM transfer. 60 NRF_PDM_TASK_STOP = offsetof(NRF_PDM_Type, TASKS_STOP) ///< Stops PDM transfer. 61 } nrf_pdm_task_t; 62 63 64 /** 65 * @brief PDM events. 66 */ 67 typedef enum /*lint -save -e30 -esym(628,__INTADDR__) */ 68 { 69 NRF_PDM_EVENT_STARTED = offsetof(NRF_PDM_Type, EVENTS_STARTED), ///< PDM transfer has started. 70 NRF_PDM_EVENT_STOPPED = offsetof(NRF_PDM_Type, EVENTS_STOPPED), ///< PDM transfer has finished. 71 NRF_PDM_EVENT_END = offsetof(NRF_PDM_Type, EVENTS_END) ///< The PDM has written the last sample specified by SAMPLE.MAXCNT (or the last sample after a STOP task has been received) to Data RAM. 72 } nrf_pdm_event_t; 73 74 75 /** 76 * @brief PDM interrupt masks. 77 */ 78 typedef enum 79 { 80 NRF_PDM_INT_STARTED = PDM_INTENSET_STARTED_Msk, ///< Interrupt on EVENTS_STARTED event. 81 NRF_PDM_INT_STOPPED = PDM_INTENSET_STOPPED_Msk, ///< Interrupt on EVENTS_STOPPED event. 82 NRF_PDM_INT_END = PDM_INTENSET_END_Msk ///< Interrupt on EVENTS_END event. 83 } nrf_pdm_int_mask_t; 84 85 /** 86 * @brief PDM clock frequency. 87 */ 88 typedef enum 89 { 90 NRF_PDM_FREQ_1000K = PDM_PDMCLKCTRL_FREQ_1000K, ///< PDM_CLK = 1.000 MHz. 91 NRF_PDM_FREQ_1032K = PDM_PDMCLKCTRL_FREQ_Default, ///< PDM_CLK = 1.032 MHz. 92 NRF_PDM_FREQ_1067K = PDM_PDMCLKCTRL_FREQ_1067K ///< PDM_CLK = 1.067 MHz. 93 } nrf_pdm_freq_t; 94 95 96 /** 97 * @brief PDM operation mode. 98 */ 99 typedef enum 100 { 101 NRF_PDM_MODE_STEREO = PDM_MODE_OPERATION_Stereo, ///< Sample and store one pair (Left + Right) of 16-bit samples per RAM word. 102 NRF_PDM_MODE_MONO = PDM_MODE_OPERATION_Mono ///< Sample and store two successive Left samples (16 bit each) per RAM word. 103 } nrf_pdm_mode_t; 104 105 106 /** 107 * @brief PDM sampling mode. 108 */ 109 typedef enum 110 { 111 NRF_PDM_EDGE_LEFTFALLING = PDM_MODE_EDGE_LeftFalling, ///< Left (or mono) is sampled on falling edge of PDM_CLK. 112 NRF_PDM_EDGE_LEFTRISING = PDM_MODE_EDGE_LeftRising ///< Left (or mono) is sampled on rising edge of PDM_CLK. 113 } nrf_pdm_edge_t; 114 115 116 /** 117 * @brief Function for triggering a PDM task. 118 * 119 * @param[in] pdm_task PDM task. 120 */ 121 __STATIC_INLINE void nrf_pdm_task_trigger(nrf_pdm_task_t pdm_task); 122 123 /** 124 * @brief Function for getting the address of a PDM task register. 125 * 126 * @param[in] pdm_task PDM task. 127 * 128 * @return Address of the specified PDM task. 129 */ 130 __STATIC_INLINE uint32_t nrf_pdm_task_address_get(nrf_pdm_task_t pdm_task); 131 132 /** 133 * @brief Function for getting the state of a PDM event. 134 * 135 * @param[in] pdm_event PDM event. 136 * 137 * @return State of the specified PDM event. 138 */ 139 __STATIC_INLINE bool nrf_pdm_event_check(nrf_pdm_event_t pdm_event); 140 141 /** 142 * @brief Function for clearing a PDM event. 143 * 144 * @param[in] pdm_event PDM event. 145 */ 146 __STATIC_INLINE void nrf_pdm_event_clear(nrf_pdm_event_t pdm_event); 147 148 /** 149 * @brief Function for getting the address of a PDM event register. 150 * 151 * @param[in] pdm_event PDM event. 152 * 153 * @return Address of the specified PDM event. 154 */ 155 __STATIC_INLINE volatile uint32_t * nrf_pdm_event_address_get(nrf_pdm_event_t pdm_event); 156 157 /** 158 * @brief Function for enabling PDM interrupts. 159 * 160 * @param[in] pdm_int_mask Interrupts to enable. 161 */ 162 __STATIC_INLINE void nrf_pdm_int_enable(uint32_t pdm_int_mask); 163 164 /** 165 * @brief Function for retrieving the state of PDM interrupts. 166 * 167 * @param[in] pdm_int_mask Interrupts to check. 168 * 169 * @retval true If all specified interrupts are enabled. 170 * @retval false If at least one of the given interrupts is not enabled. 171 */ 172 __STATIC_INLINE bool nrf_pdm_int_enable_check(uint32_t pdm_int_mask); 173 174 /** 175 * @brief Function for disabling interrupts. 176 * 177 * @param pdm_int_mask Interrupts to disable. 178 */ 179 __STATIC_INLINE void nrf_pdm_int_disable(uint32_t pdm_int_mask); 180 181 #if defined(DPPI_PRESENT) || defined(__NRFX_DOXYGEN__) 182 /** 183 * @brief Function for setting the subscribe configuration for a given 184 * PDM task. 185 * 186 * @param[in] task Task for which to set the configuration. 187 * @param[in] channel Channel through which to subscribe events. 188 */ 189 __STATIC_INLINE void nrf_pdm_subscribe_set(nrf_pdm_task_t task, 190 uint8_t channel); 191 192 /** 193 * @brief Function for clearing the subscribe configuration for a given 194 * PDM task. 195 * 196 * @param[in] task Task for which to clear the configuration. 197 */ 198 __STATIC_INLINE void nrf_pdm_subscribe_clear(nrf_pdm_task_t task); 199 200 /** 201 * @brief Function for setting the publish configuration for a given 202 * PDM event. 203 * 204 * @param[in] event Event for which to set the configuration. 205 * @param[in] channel Channel through which to publish the event. 206 */ 207 __STATIC_INLINE void nrf_pdm_publish_set(nrf_pdm_event_t event, 208 uint8_t channel); 209 210 /** 211 * @brief Function for clearing the publish configuration for a given 212 * PDM event. 213 * 214 * @param[in] event Event for which to clear the configuration. 215 */ 216 __STATIC_INLINE void nrf_pdm_publish_clear(nrf_pdm_event_t event); 217 #endif // defined(DPPI_PRESENT) || defined(__NRFX_DOXYGEN__) 218 219 /** 220 * @brief Function for enabling the PDM peripheral. 221 * 222 * The PDM peripheral must be enabled before use. 223 */ 224 __STATIC_INLINE void nrf_pdm_enable(void); 225 226 /** 227 * @brief Function for disabling the PDM peripheral. 228 */ 229 __STATIC_INLINE void nrf_pdm_disable(void); 230 231 /** 232 * @brief Function for checking if the PDM peripheral is enabled. 233 * 234 * @retval true If the PDM peripheral is enabled. 235 * @retval false If the PDM peripheral is not enabled. 236 */ 237 __STATIC_INLINE bool nrf_pdm_enable_check(void); 238 239 /** 240 * @brief Function for setting the PDM operation mode. 241 * 242 * @param[in] pdm_mode PDM operation mode. 243 * @param[in] pdm_edge PDM sampling mode. 244 */ 245 __STATIC_INLINE void nrf_pdm_mode_set(nrf_pdm_mode_t pdm_mode, nrf_pdm_edge_t pdm_edge); 246 247 /** 248 * @brief Function for getting the PDM operation mode. 249 * 250 * @param[out] p_pdm_mode PDM operation mode. 251 * @param[out] p_pdm_edge PDM sampling mode. 252 */ 253 __STATIC_INLINE void nrf_pdm_mode_get(nrf_pdm_mode_t * p_pdm_mode, nrf_pdm_edge_t * p_pdm_edge); 254 255 /** 256 * @brief Function for setting the PDM clock frequency. 257 * 258 * @param[in] pdm_freq PDM clock frequency. 259 */ 260 __STATIC_INLINE void nrf_pdm_clock_set(nrf_pdm_freq_t pdm_freq); 261 262 /** 263 * @brief Function for getting the PDM clock frequency. 264 */ 265 __STATIC_INLINE nrf_pdm_freq_t nrf_pdm_clock_get(void); 266 267 /** 268 * @brief Function for setting up the PDM pins. 269 * 270 * @param[in] psel_clk CLK pin number. 271 * @param[in] psel_din DIN pin number. 272 */ 273 __STATIC_INLINE void nrf_pdm_psel_connect(uint32_t psel_clk, uint32_t psel_din); 274 275 /** 276 * @brief Function for disconnecting the PDM pins. 277 */ 278 __STATIC_INLINE void nrf_pdm_psel_disconnect(void); 279 280 /** 281 * @brief Function for setting the PDM gain. 282 * 283 * @param[in] gain_l Left channel gain. 284 * @param[in] gain_r Right channel gain. 285 */ 286 __STATIC_INLINE void nrf_pdm_gain_set(nrf_pdm_gain_t gain_l, nrf_pdm_gain_t gain_r); 287 288 /** 289 * @brief Function for getting the PDM gain. 290 * 291 * @param[out] p_gain_l Left channel gain. 292 * @param[out] p_gain_r Right channel gain. 293 */ 294 __STATIC_INLINE void nrf_pdm_gain_get(nrf_pdm_gain_t * p_gain_l, nrf_pdm_gain_t * p_gain_r); 295 296 /** 297 * @brief Function for setting the PDM sample buffer. 298 * 299 * @param[in] p_buffer Pointer to the RAM address where samples should be written with EasyDMA. 300 * @param[in] num Number of samples to allocate memory for in EasyDMA mode. 301 * 302 * The amount of allocated RAM depends on the operation mode. 303 * - For stereo mode: N 32-bit words. 304 * - For mono mode: Ceil(N/2) 32-bit words. 305 */ 306 __STATIC_INLINE void nrf_pdm_buffer_set(uint32_t * p_buffer, uint32_t num); 307 308 /** 309 * @brief Function for getting the current PDM sample buffer address. 310 * 311 * @return Pointer to the current sample buffer. 312 */ 313 __STATIC_INLINE uint32_t * nrf_pdm_buffer_get(void); 314 315 #ifndef SUPPRESS_INLINE_IMPLEMENTATION 316 __STATIC_INLINE void nrf_pdm_task_trigger(nrf_pdm_task_t pdm_task) 317 { 318 *((volatile uint32_t *)((uint8_t *)NRF_PDM + (uint32_t)pdm_task)) = 0x1UL; 319 } 320 321 __STATIC_INLINE uint32_t nrf_pdm_task_address_get(nrf_pdm_task_t pdm_task) 322 { 323 return (uint32_t)((uint8_t *)NRF_PDM + (uint32_t)pdm_task); 324 } 325 326 __STATIC_INLINE bool nrf_pdm_event_check(nrf_pdm_event_t pdm_event) 327 { 328 return (bool)*(volatile uint32_t *)((uint8_t *)NRF_PDM + (uint32_t)pdm_event); 329 } 330 331 __STATIC_INLINE void nrf_pdm_event_clear(nrf_pdm_event_t pdm_event) 332 { 333 *((volatile uint32_t *)((uint8_t *)NRF_PDM + (uint32_t)pdm_event)) = 0x0UL; 334 #if __CORTEX_M == 0x04 335 volatile uint32_t dummy = *((volatile uint32_t *)((uint8_t *)NRF_PDM + (uint32_t)pdm_event)); 336 (void)dummy; 337 #endif 338 } 339 340 __STATIC_INLINE volatile uint32_t * nrf_pdm_event_address_get(nrf_pdm_event_t pdm_event) 341 { 342 return (volatile uint32_t *)((uint8_t *)NRF_PDM + (uint32_t)pdm_event); 343 } 344 345 __STATIC_INLINE void nrf_pdm_int_enable(uint32_t pdm_int_mask) 346 { 347 NRF_PDM->INTENSET = pdm_int_mask; 348 } 349 350 __STATIC_INLINE bool nrf_pdm_int_enable_check(uint32_t pdm_int_mask) 351 { 352 return (bool)(NRF_PDM->INTENSET & pdm_int_mask); 353 } 354 355 __STATIC_INLINE void nrf_pdm_int_disable(uint32_t pdm_int_mask) 356 { 357 NRF_PDM->INTENCLR = pdm_int_mask; 358 } 359 360 #if defined(DPPI_PRESENT) 361 __STATIC_INLINE void nrf_pdm_subscribe_set(nrf_pdm_task_t task, 362 uint8_t channel) 363 { 364 *((volatile uint32_t *) ((uint8_t *) NRF_PDM + (uint32_t) task + 0x80uL)) = 365 ((uint32_t)channel | PDM_SUBSCRIBE_START_EN_Msk); 366 } 367 368 __STATIC_INLINE void nrf_pdm_subscribe_clear(nrf_pdm_task_t task) 369 { 370 *((volatile uint32_t *) ((uint8_t *) NRF_PDM + (uint32_t) task + 0x80uL)) = 0; 371 } 372 373 __STATIC_INLINE void nrf_pdm_publish_set(nrf_pdm_event_t event, 374 uint8_t channel) 375 { 376 *((volatile uint32_t *) ((uint8_t *) NRF_PDM + (uint32_t) event + 0x80uL)) = 377 ((uint32_t)channel | PDM_PUBLISH_STARTED_EN_Msk); 378 } 379 380 __STATIC_INLINE void nrf_pdm_publish_clear(nrf_pdm_event_t event) 381 { 382 *((volatile uint32_t *) ((uint8_t *) NRF_PDM + (uint32_t) event + 0x80uL)) = 0; 383 } 384 #endif // defined(DPPI_PRESENT) 385 386 __STATIC_INLINE void nrf_pdm_enable(void) 387 { 388 NRF_PDM->ENABLE = (PDM_ENABLE_ENABLE_Enabled << PDM_ENABLE_ENABLE_Pos); 389 } 390 391 __STATIC_INLINE void nrf_pdm_disable(void) 392 { 393 NRF_PDM->ENABLE = (PDM_ENABLE_ENABLE_Disabled << PDM_ENABLE_ENABLE_Pos); 394 } 395 396 __STATIC_INLINE bool nrf_pdm_enable_check(void) 397 { 398 return (NRF_PDM->ENABLE == (PDM_ENABLE_ENABLE_Enabled << PDM_ENABLE_ENABLE_Pos)); 399 } 400 401 __STATIC_INLINE void nrf_pdm_mode_set(nrf_pdm_mode_t pdm_mode, nrf_pdm_edge_t pdm_edge) 402 { 403 NRF_PDM->MODE = ((pdm_mode << PDM_MODE_OPERATION_Pos) & PDM_MODE_OPERATION_Msk) 404 | ((pdm_edge << PDM_MODE_EDGE_Pos) & PDM_MODE_EDGE_Msk); 405 } 406 407 __STATIC_INLINE void nrf_pdm_mode_get(nrf_pdm_mode_t * p_pdm_mode, nrf_pdm_edge_t * p_pdm_edge) 408 { 409 uint32_t mode = NRF_PDM->MODE; 410 *p_pdm_mode = (nrf_pdm_mode_t)((mode & PDM_MODE_OPERATION_Msk ) >> PDM_MODE_OPERATION_Pos); 411 *p_pdm_edge = (nrf_pdm_edge_t)((mode & PDM_MODE_EDGE_Msk ) >> PDM_MODE_EDGE_Pos); 412 } 413 414 __STATIC_INLINE void nrf_pdm_clock_set(nrf_pdm_freq_t pdm_freq) 415 { 416 NRF_PDM->PDMCLKCTRL = ((pdm_freq << PDM_PDMCLKCTRL_FREQ_Pos) & PDM_PDMCLKCTRL_FREQ_Msk); 417 } 418 419 __STATIC_INLINE nrf_pdm_freq_t nrf_pdm_clock_get(void) 420 { 421 return (nrf_pdm_freq_t) ((NRF_PDM->PDMCLKCTRL << PDM_PDMCLKCTRL_FREQ_Pos) & PDM_PDMCLKCTRL_FREQ_Msk); 422 } 423 424 __STATIC_INLINE void nrf_pdm_psel_connect(uint32_t psel_clk, uint32_t psel_din) 425 { 426 NRF_PDM->PSEL.CLK = psel_clk; 427 NRF_PDM->PSEL.DIN = psel_din; 428 } 429 430 __STATIC_INLINE void nrf_pdm_psel_disconnect(void) 431 { 432 NRF_PDM->PSEL.CLK = ((PDM_PSEL_CLK_CONNECT_Disconnected << PDM_PSEL_CLK_CONNECT_Pos) 433 & PDM_PSEL_CLK_CONNECT_Msk); 434 NRF_PDM->PSEL.DIN = ((PDM_PSEL_DIN_CONNECT_Disconnected << PDM_PSEL_DIN_CONNECT_Pos) 435 & PDM_PSEL_DIN_CONNECT_Msk); 436 } 437 438 __STATIC_INLINE void nrf_pdm_gain_set(nrf_pdm_gain_t gain_l, nrf_pdm_gain_t gain_r) 439 { 440 NRF_PDM->GAINL = gain_l; 441 NRF_PDM->GAINR = gain_r; 442 } 443 444 __STATIC_INLINE void nrf_pdm_gain_get(nrf_pdm_gain_t * p_gain_l, nrf_pdm_gain_t * p_gain_r) 445 { 446 *p_gain_l = NRF_PDM->GAINL; 447 *p_gain_r = NRF_PDM->GAINR; 448 } 449 450 __STATIC_INLINE void nrf_pdm_buffer_set(uint32_t * p_buffer, uint32_t num) 451 { 452 NRF_PDM->SAMPLE.PTR = (uint32_t)p_buffer; 453 NRF_PDM->SAMPLE.MAXCNT = num; 454 } 455 456 __STATIC_INLINE uint32_t * nrf_pdm_buffer_get(void) 457 { 458 return (uint32_t *)NRF_PDM->SAMPLE.PTR; 459 } 460 461 #endif // SUPPRESS_INLINE_IMPLEMENTATION 462 /** @} */ 463 464 #ifdef __cplusplus 465 } 466 #endif 467 468 #endif // NRF_PDM_H_ 469