|
Виж темите без отговор | Виж активните теми
Дата и час: Вто Юли 28, 2026 1:18 am
Четене на SD (Secure Digital) Card
| Автор |
Съобщение |
|
npelov
Ранг: Почетен член
Регистриран на: Пет Яну 22, 2010 5:46 pm Мнения: 680
|
 Четене на SD (Secure Digital) Card
Пробвам се да прочета SD карта, но нещо не ми се получава. Контролера е PIC16F874.
До момента успях да инициализирам картата с команди:
CMD0
CMD8
CMD58
CMD55+ACMD41
След последната получавам отговор 0x00, а преди това когато няма грешка е 0х01 - както си пише по спецификация.
След това опитах команда CMD9 - работи и връща смислени неща съгласно спецификацията.
CMD17 обаче отказва да работи. Изобщо. При четенето опитах следните подходи:
Опитах:
1. изпращам CMD16 за да укажа големина на блока 1 байт - отговор - ОК, четене - никакво.
2. Махнах CMD16 и прочитам и показвам 4 байта, и след това с цикъл прочитам останалите
Резултати:
1. След CMD17 получавам 0xFF
2. С цикък пропускам всички0xFF -> получавам няколко 0x00 и пак 0xFF
3. С цикъл чакам токен за начало на данни - 0xFE -> отново следват 0x00 и/или 0xFF.
4. Опитах различни закъснения в цикъла (от 40us до 200ms) - никаква разлика
Кода след толкова опити е каша, но все пак ще пусна малко:
 |  |  |  | Код: ; writeSPI - write byte in WREG and read in WREG ; readSPI - write 0xFF and read in WREG readSPI: movlw 0xFF writeSPI:
;movf SSPBUF, w movwf SSPBUF ;write
waitSSPIF: btfss PIR1, SSPIF goto waitSSPIF ; wait bcf PIR1, SSPIF
movf SSPBUF, w ; read return
sdWriteCmd17 ; read single block
call readSPI
movlw 0x40+.17 movlw 0x51 movwf sdCmd ; display on LCD call writeSPI
movf sdAddr3, w ; MSB first call writeSPI movf sdAddr2, w call writeSPI movf sdAddr1, w call writeSPI movf sdAddr0, w call writeSPI
call readSPI ; send 8 clock sycles after the command
movlw .10 movwf sdReadRetryCount movlw 0xFF movwf sdResponse
retryGetResponseCmd17
decf sdReadRetryCount, f skipnz return call readSPI movwf sdResponse xorlw 0xFF skipnz goto retryGetResponseCmd17
;call sdWriteCmd
callw delayms, .1
movlw .255 movwf sdReadRetryCount
retryReadCmd17 callw delayms, .1 decf sdReadRetryCount, f skipnz goto cmd17Timeout
call readSPI movwf sdCrc xorlw 0xFF skipnz goto retryReadCmd17
movf sdReadRetryCount, f skipz return
cmd17Timeout ; error - timeout setDDAddress 0x40 + .17 callw writeChar, 'E' callw writeChar, 'r' callw writeChar, 'r'
return
;................. в main.asm
button1pressed2 delaymsm .10 btfss PORTB, button1 goto $-1
ledOn bcf sdCsPort, sdCsBit callw delayms, .1
call sdWriteCmd17
setDDAddress 0x40
call readSPI movwf sdOCR3 call writeHexLcd
call readSPI ; crc byte 1 movwf sdOCR2 call writeHexLcd
call readSPI ; crc byte 2 movwf sdOCR1 call writeHexLcd
call readSPI movwf sdOCR0 call writeHexLcd
call readSPI call writeHexLcd call readSPI call writeHexLcd call readSPI call writeHexLcd call readSPI call writeHexLcd
clrf sdReadRetryCount readLoop1 call readSPI decfsz sdReadRetryCount, f goto readLoop1
clrf sdReadRetryCount readLoop2 call readSPI decfsz sdReadRetryCount,f goto readLoop2
call lcdJob2 incf sdAddr1, f incf sdAddr1, f
bsf sdCsPort, sdCsBit
callw delayms, .50 ledOff
movlw 9 movwf stage
call displayStage goto endStage
|  |  |  |  |
Последна промяна npelov на Нед Юли 17, 2011 1:40 pm, променена общо 1 път
|
| Нед Юли 17, 2011 12:02 pm |
|
 |
