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.
 
 
 
 

182 lines
3.9 KiB

  1. #include "config.h"
  2. #include "calibrate.h"
  3. #include "util.h"
  4. #include "adc.h"
  5. #include "dac.h"
  6. #include "led.h"
  7. #include "timer.h"
  8. #include "uart.h"
  9. //#define DEBUG_CALIBRATION
  10. float g_scale; /* delta(DAC) / delta(ADC) */
  11. /* Initialize. Assume some relatively-safe scaling if no calibration is run */
  12. void calibrate_init(void)
  13. {
  14. g_scale = (DAC_RANGE / 65536.0); /* 1 count at 16-bit DAC
  15. * means 1 counts at ADC */
  16. }
  17. /* Given the current DAC and ADC values d1 and a1,
  18. compute a new DAC value d2 to give the desired ADC value a2 */
  19. uint16_t adc_to_dac(uint16_t d1, int16_t a1, int16_t a2, float scale)
  20. {
  21. int32_t delta;
  22. int32_t d2;
  23. delta = (int32_t)((a2 - a1) * scale + 0.5);
  24. d2 = d1 + delta;
  25. return clamp(DAC_MIN, d2, DAC_MAX);
  26. }
  27. /* Calculate a new scale factor given two DAC and ADC points */
  28. float calculate_scale(uint16_t d1, float a1, uint16_t d2, float a2)
  29. {
  30. float scale;
  31. float a = a2 - a1;
  32. /* Correct for known errors */
  33. d1 = dac_get_actual_float(d1);
  34. d2 = dac_get_actual_float(d2);
  35. if (a < 0.1 && a > -0.1)
  36. scale = 1.0;
  37. else {
  38. scale = ((float)d2 - d1) / a;
  39. if (scale < 0.01)
  40. scale = 0.01;
  41. if (scale > 20)
  42. scale = 20;
  43. }
  44. return scale;
  45. }
  46. /* Seek with the DAC to reach a specific ADC value. Uses g_scale as
  47. an initial guess for scaling factor, but adjusts it dynamically. */
  48. uint16_t seek(uint16_t starting_dac, int16_t desired_adc)
  49. {
  50. uint16_t old_dac, dac;
  51. int16_t old_adc, adc;
  52. float scale = g_scale;
  53. int steps = 0;
  54. dac = starting_dac;
  55. /* goto current location */
  56. dac_write(dac);
  57. msleep(1);
  58. adc = adc_get();
  59. while (1)
  60. {
  61. /* give up if we're not making progress */
  62. if (steps++ > SEEK_MAX_STEPS) {
  63. // 2 flashes, delay, repeat
  64. led_pattern(0b00101000);
  65. break;
  66. }
  67. old_dac = dac;
  68. old_adc = adc;
  69. /* jump to the desired value */
  70. dac = adc_to_dac(old_dac, old_adc, desired_adc, scale);
  71. /* write it out */
  72. dac_write(dac);
  73. msleep(1);
  74. adc = adc_get();
  75. #ifdef DEBUG_CALIBRATION
  76. uart1_put_hex16(dac);
  77. uart1_put(' ');
  78. uart1_put_hex16(adc);
  79. uart1_put(' ');
  80. uart1_put_hex16(desired_adc);
  81. uart1_put(' ');
  82. uart1_put_hex32(*(uint32_t *)&scale);
  83. uart1_crlf();
  84. #endif
  85. /* if we're close, accept it */
  86. if (abs(adc - desired_adc) <= SEEK_FUZZ_ADC) {
  87. led_pattern(0b11111110);
  88. break;
  89. }
  90. /* otherwise, if we were within ADC clamp limits, and
  91. the DAC changed a non-trivial amount, readjust
  92. scale factor */
  93. if (adc > ADC_CLAMP_MIN && old_adc > ADC_CLAMP_MIN &&
  94. adc < ADC_CLAMP_MAX && old_adc < ADC_CLAMP_MAX &&
  95. abs((int32_t)dac - old_dac) >= SEEK_FUZZ_DAC) {
  96. scale = calculate_scale(old_dac, old_adc, dac, adc);
  97. }
  98. /* if we totally overshot the window, cut the scale in half */
  99. if ((adc < ADC_CLAMP_MIN && old_adc > ADC_CLAMP_MAX) ||
  100. (adc > ADC_CLAMP_MAX && old_adc < ADC_CLAMP_MIN))
  101. {
  102. scale *= 0.5;
  103. }
  104. }
  105. return dac;
  106. }
  107. /* Perform calibration */
  108. uint16_t do_calibrate(void)
  109. {
  110. uint16_t daczero, x1, x2;
  111. float y1, y2;
  112. /* Zero ADC */
  113. daczero = seek((DAC_MIN + DAC_MAX) / 2, CALIBRATE_ADC_ZERO);
  114. /* Go down take an accurate sample */
  115. x1 = seek(daczero, CALIBRATE_ADC_LOW);
  116. y1 = oversample(x1);
  117. /* Go up and take an accurate sample */
  118. x2 = seek(daczero, CALIBRATE_ADC_HIGH);
  119. y2 = oversample(x2);
  120. /* Calculate scale */
  121. g_scale = calculate_scale(x1, y1, x2, y2);
  122. #ifdef DEBUG_CALIBRATION
  123. uart1_put_string("calibrate x1=");
  124. uart1_put_dec(x1);
  125. uart1_put_string(" y1=");
  126. uart1_put_float(y1);
  127. uart1_put_string(" x2=");
  128. uart1_put_dec(x2);
  129. uart1_put_string(" y2=");
  130. uart1_put_float(y2);
  131. uart1_put_string(" scale=");
  132. uart1_put_float(g_scale);
  133. uart1_crlf();
  134. #endif
  135. /* Return to zero position */
  136. dac_write(daczero);
  137. return daczero;
  138. }
  139. /* Oversample to get a nice ADC value */
  140. float oversample(uint16_t dac)
  141. {
  142. int i;
  143. int32_t sum = 0;
  144. for (i = 0; i < OVERSAMPLE_COUNT; i++) {
  145. dac_write(dac);
  146. msleep(1);
  147. sum += adc_get();
  148. }
  149. return (float)sum / (float)OVERSAMPLE_COUNT;
  150. }