Picproje Elektronik Sitesi

PICPROJE PROGRAMLAMA DERSLERİ => STM32 Örnekleri => Konuyu başlatan: Klein - 11 Mart 2013, 13:37:23

Başlık: STM32F10X PWM+DMA ile Sinüs oluşturma (Örnek)
Gönderen: Klein - 11 Mart 2013, 13:37:23
Başlık  "Sinüs oluşturma" ancak , sinüs ile sınırlı değiliz. İstediğimiz dalga şeklini oluşturmamız mümkün. HAtta çok karmaşık dalga şekilleri oluşturmak mümkün.

Neden DMA kullanmalıyız?
PWM ile herhangi bir dalga şeklini oluşturmak için , oluşturacağımız dalganın şekline göre ,PWM değerini belirli zamanlarda belirli sırada değiştirmemiz gerek. Bunun için kesmeleri kullanabiliriz. Her PWM kesmesi oluştuğunda kesme rutinine girip  PWM değerini hesaplayabilir veya bir tablodan çekeceğimiz değeri PWM registerine yazabiliriz.
Ancak oluşturacağımız dalganın frekansı ve çözünürlüğü ne kadar yüksekse , PWM frekansımız ve kesmeye girme sıklığımız o kadar yüksek olacaktır.
Örneğin:
1 derece çözünürlükte 360 derecelik 300Hz sinüs oluşturmak için ne sıklıkta kesmeye gireceğimize bakalım.
Bir periyodu tamamlamak için periyot boyunca 360 kez kesmeye gideceğiz. Frekansımız 300Hz  olacağı için bu işlemi saniyede 300 kez tekrarlayacağız.  Bu da saniyede 360*300 = 108000 kez kesme rutinini çalıştıracağız demektir. Buna bir de kesme rutininde yapacağımız işlemleri katarsak, bu iş için ne kadar büyük CPU zamanı kullanacağımız görülecektir.

İşte bu yüzden bu tip işleri DMA'ya bırakmak CPU'yu bize geri kazandıracaktır. PWM modülüne tablomuzun adresini , Hangi PWM kanalı ile çalışacağını bildiriyoruz. Bundan sonrasını DMA hallediyor. Biz hiç bir işe karışmıyoruz.

Örnekteki
void hsi_clock_init(void);
rutini  Dahili osilatörle çalışmak için koyduğum bir rutin. Siz Harici osilatörle çalışıyorsanız bu rutini çağırmanız gerekmiyor.

Örneğimiz 48Mhz Saat hızında çalışıyor.  Timer3'ün 4. PWM kanalından çıkış alıyor.
Sinüs frekansımız 50Hz. Çözünürlüğümüz 360 derece. 
Tabloyu değiştirerek istediğimiz dalga şeklini oluşturmamız mümkün.


#include "stm32f10x.h"
const uint16_t SineTable[] ={
180,183,186,189,192,195,198,201,205,208,211,214,217,220,223,226,229,232,235,238,
241,244,247,250,253,256,258,261,264,267,270,272,275,278,280,283,285,288,290,293,
295,298,300,302,305,307,309,311,313,315,317,319,321,323,325,327,329,330,332,334,
335,337,338,340,341,343,344,345,346,348,349,350,351,352,353,353,354,355,356,356,
357,357,358,358,359,359,359,359,359,359,360,359,359,359,359,359,359,358,358,357,
357,356,356,355,354,353,353,352,351,350,349,348,346,345,344,343,341,340,338,337,
335,334,332,330,329,327,325,323,321,319,317,315,313,311,309,307,305,302,300,298,
295,293,290,288,285,283,280,278,275,272,270,267,264,261,258,256,253,250,247,244,
241,238,235,232,229,226,223,220,217,214,211,208,205,201,198,195,192,189,186,183,
180,176,173,170,167,164,161,158,154,151,148,145,142,139,136,133,130,127,124,121,
118,115,112,109,106,103,101,98,95,92,90,87,84,81,79,76,74,71,69,66,64,61,59,57,
54,52,50,48,46,44,42,40,38,36,34,32,30,29,27,25,24,22,21,19,18,16,15,14,13,11,
10,9,8,7,6,6,5,4,3,3,2,2,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,2,2,3,3,4,5,6,6,7,8,
9,10,11,13,14,15,16,18,19,21,22,24,25,27,29,30,32,34,36,38,40,42,44,46,48,50,52,
54,57,59,61,64,66,69,71,74,76,79,81,84,87,89,92,95,98,101,103,106,109,112,115,
118,121,124,127,130,133,136,139,142,145,148,151,154,158,161,164,167,170,173,176
};

void hsi_clock_init(void)
{
RCC_HSICmd(ENABLE);
RCC_HCLKConfig(RCC_SYSCLK_Div1);
RCC_PCLK1Config(RCC_HCLK_Div1);
RCC_PCLK2Config(RCC_HCLK_Div1);
RCC_PLLConfig(RCC_CFGR_PLLSRC_HSI_Div2,RCC_CFGR_PLLMULL12);
RCC_PLLCmd(ENABLE);
while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
while (RCC_GetSYSCLKSource() != 0x08);
}

