You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

288 line
7.2KB

  1. /* Teensyduino Core Library
  2. * http://www.pjrc.com/teensy/
  3. * Copyright (c) 2013 PJRC.COM, LLC.
  4. *
  5. * Permission is hereby granted, free of charge, to any person obtaining
  6. * a copy of this software and associated documentation files (the
  7. * "Software"), to deal in the Software without restriction, including
  8. * without limitation the rights to use, copy, modify, merge, publish,
  9. * distribute, sublicense, and/or sell copies of the Software, and to
  10. * permit persons to whom the Software is furnished to do so, subject to
  11. * the following conditions:
  12. *
  13. * 1. The above copyright notice and this permission notice shall be
  14. * included in all copies or substantial portions of the Software.
  15. *
  16. * 2. If the Software is incorporated into a build system that allows
  17. * selection among a list of target devices, then similar target
  18. * devices manufactured by PJRC.COM must be included in the list of
  19. * target devices and selectable in the same manner.
  20. *
  21. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  22. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  23. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  24. * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  25. * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  26. * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  27. * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  28. * SOFTWARE.
  29. */
  30. #include "core_pins.h"
  31. //#include "HardwareSerial.h"
  32. static uint8_t calibrating;
  33. static uint8_t analog_right_shift = 0;
  34. static uint8_t analog_config_bits = 10;
  35. static uint8_t analog_num_average = 4;
  36. static uint8_t analog_reference_internal = 0;
  37. // the alternate clock is connected to OSCERCLK (16 MHz).
  38. // datasheet says ADC clock should be 2 to 12 MHz for 16 bit mode
  39. // datasheet says ADC clock should be 1 to 18 MHz for 8-12 bit mode
  40. #if F_BUS == 48000000
  41. #define ADC0_CFG1_6MHZ ADC_CFG1_ADIV(2) + ADC_CFG1_ADICLK(1)
  42. #define ADC0_CFG1_12MHZ ADC_CFG1_ADIV(1) + ADC_CFG1_ADICLK(1)
  43. #define ADC0_CFG1_24MHZ ADC_CFG1_ADIV(0) + ADC_CFG1_ADICLK(1)
  44. #elif F_BUS == 24000000
  45. #define ADC0_CFG1_6MHZ ADC_CFG1_ADIV(2) + ADC_CFG1_ADICLK(0)
  46. #define ADC0_CFG1_12MHZ ADC_CFG1_ADIV(1) + ADC_CFG1_ADICLK(0)
  47. #define ADC0_CFG1_24MHZ ADC_CFG1_ADIV(0) + ADC_CFG1_ADICLK(0)
  48. #else
  49. #error
  50. #endif
  51. void analog_init(void)
  52. {
  53. uint32_t num;
  54. VREF_TRM = 0x60;
  55. VREF_SC = 0xE1; // enable 1.2 volt ref
  56. if (analog_config_bits == 8) {
  57. ADC0_CFG1 = ADC0_CFG1_24MHZ + ADC_CFG1_MODE(0);
  58. ADC0_CFG2 = ADC_CFG2_MUXSEL + ADC_CFG2_ADLSTS(3);
  59. } else if (analog_config_bits == 10) {
  60. ADC0_CFG1 = ADC0_CFG1_12MHZ + ADC_CFG1_MODE(2) + ADC_CFG1_ADLSMP;
  61. ADC0_CFG2 = ADC_CFG2_MUXSEL + ADC_CFG2_ADLSTS(3);
  62. } else if (analog_config_bits == 12) {
  63. ADC0_CFG1 = ADC0_CFG1_12MHZ + ADC_CFG1_MODE(1) + ADC_CFG1_ADLSMP;
  64. ADC0_CFG2 = ADC_CFG2_MUXSEL + ADC_CFG2_ADLSTS(2);
  65. } else {
  66. ADC0_CFG1 = ADC0_CFG1_12MHZ + ADC_CFG1_MODE(3) + ADC_CFG1_ADLSMP;
  67. ADC0_CFG2 = ADC_CFG2_MUXSEL + ADC_CFG2_ADLSTS(2);
  68. }
  69. if (analog_reference_internal) {
  70. ADC0_SC2 = ADC_SC2_REFSEL(1); // 1.2V ref
  71. } else {
  72. ADC0_SC2 = ADC_SC2_REFSEL(0); // vcc/ext ref
  73. }
  74. num = analog_num_average;
  75. if (num <= 1) {
  76. ADC0_SC3 = ADC_SC3_CAL; // begin cal
  77. } else if (num <= 4) {
  78. ADC0_SC3 = ADC_SC3_CAL + ADC_SC3_AVGE + ADC_SC3_AVGS(0);
  79. } else if (num <= 8) {
  80. ADC0_SC3 = ADC_SC3_CAL + ADC_SC3_AVGE + ADC_SC3_AVGS(1);
  81. } else if (num <= 16) {
  82. ADC0_SC3 = ADC_SC3_CAL + ADC_SC3_AVGE + ADC_SC3_AVGS(2);
  83. } else {
  84. ADC0_SC3 = ADC_SC3_CAL + ADC_SC3_AVGE + ADC_SC3_AVGS(3);
  85. }
  86. calibrating = 1;
  87. }
  88. static void wait_for_cal(void)
  89. {
  90. uint16_t sum;
  91. //serial_print("wait_for_cal\n");
  92. while (ADC0_SC3 & ADC_SC3_CAL) {
  93. // wait
  94. //serial_print(".");
  95. }
  96. __disable_irq();
  97. if (calibrating) {
  98. //serial_print("\n");
  99. sum = ADC0_CLPS + ADC0_CLP4 + ADC0_CLP3 + ADC0_CLP2 + ADC0_CLP1 + ADC0_CLP0;
  100. sum = (sum / 2) | 0x8000;
  101. ADC0_PG = sum;
  102. //serial_print("ADC0_PG = ");
  103. //serial_phex16(sum);
  104. //serial_print("\n");
  105. sum = ADC0_CLMS + ADC0_CLM4 + ADC0_CLM3 + ADC0_CLM2 + ADC0_CLM1 + ADC0_CLM0;
  106. sum = (sum / 2) | 0x8000;
  107. ADC0_MG = sum;
  108. //serial_print("ADC0_MG = ");
  109. //serial_phex16(sum);
  110. //serial_print("\n");
  111. calibrating = 0;
  112. }
  113. __enable_irq();
  114. }
  115. // ADCx_SC2[REFSEL] bit selects the voltage reference sources for ADC.
  116. // VREFH/VREFL - connected as the primary reference option
  117. // 1.2 V VREF_OUT - connected as the VALT reference option
  118. #define DEFAULT 0
  119. #define INTERNAL 2
  120. #define INTERNAL1V2 2
  121. #define INTERNAL1V1 2
  122. #define EXTERNAL 0
  123. void analogReference(uint8_t type)
  124. {
  125. if (type) {
  126. // internal reference requested
  127. if (!analog_reference_internal) {
  128. analog_reference_internal = 1;
  129. if (calibrating) ADC0_SC3 = 0; // cancel cal
  130. analog_init();
  131. }
  132. } else {
  133. // vcc or external reference requested
  134. if (analog_reference_internal) {
  135. analog_reference_internal = 0;
  136. if (calibrating) ADC0_SC3 = 0; // cancel cal
  137. analog_init();
  138. }
  139. }
  140. }
  141. void analogReadRes(unsigned int bits)
  142. {
  143. unsigned int config;
  144. if (bits >= 13) {
  145. if (bits > 16) bits = 16;
  146. config = 16;
  147. } else if (bits >= 11) {
  148. config = 12;
  149. } else if (bits >= 9) {
  150. config = 10;
  151. } else {
  152. config = 8;
  153. }
  154. analog_right_shift = config - bits;
  155. if (config != analog_config_bits) {
  156. analog_config_bits = config;
  157. if (calibrating) ADC0_SC3 = 0; // cancel cal
  158. analog_init();
  159. }
  160. }
  161. void analogReadAveraging(unsigned int num)
  162. {
  163. if (calibrating) wait_for_cal();
  164. if (num <= 1) {
  165. num = 0;
  166. ADC0_SC3 = 0;
  167. } else if (num <= 4) {
  168. num = 4;
  169. ADC0_SC3 = ADC_SC3_AVGE + ADC_SC3_AVGS(0);
  170. } else if (num <= 8) {
  171. num = 8;
  172. ADC0_SC3 = ADC_SC3_AVGE + ADC_SC3_AVGS(1);
  173. } else if (num <= 16) {
  174. num = 16;
  175. ADC0_SC3 = ADC_SC3_AVGE + ADC_SC3_AVGS(2);
  176. } else {
  177. num = 32;
  178. ADC0_SC3 = ADC_SC3_AVGE + ADC_SC3_AVGS(3);
  179. }
  180. analog_num_average = num;
  181. }
  182. // The SC1A register is used for both software and hardware trigger modes of operation.
  183. static const uint8_t channel2sc1a[] = {
  184. 5, 14, 8, 9, 13, 12, 6, 7, 15, 4,
  185. 0, 19, 3, 21, 26, 22
  186. };
  187. // TODO: perhaps this should store the NVIC priority, so it works recursively?
  188. static volatile uint8_t analogReadBusy = 0;
  189. int analogRead(uint8_t pin)
  190. {
  191. int result;
  192. if (pin >= 14) {
  193. if (pin <= 23) {
  194. pin -= 14; // 14-23 are A0-A9
  195. } else if (pin >= 34 && pin <= 39) {
  196. pin -= 24; // 34-37 are A10-A13, 38 is temp sensor, 39 is vref
  197. } else {
  198. return 0; // all others are invalid
  199. }
  200. }
  201. //serial_print("analogRead");
  202. //return 0;
  203. if (calibrating) wait_for_cal();
  204. //pin = 5; // PTD1/SE5b, pin 14, analog 0
  205. __disable_irq();
  206. start: ADC0_SC1A = channel2sc1a[pin];
  207. analogReadBusy = 1;
  208. __enable_irq();
  209. while (1) {
  210. __disable_irq();
  211. if ((ADC0_SC1A & ADC_SC1_COCO)) {
  212. result = ADC0_RA;
  213. analogReadBusy = 0;
  214. __enable_irq();
  215. result >>= analog_right_shift;
  216. return result;
  217. }
  218. // detect if analogRead was used from an interrupt
  219. // if so, our analogRead got canceled, so it must
  220. // be restarted.
  221. if (!analogReadBusy) goto start;
  222. __enable_irq();
  223. yield();
  224. }
  225. #if 0
  226. ADC0_SC1A = channel2sc1a[pin];
  227. while ((ADC0_SC1A & ADC_SC1_COCO) == 0) {
  228. yield();
  229. // wait
  230. //serial_print(".");
  231. }
  232. //serial_print("\n");
  233. result = ADC0_RA >> analog_right_shift;
  234. //serial_phex16(result >> 3);
  235. //serial_print("\n");
  236. return result;
  237. #endif
  238. }