|
nedoPC.orgElectronics hobbyists community established in 2002 |
|
Author |
Message |
Romanich
Banned
Joined: 12 Oct 2006 16:44 Posts: 608
|
в общем купил в магазине я устройство под названием MMC plus от производителя Kingston. В инструкции на девайс написано что отвечает стандарту MMC 4.0, но совместима с более древними стандартами MMC.
Очень удивило расположение и количество ножек - их не 7 (как в классических MMC), и не 9 (как в SD) - а больше(см. нижний рисунок)
Нумерацию выводов расставил я - в предположении что указанная группа контактов совместима с 9-ми контактами SD. (рисунок ниже)
Далее подрубил её к контроллеру и по SPI завязал обмен.
Два исходника пересмотрел (русский и немецкий) - как с MMC работать в режиме SPI (интересует именно этот режим).
Пробовал команды CMD0(reset),CMD1(init) и CMD17 - block read...
При использовании команды CMD17 - возвращается лажа!!!
или иногда вообще повисает - при опросе байтов в цикле
В чем может быть дело?:
1) неверно определены выводы
2) карта поддерживает другие команды
3) не верен перевод в SPI-режим
4) ?
Помогите разобраться плиз
|
29 Mar 2007 18:50 |
|
|
Romanich
Banned
Joined: 12 Oct 2006 16:44 Posts: 608
|
в кард-ридере/райтере на разъёме дополнительные контакты не импользуются (посмотрел)
MMC отформатирована и на неё записан файл (в WinXP)
зарезервированные пины (8/9) подтянул к питанию +3.3V через резисторы на 4,7кОм
питание контроллера и MMCplus тоже 3.3V
на MMCplus указано напряжение 3,3V
|
29 Mar 2007 18:53 |
|
|
Shaos
Admin
Joined: 08 Jan 2003 23:22 Posts: 22621 Location: Silicon Valley
|
У меня на новом пальме телефоне SD/MMC-карточка с лишними контактами SD-читалкой на моём ноуте НЕ читается, зато читается универсальной читалкой карточек что к компу по USB цепляется. Видимо не всё там стандартно...
|
29 Mar 2007 19:18 |
|
|
Romanich
Banned
Joined: 12 Oct 2006 16:44 Posts: 608
|
На моём рисунке выводы красного цвета для кард ридера/райтера не используются (это точно -смотрел разъём)!
к-р/р - читает и пишет всё! и MMC,SD,CF,и другие редко встречаемые.
USB-шный
можно конечно питание прозвонить с землёй при включенном кард-ридере - чтоб быть уверенным в совпадении распиновки. Но боюсь, что там ПЛИС - тоесть выводы могут переназначаться для каждой MMC/SD
P.S. и всё-таки непонятный у меня девайс-мутант. 9-ножек говорят об SD, а написано что MMC+ 128MB
другого дешёвого к сожалению нет - 128MB(которые счас никто не берет) и сразу 2GB (которые дорого - и не каждый возьмет)
а такой "классики" как ATmel или SanDisk - и подавно нет - антиквариат...
|
29 Mar 2007 19:25 |
|
|
Romanich
Banned
Joined: 12 Oct 2006 16:44 Posts: 608
|
Выдержка из статьи по Flash-носителям:
Несколько удивляет отсутствие прямой совместимости между этими двумя видами карт (т.е. то, что SD неспособна работать по протоколу MMC). Если внимательно рассматривать спецификации обоих типов карт и не обращать внимания на то, что SD может быть толще MMC, то отсутствие такой совместимости даже удивляет, поскольку реализовать её было несложно, да и выглядело бы это очень естественно. Что наводит на мысль о том, что, хотя подобную совместимость можно было реализовать без особых трудностей, SD намеренно разработана не как расширение спецификации MMC, а как отдельный конкурирующий стандарт
А вот выдержка из статьи счастливого юзера, у которого SD-карточка якобы оказалась совместимой с MMC (на которую может я и повёлся):
P.S.: Как выяснилось, SD карты полностью совместимы с карточками MMC, в т.ч. в режиме SPI. "Лишние" выводы в этом режиме не используются. Единственно что стоит сделать - поставить подтягивающие сопротивления на выв. 8 и 9 (в р-не неск. деятков кОм).
ХТО ПРАВЕЕ???
|
29 Mar 2007 19:52 |
|
|
Shaos
Admin
Joined: 08 Jan 2003 23:22 Posts: 22621 Location: Silicon Valley
|
SD-карточки у нас уже обсуждались в прошлом году:
http://www.nedopc.org/forum/viewtopic.php?t=8353
|
29 Mar 2007 20:18 |
|
|
Romanich
Banned
Joined: 12 Oct 2006 16:44 Posts: 608
|
Нашёл!!!
Как раз мой случай на стр.19 сего даташита
Буду разбираца... вначале хотя бы по SPI
Shaos убрал даташит из аплоада...
|
29 Mar 2007 22:38 |
|
|
jdigreze
God
Joined: 02 Jan 2006 02:28 Posts: 1390 Location: Abakan
|
... как и я сам когда-то
Вот рабочий код для AT89S8252:
| | | | Code: ;============================================================================== ;--- описатели портов устройства --- _CS EQU P1.4 MOSI EQU P1.5 MISO EQU P1.6 SCK EQU P1.7
;============================================================================== ;--- описатели для работы SPI --- CMD0 EQU 0 ;reset the sd-card CMD1 EQU 1 ;activates the card's initialization process CMD9 EQU 9 ;read card specific data CMD10 EQU 10 ;read card identification (CID register) CMD17 EQU 17 ;read single block from SD-card CMD24 EQU 24 ;write single block to SD-card CMD55 EQU 55 ;next command to be application
ACMD13 EQU 13 ;read status block
SPI_REG_LEN EQU 010h ;длина регистров CID И CSD
spcr data 0d5h ;SPI control register spsr data 0aah ;SPI status register spif equ 10000000b ;interrupt flag spdr data 086h ;SPI data register
WMCON DATA 096h PS2 EQU 10000000b PS1 EQU 01000000b PS0 EQU 00100000b EEMWE EQU 00010000b EEMEN EQU 00001000b DPS EQU 00000100b WDTRST EQU 00000010b WDTEN EQU 00000001b
;============================================================================== ccitt_crc: mov b,#8 ; 8 Bits In A Byte xrl CRC_H,a ; HI ^= Data l_p1: clr c ; 0 Into Low Bit mov a,CRC_L ; D_CRC << 1 rlc a ; Shift Left mov CRC_L,a ; Store Back mov a,CRC_H ; Get High Byte rlc a ; Shift Left mov CRC_H,a ; Store Back jnc l_p2 ; Skip If Bit 15 Wasn't Set xrl CRC_H,#10h ; XOR In Polynomial High xrl CRC_L,#21h ; XOR In Polynomial Low l_p2: djnz b,l_p1 ; Repeat R0 More Times ret ; Return To Caller
;======================================================================== ; работа с SPI ;======================================================================== spi_init: setb _cs setb mosi setb miso setb sck mov spcr, #01010001b
call spi_sync_byte call spi_sync_byte call spi_sync_byte call spi_sync_byte call spi_sync_byte call spi_sync_byte call spi_sync_byte call spi_sync_byte call spi_sync_byte call spi_sync_byte
clr a mov param1, a mov param2, a mov param3, a mov param4, a call spi_send_command
call spi_read_response cjne a, #001h, _no_response
_wait_for_init: mov a, #CMD1 call spi_send_command
call spi_read_response jnz _wait_for_init
setb cy ret _no_response: mov last_error, #err_sd_init clr cy ret
;--- чтение регистров CID и CSD SD-карты в ОЗУ --- spi_read_csd: mov b, #CMD9 ;номер команды чтения CSD в "В" sjmp spi_read_reg ;переход на обработку команды spi_read_cid: mov b, #CMD10 ;номер команды чтения CID в "В" spi_read_reg: mov dptr, #temp_buffer clr a ;обнулим аккумулятор mov param1, a ;обнулим параметр 1 mov param2, a ;обнулим параметр 2 mov param3, a ;обнулим параметр 3 mov param4, a ;обнулим параметр 4
mov crc_h, a mov crc_l, a
mov a, b ;получим команду из "В" call spi_send_command ;отправить команду
call spi_wait_data jnc _spi_read_cid_err
mov b, #spi_reg_len ;длина буфера _spi_read_cid_l1: push b call spi_read_byte ;получить данные call mem_write_rep ;запишем полученный байт в ОЗУ call ccitt_crc inc dptr ;увеличим указатель ОЗУ на 1 pop b djnz b, _spi_read_cid_l1 ;если не все получено, то повторить
mov last_error, #err_crc call spi_read_byte ;получим байт из SD-карты MSB_CRC16 cjne a, crc_h, _spi_read_cid_err call spi_read_byte ;получим байт из SD-карты LSB_CRC16 cjne a, crc_l, _spi_read_cid_err
setb cy ;данные получены ret ;вернемся
;--- чтение статуса SD-карты (ACMD13) --- ; всегда читаем во внешнее ОЗУ с адреса 0!!! spi_read_status: mov dptr, #00000h
clr a ;обнулим аккумулятор mov param1, a ;обнулим параметр 1 mov param2, a ;обнулим параметр 2 mov param3, a ;обнулим параметр 3 mov param4, a ;обнулим параметр 4 mov a, #CMD55 ;получим команду расширения call spi_send_command ;отправить команду
call spi_read_response ;ждем ответа jnz _spi_read_cid_err ;ошибка выполнения команды
mov a, #ACMD13 ;чтение статуса call spi_send_command ;отправить команду
call spi_wait_data_r2 jnc _spi_read_cid_err
mov b, #042h ;для получения 66 байт sjmp _spi_read_data_l1 ;если все нормально, то читаем данные
;--- была ошибка --- _spi_read_cid_err: clr cy ;ошибка выполнения команды ret ;вернемся
;--- чтение блока данных из SD карты --- ; на входе должен быть установлен DPTR spi_read_data: mov last_error, #err_read mov a, #CMD17 ;команда чтения одного блока данных call spi_send_command ;отправить команду
mov crc_h, #000h mov crc_l, #000h
call spi_wait_data jnc _spi_read_cid_err
call _spi_read_data_d1 ;выполним прием первых 256 байт call _spi_read_data_d1 ;а после еще 256 байт
call spi_read_byte ;получим байт из SD-карты MSB_CRC16 cjne a, crc_h, _spi_read_cid_err call spi_read_byte ;получим байт из SD-карты LSB_CRC16 cjne a, crc_l, _spi_read_cid_err
setb cy ret ;вернемся ;--- _spi_read_data_d1: mov b, #000h ;счетчик 256 байт _spi_read_data_l1: push b ;сохраним, т.к. точно потеряем call spi_read_byte ;получим байт из SD-карты call mem_write_rep ;запишем полученный байт в ОЗУ call ccitt_crc inc dptr ;увеличим указатель ОЗУ на 1 pop b ;восстановим счетчик принятых байт djnz b, _spi_read_data_l1 ;если не все считано, то повторим ret
;--- запись блока данных в SD карту --- spi_write_data: mov last_error, #err_write mov a, #CMD24 call spi_send_command
call spi_read_response jnz _spi_write_err
mov crc_h, a mov crc_l, a
call spi_sync_byte call spi_sync_byte call spi_sync_byte
mov a, #0FEh call spi_send_byte
call _spi_write_data call _spi_write_data
mov a, crc_h call spi_send_byte mov a, crc_l call spi_send_byte
call spi_read_response anl a, #01Fh cjne a, #005h, _spi_write_err _spi_write_busy: call spi_read_byte jz _spi_write_busy ;wait for busy
setb cy ret _spi_write_err: clr cy ret ;--- send 256 bytes block from dptr and accumulate ccitt crc16 --- _spi_write_data: mov b, #000h _spi_write_data_l1: push b movx a, @dptr call spi_send_byte movx a, @dptr call ccitt_crc pop b inc dptr djnz b, _spi_write_data_l1 ret ;--- wait for data block start --- spi_wait_data_r2: call spi_read_response ;ждем ответа R1 jnz _spi_wait_data ;ошибка выполнения команды spi_wait_data: call spi_read_response ;ждем ответа R1 или R2 jnz _spi_wait_data ;ошибка выполнения команды
call spi_read_response ;ждем готовности карты cjne a, #0FEh, _spi_wait_data ;получен не заголовок блока данных setb cy ret _spi_wait_data: clr cy ret
;--- read the response from sd-card --- spi_read_response: call spi_read_byte ;читаем шину cpl a ;инверсия для проверки на #0FFh jz spi_read_response ;если #000h (а фактически #0FFh), то ждем cpl a ;инверсия, для восстановления фактического значения ret ;вернемся
;--- in acc command to be send, and param[1..4] - parameters to be send --- spi_send_command: setb _cs ;отключимся от карты push acc ;запомним номер команды call spi_sync_byte ;межоперационное пространство clr _cs ;подключимся к карте call spi_sync_byte ;синхронизируемся pop acc ;восстановим номер команды orl a, #040h ;установим префикс call spi_send_byte ;отошлем команду mov a, param1 ;получим параметр #1 call spi_send_byte ;отошлем параметр #1 mov a, param2 ;получим параметр #2 call spi_send_byte ;отошлем параметр #2 mov a, param3 ;получим параметр #3 call spi_send_byte ;отошлем параметр #3 mov a, param4 ;получим параметр #4 call spi_send_byte ;отошлем параметр #4 mov a, #095h ;CRC7 для команды "0" (idle), остальные команды без проверки sjmp spi_send_byte ;отошлем CRC7
;--- прием и синхронизация ведется при высоком уровне MOSI spi_sync_byte: spi_read_byte: mov a, #0FFh ;во время приема идет передача "1"
;--- прием и передача идут одновременно, в аккумуляторе данные для передачи и результат приема --- spi_send_byte: mov spdr, a ;загрузим передатчик _spi_send_byte: mov a, spsr ;регистр флагов SPI anl a, #spif ;проверим флаг готовности jz _spi_send_byte ;если передача не завершена, то проверяем снова mov a, spdr ;отсылка прошла успешно, в регистре данных результат приема ret ;вернемся
| | | | |
В общем, перед CMD0 надо 10 штук FF кинуть(!!!), по документации это что-то типа синхронизации. Потом CMD0 и ждем response. Потом CMD1 и опять response. Теперь карта должна войти в нормальный режим работы по SPI, т.е. можно читать, писать, идентифицировать и т.п.
И еще, на МК надо корректно настроить фазы синхронизации относительно данных, в доке это описано. Для S8252 это через SPCR (SPI control register) делается.
Romanich, пиши о результатах
|
30 Mar 2007 05:38 |
|
|
Romanich
Banned
Joined: 12 Oct 2006 16:44 Posts: 608
|
Как только разбирусь и попробую - обязательно напишу!
Спасибо за код!
|
30 Mar 2007 14:26 |
|
|
Romanich
Banned
Joined: 12 Oct 2006 16:44 Posts: 608
|
Ура!!! Получилось!!!
В процессе написания программы было несколько ошибок:
1) Команда 17 - это не 0x57, а 0x51 !!! (по инерции забыл что 17=0x11 и прибавил к 0x40+0x17, забыв что в десятичной записано)
2) Неверно была написаны инициализация и сброс MMC
3) Ясного понимания раньше небыло в алгоритмах перехвата данных и статуса от MMC+
|
30 Mar 2007 23:55 |
|
|
Romanich
Banned
Joined: 12 Oct 2006 16:44 Posts: 608
|
Вот мой рабочий код:
| | | | Code: /* Фрагмент кода, демонстрирующий работу с 128MB MMCplus Memory Card Kingston technology в режиме SPI Карта отвечает спецификации MMC 4.0 при обратной совместимости с прежними моделями MMC
Используются самые КРАЙНИЕ контакты:
1 xCS Выбор кристалла 2 DI Входные данные 3 GND Земля 4 VDD Питание +3.3V 5 SCLK Синхронизация 6 GND Земля 7 DO Выходные данные 8 Reserv Подтянуть к +3.3V резистором 4.7кОм 9 Reserv Подтянуть к +3.3V резистором 4.7кОм
Остальные контакты(10,11,12,13 Reserv) оставить свободными */
unsigned char Buffer[512]; //Буфер для сектора
void MMCCS(unsigned long cs) //Выбор чипа MMC+ { <используем софтварное управление ножкой выбора кристалла, так удобнее :)> }
unsigned char SPI(unsigned char b) //Передача байта по SPI и тут же его приём { <ждем пока буфер передачи не освободится> <передаём по SPI байт b> <ждём пока буфер приёма не заполнится> <читаем байт из SPI - и возвращаем его значение return> }
void InSector(unsigned long Address) //Чтение сектора 512 байт { unsigned char b; unsigned int i; MMCCS(0); SPI(0x51); //Код команды чтения одиночного сектора SPI(Address>>24); SPI(Address>>16); SPI(Address>> 8); SPI(Address ); b=SPI(0xFF); while(b==0xFF) b=SPI(0xFF); //Опрашиваем пока не встретится что-нибудь отличное от 0xFF while(b!=0xFF) b=SPI(0xFF); //Опрашиваем пока не встретится 0xFF while(b==0xFF) b=SPI(0xFF); //Опрашиваем пока не встретим что-нибудь отличное от 0xFF - ожидаем что 0xFE :) for(i=0;i<512;i++) Buffer[i]=SPI(0xFF); //Теперь MMC+ готова передать 512 байт ЧИСТЫХ данных while(SPI(0xFF)!=0xFF); //Опрашиваем пока не встретится 0xFF (тут и два байта CRC замаятся - фиг с ними :) MMCCS(1); }
void MMCSpeedSlow(void) //медленная скорость по SPI { <настраиваем клок SPI на малую частоту (желательно 0.4МГц)> }
void MMCSpeedFast(void) //быстрая скорость по SPI { <настраиваем клок SPI на высокую частоту (до 20МГц?)> }
int main(void) { unsigned char b; unsigned long i; <энаблим SPI> <настраиваем его как мастер,запрещаем прерывания от SPI> <для MMC+ главное чтоб запись битов происходила по возрастанию клока, тоесть POL=0 & PHA=1 или POL=1 & PHA=0> //Начинаем работать с MMC+ MMCSpeedSlow(); //Устанавливаем медленную скорость обмена с MMC+ MMCCS(0); for(i=0;i<10;i++) SPI(0xFF); //10 байтов 0xFF MMCCS(1); for(i=0;i<2;i++) SPI(0xFF); //2 байта 0xFF //Даём команду сброса (CMD0) MMCCS(0); SPI(0x40); //Код команды сброса SPI(0); SPI(0); SPI(0); SPI(0); b=SPI(0x95); //CRC здесь обязателен! while(b==0xFF) b=SPI(0xFF); //Опрашиваем пока не встретится что-нибудь отличное от 0xFF while(b!=0xFF) b=SPI(0xFF); //Опрашиваем пока не встретится 0xFF MMCCS(1); //А теперь инициализируем карту пока из спячки не выйдет (CMD1) MMCCS(0); Again: SPI(0x41); //Код команды инициализации SPI(0); SPI(0); SPI(0); SPI(0); b=SPI(0xFF); while(b==0xFF) b=SPI(0xFF); //Опрашиваем пока не встретится что-нибудь отличное от 0xFF while(SPI(0xFF)!=0xFF); //Опрашиваем пока не встретится 0xFF if(b!=0) goto Again; //Если карта из спячки не проснулась то заново посылаем команду MMCCS(1); MMCSpeedFast(); //Устанавливаем быструю скорость обмена с MMC+ /* Далее ради примера читаем ВСЕ сектора MMC+ карточки (128МБ = 262144 сектора) Аргумент в функции InSector - адрес, должен быть кратен 512, т.к. по умолчанию длина считываемых байт равна размеру сектора, а пересекать сектора при чтении нельзя! */ for(i=0;i<(128*1024*1024/512);i++) InSector(i<<9); }
| | | | |
|
30 Mar 2007 23:57 |
|
|
Romanich
Banned
Joined: 12 Oct 2006 16:44 Posts: 608
|
Разобрался и с записью. Ничего сложного
Вот рабочий код:
На самом деле моя MMC+ не ровно 128МБ, а 122,5МБ с точностью до байта! Выяснилось когда хотел записать в самый последний сектор(чтоб FAT не разрушить) - возникла ошибка записи и чтения - стало ясно что сектор с номером 262143 НЕ существует! Последний доступный сектор ¹250879
А вообще от себя добавлю, что MMC+ карточки - КРУТО!
Маленькие, удобные, быстрые, много-Erse/Write'абельные
Очень полезны для хранения больших объёмов информации (в основном мультимедийной)
|
01 Apr 2007 02:26 |
|
|
jdigreze
God
Joined: 02 Jan 2006 02:28 Posts: 1390 Location: Abakan
|
Именно CRC. Посмотри как в моем исходнике считается.
Кстати, там полином CCITT, но инициализируется 0x0000.
|
01 Apr 2007 11:03 |
|
|
Shaos
Admin
Joined: 08 Jan 2003 23:22 Posts: 22621 Location: Silicon Valley
|
Ну они (впрочем как и все производители винчестеров) считают мегабайтом не то в чём 1024 килобайта, а где есть 1000000 байт - умножь 250880 на 512 и получишь число 128 450 560 (те самые 128M что значатся на карточке).
|
01 Apr 2007 11:22 |
|
|
Romanich
Banned
Joined: 12 Oct 2006 16:44 Posts: 608
|
Насколько я знаю, что в режиме SPI правильный CRC нужен только в CMD0, а он уже всеми кому не лень подсчитан(0x95)
|
01 Apr 2007 18:03 |
|
|
Who is online |
Users browsing this forum: No registered users and 69 guests |
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot post attachments in this forum
|
|