Hal kütüphanesinde ADC kanal ayarları nasıl yapılıyor?

Başlatan Mucit23, 13 Ocak 2016, 17:45:17

Mucit23

Selamlar,

STM32F7 ile 3 kanal Adc den veri almak istiyorum. Her bir kanalın verisini DMA ile Değişkenlere yüklemem gerek.

Şuanda Tek kanaldan bu işi yapıyorum ama 3 kanala çıkınca takılıp kaldım. Öncelikle bu iş olurmu merak ediyorum. ADC sırasıyla 3 kanalı birde tarayıp benim değişkenlerime yazması lazım.

Stm32F4'de bu iş yapılıyor diye biliyorum. Hatta burada örnek kod var. 2 Kanaldan okuma yapılıp 2 boyutlu bir diziye kanal verileri yazılmış

https://github.com/FabLabSeoul/WingProject/wiki/STM32-ADC-Multi-Channel-Using-DMA

Aynısının 3 kanalını yapmaya çalışıyorum ama HAL library ile takıldığım birkaç nokta var.
Eski kütüphanede ADC kanal ayarı için tek bir fonksiyon vardı. Örneğin aşağıdaki gibi yapılıyordu.

  ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 1, ADC_SampleTime_55Cycles5); //PC1 as Input
  ADC_RegularChannelConfig(ADC1, ADC_Channel_12, 2, ADC_SampleTime_55Cycles5);


HAL library'de ise aşağıdaki gibi bir structy yapısı kullanılıyor.

  if (HAL_ADC_Init(&AdcHandle) != HAL_OK)
  {
    /* ADC initialization Error */
  }
	
  /*##-2- Configure ADC regular channel ######################################*/
  sConfig.Channel      = ADC_CHANNEL_8;
  sConfig.Rank         = 1;
  sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;
  sConfig.Offset       = 0;

  if (HAL_ADC_ConfigChannel(&AdcHandle, &sConfig) != HAL_OK)
  {
    /* Channel Configuration Error */
  }
	
  /*##-2- Configure ADC regular channel ######################################*/
  sConfig.Channel      = ADC_CHANNEL_7;
  sConfig.Rank         = 1;
  sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;
  sConfig.Offset       = 0;

  if (HAL_ADC_ConfigChannel(&AdcHandle, &sConfig) != HAL_OK)
  {
    /* Channel Configuration Error */
  }

  /*##-2- Configure ADC regular channel ######################################*/
  sConfig.Channel      = ADC_CHANNEL_6;
  sConfig.Rank         = 1;
  sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;
  sConfig.Offset       = 0;

  if (HAL_ADC_ConfigChannel(&AdcHandle, &sConfig) != HAL_OK)
  {
    /* Channel Configuration Error */
  }


Ben Channel6, Channel7 ve Channel8 'i kullanmak istiyorum. Bunun için yukarıdaki kanal ayarlama işlemini her bir kanal için tekrarladım. 

DMA ayarlarındada farklılık var.

HAL kütüphanesinde DMA'da sadece boyut ayarı var başka birşey bulamadım ben. 3 kanal için aşağıdaki gibi yapmaya çalıştım.
  HAL_ADC_Start_DMA(&AdcHandle, (uint32_t*)&uhADCxConvertedValue[0], 3)


En sonda gönderdiğim 3 verisi Lenght yani boyut olarak geçiyor. Tek kanal için 1 yazıyordum oraya.

ADC ayarlarında   ScanConvMode  = ENABLE; yaptım. Bu ayar aktif olunca kanalların taranması lazım. Ayrıca NbrOfConversion Parametresini 3 yaptım. 3 kez dönüşüm işlemi yapılacak.

