STM32F1'de DMA ile Paralel veri Aktarımı

Mucit23

Üye
Katılım
7 Ekim 2022
Mesajlar
61
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ü?
 
Timer in countu up dan down a çekseniz de çözülebilir gibi geldi bana
 
Hocam birçok olasılığı denedim ama olmadı. Tim Counter UP mode, Down Mode, PWM Mode 1 PWM Mode 2 vs hepsinde aynı problem var. PWM'i başlatmadan önce DMA'yı software olarak tetikleyip bir adet transfer yaptırmam lazım.
 
TIM2->EGR |= TIM_EGR_CC1G;

Yukarıdaki satır ile DMA'ya software tetik verebildim. Bu şekilde oldu gibi. Artık clock polaritesi uyuyor. Fakat Biraz daha iyileştirebilirmiyim diye uğraşıyorum.

DMA'yı TIM_DMA_ID_CC1 kanalı ile tetikliyorum. Bu sinyal kanyağı DMA kanal5 ile kullanılabiliyor. Ben Timer Update ile DMAyı tetiklersem counter her sıfırlandığında dma tetiklenir diye düşündüm. Ama Tim Update Kaynağı ancak DMA kanal2 ile tetikleniyor. Ayarlarımı aşağıdaki gibi yaptım.
Kod:
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();
    __HAL_RCC_GPIOE_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_PWM2;
  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();
  }
   
  GPIO_InitStruct.Pin = GPIO_PIN_All;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_MEDIUM;
  HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
   
    /**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_Channel2;
    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_VERY_HIGH;
    if (HAL_DMA_Init(&hdma_tim2_ch1) != HAL_OK)
    {
        Error_Handler();
    }

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

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

void DMA_Transfer_Complete(DMA_HandleTypeDef *DmaHandle)
{
   HAL_GPIO_WritePin(GPIOD,GPIO_PIN_9,GPIO_PIN_RESET);
}

void DMA_Transfer_Error(DMA_HandleTypeDef *DmaHandle)
{

}


void DMA1_Channel2_IRQHandler(void)
{
  /* stop clock generation immediately  */
  TIM2->CCMR1 = 0x00000000;

  HAL_DMA_IRQHandler(htim2.hdma[TIM_DMA_ID_UPDATE]);
  /* USER CODE END DMA1_Channel5_IRQn 1 */
}

Başlatma kodum da aynı. DMA hiç bir transfer yapmıyor. Yorum yapabilecek olan var mı?

PWM çalışıyor ama DMA hiç bir transfer yapmıyor. Yine Basit bir hata yapmış olabilirim.
 
Şimdi anladım olayı. Benzer bir şeyi ben timer ile yaşıyorum, timer ı başlattığın anda kesme oluşuyor. Ben bunu timer için çözmek için timeri başlatmadan hemen önce şunu koyuyorum.

C:
__HAL_TIM_CLEAR_IT(&htim16,TIM_IT_UPDATE);

Dma yı manuel olarak tetiklemek sanırım mümkün değil, ama dma yı tetikleyen eventi manuel olarak oluşturabilirsin. Büyük ihtimalle onun için bir hal kodu yoktur, TIMx->EGR üzerinde dma yı tetikleyen eventi soft olarak oluşturursan bence istediğin olur.

Edit:Tam ben yazarken çözmüşsün sanırım.
 
@clc Şuan amacın veri transferini Tim update eventi ile yapmak. Clock pulse ise tim arr/2 de olacağından dolayı clock pulse tam ortada olur. Bunu yapmaya çalışıyorum ama yapamadım. Yukarıdaki ayarlarını bi incelemeniz mümkünmü
 
STM32F103'de DMA'yı TIM_UPDATE olayı ile nasıl tetiklerim? Kafamda bir proje var onu yapmaya çalışıyorum fakat bunun için paralel veri aktarım işini tam anlamıyla oturtmam gerekiyor.