void timer_pwm_mode_init(void){
TIM_TimeBaseInitTypeDef TIM_TBInitStruct;
TIM_OCInitTypeDef TIM_OCInitStruct;

         TIM_TBInitStruct.TIM_Period =381;
         TIM_TBInitStruct.TIM_Prescaler =6;
         TIM_TBInitStruct.TIM_ClockDivision = 0;
         TIM_TBInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
         TIM_TimeBaseInit(TIM3, &TIM_TBInitStruct);


         TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;
     TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;

         TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;
     TIM_OCInitStruct.TIM_OCIdleState = TIM_OCIdleState_Set;
     TIM_OCInitStruct.TIM_Pulse = SineTable[0];
         TIM_OC4Init(TIM3, &TIM_OCInitStruct);

         TIM_DMACmd(TIM3,TIM_DMA_Update,ENABLE);
         TIM_Cmd(TIM3,ENABLE);
TIM_CtrlPWMOutputs(TIM3,ENABLE);
}

void rcc_init()
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO,ENABLE);
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
}

void gpio_init()
{
GPIO_InitTypeDef  GPIO_InitStructure;


GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 ;  // PWM
GPIO_Init(GPIOB, &GPIO_InitStructure);
}

void tim_dma_config(void)
{
DMA_InitTypeDef DMA_InitStructure1;

  DMA_DeInit ( DMA1_Channel3);
  DMA_Cmd(DMA1_Channel3,DISABLE);

  DMA_InitStructure1.DMA_PeripheralBaseAddr = 0x40000440;
  DMA_InitStructure1.DMA_MemoryBaseAddr = (uint32_t)SineTable;
  DMA_InitStructure1.DMA_DIR = DMA_DIR_PeripheralDST;
  DMA_InitStructure1.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  DMA_InitStructure1.DMA_MemoryInc = DMA_MemoryInc_Enable;
  DMA_InitStructure1.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
  DMA_InitStructure1.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
  DMA_InitStructure1.DMA_Mode = DMA_Mode_Circular;
  DMA_InitStructure1.DMA_Priority = DMA_Priority_Medium;
  DMA_InitStructure1.DMA_M2M = DMA_M2M_Disable;
  DMA_InitStructure1.DMA_BufferSize = 360;
  DMA_Init(DMA1_Channel3, &DMA_InitStructure1);

  DMA_Cmd(DMA1_Channel3,ENABLE);
}

int main(void)
{
hsi_clock_init();
rcc_init();
gpio_init();
timer_pwm_mode_init();
tim_dma_config();
    while(1)
    {
    }
}

Başlık: Ynt: STM32F10X PWM+DMA ile Sinüs oluşturma
Gönderen: SpeedyX - 11 Mart 2013, 14:44:21
const uint16_t sinTable[32] = {
  2047, 2447, 2831, 3185, 3498, 3750, 3939, 4056, 4095, 4056,
  3939, 3750, 3495, 3185, 2831, 2447, 2047, 1647, 1263, 909,
  599, 344, 155, 38, 0, 38, 155, 344, 599, 909, 1263, 1647};

uint32_t sinCosTable[32];

int main(void) {
  GPIO_InitTypeDef GPIO_InitStructure;
  DAC_InitTypeDef DAC_InitStructure;
  TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
  DMA_InitTypeDef DMA_InitStructure;

  SystemInit();

  for(uint8_t i = 0; i < 32; i++){
    sinCosTable[i] = sinTable[i] << 16;
  }
  for(uint8_t i = 8; i < 32; i++){
    sinCosTable[i - 8] |= sinTable[i];
  }
  for(uint8_t i = 0; i < 8; i++){
    sinCosTable[i + 24] |= sinTable[i];
  }

  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC | RCC_APB1Periph_TIM2, ENABLE);
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5;
  GPIO_Init(GPIOA, &GPIO_InitStructure);

  TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
  TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
  TIM_TimeBaseInitStructure.TIM_Period = 74;
  TIM_TimeBaseInitStructure.TIM_Prescaler = 0;
  TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
  TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);

  TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update);

  DAC_InitStructure.DAC_LFSRUnmask_TriangleAmplitude = DAC_LFSRUnmask_Bit0;
  DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Disable;
  DAC_InitStructure.DAC_Trigger = DAC_Trigger_T2_TRGO;
  DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None;
  DAC_Init(DAC_Channel_1, &DAC_InitStructure);
  DAC_Init(DAC_Channel_2, &DAC_InitStructure);

  DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(DAC->DHR12RD);
  DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&sinCosTable;
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
  DMA_InitStructure.DMA_BufferSize = 32;
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;
  DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
  DMA_InitStructure.DMA_Priority = DMA_Priority_High;
  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
  DMA_Init(DMA1_Channel3, &DMA_InitStructure);

  DMA_Cmd(DMA1_Channel3, ENABLE);

  DAC_Cmd(DAC_Channel_1, ENABLE);
  DAC_Cmd(DAC_Channel_2, ENABLE);

  DAC_DMACmd(DAC_Channel_1, ENABLE);

  TIM_Cmd(TIM2, ENABLE);

  while (1) {}
}
Başlık: Ynt: STM32F10X PWM+DMA ile Sinüs oluşturma
Gönderen: muhittin_kaplan - 11 Mart 2013, 14:56:06
Hocam Ellerinize Sağlık..
İlk Fırsatta deneyeceğim.
Başlık: Ynt: STM32F10X PWM+DMA ile Sinüs oluşturma (Örnek)
Gönderen: kantirici - 12 Mart 2013, 10:19:06
hocam bununla ilgili aklıma takılan bir iki soru var.Öncelikle oluşturacacagımız tablo için frekansın nasıl br etkisi oluyor.Mesela 50Hz'lik bir sinüs için 10 bit ve 32 örnek durumunda 1023*(1+sin(2*pi*n/32))/2 ile tablo degerlerini oluşturursak sinüs frekansının burada etkisi nasıl oluyor.
Diger sorusu ise pwm frekansının oluşturulacak sinüs frekansına eşit olması gerekiyormu? teşekkürler.
Başlık: Ynt: STM32F10X PWM+DMA ile Sinüs oluşturma (Örnek)
Gönderen: Klein - 12 Mart 2013, 21:58:18
PWM frekansı  = sinüs frekansı * örnekleme sayısı.  olmalı.

