SPWM Uygulaması
C2000 ailesinden TMS320F069M ile SPWM...
SPWM (Sinusoidal Pulse Width Modulation) veya Sinüs Dalga Genişlik Modülasyonu, birçok uygulamada kullanılan bir sinyal işleme tekniğidir. Bu teknik, genellikle invertörler, güç kaynakları ve motor sürücüleri gibi uygulamalarda kullanılır.

SPWM, bir sinüs dalga formunun genlikleri ve genişlikleri modüle edilerek bir kare dalga formu oluşturur. Bu modülasyon, birçok farklı frekansta kullanılabilir ve sinyalin frekansına bağlı olarak, çıkış dalga formunun doğrusallığı ve çözünürlüğü değişebilir.
SPWM, birçok avantaj sunar. Örneğin, invertörlerde kullanıldığında, çok düşük harmonik bozulma ve yüksek verimlilik sağlar. Bu, üç fazlı motor sürücülerinin, alternatif akım (AC) motorları verimli bir şekilde çalıştırmalarına olanak tanır. Ayrıca, güç kaynaklarında kullanıldığında, istenen bir çıkış gerilimi veya akımı elde etmek için kullanılabilir.
SPWM'nin çalışma prensibi, sinüs dalga formunun pik noktasının belirlenmesine dayanır. Sinüs dalga formu, genellikle bir analog sensör veya bir dijital işlemci tarafından oluşturulur. Pik noktası, sinüs dalga formunun en yüksek noktasıdır ve bu nokta, kare dalga formunun duty cycle'ı için temel bir referans olarak kullanılır.

Duty cycle, kare dalga formunun açık süresinin toplam periyoduna oranıdır. Örneğin, bir 50% duty cycle, kare dalga formunun yarısı açık, yarısı kapalı olacaktır. SPWM'de, sinüs dalga formunun pik noktası belirlenerek, kare dalga formunun duty cycle'ı ayarlanır.
Sinüs dalga formunun pik noktasına göre kare dalga formunun duty cycle'ı, sinüs dalga formunun belirli bir noktasında %100 olarak ayarlanır. Daha sonra, sinüs dalga formunun diğer noktalarında, kare dalga formunun duty cycle'ı, sinüs dalga formunun genliği ile orantılı olarak azaltılır. Bu, kare dalga formunun genişliklerinin, sinüs dalga formunun genliklerine uygun şekilde değiştirilmesine yol açar.
Bu işlem, sinüs dalga formunun bir periyodunda birden fazla kare dalga formu oluşturulmasını sağlar. Bu kare dalga formları, sinüs dalga formunun belirli bir frekansında oluşur ve birçok farklı frekansta kullanılabilir. Bu, çıkış dalga formunun doğrusallığı ve çözünürlüğünü belirler.
TMS32 ile SPWM Uygulaması


Öncelikle MATLAB yardımı ile 0 ila 2π arasında bir sinüs fonksiyonunu örnekleyerek, bu fonksiyonun değerlerini 0 ila 1 arasına sıkıştıran bir sinüs tablosu oluşturalım. Bunun yerine bir sinyal jeneratörü yardımıyla ADC kullanarak da bu sinüs dizisini oluşturabilirsiniz.

TI kodları sayfanın en aşağısında verilmiştir. Dilerseniz kodun önemli kısımlarına göz atalım. Aşağıdaki görselde Sinüs tablosundan alınan değerlerin uygulama için belirlenen TBPRD (Timer Base Period) ile ölçeklendiği görülmektedir.
TI TMS32F28 mikrodenetleyicileri için PWM ayarlamaları şu şekilde özetlenebilir:
PWM Frekansı = EPWM_clk / (2 * TBPRD * CLKDIV * HSPCLKDIV)
PWM Duty cycle ayarları ise TBPRD'ye bağlı olarak CMPA (ComparatorX) ' göre ayarlanır. Örneğin:
BPRD = 5000 CMPA=2500 -> duty cycle %50

SPWM uygulamasında sinüs dalgasının pik değeri %100 duty cycle gibi düşünülür ve TBPRD'ye göre ölçeklenir.