DMA'yı önceki mesajlarımda TIM2_CH1_CC olayı ile tetikleyerek istediğim boyutta veriyi GPIO'ya aktardım. Fakat amacım update olayı ile daha düzgün bir çıkış elde etmek. Bunu başaramadım
Kod:
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();
    __HAL_RCC_GPIOE_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_PWM2;
  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();
  }
    
  GPIO_InitStruct.Pin = GPIO_PIN_All;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_MEDIUM;
  HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
    
    /**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_tim.Instance = DMA1_Channel2;
    hdma_tim.Init.Direction = DMA_MEMORY_TO_PERIPH;
    hdma_tim.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_tim.Init.MemInc = DMA_MINC_ENABLE;
    hdma_tim.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
    hdma_tim.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
    hdma_tim.Init.Mode = DMA_NORMAL;
    hdma_tim.Init.Priority = DMA_PRIORITY_VERY_HIGH;
    if (HAL_DMA_Init(&hdma_tim) != HAL_OK)
    {
        Error_Handler();
    }
    __HAL_LINKDMA(&htim2,hdma[TIM_DMA_ID_UPDATE],hdma_tim);
    
    htim2.hdma[TIM_DMA_ID_UPDATE]->XferCpltCallback = DMA_Transfer_Complete;
  htim2.hdma[TIM_DMA_ID_UPDATE]->XferErrorCallback = DMA_Transfer_Error;
    
  if (HAL_DMA_Start_IT(htim2.hdma[TIM_DMA_ID_UPDATE], (uint32_t)&buffer, (uint32_t)&GPIOE->ODR, 100) != HAL_OK)
  {
    /* Transfer Error */
    Error_Handler();
  }
    
  __HAL_DMA_DISABLE_IT(htim2.hdma[TIM_DMA_ID_UPDATE], DMA_IT_HT);

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

Ayarlarım bu şekilde.

Request MAP'e bakıyorum. Tim2_UP olayı DMA1 Channel 2 ile kullanılabiliyor.
1767131426307.png


Bu ayarlarda hata görebilen var mı? Aslında tek yaptığım TIM_DMA_ID_CC1 yerine TIM_DMA_ID_UPDATE olarak değiştiriyorum. Tabi DMA Kanal 2 için diğer yönlendirmeleri de yapıyorum.
 
Sonunda bu işi hallettim. HAL kütüphane ile yapamadım. Anlamsız problemlerle uğraşıp durdum. Bende mecburen Register seviyesinde kodlama yaparak işi çözmeye çalıştım. Chat GPT bu konuda işlerimi inanılmaz derece kolaylaştırdı. Gerçekten en büyük yardımcım olmuş durumda. Yoksa referans manuel içinde kaybolup gidecektim.

DMA1 Kanal3'e geçtim. Burada TIM3 Update kanalı ile DMAyı tetikledim. Aynı zamanda TIM3 CH4 ile PWM2 modunda PWM oluşturdum. Şuanda Arka planda gerçekleşen olay şu.
Timeri ve DMA ayarlarını yaptıktan sonra Timeri başlatmadan önce DMA'ya önden bir tetik veriyorum. DMA ilk transferi yapıyor ve ardından hemen Timeri başlatıyorum. Timer PWM2 modunda çalışırken ARR/2 de clock oluşturuyor. Dolayısıyla 2 veri transferinin tam ortasında Clock üretilmiş oluyor. Daha sonra Timer ARR ye ulaştığında Update oluşuyor ve DMA sonraki Transferini yapıyor. DMA bütün tranferlerini Tamamladığında TC kesmesi oluşuyor ve hemen kesme içerisinde Timeri ve PWM'i durduruyorum. Döngü bu şekilde.

En son testlerimde aşağıdaki gibi sonuçlara ulaştım tam istediğim gibi. Logic analizörüm 8 girişli olduğundan dolayı anca 8 kanal görüntüleyebildim.

res1.png

Burada da daha yakınlaşarak göstermeye çalıştım.
Res2.png