Tablonun sinüs frekansına doğrudan bir etkisi yok. Ancak tablodaki eleman sayımız  bir periyottaki örnekleme sayımız olduğu için , doğal olarak örnekleme sayımız ne kadar yükselirse aynı dalga frekansı için PWM frekansımız da okadar yükselecektir.


Başlık: Ynt: STM32F10X PWM+DMA ile Sinüs oluşturma (Örnek)
Gönderen: fractal - 13 Mart 2013, 08:38:46
tam olarak neden dma ihtiyacımız var anlamadım.zaten bir timer her türlü durumda çalışmayacakmı.?.örneğin 50hz-ile 500hz arasında sinüs için ben şöyle yapıyorum.max frekansa göre hesaplıyorum.T=2ms.ben T/2 kullanıyorum.çünkü tam köprü var.ve yarım period için hesaplama yapıyorum sadece yani 180 dereceye kadar.sonra zaten akım yön değiştiriyor.ne kadar örnekleme yapacaksam  1ms/örnekleme adedim    bana timer kesme zamanını veriyor.örneğin 32 örnek varsa yarım period için ozaman yaklaşık 32 ms de bir kesme yaparak diziden değerleri okuyarak güncelleme yapıyorum.hangi frekansı kullanıcaksam ilk önçe onun tablosunu oluşturuyorum tabi.şimdi bu dma hangi noktada devreye giriyor?
Başlık: Ynt: STM32F10X PWM+DMA ile Sinüs oluşturma (Örnek)
Gönderen: Klein - 13 Mart 2013, 15:00:29
32 mikrosaniye olacaktı sanırım.

Bu kod interrupt içinde tablodan çektiği veriyi PWM registerine yazan basit bir kod.
void TIM2_IRQHandler(void)
{
TIM3->CCR4 = sine_table[sine_index];
if(++sine_index == 31) sine_index =0;
TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
}


