1 /** 2 * \file 3 * 4 * \brief SAM Timer Counter (TC) driver. 5 * 6 * Copyright (c) 2011-2015 Atmel Corporation. All rights reserved. 7 * 8 * \asf_license_start 9 * 10 * \page License 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions are met: 14 * 15 * 1. Redistributions of source code must retain the above copyright notice, 16 * this list of conditions and the following disclaimer. 17 * 18 * 2. Redistributions in binary form must reproduce the above copyright notice, 19 * this list of conditions and the following disclaimer in the documentation 20 * and/or other materials provided with the distribution. 21 * 22 * 3. The name of Atmel may not be used to endorse or promote products derived 23 * from this software without specific prior written permission. 24 * 25 * 4. This software may only be redistributed and used in connection with an 26 * Atmel microcontroller product. 27 * 28 * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED 29 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 30 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE 31 * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR 32 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 36 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 37 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 38 * POSSIBILITY OF SUCH DAMAGE. 39 * 40 * \asf_license_stop 41 * 42 */ 43 /* 44 * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a> 45 */ 46 47 #include <assert.h> 48 #include "tc.h" 49 50 /// @cond 51 /**INDENT-OFF**/ 52 #ifdef __cplusplus 53 extern "C" { 54 #endif 55 /**INDENT-ON**/ 56 /// @endcond 57 58 #ifndef TC_WPMR_WPKEY_PASSWD 59 #define TC_WPMR_WPKEY_PASSWD TC_WPMR_WPKEY((uint32_t)0x54494D) 60 #endif 61 62 /** 63 * \brief Configure TC for timer, waveform generation, or capture. 64 * 65 * \param[in,out] p_tc Module hardware register base address pointer 66 * \param[in] ul_channel Channel to configure 67 * \param[in] ul_mode Control mode register bitmask value to set 68 * 69 * \note For more information regarding <i>ul_mode</i> configuration refer to 70 * the section entitled "Channel Mode Register: Capture Mode" and/or section 71 * "Waveform Operating Mode" in the device-specific datasheet. 72 * 73 * \note If the TC is configured for waveform generation then the external event 74 * selection (EEVT) should only be set to TC_CMR_EEVT_TIOB, or the 75 * equivalent value of 0, if it really is the intention to use TIOB as an 76 * external event trigger. This is because this setting forces TIOB to be 77 * an input, even if the external event trigger has not been enabled with 78 * TC_CMR_ENETRG, and thus prevents normal operation of TIOB. 79 */ 80 void tc_init( 81 Tc *p_tc, 82 uint32_t ul_channel, 83 uint32_t ul_mode) 84 { 85 TcChannel *tc_channel; 86 87 /* Validate inputs. */ 88 Assert(p_tc); 89 Assert(ul_channel < 90 (sizeof(p_tc->TC_CHANNEL) / sizeof(p_tc->TC_CHANNEL[0]))); 91 tc_channel = p_tc->TC_CHANNEL + ul_channel; 92 93 /* Disable TC clock. */ 94 tc_channel->TC_CCR = TC_CCR_CLKDIS; 95 96 /* Disable interrupts. */ 97 tc_channel->TC_IDR = 0xFFFFFFFF; 98 99 /* Clear status register. */ 100 tc_channel->TC_SR; 101 102 /* Set mode. */ 103 tc_channel->TC_CMR = ul_mode; 104 } 105 106 /** 107 * \brief Asserts a SYNC signal to generate a software trigger on 108 * all channels. 109 * 110 * \param[out] p_tc Module hardware register base address pointer 111 * 112 */ 113 void tc_sync_trigger( 114 Tc *p_tc) 115 { 116 /* Validate inputs. */ 117 Assert(p_tc); 118 119 p_tc->TC_BCR = TC_BCR_SYNC; 120 } 121 122 /** 123 * \brief Configure the TC Block mode. 124 * 125 * \note The function tc_init() must be called prior to this one. 126 * 127 * \param[out] p_tc Module hardware register base address pointer 128 * \param[in] ul_blockmode Block mode register value to set 129 * 130 * \note For more information regarding <i>ul_blockmode</i> configuration refer to 131 * the section entitled "TC Block Mode Register" in the device-specific datasheet. 132 */ 133 void tc_set_block_mode( 134 Tc *p_tc, 135 uint32_t ul_blockmode) 136 { 137 /* Validate inputs. */ 138 Assert(p_tc); 139 140 p_tc->TC_BMR = ul_blockmode; 141 } 142 143 #if (!SAM3U) || defined(__DOXYGEN__) 144 145 /** 146 * \brief Configure TC for 2-bit Gray Counter for Stepper Motor. 147 * \note The function tc_init() must be called prior to this one. 148 * 149 * \note This function is not available on SAM3U devices. 150 * 151 * \param[out] p_tc Module hardware register base address pointer 152 * \param[in] ul_channel Channel to configure 153 * \param[in] ul_steppermode Stepper motor mode register value to set 154 * 155 * \return 0 for OK. 156 */ 157 uint32_t tc_init_2bit_gray( 158 Tc *p_tc, 159 uint32_t ul_channel, 160 uint32_t ul_steppermode) 161 { 162 /* Validate inputs. */ 163 Assert(p_tc); 164 Assert(ul_channel < 165 (sizeof(p_tc->TC_CHANNEL) / sizeof(p_tc->TC_CHANNEL[0]))); 166 167 p_tc->TC_CHANNEL[ul_channel].TC_SMMR = ul_steppermode; 168 return 0; 169 } 170 171 #endif /* (!SAM3U) || defined(__DOXYGEN__) */ 172 173 /** 174 * \brief Start the TC clock on the specified channel. 175 * 176 * \param[out] p_tc Module hardware register base address pointer 177 * \param[in] ul_channel Channel to configure 178 */ 179 void tc_start( 180 Tc *p_tc, 181 uint32_t ul_channel) 182 { 183 /* Validate inputs. */ 184 Assert(p_tc); 185 Assert(ul_channel < 186 (sizeof(p_tc->TC_CHANNEL) / sizeof(p_tc->TC_CHANNEL[0]))); 187 188 p_tc->TC_CHANNEL[ul_channel].TC_CCR = TC_CCR_CLKEN | TC_CCR_SWTRG; 189 } 190 191 /** 192 * \brief Stop the TC clock on the specified channel. 193 * 194 * \param[out] p_tc Module hardware register base address pointer 195 * \param[in] ul_channel Channel to configure 196 */ 197 void tc_stop( 198 Tc *p_tc, 199 uint32_t ul_channel) 200 { 201 /* Validate inputs. */ 202 Assert(p_tc); 203 Assert(ul_channel < 204 (sizeof(p_tc->TC_CHANNEL) / sizeof(p_tc->TC_CHANNEL[0]))); 205 206 p_tc->TC_CHANNEL[ul_channel].TC_CCR = TC_CCR_CLKDIS; 207 } 208 209 /** 210 * \brief Read the counter value on the specified channel. 211 * 212 * \param[in] p_tc Module hardware register base address pointer 213 * \param[in] ul_channel Channel to read 214 * 215 * \return The counter value. 216 */ 217 uint32_t tc_read_cv( 218 Tc *p_tc, 219 uint32_t ul_channel) 220 { 221 /* Validate inputs. */ 222 Assert(p_tc); 223 Assert(ul_channel < 224 (sizeof(p_tc->TC_CHANNEL) / sizeof(p_tc->TC_CHANNEL[0]))); 225 226 return p_tc->TC_CHANNEL[ul_channel].TC_CV; 227 } 228 229 /** 230 * \brief Read TC Register A (RA) on the specified channel. 231 * 232 * \param[in] p_tc Module hardware register base address pointer 233 * \param[in] ul_channel Channel to read 234 * 235 * \return The TC Register A (RA) value. 236 */ 237 uint32_t tc_read_ra( 238 Tc *p_tc, 239 uint32_t ul_channel) 240 { 241 /* Validate inputs. */ 242 Assert(p_tc); 243 Assert(ul_channel < 244 (sizeof(p_tc->TC_CHANNEL) / sizeof(p_tc->TC_CHANNEL[0]))); 245 246 return p_tc->TC_CHANNEL[ul_channel].TC_RA; 247 } 248 249 /** 250 * \brief Read TC Register B (RB) on the specified channel. 251 * 252 * \param[in] p_tc Module hardware register base address pointer 253 * \param[in] ul_channel Channel to read 254 * 255 * \return The TC Register B (RB) value. 256 */ 257 uint32_t tc_read_rb( 258 Tc *p_tc, 259 uint32_t ul_channel) 260 { 261 /* Validate inputs. */ 262 Assert(p_tc); 263 Assert(ul_channel < 264 (sizeof(p_tc->TC_CHANNEL) / sizeof(p_tc->TC_CHANNEL[0]))); 265 266 return p_tc->TC_CHANNEL[ul_channel].TC_RB; 267 } 268 269 /** 270 * \brief Read TC Register C (RC) on the specified channel. 271 * 272 * \param[in] p_tc Module hardware register base address pointer 273 * \param[in] ul_channel Channel to read 274 * 275 * \return The Register C (RC) value. 276 */ 277 uint32_t tc_read_rc( 278 Tc *p_tc, 279 uint32_t ul_channel) 280 { 281 /* Validate inputs. */ 282 Assert(p_tc); 283 Assert(ul_channel < 284 (sizeof(p_tc->TC_CHANNEL) / sizeof(p_tc->TC_CHANNEL[0]))); 285 286 return p_tc->TC_CHANNEL[ul_channel].TC_RC; 287 } 288 289 /** 290 * \brief Write to TC Register A (RA) on the specified channel. 291 * 292 * \param[out] p_tc Module hardware register base address pointer 293 * \param[in] ul_channel Channel to write 294 * \param[in] ul_value Value to write 295 */ 296 void tc_write_ra( 297 Tc *p_tc, 298 uint32_t ul_channel, 299 uint32_t ul_value) 300 { 301 /* Validate inputs. */ 302 Assert(p_tc); 303 Assert(ul_channel < 304 (sizeof(p_tc->TC_CHANNEL) / sizeof(p_tc->TC_CHANNEL[0]))); 305 306 p_tc->TC_CHANNEL[ul_channel].TC_RA = ul_value; 307 } 308 309 /** 310 * \brief Write to TC Register B (RB) on the specified channel. 311 * 312 * \param[out] p_tc Module hardware register base address pointer 313 * \param[in] ul_channel Channel to write 314 * \param[in] ul_value Value to write 315 */ 316 void tc_write_rb( 317 Tc *p_tc, 318 uint32_t ul_channel, 319 uint32_t ul_value) 320 { 321 /* Validate inputs. */ 322 Assert(p_tc); 323 Assert(ul_channel < 324 (sizeof(p_tc->TC_CHANNEL) / sizeof(p_tc->TC_CHANNEL[0]))); 325 326 p_tc->TC_CHANNEL[ul_channel].TC_RB = ul_value; 327 } 328 329 /** 330 * \brief Write to TC Register C (RC) on the selected channel. 331 * 332 * \param[out] p_tc Module hardware register base address pointer 333 * \param[in] ul_channel Channel to write 334 * \param[in] ul_value Value to write 335 */ 336 void tc_write_rc( 337 Tc *p_tc, 338 uint32_t ul_channel, 339 uint32_t ul_value) 340 { 341 /* Validate inputs. */ 342 Assert(p_tc); 343 Assert(ul_channel < 344 (sizeof(p_tc->TC_CHANNEL) / sizeof(p_tc->TC_CHANNEL[0]))); 345 346 p_tc->TC_CHANNEL[ul_channel].TC_RC = ul_value; 347 } 348 349 /** 350 * \brief Enable the TC interrupts on the specified channel. 351 * 352 * \param[in,out] p_tc Module hardware register base address pointer 353 * \param[in] ul_channel Channel to configure 354 * \param[in] ul_sources Bitmask of interrupt sources 355 * 356 * Where the input parameter <i>ul_sources</i> can be one or more of the following: 357 * <table> 358 * <tr> 359 * <th>Parameter Value</th> 360 * <th>Description</th> 361 * </tr> 362 * <tr><td>TC_IER_COVFS</td><td>Enables the Counter Overflow Interrupt</td></tr> 363 * <tr><td>TC_IER_LOVRS</td><td>Enables the Load Overrun Interrupt</td></tr> 364 * <tr><td>TC_IER_CPAS</td><td>Enables the RA Compare Interrupt</td></tr> 365 * <tr><td>TC_IER_CPBS</td><td>Enables the RB Compare Interrupt</td></tr> 366 * <tr><td>TC_IER_CPCS</td><td>Enables the RC Compare Interrupt</td></tr> 367 * <tr><td>TC_IER_LDRAS</td><td>Enables the RA Load Interrupt</td></tr> 368 * <tr><td>TC_IER_LDRBS</td><td>Enables the RB Load Interrupt</td></tr> 369 * <tr><td>TC_IER_ETRGS</td><td>Enables the External Trigger Interrupt</td></tr> 370 * </table> 371 */ 372 void tc_enable_interrupt( 373 Tc *p_tc, 374 uint32_t ul_channel, 375 uint32_t ul_sources) 376 { 377 TcChannel *tc_channel; 378 379 /* Validate inputs. */ 380 Assert(p_tc); 381 Assert(ul_channel < 382 (sizeof(p_tc->TC_CHANNEL) / sizeof(p_tc->TC_CHANNEL[0]))); 383 tc_channel = p_tc->TC_CHANNEL + ul_channel; 384 tc_channel->TC_IER = ul_sources; 385 } 386 387 /** 388 * \brief Disable TC interrupts on the specified channel. 389 * 390 * \param[in,out] p_tc Module hardware register base address pointer 391 * \param[in] ul_channel Channel to configure 392 * \param[in] ul_sources A bitmask of Interrupt sources 393 * 394 * Where the input parameter <i>ul_sources</i> can be one or more of the following: 395 * <table> 396 * <tr> 397 * <th>Parameter Value</th> 398 * <th>Description</th> 399 * </tr> 400 * <tr><td>TC_IDR_COVFS</td><td>Disables the Counter Overflow Interrupt</td></tr> 401 * <tr><td>TC_IDR_LOVRS</td><td>Disables the Load Overrun Interrupt</td></tr> 402 * <tr><td>TC_IDR_CPAS</td><td>Disables the RA Compare Interrupt</td></tr> 403 * <tr><td>TC_IDR_CPBS</td><td>Disables the RB Compare Interrupt</td></tr> 404 * <tr><td>TC_IDR_CPCS</td><td>Disables the RC Compare Interrupt</td></tr> 405 * <tr><td>TC_IDR_LDRAS</td><td>Disables the RA Load Interrupt</td></tr> 406 * <tr><td>TC_IDR_LDRBS</td><td>Disables the RB Load Interrupt</td></tr> 407 * <tr><td>TC_IDR_ETRGS</td><td>Disables the External Trigger Interrupt</td></tr> 408 * </table> 409 */ 410 void tc_disable_interrupt( 411 Tc *p_tc, 412 uint32_t ul_channel, 413 uint32_t ul_sources) 414 { 415 TcChannel *tc_channel; 416 417 /* Validate inputs. */ 418 Assert(p_tc); 419 Assert(ul_channel < 420 (sizeof(p_tc->TC_CHANNEL) / sizeof(p_tc->TC_CHANNEL[0]))); 421 tc_channel = p_tc->TC_CHANNEL + ul_channel; 422 tc_channel->TC_IDR = ul_sources; 423 } 424 425 /** 426 * \brief Read the TC interrupt mask for the specified channel. 427 * 428 * \param[in] p_tc Module hardware register base address pointer 429 * \param[in] ul_channel Channel to read 430 * 431 * \return The TC interrupt mask value. 432 */ 433 uint32_t tc_get_interrupt_mask( 434 Tc *p_tc, 435 uint32_t ul_channel) 436 { 437 TcChannel *tc_channel; 438 439 /* Validate inputs. */ 440 Assert(p_tc); 441 Assert(ul_channel < 442 (sizeof(p_tc->TC_CHANNEL) / sizeof(p_tc->TC_CHANNEL[0]))); 443 tc_channel = p_tc->TC_CHANNEL + ul_channel; 444 return tc_channel->TC_IMR; 445 } 446 447 /** 448 * \brief Get the current status for the specified TC channel. 449 * 450 * \param[in] p_tc Module hardware register base address pointer 451 * \param[in] ul_channel Channel number 452 * 453 * \return The current TC status. 454 */ 455 uint32_t tc_get_status( 456 Tc *p_tc, 457 uint32_t ul_channel) 458 { 459 TcChannel *tc_channel; 460 461 /* Validate inputs. */ 462 Assert(p_tc); 463 Assert(ul_channel < 464 (sizeof(p_tc->TC_CHANNEL) / sizeof(p_tc->TC_CHANNEL[0]))); 465 466 tc_channel = p_tc->TC_CHANNEL + ul_channel; 467 return tc_channel->TC_SR; 468 } 469 470 /* TC divisor used to find the lowest acceptable timer frequency */ 471 #define TC_DIV_FACTOR 65536 472 473 #if (!SAM4L) && !defined(__DOXYGEN__) 474 475 #ifndef FREQ_SLOW_CLOCK_EXT 476 #define FREQ_SLOW_CLOCK_EXT 32768 /* External slow clock frequency (hz) */ 477 #endif 478 479 /** 480 * \brief Find the best MCK divisor. 481 * 482 * Finds the best MCK divisor given the timer frequency and MCK. The result 483 * is guaranteed to satisfy the following equation: 484 * \code (MCK / (DIV * 65536)) <= freq <= (MCK / DIV) \endcode 485 * With DIV being the lowest possible value, to maximize timing adjust resolution. 486 * 487 * \param[in] ul_freq Desired timer frequency 488 * \param[in] ul_mck Master clock frequency 489 * \param[out] p_uldiv Divisor value 490 * \param[out] p_ultcclks TCCLKS field value for divisor 491 * \param[in] ul_boardmck Board clock frequency 492 * 493 * \return The divisor found status. 494 * \retval 0 No suitable divisor was found 495 * \retval 1 A divisor was found 496 */ 497 uint32_t tc_find_mck_divisor( 498 uint32_t ul_freq, 499 uint32_t ul_mck, 500 uint32_t *p_uldiv, 501 uint32_t *p_ultcclks, 502 uint32_t ul_boardmck) 503 { 504 const uint32_t divisors[5] = { 2, 8, 32, 128, 505 ul_boardmck / FREQ_SLOW_CLOCK_EXT }; 506 uint32_t ul_index; 507 uint32_t ul_high, ul_low; 508 509 /* Satisfy frequency bound. */ 510 for (ul_index = 0; 511 ul_index < (sizeof(divisors) / sizeof(divisors[0])); 512 ul_index++) { 513 ul_high = ul_mck / divisors[ul_index]; 514 ul_low = ul_high / TC_DIV_FACTOR; 515 if (ul_freq > ul_high) { 516 return 0; 517 } else if (ul_freq >= ul_low) { 518 break; 519 } 520 } 521 if (ul_index >= (sizeof(divisors) / sizeof(divisors[0]))) { 522 return 0; 523 } 524 525 /* Store results. */ 526 if (p_uldiv) { 527 *p_uldiv = divisors[ul_index]; 528 } 529 530 if (p_ultcclks) { 531 *p_ultcclks = ul_index; 532 } 533 534 return 1; 535 } 536 537 #endif /* (!SAM4L) */ 538 539 #if (SAM4L) || defined(__DOXYGEN__) 540 /** 541 * \brief Find the best PBA/MCK divisor. 542 * 543 * <b>For SAM4L devices:</b> Finds the best PBA divisor given the timer 544 * frequency and PBA clock. The result is guaranteed to satisfy the following equation: 545 * \code (ul_pbaclk / (2* DIV * 65536)) <= freq <= (ul_pbaclk / (2* DIV)) \endcode 546 * with DIV being the lowest possible value, to maximize timing adjust resolution. 547 * 548 * <b>For non SAM4L devices:</b> Finds the best MCK divisor given the timer frequency 549 * and MCK. The result is guaranteed to satisfy the following equation: 550 * \code (MCK / (DIV * 65536)) <= freq <= (MCK / DIV) \endcode 551 * with DIV being the lowest possible value, to maximize timing adjust resolution. 552 * 553 * \param[in] ul_freq Desired timer frequency 554 * \param[in] ul_mck PBA clock frequency 555 * \param[out] p_uldiv Divisor value 556 * \param[out] p_ultcclks TCCLKS field value for divisor 557 * \param[in] ul_boardmck Board clock frequency (set to 0 for SAM4L devices) 558 * 559 * \return The divisor found status. 560 * \retval 0 No suitable divisor was found 561 * \retval 1 A divisor was found 562 */ 563 uint32_t tc_find_mck_divisor( 564 uint32_t ul_freq, 565 uint32_t ul_mck, 566 uint32_t *p_uldiv, 567 uint32_t *p_ultcclks, 568 uint32_t ul_boardmck) 569 { 570 const uint32_t divisors[5] = { 0, 2, 8, 32, 128}; 571 uint32_t ul_index; 572 uint32_t ul_high, ul_low; 573 574 UNUSED(ul_boardmck); 575 576 /* Satisfy frequency bound. */ 577 for (ul_index = 1; 578 ul_index < (sizeof(divisors) / sizeof(divisors[0])); 579 ul_index++) { 580 ul_high = ul_mck / divisors[ul_index]; 581 ul_low = ul_high / TC_DIV_FACTOR; 582 if (ul_freq > ul_high) { 583 return 0; 584 } else if (ul_freq >= ul_low) { 585 break; 586 } 587 } 588 if (ul_index >= (sizeof(divisors) / sizeof(divisors[0]))) { 589 return 0; 590 } 591 592 /* Store results. */ 593 if (p_uldiv) { 594 *p_uldiv = divisors[ul_index]; 595 } 596 597 if (p_ultcclks) { 598 *p_ultcclks = ul_index; 599 } 600 601 return 1; 602 } 603 604 #endif /* (SAM4L) || defined(__DOXYGEN__) */ 605 606 #if (!SAM4L && !SAMG) || defined(__DOXYGEN__) 607 608 /** 609 * \brief Enable TC QDEC interrupts. 610 * 611 * \note This function is not available on SAM4L or SAMG devices. 612 * 613 * \param[out] p_tc Module hardware register base address pointer 614 * \param[in] ul_sources A bitmask of QDEC interrupts to be enabled 615 * 616 * Where the input parameter <i>ul_sources</i> can be one or more of the following: 617 * <table> 618 * <tr> 619 * <th>Parameter Value</th> 620 * <th>Description</th> 621 * </tr> 622 * <tr><td>TC_QIER_IDX</td><td>Enable the rising edge detected on IDX input interrupt</td></tr> 623 * <tr><td>TC_QIER_DIRCHG</td><td>Enable the change in rotation direction detected interrupt</td></tr> 624 * <tr><td>TC_QIER_QERR</td><td>Enable the quadrature error detected on PHA/PHB interrupt</td></tr> 625 * </table> 626 */ 627 void tc_enable_qdec_interrupt( 628 Tc *p_tc, 629 uint32_t ul_sources) 630 { 631 /* Validate inputs. */ 632 Assert(p_tc); 633 634 p_tc->TC_QIER = ul_sources; 635 } 636 637 /** 638 * \brief Disable TC QDEC interrupts. 639 * 640 * \note This function is not available on SAM4L or SAMG devices. 641 * 642 * \param[out] p_tc Module hardware register base address pointer 643 * \param[in] ul_sources A bitmask of QDEC interrupts to be disabled 644 * 645 * Where the input parameter <i>ul_sources</i> can be one or more of the following: 646 * <table> 647 * <tr> 648 * <th>Parameter Value</th> 649 * <th>Description</th> 650 * </tr> 651 * <tr><td>TC_QIDR_IDX</td><td>Disable the rising edge detected on IDX input interrupt</td></tr> 652 * <tr><td>TC_QIDR_DIRCHG</td><td>Disable the change in rotation direction detected interrupt</td></tr> 653 * <tr><td>TC_QIDR_QERR</td><td>Disable the quadrature error detected on PHA/PHB interrupt</td></tr> 654 * </table> 655 */ 656 void tc_disable_qdec_interrupt( 657 Tc *p_tc, 658 uint32_t ul_sources) 659 { 660 /* Validate inputs. */ 661 Assert(p_tc); 662 663 p_tc->TC_QIDR = ul_sources; 664 } 665 666 /** 667 * \brief Read TC QDEC interrupt mask. 668 * 669 * \note This function is not available on SAM4L or SAMG devices. 670 * 671 * \param[in] p_tc Module hardware register base address pointer 672 * 673 * \return The QDEC interrupt mask value. 674 */ 675 uint32_t tc_get_qdec_interrupt_mask( 676 Tc *p_tc) 677 { 678 /* Validate inputs. */ 679 Assert(p_tc); 680 681 return p_tc->TC_QIMR; 682 } 683 684 /** 685 * \brief Get current TC QDEC interrupt status. 686 * 687 * \note This function is not available on SAM4L or SAMG devices. 688 * 689 * \param[in] p_tc Module hardware register base address pointer 690 * 691 * \return The TC QDEC interrupt status. 692 */ 693 uint32_t tc_get_qdec_interrupt_status( 694 Tc *p_tc) 695 { 696 /* Validate inputs. */ 697 Assert(p_tc); 698 699 return p_tc->TC_QISR; 700 } 701 702 #endif /* (!SAM4L && !SAMG) || defined(__DOXYGEN__) */ 703 704 #if (!SAM3U) || defined(__DOXYGEN__) 705 706 /** 707 * \brief Enable or disable write protection of TC registers. 708 * 709 * \note This function is not available on SAM3U devices. 710 * 711 * \param[out] p_tc Module hardware register base address pointer 712 * \param[in] ul_enable 1 to enable, 0 to disable 713 */ 714 void tc_set_writeprotect( 715 Tc *p_tc, 716 uint32_t ul_enable) 717 { 718 /* Validate inputs. */ 719 Assert(p_tc); 720 721 if (ul_enable) { 722 p_tc->TC_WPMR = TC_WPMR_WPKEY_PASSWD | TC_WPMR_WPEN; 723 } else { 724 p_tc->TC_WPMR = TC_WPMR_WPKEY_PASSWD; 725 } 726 } 727 728 #endif /* (!SAM3U) || defined(__DOXYGEN__) */ 729 730 #if SAM4L || defined(__DOXYGEN__) 731 732 /** 733 * \brief Indicate TC features. 734 * 735 * \note This function is only available on SAM4L devices. 736 * 737 * \param[in] p_tc Module hardware register base address pointer 738 * 739 * \return The TC FEATURES register contents. 740 */ 741 uint32_t tc_get_feature( 742 Tc *p_tc) 743 { 744 /* Validate inputs. */ 745 Assert(p_tc); 746 747 return p_tc->TC_FEATURES; 748 } 749 750 /** 751 * \brief Indicate TC version. 752 * 753 * \note This function is only available on SAM4L devices. 754 * 755 * \param[in] p_tc Module hardware register base address pointer 756 * 757 * \return The TC VERSION register contents. 758 */ 759 uint32_t tc_get_version( 760 Tc *p_tc) 761 { 762 /* Validate inputs. */ 763 Assert(p_tc); 764 765 return p_tc->TC_VERSION; 766 } 767 768 #endif /* SAM4L || defined(__DOXYGEN__) */ 769 770 /// @cond 771 /**INDENT-OFF**/ 772 #ifdef __cplusplus 773 } 774 #endif 775 /**INDENT-ON**/ 776 /// @endcond 777