STM32F7 Donanım ayarları

Başlatan Mucit23, 29 Aralık 2015, 01:18:57

Mucit23

STM32F7 Disco ile uğraşıyorum. Kendim bir proje dosyası oluşturdum keilde. ADC, DMA vs gibi donanımlar üzerinde uğraşarak HAL kütüphanesini anlamaya çalışıyorum. Yalnız STD Periph kütüphanesinden biraz farklı. İncelediğim örnekler hep CubeMX ile oluşturulmuş. Ben cubeMX ile uğraşmadan donanım ayarlarını yazılım ile yapayım istiyorum. Yanlış bir tercihmi anlayamadım. Çünkü örnekleri inceliyorum sistemin yapısını henüz çözemedim. Hangi ayar nerde yapılır? nasıl yapılır? vs vs. İlk etapta çok karışık geldi.

Tek yapabildiğim LCD, Onunla bir sıkıntım yok. Fonksiyonlar F4 için yazılmış STD Periph kütüphanesine çok benziyor.

CubeMX ile anlaşamadığım nokta şu. Belkide özelliği vardır pek kurcalamadım. Ben Sadece ADC ile ilgili ayarları Cube MX yardımıyla yapıp oluşan kod çıktısını kendi projeme eklemek istiyorum. CubeMX de anladığım kadarıyla sıfırıdan bütün proje oluşturuluyor.

Nedir bu işin yolu? STM32F7 ile kimler uğraşıyor forumda?

Gökhan BEKEN

Hangi donanımı kullanmak istiyorsan onun header (.h uzantılı) dosyasını aç, en başında hangi fonksiyonun ne işe yaradığını anlatıyor.
Gerekirse cubemx'de seçtiğin ayarları da bu fonksiyonlardan değiştirebilirsin.
Özel mesaj okumuyorum, lütfen göndermeyin.

Mucit23

Selamlar,

Hocam dün gece ADC'yi çalıştırmak için uğraştım.

Yaptıklarımı sırayla söyliyeyim, Hatam varsa düzeltin
İlk olarak main.c dosyamda ADC_Config diye bir fonksiyon oluşturdum. Bütün adc ayarlarını bu fonksiyon içerisinde yapmaya çalıştım.
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.ScanConvMode          = DISABLE;                       /* Sequencer disabled (ADC conversion on only 1 channel: channel set on rank 1) */
  AdcHandle.Init.ContinuousConvMode    = ENABLE;                        /* 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_NONE;        /* Conversion start trigged at each external event */
  AdcHandle.Init.ExternalTrigConv      = ADC_EXTERNALTRIGCONV_T1_CC1;
  AdcHandle.Init.DataAlign             = ADC_DATAALIGN_RIGHT;
  AdcHandle.Init.NbrOfConversion       = 1;
  AdcHandle.Init.DMAContinuousRequests = ENABLE;
  AdcHandle.Init.EOCSelection          = DISABLE;
	
  if (HAL_ADC_Init(&AdcHandle) != HAL_OK)
  {
    /* ADC initialization Error */
    Error_Handler();
  }

  /*##-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 */
    Error_Handler();
  }


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

}


Bu fonksiyonda ADC Prescaller, Çözünürlük vs gibi ayarlar yapılıyor. Bu kodlar içerisinde if şartı ile HAL_ADC_Init(&AdcHandle) fonksiyonuna gidiyorum. Hazır örnekten takip ettim.

