Sıfırdan STM32F0 Dersleri – Clock Ayarları ve GPIO Kullanımı

stm32f0discoveryGiriş kısmından sonra bu yazıda işlemcimizin çalışma frekansı ayarlarını yaptıktan sonra GPIO kullanımını anlatacağım.Öncelikle yapmamız gereken projemizin src klasörü altında bulunan src\system_stm32f0xx.c dosyasını açıp RCC(Reset And Clock Cofiguration) ayarlarını yapmak.Burada yapacağımız ayar işlemcimizin harici mi(HSE = High Speed External – Yüksek Hızlı Harici) yoksa dahili(HSI = High Speed Internal – Yüksek hızlı Dahili) kristalden mi çalışacağını belirtmek.Biz HSI ya göre ayarları yapacağız çünkü STM32F0 Discovery kitte harici kristal takılı değil.Fakat pinler mevcut isterseniz siz lehimleyebilirsiniz.(8MHz)
Şimdi system_stm32f0xx.c dosyasında gerekli tanımlamaları yapalım.Öncelikle PLL kaynağımızı belirten bir makro tanımlayalım.Biz HSI tanımlamasını aktif ediyoruz.

#define PLL_SOURCE_HSI // HSI (~8MHz) used to clock the PLL, and the PLL is used as system clock source
//#define PLL_SOURCE_HSE // HSE (8MHz) used to clock the PLL, and the PLL is used as system clock source
//#define PLL_SOURCE_HSE_BYPASS

Clock ayarları SetSysClock fonksiyonunda yapılıyor.

static void SetSysClock(void)
{
__IO uint32_t StartUpCounter = 0, HSEStatus = 0;
/* SYSCLK, HCLK, PCLK configuration ----------------------------------------*/
#if defined (PLL_SOURCE_HSI)
/* At this stage the HSI is already enabled */
/* Enable Prefetch Buffer and set Flash Latency */
FLASH->ACR = FLASH_ACR_PRFTBE | FLASH_ACR_LATENCY;
/* HCLK = SYSCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
/* PCLK = HCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE_DIV1;
/* PLL configuration = (HSI/2) * 12 = ~48 MHz */
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL));
RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSI_Div2 | RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLMULL12);
/* Enable PLL */
RCC->CR |= RCC_CR_PLLON;
/* Wait till PLL is ready */
while((RCC->CR & RCC_CR_PLLRDY) == 0)
{
}
/* Select PLL as system clock source */
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;
/* Wait till PLL is used as system clock source */
while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)RCC_CFGR_SWS_PLL)
{
}
#else
#if defined (PLL_SOURCE_HSE)
/* Enable HSE */
RCC->CR |= ((uint32_t)RCC_CR_HSEON);
#elif defined (PLL_SOURCE_HSE_BYPASS)
/* HSE oscillator bypassed with external clock */
RCC->CR |= (uint32_t)(RCC_CR_HSEON | RCC_CR_HSEBYP);
#endif /* PLL_SOURCE_HSE */
/* Wait till HSE is ready and if Time out is reached exit */
do
{
HSEStatus = RCC->CR & RCC_CR_HSERDY;
StartUpCounter++;
} while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
if ((RCC->CR & RCC_CR_HSERDY) != RESET)
{
HSEStatus = (uint32_t)0x01;
}
else
{
HSEStatus = (uint32_t)0x00;
}
if (HSEStatus == (uint32_t)0x01)
{
/* Enable Prefetch Buffer and set Flash Latency */
FLASH->ACR = FLASH_ACR_PRFTBE | FLASH_ACR_LATENCY;
/* HCLK = SYSCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
/* PCLK = HCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE_DIV1;
/* PLL configuration = HSE * 6 = 48 MHz */
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL));
RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_PREDIV1 | RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLMULL6);
/* Enable PLL */
RCC->CR |= RCC_CR_PLLON;
/* Wait till PLL is ready */
while((RCC->CR & RCC_CR_PLLRDY) == 0)
{
}
/* Select PLL as system clock source */
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;
/* Wait till PLL is used as system clock source */
while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)RCC_CFGR_SWS_PLL)
{
}
}
else
{ /* If HSE fails to start-up, the application will have wrong clock
configuration. User can add here some code to deal with this error */
}
#endif /* PLL_SOURCE_HSI */
}

Tabi her işlemciye göre register ayarları farklılık göstereceğinden bu kısma dikkat etmek de fayda var.Lakin başka bir işlemci kullanıyorsanız mesela STM32F4 olsun bu ayarlar farklılık gösterecektir. Bunun için datasheet den RCC ayarlarını takip ederek kendiniz yapacaksınız yada internetten HSI ya göre ayarlanmış system_stm32f0xx.c dosyasını bulacaksınız.İşlemcinin hız ayarları bu kadar artık uygulama yapmaya başlayabiliriz.

