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;
}
}