stm32f7xx_hal_adc.c dosyasında aşağıdaki fonksiyona geliyor.
HAL_StatusTypeDef HAL_ADC_Init(ADC_HandleTypeDef* hadc)
{
  /* Check ADC handle */
  if(hadc == NULL)
  {
     return HAL_ERROR;
  }
  
  /* Check the parameters */
  assert_param(IS_ADC_ALL_INSTANCE(hadc->Instance));
  assert_param(IS_ADC_CLOCKPRESCALER(hadc->Init.ClockPrescaler));
  assert_param(IS_ADC_RESOLUTION(hadc->Init.Resolution));
  assert_param(IS_FUNCTIONAL_STATE(hadc->Init.ScanConvMode));
  assert_param(IS_FUNCTIONAL_STATE(hadc->Init.ContinuousConvMode));
  assert_param(IS_ADC_EXT_TRIG(hadc->Init.ExternalTrigConv));
  assert_param(IS_ADC_DATA_ALIGN(hadc->Init.DataAlign));
  assert_param(IS_ADC_REGULAR_LENGTH(hadc->Init.NbrOfConversion));
  assert_param(IS_FUNCTIONAL_STATE(hadc->Init.DMAContinuousRequests));
  assert_param(IS_ADC_EOCSelection(hadc->Init.EOCSelection));
  assert_param(IS_FUNCTIONAL_STATE(hadc->Init.DiscontinuousConvMode));

  if(hadc->Init.ExternalTrigConv != ADC_SOFTWARE_START)
  {
    assert_param(IS_ADC_EXT_TRIG_EDGE(hadc->Init.ExternalTrigConvEdge));
  }

  if(hadc->State == HAL_ADC_STATE_RESET)
  {
    /* Allocate lock resource and initialize it */
    hadc->Lock = HAL_UNLOCKED;
    /* Init the low level hardware */
    HAL_ADC_MspInit(hadc);
  }

  /* Initialize the ADC state */
  hadc->State = HAL_ADC_STATE_BUSY;
  
  /* Set ADC parameters */
  ADC_Init(hadc);
  
  /* Set ADC error code to none */
  hadc->ErrorCode = HAL_ADC_ERROR_NONE;
  
  /* Initialize the ADC state */
  hadc->State = HAL_ADC_STATE_READY;

  /* Release Lock */
  __HAL_UNLOCK(hadc);

  /* Return function status */
  return HAL_OK;
}


Burada bir takım ayarlamalar yapılır vs vs. Low level Donanım ayarları için ise HAL_ADC_MspInit fonksiyonuna gitmek gerekiyor anladığım kadarıyla. Bu fonksiyonda DMA clock ayarları pin konfigürasyonları RCC clock ayarları vs gibi ayarlamalar yapılması lazım.

Bunun için stm32f7xx_hal_msp.c dosyasına aşağıdaki fonksiyonu kendim ekledim.
void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc)
{
  GPIO_InitTypeDef          GPIO_InitStruct;
  static DMA_HandleTypeDef  hdma_adc;

  /*##-1- Enable peripherals and GPIO Clocks #################################*/
  /* ADC3 Periph clock enable */
  ADCx_CLK_ENABLE();
  /* Enable GPIO clock ****************************************/
  ADCx_CHANNEL_GPIO_CLK_ENABLE();
  /* Enable DMA2 clock */
  DMAx_CLK_ENABLE();

  /*##-2- Configure peripheral GPIO ##########################################*/
  /* ADC Channel GPIO pin configuration */
  GPIO_InitStruct.Pin = ADCx_CHANNEL_PIN;
  GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(ADCx_CHANNEL_GPIO_PORT, &GPIO_InitStruct);

  /*##-3- Configure the DMA streams ##########################################*/
  /* Set the parameters to be configured */
  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);

  /* Associate the initialized DMA handle to the ADC handle */
  __HAL_LINKDMA(hadc, DMA_Handle, hdma_adc);

  /*##-4- Configure the NVIC for DMA #########################################*/
  /* NVIC configuration for DMA transfer complete interrupt */
  HAL_NVIC_SetPriority(ADCx_DMA_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(ADCx_DMA_IRQn);
}


Normalde bu işlemler cubemx ile otomatik ayarlanması lazım. Bende STM32F7_Cube kütüphanesindeki ADC örneğine bakarak yapamaya çalışıyorum. Ben manuel olarak yapayım dedim ama işin içinden çıkamadım açıkçası.

STM32F7 de ADC'yi çalıştıran oldumu?

CoşkuN

Donanım ayarlarını anlamaksa amaç önce reference manual dökümanlarında o donanıma ait bölümleri okuyup sonra koda bakmak daha faydalı olur diye düşünüyorum.

