Friday, April 25, 2014

STM32F103 ile PWM kullanımı

STM32F103  serisi ile iki kanal  PWM uygulama örneği gerçekleştireceğiz.

Uygulamayı CooCox ide ile gerçekleştireceğim. Proje oluşturma adımları , GPIO uygulamasındakine benzer.

PWM çıkışı için Timer3 ve PC6 ve PC7 pinlerini kullanacağım.

PWM kanallarını 4Khz bir sinyal ile süreceğim.
Kanallar bir birine simetrik bir şekilde 0-100 arasında değerlerde değişecek.

CH0  0  ->100 ->0
CH1  100->0 ->100

Her PWM kanalınada bir adet 12V fırçasız motor bağladım. ( Doğrudan mikro işlemci bacağına bağlı değil arada open collector bir transistör sürücü var )

Code kısmına gelince, Aşağıdaki gibi,


 /**  
  *****************************************************************************  
  * @title  EDS1 PWM TEST.c.c  
  * @author Veysel KARADAĞ  
  * @date  24.04.2014  
  * @brief  GPIO Example  
  *******************************************************************************  
  */  
 #include "stm32f10x_rcc.h"  
 #include "stm32f10x_gpio.h"  
 #include "stm32f10x_tim.h"  
 void confPWM(void);  
 void set_duty_PWM(int ch ,int duty);  
 void delay(long int tik);  
 int main(void)  
 {  
      int i=0;  
      int yon=0;  
      confPWM();  
   while(1)  
   {  
        delay(500000);  
        set_duty_PWM(0,i);  
        set_duty_PWM(1,100-i);  
        if(yon==0){  
             i++;  
        }else{  
             i--;  
        }  
        if(i==100){  
             yon=1;  
        }  
        if(i==0){  
             yon=0;  
        }  
   }  
 }  
 /*******************************************************************************  
 * Function Name : confPWM  
 * Description  : PWM 1-2 kanalı 4Khz kurar  
 *                      : PB0,PB1  
 * Input     : None  
 * Output     : None  
 * Return     : None  
 *******************************************************************************/  
 void confPWM(void){  
       GPIO_InitTypeDef GPIO_InitStructure;  
       TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;  
       TIM_OCInitTypeDef TIM_OCInitStruct;  
       RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO, ENABLE );  
       RCC_APB1PeriphClockCmd( RCC_APB1Periph_TIM3 , ENABLE );  
       GPIO_StructInit(&GPIO_InitStructure);                           // GPIO yapısını Resetler  
       GPIO_PinRemapConfig(GPIO_FullRemap_TIM3,ENABLE);  
       GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;       // Pin6 ve Pin7 Seçilir.  
       GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  
       GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;      // Push Pull olarak set edilmesi ayarlanır.  
       GPIO_Init( GPIOC, &GPIO_InitStructure );                          // GPIOC yukarıdaki ayarlara göre Set edildi.  
       // Let PWM frequency equal 100Hz.  
    // Let period equal 1000. Therefore, timer runs from zero to 1000. Gives 0.1Hz resolution.  
    // Solving for prescaler gives 18. ( Frekans = 72Mhz/1000/18)  
    TIM_TimeBaseStructInit( &TIM_TimeBaseInitStruct );  
    TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV4;  
    TIM_TimeBaseInitStruct.TIM_Period = 1000-1;                 // 0..999  
    TIM_TimeBaseInitStruct.TIM_Prescaler = 18-1;                     // Div 18-1  
    TIM_TimeBaseInit( TIM3, &TIM_TimeBaseInitStruct );  
    TIM_OCStructInit( &TIM_OCInitStruct );  
    TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;  
    TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;  
    TIM_OCInitStruct.TIM_Pulse = 500;                               // 0 .. 1000 (0=Herzaman kapalı , 1000= Herzaman Açık) %25  
    TIM_OC1Init( TIM3, &TIM_OCInitStruct );  
    TIM_OC2Init( TIM3, &TIM_OCInitStruct );  
    TIM_Cmd( TIM3, ENABLE );  
 }  
 /*******************************************************************************  
 * Function Name : set_duty_PWM  
 * Description  : setup duty cycle pwm cH0/1  
 * Input     : int ch and duty ( ch:0/1 duty 0-100)  
 * Output     : None  
 * Return     : None  
 *******************************************************************************/  
 void set_duty_PWM(int ch ,int duty){  
      switch(ch){  
      case 0:  
           TIM3->CCR1 = duty*10; // SET Duty CH0 %X  
      break;  
      case 1:  
           TIM3->CCR2 = duty*10; // SET Duty CH1 %X  
      break;  
      default :  
      break;  
      }  
 }  
 /*******************************************************************************  
 * Function Name : delay  
 * Description  : delay sistem tik  
 * Input     : long int delay tik  
 * Output     : None  
 * Return     : None  
 *******************************************************************************/  
 void delay(long int tik){  
      int i=0;  
      for (i=0;i<tik;i++);  
 }  



