STM32F1'de DMA ile Paralel veri Aktarımı

Mucit23

Üye
Katılım
7 Ekim 2022
Mesajlar
53
Selamlar.

STM32F103VET6'da DMA ile paralel veri aktarımı üzerine çalışıyorum. Amacım Clock eşliğinde 8 bit paralel data çıkışı sağlamak. Yüksek frekanslı paralel data çıkışına ihtiyacım var. Bunu arka planda otomatik olarak yapmak istediğim için DMA ile nasıl yaparım arayışına girdim.

ST'nin X-ParaCom şeklinde bir firmware örneği var o örnekten yola çıkarak bir şeyler yapmaya çalışıyorum.

Temel mantık şu. Paralel veriyi bir clock sinyali eşliğinde gönderiyoruz. Clock üretmek için bir timer ile PWM üretiyorsun. PWM çıkış sinyalin senin clock sinyali oluyor. Daha sonra TIM CC1 tetik kaynağını DMA1 kanal 5'i tetikleyecek şekilde ayarlıyoruz. TIM2 CH1, DMA1 Kanal 5 ile çalışıyor. Tim2'de her PWM puls darbesinde DMA tetikleniyor ve Veri aktarımını yapıyor. DMA Transfer Complete kesmesinde timeri durduruyoruz ve puls üretimi sonlanıyor..

Bu dediklerim çalışıyor gibi fakat veri aktarımı sağlanmıyor. Çıkamadım işin içinden.


Ayarlarım bu şekilde
Kod:
/* USER CODE BEGIN 4 */
void HAL_TIM_DMA_Init(void)
{
  TIM_OC_InitTypeDef sConfigOC = {0};
    GPIO_InitTypeDef   GPIO_InitStruct;
  static DMA_HandleTypeDef  hdma_tim;
   
    __HAL_RCC_TIM2_CLK_ENABLE();
    __HAL_RCC_GPIOA_CLK_ENABLE();
    __HAL_RCC_DMA1_CLK_ENABLE();
   
    htim2.Instance = TIM2;
  htim2.Init.Prescaler = 72-1;
  htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim2.Init.Period = 1000-1;
  htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if(HAL_TIM_PWM_Init(&htim2) != HAL_OK)
  {
    Error_Handler();
  }
   
    sConfigOC.OCMode = TIM_OCMODE_PWM1;
  sConfigOC.Pulse = 500;
  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
  if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
  {
    Error_Handler();
  }
   
    /**TIM2 GPIO Configuration
    PA0-WKUP     ------> TIM2_CH1    */
    GPIO_InitStruct.Pin = GPIO_PIN_0;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
   
    /* TIM2 DMA Init */
    /* TIM2_CH1 Init */  
  hdma_tim2_ch1.Instance = DMA1_Channel5;
    hdma_tim2_ch1.Init.Direction = DMA_MEMORY_TO_PERIPH;
    hdma_tim2_ch1.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_tim2_ch1.Init.MemInc = DMA_MINC_ENABLE;
    hdma_tim2_ch1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
    hdma_tim2_ch1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
    hdma_tim2_ch1.Init.Mode = DMA_NORMAL;
    hdma_tim2_ch1.Init.Priority = DMA_PRIORITY_LOW;
    if (HAL_DMA_Init(&hdma_tim2_ch1) != HAL_OK)
    {
        Error_Handler();
    }

    __HAL_LINKDMA(&htim2,hdma[TIM_DMA_ID_CC1],hdma_tim2_ch1);
   
    htim2.hdma[TIM_DMA_ID_CC1]->XferCpltCallback = DMA_Transfer_Complete;
  htim2.hdma[TIM_DMA_ID_CC1]->XferErrorCallback = DMA_Transfer_Error;
   
  if (HAL_DMA_Start_IT(htim2.hdma[TIM_DMA_ID_CC1], (uint32_t)&buffer, (uint32_t)&GPIOE->ODR, 100) != HAL_OK)
  {
    /* Transfer Error */
    Error_Handler();
  }
   
  __HAL_DMA_DISABLE_IT(htim2.hdma[TIM_DMA_ID_CC1], DMA_IT_HT);

  __HAL_TIM_ENABLE_DMA(&htim2, TIM_DMA_CC1);
   
      /* Configure the NVIC for DMA                             */
  /* NVIC configuration for DMA transfer complete interrupt */
  HAL_NVIC_SetPriority(DMA1_Channel5_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn);
   
}

