Required knowledge:
[HW] Kontrollermoodul, [HW] Kasutajaliidese moodul,
[LIB] Sisend-väljundviigud, [LIB] Graafiline LCD
Secure Digital (SD) is a memory card format developed by the SD Card Association (SDA) for portable devices. Communication can use the card's SD interface or the SPI bus. SPI is a good option for simpler systems. The SD card operating voltage is 3.3 V.
An SD card is basically a large set of memory bits that can be modified, but other devices cannot use the stored data without a file system. The file system enables working with files instead of the raw memory array. One of the main tasks of a file system is to organize logical files on the physical storage device. The storage space is divided into sectors, usually 512 bytes in size. Since it is more efficient to work with larger units, sectors are grouped into clusters. A cluster is a contiguous set of sectors. Larger clusters reduce fragmentation for large files, but increase wasted space for small files because some clusters remain only partially filled.
Portable storage devices and memory cards commonly use the FAT (File Allocation Table) file system, supported by most operating systems. The FAT file allocation table contains an entry for each file's starting cluster, which points to the next cluster for the file, and so on until the end-of-file cluster. In FAT, clusters are addressed in an n-bit address table where n depends on FAT version: 12 (FAT12), 16 (FAT16), or 32 bits (FAT32). In older FAT versions, large disk sizes required large cluster sizes, resulting in inefficient space usage.
SD cards are available in three physical form factors: standard SD, smaller miniSD, and smallest microSD. microSD is common in mobile phones and tablets and is also used in the HomeLab Controller module. In addition to form factor, SD cards are divided into generations:
SD cards are available in different speeds, classified by Speed Class Rating (SCR). Common speed classes are:
The HomeLab Controller module has a microSD card slot. The card is connected to the SPI bus, and on the HomeLab II Controller module it shares the SPI bus with the Ethernet controller. The HomeLab library includes the FatFs file system module, which you can read about at http://elm-chan.org/fsw/ff/00index_e.html. In FatFs, there are two layers for SD card communication. The first disk layer is in diskio.h and mmc.c. It handles direct communication with the disk and its initialization, including low-level read/write functions. For the end user, the most important function is disk_initialize, which initializes the selected card.
For the file system to work, the function disk_timerproc must be called at 100 Hz. This is handled by a timer interrupt. The HomeLab Controller module does not have a real-time clock, so file timestamps are constant.
The second file system layer is in ff.c and ff.h. It communicates with the first layer via low-level functions and provides file operations. The file system can be mounted only after the disk is initialized, using f_mount. The function takes a file system object and returns a result code.
After initializing the disk and file system, you can start working with files. To open a file use f_open with the desired mode. There are many options, for example FA_WRITE opens the file for writing. Then you can write to the file with f_write or read with f_read. When done, close the file with f_close. FAT12, FAT16, and FAT32 file systems are supported and tested.
The next example demonstrates reading and writing a text file. Pressing S1 initializes the card and file system. Pressing S3 creates a directory on the disk and a file inside it, then writes content to the file. S2 displays the file contents on the screen.
// HomeLab SD card usage example program #include <stdio.h> #include <homelab/module/ff.h> #include <homelab/module/diskio.h> #include <homelab/delay.h> #include <homelab/pin.h> #include <homelab/module/lcd_gfx.h> // Main program int main (void) { // Disk error flag int f_err_flag = -1; // File system error flag int d_err_flag = -1; char f_err_buf[16]; char d_err_buf[16]; int variableName = 0; static FATFS FATFS_Obj; FIL fil_obj; char read_buf[20]; unsigned char new_value1, old_value1 = 0; unsigned char new_value2, old_value2 = 0; unsigned char new_value3, old_value3 = 0; // Configure LEDs and turn them off pin_setup_output(led_red); pin_set(led_red); pin_setup_output(led_yellow); pin_set(led_yellow); pin_setup_output(led_green); pin_set(led_green); // LCD initialization and text lcd_gfx_init(); lcd_gfx_goto_char_xy(3, 2); lcd_gfx_write_string("SD Card"); // Infinite loop while (1) { // Read button values new_value1 = pin_get_debounced_value(button1); new_value2 = pin_get_debounced_value(button2); new_value3 = pin_get_debounced_value(button3); // S1 pressed. Register only one press. if((!new_value1) && (old_value1)) { // SD card initialization // On failure, set error flag. d_err_flag = disk_initialize(0); sw_delay_ms(2); // File system initialization // On failure, set error flag. f_err_flag = f_mount(0, &FATFS_Obj); sw_delay_ms(2); } // S2 pressed. Register only one press if((!new_value2) && (old_value2)) { // Open file "file.txt" for read f_open(&fil_obj, "/Homelab/fail.txt", FA_READ); // Read first 14 characters from file f_gets (read_buf,14, &fil_obj); f_close(&fil_obj); // Write the first 14 characters to the screen lcd_gfx_goto_char_xy(0, 0); lcd_gfx_write_string(read_buf); } // S3 pressed. Register only one press if((!new_value3) && (old_value3)) { // Random variable to store in file variableName = 4; // Create directory "Homelab" on disk f_mkdir("Homelab"); // Create text file "fail.txt" in the directory f_open(&fil_obj, "/Homelab/fail.txt", FA_CREATE_NEW); // Open file for writing f_open(&fil_obj, "/Homelab/fail.txt", FA_WRITE); // Write to file f_printf(&fil_obj, "Variable: %d", variableName); // Close file f_close(&fil_obj); } // Remember previous button values old_value1 = new_value1; old_value2 = new_value2; old_value3 = new_value3; // If SD card is initialized and OK, green LED on, // otherwise red LED on if((f_err_flag == 0) && (d_err_flag == 0)) { pin_clear(led_green); pin_set(led_red); } else { pin_set(led_green); pin_clear(led_red); } // Display error flag values: // -1 not initialized // 0 no error // 1 (or higher) error sprintf(f_err_buf, "Error_f: %02d", f_err_flag ); sprintf(d_err_buf, "Error_d: %02d", d_err_flag ); lcd_gfx_goto_char_xy(0, 4); lcd_gfx_write_string(f_err_buf); lcd_gfx_goto_char_xy(0, 5); lcd_gfx_write_string(d_err_buf); sw_delay_ms(2); } }