Работа с SD-картой на ПИК и CCS C

 

В этой статье показана работа с  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 микроконтроллера!

SD-Card module schematic

Изображения собранного прототипа:

SD-Card module on breadboard

SD-Card experimental setup

 

 

Программа

 

Изменения в 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

 

Загрузка...