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 32 #ifndef NRF_PPI_H__ 33 #define NRF_PPI_H__ 34 35 #include <nrfx.h> 36 37 #ifdef __cplusplus 38 extern "C" { 39 #endif 40 41 /** 42 * @defgroup nrf_ppi_hal PPI HAL 43 * @{ 44 * @ingroup nrf_ppi 45 * @brief Hardware access layer for managing the Programmable Peripheral Interconnect (PPI) 46 * channels. 47 */ 48 49 #define NRF_PPI_TASK_SET (1UL) 50 51 /** 52 * @enum nrf_ppi_channel_t 53 * @brief PPI channels. 54 */ 55 typedef enum 56 { 57 NRF_PPI_CHANNEL0 = PPI_CHEN_CH0_Pos, /**< Channel 0. */ 58 NRF_PPI_CHANNEL1 = PPI_CHEN_CH1_Pos, /**< Channel 1. */ 59 NRF_PPI_CHANNEL2 = PPI_CHEN_CH2_Pos, /**< Channel 2. */ 60 NRF_PPI_CHANNEL3 = PPI_CHEN_CH3_Pos, /**< Channel 3. */ 61 NRF_PPI_CHANNEL4 = PPI_CHEN_CH4_Pos, /**< Channel 4. */ 62 NRF_PPI_CHANNEL5 = PPI_CHEN_CH5_Pos, /**< Channel 5. */ 63 NRF_PPI_CHANNEL6 = PPI_CHEN_CH6_Pos, /**< Channel 6. */ 64 NRF_PPI_CHANNEL7 = PPI_CHEN_CH7_Pos, /**< Channel 7. */ 65 NRF_PPI_CHANNEL8 = PPI_CHEN_CH8_Pos, /**< Channel 8. */ 66 NRF_PPI_CHANNEL9 = PPI_CHEN_CH9_Pos, /**< Channel 9. */ 67 NRF_PPI_CHANNEL10 = PPI_CHEN_CH10_Pos, /**< Channel 10. */ 68 NRF_PPI_CHANNEL11 = PPI_CHEN_CH11_Pos, /**< Channel 11. */ 69 NRF_PPI_CHANNEL12 = PPI_CHEN_CH12_Pos, /**< Channel 12. */ 70 NRF_PPI_CHANNEL13 = PPI_CHEN_CH13_Pos, /**< Channel 13. */ 71 NRF_PPI_CHANNEL14 = PPI_CHEN_CH14_Pos, /**< Channel 14. */ 72 NRF_PPI_CHANNEL15 = PPI_CHEN_CH15_Pos, /**< Channel 15. */ 73 #if (PPI_CH_NUM > 16) || defined(__NRFX_DOXYGEN__) 74 NRF_PPI_CHANNEL16 = PPI_CHEN_CH16_Pos, /**< Channel 16. */ 75 NRF_PPI_CHANNEL17 = PPI_CHEN_CH17_Pos, /**< Channel 17. */ 76 NRF_PPI_CHANNEL18 = PPI_CHEN_CH18_Pos, /**< Channel 18. */ 77 NRF_PPI_CHANNEL19 = PPI_CHEN_CH19_Pos, /**< Channel 19. */ 78 #endif 79 NRF_PPI_CHANNEL20 = PPI_CHEN_CH20_Pos, /**< Channel 20. */ 80 NRF_PPI_CHANNEL21 = PPI_CHEN_CH21_Pos, /**< Channel 21. */ 81 NRF_PPI_CHANNEL22 = PPI_CHEN_CH22_Pos, /**< Channel 22. */ 82 NRF_PPI_CHANNEL23 = PPI_CHEN_CH23_Pos, /**< Channel 23. */ 83 NRF_PPI_CHANNEL24 = PPI_CHEN_CH24_Pos, /**< Channel 24. */ 84 NRF_PPI_CHANNEL25 = PPI_CHEN_CH25_Pos, /**< Channel 25. */ 85 NRF_PPI_CHANNEL26 = PPI_CHEN_CH26_Pos, /**< Channel 26. */ 86 NRF_PPI_CHANNEL27 = PPI_CHEN_CH27_Pos, /**< Channel 27. */ 87 NRF_PPI_CHANNEL28 = PPI_CHEN_CH28_Pos, /**< Channel 28. */ 88 NRF_PPI_CHANNEL29 = PPI_CHEN_CH29_Pos, /**< Channel 29. */ 89 NRF_PPI_CHANNEL30 = PPI_CHEN_CH30_Pos, /**< Channel 30. */ 90 NRF_PPI_CHANNEL31 = PPI_CHEN_CH31_Pos /**< Channel 31. */ 91 } nrf_ppi_channel_t; 92 93 /** 94 * @enum nrf_ppi_channel_group_t 95 * @brief PPI channel groups. 96 */ 97 typedef enum 98 { 99 NRF_PPI_CHANNEL_GROUP0 = 0, /**< Channel group 0. */ 100 NRF_PPI_CHANNEL_GROUP1 = 1, /**< Channel group 1. */ 101 NRF_PPI_CHANNEL_GROUP2 = 2, /**< Channel group 2. */ 102 NRF_PPI_CHANNEL_GROUP3 = 3, /**< Channel group 3. */ 103 #if (PPI_GROUP_NUM > 4) || defined(__NRFX_DOXYGEN__) 104 NRF_PPI_CHANNEL_GROUP4 = 4, /**< Channel group 4. */ 105 NRF_PPI_CHANNEL_GROUP5 = 5 /**< Channel group 5. */ 106 #endif 107 } nrf_ppi_channel_group_t; 108 109 /** 110 * @enum nrf_ppi_channel_include_t 111 * @brief Definition of which PPI channels belong to a group. 112 */ 113 typedef enum 114 { 115 NRF_PPI_CHANNEL_EXCLUDE = PPI_CHG_CH0_Excluded, /**< Channel excluded from a group. */ 116 NRF_PPI_CHANNEL_INCLUDE = PPI_CHG_CH0_Included /**< Channel included in a group. */ 117 } nrf_ppi_channel_include_t; 118 119 /** 120 * @enum nrf_ppi_channel_enable_t 121 * @brief Definition if a PPI channel is enabled. 122 */ 123 typedef enum 124 { 125 NRF_PPI_CHANNEL_DISABLED = PPI_CHEN_CH0_Disabled, /**< Channel disabled. */ 126 NRF_PPI_CHANNEL_ENABLED = PPI_CHEN_CH0_Enabled /**< Channel enabled. */ 127 } nrf_ppi_channel_enable_t; 128 129 /** 130 * @enum nrf_ppi_task_t 131 * @brief PPI tasks. 132 */ 133 typedef enum 134 { 135 /*lint -save -e30 -esym(628,__INTADDR__)*/ 136 NRF_PPI_TASK_CHG0_EN = offsetof(NRF_PPI_Type, TASKS_CHG[0].EN), /**< Task for enabling channel group 0 */ 137 NRF_PPI_TASK_CHG0_DIS = offsetof(NRF_PPI_Type, TASKS_CHG[0].DIS), /**< Task for disabling channel group 0 */ 138 NRF_PPI_TASK_CHG1_EN = offsetof(NRF_PPI_Type, TASKS_CHG[1].EN), /**< Task for enabling channel group 1 */ 139 NRF_PPI_TASK_CHG1_DIS = offsetof(NRF_PPI_Type, TASKS_CHG[1].DIS), /**< Task for disabling channel group 1 */ 140 NRF_PPI_TASK_CHG2_EN = offsetof(NRF_PPI_Type, TASKS_CHG[2].EN), /**< Task for enabling channel group 2 */ 141 NRF_PPI_TASK_CHG2_DIS = offsetof(NRF_PPI_Type, TASKS_CHG[2].DIS), /**< Task for disabling channel group 2 */ 142 NRF_PPI_TASK_CHG3_EN = offsetof(NRF_PPI_Type, TASKS_CHG[3].EN), /**< Task for enabling channel group 3 */ 143 NRF_PPI_TASK_CHG3_DIS = offsetof(NRF_PPI_Type, TASKS_CHG[3].DIS), /**< Task for disabling channel group 3 */ 144 #if (PPI_GROUP_NUM > 4) || defined(__NRFX_DOXYGEN__) 145 NRF_PPI_TASK_CHG4_EN = offsetof(NRF_PPI_Type, TASKS_CHG[4].EN), /**< Task for enabling channel group 4 */ 146 NRF_PPI_TASK_CHG4_DIS = offsetof(NRF_PPI_Type, TASKS_CHG[4].DIS), /**< Task for disabling channel group 4 */ 147 NRF_PPI_TASK_CHG5_EN = offsetof(NRF_PPI_Type, TASKS_CHG[5].EN), /**< Task for enabling channel group 5 */ 148 NRF_PPI_TASK_CHG5_DIS = offsetof(NRF_PPI_Type, TASKS_CHG[5].DIS) /**< Task for disabling channel group 5 */ 149 #endif 150 /*lint -restore*/ 151 } nrf_ppi_task_t; 152 153 /** 154 * @brief Function for enabling a given PPI channel. 155 * 156 * @details This function enables only one channel. 157 * 158 * @param[in] channel Channel to enable. 159 * 160 * */ 161 __STATIC_INLINE void nrf_ppi_channel_enable(nrf_ppi_channel_t channel); 162 163 /** 164 * @brief Function for disabling a given PPI channel. 165 * 166 * @details This function disables only one channel. 167 * 168 * @param[in] channel Channel to disable. 169 */ 170 __STATIC_INLINE void nrf_ppi_channel_disable(nrf_ppi_channel_t channel); 171 172 /** 173 * @brief Function for checking if a given PPI channel is enabled. 174 * 175 * @details This function checks only one channel. 176 * 177 * @param[in] channel Channel to check. 178 * 179 * @retval NRF_PPI_CHANNEL_ENABLED If the channel is enabled. 180 * @retval NRF_PPI_CHANNEL_DISABLED If the channel is not enabled. 181 * 182 */ 183 __STATIC_INLINE nrf_ppi_channel_enable_t nrf_ppi_channel_enable_get(nrf_ppi_channel_t channel); 184 185 /** 186 * @brief Function for disabling all PPI channels. 187 */ 188 __STATIC_INLINE void nrf_ppi_channel_disable_all(void); 189 190 /** 191 * @brief Function for enabling multiple PPI channels. 192 * 193 * @param[in] mask Channel mask. 194 */ 195 __STATIC_INLINE void nrf_ppi_channels_enable(uint32_t mask); 196 197 /** 198 * @brief Function for disabling multiple PPI channels. 199 * 200 * @param[in] mask Channel mask. 201 */ 202 __STATIC_INLINE void nrf_ppi_channels_disable(uint32_t mask); 203 204 /** 205 * @brief Function for setting up event and task endpoints for a given PPI channel. 206 * 207 * @param[in] eep Event register address. 208 * 209 * @param[in] tep Task register address. 210 * 211 * @param[in] channel Channel to which the given endpoints are assigned. 212 */ 213 __STATIC_INLINE void nrf_ppi_channel_endpoint_setup(nrf_ppi_channel_t channel, 214 uint32_t eep, 215 uint32_t tep); 216 217 /** 218 * @brief Function for setting up the event endpoint for a given PPI channel. 219 * 220 * @param[in] eep Event register address. 221 * @param[in] channel Channel to which the given endpoint is assigned. 222 */ 223 __STATIC_INLINE void nrf_ppi_event_endpoint_setup(nrf_ppi_channel_t channel, 224 uint32_t eep); 225 226 /** 227 * @brief Function for setting up the task endpoint for a given PPI channel. 228 * 229 * @param[in] tep Task register address. 230 * @param[in] channel Channel to which the given endpoint is assigned. 231 */ 232 __STATIC_INLINE void nrf_ppi_task_endpoint_setup(nrf_ppi_channel_t channel, 233 uint32_t tep); 234 235 236 #if defined(PPI_FEATURE_FORKS_PRESENT) || defined(__NRFX_DOXYGEN__) 237 /** 238 * @brief Function for setting up task endpoint for a given PPI fork. 239 * 240 * @param[in] fork_tep Task register address. 241 * 242 * @param[in] channel Channel to which the given fork endpoint is assigned. 243 */ 244 __STATIC_INLINE void nrf_ppi_fork_endpoint_setup(nrf_ppi_channel_t channel, 245 uint32_t fork_tep); 246 247 /** 248 * @brief Function for setting up event and task endpoints for a given PPI channel and fork. 249 * 250 * @param[in] eep Event register address. 251 * 252 * @param[in] tep Task register address. 253 * 254 * @param[in] fork_tep Fork task register address (register value). 255 * 256 * @param[in] channel Channel to which the given endpoints are assigned. 257 */ 258 __STATIC_INLINE void nrf_ppi_channel_and_fork_endpoint_setup(nrf_ppi_channel_t channel, 259 uint32_t eep, 260 uint32_t tep, 261 uint32_t fork_tep); 262 #endif 263 264 /** 265 * @brief Function for including a PPI channel in a channel group. 266 * 267 * @details This function adds only one channel to the group. 268 * 269 * @param[in] channel Channel to be included in the group. 270 * 271 * @param[in] channel_group Channel group. 272 * 273 */ 274 __STATIC_INLINE void nrf_ppi_channel_include_in_group(nrf_ppi_channel_t channel, 275 nrf_ppi_channel_group_t channel_group); 276 277 /** 278 * @brief Function for including multiple PPI channels in a channel group. 279 * 280 * @details This function adds all specified channels to the group. 281 * 282 * @param[in] channel_mask Channels to be included in the group. 283 * 284 * @param[in] channel_group Channel group. 285 * 286 */ 287 __STATIC_INLINE void nrf_ppi_channels_include_in_group(uint32_t channel_mask, 288 nrf_ppi_channel_group_t channel_group); 289 290 /** 291 * @brief Function for removing a PPI channel from a channel group. 292 * 293 * @details This function removes only one channel from the group. 294 * 295 * @param[in] channel Channel to be removed from the group. 296 * 297 * @param[in] channel_group Channel group. 298 */ 299 __STATIC_INLINE void nrf_ppi_channel_remove_from_group(nrf_ppi_channel_t channel, 300 nrf_ppi_channel_group_t channel_group); 301 302 /** 303 * @brief Function for removing multiple PPI channels from a channel group. 304 * 305 * @details This function removes all specified channels from the group. 306 * 307 * @param[in] channel_mask Channels to be removed from the group. 308 * 309 * @param[in] channel_group Channel group. 310 */ 311 __STATIC_INLINE void nrf_ppi_channels_remove_from_group(uint32_t channel_mask, 312 nrf_ppi_channel_group_t channel_group); 313 314 /** 315 * @brief Function for removing all PPI channels from a channel group. 316 * 317 * @param[in] group Channel group. 318 * 319 */ 320 __STATIC_INLINE void nrf_ppi_channel_group_clear(nrf_ppi_channel_group_t group); 321 322 /** 323 * @brief Function for enabling a channel group. 324 * 325 * @param[in] group Channel group. 326 * 327 */ 328 __STATIC_INLINE void nrf_ppi_group_enable(nrf_ppi_channel_group_t group); 329 330 /** 331 * @brief Function for disabling a channel group. 332 * 333 * @param[in] group Channel group. 334 * 335 */ 336 __STATIC_INLINE void nrf_ppi_group_disable(nrf_ppi_channel_group_t group); 337 338 /** 339 * @brief Function for setting a PPI task. 340 * 341 * @param[in] ppi_task PPI task to set. 342 */ 343 __STATIC_INLINE void nrf_ppi_task_trigger(nrf_ppi_task_t ppi_task); 344 345 /** 346 * @brief Function for returning the address of a specific PPI task register. 347 * 348 * @param[in] ppi_task PPI task. 349 */ 350 __STATIC_INLINE uint32_t * nrf_ppi_task_address_get(nrf_ppi_task_t ppi_task); 351 352 /** 353 * @brief Function for returning the PPI enable task address of a specific group. 354 * 355 * @param[in] group PPI group. 356 */ 357 __STATIC_INLINE uint32_t * nrf_ppi_task_group_enable_address_get(nrf_ppi_channel_group_t group); 358 359 /** 360 * @brief Function for returning the PPI disable task address of a specific group. 361 * 362 * @param[in] group PPI group. 363 */ 364 __STATIC_INLINE uint32_t * nrf_ppi_task_group_disable_address_get(nrf_ppi_channel_group_t group); 365 366 367 #ifndef SUPPRESS_INLINE_IMPLEMENTATION 368 369 __STATIC_INLINE void nrf_ppi_channel_enable(nrf_ppi_channel_t channel) 370 { 371 NRF_PPI->CHENSET = PPI_CHENSET_CH0_Set << ((uint32_t) channel); 372 } 373 374 __STATIC_INLINE void nrf_ppi_channel_disable(nrf_ppi_channel_t channel) 375 { 376 NRF_PPI->CHENCLR = PPI_CHENCLR_CH0_Clear << ((uint32_t) channel); 377 } 378 379 __STATIC_INLINE nrf_ppi_channel_enable_t nrf_ppi_channel_enable_get(nrf_ppi_channel_t channel) 380 { 381 if (NRF_PPI->CHEN & (PPI_CHEN_CH0_Msk << ((uint32_t) channel))) 382 { 383 return NRF_PPI_CHANNEL_ENABLED; 384 } 385 else 386 { 387 return NRF_PPI_CHANNEL_DISABLED; 388 } 389 } 390 391 __STATIC_INLINE void nrf_ppi_channel_disable_all(void) 392 { 393 NRF_PPI->CHENCLR = ((uint32_t)0xFFFFFFFFuL); 394 } 395 396 __STATIC_INLINE void nrf_ppi_channels_enable(uint32_t mask) 397 { 398 NRF_PPI->CHENSET = mask; 399 } 400 401 __STATIC_INLINE void nrf_ppi_channels_disable(uint32_t mask) 402 { 403 NRF_PPI->CHENCLR = mask; 404 } 405 406 __STATIC_INLINE void nrf_ppi_channel_endpoint_setup(nrf_ppi_channel_t channel, 407 uint32_t eep, 408 uint32_t tep) 409 { 410 NRF_PPI->CH[(uint32_t) channel].EEP = eep; 411 NRF_PPI->CH[(uint32_t) channel].TEP = tep; 412 } 413 414 __STATIC_INLINE void nrf_ppi_event_endpoint_setup(nrf_ppi_channel_t channel, 415 uint32_t eep) 416 { 417 NRF_PPI->CH[(uint32_t) channel].EEP = eep; 418 } 419 420 __STATIC_INLINE void nrf_ppi_task_endpoint_setup(nrf_ppi_channel_t channel, 421 uint32_t tep) 422 { 423 NRF_PPI->CH[(uint32_t) channel].TEP = tep; 424 } 425 426 #if defined(PPI_FEATURE_FORKS_PRESENT) 427 428 __STATIC_INLINE void nrf_ppi_fork_endpoint_setup(nrf_ppi_channel_t channel, 429 uint32_t fork_tep) 430 { 431 NRF_PPI->FORK[(uint32_t) channel].TEP = fork_tep; 432 } 433 434 __STATIC_INLINE void nrf_ppi_channel_and_fork_endpoint_setup(nrf_ppi_channel_t channel, 435 uint32_t eep, 436 uint32_t tep, 437 uint32_t fork_tep) 438 { 439 nrf_ppi_channel_endpoint_setup(channel, eep, tep); 440 nrf_ppi_fork_endpoint_setup(channel, fork_tep); 441 } 442 #endif 443 444 __STATIC_INLINE void nrf_ppi_channel_include_in_group(nrf_ppi_channel_t channel, 445 nrf_ppi_channel_group_t channel_group) 446 { 447 NRF_PPI->CHG[(uint32_t) channel_group] = 448 NRF_PPI->CHG[(uint32_t) channel_group] | (PPI_CHG_CH0_Included << ((uint32_t) channel)); 449 } 450 451 __STATIC_INLINE void nrf_ppi_channels_include_in_group(uint32_t channel_mask, 452 nrf_ppi_channel_group_t channel_group) 453 { 454 NRF_PPI->CHG[(uint32_t) channel_group] = 455 NRF_PPI->CHG[(uint32_t) channel_group] | (channel_mask); 456 } 457 458 __STATIC_INLINE void nrf_ppi_channel_remove_from_group(nrf_ppi_channel_t channel, 459 nrf_ppi_channel_group_t channel_group) 460 { 461 NRF_PPI->CHG[(uint32_t) channel_group] = 462 NRF_PPI->CHG[(uint32_t) channel_group] & ~(PPI_CHG_CH0_Included << ((uint32_t) channel)); 463 } 464 465 __STATIC_INLINE void nrf_ppi_channels_remove_from_group(uint32_t channel_mask, 466 nrf_ppi_channel_group_t channel_group) 467 { 468 NRF_PPI->CHG[(uint32_t) channel_group] = 469 NRF_PPI->CHG[(uint32_t) channel_group] & ~(channel_mask); 470 } 471 472 __STATIC_INLINE void nrf_ppi_channel_group_clear(nrf_ppi_channel_group_t group) 473 { 474 NRF_PPI->CHG[(uint32_t) group] = 0; 475 } 476 477 __STATIC_INLINE void nrf_ppi_group_enable(nrf_ppi_channel_group_t group) 478 { 479 NRF_PPI->TASKS_CHG[(uint32_t) group].EN = NRF_PPI_TASK_SET; 480 } 481 482 __STATIC_INLINE void nrf_ppi_group_disable(nrf_ppi_channel_group_t group) 483 { 484 NRF_PPI->TASKS_CHG[(uint32_t) group].DIS = NRF_PPI_TASK_SET; 485 } 486 487 __STATIC_INLINE void nrf_ppi_task_trigger(nrf_ppi_task_t ppi_task) 488 { 489 *((volatile uint32_t *) ((uint8_t *) NRF_PPI_BASE + (uint32_t) ppi_task)) = NRF_PPI_TASK_SET; 490 } 491 492 __STATIC_INLINE uint32_t * nrf_ppi_task_address_get(nrf_ppi_task_t ppi_task) 493 { 494 return (uint32_t *) ((uint8_t *) NRF_PPI_BASE + (uint32_t) ppi_task); 495 } 496 497 __STATIC_INLINE uint32_t * nrf_ppi_task_group_enable_address_get(nrf_ppi_channel_group_t group) 498 { 499 return (uint32_t *) &NRF_PPI->TASKS_CHG[(uint32_t) group].EN; 500 } 501 502 __STATIC_INLINE uint32_t * nrf_ppi_task_group_disable_address_get(nrf_ppi_channel_group_t group) 503 { 504 return (uint32_t *) &NRF_PPI->TASKS_CHG[(uint32_t) group].DIS; 505 } 506 507 #endif // SUPPRESS_INLINE_IMPLEMENTATION 508 509 /** @} */ 510 511 #ifdef __cplusplus 512 } 513 #endif 514 515 #endif // NRF_PPI_H__ 516