Ayarlarım bu şekilde. Bu arada transfer tamamlandığında DMA Transfer Completed kesmesi oluşuyor. Clock sinyali uygun olmasına rağmen data aktarımı hiç sağlanmıyor. Referans manual içinde kayboldum.
Acaba mimaride mi sıkıntı var. Referans manual'de APB2 üzerinden GPIOE'ye yazma yapılabildiğini göstermiş.

görsel_2025-12-28_223552257.png


Bunu F1 serisi desteklemiyor mu anlamadım. ST vermiş olduğu örnekte STM32L476 ile yapmış. Ben F1 de yapmaya çalışıyorum. DMA ile GPIOE'nin (Yada başka bir GPIO) ODR sine nasıl veri yazarım? Şuan için tetik kaynağı önemli değil. DMA ile doğrudan GPIO'ya veri aktarmak mümkün mü?
 
Son düzenleme:
Cubemx ve hal kullanarak bu tür şeyler çalıştırmak çok zor olabiliyor. Hal ı ne kadar temizleselerde hala buglar var(en basitinden yakın zamanda i2c de alternate pin e geçirdim bir türlü çalışmıyordu meğer cubemx alternate ile generate ederken pinleri doğru ayarlamıyormuş), referans manuel de bu işin yapılması tarif edildiyse register üzerinden kendin konfigre edip denersen başarı şansın bence artar. Yalnız ben soruda şunu anlamadım veri aktarımı tamamlanmıtor ne demek? Çıkış mı yok?

Dma ile gpio ya veri aktarma sorusunun cevabı ise evet, hatta gpio değil neredeyse her peripheral için aktarım mümkün
 
Cubemx platformuna çok alıştım aslında fakat kodu iyice anlayabilmek adına herşeyi tek bir init fonksiyonunda yapmaya çalıştım. Dediğiniz gibi veri yazma adresinde bir kısıt yok gibi. Hata çok anlamsız. İşin ilginci DMA çalışıyor gibi. Transferi yapıyor gibi. Transfer tamamlandığında TC kesmesi de oluşuyor. Fakat çıkışta bir değişim göremiyorum. Buffer içeriği 0xAAAA ve farklı değerler denedim.

Ne önerirsiniz? Adım adım register seviyesinde kodlama mı yapmak gerekir? Yardımcı olabilirmisiniz?
 
St nin forumunu kazmak lazım, bir ihtimal çalışan bir kod çıkar oradan. Anladığım kadarıyla kod içerisinde çalışıyor gibi görüyorsun ama pinlerde fiziksel olarak değişimi gözlemleyemiyorsun, clock var ama değil mi? O gpio pinlerini output olarak ayarladın mı?
 
Tabi hocam yaptım. Cubemx tarafında projeyi oluştururken yapmıştım. Otomatik oluşturulan fonksiyon içinde ayarlı. Ama onuda genel ayar fonksiyonuna ekledim emin olmak için. DMA bir yere transfer yapıyor gibi ama bu yapmış olduğu transfer gerçekte işe yaramıyor.

Bunu debug ile çözebilirmiyim ona bakıyorum.
 
Galiba çözdüm. Kodun başka bir yerinde yapmış olduğum ayarları bozan başka bir kod parçası vardı. Ondan dolayı hata yapmışım. Çalışıyor gibi fakat biraz daha uğraşmam lazım. Bu gelişme sevindirdi beni.

