STM32-FATFS İLE SD KART UYGULAMALARI – 1

STM32 projelerimde yıllardır SD kart kullanırım. Özellikle CNC uygulamalarımda Gerber kodları makinaya vermek için iyi bir seçenek oluyordu. Ancak kullanmakta olduğum sürücü kodları, zamanında internetten bulduğum örnekler üzerinden geliştirmiştim. Bu kodlar yaptığım eklemeler ve değişiklikler ile yamalı bohçaya dönmüş bir durumda idi.

Son zamanlarda, STM32 cube IDE platformuna geçtiğimden beri bunları güncelleyip temize çekmeyi aklıma koymuştum. STM32 CubeIDE FATFS alt yapısını da entegre etmiş olduğundan bu işe el atmanın zamanı gelmişti ve geçiyordu.

Geçenlerde kolları sıvayıp işe giriştim ve derli toplu bir sonuca ulaştım. Bu yayında bunu nasıl yaptığımı anlatacağım.

STM32 cube IDE İLE FATFS

Burada konuyu, STM32 CubeIDE ve FATFS sistemine aşina olunduğu varsayımı ile anlatacağım. CNC uygulamalarımda SD karta text dosyası olarak kaydedilmiş Gerber dosyalarını satır satır okutarak kullandığımdan işim çok karmaşık değil. Bu bölümde anlatacaklarım temel işlemler, yani bir text dosyasının açılıp okunması, fazladan da SD karta yazılmasından ibaret.

Kod ayrıntılarına burada girmeyeceğim. Kendi yazdığım kodları anlattığım bir devam yayını olacak. Ona ulaşmak için buraya tıklayınız.

Bunları yaparken ControllersTech.com adlı Youtube kanalı ve blog sitesinden çok yararlandım. Orada, benim burada vereceğimden çok daha güzel anlatılıyor. Zaten bazı kodları da o siteden aldım. STM32 ile ilgili olarak başka pek çok konuda da güzel yayınları var, ziyaret edilmesini tavsiye ederim.

KULLANDIĞIM KİT ve TFT

STM32F103C8 Pico kit, SPI arayüz TFT adaptor kartımın üzerine takılı, TFT alt tarafta

Bu çalışmayı en harcıalem, ucuz STM32 MCU lardan birisini kullanarak yaptım. 1.5-2 Dolara satılan “Pico” adı ile anılan STM32F103C8 modülü kullandım. Bunu kendi tasarımım olan adaptör kartıma -hani break out diyorlar ya- takınca 2.4″ TFT ekranı bağlamak da kolay oluyor. SD kart soketi de zaten TFT üzerinde. TFT ekranım 2.4″ ILI9341, SPI arayüzlü.

Burada vereceğim kodlar ve açıklamalar geniş bir STM32 ailesi için geçerli. Geçersiz olduğu bir STM32 MCU var mıdır, doğrusu araştırmadım. Ama ben STM32F103 ailesinin 48 ve 64 ayaklı tiplerinde sorun yaşamadım.

