4 * \brief Timer Counter (TC) driver for SAM.
\r
6 * Copyright (c) 2011-2012 Atmel Corporation. All rights reserved.
\r
12 * Redistribution and use in source and binary forms, with or without
\r
13 * modification, are permitted provided that the following conditions are met:
\r
15 * 1. Redistributions of source code must retain the above copyright notice,
\r
16 * this list of conditions and the following disclaimer.
\r
18 * 2. Redistributions in binary form must reproduce the above copyright notice,
\r
19 * this list of conditions and the following disclaimer in the documentation
\r
20 * and/or other materials provided with the distribution.
\r
22 * 3. The name of Atmel may not be used to endorse or promote products derived
\r
23 * from this software without specific prior written permission.
\r
25 * 4. This software may only be redistributed and used in connection with an
\r
26 * Atmel microcontroller product.
\r
28 * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
\r
29 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
\r
30 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
\r
31 * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
\r
32 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
\r
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
\r
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
\r
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
\r
36 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
\r
37 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
\r
38 * POSSIBILITY OF SUCH DAMAGE.
\r
55 #define TC_WPMR_WPKEY_VALUE TC_WPMR_WPKEY((uint32_t)0x54494D)
\r
58 * \defgroup sam_drivers_tc_group Timer Counter (TC)
\r
60 * The Timer Counter (TC) includes three identical 32-bit Timer Counter
\r
61 * channels. Each channel can be independently programmed to perform a wide
\r
62 * range of functions including frequency measurement, event counting,
\r
63 * interval measurement, pulse generation, delay timing and pulse width
\r
70 * \brief Configure TC for timer, waveform generation or capture.
\r
72 * \param p_tc Pointer to a TC instance.
\r
73 * \param ul_channel Channel to configure.
\r
74 * \param ul_mode Control mode register value to set.
\r
76 * \attention If the TC is configured for waveform generation, the external
\r
77 * event selection (EEVT) should only be set to \c TC_CMR_EEVT_TIOB or the
\r
78 * equivalent value \c 0 if it really is the intention to use TIOB as an
\r
79 * external event trigger.\n
\r
80 * This is because the setting forces TIOB to be an input even if the
\r
81 * external event trigger has not been enabled with \c TC_CMR_ENETRG, and
\r
82 * thus prevents normal operation of TIOB.
\r
84 void tc_init(Tc *p_tc, uint32_t ul_channel, uint32_t ul_mode)
\r
86 TcChannel *tc_channel;
\r
89 (sizeof(p_tc->TC_CHANNEL) / sizeof(p_tc->TC_CHANNEL[0])));
\r
90 tc_channel = p_tc->TC_CHANNEL + ul_channel;
\r
92 /* Disable TC clock. */
\r
93 tc_channel->TC_CCR = TC_CCR_CLKDIS;
\r
95 /* Disable interrupts. */
\r
96 tc_channel->TC_IDR = 0xFFFFFFFF;
\r
98 /* Clear status register. */
\r
102 tc_channel->TC_CMR = ul_mode;
\r
106 * \brief Asserts a SYNC signal to generate a software trigger to
\r
109 * \param p_tc Pointer to a TC instance.
\r
112 void tc_sync_trigger(Tc *p_tc)
\r
114 p_tc->TC_BCR = TC_BCR_SYNC;
\r
118 * \brief Configure TC Block mode.
\r
119 * \note tc_init() must be called first.
\r
121 * \param p_tc Pointer to a TC instance.
\r
122 * \param ul_blockmode Block mode register value to set.
\r
125 void tc_set_block_mode(Tc *p_tc, uint32_t ul_blockmode)
\r
127 p_tc->TC_BMR = ul_blockmode;
\r
133 * \brief Configure TC for 2-bit Gray Counter for Stepper Motor.
\r
134 * \note tc_init() must be called first.
\r
136 * \param p_tc Pointer to a TC instance.
\r
137 * \param ul_channel Channel to configure.
\r
138 * \param ul_steppermode Stepper motor mode register value to set.
\r
140 * \return 0 for OK.
\r
142 uint32_t tc_init_2bit_gray(Tc *p_tc, uint32_t ul_channel,
\r
143 uint32_t ul_steppermode)
\r
145 Assert(ul_channel <
\r
146 (sizeof(p_tc->TC_CHANNEL) / sizeof(p_tc->TC_CHANNEL[0])));
\r
148 p_tc->TC_CHANNEL[ul_channel].TC_SMMR = ul_steppermode;
\r
155 * \brief Start TC clock counter on the selected channel.
\r
157 * \param p_tc Pointer to a TC instance.
\r
158 * \param ul_channel Channel to configure.
\r
160 void tc_start(Tc *p_tc, uint32_t ul_channel)
\r
162 Assert(ul_channel <
\r
163 (sizeof(p_tc->TC_CHANNEL) / sizeof(p_tc->TC_CHANNEL[0])));
\r
165 p_tc->TC_CHANNEL[ul_channel].TC_CCR = TC_CCR_CLKEN | TC_CCR_SWTRG;
\r
169 * \brief Stop TC clock counter on the selected channel.
\r
171 * \param p_tc Pointer to a TC instance.
\r
172 * \param ul_channel Channel to configure.
\r
174 void tc_stop(Tc *p_tc, uint32_t ul_channel)
\r
176 Assert(ul_channel <
\r
177 (sizeof(p_tc->TC_CHANNEL) / sizeof(p_tc->TC_CHANNEL[0])));
\r
179 p_tc->TC_CHANNEL[ul_channel].TC_CCR = TC_CCR_CLKDIS;
\r
183 * \brief Read RA TC counter on the selected channel.
\r
185 * \param p_tc Pointer to a TC instance.
\r
186 * \param ul_channel Channel to configure.
\r
188 * \return RA value.
\r
190 int tc_read_ra(Tc *p_tc, uint32_t ul_channel)
\r
192 Assert(ul_channel <
\r
193 (sizeof(p_tc->TC_CHANNEL) / sizeof(p_tc->TC_CHANNEL[0])));
\r
195 return p_tc->TC_CHANNEL[ul_channel].TC_RA;
\r
199 * \brief Read RB TC counter on the selected channel.
\r
201 * \param p_tc Pointer to a TC instance.
\r
202 * \param ul_channel Channel to configure.
\r
204 * \return RB value.
\r
206 int tc_read_rb(Tc *p_tc, uint32_t ul_channel)
\r
208 Assert(ul_channel <
\r
209 (sizeof(p_tc->TC_CHANNEL) / sizeof(p_tc->TC_CHANNEL[0])));
\r
211 return p_tc->TC_CHANNEL[ul_channel].TC_RB;
\r
215 * \brief Read RC TC counter on the selected channel.
\r
217 * \param p_tc Pointer to a TC instance.
\r
218 * \param ul_channel Channel to configure.
\r
220 * \return RC value.
\r
222 int tc_read_rc(Tc *p_tc, uint32_t ul_channel)
\r
224 Assert(ul_channel <
\r
225 (sizeof(p_tc->TC_CHANNEL) / sizeof(p_tc->TC_CHANNEL[0])));
\r
227 return p_tc->TC_CHANNEL[ul_channel].TC_RC;
\r
231 * \brief Write RA TC counter on the selected channel.
\r
233 * \param p_tc Pointer to a TC instance.
\r
234 * \param ul_channel Channel to configure.
\r
235 * \param ul_value Value to set in register.
\r
237 void tc_write_ra(Tc *p_tc, uint32_t ul_channel,
\r
240 Assert(ul_channel <
\r
241 (sizeof(p_tc->TC_CHANNEL) / sizeof(p_tc->TC_CHANNEL[0])));
\r
243 p_tc->TC_CHANNEL[ul_channel].TC_RA = ul_value;
\r
247 * \brief Write RB TC counter on the selected channel.
\r
249 * \param p_tc Pointer to a TC instance.
\r
250 * \param ul_channel Channel to configure.
\r
251 * \param ul_value Value to set in register.
\r
253 void tc_write_rb(Tc *p_tc, uint32_t ul_channel,
\r
256 Assert(ul_channel <
\r
257 (sizeof(p_tc->TC_CHANNEL) / sizeof(p_tc->TC_CHANNEL[0])));
\r
259 p_tc->TC_CHANNEL[ul_channel].TC_RB = ul_value;
\r
263 * \brief Write RC TC counter on the selected channel.
\r
265 * \param p_tc Pointer to a TC instance.
\r
266 * \param ul_channel Channel to configure.
\r
267 * \param ul_value Value to set in register.
\r
269 void tc_write_rc(Tc *p_tc, uint32_t ul_channel,
\r
272 Assert(ul_channel <
\r
273 (sizeof(p_tc->TC_CHANNEL) / sizeof(p_tc->TC_CHANNEL[0])));
\r
275 p_tc->TC_CHANNEL[ul_channel].TC_RC = ul_value;
\r
279 * \brief Enable TC interrupts on the selected channel.
\r
281 * \param p_tc Pointer to a TC instance.
\r
282 * \param ul_channel Channel to configure.
\r
283 * \param ul_sources Interrupt sources bit map.
\r
285 void tc_enable_interrupt(Tc *p_tc, uint32_t ul_channel,
\r
286 uint32_t ul_sources)
\r
288 TcChannel *tc_channel;
\r
290 Assert(ul_channel <
\r
291 (sizeof(p_tc->TC_CHANNEL) / sizeof(p_tc->TC_CHANNEL[0])));
\r
292 tc_channel = p_tc->TC_CHANNEL + ul_channel;
\r
293 tc_channel->TC_IER = ul_sources;
\r
297 * \brief Disable TC interrupts on the selected channel.
\r
299 * \param p_tc Pointer to a TC instance.
\r
300 * \param ul_channel Channel to configure.
\r
301 * \param ul_sources Interrupt sources bit map.
\r
303 void tc_disable_interrupt(Tc *p_tc, uint32_t ul_channel,
\r
304 uint32_t ul_sources)
\r
306 TcChannel *tc_channel;
\r
308 Assert(ul_channel <
\r
309 (sizeof(p_tc->TC_CHANNEL) / sizeof(p_tc->TC_CHANNEL[0])));
\r
310 tc_channel = p_tc->TC_CHANNEL + ul_channel;
\r
311 tc_channel->TC_IDR = ul_sources;
\r
315 * \brief Read TC interrupt mask on the selected channel.
\r
317 * \param p_tc Pointer to a TC instance.
\r
318 * \param ul_channel Channel to configure.
\r
320 * \return The interrupt mask value.
\r
322 uint32_t tc_get_interrupt_mask(Tc *p_tc, uint32_t ul_channel)
\r
324 TcChannel *tc_channel;
\r
326 Assert(ul_channel <
\r
327 (sizeof(p_tc->TC_CHANNEL) / sizeof(p_tc->TC_CHANNEL[0])));
\r
328 tc_channel = p_tc->TC_CHANNEL + ul_channel;
\r
329 return tc_channel->TC_IMR;
\r
333 * \brief Get current status on the selected channel.
\r
335 * \param p_tc Pointer to a TC instance.
\r
336 * \param ul_channel Channel to configure.
\r
338 * \return The current TC status.
\r
340 uint32_t tc_get_status(Tc *p_tc, uint32_t ul_channel)
\r
342 TcChannel *tc_channel;
\r
344 Assert(ul_channel <
\r
345 (sizeof(p_tc->TC_CHANNEL) / sizeof(p_tc->TC_CHANNEL[0])));
\r
346 tc_channel = p_tc->TC_CHANNEL + ul_channel;
\r
347 return tc_channel->TC_SR;
\r
350 /* TC divisor used to find the lowest acceptable timer frequency */
\r
351 #define TC_DIV_FACTOR 65536
\r
355 #ifndef FREQ_SLOW_CLOCK_EXT
\r
356 #define FREQ_SLOW_CLOCK_EXT 32768 /* External slow clock frequency (hz) */
\r
360 * \brief Find the best MCK divisor.
\r
362 * Finds the best MCK divisor given the timer frequency and MCK. The result
\r
363 * is guaranteed to satisfy the following equation:
\r
365 * (MCK / (DIV * 65536)) <= freq <= (MCK / DIV)
\r
367 * with DIV being the lowest possible value,
\r
368 * to maximize timing adjust resolution.
\r
370 * \param ul_freq Desired timer frequency.
\r
371 * \param ul_mck Master clock frequency.
\r
372 * \param p_uldiv Divisor value.
\r
373 * \param p_ultcclks TCCLKS field value for divisor.
\r
374 * \param ul_boardmck Board clock frequency.
\r
376 * \return 1 if a proper divisor has been found, otherwise 0.
\r
378 uint32_t tc_find_mck_divisor(uint32_t ul_freq, uint32_t ul_mck,
\r
379 uint32_t *p_uldiv, uint32_t *p_ultcclks, uint32_t ul_boardmck)
\r
381 const uint32_t divisors[5] = { 2, 8, 32, 128,
\r
382 ul_boardmck / FREQ_SLOW_CLOCK_EXT };
\r
384 uint32_t ul_high, ul_low;
\r
386 /* Satisfy frequency bound. */
\r
388 ul_index < (sizeof(divisors) / sizeof(divisors[0]));
\r
390 ul_high = ul_mck / divisors[ul_index];
\r
391 ul_low = ul_high / TC_DIV_FACTOR;
\r
392 if (ul_freq > ul_high) {
\r
394 } else if (ul_freq >= ul_low) {
\r
398 if (ul_index >= (sizeof(divisors) / sizeof(divisors[0]))) {
\r
402 /* Store results. */
\r
404 *p_uldiv = divisors[ul_index];
\r
408 *p_ultcclks = ul_index;
\r
418 * \brief Find the best PBA clock divisor.
\r
420 * Finds the best divisor given the timer frequency and PBA clock. The result
\r
421 * is guaranteed to satisfy the following equation:
\r
423 * (ul_pbaclk / (2* DIV * 65536)) <= freq <= (ul_pbaclk / (2* DIV))
\r
425 * with DIV being the lowest possible value,
\r
426 * to maximize timing adjust resolution.
\r
428 * \param ul_freq Desired timer frequency.
\r
429 * \param ul_mck PBA clock frequency.
\r
430 * \param p_uldiv Divisor value.
\r
431 * \param p_ultcclks TCCLKS field value for divisor.
\r
432 * \param ul_boardmck useless here.
\r
434 * \return 1 if a proper divisor has been found, otherwise 0.
\r
436 uint32_t tc_find_mck_divisor(uint32_t ul_freq, uint32_t ul_mck,
\r
437 uint32_t *p_uldiv, uint32_t *p_ultcclks, uint32_t ul_boardmck)
\r
439 const uint32_t divisors[5] = { 0, 2, 8, 32, 128};
\r
441 uint32_t ul_high, ul_low;
\r
443 UNUSED(ul_boardmck);
\r
445 /* Satisfy frequency bound. */
\r
447 ul_index < (sizeof(divisors) / sizeof(divisors[0]));
\r
449 ul_high = ul_mck / divisors[ul_index];
\r
450 ul_low = ul_high / TC_DIV_FACTOR;
\r
451 if (ul_freq > ul_high) {
\r
453 } else if (ul_freq >= ul_low) {
\r
457 if (ul_index >= (sizeof(divisors) / sizeof(divisors[0]))) {
\r
461 /* Store results. */
\r
463 *p_uldiv = divisors[ul_index];
\r
467 *p_ultcclks = ul_index;
\r
478 * \brief Enable TC QDEC interrupts.
\r
480 * \param p_tc Pointer to a TC instance.
\r
481 * \param ul_sources Interrupts to be enabled.
\r
483 void tc_enable_qdec_interrupt(Tc *p_tc, uint32_t ul_sources)
\r
485 p_tc->TC_QIER = ul_sources;
\r
489 * \brief Disable TC QDEC interrupts.
\r
491 * \param p_tc Pointer to a TC instance.
\r
492 * \param ul_sources Interrupts to be disabled.
\r
494 void tc_disable_qdec_interrupt(Tc *p_tc, uint32_t ul_sources)
\r
496 p_tc->TC_QIDR = ul_sources;
\r
500 * \brief Read TC QDEC interrupt mask.
\r
502 * \param p_tc Pointer to a TC instance.
\r
504 * \return The interrupt mask value.
\r
506 uint32_t tc_get_qdec_interrupt_mask(Tc *p_tc)
\r
508 return p_tc->TC_QIMR;
\r
512 * \brief Get current QDEC status.
\r
514 * \param p_tc Pointer to a TC instance.
\r
516 * \return The current TC status.
\r
518 uint32_t tc_get_qdec_interrupt_status(Tc *p_tc)
\r
520 return p_tc->TC_QISR;
\r
528 * \brief Enable or disable write protection of TC registers.
\r
530 * \param p_tc Pointer to a TC instance.
\r
531 * \param ul_enable 1 to enable, 0 to disable.
\r
533 void tc_set_writeprotect(Tc *p_tc, uint32_t ul_enable)
\r
536 p_tc->TC_WPMR = TC_WPMR_WPKEY_VALUE | TC_WPMR_WPEN;
\r
538 p_tc->TC_WPMR = TC_WPMR_WPKEY_VALUE;
\r
547 * \brief Indicate features.
\r
549 * \param p_tc Pointer to a TC instance.
\r
551 * \return TC_FEATURES value.
\r
553 uint32_t tc_get_feature(Tc *p_tc)
\r
555 return p_tc->TC_FEATURES;
\r
559 * \brief Indicate version.
\r
561 * \param p_tc Pointer to a TC instance.
\r
563 * \return TC_VERSION value.
\r
565 uint32_t tc_get_version(Tc *p_tc)
\r
567 return p_tc->TC_VERSION;
\r