17

STM32-Flash Hafızaya Veri Yazma ve Okuma

Bazı Gömülü Sistem projelerinde kullanıcı tarafından değiştirilen bir değere (kullanıcı adı,şifre vb.), sistemin enerjisi kesilip tekrar geldiğinde veya sistem resetlendiğinde tekrar erişmek gerekebiliyor. Böyle durumlarda mikrodenetleyicinin programcılar için ayrılan adreslerine veri yazılıp ve gerektiğinde o adrese erişerek veriler çekilebilir. Flash hafızanın bir yazma sınırı olduğunu unutmayalım. Yani sürekli flash hafızaya veri yazılıp okunduğu bir uygulama önerilmemektedir. Bu yazıda STM32F1 serisi için Flash Hafızaya veri yazma veya Flash Hafızadan veri okuma işleminin bir örnek uygulamasından bahsedeceğim.
Öncelikle STM32f1 de flash adrese veri yazma ve okuma işlemi 16 bitlik(half-word) değişkenler ile yapılır. İlk olarak en basit olanından yani veri okuma fonksiyonundan başlayalım. Aşağıda görüldüğü gibi bu fonksiyon iki satırdan oluşmaktadır. C programlamadan hatırlayacağınız üzere pointerlar ile adrese erişip adresteki veriyi alma mantığına dayanır.

Flash adrese veri yazmak ve flash adresteki veriyi silmek , okumaya göre biraz daha farklıdır. STM32 de bu işlemleri yapabilmek için öncelikle flash kilidini açmak gerekir. Bunun için STM32 programming manualden  yararlanabiliriz. Flash kilidini açmak için FLASH->KEYR registerına programming manualdeki key1 ve key2 sırası ile gönderilmelidir. Böylece flash kilidi açılmış olur. Yazma veya silme işlemi bittikten sonra FLASH_CR registerı resetlendiği zaman flash tekrar kilitlenmiş olur ve yazma,silme işlemi yapılamaz. Aşağıda programming manuel den alınan flash key değerlerine ait değerler verilmiştir.

STM32f1 Flash Keys

Flash Keys

Peki hangi adrese veri yazacağız. Bunu da yine programming manual veya reference manual’deki “flash memory map” tablosundan bulabiliriz. Aşağıda bu tablo verilmiştir.

stm32 flash memory map

STM32F1 Memory Map

Dikkat edilirse main memory 128 adet 1 kbyte’lık sayfalardan oluşmaktadır. Burada önemli bir noktaya değinmek gerekir. Yazma işlemi yapılırken tek bir adrese yazılır fakat silme işlemi tüm sayfayı siler.

Yukarıda yazma ve silme işlemleri için yazılan fonksiyonlar verilmiştir. Aşağıdaki kodda dikkat edilirse yazma adresi olarak Page 127‘nin başlangıç adresi seçilmiştir.

Kod yüklendikten sonra değişkenlerdeki değişimleri STMStudio ile izleyebilirsiniz.

Read_Flash Öncesi

Read_Flash Sonrası

Kodların Tamamı

 HAL Kütüphanesi ile Flash Hafıza Örneği

Bir örnekte HAL kütüphanesi ile yapalım. Bu örnekte silme işlemi ile yazma işlemini tek bir fonksiyon içerisinde yapacağız. Silme işlemi bir kaç satırdan oluştuğu için aynı fonksiyon içinde aşağıdaki gibi kullanabiliriz.

Bu fonksiyon içerisinde HAL_FLASH_Program() fonksiyonu ile istersek 32 bit veya 64 bitlik değerleri hafızaya yazabiliriz. Tabi arka planda değerler yine 16 bit olarak hafızaya yazılır. HAL_FLASHx_Erase() fonskiyonu bizden bir hata parametresi bekler. Eğer silme işleminde hata oluşur ise bu parametreye girilen değişkeni hangi adresi silerken hata oluştu ise o adresin değerine eşitler.

NOT: Ben bu örneği STM32F103C8T6(Blue Pill) üzerinde denedim. Yazının başında verdiğim tabloda STM32F1 serisinin Memory Map tablosunda 128 sayfa olduğu görülmektedir fakat her f1 modeli 128 sayfalık yani 128 kb flash hafızaya sahip değildir. STM32F103C8T6 da C den sonra gelen 8 kodu 64 kb lık bir flash hafızaya sahip olduğunu belirtmektedir.

Memory Map tablosunda 63. sayfanın hangi adreste olduğu yazmamaktadır. Peki herhangi bir sayfanın adresini nasıl hesaplayabiliriz? Bunu basitçe aşağıdaki gibi hesaplayabiliriz.

Memory map’ten page 0′ ın başlangıç adresini ve her sayfanın 1 kb(1024 byte) olduğunu biliyoruz. Buna göre istenilen sayfanın başlangıç adresini yukarıdaki gibi hesaplayabiliriz.

Kaynak: http://www.picproje.org/

Mehmet Topuz

