Nuvoton M23 core ARM işlemcisinin herhangi bir GPIO'sunun output ve input olarak nasıl kurulacağını bu yazımızda basitçe anlatmaya çalıştık.
GPIO Clock Modülünün Aktif Edilmesi
Kullanılacak olan GPIO pininin her ARM işlemcide olduğu gibi Nuvoton ARM işlemcisinde de clock sinyalinin açık olması gerekir. Bunun için aşağıdaki fonksiyon kullanılarak clock özelliği açılır. Kullanılmayan GPIO portlarının clock sinyalini kapatmak işlemcinin power tüketimini azaltacaktır.
Biz anlatımımızda PB portunun 14 nolu pinini yani PB.14'i kullanacağız.
CLK_EnableModuleClock(GPB_MODULE);
Bu fonksiyon ile PB portunun clock kaynağı aktif edilir.
Bu fonksiyon tüm çevresel birimlerin clock kaynaklarını aktif hale getirmek için kullanılır. Fonksiyon içine bakacak olursanız hangi modüllerin yönetilebileceğinin listesini görebilirsiniz.
/**
* @brief This function enable module clock
* @param[in] u32ModuleIdx is module index. Including :
* - \ref PDMA_MODULE
* - \ref ISP_MODULE
* - \ref EBI_MODULE
* - \ref EXST_MODULE
* - \ref CRC_MODULE
* - \ref FMCIDLE_MODULE
* - \ref GPA_MODULE
* - \ref GPB_MODULE
* - \ref GPC_MODULE
* - \ref GPD_MODULE
* - \ref GPE_MODULE
* - \ref GPF_MODULE
* - \ref WDT_MODULE
* - \ref WWDT_MODULE
* - \ref RTC_MODULE
* - \ref TMR0_MODULE
* - \ref TMR1_MODULE
* - \ref TMR2_MODULE
* - \ref TMR3_MODULE
* - \ref CLKO_MODULE
* - \ref ACMP01_MODULE
* - \ref I2C0_MODULE
* - \ref I2C1_MODULE
* - \ref QSPI0_MODULE
* - \ref SPI0_MODULE
* - \ref UART0_MODULE
* - \ref UART1_MODULE
* - \ref UART2_MODULE
* - \ref USBD_MODULE
* - \ref EADC_MODULE
* - \ref TK_MODULE
* - \ref SC0_MODULE
* - \ref USCI0_MODULE
* - \ref USCI1_MODULE
* - \ref USCI2_MODULE
* - \ref DAC_MODULE
* - \ref LCD_MODULE
* - \ref PWM0_MODULE
* - \ref PWM1_MODULE
* - \ref BPWM0_MODULE
* - \ref BPWM1_MODULE
* - \ref OPA_MODULE
* - \ref PSIO_MODULE
* @return None
* @details This function enable module clock.
*/
Clock özelliğini kapatmak için
CLK_DisableModuleClock(GPB_MODULE);
kullanılır.GPIO Pinin Çıkış Olarak Kurulması
GPIO pini çıkış olarak kurmak için aşağıdaki fonksiyon kullanılır. Biz anlatımımızda PB portunun 14 nolu pinini yani PB.14'i kullanacağız.
GPIO_SetMode(PB, BIT14, GPIO_MODE_OUTPUT);
Fonksiyon üç adet parametre ile kullanılır. Sırasıyla Port ismi, portun hangi pini olduğu ve çıkış özelliği.
Çıkış olarak kurmak için " GPIO_MODE_OUTPUT" parametresi kullanılır.
Çıkışı Open-Drain çıkış olarak kullanmak istiyorsanız aşağıdaki gibi kurulum yapabilirsiniz.
GPIO_SetMode(PB, BIT14, GPIO_MODE_OPEN_DRAIN);
Çıkış Olarak Kurulmuş Olan Pinin Kontrolü
Çıkış olarak kurulmuş olan pini lojik "1" veya lojik "0" yapmak için öncelikle pine #define ile bir isim veriyoruz.
#define Out_Pin PB14
Şimdi pini lojik "1" yapmak için tanımlamamızı kullanıyoruz.
Out_Pin = 1;
veya lojik "0" yapmak için
Out_Pin = 0;
dememiz yeterli olur.
Örnek Uygulama
#define Out_Pin PB14
CLK_EnableModuleClock(GPB_MODULE); // clock enable
GPIO_SetMode(PB, BIT14, GPIO_MODE_OUTPUT); // output enable
Out_Pin = 1; // output logic 1
Out_Pin = 0; // output logic 0
GPIO Pininin Giriş Olarak Kurulması
GPIO pini giriş olarak kurmak için aşağıdaki fonksiyon kullanılır.
GPIO_SetMode(PB, BIT14, GPIO_MODE_INPUT);
Fonksiyon üç adet parametre ile kullanılır. Sırasıyla Port ismi, portun hangi pini olduğu ve giriş özelliği.
Giriş olarak kurmak için " GPIO_MODE_INPUT" parametresi kullanılır.
GPIO_SetMode(PB, BIT14, GPIO_MODE_INPUT);
Giriş Olarak Kurulan Pinin Pull-Up/Down Dirençlerinin Ayarlanması
Giriş olarak kurulan GPIO pini Pull dirençleri aşağıdaki değerler ile ayarlanabilir. İşlemci içerisinde bulunan pull-up/down direnç değerleri 50KOhm değerindedir.
GPIO_PUSEL_DISABLE
Bu parametre kullanılırak giriş pininde pull-up veya pull-down özelliği kaldırılır.
GPIO_PUSEL_PULL_UP
Bu parametre kullanılarak giriş pini işlemci beslemesine işlemci içerisinde bulunan direnç ile bağlanır.
GPIO_PUSEL_PULL_DOWN
Bu parametre kullanılarak giriş pini işlemci GND'sine işlemci içerisinde bulunan direnç ile bağlanır.
GPIO_SetPullCtl(PB, BIT14, GPIO_PUSEL_DISABLE);
GPIO_SetPullCtl(PB, BIT14, GPIO_PUSEL_PULL_UP);
GPIO_SetPullCtl(PB, BIT14, GPIO_PUSEL_PULL_DOWN);
Giriş Pininin Interrupt Olmadan Kullanımı
PB.14 pinini pull-up özelliği ile giriş olarak ayarlayan program parçacığı aşağıdaki gibi olacaktır.
#define Giris_Pin PB14
CLK_EnableModuleClock(GPB_MODULE); // clock enable
GPIO_SetMode(PB, BIT14, GPIO_MODE_INPUT); // PB.14 input
GPIO_SetPullCtl(PB, BIT14, GPIO_PUSEL_PULL_UP); // pull-up resistor enable
if(Giris_Pin == 0){
printf("Giris pini lojik 0 yapildi\r\n");
}
PB.14 pinini pull-down özelliği ile giriş olarak ayarlayan program parçacığı aşağıdaki gibi olacaktır.
#define Giris_Pin PB14
CLK_EnableModuleClock(GPB_MODULE); // clock enable
GPIO_SetMode(PB, BIT14, GPIO_MODE_INPUT); // PB.14 input
GPIO_SetPullCtl(PB, BIT14, GPIO_PUSEL_PULL_DOWN); // pull-down resistor enable
if(Giris_Pin) {
printf("Giris pini lojik 1 yapildi\r\n");
}
Giriş Pininin Interrupt Özelliği ile Kullanımı
PB.14 pinini interrupt özelliği ile kuralım.
#define Giris_Pin PB14
CLK_EnableModuleClock(GPB_MODULE); // clock enable
Burada "multi function register" ayarını yapmamız gerekiyor.
SYS->GPB_MFPH = (SYS->GPB_MFPH & ~(SYS_GPB_MFPH_PB14MFP_Msk)) | (SYS_GPB_MFPH_PB14MFP_GPIO);
Interrupt olarak ;
GPIO_INT_RISING : Yükselen kenar
GPIO_INT_FALLING : Düşen kenar
GPIO_INT_BOTH_EDGE : Hem düşen kenar hem yükselen kenar
GPIO_INT_HIGH : Lojik 1 durumunda
GPIO_INT_LOW : Lojik 0 durumunda
Kurulumu yapabiliyourz.
Biz bu örnekte pini pull-up olarak kuracağımızdan dolayı interrupt özelliğini de düşen kenar (falling edge) olarak kuracağız.
GPIO_EnableInt(PB, 14, GPIO_INT_FALLING);
GPIO_SetPullCtl(PB, BIT14, GPIO_PUSEL_PULL_UP); // pull-up resistor enable
Şimdi interrupt özelliğini açalım.
NVIC_EnableIRQ(GPB_IRQn);
Örnek kodumuz aşağıdaki gibi oluştu.
#define Giris_Pin PB14
uint8_t Flag = 0;
CLK_EnableModuleClock(GPB_MODULE); // clock enable
SYS->GPB_MFPH = (SYS->GPB_MFPH & ~(SYS_GPB_MFPH_PB14MFP_Msk))| (SYS_GPB_MFPH_PB14MFP_GPIO);
GPIO_EnableInt(PB, 14, GPIO_INT_FALLING);
GPIO_SetPullCtl(PB, BIT14, GPIO_PUSEL_PULL_UP); // pull-up resistor enable
NVIC_EnableIRQ(GPB_IRQn);
// PB.14 pinini lojik "0" yaptığımızda program bu fonksiyona gelecektir
void GPB_IRQHandler(void) {
uint32_t Temp_intsrc;
if (GPIO_GET_INT_FLAG(PB, BIT14)) {
/* Check if PB.14 the interrupt occurred */
Flag = 1;
/* Clear PB.14 interrupt flag */
GPIO_CLR_INT_FLAG(PB, BIT14);
} else {
/* Un-expected interrupt. Just clear all PB interrupts */
Temp_intsrc = PB->INTSRC;
PB->INTSRC = Temp_intsrc;
}
}
// Ana program içerisinde Flag değişkeni kontrol edilerek istenilen işlem yaptırılır.
while(1){
if(Flag){
printf("PB.14 pininden interrupt geldi \r\n");
Flag = 0;
}
}
Interrupt Özelliğine DEBOUNCE Özelliği Ekleme
Debounce kısaca giriş pininde istenmeyen sinyallerin oluşmasının engellenmesidir. Giriş pinine bir buton bağladığınızı varsayalım. Butona mekanik olarak basdığımızda butonda voltaj oturana kadar pek çok kez işlemci lojik "1" ve lojik "0" olarak giriş pinini çok hızlı bir şekilde okuyacaktır. Bu istenmeyen durumun çözümlerinden biri de debounce devreleri kullanmaktır. Nuvoton bu özelliği yazılımsal olarak işlemcisine koymuş görünüyor.
( Kaynak : https://www.nuvoton.com/export/resource-files/TRM_M251_M252_M254_M256_M258_Series_EN_Rev2.pdf page 1320)
Bu özelliği aşağıdaki fonksiyon ile kullanıyoruz.
Öncelikle bu özelliği ayarlıyoruz
GPIO_SET_DEBOUNCE_TIME(GPIO_DBCTL_DBCLKSRC_LIRC, GPIO_DBCTL_DBCLKSEL_8)
Burada iki parametre kullanılıyor. İlk parametre işlemcinin kullandığı clock kaynağıdır. Biz uygulamamızda dahili RC osilatörü kullandığımızdan
GPIO_DBCTL_DBCLKSRC_LIRC parametresini kullandık.
İkinci parametre ise giriş sinyalinin oturması için gereken clock süresini belirtiyor. Biz uygulamada dahili clock frekansını 8'e bölerek kullandık.
GPIO_DBCTL_DBCLKSEL_8
Bunun dışında aşağıda verilen değerleri kullanabilirsiniz. Bu seçimi donanımıza göre seçmeniz gerekir.
GPIO_DBCTL_DBCLKSEL_1 // 1 clocks
GPIO_DBCTL_DBCLKSEL_2 // 2 clocks
GPIO_DBCTL_DBCLKSEL_4 // 4 clocks
GPIO_DBCTL_DBCLKSEL_8 // 8 clocks
GPIO_DBCTL_DBCLKSEL_16 // 16 clocks
GPIO_DBCTL_DBCLKSEL_32 // 32 clocks
GPIO_DBCTL_DBCLKSEL_64 // 64 clocks
GPIO_DBCTL_DBCLKSEL_128 // 128 clocks
GPIO_DBCTL_DBCLKSEL_256 // 256 clocks
GPIO_DBCTL_DBCLKSEL_512 // 512 clocks
GPIO_DBCTL_DBCLKSEL_1024 // 1024 clocks
GPIO_DBCTL_DBCLKSEL_2048 // 2048 clocks
GPIO_DBCTL_DBCLKSEL_4096 // 4096 clocks
GPIO_DBCTL_DBCLKSEL_8192 // 8192 clocks
GPIO_DBCTL_DBCLKSEL_16384 // 16384 clocks
GPIO_DBCTL_DBCLKSEL_32768 // 32768 clocks
Bu ayar tüm girişler için kullanılacaktır. Şimdi hangi girişi kullanıcak ise o pin için bu özelliği aktif ediyoruz.
GPIO_ENABLE_DEBOUNCE(PB, BIT14);
Bu ayarların kullanıldığı kod parçası aşağıdaki gibidir.
#define Giris_Pin PB14
uint8_t Flag = 0;
GPIO_SET_DEBOUNCE_TIME(GPIO_DBCTL_DBCLKSRC_LIRC, GPIO_DBCTL_DBCLKSEL_8)
CLK_EnableModuleClock(GPB_MODULE); // clock enable
SYS->GPB_MFPH = (SYS->GPB_MFPH & ~(SYS_GPB_MFPH_PB14MFP_Msk)) | (SYS_GPB_MFPH_PB14MFP_GPIO);
GPIO_EnableInt(PB, 14, GPIO_INT_FALLING);
GPIO_SetPullCtl(PB, BIT14, GPIO_PUSEL_PULL_UP); // pull-up resistor enable
GPIO_ENABLE_DEBOUNCE(PB, BIT14);
NVIC_EnableIRQ(GPB_IRQn);
// PB.14 pinini lojik "0" yaptığımızda prorgram bu fonksiyona gelecektir
void GPB_IRQHandler(void) {
uint32_t Temp_intsrc;
if (GPIO_GET_INT_FLAG(PB, BIT14)) {
/* Check if PB.14 the interrupt occurred */
Flag = 1;
/* Clear PB.14 interrupt flag */
GPIO_CLR_INT_FLAG(PB, BIT14);
} else {
/* Un-expected interrupt. Just clear all PB interrupts */
Temp_intsrc = PB->INTSRC;
PB->INTSRC = Temp_intsrc;
}
}
// Ana program içerisinde Flag değişkeni kontrol edilerek istenilen işlem yaptırılır.
while(1){
if(Flag){
printf("PB.14 pininden interrupt geldi \r\n");
Flag = 0;
}
}
Merhaba, bilgi verici bir yazı olmuş teşekkürler
YanıtlaSilIDE olarak ne kullanıyorsunuz?
Nuvoton Eclipse Mars, Keil ve IAR için de pack desteği veriyor. Ben açık kanak olmasından dolayı ve Linux kullanıcısı olmamdan kaynaklı Eclipse Mars'ı tercih ettim.
SilTeşekkür ederimm
SilBu yorum yazar tarafından silindi.
YanıtlaSil