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;

    }

}

28 Şubat 2018 Çarşamba

Independent watchdog (IWDG)

STM32L051 işlemcisinde bulunan Independent watchdog özelliğini inceleyeceğiz.

         Bu yazımızda bir problemin oluşması durumunda veya zaman aşımı uygulamaları için kullanılan bu özelliği inceleyeceğiz.

Yazılım hatasından kaynaklanan arızaları çözmek için kullanılır.
  •  Zaman aşımı oluştuğunda sistem reset’i oluşturur.
  •  Ana clock sinyali bir hatadan dolayı dursa bile her zaman aktiftir.
  •  Bir kez aktif edilmiş ise kapatılamaz sadece tekrar yenilenmek zorundadır. Yani timeout sayacını sıfırlamak gerekir.

Uygulama avantajları:
  •           Ana uygulama dışında tamamen bağımsız bir işlemdir.
  •           Donanım veya yazılım ile başlatılabilir.
  •           Standby modunda veya stop modunda low-power olarak dondurabilir.

       Yazılım hatasından kaynaklanan sorunları tespit etmek için ve çözmek için kullanılır. Sayıcı zaman aşımı değerine ulaştığında bir reset sırasını tetikler. Saat bağımsız bir 37 kHz düşük hızlı dahili RC osilatöre (LSI RC) sahip olduğundan, ana clock başarısız olsa bile watchdog aktif kalır. Bir kez aktif edildiğinde sadece bir reset ile pasif edilebilir.

       Uygulamalar için en önemli yararlarından birisi, ana clock’dan bağımsız çalışabilme yeteneğidir. Ayrıca, IWDG, isteğe bağlı baytları kullanarak donanım veya yazılım aracılığıyla yapılandırılabilir. Stop mod veya Standby süresince IWDG sayacı dondurulabilir.

IWDG ana özellikleri:
  •           12-bit bağımsız çalışan downcounter
  •           Bağımsız RC osilatörden Saat sinyali (LSI)
  •           Koşullu Reset ( watchdog aktif ise)
    • Downcounter değeri 0x000’a geldiğinde
    • Downcounter sayacı window dışında tekrar yüklendiğinde ( window opsiyonu seçili ise)
       IWDG 12-bit bağımsız çalışan bir downcounter sayacına sahiptir. 37-kHz olan dahili bir low-speed osilatörden saat sinyalini alır. 

       IWDG ne zaman aktif edilir ise, downcounter sayacı sıfır gittiğinde veya downcounter window dışında tekrar yüklendiğinde (bu opsiyon aktif ise) reset sinyali oluşturulur.


        IWDG register’ları CORE voltajının bulunduğu alana yerleştirilmiştir. Bu mimari kullanılarak IWDG özelliği Stop ve Standby modlarında kullanılabilmektedir. LSI osilatör frekansı 8-bit prescaler ile bölünerek kullanılmaktadır.

        IWDG başlatıldığında 12-bit sayaç reset değeri olan 0xFFF’den aşağı doğru saymaya başlar. IWDG sayacını yenilemek için Anahtar değer olarak 0xAAAA Key register içerisine yazılarak sayacın terkrar geri yüklenmesi gerekmektedir. Yani bu anahtar girilmeden sayaç temizlenemez. Yazılım içerisinde yanlışlıkla bu sayacın temizlenmesi imkânsızdır.

         Downcounter sayaç değeri(0x000) olduğunda bir sistem reset sinyali üretilir.

        Window opsiyonu aktif edilmiş ise, sayaç window içerisinde yenilenmek zorundadır. Window dışında yenilenir ise bir sistem reset sinyali oluşturulur ve sistem resetlenir.
