adc.c 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. /**
  2. ******************************************************************************
  3. * @file VAPC-meter/lib/adc.c
  4. * @author "Vladimir N. Shilov" <shilow@ukr.net>
  5. * @version V1
  6. * @date 24-March-2016
  7. * @brief This file contains the ADC functions.
  8. ******************************************************************************
  9. * Tim2 регулярно запускат АЦП.
  10. * АЦП измеряет два заданных канала и пинает DMA
  11. * DMA забирает данные у ADC и складывает их в ADC_Buffer
  12. * В прерывании по окончанию транзакции данные из ADC_Buffer
  13. * раскладываем по FastBuffers.
  14. */
  15. /* Includes ------------------------------------------------------------------*/
  16. #include "adc.h"
  17. /** @addtogroup ADC
  18. * @{
  19. */
  20. /* Private typedef -----------------------------------------------------------*/
  21. /* Private define ------------------------------------------------------------*/
  22. #define VOLTAGE_CHANNEL ADC_Channel_17
  23. #define CURRENT_CHANNEL ADC_Channel_18
  24. #define ADC1_DR_ADDRESS ((uint16_t)0x5344)
  25. #define ADC_BUFFER_ADDRESS ((uint16_t)(&ADC_Buffer))
  26. // Supply voltage
  27. #define ADC_REF 3306
  28. // Normal K for current channel = 4095 * 5.43 (Ку ОУ) * 0.05 (Rш)
  29. //#define ADC_DIV 1151
  30. //#define ADC_DIV_H 575
  31. // Oversampled K for current channel = (4095 * 64 / 8) * 5.43 (Ку ОУ) * 0.0501877 (Rш) * 0.937163 (Compensation)
  32. #define ADC_ODIV 8366
  33. #define ADC_ODIV_H 4183
  34. // for voltage calculation == 4095 * 64 / 8
  35. #define ADC_ORES 32760
  36. #define ADC_ORES_H 16380
  37. // OU parameters
  38. #define ADC_OU_MUL 543
  39. #define ADC_OU_MUL_DIV 100
  40. #define ADC_OU_ZERO_DRIFT 40
  41. // Input Voltage divider
  42. #define ADC_VOLT_K 11
  43. // (Частота МК (16 МHz) / Предделитель таймера (8) * Нужное время в секундах (0.0015625)) - 1
  44. #define TIM_PERIOD ((uint16_t)3128)
  45. #define TIM_PRESCALER TIM2_Prescaler_8
  46. /* Private macro -------------------------------------------------------------*/
  47. /* Private variables ---------------------------------------------------------*/
  48. static __IO uint16_t ADC_Buffer[ADC_BUFFER_SIZE];
  49. static __IO uint16_t VoltageFastBuffer[FAST_BUFFER_SIZE];
  50. static __IO uint16_t CurrentFastBuffer[FAST_BUFFER_SIZE];
  51. /* Private constants ---------------------------------------------------------*/
  52. __near __no_init const unsigned char Factory_VREFINT @ 0x4910;
  53. /* Private function prototypes -----------------------------------------------*/
  54. static void ADC_ConfigADC(void);
  55. static void ADC_ConfigDMA(void);
  56. static void ADC_ConfigTIM2(void);
  57. /* Private functions ---------------------------------------------------------*/
  58. /**
  59. * @brief Initialize and start ADC
  60. * @param None
  61. * @retval None
  62. */
  63. void ADC_Config(void)
  64. {
  65. /* ADC configuration */
  66. ADC_ConfigADC();
  67. /* DMA configuration */
  68. ADC_ConfigDMA();
  69. /* TIM2 configuration */
  70. ADC_ConfigTIM2();
  71. }
  72. /**
  73. * @brief Configure ADC peripheral
  74. * @param None
  75. * @retval None
  76. */
  77. static void ADC_ConfigADC(void)
  78. {
  79. /* Enable ADC1 clock */
  80. CLK_PeripheralClockConfig(CLK_Peripheral_ADC1, ENABLE);
  81. /* Initialize and configure ADC1 */
  82. ADC_Init(ADC1, ADC_ConversionMode_Single, ADC_Resolution_12Bit, ADC_Prescaler_1);
  83. ADC_SamplingTimeConfig(ADC1, ADC_Group_SlowChannels, ADC_SamplingTime_384Cycles);
  84. ADC_SamplingTimeConfig(ADC1, ADC_Group_FastChannels, ADC_SamplingTime_384Cycles);
  85. /* Enable ADC1 */
  86. ADC_Cmd(ADC1, ENABLE);
  87. /* Enable ADC1 Voltage meter channel */
  88. ADC_ChannelCmd(ADC1, VOLTAGE_CHANNEL, ENABLE);
  89. ADC_SchmittTriggerConfig(ADC1, VOLTAGE_CHANNEL, DISABLE);
  90. /* Enable ADC1 Current meter channel */
  91. ADC_ChannelCmd(ADC1, CURRENT_CHANNEL, ENABLE);
  92. ADC_SchmittTriggerConfig(ADC1, CURRENT_CHANNEL, DISABLE);
  93. #ifdef ADC_MEASURE_REF_VOLT
  94. /* ADC Voltage Reference */
  95. ADC_VrefintCmd(ENABLE);
  96. /* Enable ADC1 Vrefint Channel */
  97. ADC_ChannelCmd(ADC1, ADC_Channel_Vrefint, ENABLE);
  98. #endif // ADC_MEASURE_REF_VOLT
  99. /* Enable ADC1 DMA requests*/
  100. ADC_DMACmd(ADC1, ENABLE);
  101. /* Start ADC1 Conversion using TIM1 TRGO*/
  102. ADC_ExternalTrigConfig(ADC1, ADC_ExtEventSelection_Trigger3, ADC_ExtTRGSensitivity_Rising);
  103. }
  104. /**
  105. * @brief Configure DMA peripheral
  106. * @param None
  107. * @retval None
  108. */
  109. static void ADC_ConfigDMA(void)
  110. {
  111. /* Enable DMA1 clock */
  112. CLK_PeripheralClockConfig(CLK_Peripheral_DMA1, ENABLE);
  113. /* Connect ADC to DMA channel 0 */
  114. SYSCFG_REMAPDMAChannelConfig(REMAP_DMA1Channel_ADC1ToChannel0);
  115. DMA_Init(DMA1_Channel0, ADC_BUFFER_ADDRESS,
  116. ADC1_DR_ADDRESS,
  117. ADC_BUFFER_SIZE,
  118. DMA_DIR_PeripheralToMemory,
  119. DMA_Mode_Circular,
  120. DMA_MemoryIncMode_Inc,
  121. DMA_Priority_High,
  122. DMA_MemoryDataSize_HalfWord);
  123. /* DMA Channel0 enable */
  124. DMA_Cmd(DMA1_Channel0, ENABLE);
  125. /* Enable DMA1 channel0 Transfer complete interrupt */
  126. DMA_ITConfig(DMA1_Channel0, DMA_ITx_TC, ENABLE);
  127. /* DMA enable */
  128. DMA_GlobalCmd(ENABLE);
  129. }
  130. /**
  131. * @brief Configure TIM2 peripheral
  132. * @param None
  133. * @retval None
  134. */
  135. static void ADC_ConfigTIM2(void)
  136. {
  137. /* Enable TIM2 clock */
  138. CLK_PeripheralClockConfig(CLK_Peripheral_TIM2, ENABLE);
  139. /* Initializes the TIM2 Time Base Unit */
  140. TIM2_TimeBaseInit(TIM_PRESCALER, TIM2_CounterMode_Up, TIM_PERIOD);
  141. /* Selects the TIM2 Update Request Interrupt source */
  142. TIM2_UpdateRequestConfig(TIM2_UpdateSource_Regular);
  143. /* Master Mode selection: Update event */
  144. TIM2_SelectOutputTrigger(TIM2_TRGOSource_Update);
  145. /* Enable TIM2 */
  146. TIM2_Cmd(ENABLE);
  147. }
  148. /**
  149. * @brief DMA1 channel0 and channel1 Interrupt routine.
  150. * @param None
  151. * @retval None
  152. */
  153. INTERRUPT_HANDLER(DMA1_CHANNEL0_1_IRQHandler,2)
  154. {
  155. static uint8_t idx = 0;
  156. static uint16_t va1=0, va2=0, ca1=0, ca2=0;
  157. if (ADC_Buffer[0] < va1 && ADC_Buffer[0] < va2) {
  158. VoltageFastBuffer[idx] = va1;
  159. } else if (ADC_Buffer[0] > va1 && ADC_Buffer[0] > va2) {
  160. VoltageFastBuffer[idx] = va1;
  161. } else {
  162. VoltageFastBuffer[idx] = ADC_Buffer[0];
  163. }
  164. va2 = va1;
  165. va1 = ADC_Buffer[0];
  166. if (ADC_Buffer[1] < ca1 && ADC_Buffer[1] < ca2) {
  167. CurrentFastBuffer[idx] = ca1;
  168. } else if (ADC_Buffer[1] > ca1 && ADC_Buffer[1] > ca2) {
  169. CurrentFastBuffer[idx] = ca1;
  170. } else {
  171. CurrentFastBuffer[idx] = ADC_Buffer[1];
  172. }
  173. ca2 = ca1;
  174. ca1 = ADC_Buffer[1];
  175. idx ++;
  176. if(idx >= FAST_BUFFER_SIZE) {
  177. idx = 0;
  178. }
  179. /* Clear IT Pending Bit */
  180. DMA1_Channel0->CSPR &= (uint8_t)~(uint8_t)(DMA1_IT_TC0 & (uint8_t)0x06);
  181. }
  182. /**
  183. * @brief Return average values from fast buffers
  184. * @param None
  185. * @retval Latest_Voltage
  186. */
  187. uint16_t * ADC_GetValues(void) {
  188. static uint16_t avgVal[ADC_BUFFER_SIZE];
  189. uint32_t volt=0, curr=0, shunt_volt=0;
  190. uint8_t i;
  191. /* Summarize buffers values */
  192. for(i=0;i<FAST_BUFFER_SIZE;i++){
  193. volt += VoltageFastBuffer[i];
  194. curr += CurrentFastBuffer[i];
  195. }
  196. curr += 4;
  197. curr /= 8;
  198. // компенсация смещения нуля ОУ
  199. if (curr > ADC_OU_ZERO_DRIFT) {
  200. curr -= ADC_OU_ZERO_DRIFT;
  201. curr *= ADC_REF;
  202. shunt_volt = curr;
  203. curr += ADC_ODIV_H; // для округления
  204. curr /= ADC_ODIV; // делим на К -- на выходе ток в мА
  205. /* так как шунт стоит в разрыве земли до выхода из БП
  206. компенсируем падение напряжения на нём. */
  207. shunt_volt *= ADC_OU_MUL_DIV;
  208. shunt_volt += (ADC_OU_MUL/2);
  209. shunt_volt /= ADC_OU_MUL; // значение с выхода ОУ преобразуем в значение со входа ОУ
  210. } else {
  211. curr = 0;
  212. }
  213. /* Попытка оверсемплинга, чтобы сделать шаг ~1мВ
  214. делим на 8, умножаем на опорное напряжение, умножаем на входной делитель
  215. и делим на (12 бит АЦП * 8). */
  216. volt += 4; // для округления
  217. volt /= 8; // усредняем
  218. volt *= ADC_REF;
  219. volt *= ADC_VOLT_K;
  220. volt -= shunt_volt;
  221. volt += ADC_ORES_H;
  222. volt /= ADC_ORES;
  223. avgVal[0] = (uint16_t)volt;
  224. avgVal[1] = (uint16_t)curr;
  225. return avgVal;
  226. }
  227. /**
  228. * @}
  229. */
  230. /************************ (C) Vladimir N. Shilov *****END OF FILE****/