7 Haziran 2022 Salı


Nuvoton RTC Kullanımı

Nuvoton M252KG M23 ARM işlemcisi ile RTC kullanımını anlatacağım. Geliştirme kartı olarak Nuvoton NuMaker-M252KG V1.3 kullanıyoruz.

Harici 32.768KHz Kristal Osilatörün Kurulumu

32.768KHz kristal osilatör kartımızda PF.4 ve PF.5 pinlerinde bağlıdır.

 


 

Kaynak: Nuvoton UM_NuMaker-M252KG_EN_Rev1.00.pdf

Bu pinleri giriş olarak kuralım.

PF->MODE &= ~(GPIO_MODE_MODE4_Msk | GPIO_MODE_MODE5_Msk);


Daha sonra Harici 32.768Khz kristal girişini aktif edelim.


CLK_EnableXtalRC(CLK_PWRCTL_LXTEN_Msk);


Aktif edilen kristal girişinin stabil hale gelmesini bekliyelim. İlk enerji verildiğinde voltaj oturana kadar osilatör stabil hale gelmeyebiliyor.


CLK_WaitClockReady(CLK_STATUS_LXTSTB_Msk);


Her iki giriş pininde oluşacak olan sızıntı akımlarını önlemek için işlemci içerisinde bulunan dijital giriş yolunu pasif hale getiriyoruz.


GPIO_DISABLE_DIGITAL_PATH(PF, (1ul << 4));

GPIO_DISABLE_DIGITAL_PATH(PF, (1ul << 5));


Tüm bunları tek bir fonksiyonda topluyalım. Bu fonksiyon harici kristal kurulum fonksiyonumuz olsun. Bu fonksiyonu sistem clock fonksiyonlarından sonra kullanmamız gerekiyor.


void LXT_Init(void)

{

PF->MODE &= ~(GPIO_MODE_MODE4_Msk | GPIO_MODE_MODE5_Msk);


CLK_EnableXtalRC(CLK_PWRCTL_LXTEN_Msk);


CLK_WaitClockReady(CLK_STATUS_LXTSTB_Msk);


GPIO_DISABLE_DIGITAL_PATH(PF, (1ul << 4));


GPIO_DISABLE_DIGITAL_PATH(PF, (1ul << 5));

}

 

RTC Modülünün Aktif Hale Getirilmesi

Harici kristal kurulumunu tamamladığımıza göre şimdi de RTC (Real Time Clock) modülümüzün clock sinyalini aktif hale getirelim.

CLK_EnableModuleClock(RTC_MODULE);


Her ARM işlemcide olduğu gibi bu işlemcide de RTC kullanmamız için bir struct yapı bulunmaktadır. rtc.h dosyası içerisnde bu yapı tanımlanmış olarak gelmektedir.


typedef struct

{

    uint32_t u32Year;                 /*!< Year value */

    uint32_t u32Month;             /*!< Month value */

    uint32_t u32Day;                  /*!< Day value */

    uint32_t u32DayOfWeek;     /*!< Day of week value */

    uint32_t u32Hour;               /*!< Hour value */

    uint32_t u32Minute;             /*!< Minute value */

    uint32_t u32Second;             /*!< Second value */

    uint32_t u32TimeScale;        /*!< 12-Hour, 24-Hour */

    uint32_t u32AmPm;              /*!< Only Time Scale select 12-hr used */

} S_RTC_TIME_DATA_T;


Struct yapısını incelediğimizde takvim ile ilgili tüm değişkenlerin tanımlı olduğunu görmekteyiz.


Bu yapıyı RTC_Kurulum olarak tanımlayalım.


S_RTC_TIME_DATA_T RTC_Kurulum;


Tarih ve saat bilgilerimizi girelim.


RTC_Kurulum.u32Year = 2022; // yıl bilgisi

RTC_Kurulum.u32Month = 6; // ay bilgisi

RTC_Kurulum.u32Day = 7; // gün bilgisi

RTC_Kurulum.u32Hour = 9; // saat bilgisi

RTC_Kurulum.u32Minute = 30; // dakika bilgisi

RTC_Kurulum.u32Second = 0; // saniye bilgisi

RTC_Kurulum.u32DayOfWeek = RTC_TUESDAY; // haftanın günü bilgisi

RTC_Kurulum.u32TimeScale = RTC_CLOCK_24; // saat formatı 24 saat


struct yapıyı doldurduktan sonra bu parametreler ile RTC modülünü kuralım.


if (RTC_Open(&sInitTime) != 0) {

    printf("\n RTC kurulumu basarisiz oldu!!");

    printf("\n Lutfen Donaniminizin calistigindan emin olunuz!!");

    while (1);

}


Kurulum başarılı oldu ise RTC_Open fonksiyonu "0" değeri ile geri döner.


Not: RTC modülü geliştirme kartında enerji kesilene kadar devam eder. Enerji kesilir ise veya kart resetlenir ise her şey baştan başlar. İşlemcinin VBAT pinine bir batarya takmalısınız

RTC Modülünden Güncel Tarih ve Zaman Verilerinin Alınması


RTC modülü çalışmaya başlamıştır. Peki çalışan RTC modülünden güncel tarih ve zamanı nasıl alacağız.


Bunun için aşağıdaki fonksiyonu herhangi bir zamanda kullanıp tanımladığınız struct yapıya güncel verileri çekebilirsiniz.


RTC_Guncel isimli bir struct tanımlayalım.

S_RTC_TIME_DATA_T RTC_Guncel;


Bu fonksiyon ile de güncel tarih ve zaman bilgilerini çekelim.

RTC_GetDateAndTime(&RTC_Guncel);


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;

    }

}