Program Çalıştığında PWM çıkışları aşağıdaki gibi oluyor. Video olan dosyada delay süresini biraz uzattım. Delay az olunca fanın yavaşladığı belli olmuyordu.








Thursday, April 24, 2014

STM32 Discovery / Atollic Suite Sample Project



Atollic TrueSTUDIO (TS) , GCC tabanlı Eclipse IDE kullanan , ARM mikroişlemciler için geliştirilmiş bir derleyici. Detaylı bilgileri aşağıdaki linkten bulabilirsiniz. 



Bu yazıda STM32VL Discovery ile UART ve LED leri kullanmak hakkında bir şeyler paylaşacağım.

Öncelikle TS programını Atollic web sayfasından indirip kurulumunu yapmamız gerekiyor. Kurulum ile ilgili dokümanlar Atollic web sayfasında var.

Yeni proje başlatmak için ,

File / New / C Project  seçiyoruz.

Gelen pencerede projemize isim verip, Embedded C Project ve Atollic ARM Tools seçiyoruz. Sonra NEXT..


Gelen pencereden (Build setting) , İşlemci , Development Board seçeneklerinden kendi boardumuzu seçiyoruz. Bu seçin sayesinde , derleyici işlemcimizin  ROM ve RAM yapısını , bazı start up dosyalarını hazırlıyor.  Eval board seçtiğimiz için board üzerindeki led button gibi pinler içinde gerekli dosyaları hazırlıyor.





Resimdeki seçenekleri işaretleyip Next diyoruz....

Bir sonraki pencere Debug ile ilgili araçları seçmemize yarıyor.  Discovery üzerinde  debugger olarak Stlink sabit olduğundan ST-Link Seçili olmalı.  Sonrasında yine Next diyoruz. Bir sonra gelen pencereyede next diyeceğiz.. Runtime library seçeneklerinde Use tiny printf... seçili olmalı.




TS , discovery board üzerinde User butonuna basıldığında Toggle yapan bir örnek programı ( Discovery Board ile gelen default Program) hazırlıyor.

Buid all yapıp derleme işleminden sonra , Debug yaparak programı STM32 Discovery board a yükleyip, kurulumun , ST link driverlarının doğru bir şekilde yapıldığını test edebilirsiniz.

TS , projeyi hazırlarken , başka eval boardlar ile ilgili tanımlamaları da #ifdef ifadeleri ile main dosyasına ekliyor. Yeni başlayanlar için kafa karıştırıcı geldi bana .. Bu yüzden ben gereksiz gördüğüm bu satırları sildim.  Proje dosyasını paylaşacağım için burda bütün kodu yazmıyorum. Kısaca Main.c dosyası aşağıdaki gibi oluyor.




#include <stddef.h>
#include "stm32f10x.h"
#include "STM32vldiscovery.h"  

// Değikenleri tanımla..

int main(void)
{

  // GPIO kur
  // USart Kur
  while (1)
  {
      // Program..

     }
}


