freqm.c 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. /**
  2. * \file
  3. *
  4. * \brief SAM Frequency Meter (FREQM) Driver
  5. *
  6. * Copyright (C) 2015-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 "freqm.h"
  47. #include <gclk.h>
  48. #ifndef FREQM_GCLK_ID_REF
  49. #define FREQM_GCLK_ID_REF (FREQM_GCLK_ID_MSR + 1)
  50. #endif
  51. /**
  52. * \brief Initializes a hardware FREQM module instance.
  53. *
  54. * Enables the clock and initializes the FREQM module, based on the given
  55. * configuration values.
  56. *
  57. * \param[in,out] module_inst Pointer to the software module instance struct
  58. * \param[in] hw Pointer to the FREQM hardware module
  59. * \param[in] config Pointer to the FREQM configuration options struct
  60. *
  61. * \return Status of the initialization procedure.
  62. *
  63. * \retval STATUS_OK The module was initialized successfully
  64. */
  65. enum status_code freqm_init(
  66. struct freqm_module *const module_inst,
  67. Freqm *const hw,
  68. struct freqm_config *const config)
  69. {
  70. /* Sanity check arguments */
  71. Assert(module_inst);
  72. Assert(hw);
  73. Assert(config);
  74. Assert(config->ref_clock_circles);
  75. /* Initialize device instance */
  76. module_inst->hw = hw;
  77. /* Turn on the digital interface clock */
  78. system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBA, MCLK_APBAMASK_FREQM);
  79. /* Set up the GCLK for the module */
  80. struct system_gclk_chan_config gclk_chan_conf;
  81. system_gclk_chan_get_config_defaults(&gclk_chan_conf);
  82. gclk_chan_conf.source_generator = config->msr_clock_source;
  83. system_gclk_chan_set_config(FREQM_GCLK_ID_MSR, &gclk_chan_conf);
  84. system_gclk_chan_enable(FREQM_GCLK_ID_MSR);
  85. gclk_chan_conf.source_generator = config->ref_clock_source;
  86. system_gclk_chan_set_config(FREQM_GCLK_ID_REF, &gclk_chan_conf);
  87. system_gclk_chan_enable(FREQM_GCLK_ID_REF);
  88. module_inst->ref_clock_freq = system_gclk_gen_get_hz(config->ref_clock_source);
  89. /* Perform a software reset */
  90. hw->CTRLA.reg = FREQM_CTRLA_SWRST;
  91. while (freqm_is_syncing()) {
  92. /* Wait for all hardware modules to complete synchronization */
  93. }
  94. /* Initialize the FREQM with new configurations */
  95. hw->CFGA.reg = config->ref_clock_circles;
  96. #if FREQM_CALLBACK_MODE == true
  97. /* Initialize parameters */
  98. for (uint8_t i = 0; i < FREQM_CALLBACK_N; i++) {
  99. module_inst->callback[i] = NULL;
  100. }
  101. /* Register this instance for callbacks*/
  102. _freqm_instance = module_inst;
  103. #endif
  104. return STATUS_OK;
  105. }
  106. /**
  107. * \brief Read the measurement data result
  108. *
  109. * Reads the measurement data result.
  110. *
  111. * \param[in] module_inst Pointer to the FREQM software instance struct
  112. * \param[out] result Pointer to store the result value in
  113. *
  114. * \return Status of the FREQM read request.
  115. * \retval FREQM_STATUS_MEASURE_DONE Measurement result was retrieved successfully
  116. * \retval FREQM_STATUS_MEASURE_BUSY Measurement result was not ready
  117. * \retval FREQM_STATUS_CNT_OVERFLOW Measurement result was overflow
  118. *
  119. * \note If overflow occurred, configure faster reference clock or reduce reference clock cycles.
  120. */
  121. enum freqm_status freqm_get_result_value(
  122. struct freqm_module *const module_inst, uint32_t *result)
  123. {
  124. /* Sanity check arguments */
  125. Assert(module_inst);
  126. Assert(module_inst->hw);
  127. Assert(result);
  128. Freqm *const freqm_hw = module_inst->hw;
  129. uint32_t result_cal;
  130. *result = result_cal= 0;
  131. if (freqm_hw->STATUS.reg & FREQM_STATUS_BUSY) {
  132. /* Result not ready */
  133. return FREQM_STATUS_MEASURE_BUSY;
  134. } else {
  135. if (freqm_hw->STATUS.reg & FREQM_STATUS_OVF) {
  136. /* Overflow */
  137. return FREQM_STATUS_CNT_OVERFLOW;
  138. } else {
  139. /* Get measurement output data (it will clear data done flag) */
  140. result_cal = freqm_hw->VALUE.reg;
  141. freqm_hw->INTFLAG.reg = FREQM_INTFLAG_DONE;
  142. *result = result_cal * module_inst->ref_clock_freq / freqm_hw->CFGA.reg;
  143. return FREQM_STATUS_MEASURE_DONE;
  144. }
  145. }
  146. }