• Объявления

    • admin

      Просьба всем принять участие!   24.11.2017

      На форуме разыгрывается спектроанализатор Arinst SSA-TG LC (цена 18500 руб). Просьба всем перейти по ссылке ниже и принять участие!
Рыгз

Помогите с АЦП.

13 сообщений в этой теме

Рыгз    1

Привет. Пилю кое что на китайской плате с ф103, понадобилось добавить в схему термометр и еще кой-чего на ацп. Но уже с термометром возникла проблема. Воткнул что было, lm35, микроконтроллером намерил 15 градусов. Подоткнул к лм-ке мультиметр, показания ацп выросли до 18 градусов, на мультиметре 247мВ (26,7С). Раз мультиметр добавил показаний ацп, я решил попробовать воткнуть резистор между ацп и землей, сначала 4.7к а потом и 1к. Лм-ка по прежнему показывала 247мВ, но с 1к резистором показания ацп микроконтроллера выросли до требуемых 26С, но резистор выглядит костылем. Может у кого есть предположения что не так? Ацп калибруется, при соединении с землей показания 0, с питанием 4095.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Быстрый заказ печатных плат

Полный цикл производства PCB по низким ценам!

  • x
    мм
Заказать Получить купон на $5.00
mail_robot    1 208

во всем виновата емкость УВХ. Нужно либо увеличивать число циклов одного преобразования, либо ставить низкоомный буфер-повторитель на ОУ, либо добавлять RC цепочку по расчету. В вашем случае видимо наиболее правильным будет применение первого способа.

вот информация из даташита по этому поводу. Показывает влияние выходного сопротивления источника сигнала на время опроса для получения гарантированой точности. Видно, что влияние прекращается совсем, начиная с 71, 5 цикла. Но на температуру и вообще медленные процессы не требующие скоростного опроса лучше всегда ставить 239,5 циклов (это тоже весьма быстро на самом деле) и уже подниматься вверх чисто по необходимости.

2017-02-28_08-39-31.png

многие АЦП пользователи сталкиваются с этим моментом по первости. Такие уж особенности в архитектуре этого блока у STM32

вот эту статейку еще прочтите. Очень полезно http://leoniv.livejournal.com/194681.html

Изменено пользователем mail_robot

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Рыгз    1

Очень надеюсь что Вы мне поможете еще кое с чем. Продолжаю пытаться освоить stm-овский ацп. В даташите не совсем понятен один момент. Допустим ацп работает в сканирующем режиме, но не в режиме непрерывного преобразования, то есть по запросу ADC_SoftwareStartConvCmd(ADC1, ENABLE); сканирует несколько каналов и отключается, в ДШ ничего не сказано про ЕОС флаг. Судя по тому что моя программа виснет на while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET); бит не устанавливается ни в конце группы каналов, ни после каждого канала. Как синхронизировать ацп, дма и программу в таком случае? Мне нужна элементарная вещь, по запросу программы получить ответ одного из регулярных каналов АЦП, так как отдельный канал прочитать невозможно, я пытаюсь прочитать всю группу каналов в буфер, и вернуть значение отдельного канала из него. В режиме непрерывного преобразования все работает, но хочется что бы АЦП опрашивал входы в синхронном с программой режиме. Допустимо ли использовать вот такую строку while(DMA_GetFlagStatus(DMA1_FLAG_TC1) == RESET); ?

Понятно что можно использовать инжектированные каналы, но их всего 4 и хочется разобраться.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
mail_robot    1 208

именно инжектированный и надо использовать для одиночных опросов. Для того они и созданы. А регулярная группа обычно садится на канал DMA и читается непрерывно в память куда нибудь. Попутно еще и сэмплируется. Одиночный опрос группы регулярных каналов тоже никогда особых проблем не вызывал. Наверное стоит еще раз внимательно почитать раздел ДШ по этому вопросу.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Рыгз    1

Инжектированных слишком мало. И я не помню что бы в тех устройствах, что мне приходилось делать на мк, мне требовалась непрерывная асинхронная работа ацп, а вот недоделанный и пока брошенный пример когда надо было быстро опросить несколько каналов есть)

17 часов назад, mail_robot сказал:

Одиночный опрос группы регулярных каналов тоже никогда особых проблем не вызывал. Наверное стоит еще раз внимательно почитать раздел ДШ по этому вопросу.

Очень внимательно читал. Не нашел. Нет про ЕОС флаг при SCAN режиме и все, и не предложен способ обнаружения окончания обработки регулярной группы. В разделе ДМА тоже не особо понятно описан момент появления флага окончания передачи. И были сомнения то ли он считает концом передачи конец регистров источника, в этом случае ацп и всего 1 регистр, толи буфера, куда пишет, где регистров больше одного, то ли вообще периферия как то сообщает ДМА что передача закончилась. В любом случае экспериментально для себя выяснил, что строка