MALZEME LİSTESİ VE BAĞLANTILAR

  • STM32F103C8 Pico geliştirme kiti
  • 1.4″ SPI arayüzlü TFT ekran, ILI9341 kontrol protokollu, SD kart yuvası var.
  • Kendi üretimim Pico Adaptör kartı ( Bu şart değil bağlantıları kısa jumper tellerle yapabilirsiniz, 10 cm lik olanlar yeterlidir.

Bağlantılar :

TFT bağlantıları:
TFT_Mosi : PA7 (SPI1 Mosi)
TFT_CLK : PA5 (SPI1 Ilk)
TFT_RST : PB0
TFT_CS : PB5
TFT_RS : PA4

SD_Mosi : PB15 (SPI2 Mosi)
SD_Miso : PB14 (SPI2 Miso)
SD_CLK : PB13 (SPI2 CLK)
SD_CS : PB12

TFT LED : 5V
TFT VCC: 5V

PROJENİN STM32 cubeIDE İLE KURULMASI

İlk olarak STM32 cubeIDE de “new STM32 Project” seçeceği ile bir STM32F103C8 MCU seçerek projemizi yaratalım.

STM32 CubeIDE ile yeni projenin oluşturulması
MCU Seçimi
RCC üzerinde, ana işlemci saati için harici kristal seçimi
MCU saat frekansının 72 MHz olarak ayarlanması

SPI ve GPIO ayarları

SPI1 aktiflenmesi ve baud rate ayarı.

TFT ekranımızı SPI1 üzerinden sürüyoruz. Prescaler’i 4 olarak seçerek Baudrate’i 18 MHz e ayarlıyoruz. SPI ın çalışabileceği maksimum hız da bu zaten. TFT ye sadece veri gönderiyoruz, TFT den veri okuma yok. O nedenle “Half Duplex Master” modunu seçiyoruz.

TFT yi DMA ile kullandığımız için SPI1 üzerinde yapacağımız DMA ayarları var.

SPI1 DMA ayarlarından SPI1_TX kanalı seçimi
SPI1 DMA Ayarları

SD KART İÇİN SPI2 ayarları

SD Kartımız SPI2 üzerinde. Bunun için SPI2 yi “Full Duplex Master” olarak aktif hale getirmemiz gerekiyor.

SD Kart için SPI2 ayarları.

SPI2 baudrate i Prescaler’i 8 seçerek 4.5Mbit/s ye ayarlıyorum. Daha hızlı çalışabilen SD kartlar için bu ayar değiştirilebilir.

GPIO AYARLARI

TFT kontrol pinleri ile SD kart seçim pini için bazı GPIO ayarları yapılması gerekiyor. Bu pinlerin hepsi de OUTPUT_PP olarak ayarlanıyor.

Bu pinler:

  • TFT_CS
  • TFT_RS (Bazı TFT lerde bu pine DC adı veriliyor. Biz her zaman RS adını kullanıyoruz)
  • TFT_RST
  • SD_CS
GPIO Ayarları

FATFS AYARLARININ YAPILMASI

SD yi FAT Dosya sistemi altında kullanıyoruz. O nedenle STM32 cubeIDE üzerinden FATFS kütüphanelerini yüklememiz gerekiyor.
Bu amaçla “Middleware” menüsü altındaki FATFS seçeceğini, “user-defined” kutucuğunu da işaretleyerek aktif hale getiriyoruz.

FATFS Kütüphanelerinin eklenmesi

FATFS için herhangi bir parametre değişikliği yapmadan varsayılan ayarlar ile çalışacağız. Ama ben her ihtimale karşı burada FATFS parametre ayarlarının ekran kopyalarını vereceğim:

FATFS Parametre ayarları – 1
FATFS Parametre ayarları – 2
FATFS Parametre ayarları – 3

PROJE KODLARININ OLUŞTURULMASI

Artık cubeIDE bin “project/GenerateCode” seçeceğini tıklayarak projenin başlangıç dosyalarını oluşturabiliriz. Bunun devamında kendi kodlarımızı eklemeye başlayacağız.

SÜRÜCÜ VE KULLANICI FONKSİYONLARININ EKLENMESİ

TFT yi sürmek, FATFS aracılığıyla SD karta yazıp okumak üzere projeye bazı fonksiyonlar eklemek gerekiyor.

Projeye eklediğimiz dosyalar

Eklediğimiz dosyalar şunlar:

  • fatfs_sd.c/h : Bu dosyalar FATFS üzerinden SD karta erişim sağlayan okuma-yazma fonksiyonlarını içeriyor. Orijinal kod yazarını bilmiyorum, ben ControllersTECH.com blog sitesinden aldım.
  • SD_Card_CntTech.c : Bu dosyada fatfs_sd.c fonksiyonlarını kullanarak SD karta erişen, yazan ve okuyan kod örnekleri var. Yine, controllersTECH.com blog sitesinden aldım. Ancak orada verilen örnekte bu kodlar böyle ayrı bir dosya halinde değil, main.c içinde yer alıyordu. Ben kendi kodlarımdan ayrı tutmak amacı ile bunları projeme ayrı bir dosya haline getirerek ekledim.
  • SD_Card_2020.c : Bu dosyada benim geliştirdiğim kodlar var. Şimdilik bu dosyadan sadece sdCard-spi_init() fonksiyonunu kullanıyorum. Dosyanın geri kalanı benim diğer SD kart uygulama programlarımı içeriyor.
  • tft_basic paketi : Bu klasörde benim TFT sürücü kodlarım yer alıyor. TFT ekran yerine başka bir görüntüleme aracı kullanılırsa, bunun yerine bir başka ekran sürücüsü konması gerekir.
    Sözünü ettiğim controllersTech.com sitesindeki örnekte ekran yok, mesajlar ekran yerine USART1 üzerinden seri porta printf komutları ile veriliyor.
    Ben çıktıları TFT ye yönlendirmek üzere siteden aldığım orijinal koalarda değişiklikler yaptım.

PROJEYE DOSYALARIN EKLENME YÖNTEMİ

Basitçe, daha önceki projelerimden ve controllersTech.com dan indirdiğim dosyalardan kopyala/yapıştır yöntemi ile ekleme yaptım.
Derleyicinin Drivers/Displays/Tft_basic/ klasörü içindeki dosyalara erişebilmesi için project/Properties/ altından erişilen aşağıdaki path tanımlarını yapmak gerekiyor:

Ayrıca benim kodlarımın gerektirdiği bazı derleyici tercihlerini de yine project/properties altında erişilen project defines penceresine eklemek gerekiyor. Bu tanımlar kullandığım TFT nin özelliklerini ve çözünürlüğünü belirliyor. (SPIMODE ve TFT_320x240)

FATFS KODLARINDA YAPILMASI GEREKEN DEĞİŞİKLİKLER

Buraya kadar yaptıklarımız ile projeye kendi kodlarımızı eklemiş olduk. Ancak FATFS ile bizim kodlarımızı birbirine bağlayacak bazı düzenlemeler gerekiyor.

Zira FATFS genel bir paket, SD kart, hard disk, USB gibi farklı ortamlar için kullanılabilecek “middleware” niteliğinde. Bu nedenle, FATFS’i SD kart ile konuşturacak, SD kart ile doğrudan çalışacak alt seviye kodları ayrıca sağlamak gerekiyor. Bizim durumumuzda bu kodlar fatfs_sd.c/h dosyalarında bulunuyor.

Şimdi FATFS in bizim SD Karta özel fonksiyonlarımıza erişimini sağlayacak işlemleri yapalım.

Bu bağlantıyı sağlayacak fonksiyonlar FATFS ile birlikte projemize eklenmiş olan user_diskio.c dosyası içinde.

user_diskio.c içinde user_initialize(…), user_status(…), user_read(…), user_write(…) ve user_ioctl(…) adlı 5 fonksiyonun “USER CODE” bölümlerine kendi fonksiyonlarımızı çağıran kodları aşağıdaki gibi yazmamız gerekiyor. Eklenen/değiştirilen satırları kırmızı ile gösterdim.

/**
  * @brief  Initializes a Drive
  * @param  pdrv: Physical drive number (0..)
  * @retval DSTATUS: Operation status
  */
DSTATUS USER_initialize (
BYTE pdrv           /* Physical drive nmuber to identify the drive */
)
{
  /* USER CODE BEGIN INIT */
	return SD_disk_initialize(pdrv);
  /* USER CODE END INIT */
}

/**
  * @brief  Gets Disk Status
  * @param  pdrv: Physical drive number (0..)
  * @retval DSTATUS: Operation status
  */
DSTATUS USER_status (
	BYTE pdrv       /* Physical drive number to identify the drive */
)
{
  /* USER CODE BEGIN STATUS */
	return SD_disk_status(pdrv);
  /* USER CODE END STATUS */
}


/**
  * @brief  Reads Sector(s)
  * @param  pdrv: Physical drive number (0..)
  * @param  *buff: Data buffer to store read data
  * @param  sector: Sector address (LBA)
  * @param  count: Number of sectors to read (1..128)
  * @retval DRESULT: Operation result
  */
DRESULT USER_read (
	BYTE pdrv,      /* Physical drive nmuber to identify the drive */
	BYTE *buff,     /* Data buffer to store read data */
	DWORD sector,   /* Sector address in LBA */
	UINT count      /* Number of sectors to read */
)
{
  /* USER CODE BEGIN READ */
	return SD_disk_read(pdrv, buff, sector, count);
  /* USER CODE END READ */
}

/**
  * @brief  Writes Sector(s)
  * @param  pdrv: Physical drive number (0..)
  * @param  *buff: Data to be written
  * @param  sector: Sector address (LBA)
  * @param  count: Number of sectors to write (1..128)
  * @retval DRESULT: Operation result
  */
#if _USE_WRITE == 1
DRESULT USER_write (
	BYTE pdrv,          /* Physical drive nmuber to identify the drive */
	const BYTE *buff,   /* Data to be written */
	DWORD sector,       /* Sector address in LBA */
	UINT count          /* Number of sectors to write */
)
{
  /* USER CODE BEGIN WRITE */
  /* USER CODE HERE */
	return SD_disk_status(pdrv, buff, sector, count);
  /* USER CODE END WRITE */
}
#endif /* _USE_WRITE == 1 */

/**
  * @brief  I/O control operation
  * @param  pdrv: Physical drive number (0..)
  * @param  cmd: Control code
  * @param  *buff: Buffer to send/receive control data
  * @retval DRESULT: Operation result
  */
#if _USE_IOCTL == 1
DRESULT USER_ioctl (
	BYTE pdrv,      /* Physical drive nmuber (0..) */
	BYTE cmd,       /* Control code */
	void *buff      /* Buffer to send/receive control data */
)
{
  /* USER CODE BEGIN IOCTL */
    DRESULT res = RES_ERROR;
    return SD_disk_ioctl(pdrv, cmd, buff);
  /* USER CODE END IOCTL */
}
#endif /* _USE_IOCTL == 1 */


Bu fonksiyonlar fatfs_sd.c/h kodları içinde yer alıyor. İsim ve parametrelerine erişmek için fatfs_sd.h başlık doyasını açıp bakabiliriz:

user_diskio.c içerisine eklediğimiz bu fonksiyon çağrılarındaki parametrelerin fatfs_sd.h deki tanımlara uygun olmasına dikkat edilmelidir.

STM32F1xx_it.c İÇİNDE YAPILMASI GEREKEN DEĞİŞİKLİKLER

SD kart üzerinde işlem yapan fatfs.sd.c fonksiyonlarının bazı zamanlayıcılara ihtiyacı var. Tim1 ve Tim2 adı verilmiş olan 10 milisaniyelik bu sayaçları STM32F1xx_it.c içinde tanımlayarak systick() ile 10 milisaniyede bir eksiltmemiz gerekiyor.

STM32F1xx_it.c içinde Tim1 ve Tim2 sayaç tanımları
STM32F1xx_it.c içinde systick() interrupt içinden timer azaltma

MAIN.c İÇİNDE YAPILACAK EKLEMELER

main.c başlığına tft_basic.h eklenmesi

Main.c nin, TFT sürücü veri ve fonksiyonlarına ulaşabilmesi için tft_basic.h başlığını eklemek gerekiyor.

main.c içine TFT başlangıç ve FATFS_SD test fonksiyon çağrılarının eklenmesi.

Son olarak da, projemizi çalıştırıp test etmek için gereken satırları main.c nin USER_CODE_BEGIN/END 2 aralığına yukarıda görüldüğü gibi ekliyoruz.

SONUÇ – PROGRAMIN ÇALIŞTIRILMASI VE TEST ÇIKTILARI

Şimdi sıra programımızı “build” komutu ile derleyip, devamında “debug” komutu ile MCU ya aktararak çalıştırmaya geldi.

Başlarda da belirttiğim gibi, bu projede controllersTech.com dan aldığım kodları kullandım. TFT sürücüler bana ait. SD karta yönelik olarak kendi yazdığım kodlar da var, gelecek projelerimde kendi kodlarımı kullanarak devam edeceğim. Arada bir başkalarının çalışmalarına da bakmak insana farklı yaklaşımlar açısından ilham veriyor.

Kendi kodlarımla çalıştığım daha karmaşık işlemler için bir başka yayın yapacağım.

Şimdilik bu projenin çıktılarını aşağıdaki gibi vererek bu yayına son verelim.:

Bu yayının sonu – Selçuk Özbayraktar Temmuz 2020

13 Replies to “STM32-FATFS İLE SD KART UYGULAMALARI – 1”

  1. hocam merhabalar,
    acaba bağlantı şeması ve kullandığın malzelerin ne olduğu öğrenme şansımız var mıdır?

    1. Merhaba, Mehmet Can Bey,
      Yayının GPIO ayarları paragrafında bu bilgiler var ama madem istediniz, Kullanılan Malzemeler ve bağlantılar başlıklı bir paragraf daha ekledim.
      Selamlarımla,

    1. Osman Bey merhaba,
      Yayınımda bu konuya meraklı genç arkadaşlarıma yol göstermeye yeterli bilgi ve kod paylaştığımı düşünüyorum. Vermiş olduğum bilgiler ile gelip de takıldığınız noktada yardımcı olmak için elimden geleni yapacağıma da söz veriyorum. Yeter ki öğrenmek için biraz çaba göstermiş olduğunuzu göreyim. Bu güne kadar bu tür istekleri karşılamak üzere -yani proje dosyalarının tamamının verilmesini- bana biraz yük de getirse dosyaları hazırlayıp zip’leyip gönderiyordum. Ancak bunun sizlere yardım değil, işi öğrenmenize engel olan bir eylem olduğunu farkettim.

      Son olarak dosyaları verdiğim bir arkadaş da teşekkür bile etmeden arkasını dönüp gitti, sonucun ne olduğunu sorduğum mesajlarıma da tenezzül edip yanıt dahi vermedi.

      Sonuç olarak, lütfen vermiş olduğum bilgilerle ilerlemeye çalışıp takıldığınız noktada bana başvurun. O zaman seve seve yardımcı olacağım. Benim amacım, niyeti bir ödevi kısa yoldan yetiştirmek değil, ortaklaşa bir ilgi alanında paylaşımda bulunmak olan arkadaşları desteklemek, bu mesleği sevmelerini sağlamak.
      Sevgi ve selamlarımla,

      1. Selçuk Bey Merhaba,

        Tüm ayarları yaptım ve kütüphane oluşturdum. Bunu STM32WB55 serisinde yaptım. Kendime göre SD kart kütüphanelerini de oluşturdum. FreeRTOS içinde bir thread açıp Queue içine attığım bilgileri SD karta yazmaya çalışıyorum ama hata veriyor. Bari 2 -3 satır SD karta byte[] nasıl yazılır gösterseniz nasıl olur?

  2. Merhaba,
    SD_Card_CntTech.c ve SD_Card_2020.c dosyalarını herhangi bir yerde göremedim de nereden ulaşabilirim.

    Teşekkürler

    1. Erdinç bey merhaba,

      SD_Card_CntTech.c dosyasını kullanmadığım için program yapısından çıkardım. Diğerini size mail ile gönderdim.

      Selamlarımla,

  3. Selçuk Bey kolay gelsin, sizinle mailden ya da herhangi bir iletişim adresinizden iletişime geçme şansım var mı acaba? STM32 ve SD kart hakkında bir kaç problem yaşıyorum yardımlarınızı rica edecektim. Şimdiden teşekkür ederim iyi çalışmalar.

  4. hocam ben stm32f103c8t6 ile sd karta veri yazmaya çalışıyorum. bu bir okul projesinin parçası olarak kullanılacak. elimde bir kaç farklı sd card mevcut, ayrı ayrı deniyorum hepsinde şu ana kadar FR_NOT_READY ve sadece bir seferinde ise FR_DISK_ERR alıyorum f_mount() dan. sorun donanımsal olmasa gerek. dediklerinizi adım adım yaptım, buradan önce bir çok kaynaktan da yararlandım. benim düşünceme göre sorunun kaynağı yazılımsal lakin sorunu çözemiyorum. rica etsem kodları paylaşmanız mümkün müdür? belki sorunumu çözer. sizi haberdar ederim.

    1. Can Bey, SD kartınızın FAT32 ile formatlanmış olduğundan emin misiniz? Ben başka formatları denemedim.
      Kodları paylaşmaya gelince, profesyonel amaçlarla çalışmadığımdan kod geliştirirken sürüm kontroluna dikkat etmiyor, çalışmaya devam ederken kodlarımı değiştirip duruyorum. Bu nedenle blog yayınını yaptıktan bir süre sonra makinada yüklü olan kod bambaşka bir kılığa girmiş oluyor. (Kötü bir huy malesef, yayına taban oluşturan kodları olduğu gibi saklamam gerektiğini biliyorum.) Ama yayına koymuş olduğum detaylı program listeleri her türlü bilgiyi içeriyor.
      Size kodları göndermek için geri dönüp her şeyi yeniden test etmem gerekiyor. Örneğin TFT sürücülerimi arada geliştirdiğim için TFT kullanan eski kodlarımı da buna göre revize etmek zorundayım. STM32Cube IDE nin yeni sürümleri de böyle güncellemeler gerektiriyor, eski kodlar oldukları gibi çalışmıyorlar. Eski programlara işim düştükçe bu düzeltmeleri yapıyorum, işim düşmezse öylece bekliyorlar.
      Sizin için buna el atıp, kodlarımı gözden geçireceğim ve paylaşacağım ama şu anda meşgul olduğum işler nedeniyle bu bir kaç hafta vakit alacak.

      Bu arada siz SD kart formatlarınızın FAT32 oılup olmadığını, SD kart boyutlarınızı kontrol edip bilgi verebilirsiniz. Sizin sorununuz temel bir aşamada, kart açılıp okunamıyor bile. Belki sorun kendiliğinden çözülür.

      Selamlarımla,

    1. Erdem Bey merhaba,
      Önceleri blog sayfama yorum geldiğinde bir e mail ile bilgilendirilirdim ama artık o işe son vermişler anlaşılan. O nedenle mesajınızı yeni gördüm. Kodları güncellemem gerekiyor. Ondan sonra paylaşırım, 15 gün alabilir.

      Selamlar,

      1. Merhaba Selçuk Bey,

        Bilgi için teşekkür ederim. Dönüşünüzü bekliyor olacağım.

        Saygılarımla,

Comments are closed.