17 Comments

    • Evet doğrudur. Flash hafızanın boş olduğu durum 0xFF değeridir. Aynı zamanda hafızadan veri silindiğinde değeri 0xFF olmalıdır.

  1. Mehmet bey merhabalar, öncelikle verdiğiniz bilgiler için teşekkür ederim. Takıldığım bir nokta var. STM32F103CBT6 kodlu işlemci kullanıyorum. Float değerim var ve flash hafızaya kaydetmek istiyorum. Nasıl bir yol izleyebilirim?

    • Merhaba, rica ederim. Öncelikle float 32 bitlik bir değişkendir. Flash hafızaya yazarken 16 bitlik değerler yazabiliyoruz. Float değişkenlerde bit kaydırma işlemi(<<) yapılmadığı için float değişkeni 16 bitlik iki değişkene parçalamak zor bir iş. Bunun yerine float değişkenin virgülden sonraki basamağını sabit kabul ederek virgülden önceki ve virgülden sonraki sayıyı iki ayrı 16 bitlik değişkene atayıp hafızaya kaydedebilirsin. Örneğin; Float değişkeni şöyle iki değişkene atayabilirsin.

      float a = 13.35;

      uint16_t b = a; // b = 13

      uint16_t c = a*100;

      c = c%100; // c = 35

      Burada değişkenin birini örnek olarak 0x0801FC00 adresine diğerini ise 0x0801FC02 adresine kaydedebilirsin. Daha sonra bu adreslerden veri okuduktan sonra tekrar bu iki sayıyı float tipine dönüştürmek istiyorsan bunu da şu şekilde yapabilirsin.

      float d = b; // d = 13.0

      d = d+ (float)c/100; // d = 13.35000

      Bunu böyle bir deneyiniz. Eğer kod çalışırsa buraya tekrar yazarsanız sevinirim. Sonucu ben de merak ediyorum.

  2. Sorunumu şu şekilde çözüme ulaştırdım. Belki ihtiyacı olan arkadaşlar olabilir;
    typedef union
    {
    uint16_t dataBytes[2];
    float f;
    }floatToChar_t ;

    fonksiyon olarak kullanımı;
    Write_Flash(carpanDegeriAdress, degisken.dataBytes[0]);
    Write_Flash(carpanDegeriAdress1, degisken.dataBytes[1]);

    ve;
    degisken.dataBytes[0] = Read_Flash(carpanDegeriAdress);
    degisken.dataBytes[1] = Read_Flash(carpanDegeriAdress1);

    şeklinde. (Read_Flash ve Write_Flash fonksiyonları sizin yukarıda yazmış olduğunuz fonksiyonlar.)

    • Merhaba Gökhan Bey,
      Çözümü bir örnek üzerinde detaylı olarak gösterebilir misiniz ?

  3. İşlemler bittikten sonra Flash_Lock komutunun önemi nedir?
    Resetten sonra flash’ı unlock etsek ve bir daha hiç Lock etmesek, veri kaybı yaşar mıyız? Veya veri kaybı yaşama olasılığımız ne oranda etkilenir?

    • Bu komut sadece flasha yazmayı engeller. Genelde yanlışlıkla program kodları değiştirilmesin diye kullanılır. Mikrodenetleyici üzerinde çalışan kodlar da flash hafızda tutulur. Bu kodlardan herhangi bir byte silinse mikrodenetleyicide bir süre sonra hata oluşur. Bunun önüne geçmek için konulmuş bir önlem olabilir. Flashı lock etmesende bir sıkıntı çıkacağını zannetmiyorum program hafızasına veri yazmadığın sürece tabi. Mikrodenetleyici resetlendiğinde tekrar otomatik kilitlenecektir.

  4. Merhabalar. Bir sorum olacak. Flash hafızaya aynı sector’e mesela 11.sector’e farklı adreslerine birçok değer atamak istiyorum. Fakat Flash_Write komutu her çalıştığında sector11’i tamamen sildiği için ilk yazdığım veriler siliniyor. Doğal olarak 10 tane veri kaydetmek istesem sadece sonuncu kalıyor. Diğerleri tüm sector silindiği için siliniyor. Bunun için bir öneriniz var mı ? Yardımcı olursanız çok sevinirim.

    • Merhaba, Daha önce bu sorunu şu şekilde çözmüştüm. Atıyorum aynı sayfadaki 10 adet verilerden sadece birini silip yerine başka bir tane kaydetmek istedik. Tüm sayfa silineceği için önce 10 adet veriyi hafızadan sırası ile okuyup bir diziye kaydettim. Daha sonra kaydedecek olduğum yeni veriyi dizideki yerine kaydettim. Ardından flash hafızadaki sayfayı silip, bütün diziyi tekrar ilgili sayfaya yazmıştım. Burada verilerin yazılacağı adresi ardışık seçmeniz daha iyi olacaktır. Örneğin; 16 bitlik veriler kaydediyorsanız adresi 2 arttırarak kaydedin.32bitlik değerler kaydediyorsanız adresi 4 arttırarak kaydedin.Böylece basit bir for döngüsü ile bütün verileri okuyup kaydedebilirsiniz. Normalde flash write fonskiyonundan sonra hafızayı silmez. Yazma ve silme fonksiyonlarını ayrı ayrı oluşturmuştum. Sadece HAL kütüphanesi ile yazılmış örnekte write fonksiyonu önce silip sonra yazar. Bu fonksiyonuda yazma ve silme olarak ikiye fonksiyon haline getirebilirsiniz.

  5. Hocam merhaba, kafamı kurcalayan bir soru var. Flash hafızaya yazdırma işlemi yaparken datasheette verilen adreslerden page1’de bulunan 0x08000800 adresine yazdırmak istedim ve başardım da ancak sistem enerjisini kesip yeniden başlattıtğımda bu değer yine ilk değerini aldı ve benim sonradan yazdığım değeri silmiş. ancak sizin kullandıgınız adresi kullandığımda düzgün çalıştığını gördüm. ayrıca c8 ifadesinin 64kb hafıza ifade ettiğini yazmışsınız, o halde datasheette verilen son 64kblık adresi mi kullanmam gerekiyor. yani 64. sayfadan 127. sayfaya kadar olan kısmı? datasheette böyle bir yazı göremedim veya kaçırdım.

    • Merhaba, Öncelikle flash hafızaya veri yazarken ilk sayfalara yazmak önerilmez çünkü ilk sayfalarda mikrodenetleyici üzerinde çalışan program kodu bulunur. Bu yüzden son sayfalara yazmak daha mantıklıdır. Fakat şöyle bir durumda var; Yazdığınız kodların derlendikten sonraki boyutu atıyorum 8kb ise flash hafızaya bu kodlar 8. sayfaya kadar yüklenecektir. Yani 8. sayfadan sonrası halen boştur. Bu yüzden bu örnekte 9. sayfa da kullanılabilir ama yazıp sildiğiniz sayfada program kodları bulunmamalı çünkü progam kodunun tek bir byte’ının silinmesi çalışma zamanında hataya sebep olur. stm32f103c8t6 daki 8 değeri aslında 64kb olduğunu söyler. Yukarıda paylaştığım resmi şu linkteki-> https://www.st.com/resource/en/datasheet/stm32f103c8.pdf datasheet’in 108. sayfasından aldım. Siz hangi seriyi kullanıyorsunuz bilmiyorum ama her seride flash hafıza büyüklüğü farklıdır. Kullandığınız stm32’nin datasheetinde aynı tablonun olması gerekir. Eğer 64 kb hafıza diyorsa 64kb’tan ilerisine yazamassınız. İlk örnekte farklı bir bluepill kullanmıştım ve hata vermemişti. O zaman bluepill üzerindeki mcu’nun paket tipine detaylı bakmamıştım demekki o c8t6 değilmiş, 128kb hafızaya sahip farklı bir f1 serisi de olabilir.

    • Arduino’yu elime almayalı yıllar oldu. Arduino gibi bir platformun bununla ilgili bir sürü örneği vardır. O yüzden biraz daha araştırmanızı tavsiye edeceğim. Bu konuyla ilgili yardım edemeceyeceğim malesef. Araştırmanızı EEPROM şeklinde yapabilirsiniz. Atmel MCU’larda FLASH yerine EEPROM vardı yanlış hatırlamıyorsam.

    • Soruyu yanlış mı anladım? Siz Arduino IDE’si ile STM32 mi programlamak istiyorsunuz yoksa bu yazıdaki gibi bir uygulamayı herhangi bir Arduino kartı üzerinde mi uygulamak istiyorsunuz? Arduino IDE’si ile STM32 programlamadım hiç. Eğer Arduino IDE’si arkaplanda stm’in kendi kütüphanelerini kullanıyorsa yazıdaki gibi register seviyesindeki kodlar ile flash hafızaya yazıp okuyabilmeniz lazım.

  6. merhaba mehmet bey ;
    ben bitwise komutlarıyla bu işi başlamak istiyorum ama yeterli örnek ve konu anlatımı yok gerçi hal kütüphanesinde bitwise başlamak ilerki dönemlerde bir yerde tıkanır mı? kaynak bulmada gibi sizin bu konuda düşüncelerınız nedır.
    acaba siz bitwise kodları baştan sona bir konu anlatmayı düşünüyormusunuz.teşekkür ederim

    • Merhaba,
      Bitwise’dan kastınız register seviyesinden başlamak galiba. Register seviyesinden başlamak temeli sağlam atmak açısından iyi olacaktır. İleride HAL kullansanız dahi bazı noktalarda register seviyesine inmeniz gerekebilir. Tavsiyem her konu için önce register seviyesi daha sonra HAL ile örnekler yapmak olacaktır. Yeni başlıyorsanız temeli sağlam atmak önemli.
      Ben STM32 yada farklı bir MCU bazında bir ders niteliğinde yazılar paylaşmayı düşünmüyorum. Ben daha çok uygulamaya yönelik örnekler paylaşmayı daha çok seviyorum. Bu işin dersini anlatan gerek video gerek yazılı birçok kaynak bulunabileceğini düşünüyorum.

Bir cevap yazın

E-posta hesabınız yayımlanmayacak.