İşlemcinin , hangi portun IO , hangi portun USART olduğunu anlayabilmesi için gerekli olan tanımlamalar. "STM32vldiscovery.h" dosyasında belirtilmekte. Bu dosyaya erişmek için sol CTRL tuşuna basılı tutup main.c dosyasında   üzerini tıklamanız yeterli olur.

"STM32vldiscovery.h" içeriğinde ise Discovery Board üzerinde bulunan Led ler ve buton için gerekli tanımlama satırlarını görebiliriz. Bu tanımlamalar , programda kullanmak isteğimiz tanımları ve buna karşılık Standart STM32 kütüphanelerinde olan karşılıklarını içeriyor.

Örneğin, Discovery üzerinde LED için ( yeşil olan) yapılmış tanımlamalar. PIN, port ve clok için , standart kütüphanede ( örn , stm32f10x_rcc.h) dosyasındaki karşılıklarını içeriyor.

#define LED3_PIN                         GPIO_Pin_9 
#define LED3_GPIO_PORT                   GPIOC
#define LED3_GPIO_CLK                    RCC_APB2Periph_GPIOC


STM32vldiscovery.h ve C dosyaları  TS tarafından , build setting adımında STM32VLDiscovery boardu seçtiğimiz için TS tarafından projeye eklendi.

STM32vldiscovery.h ve c dosylarında aynı zamanda GPIO hazırlamak ve kullanmak için gerekli olan tanımlamalar ve fonksiyonlar bulunmakta.

Main.c de bu fonksiyonları çağırarak. STM32 çevre birimlerini aktif hale getiriyoruz.

Seri Port , entegrasyonu içinse GPIO lar gibi bir hazırlama ve kullanma işlemleri gerekli. Discovery board üzerinde , donanım olarak bir RS232 port olmadığından TS seri port için gerekli tanımlamaları ve fonksiyonları STM32vldiscovery.h ve .c  dosyalarının içerisine eklemiyor.

Bu yüzden , benzer başka bir örnek projeyi açıp oradan gerekli satırları kopyaladım.  Bana en uygun olarak (STM3210E-EVAL_XL_USART_Printf) projesini uygun gördüm.  Bu projedeki, stm3210e_eval.h ve c dosylarını açtığımızda aşağıdaki tanımlamaları göreceğiz.


/** @addtogroup STM3210E_EVAL_LOW_LEVEL_COM
  * @{
  */
#define COMn                             2

/**
 * @brief Definition for COM port1, connected to USART1
 */
#define EVAL_COM1                        USART1
#define EVAL_COM1_CLK                    RCC_APB2Periph_USART1
#define EVAL_COM1_TX_PIN                 GPIO_Pin_9
#define EVAL_COM1_TX_GPIO_PORT           GPIOA
#define EVAL_COM1_TX_GPIO_CLK            RCC_APB2Periph_GPIOA
#define EVAL_COM1_RX_PIN                 GPIO_Pin_10
#define EVAL_COM1_RX_GPIO_PORT           GPIOA
#define EVAL_COM1_RX_GPIO_CLK            RCC_APB2Periph_GPIOA
#define EVAL_COM1_IRQn                   USART1_IRQn

/**
 * @brief Definition for COM port2, connected to USART2
 */
#define EVAL_COM2                        USART2
#define EVAL_COM2_CLK                    RCC_APB1Periph_USART2
#define EVAL_COM2_TX_PIN                 GPIO_Pin_2
#define EVAL_COM2_TX_GPIO_PORT           GPIOA
#define EVAL_COM2_TX_GPIO_CLK            RCC_APB2Periph_GPIOA
#define EVAL_COM2_RX_PIN                 GPIO_Pin_3
#define EVAL_COM2_RX_GPIO_PORT           GPIOA
#define EVAL_COM2_RX_GPIO_CLK            RCC_APB2Periph_GPIOA
#define EVAL_COM2_IRQn                   USART2_IRQn


/** @defgroup STM3210E_EVAL_LOW_LEVEL_Exported_Functions
  * @{
  */
void STM_EVAL_COMInit(COM_TypeDef COM, USART_InitTypeDef* USART_InitStruct);

