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 #include <nrfx.h> 33 34 #if NRFX_CHECK(NRFX_PPI_ENABLED) 35 36 #include <nrfx_ppi.h> 37 38 #define NRFX_LOG_MODULE PPI 39 #include <nrfx_log.h> 40 41 42 static uint32_t m_channels_allocated; /**< Bitmap representing channels availability. 1 when a channel is allocated, 0 otherwise. */ 43 static uint8_t m_groups_allocated; /**< Bitmap representing groups availability. 1 when a group is allocated, 0 otherwise.*/ 44 45 46 /** 47 * @brief Compute a group mask (needed for driver internals, not used for NRF_PPI registers). 48 * 49 * @param[in] group Group number to transform to a mask. 50 * 51 * @retval Group mask. 52 */ 53 __STATIC_INLINE uint32_t group_to_mask(nrf_ppi_channel_group_t group) 54 { 55 return (1uL << (uint32_t) group); 56 } 57 58 59 /** 60 * @brief Check whether a channel is a programmable channel and can be used by an application. 61 * 62 * @param[in] channel Channel to check. 63 * 64 * @retval true The channel is a programmable application channel. 65 * @retval false The channel is used by a stack (for example SoftDevice) or is preprogrammed. 66 */ 67 __STATIC_INLINE bool is_programmable_app_channel(nrf_ppi_channel_t channel) 68 { 69 return ((NRFX_PPI_PROG_APP_CHANNELS_MASK & nrfx_ppi_channel_to_mask(channel)) != 0); 70 } 71 72 73 /** 74 * @brief Check whether channels can be used by an application. 75 * 76 * @param[in] channel_mask Channel mask to check. 77 * 78 * @retval true All specified channels can be used by an application. 79 * @retval false At least one specified channel is used by a stack (for example SoftDevice). 80 */ 81 __STATIC_INLINE bool are_app_channels(uint32_t channel_mask) 82 { 83 //lint -e(587) 84 return ((~(NRFX_PPI_ALL_APP_CHANNELS_MASK) & channel_mask) == 0); 85 } 86 87 88 /** 89 * @brief Check whether a channel can be used by an application. 90 * 91 * @param[in] channel Channel to check. 92 * 93 * @retval true The channel can be used by an application. 94 * @retval false The channel is used by a stack (for example SoftDevice). 95 */ 96 __STATIC_INLINE bool is_app_channel(nrf_ppi_channel_t channel) 97 { 98 return are_app_channels(nrfx_ppi_channel_to_mask(channel)); 99 } 100 101 102 /** 103 * @brief Check whether a channel group can be used by an application. 104 * 105 * @param[in] group Group to check. 106 * 107 * @retval true The group is an application group. 108 * @retval false The group is not an application group (this group either does not exist or 109 * it is used by a stack (for example SoftDevice)). 110 */ 111 __STATIC_INLINE bool is_app_group(nrf_ppi_channel_group_t group) 112 { 113 return ((NRFX_PPI_ALL_APP_GROUPS_MASK & group_to_mask(group)) != 0); 114 } 115 116 117 /** 118 * @brief Check whether a channel is allocated. 119 * 120 * @param[in] channel_num Channel number to check. 121 * 122 * @retval true The channel is allocated. 123 * @retval false The channel is not allocated. 124 */ 125 __STATIC_INLINE bool is_allocated_channel(nrf_ppi_channel_t channel) 126 { 127 return ((m_channels_allocated & nrfx_ppi_channel_to_mask(channel)) != 0); 128 } 129 130 131 /** 132 * @brief Set channel allocated indication. 133 * 134 * @param[in] channel_num Specifies the channel to set the "allocated" indication. 135 */ 136 __STATIC_INLINE void channel_allocated_set(nrf_ppi_channel_t channel) 137 { 138 m_channels_allocated |= nrfx_ppi_channel_to_mask(channel); 139 } 140 141 142 /** 143 * @brief Clear channel allocated indication. 144 * 145 * @param[in] channel_num Specifies the channel to clear the "allocated" indication. 146 */ 147 __STATIC_INLINE void channel_allocated_clr(nrf_ppi_channel_t channel) 148 { 149 m_channels_allocated &= ~nrfx_ppi_channel_to_mask(channel); 150 } 151 152 153 /** 154 * @brief Clear all allocated channels. 155 */ 156 __STATIC_INLINE void channel_allocated_clr_all(void) 157 { 158 m_channels_allocated &= ~NRFX_PPI_ALL_APP_CHANNELS_MASK; 159 } 160 161 162 /** 163 * @brief Check whether a group is allocated. 164 * 165 * @param[in] group_num Group number to check. 166 * 167 * @retval true The group is allocated. 168 * false The group is not allocated. 169 */ 170 __STATIC_INLINE bool is_allocated_group(nrf_ppi_channel_group_t group) 171 { 172 return ((m_groups_allocated & group_to_mask(group)) != 0); 173 } 174 175 176 /** 177 * @brief Set group allocated indication. 178 * 179 * @param[in] group_num Specifies the group to set the "allocated" indication. 180 */ 181 __STATIC_INLINE void group_allocated_set(nrf_ppi_channel_group_t group) 182 { 183 m_groups_allocated |= group_to_mask(group); 184 } 185 186 187 /** 188 * @brief Clear group allocated indication. 189 * 190 * @param[in] group_num Specifies the group to clear the "allocated" indication. 191 */ 192 __STATIC_INLINE void group_allocated_clr(nrf_ppi_channel_group_t group) 193 { 194 m_groups_allocated &= ~group_to_mask(group); 195 } 196 197 198 /** 199 * @brief Clear all allocated groups. 200 */ 201 __STATIC_INLINE void group_allocated_clr_all() 202 { 203 m_groups_allocated &= ~NRFX_PPI_ALL_APP_GROUPS_MASK; 204 } 205 206 207 void nrfx_ppi_free_all(void) 208 { 209 uint32_t mask = NRFX_PPI_ALL_APP_GROUPS_MASK; 210 nrf_ppi_channel_group_t group; 211 212 // Disable all channels and groups 213 nrf_ppi_channels_disable(NRFX_PPI_ALL_APP_CHANNELS_MASK); 214 215 for (group = NRF_PPI_CHANNEL_GROUP0; mask != 0; mask &= ~group_to_mask(group), group++) 216 { 217 if (mask & group_to_mask(group)) 218 { 219 nrf_ppi_channel_group_clear(group); 220 } 221 } 222 channel_allocated_clr_all(); 223 group_allocated_clr_all(); 224 } 225 226 227 nrfx_err_t nrfx_ppi_channel_alloc(nrf_ppi_channel_t * p_channel) 228 { 229 nrfx_err_t err_code = NRFX_SUCCESS; 230 nrf_ppi_channel_t channel; 231 uint32_t mask = 0; 232 err_code = NRFX_ERROR_NO_MEM; 233 234 mask = NRFX_PPI_PROG_APP_CHANNELS_MASK; 235 for (channel = NRF_PPI_CHANNEL0; 236 mask != 0; 237 mask &= ~nrfx_ppi_channel_to_mask(channel), channel++) 238 { 239 NRFX_CRITICAL_SECTION_ENTER(); 240 if ((mask & nrfx_ppi_channel_to_mask(channel)) && (!is_allocated_channel(channel))) 241 { 242 channel_allocated_set(channel); 243 *p_channel = channel; 244 err_code = NRFX_SUCCESS; 245 } 246 NRFX_CRITICAL_SECTION_EXIT(); 247 if (err_code == NRFX_SUCCESS) 248 { 249 NRFX_LOG_INFO("Allocated channel: %d.", channel); 250 break; 251 } 252 } 253 254 NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code)); 255 return err_code; 256 } 257 258 259 nrfx_err_t nrfx_ppi_channel_free(nrf_ppi_channel_t channel) 260 { 261 nrfx_err_t err_code = NRFX_SUCCESS; 262 263 if (!is_programmable_app_channel(channel)) 264 { 265 err_code = NRFX_ERROR_INVALID_PARAM; 266 } 267 else 268 { 269 // First disable this channel 270 nrf_ppi_channel_disable(channel); 271 NRFX_CRITICAL_SECTION_ENTER(); 272 channel_allocated_clr(channel); 273 NRFX_CRITICAL_SECTION_EXIT(); 274 } 275 NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code)); 276 return err_code; 277 } 278 279 280 nrfx_err_t nrfx_ppi_channel_assign(nrf_ppi_channel_t channel, uint32_t eep, uint32_t tep) 281 { 282 if ((uint32_t *)eep == NULL || (uint32_t *)tep == NULL) 283 { 284 return NRFX_ERROR_NULL; 285 } 286 287 nrfx_err_t err_code = NRFX_SUCCESS; 288 289 if (!is_programmable_app_channel(channel)) 290 { 291 err_code = NRFX_ERROR_INVALID_PARAM; 292 } 293 else if (!is_allocated_channel(channel)) 294 { 295 err_code = NRFX_ERROR_INVALID_STATE; 296 } 297 else 298 { 299 nrf_ppi_channel_endpoint_setup(channel, eep, tep); 300 NRFX_LOG_INFO("Assigned channel: %d, event end point: %x, task end point: %x.", 301 channel, 302 eep, 303 tep); 304 } 305 NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code)); 306 return err_code; 307 } 308 309 nrfx_err_t nrfx_ppi_channel_fork_assign(nrf_ppi_channel_t channel, uint32_t fork_tep) 310 { 311 nrfx_err_t err_code = NRFX_SUCCESS; 312 #ifdef PPI_FEATURE_FORKS_PRESENT 313 if (!is_allocated_channel(channel)) 314 { 315 err_code = NRFX_ERROR_INVALID_STATE; 316 } 317 else 318 { 319 nrf_ppi_fork_endpoint_setup(channel, fork_tep); 320 NRFX_LOG_INFO("Fork assigned channel: %d, task end point: %d.", channel, fork_tep); 321 } 322 NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code)); 323 return err_code; 324 #else 325 err_code = NRFX_ERROR_NOT_SUPPORTED; 326 NRFX_LOG_WARNING("Function: %s, error code: %s.", 327 __func__, 328 NRFX_LOG_ERROR_STRING_GET(err_code)); 329 return err_code; 330 #endif 331 } 332 333 nrfx_err_t nrfx_ppi_channel_enable(nrf_ppi_channel_t channel) 334 { 335 nrfx_err_t err_code = NRFX_SUCCESS; 336 337 if (!is_app_channel(channel)) 338 { 339 err_code = NRFX_ERROR_INVALID_PARAM; 340 } 341 else if (is_programmable_app_channel(channel) && !is_allocated_channel(channel)) 342 { 343 err_code = NRFX_ERROR_INVALID_STATE; 344 } 345 else 346 { 347 nrf_ppi_channel_enable(channel); 348 } 349 NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code)); 350 return err_code; 351 } 352 353 354 nrfx_err_t nrfx_ppi_channel_disable(nrf_ppi_channel_t channel) 355 { 356 nrfx_err_t err_code = NRFX_SUCCESS; 357 358 if (!is_app_channel(channel)) 359 { 360 err_code = NRFX_ERROR_INVALID_PARAM; 361 } 362 else if (is_programmable_app_channel(channel) && !is_allocated_channel(channel)) 363 { 364 err_code = NRFX_ERROR_INVALID_STATE; 365 } 366 else 367 { 368 nrf_ppi_channel_disable(channel); 369 err_code = NRFX_SUCCESS; 370 } 371 NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code)); 372 return err_code; 373 } 374 375 376 nrfx_err_t nrfx_ppi_group_alloc(nrf_ppi_channel_group_t * p_group) 377 { 378 nrfx_err_t err_code; 379 uint32_t mask = 0; 380 nrf_ppi_channel_group_t group; 381 382 err_code = NRFX_ERROR_NO_MEM; 383 384 mask = NRFX_PPI_ALL_APP_GROUPS_MASK; 385 for (group = NRF_PPI_CHANNEL_GROUP0; mask != 0; mask &= ~group_to_mask(group), group++) 386 { 387 NRFX_CRITICAL_SECTION_ENTER(); 388 if ((mask & group_to_mask(group)) && (!is_allocated_group(group))) 389 { 390 group_allocated_set(group); 391 *p_group = group; 392 err_code = NRFX_SUCCESS; 393 } 394 NRFX_CRITICAL_SECTION_EXIT(); 395 if (err_code == NRFX_SUCCESS) 396 { 397 NRFX_LOG_INFO("Allocated group: %d.", group); 398 break; 399 } 400 } 401 402 NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code)); 403 return err_code; 404 } 405 406 407 nrfx_err_t nrfx_ppi_group_free(nrf_ppi_channel_group_t group) 408 { 409 nrfx_err_t err_code = NRFX_SUCCESS; 410 411 if (!is_app_group(group)) 412 { 413 err_code = NRFX_ERROR_INVALID_PARAM; 414 } 415 if (!is_allocated_group(group)) 416 { 417 err_code = NRFX_ERROR_INVALID_STATE; 418 } 419 else 420 { 421 nrf_ppi_group_disable(group); 422 NRFX_CRITICAL_SECTION_ENTER(); 423 group_allocated_clr(group); 424 NRFX_CRITICAL_SECTION_EXIT(); 425 } 426 NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code)); 427 return err_code; 428 } 429 430 431 nrfx_err_t nrfx_ppi_group_enable(nrf_ppi_channel_group_t group) 432 { 433 nrfx_err_t err_code = NRFX_SUCCESS; 434 435 if (!is_app_group(group)) 436 { 437 err_code = NRFX_ERROR_INVALID_PARAM; 438 } 439 else if (!is_allocated_group(group)) 440 { 441 err_code = NRFX_ERROR_INVALID_STATE; 442 } 443 else 444 { 445 nrf_ppi_group_enable(group); 446 } 447 NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code)); 448 return err_code; 449 } 450 451 452 nrfx_err_t nrfx_ppi_group_disable(nrf_ppi_channel_group_t group) 453 { 454 nrfx_err_t err_code = NRFX_SUCCESS; 455 456 if (!is_app_group(group)) 457 { 458 err_code = NRFX_ERROR_INVALID_PARAM; 459 } 460 else 461 { 462 nrf_ppi_group_disable(group); 463 } 464 NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code)); 465 return err_code; 466 } 467 468 nrfx_err_t nrfx_ppi_channels_remove_from_group(uint32_t channel_mask, 469 nrf_ppi_channel_group_t group) 470 { 471 nrfx_err_t err_code = NRFX_SUCCESS; 472 473 if (!is_app_group(group)) 474 { 475 err_code = NRFX_ERROR_INVALID_PARAM; 476 } 477 else if (!is_allocated_group(group)) 478 { 479 err_code = NRFX_ERROR_INVALID_STATE; 480 } 481 else if (!are_app_channels(channel_mask)) 482 { 483 err_code = NRFX_ERROR_INVALID_PARAM; 484 } 485 else 486 { 487 NRFX_CRITICAL_SECTION_ENTER(); 488 nrf_ppi_channels_remove_from_group(channel_mask, group); 489 NRFX_CRITICAL_SECTION_EXIT(); 490 } 491 NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code)); 492 return err_code; 493 } 494 495 nrfx_err_t nrfx_ppi_channels_include_in_group(uint32_t channel_mask, 496 nrf_ppi_channel_group_t group) 497 { 498 nrfx_err_t err_code = NRFX_SUCCESS; 499 500 if (!is_app_group(group)) 501 { 502 err_code = NRFX_ERROR_INVALID_PARAM; 503 } 504 else if (!is_allocated_group(group)) 505 { 506 err_code = NRFX_ERROR_INVALID_STATE; 507 } 508 else if (!are_app_channels(channel_mask)) 509 { 510 err_code = NRFX_ERROR_INVALID_PARAM; 511 } 512 else 513 { 514 NRFX_CRITICAL_SECTION_ENTER(); 515 nrf_ppi_channels_include_in_group(channel_mask, group); 516 NRFX_CRITICAL_SECTION_EXIT(); 517 } 518 NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code)); 519 return err_code; 520 } 521 #endif // NRFX_CHECK(NRFX_PPI_ENABLED) 522