İşlemci hızı ve clock ayarlarını yaptıktan sonra artık GPIO fonksiyonları ile ilk ledi yakabiliriz.Öncelikle bir portu kullanabilmemiz için o porta Clock vermemiz gerekir.Bir nevi uyandırma enerjileme diyebiliriz.Bu kısımları SPL->src altında bulunan stm32f0xx_gpio.c dosyasını açıp en üstteki açıklamada “How to use this driver ” kısmından adımları takip ederek öğrenebiliriniz.

Bunun için RCC_AHBPeriphClockCmd fonksiyonu kullanılıyor.Tabi bu fonskiyonlar işlemciye göre değişebilir biz STM32F0 a göre ilerliyoruz.Bu fonksiyon 2 parametre alır.Bunlar port ismi ve durumdur.Biz A potunun 0.bitini High yapalım.

Port isimleri şu şekilde tanımlanmıştır.

#define RCC_AHBPeriph_GPIOA   RCC_AHBENR_GPIOAEN
#define RCC_AHBPeriph_GPIOB   RCC_AHBENR_GPIOBEN
#define RCC_AHBPeriph_GPIOC   RCC_AHBENR_GPIOCEN
#define RCC_AHBPeriph_GPIOD   RCC_AHBENR_GPIODEN
#define RCC_AHBPeriph_GPIOE   RCC_AHBENR_GPIOEEN /*!< Only applicable for STM32F072 devices */
#define RCC_AHBPeriph_GPIOF   RCC_AHBENR_GPIOFEN

Durum olarak ENABLE yani yazdığımız port’u clock vererek aktif hale getiriyoruz.

RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);

Şimdi yapmamız gereken bu portun ayarlarını yapmak. Bunun için bir struct tanımlıyoruz.

GPIO_InitTypeDef GPIO_InitStructure;

Bu yapıya ayarları yükleyeceğiz. Toplamda 5 ayar var.

  • GPIO_Pin,
  • GPIO_Mode
  • GPIO_Speed
  • GPIO_OType
  • GPIO_PuPd

GPIO_Pin : Hangi pinleri kullanacağımız seçmemize yarıyor.
Örneğin 0.biti kullanmak istesek şöyle yapacaktık;

//Bir pin için;
GPIO_InitTypeDef.GPIO_Pin = GPIO_Pin_0;

//Birden fazla pin için;
GPIO_InitTypeDef.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;

GPIO_Mode : Belirtilen pinlerin hangi modda çalışacağını ayarlıyor.4 Mod mevcut.
Giriş, Çıkış, AF, AN (Alternatif fonksiyon = SPI, UART vb, AN = Analog Giriş)

GPIO_Mode_IN  = 0x00  /*!< GPIO Input Mode */
GPIO_Mode_OUT = 0x01  /*!< GPIO Output Mode */
GPIO_Mode_AF  = 0x02  /*!< GPIO Alternate function Mode */
GPIO_Mode_AN  = 0x03  /*!< GPIO Analog Input Mode */

LED uygulaması için Çıkış seçiyoruz.

GPIO_InitTypeDef.GPIO_Mode = GPIO_Mode_OUT;

GPIO_Speed : Pinin çalışma frekansını belirler.

#define GPIO_Speed_2MHz  GPIO_Speed_Level_1   /*!< I/O output speed: Low 2 MHz */
#define GPIO_Speed_10MHz GPIO_Speed_Level_2  /*!< I/O output speed: Medium 10 MHz */
#define GPIO_Speed_50MHz GPIO_Speed_Level_3

Başlangıç için 2 Mhz verebiliriz. Unutmayın yüksek hız yüksek enerji tüketimi !

GPIO_InitTypeDef.GPIO_Speed = GPIO_Speed_2MHz;

GPIO_OType : Çıkış bağlantısı denenebilir. Output open-drain: Pinin çıkış bacağı, P-Mos ile N-Mos mosfetleri arasında bulunmaktadır.Eğer çıkışı open-drain ayarlarsanız, pin bacağı GND’ye bağlanır. VDD ile arasında sonsuz empedans oluşur.Bu durumda pini high olarak çıkış vermek için dışarıdan pull-up dirençleri eklemeniz gerekmekte. Bu özellikle, çıkışa bağlanacak olan devre elemanının daha fazla akım çekmesi sağlanabilmektedir. Röle gibi akım gerektiren devre elemanlarını sürmek için kullanılır. Akım mikroişlemciden değil, pull-up direnci üzerinden çekilir. Output push-pull: Pin bacağı P-Mos mosfeti ile VDD pinine bağlanır. Akım gerektirmeyen işlemlerde, çıkışı logik 1 yapmak için bu mod kullanılır. Yüksek akım gerektirmediğinden PP = Push-Pull kullanıyoruz.