IWDG donanımı cihazın opsiyon byte’ları ile aktif edilir. Aktif edildi ise, watchdog power on durumunda otomatik olarak başlatılır.

        Herhangi bir reset’lenmeyi önlemek için Key register sayaç 0 değerine ulaşmadan önce veya window’da (bu opsiyon aktif ise) düzenli aralıklarla yenilenmelidir. IWDG yazılımda başlatılması birkaç adımda yapılandırılır.
  •           İlk adım watchdog’un başlatılması için Key register’a 0x0000 CCCC yazılır.
  •           Daha sonra IWDG register koruması 0x0000 5555 yazılarak kaldırılır.
  •           IWDG prescaler IWDG_PR register üzerinden ayarlanır.
  •           Watchdog sayacı IWDG_RLR reload register üzerinden başlangıç değeri ayarlanır.

       Önceki kayıtlara eriştikten sonra kayıtların güncellendiğini onaylamak için IWDG_SR bitinin sıfırlanmasını beklemek gereklidir.
  •          İki seçim mevcuttur. IWDG window opsiyonu aktif etmek veya pasif etmek.
    •        IWDG_WINR register içerisine window değeri yazılarak window opsiyon aktif edilir.
    •         Diğeri, Key register içerisine 0x0000 AAAA yazılarak window opsiyonu pasif edilir.

       IWDG zaman tabanı LSI saatinden 37kHz'de beslenir. IWDG_PR prescaler register LSI saat frekansını 4’den 256’ye kadar bölebilir. Watchdog sayacı tekrar yükleme değeri 12-bit olarak IWDG_RLR register içerisine yazılabilir.

        IWDG zaman aşımını belirlemek için bir formül kullanılabilir. IWDG zamanı seçilen watchdog sayıcısının geri yükleme değerinin yanı sıra LSI periyoduna ve prescaler değerine bağlıdır. Parametre limitleri göz önüne alındığında, IWDG zaman aşımı değeri :

37kHz / 4(prescaler) = 9,25ms * 4095(reload value) = 37,8 saniye
37kHz / 256(prescaler) = 144,5us * 1(reload value)  = 144,5 us

arasında olabilir.

       IWDG çevrebirimi tarafından bir reset sinyali oluşturulduktan sonra, RCC_CSR register içerisinde yer alan IWDGRSTF bayrağı işlemcinin hangi sebepten reset’lendiğini anlamak için set edilir.

       Mikro kontrolör Debug moda girdiğinde, IWDG sayacı DBG modülündeki DBG_IWDG_STOP bit’inin değerine bağlı olarak normal çalışmaya devam eder veya durur.

       IWDG, beslemenin kapalı olduğu durum olan Shutdown modu hariç tüm çalıştırma ve düşük güç modlarında etkin olabilir. Bununla birlikte, Stop0, Stop1, Stop2 ve Bekleme modlarında, watchdog sayacı FLASH_OPTR register’ın ilgili bitleri programlanarak dondurulabilir.

       Şimdi bunu STM32CubeMx ve Atollic IDE kullanarak uygulayalım ve sonuçlara bakalım.
Öncelikle CubeMx’de projemizi adım adım oluşturalım.


      Resimde görüldüğü gibi “New Project” kısmına basalım.


      Çıkan listeden kullanacağımız işlemciyi seçelim. Ben STM32L051K8T6 kullanacağım için yukarıdaki resimde de görüldüğü üzere bu işlemciyi seçip “OK” butonuna basıyoruz.


       Projemiz için ana ekran yukarıdaki şekilde geldi.


       Öncelikle Atollic programında debug yapabilmek için yukarıda görüldüğüü gibi “Peripherals” sekmesinin altında yer alan “SYS” sekmesinin altındaki “Debug Serial Wire” seçeneğini seçiyoruz. Bu seçimi yapmadan proje oluşturduğumuzda Atollic programı debug yapmamıza izin vermeyecektir.

























       Daha sonra “Peripherals” sekmesinin altında bulunan “IWDG” sekmesinden  “Activated” kısmını işaretleyerek Independent Watchdog özelliğini aktif hale getiriyoruz.


       Daha sonra “Clock Configuration” kısmına gelip HCLK değerini 32MHz olarak değiştirip Enter tuşuna basıyoruz. Böylece sistem clock frekansımızı 32MHz olarak ayarlamış oluyoruz.
         Resimde de görüleceği üzere IWDG clock kaynağı 37kHz’dir. İncelemelerim sonucunda her işlemci ailesinde bu değer farklılıklar göstermektedir.

       Şimdi de LED’lerimizin bağlı olduğu pinleri ayarlayalım.


       Kırmızı LED’imizi PB7 pinine , yeşil LED’imizi de PB6 pinine bağlayalım. Pin üzerine gelerek sağ tuş ile açılan menüden “Enter User Label” seçeneğini seçerek LED’lerin isimlerini tek tek girelim.
      Daha sonra 

      Yukarıdaki resimde işaretlenmiş olan “Configuration” sekmesinde bulunan “IWDG” butonuna tıklayarak IWDG menüsünü açınız.


       Burada 3(üç) adet parametre bulunuyor. Bunlar;
  • IWDG counter clock prescaler
  • IWDG window value
  • IWDG down-counter reload value

      Yukarıdaki anlatılan formülü hatırlayalım:

