tcc.c 49 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608
  1. /**
  2. * \file
  3. *
  4. * \brief SAM TCC - Timer Counter for Control Applications Driver
  5. *
  6. * Copyright (C) 2013-2016 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. #include "tcc.h"
  47. #if TCC_ASYNC == true
  48. # include "tcc_callback.h"
  49. # include <system_interrupt.h>
  50. /** \internal
  51. * Converts a given TCC index to its interrupt vector index.
  52. */
  53. # define _TCC_INTERRUPT_VECT_NUM(n, unused) \
  54. SYSTEM_INTERRUPT_MODULE_TCC##n,
  55. #endif
  56. #define _SIZE_MAX(size) ((size==32u) ? 0xFFFFFFFF : ( \
  57. (1u << size) - 1))
  58. #define _SIZE_MAX_WITH_DITHER 0x03FFFFFF
  59. /* Extension support mapping bits */
  60. #define _TCC_DITHERING_B 16u
  61. #define _TCC_PG_B 8u
  62. #define _TCC_SWAP_B 4u
  63. #define _TCC_DTI_B 2u
  64. #define _TCC_OTMX_B 1u
  65. #if !defined(__DOXYGEN__)
  66. # define _TCC_GCLK_ID(n,unused) TPASTE3(TCC,n,_GCLK_ID),
  67. # if (SAML21) || (SAML22) || (SAMC20) || (SAMC21) || (SAMR30)
  68. # define _TCC_APBCMASK(n,unused) TPASTE2(MCLK_APBCMASK_TCC,n),
  69. # else
  70. # define _TCC_APBCMASK(n,unused) TPASTE2(PM_APBCMASK_TCC,n),
  71. # endif
  72. # define _TCC_SIZE(n,unused) TPASTE3(TCC,n,_SIZE),
  73. # define _TCC_MAX(n,unused) _SIZE_MAX(TPASTE3(TCC,n,_SIZE)),
  74. # define _TCC_EXT(n,unused) TPASTE3(TCC,n,_EXT),
  75. # define _TCC_CC_NUM(n,unused) min(TPASTE3(TCC,n,_CC_NUM),TCC_NUM_CHANNELS),
  76. # define _TCC_OW_NUM(n,unused) min(TPASTE3(TCC,n,_OW_NUM),TCC_NUM_WAVE_OUTPUTS),
  77. # define TCC_GCLK_IDS { MREPEAT(TCC_INST_NUM, _TCC_GCLK_ID, 0) }
  78. # define TCC_APBCMASKS { MREPEAT(TCC_INST_NUM, _TCC_APBCMASK, 0) }
  79. # define TCC_SIZES { MREPEAT(TCC_INST_NUM, _TCC_SIZE, 0) }
  80. # define TCC_MAXS { MREPEAT(TCC_INST_NUM, _TCC_MAX, 0) }
  81. # define TCC_EXTS { MREPEAT(TCC_INST_NUM, _TCC_EXT, 0) }
  82. # define TCC_CC_NUMS { MREPEAT(TCC_INST_NUM, _TCC_CC_NUM, 0) }
  83. # define TCC_OW_NUMS { MREPEAT(TCC_INST_NUM, _TCC_OW_NUM, 0) }
  84. #endif
  85. /* List of available TCC modules. */
  86. const Tcc *const tcc_modules[TCC_INST_NUM] = TCC_INSTS;
  87. /* List of TCC GCLK IDs */
  88. const uint8_t _tcc_gclk_ids[TCC_INST_NUM] = TCC_GCLK_IDS;
  89. /* List of TCC APBC Masks */
  90. const uint32_t _tcc_apbcmasks[TCC_INST_NUM] = TCC_APBCMASKS;
  91. /* List of extension support of TCC modules. */
  92. const uint8_t _tcc_exts[TCC_INST_NUM] = TCC_EXTS;
  93. /* List of sizes support of TCC modules. */
  94. const uint8_t _tcc_sizes[TCC_INST_NUM] = TCC_SIZES;
  95. /* List of maximumvalues supported of TCC modules. */
  96. const uint32_t _tcc_maxs[TCC_INST_NUM] = TCC_MAXS;
  97. /* List of available channel number of TCC modules. */
  98. const uint8_t _tcc_cc_nums[TCC_INST_NUM] = TCC_CC_NUMS;
  99. /* List of available output number of TCC modules. */
  100. const uint8_t _tcc_ow_nums[TCC_INST_NUM] = TCC_OW_NUMS;
  101. /**
  102. * \internal Find the index of the given TCC module instance.
  103. *
  104. * \param[in] The TCC module instance pointer
  105. *
  106. * \return Index of the given TCC module instance.
  107. */
  108. uint8_t _tcc_get_inst_index(
  109. Tcc *const hw)
  110. {
  111. /* Find index for TCC instance. */
  112. for (uint32_t i = 0; i < TCC_INST_NUM; i++) {
  113. if (hw == tcc_modules[i]) {
  114. return i;
  115. }
  116. }
  117. /* Invalid data given. */
  118. Assert(false);
  119. return 0;
  120. }
  121. /**
  122. * \brief Initializes config with predefined default values.
  123. *
  124. * This function will initialize a given TCC configuration structure to
  125. * a set of known default values. This function should be called on
  126. * any new instance of the configuration structures before being
  127. * modified by the user application.
  128. *
  129. * The default configuration is as follows:
  130. * \li Don't run in standby
  131. * \li When setting top, compare, or pattern by API, do double buffering write
  132. * \li The base timer/counter configurations:
  133. * - GCLK generator 0 clock source
  134. * - No prescaler
  135. * - GCLK reload action
  136. * - Count upward
  137. * - Don't perform one-shot operations
  138. * - Counter starts on 0
  139. * - Period/top value set to maximum
  140. * \li The match/capture configurations:
  141. * - All Capture compare channel value set to 0
  142. * - No capture enabled (all channels use compare function)
  143. * - Normal frequency wave generation
  144. * - Waveform generation polarity set to 0
  145. * - Don't perform ramp on waveform
  146. * \li The waveform extension configurations:
  147. * - No recoverable fault is enabled, fault actions are disabled, filter
  148. * is set to 0
  149. * - No non-recoverable fault state output is enabled and filter is 0
  150. * - No inversion of waveform output
  151. * \li No channel output enabled
  152. * \li No PWM pin output enabled
  153. * \li Pin and MUX configuration not set
  154. *
  155. * \param[out] config Pointer to a TCC module configuration structure to set
  156. * \param[in] hw Pointer to the TCC hardware module
  157. *
  158. */
  159. void tcc_get_config_defaults(
  160. struct tcc_config *const config,
  161. Tcc *const hw)
  162. {
  163. /* TCC instance index */
  164. uint8_t module_index = _tcc_get_inst_index(hw);
  165. /* Base counter defaults */
  166. config->counter.count = 0;
  167. config->counter.period = _tcc_maxs[module_index];
  168. config->counter.clock_source = GCLK_GENERATOR_0;
  169. config->counter.clock_prescaler = TCC_CLOCK_PRESCALER_DIV1;
  170. config->counter.reload_action = TCC_RELOAD_ACTION_GCLK;
  171. config->counter.direction = TCC_COUNT_DIRECTION_UP;
  172. config->counter.oneshot = false;
  173. #ifdef FEATURE_TCC_GENERATE_DMA_TRIGGER
  174. config->counter.dma_trigger_mode = TCC_COUNT_OVERFLOW_DMA_TRIGGER_MODE_CONTINUE;
  175. #endif
  176. /* Match/Capture defaults */
  177. # define _TCC_CHANNEL_MATCH_VALUE_INIT(n, value) \
  178. config->compare.match[n] = value;
  179. MREPEAT(TCC_NUM_CHANNELS,
  180. _TCC_CHANNEL_MATCH_VALUE_INIT, 0)
  181. # undef _TCC_CHANNEL_MATCH_VALUE_INIT
  182. /* Wave polarity defaults */
  183. # define _TCC_CHANNEL_WAVE_POLARITY_INIT(n, value) \
  184. config->compare.wave_polarity[n] = value;
  185. MREPEAT(TCC_NUM_CHANNELS,
  186. _TCC_CHANNEL_WAVE_POLARITY_INIT, TCC_WAVE_POLARITY_0)
  187. # undef _TCC_CHANNEL_WAVE_POLARITY_INIT
  188. config->compare.wave_generation = TCC_WAVE_GENERATION_NORMAL_FREQ;
  189. config->compare.wave_ramp = TCC_RAMP_RAMP1;
  190. # define _TCC_CHANNEL_FUNCTION_INIT(n, value) \
  191. config->compare.channel_function[n] = value;
  192. MREPEAT(TCC_NUM_CHANNELS,
  193. _TCC_CHANNEL_FUNCTION_INIT, TCC_CHANNEL_FUNCTION_COMPARE)
  194. # undef _TCC_CHANNEL_FUNCTION_INIT
  195. /* Recoverable fault defaults */
  196. # define _TCC_FAULT_FUNCTION_INIT(n, dummy) \
  197. config->wave_ext.recoverable_fault[n].filter_value = 0; \
  198. config->wave_ext.recoverable_fault[n].blanking_cycles = 0; \
  199. config->wave_ext.recoverable_fault[n].restart = false; \
  200. config->wave_ext.recoverable_fault[n].keep = false; \
  201. config->wave_ext.recoverable_fault[n].qualification = false; \
  202. config->wave_ext.recoverable_fault[n].source = TCC_FAULT_SOURCE_DISABLE; \
  203. config->wave_ext.recoverable_fault[n].blanking = TCC_FAULT_BLANKING_DISABLE; \
  204. config->wave_ext.recoverable_fault[n].halt_action = TCC_FAULT_HALT_ACTION_DISABLE; \
  205. config->wave_ext.recoverable_fault[n].capture_action = TCC_FAULT_CAPTURE_DISABLE; \
  206. config->wave_ext.recoverable_fault[n].capture_channel = TCC_FAULT_CAPTURE_CHANNEL_0;
  207. MREPEAT(TCC_NUM_FAULTS, _TCC_FAULT_FUNCTION_INIT, 0)
  208. # undef _TCC_FAULT_FUNCTION_INIT
  209. /* Non-recoverable fault defaults */
  210. # define _TCC_NRF_FUNCTION_INIT(n, dummy) \
  211. config->wave_ext.non_recoverable_fault[n].filter_value = 0; \
  212. config->wave_ext.non_recoverable_fault[n].output = TCC_FAULT_STATE_OUTPUT_OFF;
  213. MREPEAT(TCC_NUM_WAVE_OUTPUTS, _TCC_NRF_FUNCTION_INIT, 0)
  214. # undef _TCC_NRF_FUNCTION_INIT
  215. /* Output inversion defaults */
  216. # define _TCC_OUT_INVERT_INIT(n, value) \
  217. config->wave_ext.invert[n] = value;
  218. MREPEAT(TCC_NUM_WAVE_OUTPUTS, _TCC_OUT_INVERT_INIT, false)
  219. # undef _TCC_OUT_INVERT_INIT
  220. # define _TCC_CHANNEL_OUT_PIN_INIT(n, dummy) \
  221. config->pins.enable_wave_out_pin[n] = false;\
  222. config->pins.wave_out_pin[TCC_WAVE_OUTPUT_##n] = 0; \
  223. config->pins.wave_out_pin_mux[TCC_WAVE_OUTPUT_##n] = 0;
  224. MREPEAT(TCC_NUM_WAVE_OUTPUTS, _TCC_CHANNEL_OUT_PIN_INIT, 0)
  225. # undef _TCC_CHANNEL_OUT_PIN_INIT
  226. config->double_buffering_enabled = true;
  227. config->run_in_standby = false;
  228. }
  229. /**
  230. * \brief Build CTRLA register value from configuration.
  231. *
  232. * \param[in] module_index The software module instance index
  233. * \param[in] config Pointer to the TCC configuration options struct
  234. * \param[out] value_buffer Pointer to the buffer to fill with built value
  235. *
  236. * \return Configuration validation status.
  237. *
  238. * \retval STATUS_OK Configuration values are good and register
  239. * value built and save to buffer
  240. * \retval STATUS_ERR_INVALID_ARG Invalid parameter found:
  241. * assigned dither mode is invalid for module;
  242. * used capture channel is invalid for module
  243. */
  244. static inline enum status_code _tcc_build_ctrla(
  245. const uint8_t module_index,
  246. const struct tcc_config *const config,
  247. uint32_t *value_buffer)
  248. {
  249. uint32_t ctrla = 0;
  250. int i;
  251. for (i = 0; i < TCC_NUM_CHANNELS; i ++) {
  252. if (config->capture.channel_function[i] ==
  253. TCC_CHANNEL_FUNCTION_CAPTURE) {
  254. if (i > _tcc_cc_nums[module_index]) {
  255. /* Channel not supported */
  256. return STATUS_ERR_INVALID_ARG;
  257. }
  258. ctrla |= (TCC_CTRLA_CPTEN0 << i);
  259. }
  260. }
  261. if (config->run_in_standby) {
  262. ctrla |= TCC_CTRLA_RUNSTDBY;
  263. }
  264. ctrla |= config->counter.reload_action << TCC_CTRLA_PRESCSYNC_Pos;
  265. ctrla |= config->counter.clock_prescaler << TCC_CTRLA_PRESCALER_Pos;
  266. *value_buffer = ctrla;
  267. return STATUS_OK;
  268. }
  269. /**
  270. * \brief Build CTRLB register value from configuration.
  271. *
  272. * \param[in] module_index The software module instance index
  273. * \param[in] config Pointer to the TCC configuration options struct
  274. * \param[out] value_buffer Pointer to the buffer to fill with built value
  275. */
  276. static inline void _tcc_build_ctrlb(
  277. const uint8_t module_index,
  278. const struct tcc_config *const config,
  279. uint8_t *value_buffer)
  280. {
  281. uint8_t ctrlb = 0;
  282. if (config->counter.oneshot) {
  283. ctrlb |= TCC_CTRLBSET_ONESHOT;
  284. }
  285. if (config->counter.direction == TCC_COUNT_DIRECTION_DOWN) {
  286. ctrlb |= TCC_CTRLBSET_DIR;
  287. }
  288. *value_buffer = ctrlb;
  289. }
  290. /**
  291. * \brief Build FAULTs register values from configuration.
  292. *
  293. * \param[in] module_index The software module instance index
  294. * \param[in] config Pointer to the TCC configuration options struct
  295. * \param[out] value_buffer Pointer to the buffer to fill with built values
  296. *
  297. * \retval STATUS_OK Configuration values are good and register
  298. * value built and save to buffer
  299. * \retval STATUS_ERR_INVALID_ARG Invalid parameter found: assigned fault
  300. * capture channel is invalid; assigned filter
  301. * value is invalid
  302. */
  303. static inline enum status_code _tcc_build_faults(
  304. const uint8_t module_index,
  305. const struct tcc_config *const config,
  306. uint32_t *value_buffer)
  307. {
  308. struct tcc_recoverable_fault_config *cfg;
  309. uint8_t cc_num = _tcc_cc_nums[module_index];
  310. uint32_t fault;
  311. int i;
  312. for (i = 0; i < TCC_NUM_FAULTS; i ++) {
  313. cfg = (struct tcc_recoverable_fault_config *)
  314. &config->wave_ext.recoverable_fault[i];
  315. if (cfg->capture_channel >= cc_num) {
  316. return STATUS_ERR_INVALID_ARG;
  317. }
  318. if (cfg->filter_value > 0xF) {
  319. return STATUS_ERR_INVALID_ARG;
  320. }
  321. fault = TCC_FCTRLA_FILTERVAL(cfg->filter_value)
  322. | TCC_FCTRLA_BLANKVAL(cfg->blanking_cycles)
  323. | (cfg->restart ? TCC_FCTRLA_RESTART : 0)
  324. | (cfg->keep ? TCC_FCTRLA_KEEP : 0)
  325. | (cfg->qualification ? TCC_FCTRLA_QUAL : 0)
  326. | TCC_FCTRLA_SRC(cfg->source)
  327. | TCC_FCTRLA_BLANK(cfg->blanking)
  328. | TCC_FCTRLA_HALT(cfg->halt_action)
  329. | TCC_FCTRLA_CAPTURE(cfg->capture_action)
  330. | TCC_FCTRLA_CHSEL(cfg->capture_channel);
  331. value_buffer[i] = fault;
  332. }
  333. return STATUS_OK;
  334. }
  335. /**
  336. * \brief Build DRVCTRL register values from configuration.
  337. *
  338. * \param[in] module_index The software module instance index
  339. * \param[in] config Pointer to the TCC configuration options struct
  340. * \param[out] value_buffer Pointer to the buffer to fill with built value
  341. *
  342. * \retval STATUS_OK Configuration values are good and register
  343. * value built and save to buffer
  344. * \retval STATUS_ERR_INVALID_ARG Invalid parameter found: assigned output line
  345. * is invalid; filter value is invalid
  346. */
  347. static inline enum status_code _tcc_build_drvctrl(
  348. const uint8_t module_index,
  349. const struct tcc_config *const config,
  350. uint32_t *value_buffer)
  351. {
  352. uint32_t i;
  353. uint8_t ow_num = _tcc_ow_nums[module_index];
  354. uint32_t drvctrl;
  355. drvctrl = 0;
  356. for (i = 0; i < TCC_NUM_WAVE_OUTPUTS; i ++) {
  357. if (config->wave_ext.invert[i]) {
  358. if (i >= ow_num) {
  359. return STATUS_ERR_INVALID_ARG;
  360. }
  361. drvctrl |= (TCC_DRVCTRL_INVEN0 << i);
  362. }
  363. if (config->wave_ext.non_recoverable_fault[i].output !=
  364. TCC_FAULT_STATE_OUTPUT_OFF) {
  365. if (i >= ow_num) {
  366. return STATUS_ERR_INVALID_ARG;
  367. }
  368. if (config->wave_ext.non_recoverable_fault[i].output ==
  369. TCC_FAULT_STATE_OUTPUT_1) {
  370. drvctrl |= (TCC_DRVCTRL_NRE0 | TCC_DRVCTRL_NRV0) << i;
  371. } else {
  372. drvctrl |= (TCC_DRVCTRL_NRE0) << i;
  373. }
  374. }
  375. }
  376. *value_buffer = drvctrl;
  377. return STATUS_OK;
  378. }
  379. /**
  380. * \brief Build WAVE & WAVEB register values from configuration.
  381. *
  382. * \param[in] module_index The software module instance index
  383. * \param[in] config Pointer to the TCC configuration options struct
  384. * \param[out] value_buffer Pointer to the buffer to fill with built value
  385. *
  386. * \retval STATUS_OK Configuration values are good and register
  387. * value built and save to buffer
  388. * \retval STATUS_ERR_INVALID_ARG Invalid parameter found: assigned output line
  389. * is invalid; circular and double buffering
  390. * conflict; assigned function not supported by
  391. * module
  392. */
  393. static inline enum status_code _tcc_build_waves(
  394. const uint8_t module_index,
  395. const struct tcc_config *const config,
  396. uint32_t *value_buffer)
  397. {
  398. int n;
  399. uint8_t cc_num = _tcc_cc_nums[module_index];
  400. struct tcc_match_wave_config const *wav_cfg = &config->compare;
  401. uint32_t wave;
  402. wave = TCC_WAVE_RAMP(wav_cfg->wave_ramp) |
  403. TCC_WAVE_WAVEGEN(wav_cfg->wave_generation);
  404. for (n = 0; n < TCC_NUM_CHANNELS; n++) {
  405. if (wav_cfg->wave_polarity[n]) {
  406. if (n >= cc_num) {
  407. return STATUS_ERR_INVALID_ARG;
  408. }
  409. wave |= (TCC_WAVE_POL0 << n);
  410. }
  411. }
  412. value_buffer[0] = wave;
  413. return STATUS_OK;
  414. }
  415. /**
  416. * \brief Initializes a hardware TCC module instance.
  417. *
  418. * Enables the clock and initializes the given TCC module, based on the given
  419. * configuration values.
  420. *
  421. * \param[in,out] module_inst Pointer to the software module instance struct
  422. * \param[in] hw Pointer to the TCC hardware module
  423. * \param[in] config Pointer to the TCC configuration options struct
  424. *
  425. * \return Status of the initialization procedure.
  426. *
  427. * \retval STATUS_OK The module was initialized successfully
  428. * \retval STATUS_BUSY The hardware module was busy when the
  429. * initialization procedure was attempted
  430. * \retval STATUS_INVALID_ARG An invalid configuration option or argument
  431. * was supplied
  432. * \retval STATUS_ERR_DENIED The hardware module was already enabled
  433. */
  434. enum status_code tcc_init(
  435. struct tcc_module *const module_inst,
  436. Tcc *const hw,
  437. const struct tcc_config *const config)
  438. {
  439. int i;
  440. /* Sanity check arguments */
  441. Assert(hw);
  442. Assert(module_inst);
  443. Assert(config);
  444. /* TCC instance index */
  445. uint8_t module_index = _tcc_get_inst_index(hw);
  446. /* Enable the user interface clock for TCC */
  447. system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC,
  448. _tcc_apbcmasks[module_index]);
  449. /* Check if it's enabled. */
  450. if (hw->CTRLA.reg & TCC_CTRLA_ENABLE) {
  451. return STATUS_ERR_DENIED;
  452. }
  453. /* Check if it's resetting */
  454. if (hw->CTRLA.reg & TCC_CTRLA_SWRST) {
  455. return STATUS_ERR_DENIED;
  456. }
  457. enum status_code status;
  458. /* Check COUNT, PER, CCx */
  459. uint32_t count_max = _tcc_maxs[module_index];
  460. /* Check all counter values */
  461. if ((config->counter.count > count_max)
  462. || (config->counter.period > count_max)
  463. ) {
  464. return STATUS_ERR_INVALID_ARG;
  465. }
  466. /* Check all channel values */
  467. for (i = 0; i < TCC_NUM_CHANNELS; i ++) {
  468. if ((config->compare.match[i] > count_max)
  469. ) {
  470. return STATUS_ERR_INVALID_ARG;
  471. }
  472. }
  473. /* Check all outputs */
  474. for (i = 0; i < TCC_NUM_WAVE_OUTPUTS; i ++) {
  475. if (!config->pins.enable_wave_out_pin[i]) {
  476. continue;
  477. }
  478. /* Output line is not supported */
  479. if (i >= _tcc_ow_nums[module_index]) {
  480. return STATUS_ERR_INVALID_ARG;
  481. }
  482. }
  483. /* CTRLA settings */
  484. uint32_t ctrla = 0;
  485. status = _tcc_build_ctrla(module_index, config, &ctrla);
  486. if (STATUS_OK != status) {
  487. return status;
  488. }
  489. /* CTRLB settings */
  490. uint8_t ctrlb;
  491. _tcc_build_ctrlb(module_index, config, &ctrlb);
  492. /* FAULTs settings */
  493. uint32_t faults[TCC_NUM_FAULTS];
  494. status = _tcc_build_faults(module_index, config, faults);
  495. if (STATUS_OK != status) {
  496. return status;
  497. }
  498. /* DRVCTRL */
  499. uint32_t drvctrl = 0;
  500. status = _tcc_build_drvctrl(module_index, config, &drvctrl);
  501. if (STATUS_OK != status) {
  502. return status;
  503. }
  504. /* WAVE */
  505. uint32_t waves[1];
  506. status = _tcc_build_waves(module_index, config, waves);
  507. if (STATUS_OK != status) {
  508. return status;
  509. }
  510. /* Initialize module */
  511. #if TCC_ASYNC
  512. /* Initialize parameters */
  513. for (i = 0; i < TCC_CALLBACK_N; i ++) {
  514. module_inst->callback[i] = NULL;
  515. }
  516. module_inst->register_callback_mask = 0;
  517. module_inst->enable_callback_mask = 0;
  518. _tcc_instances[module_index] = module_inst;
  519. #endif
  520. module_inst->hw = hw;
  521. module_inst->double_buffering_enabled = config->double_buffering_enabled;
  522. /* Setup clock for module */
  523. struct system_gclk_chan_config gclk_chan_config;
  524. system_gclk_chan_get_config_defaults(&gclk_chan_config);
  525. gclk_chan_config.source_generator = config->counter.clock_source;
  526. system_gclk_chan_set_config(_tcc_gclk_ids[module_index], &gclk_chan_config);
  527. system_gclk_chan_enable(_tcc_gclk_ids[module_index]);
  528. /* Initialize pins */
  529. struct system_pinmux_config pin_config;
  530. for (i = 0; i < _tcc_ow_nums[module_index]; i ++) {
  531. if (!config->pins.enable_wave_out_pin[i]) {
  532. continue;
  533. }
  534. system_pinmux_get_config_defaults(&pin_config);
  535. pin_config.mux_position = config->pins.wave_out_pin_mux[i];
  536. pin_config.direction = SYSTEM_PINMUX_PIN_DIR_OUTPUT;
  537. system_pinmux_pin_set_config(
  538. config->pins.wave_out_pin[i], &pin_config);
  539. }
  540. /* Write to registers */
  541. hw->CTRLA.reg = ctrla;
  542. while (hw->SYNCBUSY.reg & TCC_SYNCBUSY_CTRLB) {
  543. /* Wait for sync */
  544. }
  545. hw->CTRLBCLR.reg = 0xFF;
  546. while (hw->SYNCBUSY.reg & TCC_SYNCBUSY_CTRLB) {
  547. /* Wait for sync */
  548. }
  549. hw->CTRLBSET.reg = ctrlb;
  550. hw->FCTRLA.reg = faults[0];
  551. hw->FCTRLB.reg = faults[1];
  552. hw->DRVCTRL.reg = drvctrl;
  553. #if (!SAML21) && (!SAMC20) && (!SAMC21) && (!SAML22) && (!SAMR30)
  554. while (hw->SYNCBUSY.reg & (TCC_SYNCBUSY_WAVE | TCC_SYNCBUSY_WAVEB)) {
  555. /* Wait for sync */
  556. }
  557. #endif
  558. hw->WAVE.reg = waves[0];
  559. while (hw->SYNCBUSY.reg & TCC_SYNCBUSY_COUNT) {
  560. /* Wait for sync */
  561. }
  562. hw->COUNT.reg = config->counter.count;
  563. #if (!SAML21) && (!SAMC20) && (!SAMC21) && (!SAML22) && (!SAMR30)
  564. while (hw->SYNCBUSY.reg & (TCC_SYNCBUSY_PER | TCC_SYNCBUSY_PERB)) {
  565. /* Wait for sync */
  566. }
  567. #endif
  568. hw->PER.reg = (config->counter.period);
  569. for (i = 0; i < _tcc_cc_nums[module_index]; i ++) {
  570. #if (!SAML21) && (!SAMC20) && (!SAMC21) && (!SAML22) && (!SAMR30)
  571. while (hw->SYNCBUSY.reg & (
  572. (TCC_SYNCBUSY_CC0 | TCC_SYNCBUSY_CCB0) << i)) {
  573. /* Wait for sync */
  574. }
  575. #endif
  576. hw->CC[i].reg = (config->compare.match[i]);
  577. }
  578. return STATUS_OK;
  579. }
  580. /**
  581. * \brief Enables the TCC module event input or output.
  582. *
  583. * Enables one or more input or output events to or from the TCC module.
  584. * See \ref tcc_events for a list of events this module supports.
  585. *
  586. * \note Events cannot be altered while the module is enabled.
  587. *
  588. * \param[in] module_inst Pointer to the software module instance struct
  589. * \param[in] events Struct containing flags of events to enable or
  590. * configure
  591. *
  592. * \return Status of the events setup procedure.
  593. *
  594. * \retval STATUS_OK The module was initialized successfully
  595. * \retval STATUS_INVALID_ARG An invalid configuration option or argument
  596. * was supplied
  597. */
  598. enum status_code tcc_enable_events(
  599. struct tcc_module *const module_inst,
  600. struct tcc_events *const events)
  601. {
  602. /* Sanity check arguments */
  603. Assert(module_inst);
  604. Assert(module_inst->hw);
  605. Assert(events);
  606. Tcc *const tcc_module = module_inst->hw;
  607. /* Check if it's enabled or resetting. */
  608. if (tcc_module->CTRLA.reg & (TCC_CTRLA_ENABLE | TCC_CTRLA_SWRST)) {
  609. return STATUS_ERR_DENIED;
  610. }
  611. uint32_t evctrl = tcc_module->EVCTRL.reg;
  612. /* Setup event output action */
  613. if (events->output_config.modify_generation_selection) {
  614. evctrl &= ~ TCC_EVCTRL_CNTSEL_Msk;
  615. switch(events->output_config.generation_selection) {
  616. case TCC_EVENT_GENERATION_SELECTION_START:
  617. evctrl |= TCC_EVCTRL_CNTSEL_START;
  618. break;
  619. case TCC_EVENT_GENERATION_SELECTION_END:
  620. evctrl |= TCC_EVCTRL_CNTSEL_END;
  621. break;
  622. case TCC_EVENT_GENERATION_SELECTION_BETWEEN:
  623. evctrl |= TCC_EVCTRL_CNTSEL_BETWEEN;
  624. break;
  625. case TCC_EVENT_GENERATION_SELECTION_BOUNDARY:
  626. evctrl |= TCC_EVCTRL_CNTSEL_BOUNDARY;
  627. break;
  628. default:
  629. Assert(false);
  630. /* Wrong configuration */
  631. return STATUS_ERR_INVALID_ARG;
  632. }
  633. }
  634. /* Setup input event0 */
  635. if (events->on_input_event_perform_action[0]) {
  636. evctrl |= TCC_EVCTRL_TCEI0;
  637. }
  638. if (events->input_config[0].invert) {
  639. evctrl |= TCC_EVCTRL_TCINV0;
  640. }
  641. if (events->input_config[0].modify_action) {
  642. evctrl &= ~ TCC_EVCTRL_EVACT0_Msk;
  643. switch(events->input_config[0].action) {
  644. case TCC_EVENT0_ACTION_OFF:
  645. evctrl |= TCC_EVCTRL_EVACT0_OFF;
  646. break;
  647. case TCC_EVENT0_ACTION_RETRIGGER:
  648. evctrl |= TCC_EVCTRL_EVACT0_RETRIGGER;
  649. break;
  650. case TCC_EVENT0_ACTION_COUNT_EVENT:
  651. evctrl |= TCC_EVCTRL_EVACT0_COUNTEV;
  652. break;
  653. case TCC_EVENT0_ACTION_START:
  654. evctrl |= TCC_EVCTRL_EVACT0_START;
  655. break;
  656. case TCC_EVENT0_ACTION_INCREMENT:
  657. evctrl |= TCC_EVCTRL_EVACT0_INC;
  658. break;
  659. case TCC_EVENT0_ACTION_COUNT_DURING_ACTIVE:
  660. evctrl |= TCC_EVCTRL_EVACT0_COUNT;
  661. break;
  662. case TCC_EVENT0_ACTION_NON_RECOVERABLE_FAULT:
  663. evctrl |= TCC_EVCTRL_EVACT0_FAULT;
  664. break;
  665. default:
  666. Assert(false);
  667. /* Wrong configuration */
  668. return STATUS_ERR_INVALID_ARG;
  669. }
  670. }
  671. /* Setup input event1 */
  672. if (events->on_input_event_perform_action[1]) {
  673. evctrl |= TCC_EVCTRL_TCEI1;
  674. }
  675. if (events->input_config[1].invert) {
  676. evctrl |= TCC_EVCTRL_TCINV1;
  677. }
  678. if (events->input_config[1].modify_action) {
  679. evctrl &= ~ TCC_EVCTRL_EVACT1_Msk;
  680. switch(events->input_config[1].action) {
  681. case TCC_EVENT1_ACTION_OFF:
  682. evctrl |= TCC_EVCTRL_EVACT1_OFF;
  683. break;
  684. case TCC_EVENT1_ACTION_RETRIGGER:
  685. evctrl |= TCC_EVCTRL_EVACT1_RETRIGGER;
  686. break;
  687. case TCC_EVENT1_ACTION_DIR_CONTROL:
  688. evctrl |= TCC_EVCTRL_EVACT1_DIR;
  689. break;
  690. case TCC_EVENT1_ACTION_STOP:
  691. evctrl |= TCC_EVCTRL_EVACT1_STOP;
  692. break;
  693. case TCC_EVENT1_ACTION_DECREMENT:
  694. evctrl |= TCC_EVCTRL_EVACT1_DEC;
  695. break;
  696. case TCC_EVENT1_ACTION_PERIOD_PULSE_WIDTH_CAPTURE:
  697. evctrl |= TCC_EVCTRL_EVACT1_PPW |
  698. TCC_EVCTRL_MCEI0 | TCC_EVCTRL_MCEI1;
  699. break;
  700. case TCC_EVENT1_ACTION_PULSE_WIDTH_PERIOD_CAPTURE:
  701. evctrl |= TCC_EVCTRL_EVACT1_PWP |
  702. TCC_EVCTRL_MCEI0 | TCC_EVCTRL_MCEI1;
  703. break;
  704. case TCC_EVENT1_ACTION_NON_RECOVERABLE_FAULT:
  705. evctrl |= TCC_EVCTRL_EVACT1_FAULT;
  706. break;
  707. default:
  708. Assert(false);
  709. /* Wrong configuration */
  710. return STATUS_ERR_INVALID_ARG;
  711. }
  712. }
  713. uint32_t ch;
  714. for(ch = 0; ch < TCC_NUM_CHANNELS; ch ++) {
  715. if (events->generate_event_on_channel[ch]) {
  716. evctrl |= (TCC_EVCTRL_MCEO(1) << ch);
  717. }
  718. if (events->on_event_perform_channel_action[ch]) {
  719. evctrl |= (TCC_EVCTRL_MCEI(1) << ch);
  720. }
  721. }
  722. if (events->generate_event_on_counter_overflow) {
  723. evctrl |= TCC_EVCTRL_OVFEO;
  724. }
  725. if (events->generate_event_on_counter_retrigger) {
  726. evctrl |= TCC_EVCTRL_TRGEO;
  727. }
  728. if (events->generate_event_on_counter_event) {
  729. evctrl |= TCC_EVCTRL_CNTEO;
  730. }
  731. tcc_module->EVCTRL.reg = evctrl;
  732. return STATUS_OK;
  733. }
  734. /**
  735. * \brief Disables the event input or output of a TCC instance.
  736. *
  737. * Disables one or more input or output events for the given TCC module.
  738. * See \ref tcc_events for a list of events this module supports.
  739. *
  740. * \note Events cannot be altered while the module is enabled.
  741. *
  742. * \param[in] module_inst Pointer to the software module instance struct
  743. * \param[in] events Struct containing flags of events to disable
  744. */
  745. void tcc_disable_events(
  746. struct tcc_module *const module_inst,
  747. struct tcc_events *const events)
  748. {
  749. /* Sanity check arguments */
  750. Assert(module_inst);
  751. Assert(module_inst->hw);
  752. Assert(events);
  753. Tcc *const tcc_module = module_inst->hw;
  754. /* Check if it's enabled or resetting. */
  755. if (tcc_module->CTRLA.reg & (TCC_CTRLA_ENABLE | TCC_CTRLA_SWRST)) {
  756. return;
  757. }
  758. uint32_t evctrl = 0;
  759. uint32_t ch;
  760. for(ch = 0; ch < TCC_NUM_CHANNELS; ch ++) {
  761. if (events->generate_event_on_channel[ch]) {
  762. evctrl |= (TCC_EVCTRL_MCEO(1) << ch);
  763. }
  764. if (events->on_event_perform_channel_action[ch]) {
  765. evctrl |= (TCC_EVCTRL_MCEI(1) << ch);
  766. }
  767. }
  768. if (events->generate_event_on_counter_overflow) {
  769. evctrl |= TCC_EVCTRL_OVFEO;
  770. }
  771. if (events->generate_event_on_counter_retrigger) {
  772. evctrl |= TCC_EVCTRL_TRGEO;
  773. }
  774. if (events->generate_event_on_counter_event) {
  775. evctrl |= TCC_EVCTRL_CNTEO;
  776. }
  777. if (events->on_input_event_perform_action[0]) {
  778. evctrl |= TCC_EVCTRL_TCEI0;
  779. }
  780. if (events->on_input_event_perform_action[1]) {
  781. evctrl |= TCC_EVCTRL_TCEI1;
  782. }
  783. if (events->input_config[0].invert) {
  784. evctrl |= TCC_EVCTRL_TCINV0;
  785. }
  786. if (events->input_config[1].invert) {
  787. evctrl |= TCC_EVCTRL_TCINV1;
  788. }
  789. tcc_module->EVCTRL.reg &= ~evctrl;
  790. }
  791. /**
  792. * \brief Sets count value for the given TCC module.
  793. *
  794. * Sets the timer count value of an initialized TCC module. The
  795. * specified TCC module can remain running or stopped.
  796. *
  797. * \param[in] module_inst Pointer to the software module instance struct
  798. * \param[in] count New timer count value to set
  799. *
  800. * \return Status which indicates whether the new value is set.
  801. *
  802. * \retval STATUS_OK The timer count was updated successfully
  803. * \retval STATUS_ERR_INVALID_ARG An invalid timer counter size was specified
  804. */
  805. enum status_code tcc_set_count_value(
  806. const struct tcc_module *const module_inst,
  807. const uint32_t count)
  808. {
  809. /* Sanity check arguments */
  810. Assert(module_inst);
  811. Assert(module_inst->hw);
  812. /* Get a pointer to the module's hardware instance*/
  813. Tcc *const tcc_module = module_inst->hw;
  814. /* Get a index of the module */
  815. uint8_t module_index = _tcc_get_inst_index(tcc_module);
  816. uint32_t max_count = _tcc_maxs[module_index];
  817. if (count > max_count) {
  818. return STATUS_ERR_INVALID_ARG;
  819. }
  820. while (tcc_module->SYNCBUSY.reg & TCC_SYNCBUSY_COUNT) {
  821. /* Wait for sync */
  822. }
  823. /* Write to based on the TCC dithering */
  824. tcc_module->COUNT.reg = (count);
  825. return STATUS_OK;
  826. }
  827. /**
  828. * \brief Get count value of the given TCC module.
  829. *
  830. * Retrieves the current count value of a TCC module. The specified TCC module
  831. * can remain running or stopped.
  832. *
  833. * \param[in] module_inst Pointer to the software module instance struct
  834. *
  835. * \return Count value of the specified TCC module.
  836. */
  837. uint32_t tcc_get_count_value(
  838. const struct tcc_module *const module_inst)
  839. {
  840. /* Sanity check arguments */
  841. Assert(module_inst);
  842. Assert(module_inst->hw);
  843. /* Get a pointer to the module's hardware instance*/
  844. Tcc *const tcc_module = module_inst->hw;
  845. uint32_t last_cmd;
  846. /* Wait last command done */
  847. do {
  848. while (tcc_module->SYNCBUSY.reg & TCC_SYNCBUSY_CTRLB) {
  849. /* Wait for sync */
  850. }
  851. last_cmd = tcc_module->CTRLBSET.reg & TCC_CTRLBSET_CMD_Msk;
  852. if (TCC_CTRLBSET_CMD_NONE == last_cmd) {
  853. /* Issue read command and break */
  854. tcc_module->CTRLBSET.bit.CMD = TCC_CTRLBSET_CMD_READSYNC_Val;
  855. while (tcc_module->SYNCBUSY.reg & TCC_SYNCBUSY_CTRLB) {
  856. /* Wait for sync */
  857. }
  858. break;
  859. } else if (TCC_CTRLBSET_CMD_READSYNC == last_cmd) {
  860. /* Command have been issued */
  861. break;
  862. }
  863. } while (1);
  864. while (tcc_module->SYNCBUSY.reg & TCC_SYNCBUSY_COUNT) {
  865. /* Wait for sync */
  866. }
  867. return (tcc_module->COUNT.reg);
  868. }
  869. /**
  870. * \brief Gets the TCC module capture value.
  871. *
  872. * Retrieves the capture value in the indicated TCC module capture channel.
  873. *
  874. * \param[in] module_inst Pointer to the software module instance struct
  875. * \param[in] channel_index Index of the Compare Capture channel to read
  876. *
  877. * \return Capture value stored in the specified timer channel.
  878. */
  879. uint32_t tcc_get_capture_value(
  880. const struct tcc_module *const module_inst,
  881. const enum tcc_match_capture_channel channel_index)
  882. {
  883. /* Sanity check arguments */
  884. Assert(module_inst);
  885. Assert(module_inst->hw);
  886. Assert(channel_index < _tcc_cc_nums[_tcc_get_inst_index(module_inst->hw)]);
  887. /* Get a pointer to the module's hardware instance */
  888. Tcc *const tcc_module = module_inst->hw;
  889. while(tcc_module->SYNCBUSY.reg & (TCC_SYNCBUSY_CC0 << channel_index)) {
  890. /* Sync wait */
  891. }
  892. return tcc_module->CC[channel_index].reg;
  893. }
  894. /**
  895. * \internal
  896. * \brief Sets a TCC module compare value/buffer.
  897. *
  898. * Writes a compare value to the given TCC module compare/capture channel or
  899. * buffer one.
  900. *
  901. * \param[in] module_inst Pointer to the software module instance struct
  902. * \param[in] channel_index Index of the compare channel to write to
  903. * \param[in] compare New compare value/buffer value to set
  904. * \param[in] double_buffering_enabled Set to \c true to write to CCBx
  905. *
  906. * \return Status of the compare update procedure.
  907. *
  908. * \retval STATUS_OK The compare value was updated successfully
  909. * \retval STATUS_ERR_INVALID_ARG An invalid channel index was supplied or
  910. * compare value exceed resolution
  911. */
  912. static enum status_code _tcc_set_compare_value(
  913. const struct tcc_module *const module_inst,
  914. const enum tcc_match_capture_channel channel_index,
  915. const uint32_t compare,
  916. const bool double_buffering_enabled)
  917. {
  918. /* Sanity check arguments */
  919. Assert(module_inst);
  920. Assert(module_inst->hw);
  921. /* Get a pointer to the module's hardware instance */
  922. Tcc *const tcc_module = module_inst->hw;
  923. /* Get a index of the module */
  924. uint8_t module_index = _tcc_get_inst_index(tcc_module);
  925. /* Check index */
  926. if (channel_index >= _tcc_cc_nums[module_index]) {
  927. return STATUS_ERR_INVALID_ARG;
  928. }
  929. uint32_t max_count = _tcc_maxs[module_index];
  930. /* Check compare value */
  931. if (compare > max_count) {
  932. return STATUS_ERR_INVALID_ARG;
  933. }
  934. if (double_buffering_enabled) {
  935. #if (SAML21) || (SAMC20) || (SAMC21) || (SAML22) || (SAMR30)
  936. tcc_module->CCBUF[channel_index].reg = compare;
  937. #else
  938. while(tcc_module->STATUS.reg &
  939. (TCC_STATUS_CCBV0 << channel_index)) {
  940. /* Valid check */
  941. }
  942. while(tcc_module->SYNCBUSY.reg &
  943. (TCC_SYNCBUSY_CCB0 << channel_index)) {
  944. /* Sync wait */
  945. }
  946. tcc_module->CCB[channel_index].reg = compare;
  947. #endif
  948. } else {
  949. while(tcc_module->SYNCBUSY.reg & (TCC_SYNCBUSY_CC0 << channel_index)) {
  950. /* Sync wait */
  951. }
  952. tcc_module->CC[channel_index].reg = compare;
  953. }
  954. return STATUS_OK;
  955. }
  956. /**
  957. * \brief Sets a TCC module compare value.
  958. *
  959. * Writes a compare value to the given TCC module compare/capture channel.
  960. *
  961. * If double buffering is enabled it always write to the buffer
  962. * register. The value will then be updated immediately by calling
  963. * \ref tcc_force_double_buffer_update(), or be updated when the lock update bit
  964. * is cleared and the UPDATE condition happen.
  965. *
  966. * \param[in] module_inst Pointer to the software module instance struct
  967. * \param[in] channel_index Index of the compare channel to write to
  968. * \param[in] compare New compare value to set
  969. *
  970. * \return Status of the compare update procedure.
  971. *
  972. * \retval STATUS_OK The compare value was updated successfully
  973. * \retval STATUS_ERR_INVALID_ARG An invalid channel index was supplied or
  974. * compare value exceed resolution
  975. */
  976. enum status_code tcc_set_compare_value(
  977. const struct tcc_module *const module_inst,
  978. const enum tcc_match_capture_channel channel_index,
  979. const uint32_t compare)
  980. {
  981. /* Sanity check arguments */
  982. Assert(module_inst);
  983. return _tcc_set_compare_value(module_inst, channel_index, compare,
  984. module_inst->double_buffering_enabled);
  985. }
  986. /**
  987. * \brief Sets a TCC module compare value and buffer value.
  988. *
  989. * Writes compare value and buffer to the given TCC module compare/capture
  990. * channel. Usually as preparation for double buffer or circulared double buffer
  991. * (circular buffer).
  992. *
  993. * \param[in] module_inst Pointer to the software module instance struct
  994. * \param[in] channel_index Index of the compare channel to write to
  995. * \param[in] compare New compare value to set
  996. * \param[in] compare_buffer New compare buffer value to set
  997. *
  998. * \return Status of the compare update procedure.
  999. *
  1000. * \retval STATUS_OK The compare value was updated successfully
  1001. * \retval STATUS_ERR_INVALID_ARG An invalid channel index was supplied or
  1002. * compare value exceed resolution
  1003. */
  1004. enum status_code tcc_set_double_buffer_compare_values(
  1005. struct tcc_module *const module_inst,
  1006. const enum tcc_match_capture_channel channel_index,
  1007. const uint32_t compare, const uint32_t compare_buffer)
  1008. {
  1009. /* Sanity check arguments */
  1010. Assert(module_inst);
  1011. enum status_code status;
  1012. status = _tcc_set_compare_value(module_inst, channel_index, compare, false);
  1013. if (status != STATUS_OK) {
  1014. return status;
  1015. }
  1016. return _tcc_set_compare_value(module_inst, channel_index, compare_buffer,
  1017. true);
  1018. }
  1019. /**
  1020. * \internal
  1021. * \brief Set the timer TOP/PERIOD buffer/value.
  1022. *
  1023. * This function writes the given value to the PER/PERB register.
  1024. *
  1025. * \param[in] module_inst Pointer to the software module instance struct
  1026. * \param[in] top_value New value to be loaded into the PER/PERB register
  1027. * \param[in] double_buffering_enabled Set to \c true to write to PERB
  1028. *
  1029. * \return Status of the TOP set procedure.
  1030. *
  1031. * \retval STATUS_OK The timer TOP value was updated successfully
  1032. * \retval STATUS_ERR_INVALID_ARG An invalid channel index was supplied or
  1033. * top/period value exceed resolution
  1034. */
  1035. static enum status_code _tcc_set_top_value(
  1036. const struct tcc_module *const module_inst,
  1037. const uint32_t top_value,
  1038. const bool double_buffering_enabled)
  1039. {
  1040. /* Sanity check arguments */
  1041. Assert(module_inst);
  1042. Assert(module_inst->hw);
  1043. /* Get a pointer to the module's hardware instance */
  1044. Tcc *const tcc_module = module_inst->hw;
  1045. /* Get a index of the module */
  1046. uint8_t module_index = _tcc_get_inst_index(tcc_module);
  1047. uint32_t max_count = _tcc_maxs[module_index];
  1048. /* Check compare value */
  1049. if (top_value > max_count) {
  1050. return STATUS_ERR_INVALID_ARG;
  1051. }
  1052. if (double_buffering_enabled) {
  1053. #if (SAML21) || (SAMC20) || (SAMC21) || (SAML22) || (SAMR30)
  1054. tcc_module->PERBUF.reg = top_value;
  1055. #else
  1056. while(tcc_module->SYNCBUSY.reg & TCC_SYNCBUSY_PERB) {
  1057. /* Sync wait */
  1058. }
  1059. tcc_module->PERB.reg = top_value;
  1060. #endif
  1061. } else {
  1062. while(tcc_module->SYNCBUSY.reg & TCC_SYNCBUSY_PER) {
  1063. /* Sync wait */
  1064. }
  1065. tcc_module->PER.reg = top_value;
  1066. }
  1067. return STATUS_OK;
  1068. }
  1069. /**
  1070. * \brief Set the timer TOP/PERIOD value.
  1071. *
  1072. * This function writes the given value to the PER/PERB register.
  1073. *
  1074. * If double buffering is enabled it always write to the buffer
  1075. * register (PERB). The value will then be updated immediately by calling
  1076. * \ref tcc_force_double_buffer_update(), or be updated when the lock update bit
  1077. * is cleared and the UPDATE condition happen.
  1078. *
  1079. * When using MFRQ, the top value is defined by the CC0 register value and the
  1080. * PER value is ignored, so
  1081. * \ref tcc_set_compare_value (module,channel_0,value) must be used instead of
  1082. * this function to change the actual top value in that case.
  1083. * For all other waveforms operation the top value is defined by PER register
  1084. * value.
  1085. *
  1086. * \param[in] module_inst Pointer to the software module instance struct
  1087. * \param[in] top_value New value to be loaded into the PER/PERB register
  1088. *
  1089. * \return Status of the TOP set procedure.
  1090. *
  1091. * \retval STATUS_OK The timer TOP value was updated successfully
  1092. * \retval STATUS_ERR_INVALID_ARG An invalid channel index was supplied or
  1093. * top/period value exceed resolution
  1094. */
  1095. enum status_code tcc_set_top_value(
  1096. const struct tcc_module *const module_inst,
  1097. const uint32_t top_value)
  1098. {
  1099. /* Sanity check arguments */
  1100. Assert(module_inst);
  1101. return _tcc_set_top_value(module_inst, top_value,
  1102. module_inst->double_buffering_enabled);
  1103. }
  1104. /**
  1105. * \brief Set the timer TOP/PERIOD value and buffer value.
  1106. *
  1107. * This function writes the given value to the PER and PERB register. Usually as
  1108. * preparation for double buffer or circulared double buffer (circular buffer).
  1109. *
  1110. * When using MFRQ, the top values are defined by the CC0 and CCB0, the PER and
  1111. * PERB values are ignored, so
  1112. * \ref tcc_set_double_buffer_compare_values (module,channel_0,value,buffer) must
  1113. * be used instead of this function to change the actual top values in that
  1114. * case. For all other waveforms operation the top values are defined by PER and
  1115. * PERB registers values.
  1116. *
  1117. * \param[in] module_inst Pointer to the software module instance struct
  1118. * \param[in] top_value New value to be loaded into the PER register
  1119. * \param[in] top_buffer_value New value to be loaded into the PERB register
  1120. *
  1121. * \return Status of the TOP set procedure.
  1122. *
  1123. * \retval STATUS_OK The timer TOP value was updated successfully
  1124. * \retval STATUS_ERR_INVALID_ARG An invalid channel index was supplied or
  1125. * top/period value exceed resolution
  1126. */
  1127. enum status_code tcc_set_double_buffer_top_values(
  1128. const struct tcc_module *const module_inst,
  1129. const uint32_t top_value, const uint32_t top_buffer_value)
  1130. {
  1131. /* Sanity check arguments */
  1132. Assert(module_inst);
  1133. enum status_code status;
  1134. status = _tcc_set_top_value(module_inst, top_value, false);
  1135. if (status != STATUS_OK) {
  1136. return status;
  1137. }
  1138. return _tcc_set_top_value(module_inst, top_buffer_value, true);
  1139. }
  1140. /**
  1141. * \brief Sets the TCC module waveform output pattern.
  1142. *
  1143. * Force waveform output line to generate specific pattern (0, 1, or as is).
  1144. *
  1145. * If double buffering is enabled it always write to the buffer
  1146. * register. The value will then be updated immediately by calling
  1147. * \ref tcc_force_double_buffer_update(), or be updated when the lock update bit
  1148. * is cleared and the UPDATE condition happen.
  1149. *
  1150. * \param[in] module_inst Pointer to the software module instance struct
  1151. * \param[in] line_index Output line index
  1152. * \param[in] pattern Output pattern to use (\ref tcc_output_pattern)
  1153. *
  1154. * \return Status of the pattern set procedure.
  1155. *
  1156. * \retval STATUS_OK The PATT register is updated successfully
  1157. * \retval STATUS_ERR_INVALID_ARG An invalid line index was supplied
  1158. */
  1159. enum status_code tcc_set_pattern(
  1160. const struct tcc_module *const module_inst,
  1161. const uint32_t line_index,
  1162. const enum tcc_output_pattern pattern)
  1163. {
  1164. /* Sanity check arguments */
  1165. Assert(module_inst);
  1166. Assert(module_inst->hw);
  1167. /* Get a pointer to the module's hardware instance */
  1168. Tcc *const tcc_module = module_inst->hw;
  1169. /* Get a index of the module */
  1170. uint8_t module_index = _tcc_get_inst_index(tcc_module);
  1171. /* Get number of output lines */
  1172. uint8_t ow_num = _tcc_ow_nums[module_index];
  1173. /* Check if line number is OK */
  1174. if (line_index >= ow_num) {
  1175. return STATUS_ERR_INVALID_ARG;
  1176. }
  1177. uint32_t patt_value;
  1178. while(tcc_module->SYNCBUSY.reg & TCC_SYNCBUSY_PATT) {
  1179. /* Sync wait */
  1180. }
  1181. patt_value = tcc_module->PATT.reg;
  1182. if (TCC_OUTPUT_PATTERN_DISABLE == pattern) {
  1183. patt_value &= ~(TCC_PATT_PGE0 << line_index);
  1184. } else if (TCC_OUTPUT_PATTERN_0 == pattern) {
  1185. patt_value &= ~(TCC_PATT_PGV0 << line_index);
  1186. patt_value |= (TCC_PATT_PGE0 << line_index);
  1187. } else {
  1188. patt_value |= ((TCC_PATT_PGE0 | TCC_PATT_PGV0) << line_index);
  1189. }
  1190. if (module_inst->double_buffering_enabled) {
  1191. #if (SAML21) || (SAMC20) || (SAMC21) || (SAML22) || (SAMR30)
  1192. tcc_module->PATTBUF.reg = patt_value;
  1193. #else
  1194. while(tcc_module->SYNCBUSY.reg & TCC_SYNCBUSY_PATTB) {
  1195. /* Sync wait */
  1196. }
  1197. tcc_module->PATTB.reg = patt_value;
  1198. #endif
  1199. } else {
  1200. tcc_module->PATT.reg = patt_value;
  1201. }
  1202. return STATUS_OK;
  1203. }
  1204. /**
  1205. * \brief Retrieves the current module status.
  1206. *
  1207. * Retrieves the status of the module, giving overall state information.
  1208. *
  1209. * \param[in] module_inst Pointer to the TCC software instance struct
  1210. *
  1211. * \return Bitmask of \c TCC_STATUS_* flags.
  1212. *
  1213. * \retval TCC_STATUS_CHANNEL_MATCH_CAPTURE(n) Channel n match/capture has occured
  1214. * \retval TCC_STATUS_CHANNEL_OUTPUT(n) Channel n match/capture output state
  1215. * \retval TCC_STATUS_NON_RECOVERABLE_FAULT_OCCUR(x) Non-recoverable fault x has occured
  1216. * \retval TCC_STATUS_RECOVERABLE_FAULT_OCCUR(n) Recoverable fault n has occured
  1217. * \retval TCC_STATUS_NON_RECOVERABLE_FAULT_PRESENT(x) Non-recoverable fault x input present
  1218. * \retval TCC_STATUS_RECOVERABLE_FAULT_PRESENT(n) Recoverable fault n input present
  1219. * \retval TCC_STATUS_SYNC_READY None of register is syncing
  1220. * \retval TCC_STATUS_CAPTURE_OVERFLOW Timer capture data has overflowed
  1221. * \retval TCC_STATUS_COUNTER_EVENT Timer counter event has occurred
  1222. * \retval TCC_STATUS_COUNT_OVERFLOW Timer count value has overflowed
  1223. * \retval TCC_STATUS_COUNTER_RETRIGGERED Timer counter has been retriggered
  1224. * \retval TCC_STATUS_STOP Timer counter has been stopped
  1225. * \retval TCC_STATUS_RAMP_CYCLE_INDEX Wave ramp index for cycle
  1226. */
  1227. uint32_t tcc_get_status(
  1228. struct tcc_module *const module_inst)
  1229. {
  1230. /* Sanity check arguments */
  1231. Assert(module_inst);
  1232. Assert(module_inst->hw);
  1233. uint32_t int_flags = module_inst->hw->INTFLAG.reg;
  1234. uint32_t status_flags = module_inst->hw->STATUS.reg;
  1235. uint32_t status = 0;
  1236. int i;
  1237. /* SYNC */
  1238. if (module_inst->hw->SYNCBUSY.reg == 0) {
  1239. status |= TCC_STATUS_SYNC_READY;
  1240. }
  1241. /* Channels */
  1242. for (i = 0; i < TCC_NUM_CHANNELS; i++) {
  1243. if (int_flags & TCC_INTFLAG_MC(i)) {
  1244. status |= TCC_STATUS_CHANNEL_MATCH_CAPTURE(i);
  1245. }
  1246. if (status_flags & TCC_STATUS_CMP(i)) {
  1247. status |= TCC_STATUS_CHANNEL_OUTPUT(i);
  1248. }
  1249. }
  1250. /* Non-recoverable fault state */
  1251. if ((int_flags & TCC_INTFLAG_FAULT1) ||
  1252. (status_flags & TCC_STATUS_FAULT1)) {
  1253. status |= TCC_STATUS_NON_RECOVERABLE_FAULT_OCCUR(1);
  1254. }
  1255. if ((int_flags & TCC_INTFLAG_FAULT0) ||
  1256. (status_flags & TCC_STATUS_FAULT0)) {
  1257. status |= TCC_STATUS_NON_RECOVERABLE_FAULT_OCCUR(0);
  1258. }
  1259. /* Non-recoverable fault inputs */
  1260. if (status_flags & TCC_STATUS_FAULT0IN) {
  1261. status |= TCC_STATUS_NON_RECOVERABLE_FAULT_PRESENT(0);
  1262. }
  1263. if (status_flags & TCC_STATUS_FAULT1IN) {
  1264. status |= TCC_STATUS_NON_RECOVERABLE_FAULT_PRESENT(1);
  1265. }
  1266. /* Recoverable fault state */
  1267. if ((int_flags & TCC_INTFLAG_FAULTB) ||
  1268. (status_flags & TCC_STATUS_FAULTB)) {
  1269. status |= TCC_STATUS_RECOVERABLE_FAULT_OCCUR(1);
  1270. }
  1271. if ((int_flags & TCC_INTFLAG_FAULTA) ||
  1272. (status_flags & TCC_STATUS_FAULTA)) {
  1273. status |= TCC_STATUS_RECOVERABLE_FAULT_OCCUR(0);
  1274. }
  1275. /* Recoverable fault inputs */
  1276. if (status_flags & TCC_STATUS_FAULTAIN) {
  1277. status |= TCC_STATUS_RECOVERABLE_FAULT_PRESENT(0);
  1278. }
  1279. if (status_flags & TCC_STATUS_FAULTBIN) {
  1280. status |= TCC_STATUS_RECOVERABLE_FAULT_PRESENT(1);
  1281. }
  1282. /* Check for TCC capture overflow */
  1283. if (int_flags & TCC_INTFLAG_ERR) {
  1284. status |= TCC_STATUS_CAPTURE_OVERFLOW;
  1285. }
  1286. /* Check for TCC count counter */
  1287. if (int_flags & TCC_INTFLAG_CNT) {
  1288. status |= TCC_STATUS_COUNTER_EVENT;
  1289. }
  1290. /* Check for TCC count retrigger */
  1291. if (int_flags & TCC_INTFLAG_TRG) {
  1292. status |= TCC_STATUS_COUNTER_RETRIGGERED;
  1293. }
  1294. /* Check for TCC count overflow */
  1295. if (int_flags & TCC_INTFLAG_OVF) {
  1296. status |= TCC_STATUS_COUNT_OVERFLOW;
  1297. }
  1298. /* Check for TCC count stop */
  1299. if (status_flags & TCC_STATUS_STOP) {
  1300. status |= TCC_STATUS_STOPPED;
  1301. }
  1302. /* Check for TCC RAMP index */
  1303. if (status_flags & TCC_STATUS_IDX) {
  1304. status |= TCC_STATUS_RAMP_CYCLE_INDEX;
  1305. }
  1306. return status;
  1307. }
  1308. /**
  1309. * \brief Clears a module status flag.
  1310. *
  1311. * Clears the given status flag of the module.
  1312. *
  1313. * \param[in] module_inst Pointer to the TCC software instance struct
  1314. * \param[in] status_flags Bitmask of \c TCC_STATUS_* flags to clear
  1315. */
  1316. void tcc_clear_status(
  1317. struct tcc_module *const module_inst,
  1318. const uint32_t status_flags)
  1319. {
  1320. /* Sanity check arguments */
  1321. Assert(module_inst);
  1322. Assert(module_inst->hw);
  1323. uint32_t int_clr = 0;
  1324. uint32_t status_clr = 0;
  1325. int i;
  1326. /* Channels */
  1327. for (i = 0; i < TCC_NUM_CHANNELS; i++) {
  1328. if (status_flags & TCC_STATUS_CHANNEL_MATCH_CAPTURE(i)) {
  1329. int_clr |= TCC_INTFLAG_MC(i);
  1330. }
  1331. }
  1332. /* Faults */
  1333. if (status_flags & TCC_STATUS_NON_RECOVERABLE_FAULT_OCCUR(1)) {
  1334. int_clr |= TCC_INTFLAG_FAULT1;
  1335. status_clr |= TCC_STATUS_FAULT1;
  1336. }
  1337. if (status_flags & TCC_STATUS_NON_RECOVERABLE_FAULT_OCCUR(0)) {
  1338. int_clr |= TCC_INTFLAG_FAULT0;
  1339. status_clr |= TCC_STATUS_FAULT0;
  1340. }
  1341. if (status_flags & TCC_STATUS_RECOVERABLE_FAULT_OCCUR(1)) {
  1342. int_clr |= TCC_INTFLAG_FAULTB;
  1343. status_clr |= TCC_STATUS_FAULTB;
  1344. }
  1345. if (status_flags & TCC_STATUS_RECOVERABLE_FAULT_OCCUR(0)) {
  1346. int_clr |= TCC_INTFLAG_FAULTA;
  1347. status_clr |= TCC_STATUS_FAULTA;
  1348. }
  1349. /* Check for TCC capture overflow */
  1350. if (status_flags & TCC_STATUS_CAPTURE_OVERFLOW) {
  1351. int_clr |= TCC_INTFLAG_ERR;
  1352. }
  1353. /* Check for TCC count counter */
  1354. if (status_flags & TCC_STATUS_COUNTER_EVENT) {
  1355. int_clr |= TCC_INTFLAG_CNT;
  1356. }
  1357. /* Check for TCC count retrigger */
  1358. if (status_flags & TCC_STATUS_COUNTER_RETRIGGERED) {
  1359. int_clr = TCC_INTFLAG_TRG;
  1360. }
  1361. /* Check for TCC count overflow */
  1362. if (status_flags & TCC_STATUS_COUNT_OVERFLOW) {
  1363. int_clr |= TCC_INTFLAG_OVF;
  1364. }
  1365. /* Clear status flag */
  1366. module_inst->hw->STATUS.reg = status_clr;
  1367. /* Clear interrupt flag */
  1368. module_inst->hw->INTFLAG.reg = int_clr;
  1369. }
  1370. /**
  1371. * \brief Enable circular option for double buffered compare values.
  1372. *
  1373. * Enable circular option for the double buffered channel compare values.
  1374. * On each UPDATE condition, the contents of CCBx and CCx are switched, meaning
  1375. * that the contents of CCBx are transferred to CCx and the contents of CCx are
  1376. * transferred to CCBx.
  1377. *
  1378. * \param[in] module_inst Pointer to the TCC software instance struct
  1379. * \param[in] channel_index Index of the compare channel to set up to
  1380. *
  1381. * \retval STATUS_OK The module was initialized successfully
  1382. * \retval STATUS_INVALID_ARG An invalid channel index is supplied
  1383. */
  1384. enum status_code tcc_enable_circular_buffer_compare(
  1385. struct tcc_module *const module_inst,
  1386. enum tcc_match_capture_channel channel_index)
  1387. {
  1388. /* Sanity check arguments */
  1389. Assert(module_inst);
  1390. Assert(module_inst->hw);
  1391. /* Get a pointer to the module's hardware instance */
  1392. Tcc *const tcc_module = module_inst->hw;
  1393. /* Get a index of the module */
  1394. uint8_t module_index = _tcc_get_inst_index(tcc_module);
  1395. /* Check index */
  1396. if (channel_index > 3) {
  1397. return STATUS_ERR_INVALID_ARG;
  1398. }
  1399. if (channel_index >= _tcc_cc_nums[module_index]) {
  1400. return STATUS_ERR_INVALID_ARG;
  1401. }
  1402. tcc_module->WAVE.reg |= (TCC_WAVE_CICCEN0 << channel_index);
  1403. return STATUS_OK;
  1404. }
  1405. /**
  1406. * \brief Disable circular option for double buffered compare values.
  1407. *
  1408. * Stop circularing the double buffered compare values.
  1409. *
  1410. * \param[in] module_inst Pointer to the TCC software instance struct
  1411. * \param[in] channel_index Index of the compare channel to set up to
  1412. *
  1413. * \retval STATUS_OK The module was initialized successfully
  1414. * \retval STATUS_INVALID_ARG An invalid channel index is supplied
  1415. */
  1416. enum status_code tcc_disable_circular_buffer_compare(
  1417. struct tcc_module *const module_inst,
  1418. enum tcc_match_capture_channel channel_index)
  1419. {
  1420. /* Sanity check arguments */
  1421. Assert(module_inst);
  1422. Assert(module_inst->hw);
  1423. /* Get a pointer to the module's hardware instance */
  1424. Tcc *const tcc_module = module_inst->hw;
  1425. /* Get a index of the module */
  1426. uint8_t module_index = _tcc_get_inst_index(tcc_module);
  1427. /* Check index */
  1428. if (channel_index > 3) {
  1429. return STATUS_ERR_INVALID_ARG;
  1430. }
  1431. if (channel_index >= _tcc_cc_nums[module_index]) {
  1432. return STATUS_ERR_INVALID_ARG;
  1433. }
  1434. tcc_module->WAVE.reg &= ~(TCC_WAVE_CICCEN0 << channel_index);
  1435. return STATUS_OK;
  1436. }