Ölçeklenen her değer yani CMPA değerleri bir interrupt içinde alınan örnek sayısı kadar güncellenir.

Bu uygulamada PWM frekansı 10kHz ve alınan örneklem 200 adet olduğu için:
sinüs frekansı = 10000/200 = 50Hz
Elde edilen SPWM aşağıdaki gibidir. SPWM sinyaline bir Low Pass filtre uyguladığınızda 50 hz'lik sinüs sinyalinizi elde edebilirsiniz.



Kodlar
/* * ################################# NOTLAR ########################################### * PWM frekansini TBPRD ayarlar * PWM Frekansı = EPWM_clk / (2 * TBPRD * CLKDIV) * PWM Frekansı = 90 MHz / (2 * 5000 * 1) = 9 kHz * * CMPA duty cyce i ayarlar * ornegin TBPRD = 5000 CMPA=2500 -> duty cycle %50 * ornegin TBPRD = 5000 CMPA=3750 -> duty cycle %25 * ornegin TBPRD = 5000 CMPA=1250 -> duty cycle %75 * #################################################################################### */ /* MATLAB sin tablosu * clc;clear all; close all; n = 200; % örnek sayısı theta = linspace(0, 2*pi, n+1); % 0'dan 2*pi'ye kadar n+1 adet noktayı paylaştırır theta = theta(1:n); % son noktayı kaldırır sin_tablosu = ((sin(theta)+1)/2) % sinüs fonksiyonunun değerlerini 0-1 aralığına sıkıştırır */ double sinTablosu[200] = {0.5000, 0.5157, 0.5314, 0.5471, 0.5627, 0.5782, 0.5937, 0.6091, 0.6243, 0.6395, 0.6545, 0.6694, 0.6841, 0.6986, 0.7129, 0.7270, 0.7409, 0.7545, 0.7679, 0.7810, 0.7939, 0.8065, 0.8187, 0.8307, 0.8423, 0.8536, 0.8645, 0.8751, 0.8853, 0.8951, 0.9045, 0.9135, 0.9222, 0.9304, 0.9382, 0.9455, 0.9524, 0.9589, 0.9649, 0.9704, 0.9755, 0.9801, 0.9843, 0.9880, 0.9911, 0.9938, 0.9961, 0.9978, 0.9990, 0.9998, 1, 0.9998, 0.9990, 0.9978, 0.9961, 0.9938, 0.9911, 0.9880, 0.9843, 0.9801, 0.9755, 0.9704, 0.9649, 0.9589, 0.9524, 0.9455, 0.9382, 0.9304, 0.9222, 0.9135, 0.9045, 0.8951, 0.8853, 0.8751, 0.8645, 0.8536, 0.8423, 0.8307, 0.8187, 0.8065, 0.7939, 0.7810, 0.7679, 0.7545, 0.7409, 0.7270, 0.7129, 0.6986, 0.6841, 0.6694, 0.6545, 0.6395, 0.6243, 0.6091, 0.5937, 0.5782, 0.5627, 0.5471, 0.5314, 0.5157, 0.5000, 0.4843, 0.4686, 0.4529, 0.4373, 0.4218, 0.4063, 0.3909, 0.3757, 0.3605, 0.3455, 0.3306, 0.3159, 0.3014, 0.2871, 0.2730, 0.2591, 0.2455, 0.2321, 0.2190, 0.2061, 0.1935, 0.1813, 0.1693, 0.1577, 0.1464, 0.1355, 0.1249, 0.1147, 0.1049, 0.0955, 0.0865, 0.0778, 0.0696, 0.0618, 0.0545, 0.0476, 0.0411, 0.0351, 0.0296, 0.0245, 0.0199, 0.0157, 0.0120, 0.0089, 0.0062, 0.0039, 0.0022, 9.8664e-04, 2.4672e-04, 0, 2.4672e-04, 9.8664e-04, 0.0022, 0.0039, 0.0062, 0.0089, 0.0120, 0.0157, 0.0199, 0.0245, 0.0296, 0.0351, 0.0411, 0.0476, 0.0545, 0.0618, 0.0696, 0.0778, 0.0865, 0.0955, 0.1049, 0.1147, 0.1249, 0.1355, 0.1464, 0.1577, 0.1693, 0.1813, 0.1935, 0.2061, 0.2190, 0.2321, 0.2455, 0.2591, 0.2730, 0.2871, 0.3014, 0.3159, 0.3306, 0.3455, 0.3605, 0.3757, 0.3909, 0.4063, 0.4218, 0.4373, 0.4529, 0.4686, 0.4843}; double sinTablosu2[256] = {0.5, 0.5123, 0.5245, 0.5368, 0.549, 0.5612, 0.5734, 0.5855, 0.5975, 0.6096, 0.6215, 0.6334, 0.6451, 0.6568, 0.6684, 0.6799, 0.6913, 0.7026, 0.7138, 0.7248, 0.7357, 0.7464, 0.7571, 0.7675, 0.7778, 0.7879, 0.7978, 0.8076, 0.8172, 0.8266, 0.8358, 0.8448, 0.8536, 0.8621, 0.8705, 0.8786, 0.8865, 0.8942, 0.9016, 0.9088, 0.9157, 0.9224, 0.9289, 0.935, 0.941, 0.9466, 0.952, 0.9571, 0.9619, 0.9665, 0.9708, 0.9748, 0.9785, 0.9819, 0.985, 0.9879, 0.9904, 0.9926, 0.9946, 0.9962, 0.9976, 0.9986, 0.9994, 0.9998, 1, 0.9998, 0.9994, 0.9986, 0.9976, 0.9962, 0.9946, 0.9926, 0.9904, 0.9879, 0.985, 0.9819, 0.9785, 0.9748, 0.9708, 0.9665, 0.9619, 0.9571, 0.952, 0.9466, 0.941, 0.935, 0.9289, 0.9224, 0.9157, 0.9088, 0.9016, 0.8942, 0.8865, 0.8786, 0.8705, 0.8621, 0.8536, 0.8448, 0.8358, 0.8266, 0.8172, 0.8076, 0.7978, 0.7879, 0.7778, 0.7675, 0.7571, 0.7464, 0.7357, 0.7248, 0.7138, 0.7026, 0.6913, 0.6799, 0.6684, 0.6568, 0.6451,0.6334, 0.6215, 0.6096, 0.5975, 0.5855, 0.5734, 0.5612, 0.549, 0.5368, 0.5245, 0.5123, 0.5, 0.4877, 0.4755, 0.4632, 0.451, 0.4388, 0.4266, 0.4145, 0.4025, 0.3904, 0.3785, 0.3666, 0.3549, 0.3432, 0.3316, 0.3201, 0.3087, 0.2974, 0.2862, 0.2752, 0.2643, 0.2536, 0.2429, 0.2325, 0.2222, 0.2121, 0.2022, 0.1924, 0.1828, 0.1734, 0.1642, 0.1552, 0.1464, 0.1379, 0.1295, 0.1214, 0.1135, 0.1058, 0.0984, 0.0912, 0.0843, 0.0776, 0.0711, 0.065, 0.059, 0.0534, 0.048, 0.0429, 0.0381, 0.0335, 0.0292, 0.0252, 0.0215, 0.0181, 0.015, 0.0121, 0.0096, 0.0074, 0.0054, 0.0038, 0.0024, 0.0014, 0.0006, 0.0002, 0, 0.0002, 0.0006, 0.0014, 0.0024, 0.0038, 0.0054, 0.0074, 0.0096, 0.0121, 0.015, 0.0181, 0.0215, 0.0252, 0.0292, 0.0335, 0.0381, 0.0429, 0.048, 0.0534, 0.059, 0.065, 0.0711, 0.0776, 0.0843, 0.0912, 0.0984, 0.1058, 0.1135, 0.1214, 0.1295, 0.1379, 0.1464, 0.1552, 0.1642, 0.1734, 0.1828, 0.1924, 0.2022, 0.2121, 0.2222, 0.2325, 0.2429, 0.2536, 0.2643, 0.2752, 0.2862, 0.2974, 0.3087, 0.3201,0.3316, 0.3432, 0.3549, 0.3666, 0.3785, 0.3904, 0.4025, 0.4145, 0.4266, 0.4388, 0.451, 0.4632, 0.4755, 0.4877}; int i,j,k; #include "DSP28x_Project.h" // epwm struct typedef struct{ volatile struct EPWM_REGS *EPwmRegHandle; Uint16 EPwm_CMPA_Direction; Uint16 EPwm_CMPB_Direction; Uint16 EPwmTimerIntCount; Uint16 EPwmMaxCMPA; Uint16 EPwmMinCMPA; Uint16 EPwmMaxCMPB; Uint16 EPwmMinCMPB; } EPWM_INFO; EPWM_INFO epwm_info; // prototypes void Config_PWM(void); __interrupt void epwm1_isr(void); void main(void){ // init-------------------------- InitSysCtrl(); InitEPwm1Gpio(); DINT; InitPieCtrl(); IER=0x0000; IFR=0x0000; InitPieVectTable(); //------------------------------- EALLOW; PieVectTable.EPWM1_INT = &epwm1_isr; EDIS; EALLOW; SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 0; // Time Base Clock Disable EDIS; Config_PWM(); EALLOW; SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 1; // Time Base Clock Enable EDIS; // INT Config IER |= M_INT3; PieCtrlRegs.PIEIER3.bit.INTx1 = 1; EINT; ERTM; // olceklendirme for ( j = 0; j PWM Frekansini ayarlar EPwm1Regs.TBPHS.half.TBPHS = 0x0000; // Cikis fazi = 0 EPwm1Regs.TBCTR = 0x0000; // Time Base Conter = 0 // Compare Config EPwm1Regs.CMPA.half.CMPA = 3750; // cmpa_min =2500 -> duty cylei ayarlar // Counter Config EPwm1Regs.TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN; // updown count EPwm1Regs.TBCTL.bit.PHSEN = TB_DISABLE; // disable phase loading EPwm1Regs.TBCTL.bit.HSPCLKDIV = TB_DIV1; EPwm1Regs.TBCTL.bit.CLKDIV = TB_DIV1; // Shadow Config EPwm1Regs.CMPCTL.bit.SHDWAMODE = CC_SHADOW; EPwm1Regs.CMPCTL.bit.LOADAMODE = CC_CTR_ZERO; // Action Qualifier Config EPwm1Regs.AQCTLA.bit.CAU = AQ_SET; // Set PWM1A on event A, up count EPwm1Regs.AQCTLA.bit.CAD = AQ_CLEAR; // Clear PWM1A on event A, down count // Interrupt where we will change the Compare Values EPwm1Regs.ETSEL.bit.INTSEL = ET_CTR_ZERO; // Select INT on Zero event EPwm1Regs.ETSEL.bit.INTEN = 1; // Enable INT EPwm1Regs.ETPS.bit.INTPRD = ET_1ST; // Generate INT on 1rd event epwm_info.EPwm_CMPA_Direction = 1; //EPWM_CMP_UP = 1 || EPWM_CMP_DOWN = 0 epwm_info.EPwmTimerIntCount = 0; // Zero the interrupt counter epwm_info.EPwmRegHandle = &EPwm1Regs; epwm_info.EPwmMaxCMPA = 3750; epwm_info.EPwmMinCMPA = 2500; } __interrupt void epwm1_isr(void){ // Kesme sayacını artır epwm_info.EPwmTimerIntCount++; // Duty Cycle kontrolü için PWM görevlerini ayarla epwm_info.EPwmMaxCMPA = sinTablosu[epwm_info.EPwmTimerIntCount]; // PWM görevlerini güncelle epwm_info.EPwmRegHandle->CMPA.half.CMPA = epwm_info.EPwmMaxCMPA; // Kesme işaretleyicisini temizle EPwm1Regs.ETCLR.bit.INT = 1; // Gerektiği gibi sıfırla if (epwm_info.EPwmTimerIntCount == 200) { epwm_info.EPwmTimerIntCount = 0; } // ACK kesme işaretleyicisini PieCtrlRegs.PIEACK.all = PIEACK_GROUP3; }