İstenilen Zaman = (LSI RC Osilatör Frekansı / Prescaler)* down-counter reload değeri

      Biz presclaer değerini 32, ve down-counter reload değerini 865 verirsek,

      İstenilen Zaman = (37 kHz / 32)*865 = 1000,15ms olarak hesaplanır. Yani biz sistemin resetlenmemesi için yaklaşık 1 saniye içerisinde down-counter reload değerini yeniden yüklememiz gerekecek.

      Bu değerleri parametrelere girdikten sonra “OK” butonuna basarak menüden çıkalım.
Şimdi proje ayarlarını yapacağız.



                “Project” menüsünden yukarda görüldüğü gibi “ Setting…” kısmına basarak proje ayarlarını yapacağımız menüyü açalım.


      Ben proje ismi olarak IWDG_DENEME ismini verdim. “Project Location” kısmına programın nereye oluşturulmasını istiyor iseniz oranın yolunu yazın. “Toolchain /IDE” kısmından Atollic IDE ile çalışacağımızdan dolayı “TrueSTUDIO” seçeneğini seçiyoruz. “OK” butonuna basarak menüyü kapatıyoruz. 


       “Project” kısmından “Generate Code” kısmını seçerek programın oluşturulmasını sağlıyoruz.


      Karşımıza yukarıda resmi gösterilen onay menüsü gelecektir. Eğer çalışma ortamınız Linux ise “Open Folder” butonuna basın. Çünkü Linux sistemlerinde Atollic otomatik açılmıyor. Windows ise “Open Project” butonuna basıyoruz. Atollic programı otomatik olarak oluşturulan programı açacaktır.



      Atollic projeyi açtıktan sonra “Src” klasörü altında bulunan “main.c” dosyasına çift tıklayarak açıyoruz.


      Daha sonra programımızı derlemek için;



      Yukarıdaki resimde gösterilen çekiç sembolüne basarak derleme işlemini başlatıyoruz.


      Resimde de gösterildiği gibi “MX_IWDG_Init();” fonksiyonu üzerine Ctrl tuşuna basarak tıklıyoruz. Fonksiyonun bulunduğu konum gelecektir.


      Aslında HAL kütüphaneleri register seviyesinde bizim yapmamız gereken işleri kendi halletmiş durumda. Biz sadece bahsi geçen parametreleri giriyoruz. Kısaca konu başında anlatılan Key register vb. register’ların içeriği kütüphane içinde halledilmiş oluyor. Merak edenler için HAL_IWDG_Init fonksiyonunu incelemelerini öneririm. Yukarıdaki resimde de görüldüğü gibi formüle yerleştirdiğimiz değerler parametrelere set edilmiş durumdalar.

      Öncelikle IWDG counter’ı yenilemeden sistemin reset'lendiğini görmek için main fonksiyonu içerisini aşağıdaki gibi değiştirelim.


      Öncelikle MX_IWDG_Init() fonksiyonundan sonra 2000ms’lik bir gecikme fonksiyonu ekledik. Daha sonra while döngüsü içerisine Hal_Delay(50) fonksiyonu ile 50ms’lik bir gecikme ve Kırmızı LED’imizi her seferinde yakıp söndürecek HAL_GPIO_TogglePin fonksiyonunu ekledik. Programı derleyip çalıştırdığımızda kırmızı LED’in üzerindeki sinyal aşağıdaki gibi olacaktır.


      Osilaskop görüntüsünde de görüldüğü gibi LED periyodik olarak yanıp sönüyor ve reset sinyalinden sonra tekrar periyodik yanıp sönüyor. Şimdi IWDG counter’ı yenileyerek aynı kodu çalıştıralım.


      Yukarıdaki kod parçasında görüldüğü gibi while döngüsünün içerisine IWDG counter’ı yenileyen fonksiyon olan HAL_IWDG_Refresh eklendi. Yani yaklaşık 50ms’de bir watchdog sayacı yenilenecek ve böylece reset sinyali oluşmayacak. Kodu çalıştırdığımızda ki osilaskop görüntüsü aşağıdaki gibidir.


      Kırmızı LED periyodik hiç ara vermeksizin 50ms’de bir yanıp sönüyor. Bu durumda iken işlemcinin ana clock sinyali fail eder ise reset sinyali üretilecek ve program tekrar çalışmaya başlayacaktır.