|
npelov
Ранг: Почетен член
Регистриран на: Пет Яну 22, 2010 5:46 pm Мнения: 680
|
Ето малко подробности (едит):
Чатенето връща:
R1 - 0х00
FE 00 00 00 00 00 - ако големината на блока е 2 байта
Първите байтове от картата всъщност са:
EB 58 90 4D 53 44 4F 53
Каквото и да правя тези байтове не излизат. Адреса който изпращам е 00 00 00 00. Да не би да има някакъв трик в адресирането?
|
| Нед Юли 17, 2011 12:30 pm |
|
 |
|
npelov
Ранг: Почетен член
Регистриран на: Пет Яну 22, 2010 5:46 pm Мнения: 680
|
CMD9 работи - изпращам 49 00 00 00 00 FF, чакам FE и чета:
00 5Е 00 32 5F 59 83 CF
ED B6 FF 87 96 40 00 3F
C4 0F
|
| Нед Юли 17, 2011 1:51 pm |
|
 |
|
Cekins
Ранг: Форумен бог
Регистриран на: Сря Апр 20, 2005 12:02 pm Мнения: 9119 Местоположение: Разград
|
Що не разгледаш някоя библиотека за SD?
Това да се мъчиш да подкарваш такива работи си е малко спортна злоба. Скоро ползвах една библиотека с FAT16 и сякаш много прилично се държи. Пък на мен ми трябват и файлове при това.
|
| Нед Юли 17, 2011 2:51 pm |
|
 |
|
npelov
Ранг: Почетен член
Регистриран на: Пет Яну 22, 2010 5:46 pm Мнения: 680
|
щото няма за асемблер. Пък и не съм виждал библиотека за микроконтролер за някакъв хардуер да е супер универсална. Или са вързани за няколко конкретни контролера, или пък изискват да са на определени пинове... До сега съм подкарал много хардуер и нито една библиотека.
|
| Нед Юли 17, 2011 2:56 pm |
|
 |
|
npelov
Ранг: Почетен член
Регистриран на: Пет Яну 22, 2010 5:46 pm Мнения: 680
|
Нещо с адресирането не е наред. Пиша адрес 01 00 00 00 и получавам съдържание, което иначе се намеира на офсет 0х00FF3600 според WinHex.
Четох в нета някакъв имал подобен проблем. Каза, че използвал логически адрес, а трябвало физически. Тук ме хвърли в размисъл. Никъде не намерих нищо за адресиране на SD карта включително в смотаната спецификация ... навсякъде пише (или поне така аз го тълкувам), че адрес 00 00 00 00 е първия адрес от картата.
Както и да въртиш байтовете 01 00 00 00 не може да стане на 00 FF 36 00 ...
Последна промяна npelov на Нед Юли 17, 2011 3:39 pm, променена общо 1 път
|
| Нед Юли 17, 2011 3:31 pm |
|
 |
|
npelov
Ранг: Почетен член
Регистриран на: Пет Яну 22, 2010 5:46 pm Мнения: 680
|
... няма нищо общо с подкарването... По метода на опита и грешката открих че началния адрес на картата е: 0x0000CA00 ... въпроса е защо и същия ли е за всяка карта?
|
| Нед Юли 17, 2011 3:39 pm |
|
 |
|
bateAz
Ранг: Форумен бог
Регистриран на: Нед Сеп 26, 2004 4:11 pm Мнения: 3750 Местоположение: София
|
1. Прочети сектор #0 на картата. Там се намира т.н. Master Boot Record ( по аналогия с твърдите дискове )
2. Проверка за валидност: на отместване 0x1FE трябва да има 0xAA55
3. На отместване 0x1BE с дължина 4 байта се намира адресът на първия сектор от DOS/WIN партишъна ( тип 4 или 6 )
4. Действай, пари нема!
|
| Нед Юли 17, 2011 3:45 pm |
|
 |
