adc.c 7.4 KB

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