Bu da disassembly hali.
08000b78:   mov.w r3, #1024 ; 0x400
08000b7c:   movt r3, #16384 ; 0x4000
08000b80:   movw r2, #64    ; 0x40
08000b84:   movt r2, #8192  ; 0x2000
08000b88:   ldrh r2, [r2, #0]
08000b8a:   mov r1, r2
08000b8c:   movw r2, #0
08000b90:   movt r2, #8192  ; 0x2000
08000b94:   ldrh.w r2, [r2, r1, lsl #1]
08000b98:   strh.w r2, [r3, #64]    ; 0x40
128        if(++sine_index == 31) sine_index =0;
08000b9c:   movw r3, #64    ; 0x40
08000ba0:   movt r3, #8192  ; 0x2000
08000ba4:   ldrh r3, [r3, #0]
08000ba6:   add.w r3, r3, #1
08000baa:   uxth r2, r3
08000bac:   movw r3, #64    ; 0x40
08000bb0:   movt r3, #8192  ; 0x2000
08000bb4:   strh r2, [r3, #0]
08000bb6:   movw r3, #64    ; 0x40
08000bba:   movt r3, #8192  ; 0x2000
08000bbe:   ldrh r3, [r3, #0]
08000bc0:   cmp r3, #31
08000bc2:   bne.n 0x8000bd2 <TIM2_IRQHandler+94>
08000bc4:   movw r3, #64    ; 0x40
08000bc8:   movt r3, #8192  ; 0x2000
08000bcc:   mov.w r2, #0
08000bd0:   strh r2, [r3, #0]
129        TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
08000bd2:   mov.w r0, #1073741824   ; 0x40000000
08000bd6:   mov.w r1, #1
08000bda:   bl 0x80003e0 <TIM_ClearITPendingBit>
130       }


pending biti temizlerken  , kesmeye girip çıkarken çalıştırdıkları hariç 36 komut işletiliyor.

500Hz 32 örnekli sinüs üretebilmek için, saniyede 32000 kez kesmeye gidiyorsunuz.

1 saniyelik periyodu tamamlamak için 32000*36 = 1.152.000 kez kesmeye gideceksiniz.

peki sinüs 500 Hz değil de 50Khz olsaydı?

saniyede 3.200.000 kez kesmeye gidecektiniz.
1 saniyede kaç komut işletmemiz gerekecekti?
 
3.200.000*36 =  115.200.000 komut.

İşlemcimiz zaten 72MHz.  saniyede 72 milyon komut işletebiliyor. 115 milyon komutu nasıl işletecekti?

Bazien hız yüzünden 1 baytın hesabını yapıyoruz. Bu kadar küçük hesaplar yaparken , CPU kaynaklarını bu kadar hoyratça kullanmamak gerek.
CPU Mühendisleri bu donanımları biz kullanalım diye koyuyor.  Bir işi hardware yapabiliyorsa , ona yaptırmak en iyisi.
Başlık: Ynt: STM32F10X PWM+DMA ile Sinüs oluşturma (Örnek)
Gönderen: z - 13 Mart 2013, 17:20:59
Alıntı yapılan: fractal - 13 Mart 2013, 08:38:46
tam olarak neden dma ihtiyacımız var anlamadım.

Bir yerde duran yada bir yerden gelen verileri, veriler üzerinde hiç işlem yapamadan bir başka yere taşıyacaksan, işlemciyi bu işe bulaştırmadan DMA aracılığıyla yaparsın.

Fakat taşınacak veriler üzerinde gerçek zamanda işlem yapılacak ve taşınacaksa bu durumda DMA fazla bir işe yaramaz.
Başlık: Ynt: STM32F10X PWM+DMA ile Sinüs oluşturma (Örnek)
Gönderen: fractal - 13 Mart 2013, 17:43:14
hocam dma olayının bu örnekte kullanıldığı noktayı tam olarak anlayamadım.dma ile pwm güncelleme zamanı nasıl yapılıyor.bu dma nasıl bir şeyki benim istediğim güncelleme zamanını bilsin ona göre güncellesin.pwm örneğini kastederek konuşuyorum.örnekleme sayısı değiştikçe dma sız durumda güncellemek için timer kesme zamanı değişcekti.bu iş dma ile nasıl oluyor?
Başlık: Ynt: STM32F10X PWM+DMA ile Sinüs oluşturma (Örnek)
Gönderen: z - 13 Mart 2013, 18:46:14
Örneği incelemedim. Fakat soruna cevap vereyim.

DMA ünitesine dataların alınacağı yığının yada ADC vs gibi ünitelerin adresini verirsin.
Dataların taşınacağı adresi yada PWM modülü gibi ünitelerin adresini verirsin.

Sonrada dersinki DMA seni ADC yada PWM dürtükleyecek her dürtüklediğinde sıradaki veriyi oku ve hedefe yaz.

Buradaki dürtüklemenin ne olacağı seçilebilir. Atıyorum PWM Count= PWM Peryod olduğunda DMA uyarılsın gibi.

Bu durumda CPUnun hiç müdahalesi olmadan  bir taraftaki veriler diğer tarafa aktarılır.

Eğer RAM'dan RAM'a aktarım yapılacaksa dürtüklemeye gerek kalmaz. DMA ünitesine al şunları taşı dersin olur biter.



Başlık: Ynt: STM32F10X PWM+DMA ile Sinüs oluşturma (Örnek)
Gönderen: Klein - 13 Mart 2013, 19:09:56
Şöyle:

TIM_DMACmd(TIM3,TIM_DMA_Update,ENABLE);

TIM3'e diyoruz ki  sen her update olduğunda. ( yani her PWM periyodunu tamamladığında) DMA'yı tetikle.

DMA tetiklemeyi aldığında

DMA_InitStructure1.DMA_DIR = DMA_DIR_PeripheralDST;
Hedef olarak Peripherial aygıt, kaynak olarak da memory  belirttiğimiz için.

DMA_InitStructure1.DMA_MemoryBaseAddr = (uint32_t)SineTable;
Burada belirttiğimiz adresteki ( SineTable) veriyi alıp

DMA_InitStructure1.DMA_PeripheralBaseAddr = 0x40000440;
Burada belirttiğimiz adrese (TIM3->CCMR3) yazıyor.

DMA tekrar tetiklediğinde
     
DMA_InitStructure1.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure1.DMA_MemoryInc = DMA_MemoryInc_Enable;

Bellek adresini artır ama , peripherial adresi sabit kalsın dediğimiz için,
bellek adresi artıyor ve  , SineTable'nin bir sonraki elemanı TIM3->CCMR registerine yazılıyor.


     
DMA_InitStructure1.DMA_BufferSize = 360;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;

DMA bellek büyüklüğünü 360 verdiğimiz için 360 kez tetiklendiğinde 1 sinüs periyodu tamamlanmış oluyor.
Eğer sinüsün 1 periyodundaki örnek sayımız 32 olsaydı. Bu değer 32 olacaktı ve 32. tetiklemeden sonra sinüs periyodu tamamlanacaktı.

     
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;

DMA modu Circular olduğu için bir sonraki tetiklemede başa dönüp , tüm adımları yeniden işletiyor.


Başlık: Ynt: STM32F10X PWM+DMA ile Sinüs oluşturma (Örnek)
Gönderen: fractal - 13 Mart 2013, 23:25:58
hocam mükemmel anlatmışsınız.teşekkürler herkese..konuyu dma üzerine   kilitlemek istemem ama dma ile aynı anda haberleşme için aynı anda pwm  için kullanabilirmiyim.yada şöyle adc ile bir şeyler  okuyup örneğin akım hesabı yapıcam haberleşme ile bu bilgiyi sürekli bir ekrana basıcam.dma ile bu 3 şeyi sırayla cpu yu yormadan cözebilirmiyim.yoksa dma sadece bir şey içinmi kullanılır.dmabirkaç şey için kullanılırsa birbirlerini etkilerlermi?
Başlık: Ynt: STM32F10X PWM+DMA ile Sinüs oluşturma (Örnek)
Gönderen: Klein - 14 Mart 2013, 01:03:14
Kullanabilirsiiz tabi ki.
2 tane DMA modülümüz var. Birinde 7 diğerinde 5 kanal var.
Ancak DMA kullanabilen donanımımız bu sayıdan fazla olduğu için , bazı kanallar ortak.
(http://d1303.hizliresim.com/17/g/l1bwq.png) (http://bit.ly/c25MCx)

Tablodan da görüldüğü gibi.
ADC1 , TIM2_CH3, TIM4_CH1 Aynı kanalı kullanıyor.
SPI1_RX, USART3_TX, TIM1_CH1, TIM2_CH3 aynı kanalı kullanıyor.
...
...

Eğer hem USART3_TX , hem de SPI1_RX  kanalını  kullanacaksanız, DMA işini bitirdikten sonra, ilgili kanalın ayarlarını değiştirip diğer donanım için kullanabilirsiniz.
Fakat PWM örneğinde olduğu gibi Circular buffer şeklinde kesintisiz kullanım varsa ,o zaman aynı kanalı kullanamazsınız.

Bunu biraz tasarımı yaparken planlamak gerekiyor.
Örneğin DMA ile hem  PWM hem de USART TX kullanacaksınız diyelim.
Bu durumda kullanacağınız USART modülü USART3 ise , tasarımı yaparken PWM çıkışını TIM1_CH1'den değil TIM1_CH2'den almaya dikkat edeceksiniz. 
ADC kullanacaksanız TIM2_CH1 kullanmayacaksınız.
Başlık: Ynt: STM32F10X PWM+DMA ile Sinüs oluşturma (Örnek)
Gönderen: izzethoca - 14 Mart 2013, 11:46:07
hocam çok teşekkür ederim. DMA konusunu az daha açmanız mümkünmü? Nedir nasıl kullanılır gibi
Başlık: Ynt: STM32F10X PWM+DMA ile Sinüs oluşturma (Örnek)
Gönderen: Klein - 14 Mart 2013, 12:48:19
DMA Özünde basit işlevi olan bir donanım.
Tetikleme sinyali gelince şurdaki bilgiyi alıp , buraya kopyalayan bir donanım. Yaptığı tüm iş bu.
DMA'nın karışık gibi algılanmasına sebep olan şey , bir çok çevre birim ve bellek  ile ilişkilendirilebiliyor olması,
bu çevre birimleri tetikleyebilme ve bu birimler tarafından tetiklenebilme kabiliyetine sahip olması. 

DMA ile yapılmış bir kaç örnek sitede mevcut. Bunlar incelendiğinde aslında yapının ne kadar basit olduğu görülebilir.
Başlık: Ynt: STM32F10X PWM+DMA ile Sinüs oluşturma (Örnek)
Gönderen: kantirici - 14 Mart 2013, 17:24:16
Alıntı yapılan: Klein - 12 Mart 2013, 21:58:18
PWM frekansı  = sinüs frekansı * örnekleme sayısı.  olmalı.

Tablonun sinüs frekansına doğrudan bir etkisi yok. Ancak tablodaki eleman sayımız  bir periyottaki örnekleme sayımız olduğu için , doğal olarak örnekleme sayımız ne kadar yükselirse aynı dalga frekansı için PWM frekansımız da okadar yükselecektir.

Anladım hocam teşekkürler.Peki siz bu tabloyu ne ile oluşturdunuz acaba?
Başlık: Ynt: STM32F10X PWM+DMA ile Sinüs oluşturma (Örnek)
Gönderen: Klein - 14 Mart 2013, 18:17:41
microsoft excel ile.
Başlık: Ynt: STM32F10X PWM+DMA ile Sinüs oluşturma (Örnek)
Gönderen: fractal - 21 Mart 2013, 08:27:11
kafama takılan diğer sorular şöyle;

1.)örneğin denilmişki pwm her yeni period da dma tetikleyecek.bu tetikleme donanımsalmı?yoksa bir interrupt şeklindemi.yoksa 32 örnekli sinüs için geçerli olan aynı şekilde 32 tetikleme işlemi yaparki bu da  aynı şey olmazmı?

2.)dma ile pwm uygulaması yapalım.yine sinüs değerleri kullanalım.peki birde h-köprü sürdüğümüzü düşünelim.bu nu nasıl yapabiliriz?bu örnekte tek kanal pwm çıkışında çalışmak kolay.4 kanal çıkış olsaydı dma ve pwmi nasıl ayarlarık.özellikle alternas geçişleri nasıl olurdu?
Başlık: Ynt: STM32F10X PWM+DMA ile Sinüs oluşturma (Örnek)
Gönderen: Klein - 21 Mart 2013, 10:56:23
1-Tetiklemeyi donanım yapıyor.

2- PWM kanalının negatif ve pozitif çıkışları var. yarım köprü kullanırken bu çıkışlar kullanılabilir. 
Tam köprü için  birkaç farklı strateji izlenebilir.

İki tane sinüs tablosu yapılabilir. tablonun birisi bir alternans boyunca 0, diğer tablo ise diğer alternans boyunca sıfır olur. Timer başlatıldığında  iki kanal birden başlar. İlk alternansta tablonun birisi 0 olacağı için kanalın birinden 0 diğerinden ise sinüsün bir alternansı alınır.

örnek tablo:  ( tablo sinüs değil. hesap kitapla uğraşmamak için üçgen yaptım)

const sine_table_hi[] = {0,1,2,3,4,5,6,7,8,9,8,7,6,5,4,3,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
const sine_table_lo[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,3,4,5,6,7,8,9,8,7,6,5,4,3,2,1}


Başlık: Ynt: STM32F10X PWM+DMA ile Sinüs oluşturma (Örnek)
Gönderen: fractal - 21 Mart 2013, 12:29:49
hocam çok güzel anlatıyorsunuzda ben biraz yeniyim.stellaris lm3sxxx kullanıyorum.derleyicim texas ccs ..onlarda micro dma var.ayrıca pwm modülünü cözdüm.ama pwm modülü timer la çalışmıyor.tabi istersen ayarlayabiliyorsun.burdaki yapıyı uyarlamam gerekecek.yazdığınız örnek kodlarda iyi bir referans kaynağı.ayrıca çift tablo kullanma fikrini paylaşarak da güzel bir çözüm önermiş oldunuz.

birde pid  akım kontrolü işin içine girerse sanırım dma olayı olmaz.çünkü Z nin dediğine göre eğer datalar işlenecekse dma nın bir özelliği kalmıyormuş.data işlemekten kastım genlik değiştirerek  akım kontrolü tablo değerlerinin aynı oranda artması yada azalması gibi.
Başlık: Ynt: STM32F10X PWM+DMA ile Sinüs oluşturma (Örnek)
Gönderen: Klein - 21 Mart 2013, 16:11:11
Evet veri üzerinde herhangi bir işlem yapılacaksa DMA kullanmak anlamlı değil.
Ancak Cycle-by-Cycle kontrol  yapılmıyorsa, PID verileri her saykılda hesaplanmıyorsa, tablo dinamik olarak oluşturulabilir.
Tablo const olarak önceden tanımlanmaz. Tablo için bir dizi ayrılır. PID sonucuna göre tablo yeniden hesaplanır. 

Çok hızlı PID işlemlerinde çok efektif olmaz.
Ama DMA kullanmasanız da zaten PID sonucuna göre bir dalga formu üretmeniz gerekiyor.
En azından çıkış işlemleri ile uğraşmak zorunda kalmazsınız.

Başlık: Ynt: STM32F10X PWM+DMA ile Sinüs oluşturma (Örnek)
Gönderen: fractal - 21 Mart 2013, 16:57:18
hocam  ben zaten dinamik tablo kullanıcağım.istediğim frekansa göre tabloyu bir kez hesaplatacağım.daha sonra akım kontrolü için değerlerin tümünü aynı oranda arttırıp azaltacağım.tabi burda ozaman şu nokta önemli ; bir peroyot süresince tablonun tüm elemanları en azından güncellenmiş olmalı.peryot süresi dolunca pwm dma tetikleyecek.dma zaten güncel değerleri göndermiş olucak.eğer işelem yükünü dma aldığını varsayarsak işlemci 80mhz ise yani 1s de 80 milyon işlem ozaman 1ms 80000 işlem.eğer 500hz sinüs üretecksem.T=2ms  yapar.360 derece  360 değer kullnırsam en az 360 işlem demektir.burdan cıkan sonuç ozaman rahatlıkla tabloyo güncelleyebilirim.ayriyeten geriye çok işlem gücümü kalıyor.

şunuda merak ediyorum dma nın birden çok kanalı kullanmak dma nın hızını düşürürmü?dma nın performansını ne etkiler?
Başlık: Ynt: STM32F10X PWM+DMA ile Sinüs oluşturma (Örnek)
Gönderen: Klein - 21 Mart 2013, 18:20:30
DMA'da birden fazla kanal kullanmak muhakkak ki DMA hızını düşürecektir.  Ancak tablonun 360 elemanlı olduğunu düşünürsek , saniyede 500 kez 360 değer aktaracak demektir. O da saniyede 180.000 değer aktarımı demek. Çok yüksek bir değer değil.   
Başlık: Ynt: STM32F10X PWM+DMA ile Sinüs oluşturma (Örnek)
Gönderen: muhittin_kaplan - 05 Ağustos 2013, 05:03:48
DMA nın Hızını Ayarlayabiliyormuyuz ?
Başlık: Ynt: STM32F10X PWM+DMA ile Sinüs oluşturma (Örnek)
Gönderen: Klein - 05 Ağustos 2013, 17:15:35
DMA hızını , DMA'yı tetikleyen donanım belirliyor.
Başlık: Ynt: STM32F10X PWM+DMA ile Sinüs oluşturma (Örnek)
Gönderen: muhittin_kaplan - 05 Ağustos 2013, 22:04:24
Yani bir timer a bağlayabiliyormuyuz ?
SPI dan alınan bir bilgiyi USARt tan göndermek istesek
önce Perip->memory sonrasında Memory->peripheral mı yapacağız ?
SPI dan aldığımız bir bilgiyi sprintf ile bir katar oluştursak CPU yu kullanmış dolayısıyla DMA nın özüne ihanet mi etmiş oluruz ?
Başlık: Ynt: STM32F10X PWM+DMA ile Sinüs oluşturma (Örnek)
Gönderen: Klein - 06 Ağustos 2013, 18:06:59
Evet bir Timer'a bağlayabiliyoruz. DMA-PWM örneği zaten bunu yapıyor. Timer update olayı oluştuğunda DMa tetikleniyor.
periph<->periph. meselesini bilmiyorum. biraz zaman verirsen datasheet'i ararştırıp cevap veririm.
spi'dan veriyi alıp sprintf formatlamakla hiç bir şeye ihanet etmiş olmayız. 
srintf ile veriyi formatlarken CPU gücü kullanıyoruz. Ama önemli nokta şu:
Donanımlardan veriyi alırken ve veriyi gönderirken, bazı hız sınırlamalarına tabiyiz.  Usart ile veri gönderirken baud hızına göre , belirli beklemeler yapmak zorundayız.
Ama sprintf ile işlem yaparken böyle bir kısıtlama yok. Bellekten ne hızda veri çekebiliyorsak o hızda işlem yapıyoruz.
Bu sebeple SPI'dan veriyi alıp , sprintf ile formatlamak gayet olağan bir durum. DMA ile veriyi formatlama şansımız yok zaten.


mesaj birleştirme:: 06 Ağustos 2013, 18:45:02

peripherial-to-peripharial transfer yapabiliyormuş.

Ref: STM32f10xxx refsheet. sayfa 256.
Başlık: Ynt: STM32F10X PWM+DMA ile Sinüs oluşturma (Örnek)
Gönderen: muhittin_kaplan - 06 Ağustos 2013, 18:47:26
hocam Kütüphanesinde
sadece
mem to mem
pripheral to mem
mem to peripheral
var.
Başlık: Ynt: STM32F10X PWM+DMA ile Sinüs oluşturma (Örnek)
Gönderen: muhittin_kaplan - 06 Ağustos 2013, 18:53:33
Hocam Dediğiniz yerde eksik/yanlış bir durum mu mevcut
normalde mem to mem olması gerekirken yok.
Başlık: Ynt: STM32F10X PWM+DMA ile Sinüs oluşturma (Örnek)
Gönderen: Klein - 06 Ağustos 2013, 19:12:27
Evet kütüphaneye ve register yapısına baktığımda yapamayacağını görüyorum. 
http://s3.dosya.tc/server8/JqAZG4/STM32F10xxx_REF.pdf.html (http://s3.dosya.tc/server8/JqAZG4/STM32F10xxx_REF.pdf.html)
Ama bu dokümanın 256. sayfasında periph-periph yapabildiğini söylüyor.

Şöyle olabilir. Emin değilim denemek gerek.
Yavaş donanımı periph seçip tetiklemeyi bu donanıma yaptırıp, memory adresi olarak da karşı donanımın adresi verilebilir. Yer mi? Yemez mi? Bilmiyorum.
Başlık: Ynt: STM32F10X PWM+DMA ile Sinüs oluşturma (Örnek)
Gönderen: mir_as82 - 07 Ağustos 2013, 00:00:45
Hocam bu yazılan kodları ben farklı bir işlemciye nasıl uyarlarım bu noktada zorluk çekiyorum. Mesela siz stm32f10x ile yazmışsınız ben bu yapılan örneği stm32f4 ile nasıl yapabilirim? özellikle konfigürasyon ayarları sıkıntı oluyor.
Başlık: Ynt: STM32F10X PWM+DMA ile Sinüs oluşturma (Örnek)
Gönderen: 61emre89 - 27 Mayıs 2014, 18:05:36
Klein hocam merhaba,
STM32F103r8t6 işlemci ile verdiğiniz kodu denedim(PB9 pini için-TIM4-CH4). Fakat sonuc olarak hep kare dalga elde ediyorum.

Sorun ne olabilir ,fikir verebilir misiniz?
Başlık: Ynt: STM32F10X PWM+DMA ile Sinüs oluşturma (Örnek)
Gönderen: Klein - 27 Mayıs 2014, 18:26:06
Kare dalga elde etmeniz normal.  Osilaskopla baktığınızda duty oranı sürekli değişen kare dalga görürsünüz. Çıkışı seri direnten geçirip, diren ıkışından GND'ye bir kapasitör atarsanız, diren ve kapasitörün birleştiği noktada sinüs görürsünüz.
Başlık: Ynt: STM32F10X PWM+DMA ile Sinüs oluşturma (Örnek)
Gönderen: restore - 27 Mayıs 2014, 22:15:28
teşekkürler . güzel bilgi kaynagı .
Başlık: Ynt: STM32F10X PWM+DMA ile Sinüs oluşturma (Örnek)
Gönderen: 61emre89 - 28 Mayıs 2014, 10:26:00
Hocam osiloskopta gözlemlediğim kadarıyla genişlik sabit olan bir kare dalga elde ediyorum. timer ve dma channel degiştirdigim icin dikkat etmem gereken parametreler var mı?

Başlık: Ynt: STM32F10X PWM+DMA ile Sinüs oluşturma (Örnek)
Gönderen: SpeedyX - 28 Mayıs 2014, 11:22:34
Internal osc kullanıyorum ve PWM periodu örneğin 5ms olsun diye ayarlıyorum ama 4.96ms oluyor, bunu kalibre etmenin yada doğruluğunu arttırmanın kolay yolu var mı? (Kristal kullanmadan)
Başlık: Ynt: STM32F10X PWM+DMA ile Sinüs oluşturma (Örnek)
Gönderen: Klein - 28 Mayıs 2014, 14:13:28
Alıntı yapılan: 61emre89 - 28 Mayıs 2014, 10:26:00
Hocam osiloskopta gözlemlediğim kadarıyla genişlik sabit olan bir kare dalga elde ediyorum. timer ve dma channel degiştirdigim icin dikkat etmem gereken parametreler var mı?


Kare dalgayı gördüğünüze göre timer çalışıyor. DMA çalışmıyor. Kodu yayınlarsanız bir bakarım.


Alıntı yapılan: SpeedyX - 28 Mayıs 2014, 11:22:34
Internal osc kullanıyorum ve PWM periodu örneğin 5ms olsun diye ayarlıyorum ama 4.96ms oluyor, bunu kalibre etmenin yada doğruluğunu arttırmanın kolay yolu var mı? (Kristal kullanmadan)

RCC_AdjustHSICalibrationValue(uint8_t HSICalibrationValue)
Başlık: Ynt: STM32F10X PWM+DMA ile Sinüs oluşturma (Örnek)
Gönderen: SpeedyX - 28 Mayıs 2014, 14:29:02
Hocam RCC_AdjustHSICalibrationValue(uint8_t HSICalibrationValue) fonksiyonunu biliyorum tabii, yüzlerce cihazı kalibre etmek için trick gibi birşey sormuştum, yapan varsa eğer.
Başlık: Ynt: STM32F10X PWM+DMA ile Sinüs oluşturma (Örnek)
Gönderen: 61emre89 - 28 Mayıs 2014, 16:36:09

void Timer_PWM_COnfiguration(void)
{
   TIM_TimeBaseInitTypeDef TIM_TBInitStruct;
   TIM_OCInitTypeDef TIM_OCInitStruct;


    TIM_TBInitStruct.TIM_Period =381;           //381
    TIM_TBInitStruct.TIM_Prescaler =6;
   TIM_TBInitStruct.TIM_ClockDivision = 0;
   TIM_TBInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
   TIM_TimeBaseInit(TIM4, &TIM_TBInitStruct);


   TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;
    TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;


      TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStruct.TIM_OCIdleState = TIM_OCIdleState_Set;
    TIM_OCInitStruct.TIM_Pulse =SineTable[0] ;
    TIM_OC4Init(TIM4, &TIM_OCInitStruct);


    TIM_DMACmd(TIM4,TIM_DMA_Update,ENABLE);
    TIM_Cmd(TIM4,ENABLE);
    TIM_CtrlPWMOutputs(TIM4,ENABLE);


}
/**************************************************************************************/
void Timer_DMA1_Configuration(void)
{
   DMA_InitTypeDef DMA_InitStructure1;


    DMA_DeInit ( DMA1_Channel4);
    DMA_Cmd(DMA1_Channel4,DISABLE);


    DMA_InitStructure1.DMA_PeripheralBaseAddr =0x40000840;
    DMA_InitStructure1.DMA_MemoryBaseAddr = (uint32_t)SineTable;
    DMA_InitStructure1.DMA_DIR = DMA_DIR_PeripheralDST;
    DMA_InitStructure1.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure1.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure1.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
    DMA_InitStructure1.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
    DMA_InitStructure1.DMA_Mode = DMA_Mode_Circular;
    DMA_InitStructure1.DMA_Priority = DMA_Priority_Medium;
    DMA_InitStructure1.DMA_M2M = DMA_M2M_Disable;
    DMA_InitStructure1.DMA_BufferSize = 360;
    DMA_Init(DMA1_Channel4, &DMA_InitStructure1);


    DMA_Cmd(DMA1_Channel4,ENABLE);


}





Hocam kodu yukardaki gibi kucuk degişikler yaparak aynen uyguladım.
Başlık: Ynt: STM32F10X PWM+DMA ile Sinüs oluşturma (Örnek)
Gönderen: Klein - 28 Mayıs 2014, 18:36:18
DMA1 Kanal 4 kullanmışsınız.  Ancak kanal 4  TIM4 kanal4 'ten tetiklenmiyor. Hatta TIM4 Kanal4 için DMA1'de kanal yok.  DMA 1 Kanal 4 TIM4 Kanal 2 den tetikleme alabiliyor.
DMA 1 kanal listesi aşağıdaki gibi
https://www.dropbox.com/s/s05ylduij242eyq/Stm32F1_Dma.PNG (https://www.dropbox.com/s/s05ylduij242eyq/Stm32F1_Dma.PNG)
Başlık: Ynt: STM32F10X PWM+DMA ile Sinüs oluşturma (Örnek)
Gönderen: 61emre89 - 29 Mayıs 2014, 10:35:24
Tasarımdan dolayı benim (PB9/TIM4-CH4) bacagından bu cıkısı almam gerekiyor. DMA1 listesinde bunun için bir Channel yok siz söyledikten sonra ben de listeyi yanlıs yorumladıgımı farkettim. Peki bu durumda alternatif olarak ne yapabilirim.?
Başlık: Ynt: STM32F10X PWM+DMA ile Sinüs oluşturma (Örnek)
Gönderen: Klein - 29 Mayıs 2014, 11:54:19
Eğer Sinüs frekansınız yüksek değilse,  DMA yerine  interrupt içerisinde yükleme yapabilirsiniz.  Örnekle aynı sayfda  biir kaç başlık altında interrupt kullanımı da mevcut.
Başlık: Ynt: STM32F10X PWM+DMA ile Sinüs oluşturma (Örnek)
Gönderen: gokhannsahin - 19 Aralık 2014, 09:04:30
Eğer pwm ile 3 faz inverter yapmak istersek nasıl olacak benim aklımda şöyle bir çözüm var pwm tablosu diyelim ki 360 değerden oluşuyor, yanı her bir derece için bir değer. Fazlar arası 120 derece ise; R fazı tablonun 1'nci değerinden , S fazı tablosunun 121'nci değerinden ve son olarakda T fazı 241'nci değerden mi başlaması gerekiyor ?
Başlık: Ynt: STM32F10X PWM+DMA ile Sinüs oluşturma (Örnek)
Gönderen: Klein - 20 Aralık 2014, 21:19:53
Teorik olarak öyle.  Ama DMA'nın sadece base adresini verebiliyoruz. Eğer kanallardan birine adres olarak daha ilerideki bir adresi verirsek , taşacaktır.
Bu sebeple  tabloyu bir periyot yerine daha uzun hazırlarsanız taşmanın önüne geçebilirsiniz.
Başlık: Ynt: STM32F10X PWM+DMA ile Sinüs oluşturma (Örnek)
Gönderen: namso0632 - 21 Mart 2015, 14:19:41
DMA'yı DAC ile kullanmak için kodlar üzerinde nasıl bir değişiklik yapmamız gerekiyor acaba ?