|
npelov
Ранг: Почетен член
Регистриран на: Пет Яну 22, 2010 5:46 pm Мнения: 680
|
Както вече казах физическия адрес който подавам и адреса в картата се различават с 0xCA00 байта. Прочетох 2 байта от адрес 00 00 01 FE + CA00 = 00 00 CB FE и там действително има 55АА... Защо трябва да добавям това отместване 0xCA00 и защо е различно за всяка карта.
Даже успях да прочета текстов файл - с WinHex му видях адреса, добавих 0xCA00 - и всичко си е така както го написах с Notepad...
|
| Нед Юли 17, 2011 4:17 pm |
|
 |
|
bateAz
Ранг: Форумен бог
Регистриран на: Нед Сеп 26, 2004 4:11 pm Мнения: 3750 Местоположение: София
|
|
| Нед Юли 17, 2011 4:33 pm |
|
 |
|
npelov
Ранг: Почетен член
Регистриран на: Пет Яну 22, 2010 5:46 pm Мнения: 680
|
прочетох 4 байта - 6F 74 68 65 (CRC = 37 74) - изглежда ли достоверно? Само че нещо си объркал - като разглеждам с WinHex на адрес 0х01BE наистина има тези байтове, но това е текст "Remove disks or other media. Disk error Press any key to restart". Мисля че си се заблудил от размера на картата - тази е 256 МБ, а те нямат партишънинг. Форматирани са като флопи диск
Все пак колкото и опити да провеждам съвпадат напълно със това, което виждам в Hex редактора, с тази разлика, че на картата задавам адреса с отместване 0х0000CA00. Как е възможно да не намеря нищо по въпроса в спецификацията. Никакво отместване, никакви особености за адреса. Нищо дори в нета не намерих. На всякъде съветват "опитай с адрес 0 за да видиш буут рекърда". Аз го виждам, но на адрес 0x0000CA00.
|
| Нед Юли 17, 2011 5:20 pm |
|
 |
|
npelov
Ранг: Почетен член
Регистриран на: Пет Яну 22, 2010 5:46 pm Мнения: 680
|
Опалааааа.... Открих че WinHex наистина не показва физическото устройство. Отворих устройството с FlexHEX и там на адрес 0х01BE има 00 03 06 00 -> това като 4 байта int трябва да е 0х00060300. Ама нещо не се връзва - нито на 0х00060300 има нещо, нито на 0х00030600.
Все пак съм четял правилно - в началото на картата си е пълно с 00
|
| Нед Юли 17, 2011 5:38 pm |
|
 |
|
npelov
Ранг: Почетен член
Регистриран на: Пет Яну 22, 2010 5:46 pm Мнения: 680
|
С winhex разкодирах кое какво означава:
1BE - 00 (80 за активен партишън)
1BF - start head - 3
1C0 - start sector - 6
1C1 - start cylinder - 0
...
1C6 - sectors preceding partition 1 - 101
Хубаво - глави, сектори ама как са ги напъхали тия глави в СД карта. С други думи - как да знам колко байта е един сектор, колко сектора на цилиндър, колко глави има една карта. Пише ли го в спецификацията? Т.е. хардуерно ли е?
Едит - отговора се намира на 1C6 -> 101 ... не знам колко байта е това число, но 1, 2 или 4 байта в този конкретен случай все е 101. 101*512 = 51712 или 0хCA00  ето го моето отместване. А аз си мислех че карти < 1ГБ се форматират без партишън - като дискета.
Последна промяна npelov на Нед Юли 17, 2011 9:02 pm, променена общо 1 път
|
| Нед Юли 17, 2011 8:33 pm |
|
 |
