6 Haziran 2022 Pazartesi

 

 


 

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;

    }

}

4 yorum:

  1. Merhaba, bilgi verici bir yazı olmuş teşekkürler
    IDE olarak ne kullanıyorsunuz?

    YanıtlaSil
    Yanıtlar
    1. 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.

      Sil
  2. Bu yorum yazar tarafından silindi.

    YanıtlaSil