100 Adet veri transferi yapan bir kod yazdım.
Kod:
    for (int i = 0; i < 100; i++)
    {
            buffer[i] = i+1;
    }
    
  if (HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1) != HAL_OK)
  {
    /* PWM Generation Error */
    Error_Handler();
  }
Lojik analizör ile GPIOE çıkışlarını ve PA0 clock çıkışını inceliyorum. Lojik analizör D0 clock pinine bağlı. D1-D7 ise PE0,PE6 arasına bağlı. Aldığım çıktı bu şekilde.

1766957943895.png


Fakat burada Clock Polaritesi ile ilgili bir problem var. Clock ile sinyali düşen kenarı yaşadığı anda DMA tetikleniyor. Aldığım sinyale yaklaşınca görebiliyorum. Yani Clock sinyalinde her düşen kenar olduğunda GPIO çıkışı 125ns sonra güncellenmiş.

PWM modunu değiştirmeyi deneyeceğim. Yada DMA tetik kaynağını TIM_Update olarak ayarlayıp yine PWM modun da clock üretmeyi deneyeceğim.
 
  • Beğen
Reactions: clc
Şöye bir şey buldum, burayı sana uyarlamak mümkün mü sence?


Debug da ODR de bir değişiklik görüyor musun?
 
@clc Hocam aslında aynı işlemler yapılmış. Chat GPT ye de soruyorum oda zaten bana Timer + DMA + GPIO konusunda çalışmamı söyledi. Buna girişmeden FSMC donanımını denedim ama orada adres data vs işler daha karışıyor.

Her neyse

Bu dediğim clock polaritesi ile ilgili sorunun sebebi şu. Normalde DMA ayarlarımızı felan yaptık dedikki DMA'ya sen Tim2 CH1 Capture Compare tetik kaynağından tetikelenceksin. Her tetik geldiğinde bir tane transfer yap diyoruz. Transfer bittiğinde kesme oluştur ve kesme içerisinde boş yere clock üretilmesin diye Timeri aniden durduruyoruz.

Ayarlarımızı yaptıktan sonra Timeri çalıştırdığımızda timerin ilk counter değeri 0.

Timer PWM1 modun da çalışıyor ki PWM1 modunda CNT<CCR1 iken Çıkış 1 olur. Dolayısıyla timer çalışır çalışmaz Çıkış 1 oluyor, daha sonra CNT>=CCR olduğu anda çıkış 0 oluyor ve Tim2_CC1_Ref kaynağından DMA tetikleniyor bir adet transfer yapmış oluyor. Fakat bu durumda ilk başta 1 adet clock sinyali vermiş oluyorum ki bu benim slave aygıtımın boş bir veri almasına neden olur.

Ben timeri başlatmadan software olarak öncesinde DMA'ya bir tetik verip önden bir adet veriyi çıkışa göndersem sorun olmayacak gibi. Bunu nasıl yaparım? Lojik analizör çıkışındaki verileri incelediğimde bu kanıya vardım. Bu mümkün mü?
 

Forum istatistikleri

Konular
8,725
Mesajlar
142,364
Üyeler
3,486
Son üye
tolgaerd

Son kaynaklar

Son profil mesajları

Abdullah karaoglan falcon_browning Abdullah karaoglan wrote on falcon_browning's profile.
selamın aleyküm ses sistemindeki cızırtıyı hallettınızmi
"Araştırma, ne yaptığını bilmediğinde yaptığın şeydir." - Wernher von Braun
“Kendi yolunu çizen kişi, kimsenin izinden gitmez.” – Nietzsche
Kim İslâm’da güzel bir çığır açarsa (güzel bir alışkanlık başlatırsa), onun sevabı ve kendisinden sonra ona uyanların sevapları, onların sevaplarından hiçbir şey eksilmeksizin ona da yazılır.
erdemtr55 taydin erdemtr55 wrote on taydin's profile.
Merhaba Taydin bey,
Gruba spms serisi yapıcak mısınız?
ben 3 sargılı toroid ile 2 adet flyback sürücek bir devre yapmayı düşünüyorum.size soracak sorularım vardı?
Back
Top