Mucit23

Yok hocam o kadar alt seviyeye inmeye gerek yok :) STM32F746'nın Teknik dökümanı 1600 küsür sayfa.  :o :o :o Nokta atışı yapmadıktan sonra şu ne işe yarıyor, bu registerin amacı ne gibi sorularla işlemciyi anlamaya ömür yetmez.

Ben şunu anlamak istiyorum. CubeMX olsada olmasada HAL kütüphaneyi kullanmaya mecburuz. Örneğin CubeMX'den bağımsız bir kendimiz Keil ile bir proje oluşturduk. Bütün donanım kütüphanelerini vs ekledik. Projemiz derlenip çalışır halde

Şuanda bu pozisyondayım.

Amacım ADC'den DMA ile sürekli veri almak DMA TC interruptu aktif etmek vs. Bunların hepsini tek bir fonksiyonda ayarlamak istiyorum. STM32F4'de öyle yapıyordum. Bunda ise durum biraz daha karışık. Henüz çözebilmiş değilim

Kart yeni olduğundan örnekte piyasada hiç yok.


Gökhan BEKEN

Hocam hal kütüphanesi ile st standart kütüphanesini birlikte kullanabilirsin fakat biraz uğraştırıyor, çünkü aynı isimde fonksiyonlar çakışıyor tek tek değiştirmek gerekiyor.
Bazen HAL ile nasıl yapıldığını bilmediğim kısımları standart lib ile daha önce öğrenmişsem bu şekilde yapıyorum zaman harcamamak için.
Özel mesaj okumuyorum, lütfen göndermeyin.

Mucit23

Sanırım o daha uğraştırır beni. Ben ADC'nin niye çalışmadığı üzerine bi yoğunlaşayım. Hazır örnekteki ADC uygulamasını. Karta yüklediğimde A1 pinindeki analog değere göre ledi yakıp söndürmesi lazım. Eğer onu çalıştırırsam kendi kodumun neden çalışmadığını daha iyi anlayabilirim.

Mucit23

#7
ADC ayarlarım doğru gibi, HAL_ADC_GetValue() fonksiyonuyla anlık ADCX->DR registerindeki anlık değeri alabiliyorum.

Bence ya DMA çalışmıyor yada ADC-DMA link işlemi düzgün yapılmadı. Başka bir sebep göremedim ben.

Edit; DMA Kesmeside çalışıyor. Sorun ne olaki?

Mucit23

Bu sorun bana kafayı yedirtecek.

DMA kesmesi oluşuyor.
Bu fonksiyonla DMA'ya hedef değişkenin adresini gönderiyorum.
  if(HAL_ADC_Start_DMA(&AdcHandle, (uint32_t*)&uhADCxConvertedValue, 1) != HAL_OK)
  {
    /* Start Conversation Error */
    Error_Handler();
  }


DMA'nın çalıştığını DMA kesme rutini içerisinde led yakarak anlıyorum henüz. LED yanıyor dolayısıyla kesme oluşuyor olması lazım.