while(DMA_GetFlagStatus(DMA1_FLAG_TC1) == RESET);

ждет столько сколько необходимо и вопрос на том закрылся)

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
GOR23    35

Новую тему не создавал, так как вопрос похожий. Читаю данные с 7-ми каналов ацп, в режиме сканирования через dma. Проходят все семь преобразований, срабатывает колбэк, но в массиве с данными заполнен только 0 элемент, все остальные нули. В дма инкремент памяти включён, ширина пол слова. Запускаю преобразование так:

 HAL_ADC_Start_DMA(&hadc1, (uint32_t*)&adc_DmaBuffer, 7).

Может кто сталкивался, подскажите. Ниже привожу настройки АЦП и DMA. И ещё попутный вопрос, не найду где в HAL переключается битность АЦП.

void MX_DMA_Init(void)
{
  __HAL_RCC_DMA1_CLK_ENABLE();


  HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);

}

void MX_ADC1_Init(void)
{

  ADC_ChannelConfTypeDef sConfig;

  hadc1.Instance = ADC1;
  hadc1.Init.ScanConvMode = ADC_SCAN_ENABLE;
  hadc1.Init.ContinuousConvMode = DISABLE;
  hadc1.Init.DiscontinuousConvMode = DISABLE;
  hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  hadc1.Init.NbrOfConversion = 7;
  if (HAL_ADC_Init(&hadc1) != HAL_OK)
  {
    Error_Handler();
  }

  sConfig.Channel = ADC_CHANNEL_6;
  sConfig.Rank = 1;
  sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }

  sConfig.Channel = ADC_CHANNEL_7;
  sConfig.Rank = 2;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }

  sConfig.Channel = ADC_CHANNEL_9;
  sConfig.Rank = 3;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }

  sConfig.Channel = ADC_CHANNEL_14;
  sConfig.Rank = 4;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }

  sConfig.Channel = ADC_CHANNEL_15;
  sConfig.Rank = 5;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }

  sConfig.Channel = ADC_CHANNEL_TEMPSENSOR;
  sConfig.Rank = 6;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }

  sConfig.Channel = ADC_CHANNEL_VREFINT;
  sConfig.Rank = 7;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }

}

void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc)
{

  GPIO_InitTypeDef GPIO_InitStruct;
  if(hadc->Instance==ADC1)
  {
    __HAL_RCC_ADC1_CLK_ENABLE();

    GPIO_InitStruct.Pin = MCU_ADC_2_Pin|MCU_ADC_1_Pin;
    GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = MCU_ADC_Main_Pin|MCU_ADC_Batt_Pin;
    GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = MCU_ADC_V_REF_Pin;
    GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
    HAL_GPIO_Init(MCU_ADC_V_REF_GPIO_Port, &GPIO_InitStruct);
  
    hdma_adc1.Instance = DMA1_Channel1;
    hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY;
    hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_adc1.Init.MemInc = DMA_MINC_ENABLE;
    hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
    hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
    hdma_adc1.Init.Mode = DMA_NORMAL;
    hdma_adc1.Init.Priority = DMA_PRIORITY_LOW;
    if (HAL_DMA_Init(&hdma_adc1) != HAL_OK)
    {
      Error_Handler();
    }

    __HAL_LINKDMA(hadc,DMA_Handle,hdma_adc1);

  }
}

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
mail_robot    1 208

вот эту строчку в инитке поменяй на ENABLE

hadc1.Init.ContinuousConvMode = DISABLE;

 

 

