В этой статье показана работа с SD-картой с файловой системой FAT16. Она основана на примере драйвера MMC/SD-Card (mmcsd.c) и драйвера FAT (fat.c) компилятора CCS C.
К сожалению, данные примеры работают не совсем корректно. Необходимые изменения описаны в данной статье.
Железо
SD-карта может быть подключена к микроконтроллеру через шину SPI, поэтому только 4 вывода (SDI, SDO, SCK, CS) необходимы для такого соединения.
SD-карта работает при напряжениях 2.7 В .. 3.6 В в то время как ПИКи 18F серии обычно работают от 5 В. Поэтому необходим преобразователь напряжения. Для этого использована микросхема 74AC125.
Модуль карты
На рисунке показана схема модуля карты с преобразователем напряжений. Выводы разъема SV1 должны быть соединены с выводами микроконтроллера.
Внимание: SDO и SDI - названия выводов со стороны SD-карты, т.е. SDO должен быть соединен с выводом SDI микроконтроллера, а SDI - с выводом SDO микроконтроллера!
Изображения собранного прототипа:
Программа
Изменения в mmcsd.c
найдите строку
uint32_t g_mmcsdBufferAddress;
и после нее вставьте:
uint32_t g_mmcsdPartitionOffset;
Теперь, перед функцией "mmcsd_init" добавьте новую функцию:
void mmcsd_check_part(uint16_t off) { if (g_mmcsd_buffer[off + 0] == 0x80) { // active partition uint8_t t; t = g_mmcsd_buffer[off + 4]; if (t == 0x04 || t == 0x06 || t == 0x0B) { // FAT16 or FAT32 partition g_mmcsdPartitionOffset = make32( g_mmcsd_buffer[off + 11], g_mmcsd_buffer[off + 10], g_mmcsd_buffer[off + 9], g_mmcsd_buffer[off + 8]) * MMCSD_MAX_BLOCK_SIZE; } } }
в функции "mmcsd_init" , сразу после строки:
r1 = mmcsd_load_buffer();
добавьте строки:
g_mmcsdPartitionOffset = 0; mmcsd_check_part(0x1EE); mmcsd_check_part(0x1DE); mmcsd_check_part(0x1CE); mmcsd_check_part(0x1BE);
И накоенц, в функции "mmcsd_move_buffer", после строки:
new_block = new_addr - (new_addr % MMCSD_MAX_BLOCK_SIZE);
добавьте:
new_block += g_mmcsdPartitionOffset;
Изменения в fat.c
В драйвере CCS "fat.c" функции "get_next_addr" и "get_prev_addr" некорректно обрабатывают переходы между кластерами. Ниже приведены скорректированные функции, замените их следующим кодом:
signed int get_next_addr(int32* my_addr) { int32 temp; #ifdef FAT32 int32 c; #else int16 c; #endif // check to make sure that the next iteration will give us a contiguous address temp = *my_addr + 1; if((temp > Data_Start) && ((temp - Data_Start) % Bytes_Per_Cluster == 0)) { // convert the current address into the address of where information about // the address is stored in the FAT, and put this value into the current address c = addr_to_cluster(temp - 1); if(get_next_cluster(&c) == EOF) return EOF; if (c >= #ifdef FAT32 0x0FFFFFF8 #else 0xFFF8 #endif ) return EOF; temp = cluster_to_addr(c); } *my_addr = temp; return GOODEC; }
далее, get_prev_addr() нужно изменить:
signed int8 get_prev_addr(int32* my_addr) { int32 temp; #ifdef FAT32 int32 c; #else int16 c; #endif temp = *my_addr; // if we're trying to go backwards one entry from the beginning of the root, // we won't be able to... if(temp <= Root_Dir) return GOODEC; // check to make sure that the next iteration will give us a contiguous address if((temp >= Data_Start) && ((temp - Data_Start) % Bytes_Per_Cluster == 0)) { c = addr_to_cluster(temp); if(get_prev_cluster(&c) == EOF) return EOF; temp = cluster_to_addr(c) + Bytes_Per_Cluster; } *my_addr = temp - 1; return GOODEC; }
В функции fat_init() найдите следующие строчки:
#ifdef FAT32 Data_Start = Bytes_Per_Cluster + Root_Dir; #else // FAT16
замените на (удалите "Bytes_Per_Cluster +"):
#ifdef FAT32 Data_Start = Root_Dir; #else // FAT16
И наконец, функция get_short_file_name() должна быть заменена на:
signed int get_short_file_name(int32 file_entry_addr, char sname[], int8 type) { int buf, i, j = 0; // one short file name has, at the most, 11 characters for(i = 0; i < 11; ++i) { // read in a character if(mmcsd_read_data(i + file_entry_addr, 1, &buf) != GOODEC) return EOF; // convert the character if(buf != ' ') { if (i == 8 && type != 0x10) sname[j++] = '.'; sname[j++] = tolower(buf); } } if (sname[j - 1] == '.') --j; sname[j] = '\0'; return GOODEC; }
Изменения были протестированы только на FAT16
fat.c:
/// Define your FAT type here /// #define FAT16 //#define FAT32