DMA ayarlarım ise aşağıdaki gibi .
  hdma_adc.Instance = ADCx_DMA_STREAM;

  hdma_adc.Init.Channel  = ADCx_DMA_CHANNEL;
  hdma_adc.Init.Direction = DMA_PERIPH_TO_MEMORY;
  hdma_adc.Init.PeriphInc = DMA_PINC_DISABLE;
  hdma_adc.Init.MemInc = DMA_MINC_ENABLE;
  hdma_adc.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
  hdma_adc.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
  hdma_adc.Init.Mode = DMA_CIRCULAR;
  hdma_adc.Init.Priority = DMA_PRIORITY_HIGH;
  hdma_adc.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
  hdma_adc.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_HALFFULL;
  hdma_adc.Init.MemBurst = DMA_MBURST_SINGLE;
  hdma_adc.Init.PeriphBurst = DMA_PBURST_SINGLE;

  HAL_DMA_Init(&hdma_adc);


Yaptığım tek değişiklik DMA_MINC_ENABLE yapmak. Yani Hafıza adresi arttırılacak dedim. Buna rağmen çalışmadı.

Aslında Sadece Channel 6 çalışıyor.

Normalde okuma sırasına göre düşünürsek Dizinin 0. elemanı Channel 6, Dizinin 1. elemanı Channel 7 ve Dizinin 2. elemanı Channel8 olması lazım.
6. Kanal da sıkıntı yok, dizinin 0. elemanı kanal 6 nın değerini veriyor. Dizinin 1. elemanından sürekli sıfır okuyorum. Dizinin 2. elemanı ise 0. kanal ile bağımlı olarak değişiyor. Sanki 0. kanaldan etkileniyor.

Neyi atlıyor olabilirim sizce? Kanal ayarı için başka bir ayar bulamadım ben.

Bu arada GPIO ayarları tamam. İlgili pinler PF8, PF9 ve PF10 analog giriş olarak ayarlandı.

bocek

Hocam
sConfig.Rank         = 1;


hepsinde 1 yapmışssın. Sırayla 1,2,3 diye gitmeyecek mi?

Şuradaki rehberde:
http://visualgdb.com/tutorials/arm/stm32/adc/

29. maddede rank olayını açıklamış.
1 ya da 0. işte 'bit'ün mesele..

Mucit23

Hocam şuan bende Rank olayını araştırıyordum. Ne olduğunu tam olarak anlayamadım. Datasheette ADC Regular Sequence Register adında ADC_SQRL1... ADC_SWRL4 arası registerlar var. Rank değeri bu registerlara yazılıyor.

Benim anlamadığım nokta sıralamayı nasıl yapacam. Rank ayarının nasıl kullanıldığını anlayamadım. Şimdi adc ayarlarımı aşağıdaki gibi yaptım.

/**
  * @brief  ADC configuration
  * @param  htim : ADC handle
  * @retval None
  */
static void ADC_Config(void)
{
  ADC_ChannelConfTypeDef sConfig;
  /*##-1- Configure the ADC peripheral #######################################*/
  AdcHandle.Instance          = ADC3;
  
  AdcHandle.Init.ClockPrescaler        = ADC_CLOCKPRESCALER_PCLK_DIV4;
  AdcHandle.Init.Resolution            = ADC_RESOLUTION_12B;
  AdcHandle.Init.DataAlign             = ADC_DATAALIGN_RIGHT;
  AdcHandle.Init.NbrOfConversion       = 3;
  AdcHandle.Init.ScanConvMode          = ENABLE;                        /* Sequencer disabled (ADC conversion on only 1 channel: channel set on rank 1) */
  AdcHandle.Init.ContinuousConvMode    = DISABLE;                       /* Continuous mode disabled to have only 1 conversion at each conversion trig */
  AdcHandle.Init.DiscontinuousConvMode = DISABLE;                       /* Parameter discarded because sequencer is disabled */
  AdcHandle.Init.NbrOfDiscConversion   = 0;
  AdcHandle.Init.ExternalTrigConvEdge  = ADC_EXTERNALTRIGCONVEDGE_RISING;        /* Conversion start trigged at each external event */
  AdcHandle.Init.ExternalTrigConv      = ADC_EXTERNALTRIG2_T2_TRGO;
  AdcHandle.Init.DMAContinuousRequests = ENABLE;
  AdcHandle.Init.EOCSelection          = DISABLE;
	
  if (HAL_ADC_Init(&AdcHandle) != HAL_OK)
  {
    /* ADC initialization Error */
  }
	
  /*##-2- Configure ADC regular channel ######################################*/
  sConfig.Channel      = ADC_CHANNEL_6;
  sConfig.Rank         = 1;
  sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;
  sConfig.Offset       = 0;

  if (HAL_ADC_ConfigChannel(&AdcHandle, &sConfig) != HAL_OK)
  {
    /* Channel Configuration Error */
  }
	
  /*##-2- Configure ADC regular channel ######################################*/
  sConfig.Channel      = ADC_CHANNEL_7;
  sConfig.Rank         = 2;
  sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;
  sConfig.Offset       = 0;

  if (HAL_ADC_ConfigChannel(&AdcHandle, &sConfig) != HAL_OK)
  {
    /* Channel Configuration Error */
  }
	
  /*##-2- Configure ADC regular channel ######################################*/
  sConfig.Channel      = ADC_CHANNEL_8;
  sConfig.Rank         = 3;
  sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;
  sConfig.Offset       = 0;

  if (HAL_ADC_ConfigChannel(&AdcHandle, &sConfig) != HAL_OK)
  {
    /* Channel Configuration Error */
  }

  /*##-3- Start the conversion process #######################################*/
  if(HAL_ADC_Start_DMA(&AdcHandle, (uint32_t*)&uhADCxConvertedValue[0], 3) != HAL_OK)
  {
    /* Start Conversation Error */
  }

}