GPIO_InitStructure.GPIO_OType  = GPIO_OType_PP;

Son olarak GPIO_PuPd : Çıkışa dahili olarak Pull-Up yada Pull-Down direnci eklememizi sağlıyor.Örneğin buton kullanımların da işimize yarayacak bir özellik.Ama şuan için gerek yok.

3 Değeri vardır;

GPIO_PuPd_NOPULL= 0x00 //dahili direnç kapalı
GPIO_PuPd_UP = 0x01 //dahili pull up
GPIO_PuPd_DOWN = 0x02 //dahili pull down

Ve son olarak dahili direnç seçmiyoruz.

GPIO_InitStructure.GPIO_PuPd   = GPIO_PuPd_NOPULL;

Şimdi bu ayarların bulunduğu structure’ın adresini kullanacağımız porta göndermemiz gerekiyor.Bunun için GPIO_Init fonksiyonu ile ayarları porta yüklüyoruz.Tabi ayarları yüklemek için pointer adresini veriyoruz.
1.Parametre : Port, 2.Parametre : Structure adresi

GPIO_Init(GPIOA,&GPIO_InitStructure);

Pin artık işleme hazır.Şimdi bu pine seri olarak 220 Ohm direnç ile bağlı olan ledi high yapalım.

// GPIO_SetBits(GPIOA,  GPIO_Pin_0); //A0 High(SET-1) yapılır.
// GPIO_ResetBits(GPIOA,GPIO_Pin_0); //A0 Low(RESET-0) yapılır.
  
#include "stm32f0xx_conf.h"

int main(void)
{
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA,ENABLE);

	GPIO_InitTypeDef GPIO_InitStructure;

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;

	GPIO_Init(GPIOA,&GPIO_InitStructure);

	GPIO_SetBits(GPIOA,GPIO_Pin_0);

	while(1)
	{
	}
}

Şimdi buton kullanımı işleyelim.Butona bastığımızda yanan bıraktığımızda sönen LED uygulaması yapalım.
Öncelikle Clock ayarlarını kontrol edelim.Daha sonra main dosyamızda LED ve buton ayarlarını yapmaya başlayalım.Öncelikle LED için önceki uygulamadaki kodları kullanabiliriz.Öncelikle şunu belirtmekte fayda var.Bu kitte kullanabileceğimiz 2 tane LED ve 1 tanede buton mevcut.Kitin şemasıan bakarak bunları hangi pine denk geldiklerini görebiliriz.Buton A portunun 0.bitinde bulunuyor.Bu pini giriş olarak seçip pull-down olarak ayarlıyoruz.Ayarları yapıyoruz daha sonra C portunun 8.bitin deki mavi renkli ledi çıkış yapıyoruz.Bu uygulamada 2 port kullanıldığından A ve C portlarına clock vermeyi de unutmuyoruz.

#include "stm32f0xx_conf.h"

void main(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;

    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE);

    GPIO_InitStructure.GPIO_Pin     = GPIO_Pin_0;
    GPIO_InitStructure.GPIO_Mode    = GPIO_Mode_IN;
    GPIO_InitStructure.GPIO_OType   = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd    = GPIO_PuPd_NOPULL;
    GPIO_InitStructure.GPIO_Speed   = GPIO_Speed_Level_1;

    GPIO_Init(GPIOA, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin     = GPIO_Pin_8;	// LED çıkış yapıldı
    GPIO_InitStructure.GPIO_Mode    = GPIO_Mode_OUT;
    GPIO_InitStructure.GPIO_OType   = GPIO_OType_PP; 
    GPIO_InitStructure.GPIO_PuPd    = GPIO_PuPd_NOPULL;
    GPIO_InitStructure.GPIO_Speed   = GPIO_Speed_Level_1;

    GPIO_Init(GPIOC, &GPIO_InitStructure);

    while(1)
    {
        if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0)) // GPIOA(A portunun) 0 nolu pini tru mu ? (Butona basıldı mı ?) 
            GPIO_SetBits(GPIOC, GPIO_Pin_8);// LED'i yak.
        else
            GPIO_ResetBits(GPIOC, GPIO_Pin_8);//Hayır ise LED'i söndür.
    }
}

 

 

You may also like...

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir