Sıfırdan STM32F0 Dersleri – Clock Ayarları ve GPIO Kullanımı
Giriş 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. } }
Son yorumlar