Изменено пользователем mail_robot

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
GOR23    35
HAL_StatusTypeDef HAL_ADC_Init(ADC_HandleTypeDef* hadc)
{
  HAL_StatusTypeDef tmp_hal_status = HAL_OK;
  uint32_t tmp_cr1 = 0;
  uint32_t tmp_cr2 = 0;
  uint32_t tmp_sqr1 = 0;
  
  /* Check ADC handle */
  if(hadc == NULL)
  {
    return HAL_ERROR;
  }
  
  /* Check the parameters */
  assert_param(IS_ADC_ALL_INSTANCE(hadc->Instance));
  assert_param(IS_ADC_DATA_ALIGN(hadc->Init.DataAlign));
  assert_param(IS_ADC_SCAN_MODE(hadc->Init.ScanConvMode));
  assert_param(IS_FUNCTIONAL_STATE(hadc->Init.ContinuousConvMode));
  assert_param(IS_ADC_EXTTRIG(hadc->Init.ExternalTrigConv));
  
  if(hadc->Init.ScanConvMode != ADC_SCAN_DISABLE)
  {
    assert_param(IS_ADC_REGULAR_NB_CONV(hadc->Init.NbrOfConversion));
    assert_param(IS_FUNCTIONAL_STATE(hadc->Init.DiscontinuousConvMode));
    if(hadc->Init.DiscontinuousConvMode != DISABLE)
    {
      assert_param(IS_ADC_REGULAR_DISCONT_NUMBER(hadc->Init.NbrOfDiscConversion));
    }
  }
  
  /* As prerequisite, into HAL_ADC_MspInit(), ADC clock must be configured    */
  /* at RCC top level.                                                        */
  /* Refer to header of this file for more details on clock enabling          */
  /* procedure.                                                               */

  /* Actions performed only if ADC is coming from state reset:                */
  /* - Initialization of ADC MSP                                              */
  if (hadc->State == HAL_ADC_STATE_RESET)
  {
    /* Initialize ADC error code */
    ADC_CLEAR_ERRORCODE(hadc);
    
    /* Allocate lock resource and initialize it */
    hadc->Lock = HAL_UNLOCKED;
    
    /* Init the low level hardware */
    HAL_ADC_MspInit(hadc);
  }
  
  /* Stop potential conversion on going, on regular and injected groups */
  /* Disable ADC peripheral */
  /* Note: In case of ADC already enabled, precaution to not launch an        */
  /*       unwanted conversion while modifying register CR2 by writing 1 to   */
  /*       bit ADON.                                                          */
  tmp_hal_status = ADC_ConversionStop_Disable(hadc);
  
  
  /* Configuration of ADC parameters if previous preliminary actions are      */ 
  /* correctly completed.                                                     */
  if (HAL_IS_BIT_CLR(hadc->State, HAL_ADC_STATE_ERROR_INTERNAL) &&
      (tmp_hal_status == HAL_OK)                                  )
  {
    /* Set ADC state */
    ADC_STATE_CLR_SET(hadc->State,
                      HAL_ADC_STATE_REG_BUSY | HAL_ADC_STATE_INJ_BUSY,
                      HAL_ADC_STATE_BUSY_INTERNAL);
    
    /* Set ADC parameters */
    
    /* Configuration of ADC:                                                  */
    /*  - data alignment                                                      */
    /*  - external trigger to start conversion                                */
    /*  - external trigger polarity (always set to 1, because needed for all  */
    /*    triggers: external trigger of SW start)                             */
    /*  - continuous conversion mode                                          */
    /* Note: External trigger polarity (ADC_CR2_EXTTRIG) is set into          */
    /*       HAL_ADC_Start_xxx functions because if set in this function,     */
    /*       a conversion on injected group would start a conversion also on  */
    /*       regular group after ADC enabling.                                */
    tmp_cr2 |= (hadc->Init.DataAlign                               |
                ADC_CFGR_EXTSEL(hadc, hadc->Init.ExternalTrigConv) |
                ADC_CR2_CONTINUOUS(hadc->Init.ContinuousConvMode)   );
    
    /* Configuration of ADC:                                                  */
    /*  - scan mode                                                           */
    /*  - discontinuous mode disable/enable                                   */
    /*  - discontinuous mode number of conversions                            */
    tmp_cr1 |= (ADC_CR1_SCAN_SET(hadc->Init.ScanConvMode));
    
    /* Enable discontinuous mode only if continuous mode is disabled */
    /* Note: If parameter "Init.ScanConvMode" is set to disable, parameter    */
    /*       discontinuous is set anyway, but will have no effect on ADC HW.  */
    if (hadc->Init.DiscontinuousConvMode == ENABLE)
    {
      if (hadc->Init.ContinuousConvMode == DISABLE)
      {
        /* Enable the selected ADC regular discontinuous mode */
        /* Set the number of channels to be converted in discontinuous mode */
        SET_BIT(tmp_cr1, ADC_CR1_DISCEN                                            |
                         ADC_CR1_DISCONTINUOUS_NUM(hadc->Init.NbrOfDiscConversion)  );
      }
      else
      {
        /* ADC regular group settings continuous and sequencer discontinuous*/
        /* cannot be enabled simultaneously.                                */
        
        /* Update ADC state machine to error */
        SET_BIT(hadc->State, HAL_ADC_STATE_ERROR_CONFIG);
        
        /* Set ADC error code to ADC IP internal error */
        SET_BIT(hadc->ErrorCode, HAL_ADC_ERROR_INTERNAL);
      }
    }
    
    /* Update ADC configuration register CR1 with previous settings */
      MODIFY_REG(hadc->Instance->CR1,
                 ADC_CR1_SCAN    |
                 ADC_CR1_DISCEN  |
                 ADC_CR1_DISCNUM    ,
                 tmp_cr1             );
    
    /* Update ADC configuration register CR2 with previous settings */
      MODIFY_REG(hadc->Instance->CR2,
                 ADC_CR2_ALIGN   |
                 ADC_CR2_EXTSEL  |
                 ADC_CR2_EXTTRIG |
                 ADC_CR2_CONT       ,
                 tmp_cr2             );

    /* Configuration of regular group sequencer:                              */
    /* - if scan mode is disabled, regular channels sequence length is set to */
    /*   0x00: 1 channel converted (channel on regular rank 1)                */
    /*   Parameter "NbrOfConversion" is discarded.                            */
    /*   Note: Scan mode is present by hardware on this device and, if        */
    /*   disabled, discards automatically nb of conversions. Anyway, nb of    */
    /*   conversions is forced to 0x00 for alignment over all STM32 devices.  */
    /* - if scan mode is enabled, regular channels sequence length is set to  */
    /*   parameter "NbrOfConversion"                                          */
    if (ADC_CR1_SCAN_SET(hadc->Init.ScanConvMode) == ADC_SCAN_ENABLE)
    {
      tmp_sqr1 = ADC_SQR1_L_SHIFT(hadc->Init.NbrOfConversion);
    }
      
    MODIFY_REG(hadc->Instance->SQR1,
               ADC_SQR1_L          ,
               tmp_sqr1             );
    
    /* Check back that ADC registers have effectively been configured to      */
    /* ensure of no potential problem of ADC core IP clocking.                */
    /* Check through register CR2 (excluding bits set in other functions:     */
    /* execution control bits (ADON, JSWSTART, SWSTART), regular group bits   */
    /* (DMA), injected group bits (JEXTTRIG and JEXTSEL), channel internal    */
    /* measurement path bit (TSVREFE).                                        */
    if (READ_BIT(hadc->Instance->CR2, ~(ADC_CR2_ADON | ADC_CR2_DMA |
                                        ADC_CR2_SWSTART | ADC_CR2_JSWSTART |
                                        ADC_CR2_JEXTTRIG | ADC_CR2_JEXTSEL |
                                        ADC_CR2_TSVREFE                     ))
         == tmp_cr2)
    {
      /* Set ADC error code to none */
      ADC_CLEAR_ERRORCODE(hadc);
      
      /* Set the ADC state */
      ADC_STATE_CLR_SET(hadc->State,
                        HAL_ADC_STATE_BUSY_INTERNAL,
                        HAL_ADC_STATE_READY);
    }
    else
    {
      /* Update ADC state machine to error */
      ADC_STATE_CLR_SET(hadc->State,
                        HAL_ADC_STATE_BUSY_INTERNAL,
                        HAL_ADC_STATE_ERROR_INTERNAL);
      
      /* Set ADC error code to ADC IP internal error */
      SET_BIT(hadc->ErrorCode, HAL_ADC_ERROR_INTERNAL);
      
      tmp_hal_status = HAL_ERROR;
    }
  
  }
  else
  {
    /* Update ADC state machine to error */
    SET_BIT(hadc->State, HAL_ADC_STATE_ERROR_INTERNAL);
        
    tmp_hal_status = HAL_ERROR;
  }
  
  /* Return function status */
  return tmp_hal_status;
}

hadc1.Init.ContinuousConvMode = ENABLE; не помогло. Но выяснил что в массив записывается последний байт последнего измерения. Например если hadc->Instance->DR тут лежит 0x5D0, то у меня в маcиве просто 0xD0. Такое ощущение что в дма инкремент не включён, но я там сто раз проверил всё включено.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
mail_robot    1 208

а камень какой?

камень судя по всему сотка

поменяй строчку в инитке DMA

hdma_adc1.Init.Mode = DMA_NORMAL;

на

hdma_adc1.Init.Mode = DMA_CIRCULAR;

и все пройдет )

у тебя сейчас дма берет только одно значение и останавливается в ожидании следующего триггера. В режиме циркуляр завершение предыдущего трансфера генерирует автотриггер для следующего

У сотки битность АЦП не меняется. Поменять ее принудительно можно на камнях типа F0 например строчкой

hadc.Init.Resolution = ADC_RESOLUTION_12B;

с структуре hadc.init

Изменено пользователем mail_robot

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
GOR23    35

камень stm32f103rc. C circular тоже не прокатило, думаю может отладчик тупит, сейчас выкину тот массив в uart гляну ещё так.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
GOR23    35

Дело было не в бобине... Сначала инициализировал ацп MX_ADC1_Init(); потом дма  MX_DMA_Init(); Поменял местами (первый дма, потом ацп) и всё заработало. Вечером гляну почему так происходило, целый день потратил... Ребяты не наступите на те же грабли))

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Ваша публикация должна быть проверена модератором

Гость
Вы не авторизованы. Если у вас есть аккаунт, пожалуйста, войдите.
Ответить в тему...

×   Вставлено в виде отформатированного текста.   Восстановить форматирование

  Разрешено не более 75 смайлов.

×   Ваша ссылка была автоматически встроена.   Отобразить как ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставить изображения напрямую. Загрузите или вставьте изображения по ссылке.

Загрузка...