Her kanal için ayrı ayrı ayarlama yapıp Rank değerlerini 1-2-3 şeklinde belirledim. Ama buna rağmen çalışmadı hala 2. Kanaldan sürekli sıfır okuyorum. Normalde float değerler gelmesi lazım. Ama 1 ve 3 değişiyor. Kanallardan bir tanesi, genellikle yukarıda kanal ayarlaması yaparken en son hangisini ayarladıysam o kanal düzgün çalışıyor.

Bu Rank denilen olay nasıl işliyor? Benim sorunum nedir?

bocek

şunu:
  HAL_ADC_Start_DMA(&AdcHandle, (uint32_t*)&uhADCxConvertedValue[0], 3)

şöyle yapsan?:
  HAL_ADC_Start_DMA(&AdcHandle, (uint32_t*)uhADCxConvertedValue, 3)


1 ya da 0. işte 'bit'ün mesele..

Mucit23

Hocam kartı ofiste bıraktım Sabah Deneyeyim ama farkedermiki? 0. elemanın adresini göndermişim ben orada.

PROTECH_

Stm32 hal kutuphanesi tam bi fiyasko.
Std library bundan kat kat iyi.
Adam akilli bi dokumantasyon yok .
Multi-Core ,RTX,ThreadX, FreeRTOS, MODBUS  RTOS - Electronic-Hardware -- BERLIN

Mucit23


bocek

sorun şurada olabilir mi?
uhADCxConvertedValue 16-bitlik bir değişken.
ama
HAL_ADC_Start_DMA(&AdcHandle, (uint32_t*)&uhADCxConvertedValue[0], 3)

burada 32-bite çevrilip işlem yapılıyor.
yani ilk iki 16-bit birleştirilip tek değişken olarak yazılıyor sanki?
HAL_ADC_Start_DMA(&AdcHandle, (uint32_t*)&uhADCxConvertedValue[0], 6)

yapsan olur mu acaba?
şuradaki arkadaş ta ayrılacak alanı 2 ile çarpmış ve bir soru üzerine neden böyle yaptığını da açıklamış.
http://tunizem.blogspot.com.tr/2014/09/using-adc-with-dma-on-stm32.html
1 ya da 0. işte 'bit'ün mesele..

Mucit23

@Böcek dediğin mantıklı gerçekten. Verinin boyutu 32 bit yapılıyor.
DMA ayarlarında veri boyutu 32 bit olarak ayarlıydı.

  hdma_adc.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
  hdma_adc.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;

Veri boyutunu HALFWORD olarak değiştirdim.

Öyle olunca 2. byte 0 oluyor normal olarak. Haliyle 16 bitlik değerin yüksek 16 biti daima sıfır olduğundan ben ekranda onu görüyorum.

Bu konuyu iyice bir araştırayım. Muhtemelen sorun budur.

bocek

1 ya da 0. işte 'bit'ün mesele..

Mucit23

Evet Tablo 7'yi az önce inceledim.

Bu tabloya dikkat etmek gerek. Öğrenmiş olduk.

Eğer Değişken boyutu 16 bit ise Lenght kısmı dizi boyutunun 2 katı olmalı.

Dediğiniz gibi ADC ayarlarını değiştirdim. Şuan çok şükür çalıştı  :) Yalnız bir sıkıntı var.

ADC kanalları birbirinden etkileniyor nedense. Sebebini anlayamadım ama çözmem lazım.

Şöyle anlatayım.
1 Tane potansiyometrem ve 3 adet analog girişim var
Analog Girişler CH6, CH7 ve CH8 (GPIOlardan PF8, PF9 ve PF10)

Potu CH6 Ya bağlıyorum. CH7 ve CH8 boşta yani float konumunda. CH6 dan potun değerini okuyorum sıkıntı yok. Ama CH7 bundan etkileniyor. Potun değerini arttırırsam CH7'ninde değeri birazcık artıyor. CH7 boştayken 2500 civarı flaot bir değer veriyor.

Sonra Potu CH7'ye bağlıyorum. CH7'den normal olarak Potun değeri okunuyor ama bu seferde CH8 etkileniyor CH7 den. CH7 değeri arttırıldığı zaman CH8 de biraz artıyor. Aynı şekilde Potu CH8'e bağlıyorum yine CH8'den normal olarak veri alıyorum ama CH7 etkileniyor.

Tek sorun bu şuanda. Bu etkilenme sorunu neden olur fikriniz var mı?

bocek

Şundan olabilir:
ADC_SAMPLETIME_3CYCLES
Daha büyük bir 'sampletime' seçip deneyebilirsin.
1 ya da 0. işte 'bit'ün mesele..

Mucit23

Hocam hepsini denedim. En son ADC_SAMPLETIME_480CYCLES yaptım ama düzelmedi.

Şöyle bir durum var.
ADC tetikleme hızını 10Hz gibi düşük bir değer yapıyorum. ADC yavaş çalışıyorken Bu etkilenme çok az oluyor Fakat tetikleme hızını arttırırsam eğer etkilenme daha fazla oluyor. Bütün kanallar etkileniyor. Mesela potu CH7'ye bağlıyorum. CH7 4095 gösteriyorken CH8, 3000 küsürlere kadar çıkıyor. CH6 da 2000 lere kadar çıkıyor.

Timerden her tetikleme sinyali geldiğinde ADC girişindeki MUX kanal değiştiriyor bir sonraki kanal için ölçüm yapıyor. Bu sırada nasıl bir durum oluşsunki diğer kanallar birbirini etkilesin? Fikri olan var mı?

İsterseniz problem ile ilgili video çekebilirim.

bocek

Şuradaki kişi de aynı problemden muzdarip olmuş ve sample time'ı arttırarak çözmüş ama sende işe yaramadı.
Kodlarını bir incele istersen.
Şöyle bir satır gözüme çarpıyor:
ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
1 ya da 0. işte 'bit'ün mesele..

Mucit23

Bana kalırsa iki örnek arası biraz beklenmesi gerekiyor.  Sürekli kanal drgistirince kanallar bibirinden etkileniyor olsa gerek.

Daha önce asm ve pic 16f877 de başıma geldiğini  hatırlıyorum.  Kanal değiştirmeden önce bekleme yapıyordum. örnekleme süresi uzatilsada  iki ornek arasi gecikme olmadığından problem devam ediyor.  En azından adc çalışma hızı artınca bu problemin daha fazla kendini gostermesini bu şekilde yorumluyorum.  Tabi stm 32 lerdeki adc yapısını tam bilmiyorum bende farklı bir durumda olabilir.  An itibariyle sorunu nasıl halledecegimi bilmiyorum.  Bahsettiğiniz kod iki örnek arası gecikme koyuyorsa eğer sorunu çözebilir. Ama bunun HAL kütüphanesindeki karşılığına bakmam lazım