adc.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404
  1. /*
  2. * Simple PWM controller
  3. * ADC measurement
  4. *
  5. * Copyright (c) 2018-2020 Michael Buesch <m@bues.ch>
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; either version 2 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License along
  18. * with this program; if not, write to the Free Software Foundation, Inc.,
  19. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  20. */
  21. #include "compat.h"
  22. #include "debug.h"
  23. #include "adc.h"
  24. #include "util.h"
  25. #include "main.h"
  26. #include "pwm.h"
  27. #include "battery.h"
  28. #include "arithmetic.h"
  29. #include "outputsp.h"
  30. #include "standby.h"
  31. #include "remote.h"
  32. /* ADC configuration. */
  33. #define ADC_HYST 1u /* ADC hysteresis */
  34. #define ADC_MIN 0u /* Physical ADC minimum */
  35. #define ADC_MAX 0x3FFu /* Physical ADC maximum */
  36. #define ADC_VBG_MV 1100u /* Vbg in millivolts. */
  37. #define NR_ADC NR_PWM
  38. #if IS_ATMEGAx8
  39. # define ADC0_MUX ((0 << MUX3) | (0 << MUX2) | (0 << MUX1) | (0 << MUX0))
  40. # define ADC1_MUX ((0 << MUX3) | (0 << MUX2) | (0 << MUX1) | (1 << MUX0))
  41. # define ADC2_MUX ((0 << MUX3) | (0 << MUX2) | (1 << MUX1) | (0 << MUX0))
  42. #else
  43. # define ADC0_MUX ((0 << MUX3) | (0 << MUX2) | (1 << MUX1) | (0 << MUX0))
  44. # define ADC1_MUX 0
  45. # define ADC2_MUX 0
  46. #endif
  47. #if NR_ADC == 3
  48. # define ADC_DIDR_MASK ((1 << ADC2D) | (1 << ADC1D) | (1 << ADC0D))
  49. #elif NR_ADC == 1
  50. # define ADC_DIDR_MASK (1 << ADC2D)
  51. #else
  52. # error
  53. #endif
  54. /* Sample discard support. */
  55. #define USE_ADC_DISCARD (USE_BAT_MONITOR || (NR_ADC > 1))
  56. /* Analog pin switching support. */
  57. #define USE_APIN_SWITCH USE_REMOTE
  58. static struct {
  59. /* Currently active ADC MUX */
  60. uint8_t index;
  61. /* Battery measurement requested. */
  62. bool battery_meas_requested;
  63. /* Battery measurement running. */
  64. bool battery_meas_running;
  65. /* Is the input idle? */
  66. bool standby_ready[NR_ADC];
  67. /* Number of ADC inputs sucessfully measured. */
  68. uint8_t conv_count;
  69. /* Number of samples to discard. */
  70. uint8_t discard;
  71. /* Previous PWM interrupt count state. */
  72. uint8_t prev_pwm_count;
  73. /* Analog input pin measurement enabled? */
  74. bool analogpins_enabled;
  75. } adc;
  76. static bool adc_hw_enabled(void)
  77. {
  78. return !!(ADCSRA & (1 << ADEN));
  79. }
  80. #define ADC_MUXMODE_NORM 0u
  81. #define ADC_MUXMODE_BAT 1u
  82. /* Configure the ADC multiplexer.
  83. * Interrupts must be disabled before calling this function. */
  84. static inline void adc_configure_mux(uint8_t mux_mode, uint8_t index)
  85. {
  86. uint8_t mux_bits;
  87. if (mux_mode == ADC_MUXMODE_NORM) {
  88. /* Normal input signal measurement mode. */
  89. if (NR_ADC <= 1u || index == 0u)
  90. mux_bits = ADC0_MUX;
  91. else if (index == 1u)
  92. mux_bits = ADC1_MUX;
  93. else
  94. mux_bits = ADC2_MUX;
  95. if (IS_ATMEGAx8) {
  96. /* Ref = Vcc; in = ADC0/1/2; Right adjust */
  97. ADMUX = (0 << REFS1) | (1 << REFS0) |
  98. (0 << ADLAR) | mux_bits;
  99. } else {
  100. /* Ref = Vcc; in = ADC2; Right adjust */
  101. ADMUX = (0 << REFS2) | (0 << REFS1) | (0 << REFS0) |
  102. (0 << ADLAR) | mux_bits;
  103. }
  104. } else { /* mux_mode == ADC_MUXMODE_BAT */
  105. /* Battery voltage measurement mode. */
  106. if (IS_ATMEGAx8) {
  107. /* Ref = Vcc; in = Vbg (1.1V); Right adjust */
  108. ADMUX = (0 << REFS1) | (1 << REFS0) |
  109. (0 << ADLAR) |
  110. (1 << MUX3) | (1 << MUX2) | (1 << MUX1) | (0 << MUX0);
  111. } else {
  112. /* Ref = Vcc; in = Vbg (1.1V); Right adjust */
  113. ADMUX = (0 << REFS2) | (0 << REFS1) | (0 << REFS0) |
  114. (0 << ADLAR) |
  115. (1 << MUX3) | (1 << MUX2) | (0 << MUX1) | (0 << MUX0);
  116. }
  117. }
  118. }
  119. /* Configure the ADC hardware.
  120. * Interrupts must be disabled before calling this function. */
  121. static void adc_configure(bool enable)
  122. {
  123. /* Disable ADC unit. */
  124. ADCSRA = 0;
  125. /* Disable ADC digital input */
  126. DIDR0 = ADC_DIDR_MASK;
  127. /* Trigger source = free running */
  128. ADCSRB = (0 << ADTS2) | (0 << ADTS1) | (0 << ADTS0);
  129. if (enable) {
  130. if (adc_battery_measurement_active()) {
  131. /* Configure the MUX to battery measurement. */
  132. adc.battery_meas_requested = false;
  133. adc.battery_meas_running = true;
  134. adc_configure_mux(ADC_MUXMODE_BAT, 0u);
  135. /* Enable and start ADC; free running; PS = 64; IRQ enabled */
  136. ADCSRA = (1 << ADEN) | (1 << ADSC) | (1 << ADATE) |
  137. (1 << ADIF) | (1 << ADIE) |
  138. (1 << ADPS2) | (1 << ADPS1) | (0 << ADPS0);
  139. /* Discard the first few results to compensate
  140. * for Vbg settling time (1 ms). */
  141. adc.discard = 10;
  142. } else if (battery_voltage_is_critical()) {
  143. /* Battery voltage is critical and no battery measurement
  144. * has been requested.
  145. * Keep the ADC shut down. */
  146. } else if (!adc_analogpins_enabled()) {
  147. /* Analog input pins are disabled.
  148. * Keep the ADC shut down. */
  149. } else {
  150. /* Measure input pins. */
  151. /* Configure the MUX to the active input ADC. */
  152. adc_configure_mux(ADC_MUXMODE_NORM, adc.index);
  153. /* Enable and start ADC; free running; PS = 64; IRQ enabled */
  154. ADCSRA = (1 << ADEN) | (1 << ADSC) | (1 << ADATE) |
  155. (1 << ADIF) | (1 << ADIE) |
  156. (1 << ADPS2) | (1 << ADPS1) | (0 << ADPS0);
  157. if (NR_ADC > 1)
  158. adc.discard = 1;
  159. }
  160. }
  161. }
  162. /* Returns true, if a battery measurement conversion is currently active. */
  163. bool adc_battery_measurement_active(void)
  164. {
  165. if (USE_BAT_MONITOR)
  166. return adc.battery_meas_requested || adc.battery_meas_running;
  167. return false;
  168. }
  169. /* Request a measurement of the battery voltage.
  170. * Interrupts must be disabled before calling this function. */
  171. void adc_request_battery_measurement(void)
  172. {
  173. if (USE_BAT_MONITOR) {
  174. adc.battery_meas_requested = true;
  175. if (adc_hw_enabled()) {
  176. /* The ADC will be reconfigured by the completion
  177. * interrupt of the currently running conversion. */
  178. } else {
  179. /* No conversion currently running. Reconfigure ADC now. */
  180. adc_configure(true);
  181. }
  182. }
  183. }
  184. /* Get the analogpin measurement state. */
  185. bool adc_analogpins_enabled(void)
  186. {
  187. if (USE_APIN_SWITCH)
  188. return adc.analogpins_enabled;
  189. return true;
  190. }
  191. /* Enable/disable the analog input pin measurement. */
  192. void adc_analogpins_enable(bool enable)
  193. {
  194. uint8_t irq_state;
  195. if (USE_APIN_SWITCH) {
  196. irq_state = irq_disable_save();
  197. if (adc.analogpins_enabled != enable) {
  198. adc.analogpins_enabled = enable;
  199. if (enable && !adc_hw_enabled())
  200. adc_configure(true);
  201. set_standby_suppress(STANDBY_SRC_ADC, enable);
  202. }
  203. irq_restore(irq_state);
  204. }
  205. }
  206. /* Handle wake up from deep sleep.
  207. * Called with interrupts disabled. */
  208. void adc_handle_deep_sleep_wakeup(void)
  209. {
  210. if (!adc_analogpins_enabled())
  211. set_standby_suppress(STANDBY_SRC_ADC, false);
  212. }
  213. /* ADC conversion complete interrupt service routine */
  214. ISR(ADC_vect)
  215. {
  216. uint16_t raw_adc;
  217. uint16_t raw_setpoint;
  218. uint16_t filt_setpoint;
  219. uint16_t vcc_mv;
  220. uint8_t pwm_count;
  221. uint8_t index;
  222. uint8_t i;
  223. bool pwm_collision;
  224. bool allow_standby;
  225. bool go_standby;
  226. memory_barrier();
  227. /* Check if we had a PWM interrupt during our ADC measurement.
  228. * This only checks for collisions with the low frequency IRQ mode PWM.
  229. * Do this check with interrupts still disabled. */
  230. pwm_count = pwm_get_irq_count();
  231. pwm_collision = (pwm_count != adc.prev_pwm_count);
  232. adc.prev_pwm_count = pwm_count;
  233. /* Disable the ADC interrupt and
  234. * globally enable interrupts.
  235. * This allows TIM0_OVF_vect to interrupt us. */
  236. ADCSRA &= (uint8_t)~(1u << ADIE);
  237. irq_enable();
  238. /* Read the analog input */
  239. raw_adc = ADC;
  240. if (!USE_ADC_DISCARD || adc.discard == 0) {
  241. if (USE_BAT_MONITOR && adc.battery_meas_running) {
  242. /* Battery voltage measurement mode. */
  243. /* Convert the raw ADC value to millivolts. */
  244. if (raw_adc > 0u) {
  245. vcc_mv = lim_u16((((uint32_t)ADC_MAX + 1u) * (uint32_t)ADC_VBG_MV) /
  246. (uint32_t)raw_adc);
  247. } else
  248. vcc_mv = UINT16_MAX;
  249. /* Report the measured battery voltage to the
  250. * battery voltage logic. */
  251. evaluate_battery_voltage(vcc_mv);
  252. /* Disable interrupts for
  253. * - PWM shut down
  254. * - ADC re-init */
  255. irq_disable();
  256. if (battery_voltage_is_critical()) {
  257. /* Turn the output off immediately.
  258. * This also reconfigures the
  259. * battery measurement interval. */
  260. for (i = 0u; i < NR_PWM; i++)
  261. output_setpoint_set(IF_MULTIPWM(i,) false, 0u);
  262. }
  263. /* We're done.
  264. * Turn off battery measurement mode and
  265. * return to normal ADC operation mode
  266. * (if battery voltage is not critical). */
  267. adc.battery_meas_running = false;
  268. adc_configure(true);
  269. } else {
  270. if (pwm_collision) {
  271. /* An IRQ controlled PWM output actuation happened
  272. * during the measurement.
  273. * Discard this measurement. */
  274. irq_disable();
  275. allow_standby = false;
  276. } else {
  277. /* Normal operation mode. */
  278. if (ADC_INVERT)
  279. raw_adc = ADC_MAX - raw_adc;
  280. index = (NR_ADC > 1u) ? adc.index : 0u;
  281. output_setpoint_transform(IF_MULTIPWM(index,)
  282. ADC_HSL,
  283. raw_adc,
  284. &raw_setpoint,
  285. &filt_setpoint);
  286. /* This channel is ready for standby, if idle. */
  287. if (USE_DEEP_SLEEP) {
  288. adc.standby_ready[index] = (raw_setpoint == 0u);
  289. adc.conv_count = add_sat_u8(adc.conv_count, 1u);
  290. }
  291. /* Globally disable interrupts.
  292. * TIM0_OVF_vect must not interrupt re-programming of the PWM below. */
  293. irq_disable();
  294. /* Change the output signal (PWM). */
  295. if (adc_analogpins_enabled()) {
  296. output_setpoint_set(IF_MULTIPWM(index,)
  297. ADC_HSL,
  298. filt_setpoint);
  299. }
  300. /* Increment index to the next ADC. */
  301. if (NR_ADC > 1u) {
  302. if (++adc.index >= NR_ADC)
  303. adc.index = 0u;
  304. /* Switch MUX to the next ADC. */
  305. adc_configure_mux(ADC_MUXMODE_NORM, adc.index);
  306. adc.discard = 1;
  307. }
  308. allow_standby = true;
  309. }
  310. if (USE_BAT_MONITOR && adc.battery_meas_requested) {
  311. /* Battery measurement requested.
  312. * Reconfigure the ADC for battery measurement. */
  313. adc_configure(true);
  314. } else if (!adc_analogpins_enabled()) {
  315. adc_configure(false);
  316. set_standby_suppress(STANDBY_SRC_ADC, false);
  317. } else {
  318. /* If the PWM is disabled, request deep sleep to save power. */
  319. if (USE_DEEP_SLEEP && adc.conv_count >= NR_ADC) {
  320. adc.conv_count = 0u;
  321. go_standby = allow_standby;
  322. for (i = 0u; i < NR_ADC; i++)
  323. go_standby &= adc.standby_ready[i];
  324. set_standby_suppress(STANDBY_SRC_ADC, !go_standby);
  325. }
  326. }
  327. }
  328. } else {
  329. /* Discard this sample. */
  330. adc.discard--;
  331. irq_disable();
  332. }
  333. /* If deep sleep support is disabled, then the watchdog IRQ is also disabled.
  334. * Poke the watchdog here. */
  335. if (!USE_DEEP_SLEEP)
  336. wdt_reset();
  337. /* Re-enable the ADC interrupt. */
  338. ADCSRA |= (1u << ADIE);
  339. ADCSRA |= (1u << ADIF);
  340. memory_barrier();
  341. }
  342. /* Initialize the input ADC measurement.
  343. * Interrupts must be disabled before calling this function. */
  344. void adc_init(bool enable)
  345. {
  346. adc.prev_pwm_count = pwm_get_irq_count();
  347. memory_barrier();
  348. adc_configure(enable);
  349. }