|
bateAz
Ранг: Форумен бог
Регистриран на: Нед Сеп 26, 2004 4:11 pm Мнения: 3750 Местоположение: София
|
 |  |  |  | Код: // четене на MasterBoot Sector offs = read_sector(0); if (offs == 0xFFFF) return 0xFFFF; // проверка за валидност на MBR memcpy( &ui, &disk_buff[offs + 0x1FE], 2 ); if (ui != 0xAA55) return 0x8001; // данни за партишън #0 : type = 4 или 6 if ((disk_buff[offs + 0x1BE + 4] != 4) && (disk_buff[offs + 0x1BE + 4] != 6)) { drive_first_sector = 0; } else { // чете позицията на 'start sector' на партишъна memcpy( &drive_first_sector, &disk_buff[offs + 0x1BE + 8], 4 ); } // четене на Boot Sector на DOS партишъна offs = read_sector(drive_first_sector); if (offs == 0xFFFF) return 0xFFFF; // проверка за валидност на Boot Sector memcpy( &ui, &disk_buff[offs + 0x1FE], 2 ); if (ui != 0xAA55) return 0x8004; // проверка за брой байтове в сектор = 512 memcpy( &ui, &disk_buff[offs + 0x0B], 2 ); if (ui != 0x0200) return 0x8005; // проверка за брой на FAT = 2 if (disk_buff[offs + 0x10] != 2) return 0x8003; // попълва брой сектори в клъстер sectors_per_cluster = (unsigned int)(disk_buff[offs + 0x0D]); if (sectors_per_cluster == 0) return 0x8006; // попълва брой на елементите в основния каталог memcpy( &number_of_dir_entries, &disk_buff[offs + 0x11], 2 ); // попълва размер на едно копие на FAT в брой сектори memcpy( &fat_size, &disk_buff[offs + 0x16], 2 ); // размер на партишъна в сектори number_of_sectors = 0; memcpy( &number_of_sectors, &disk_buff[offs + 0x13], 2 ); if (number_of_sectors == 0) memcpy( &number_of_sectors, &disk_buff[offs + 0x20], 4 ); // размер на партишъна в брой клъстери number_of_clusters = number_of_sectors / sectors_per_cluster; if ((number_of_clusters > 65526) || (number_of_clusters < 4085)) return 0x8002; // маски за съвпадение да два адреса да са в един сектор или един клъстер in_cluster_mask = in_sector_mask * (unsigned long)(sectors_per_cluster); // стартов сектор на FAT_1 и FAT_2 memcpy( &ui, &disk_buff[offs + 0x0E], 2 ); fat_first_sector = drive_first_sector + (unsigned long)(ui); // стартов сектор на ROOT root_first_sector = fat_first_sector + (unsigned long)(fat_size) + (unsigned long)(fat_size); data_first_sector = root_first_sector + (number_of_dir_entries >> 4); // поставя текуща да е основната директория currdir_first_sector = root_first_sector; currdir_nmbr_of_entries = number_of_dir_entries; // търсенето на свободен клъстер да започне от началото на партишъна last_got_free_cluster = 0; // изход ОК mounted = 1; return 0; |  |  |  |  |
|
| Нед Юли 17, 2011 8:48 pm |
|
 |
|
npelov
Ранг: Почетен член
Регистриран на: Пет Яну 22, 2010 5:46 pm Мнения: 680
|
да, мерси ... малко ме обърка като каза че отместването на партишъна е на 1BE. Всъщност от кода дето си пуснал се вижда че е 1BE + 8 или както сам отгатнах - 1C6. Както виждам от твоя код отместването е 4 байта Int.
|
| Нед Юли 17, 2011 9:09 pm |
|
|
Кой е на линия |
Потребители разглеждащи този форум: 0 регистрирани и 3 госта |
|
Вие не можете да пускате нови теми Вие не можете да отговаряте на теми Вие не можете да променяте собственото си мнение Вие не можете да изтривате собствените си мнения Вие не можете да прикачвате файл
|
|