stm3210e_eval.h dosyasındaki bu tanımlamaları, STM32vldiscovery.h içerisine ve
stm3210e_eval.c dosyasındaki ,aşağıdaki tanımları ve fonksiyonu  STM32vldiscovery.c dosyası içerisine kopyalıyoruz.


USART_TypeDef* COM_USART[COMn] = {EVAL_COM1, EVAL_COM2};

GPIO_TypeDef* COM_TX_PORT[COMn] = {EVAL_COM1_TX_GPIO_PORT, EVAL_COM2_TX_GPIO_PORT};

GPIO_TypeDef* COM_RX_PORT[COMn] = {EVAL_COM1_RX_GPIO_PORT, EVAL_COM2_RX_GPIO_PORT};

const uint32_t COM_USART_CLK[COMn] = {EVAL_COM1_CLK, EVAL_COM2_CLK};

const uint32_t COM_TX_PORT_CLK[COMn] = {EVAL_COM1_TX_GPIO_CLK, EVAL_COM2_TX_GPIO_CLK};

const uint32_t COM_RX_PORT_CLK[COMn] = {EVAL_COM1_RX_GPIO_CLK, EVAL_COM2_RX_GPIO_CLK};

const uint16_t COM_TX_PIN[COMn] = {EVAL_COM1_TX_PIN, EVAL_COM2_TX_PIN};

const uint16_t COM_RX_PIN[COMn] = {EVAL_COM1_RX_PIN, EVAL_COM2_RX_PIN};


/**
  * @brief  Configures COM port.
  * @param  COM: Specifies the COM port to be configured.
  *   This parameter can be one of following parameters:   
  *     @arg COM1
  *     @arg COM2 
  * @param  USART_InitStruct: pointer to a USART_InitTypeDef structure that
  *   contains the configuration information for the specified USART peripheral.
  * @retval None
  */
void STM_EVAL_COMInit(COM_TypeDef COM, USART_InitTypeDef* USART_InitStruct)
{
  GPIO_InitTypeDef GPIO_InitStructure;

  /* Enable GPIO clock */
  RCC_APB2PeriphClockCmd(COM_TX_PORT_CLK[COM] | COM_RX_PORT_CLK[COM] | RCC_APB2Periph_AFIO, ENABLE);

  /* Enable UART clock */
  if (COM == COM1)
  {
    RCC_APB2PeriphClockCmd(COM_USART_CLK[COM], ENABLE);
  }
  else
  {
    RCC_APB1PeriphClockCmd(COM_USART_CLK[COM], ENABLE);
  }

  /* Configure USART Tx as alternate function push-pull */
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_InitStructure.GPIO_Pin = COM_TX_PIN[COM];
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(COM_TX_PORT[COM], &GPIO_InitStructure);

  /* Configure USART Rx as input floating */
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  GPIO_InitStructure.GPIO_Pin = COM_RX_PIN[COM];
  GPIO_Init(COM_RX_PORT[COM], &GPIO_InitStructure);

  /* USART configuration */
  USART_Init(COM_USART[COM], USART_InitStruct);
   
  /* Enable USART */
  USART_Cmd(COM_USART[COM], ENABLE);
}

Kopyalama işlemleri bittikten sonra , main.c içerisinde Ledleri ve USART birimini STM32vldiscovery_LEDIni() ve  STM_EVAL_COMInit(COM1, &USART_InitStructure) fonksiyonlarını kullanarak hazırlıyoruz.



Daha sonra PA9 ve PA10 pinlerine bağladığımı Level Transreciver devresi ile STM32VL Discovery boardumuzdan Bilgisayarımıza bağlıyoruz. Hyper Terminal penceresinde , i değişkeninin butona bastığımız andaki değerini seri porta göndermekte.  

Programda , printf fonksiyonunu da kullanabiliyoruz. Programımız içerisinde bununla ilgili tanımlamaları Atollic project wizardı kullanırken runtime library seçeneklerinde tiny printfin işaretli olması lazım. Proje dosyasını linkten indirebilir siniz.

 Proje Dosyası,