Çıkışa aktarmış olduğum veriler 1 den 100'e kadar sayıların olduğu bir diziden ibaret. Bu diziyi çıkışa aktarıyorum. Şuanda 350khz lere kadar çıktım. Amacım P2.5 RGB led panellere bit banding yaparak Renk oluşturmak. 18 yada 24 bit renk derinliği deneyeceğim. Bu yüzden yüksek hızlı transfer yapmam şart. Bunun alt yapısını oluşturuyorum .


Ayar kodlarım bu şekilde buraya ekleyelim belki birinin işine yarar.
Kod:
void HAL_TIM_DMA_Init(void)
{

    /*Timer Ayarlari*/
    RCC->APB1ENR |= RCC_APB1ENR_TIM3EN;   // TIM3 clock enable
    TIM3->PSC   = 2-1;       // Prescaler
    TIM3->ARR   = 100-1;     // Period
    TIM3->CCR4  = 50;        // Duty cycle

    TIM3->CCMR2 &= ~TIM_CCMR2_OC4M;
    TIM3->CCMR2 |= (7 << TIM_CCMR2_OC4M_Pos); // PWM Mode 2
    TIM3->CCMR2 |= TIM_CCMR2_OC4PE;           // Preload Aktif

    TIM3->CCER  |= TIM_CCER_CC4E;             // Enable CH4
    TIM3->CR1   |= TIM_CR1_ARPE;              // ARR preload enable

    // Update DMA request enable
    TIM3->DIER |= TIM_DIER_UDE;
   
    // GPIOB PB1: TIM3_CH4
    RCC->APB2ENR |= RCC_APB2ENR_IOPBEN;   // GPIOB clock enable
       
    GPIOB->CRL &= ~(GPIO_CRL_MODE1 | GPIO_CRL_CNF1);
    GPIOB->CRL |= (0x02 << GPIO_CRL_MODE1_Pos) | (0x02 << GPIO_CRL_CNF1_Pos);
    // MODE1=10 (Output 2MHz), CNF1=10 (AF Push-Pull)
   
    RCC->AHBENR |= RCC_AHBENR_DMA1EN;   // DMA1 clock enable
 
    /*DMA Ayarlari*/
    DMA1_Channel3->CCR = 0; // reset
    DMA1_Channel3->CCR |= DMA_CCR_DIR        // Mem->Periph
                                         | DMA_CCR_MINC        // Mem increment
                                         | DMA_CCR_MSIZE_0     // Mem size = 16-bit
                                         | DMA_CCR_PSIZE_0     // Periph size = 16-bit
                                         | DMA_CCR_PL_1;       // Priority high

    DMA1_Channel3->CNDTR = 100;               // transfer length
    DMA1_Channel3->CPAR  = (uint32_t)&GPIOE->ODR; // destination
    DMA1_Channel3->CMAR  = (uint32_t)buffer;      // source

    DMA1_Channel3->CCR |= DMA_CCR_TCIE;      // Transfer complete interrupt enable
    DMA1_Channel3->CCR |= DMA_CCR_EN;        // Channel enable
   
        // GPIOE: tüm pinler output
    RCC->APB2ENR |= RCC_APB2ENR_IOPEEN;
    GPIOE->CRL = 0x22222222;  // Output push-pull, 2MHz
    GPIOE->CRH = 0x22222222;

    // NVIC enable
    NVIC_EnableIRQ(DMA1_Channel3_IRQn);

}

DMA Kesme içeriği;

Kod:
void DMA1_Channel3_IRQHandler(void)
{
    if (DMA1->ISR & DMA_ISR_TCIF3) {
        DMA1->IFCR |= DMA_IFCR_CTCIF3; // clear flag
              TIM3->CR1 &= ~TIM_CR1_CEN;              // Timer stop
                TIM3->CCER &= ~TIM_CCER_CC4E;           // CH4 output disable

              TIM3->CCMR1 = 0x00000000;
    }
}
Transferi başlatmak için


Kod:
  HAL_TIM_DMA_Init();
    TIM3->EGR |= TIM_EGR_UG;
        // Counter enable
    TIM3->CR1 |= TIM_CR1_CEN;
 

Forum istatistikleri

Konular
8,768
Mesajlar
142,888
Üyeler
3,512
Son üye
marsi

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