İyi çalışmalar arkadaşlar.....

29 Aralık 2016 Perşembe

RTOS 
Real Time Operating System

    Mikrodenetleyiciler küçük ve kaynakları sınırlı işlemcilerdir. işlemciler programlarını ROM veya FLASH'ta tutarlar. Programları buradan yürütürler. Programın çalışması için RAM'e ihtiyaç duyarlar. Tipik bir program direkt olarak ROM'dan çalışır.

    Mikro denetleyiciler en alt gömülü uygulamalar kullanarak özelleştirilmiş işlemleri yaparlar. FreeRTOS, Real Time Scheduling, Görevler arası iletişim(inter-task communication) , zamanlama(timing) ve senkronizasyon ilkelerini içerir. 

    İşletim sistemi tasarımlarında önemli bir konu olan işlemci zamanlama algoritmalarına bir göz atalım. (CPU scheduling algorithms). Bu algoritmaların çalışma prensibi şöyledir; sırası gelen işlem biz bunlara genelde fonksiyon diyoruz. Bekleme sırasına alınarak görevlendirici (dispatcher) olarak adlandırılan bir işlem tarafından CPU'ya gönderilir. RTOS işlemci zamanlama algoritmasının izin verdiği kadar, fonksiyonu bitene kadar veya belirli bir zaman geçene kadar çalıştırır ve hafızadan kaldırır. Böylece birden çok fonksiyon tek bir işlemci tarafından çalıştırılır. Burada kullanılan algoritmaları iki kısımda inceleyebiliriz;
  • Kesintili algoritmalar (preemptive algorithms)
  • Kesintisiz algoritmalar (nonpreemptive algorithms)
    Kesintili algoritmalarda bir Task( bundan sonra işlemlere Task  diyeceğiz) RTOS tarafından belirlenmiş bir süre kadar çalıştırılır ve diğer bir Task'ın çalıştırılmasına geçer. Böylece birden fazla Task zaman paylaşımlı olarak çalıştırılmış olur.

    Kesintisiz algoritmalarda  çalıştırılan Task bitene kadar diğer Task çalıştırılmaz. Task'lar birbirlerini beklerler. Kesintisiz algoritmalara örnek;
  
En Kısa Task İlk (Shortest job first)
İlk Gelen İlk Çıkar (First in first out)
İlk Gelen Son Çıkar (First in last out)

Birbirini Dışlama (Mutually Exclusive)


    İki Task'ın birbiri ile ilişkisizliğini belirtmek için kullanılan terimdir. Bazı dokümanlarda Mutex olarak kısaltılarak da kullanılır.

    İki Task paralel olarak çalıştırıldığında (aslında zaman paylaşımlı kısım kısım çalıştırıldığında) aynı kaynağı veya global tanımlanmış aynı değişkeni kullanabilirler. Bu kullanım yazılımda hatalara sebep olabilir. Bu problemin çözümü için Task'ların senkronize edilmesi gerekmektedir. Temel işletim sistemlerinde 4(dört) yöntem kullanılır.
  • Koşullu Değişkenler (Conditional Variable)
  • Semaforlar (Semaphores)
  • Kilitler (Locks)
  • Monitörler (Monitors)
    Biz bunlardan Semaforları inceleyelim.

Semafor (Semaphors)


    İşletim sistemlerinde eş zamanlı programlamada sıkça kullanılan bir yöntemdir. Birden fazla Task'ın aynı anda çalışması durumunda birbirleri için risk teşkil ettikleri zamanlarda Task'ların birbirlerini beklemesini sağlayan bir mekanizmadır.

    Semafor kullanımında bölünmezlik (atomicity) baş roldedir. Yani tanımlanmış bir semafor'un içerisinde çalışan birden fazla fonksiyon işletim sistemi tarafından tek bir Task olarak kabul edilir ve araya herhangi bir Task girerek çalıştırılmaz. Semafor'lar iki tipte kullanılırlar;
  • İkili Semafor'lar (Binary Semaphores)
  • Tam sayı Semafor'lar ( Integer Semaphores)
    İkili semafor'lar sadece iki Task arasında eşleme sağlarlar. Üçüncü bir Task'a eşleme sağlamazlar. Tam sayı semafor'lar istenilen sayıda Task arasında eşleme sağlarlar.

Kaynak: ST UM1722.pdf , Yrd.Doç.Dr.Şadi Evren ŞEKER