Başka ne yapmam gerekiyor anlamadımki  :( :(

İşin ilginç tarafı stm32cubef7 ile gelen ADC örneğide çalışmıyor. Elimde bir tane örnek var oda çalışmıyor.  :o :o

Bi akıl verin nasıl çözebilirim bu işi?


Mucit23

Yeminle karttan soğudum.   :'(

stm32cubef7 dosyasının içerisinde STM32F756_eval için yazılmış adc örneği vardı. STM32F7-Disco için yazılan örnekle birebir aynı Aynı yazılımı hiç oynamadan stm32f7 disco ya yükledim çalıştı. uhADCxConvertedValue değişkeninde anlık ADC değerlerini görebiliyordum. Ama STM32F746-Disco için yazılmış ADC örneği çalışmıyor. Halbuki ADC ile ilgili ayarlar gözümden kaçmadıysa eğer bire bir aynı. Arada sorun yaratan fark varsa bile bunu nasıl bulacağımı bilmiyorum.  :(

Mucit23

#10
Selamlar.
Öncelikle herkesin yeni yılını kutlarım. Hepimiz için mutlu başarılı ve bol kazançlı bir yıl olur inşaallah.

Dün sorunu şans eseri buldum gibi. Ama henüz bir çözüm getiremedim.

Daha önce demiştim STM32F7 için yazılmış olan ADC+DMA örneği nedense çalışmıyor. Bende STM32F756-EVAL için yazılmış olan ADC+DMA örneğini hiç ellemeden karta yükledim. İlginçtir ki o yazılımla çalıştı.

Sonra aradaki farkları araştırırken Target Options bölümünde Read/Write Memory Areas adreslerinin farklı olduğunu gördüm. STM32F756 için Default olarak IRAM1 değerinin başlangıç adresi 0x20000000, ve boyutuda 0x50000 verilmiş.
Ben projeyi sıfırdan kendim oluşturduğumdan başlangıç adresi ve boyut değerleri default olarak olması gereken den farklı bir değerdeydi.

Birde Hal Library'de de sıkıntı var sanırım. Çünkü ilk başta HAL library dosyaları salt okunurdu. STM32f756 için yazılmış projeyi keilde incelerken dosyasların salt okunur olmadığını farkettim. Bende o dosyaları projeme ekledim.

Şimdi durum şöyle.

LCD çalışmıyorken ADC+DMA çalışıyor. Ama LCD'yi ne zaman init etsem ADC+DMA eski haline dönüyor. Tek problem bu kaldı.
Tahminimce LCD içerisinde LTDC, DMA2D ve SDRAM üçlüsü DMA'nın birkaç kanalını kullanıyor. Bende hazır örnek kullandığımdan aynı dma kanalları kullanılıyor olabilir tam emin değilim. Anlamak için biraz derinlere inmek gerekiyor.

Mucit23

Sorunu çözebilmiş değilim. LCD ile ADC arasında DMA bağlantısı varmı onu anlamaya çalışıyorum. LCD kullanılırken SDRAM ile birlikte kullanılıyor. LTDC ile SDRAM arasındaki veri Transferi DMA2'nin 0. kanalından stream 0 ile yapılıyor. ADC3 ile Değişkenim arasındaki veri transferi ise yine DMA2'nin 2. kanalının stream 1'i tarafından sağlanıyor.

Başka seçenek yok zaten. Sadece ADC3'ü DMA2'nin 2. kanalının stream 1'i tarafındanda sağlanabiliyor. Başka bir bağlantı bulamıyorum ben.

Sorum şudur. DMA kanalları farklı olmasına rağmen LCD'yi devreye alınca ADC verisini taşıyan dma niye dursun? Varmı bir fikri olan? 3 gecedir LCD ile DMA'yı birlikte çalıştırmak için uğraşıyorum 

yldzelektronik

Muhtemelen sorunun cevabı değil.Lakin yanlış bilmiyorsam busı ilk kapan kullanıyor.Lcd sürekli iş yükü olabileceğinden busı hiç bırakmıyor olabilir mi
Kişinin başına gelen hayır Allah'tandır. Kişinin başına gelen şer nefsindendir. Nefislerimizle kendimize zulüm ediyoruz.

Mucit23

Ama farklı kanallardalar. DMA böyle basit bir konuda çöküyor olamaz bence

DMA olmadan LCD aktif iken HAL_ADC_GetValue(&AdcHandle) fonksiyonu ile ADC verisini okuyup yazabiliyorum ekrana.

Fikir önerisine ihtiyacım var. DMA denen zıkkım neden lcd ile çalışmıyor?

ecunnu

Bildigim kadari ile DMA lar paralel olarak calisamazlar. Kendi aralarinda bir oncelik siralamasi vardir. DMA1 DMA2 den onceliklidir, kanal1 kanal2 den onceliklidir. Senin projende LCD icin kullandigin DMA daha oncelikli oldugu icin ADC kismında hata aliyor olabilirsin.