Разработка электроники,
Систем автоматики,
Программного обеспечения
ООО "Антех ПСБ",
Санкт-Петербург
+79811865082
anteh@bk.ru
17.07.2020 Сайт https://anteh.ru
Часть разрабатываемого, на 8bit AVR микроконтроллере, устройства считывает случайно приходящие данные с двух микросхем CAN шины максимум 1 Mbit, подключённых по SPI и циклически записывает считанные данные на microSDHC подключённую по тому же SPI. На SPI висит FRAM, RTC, есть температурный датчик на I2C, и реализован USB через CP2104 USART0 для подключения к компьютеру -это второстепенно и не рассматривается. Речь о 3х устройствах на SPI одно из которых SDHC карта, а 2 других генерируют записываемые данные со случайной скоростью. Рассматривается реализация драйвера обмена с SDHC, как его лучше/проще реализовать исходя из текущей задачи, готовых библиотек не будет по шкурным соображениям, будет исчерпывающее описание программной реализации, сама программная реализация AVR Assembler, будет несколько рабочих принципиальных схем для SPI подключения к 8bit AVR микроконтроллеру, SCLK=10MHz. Не планируется использование карт других типов, или сильно отличающихся от используемой, универсальность не нужна, нужна максимальная надежность устройства в разных климатических условиях для круглосуточной работы. Важна гарантрованная запись абсолютно всех сгенерированных данных на карту, без потери данных.
Максимальный для CAN шины 250kHz, теоретический объем генерируемых данных 2мя SPI устройствами 62.5 килобайта в секунду или 500 килобит в секунду -это когда одна посылка длится около 500микросекунгд и каждая посылка преобразуется в 16 байтную структуру данных. Предельный теоретически аппаратно возможный поток данных 2 мегабита в секунду с 2х SPI устройств -2 CAN шины реализованные на внешних микросхемах. Речь о уже обработанном потоке полученном с 2x CAN шин с добавлением дополнительных данных 2 мегабита. Реальный поток предположительно будет 10 - 100 килобит. Интригой будет предельная скорость записи на SDHC потоковых данных по SPI и определение загруженности SPI при обслуживании 3х SPI устройств, четвёртое FRAM в расчет пока не принимается. Имеется в виду несколько разнотипных устройств на одной SPI шине. Интересует отсутствие пропусков входных данных из-за черезмерной загрузки SPI. Частота тактирования микроконтроллера 20MHz частота SPI SCLK 10MHz. Забегая сильно вперед: на SDHC карту нужно писать поток 250 килобайта в секунду при частоте SPI 10 MHz. Это предельный теоретический никогда не достижимый объём данных генерируемый двумя CAN шинами на частоте 1 мегабит в секунду. Причем данные уже обработанные, каждой CAN посылке сопоставляется 16 байтный блок данных. Также, в рассматриваемом случае 512 байтные блоки данныхиз микроконтроллера в SDHC карту будут передаваться исключительно в одиночном режиме. И в общем передача одного 512 байтного блока данных в SDHC при SPI 10MHz занимает 800 микросекунд + около 1 миллисекунды на выполнение операции записи картой -это и есть около 250 килобайт в секунду, в притык, задача реализуема. Речь о записи на предварительно очищенный блок в SDHC. Запись на очищенный блок происходит быстрее. Есть проблема: если 512 байтный блок в карту передавать весь целиком за 800 микросекунд, то есть вероятность пропуска входних CAN посылок, на частоте CAN шины 1 мегабит длительность посылки будет около 125 микросекунд, а приемных буферов у микросхемы реализующей CAN интерфейс только 2, это максимум 250 микросекунд на реакцию управляющего AVR микроконтроллера. Обязательно нужно разбивать передачу 512 байтного блка данных на несколько частей для перерыва на считывание CAN приемных буферов. Т.е. 512 байтный блок данных по SPI передаём не целиком с буфера, а произвольными частями, это увеличивает время реакции микроконтроллера, и в силу особенностей SPI интерфейса SDHC карт здесь важна аппаратная поддержка подобной функции. Схема согласования уровней помимо согласования уровней превращает SDHC карту в обыкновенное SPI устройство которое можно подключать и отключать от SPI шины по перебросу какого-нибудь пина микроконтроллера. У SDHC карт DO не переходит в третье состояние, если её CS в высоком и карта занята внутренниими операциями, карта через DO индицирует свою занятость. Схема согласования уровней. Функция записи 512 байтного блока произвольными частями работает не для всех SDHC карт, после нескольких дней поиска проблемы выяснилось, что 32G Samsung microSDHC UHS-I Card EVO plus экзестанциально не переавривает подобный способ записи данных, после работы в течении какого-то времени карта зависала, помогало только переподключение питания. С Transcend картами всё было в порядке. Каждый производитель немного по разному реализует SPI интерфейс и если кто захочет универсальности то граблей наловите много.
Найдена официальная документация на Transcend microSDHC UHS-I 16GB Class 10 по тегу "SDHC10 Card series 4~32GB High Capacity Secure Digital Card".
Документация подтвердила или уточнила: питание SDHC стандартно 3.3V, микроконтроллер питается от 5V, уровни будем согласовывать через логические буферы с открытым стоком open drain. В реальности, аппаратно, уровни согласовывались сначала резисторами(скорость получилась максимум до 2 мегабит SPI), потом логическими буферами с открытым стоком(слишком много нужно тока на подтяжку для высоких скоростей, реализующие CAN шины микросхемы не тянули), затем самым оптимальным образом -через логические буферы поддерживающие перенапряжения логических уровней на входах. Блок/сектор чтения или записи стандартно 512 байт, после подачи питания и перед процедурой инициализации нужно подождать минимум 250ms будем ждать 300ms, токопотребление до подачи первой команды <=15mA, в течении инициализации <=100mA, работа в режиме по умолчанию <=100mA, работа в высокоскоростном режиме <=200mA, работа с другими функциями <=500mA, что это за другие функции такие непонятно, надеюсь с ними столкнуться не придется, но к сведению 500mA принимаем -линейный LDO в sot223 на ампер и керамические банки нам в помощь, скорее всего в 10MHz SPI режиме нужно расчитывать на максимум 100mA токопотребления, резисторы подтяжки рекомендуют от 10k до 100k, в режиме инициализации частота SPI должна быть 100kHz-400kHz, в режиме передачи данных для SPI максимум 25MHz будет 10MHz, в режиме высокоскоростной передачи данных 50MHz не актуально, рабочая температура -25+85 надеюсь хватит, хранения -40, влажность в текущем случае неактуальна будет заливка компаундом + герметичный корпус, важно: в регистре CSD:46 бит именуемый ERASE_BLK_EN зафиксирован в 1 и означает, что контроллер может стирать один или более блоков/секторов по 512 байт -это важно с точки зрения быстродействия, записывать блок/сектор в 512 байт оптимальнее/быстрее на пустой или стертый блок, операция записи на занятый блок выполняется дольше, чем запись на пустой. Будет реализована циклическая запись данных, блоки записывабтся на предварительно стертые блоки, для этого производится стирание кластера из нескольких блоков, стирать по 1024 блока оказалось оптимально по времени затрачиваемому на стирание по измерению осцилографом для Transcend 16G. Бывает, что стирание возможно только кластерами от единиц килобайт до мегабайт. У используемой карты размер кластера 64 килобайта, но эта информация не пригодится и вроде вообще ник чему. Для резистивного сопряжения 3.3V логики скарты с 5V логикой микроконтроллера нужен параметр напряжение минимального уровня логической единицы = 0.625*Vdd = 2.1V, для правильного подбора резисторов делителей и подтяжки. Прараметр CL: максимальная нагрузочная ёмкость на выводах хоста + емкость шины SPI не должна превышать 30pF. Для интересу сначала использовался резистивный делитель, на SPI SCLK = 10MHz обмена не было, работало на 1MHz. На 10MHz при резистивном согласовании по осцилографу фронты SCLK после делителя треугольные амплотуда 1V + постоянная составляющая 1V, не работало, стояли резисторы на единицы килоом, нужны согласующие резисторы на сотни ом, по току будет тяжеловато для AVR. На делитель SCLK приходит правильный прямаугольный. На резисторах можно мегагерца 2 SCLK получить. Cогласование логических уровней делаем через 2 логических буфера 74LVC2G07G, как на второй схеме. На 10MHz работает отлично, при необходимости можно до 25MHz реализовать но уже не на AVR. На AVR можно SPI SCLK максимум до 14-16MHz сделать желательно с кварцевым генератором и для стендов, не для штатных устройств. Предельная частота работы Flash памяти AVR микроконтроллеров 33MHz. В последствии от согласования на 74LVC2G07G пришлось отказаться, слишком низкоомной должна быть подтяжка для работы на 10MHz SPI и не все микросхемы висящие на SPI могли выдавать достаточное количество тока.
На карту данные записываются напрямую, без использования каких либо файловых систем, если на карте будут какая либо файловая система или данные, они будут потеряны. Записываются данные на карту прямо блоками по 512 байт начиная с адреса 0x00000000 и до упора -1, "упор" у каждой карты свой смотрим регистр CSD 22бита [69:48] и вычислякм размер карты в килобайтах: (CSD[69:48] +1)*512k, если *1024 получим размер в байтах, в реальности нужен размер в 512 байтных блоках. Форматирование подготовка и пр. не требуется, разумеется операционные системы читать такие карты не будут. Все данные будут перезатерты. К слову, для бытового применения, форматировать карты желательно только специализированными программами предоставляемыми или производителем карты или ассоциацией "SD Card Association" https://www.sdcard.org/ -здесь же можно разжиться официальной спецификацией на SD карты, форматирование из операционной системы приводит к замедлению работы, связано с необходимости знать индивидуальные характеристики карты и правильно подбирать размеры секторов кластеров и т.п. Из-за этой же некоммерческой ассоциации пришлось отказаться от использования 4х байтного SD режима, уже разведённого на плате и переделывать всё на работу по SPI. Хотя софтовый SD режим будет сушественно медленнее паппаратного SPI. Нюанс: если ваш хост/микроконтроллер аппаратно не поддерживает SDIO интерфейс, за который производитель микроконтроллера уже заплатил лицензионный сбор в "SD Card Association", то использовать SD режим реализованный программно официально нельзя или нужно платить лицензионный сбор. По спецификации все SD карты поддерживают SPI режим, он по понятным причинам медленнее 4х битного SD режима. Некоторые "левые" нонейм карты, не поддерживают SPI. Режим spi не поддерживается картами SDUC - и больно нужно, ёмкость от 2 до 128 террабайт. Карту нужно запитывать 1.8 вольт при высокоскоростном подключении в SD режиме. Забегая вперёд, если нужно полноценно использовать карту с возможностью работы на больших скоростях обмена, используйте контроллер с аппаратной поддержкой 4х проводного SDIO интерфейса, а согласование уровней при помощи двунаправленных преобразователей уровней, на худой конец неинвертирующих буферов с открытым стоком. У неинвертирующих буферов с открытиым стоком конец худой по причине необходимости использования резисторов подтяжки на пару сотен ом а то и сотню, а это приличная нагрузка на SPI устройства висящие на шине совместно с картой, не каждое может несколько десятков миллиампер выжать, придётся их тоже через буферы цеплять, а это очень большой паровоз по площади занимаемой печатной платы, увеличение вероятности брака при пайке, номенклатуры закупки, у SMD установщика лишние слоты отжирать будет, гемор если речь о серийном устройстве.
В сети информации о подключении SD карт к микроконтроллеру по SPI предостаточно местами она противоречива, рекомендуемая многими статья на английском http://elm-chan.org/docs/mmc/mmc_e.html и её перевод http://microsin.net/programming/file-systems/howto-use-mmc-sdc.html, самая подкрученная инфа здесь microsin.net, также смотрим http://4a4ik.blogspot.com/2015/08/sd-mmc-spi.html http://4a4ik.blogspot.com/2015/08/spi.html http://microsin.net/programming/file-systems/sd-specifications-part-1-physical-layer-simplified-specification-ver-200-spi-mode.html и http://microsin.net/programming/file-systems/sd-specifications-part-1-physical-layer-simplified-specification-ver-200.html. По статьям не получилось с начальными нулевыми знаниями понять ряд моментов. Например описания ответов на команды. На CMD0 по статьям не понять, ответ R1 то ли он одно байтный то ли шестибайтный. По факту это 1 байтный ответ с текущим статусом после предыдущей команды. Также для CMD8 утверждается что ответ будет 48 битный, по факту 40 битный как и указано в спецификации с SD Association сайта, если например CRC у CMD8 неправильная то ответ будет не R7, а однобайтный R1 = 0b00001001 = 0x09 флаги означают idle и CRC error для предыдущей команды точнее ответ при неправильной CRC будет 0x09ffffffff потому что ожидаем 5 байт. Если карта приняла команду CMD8 =0x48000001aa87, то она ответит 0x01000001aa -это правильный ответ и формат ответа R7: первый байт это R1 + ещё 32 бита, биты 0x1AA означают, версия карты V2 и может работать в диапазоне напряжения от 2.7 до 3.6 вольт. Подробности в спецификации Part1_Physical_Layer_Simplified_Specification_Ver7.10.pdf скачиваемой с сайта SD Association, раздел 7. SPI Mode
Пока не инициализируем карту всегда используем правильную CRC7 для каждой команды, есть карты которые в SPI режиме при инициализации независимо ни от чего используют CRC7. CRC7 старшие 7 бит вычисляется по первым 5 байтам команды. Полином G(x) = x^7 + x^3 + 1 (10001001), младший 0 стоп бит CRC всегда =1. Можно использовать сервис http://www.ghsi.de/pages/subpages/Online%20CRC%20Calculation/ там нужно указать полином 10001001 и 5 байт команды, полученное значение умножить на 2 прибавить 1 и перевести в hex это будет CRC шестой байт команды. Для читаемых/записываемых блоков данных 512 байт, если включена, используется CRC16. Если CRC отключена, то байты CRC16 всё равно должны быть. По спецификации SD Association для формирования CRC16 используется стандартный CCITT (CRC-16/XMODEM) полином x^16+x^12+x^5+1, 0x1021 init=0x0000. У конфигурационных регистров как минмум для Transcebd используется CRC-16/XMODEM для 128 64 512 битных регистров, описание ниже. Подозреваю, спецификация SDA(SA Association) носит рекомендательный характер, некоторые моменты, у разных производителей карт, могут быть реализованы по разному.
Name Polynom Init val Reverse byte Reverse result Swap result
CCITT 1021 ffff no no no
XModem 1021 0000 no no no
Kermit 1021 0000 yes yes yes
CCITT 1D0F 1021 1d0f no no no
IBM 8005 0000 yes yes no
Если на SPI шине несколько устройств, то первым/первыми инициализируем карту/карты. Неинициализированная карта при CS = 1 высокий уровень, может воспринимать активность на SPI шине с разными последствиями - зависание, возможно порча данных. При подаче питания, все карты на одной и той же SPI шине находятся в SD режиме, в SD режиме адресация карт выполняется не через физический CS вывод карты а через 16 бит RCA регистр адреса конкретной карты. При подаче питания RCA сбрасывается в 0x0000, т.е. все карты на одной и той же SPI шине будут одинаково воспринимать активность SPI шины. Полагаю, подача 80 единиц на карту минимум включает CS вывод и CMD0 уже подаём последовательно на каждую карту. С SD режимом не работал, проверяйте так оно или нет.
Коротко про ответы: R1 однобайтный старший бит всегда 0 -для реализации алгоритма полезный факт. R1b это R1 + индикация заняторсти карты, занятость индицируется через установку DO карты в низкий уровень, если во время занятости непрерывно слать 0xFF в карту то она будет отвечать 0x00 и когда освободится станет отвечать 0xFF -это можно использовать для определения готовности карты к дальнейшей работе, но это непрактично, особенно когда на SPI висит ещё несколько устройств требующих внимания. Поэтому занятость карты контролируем по её DO выходу, каждый раз при подключении SPI к карте проверяем вход микроконтроллера подключенного к DO карты, если вход в низком, карта занята, отключаемся от неё для работы с другими SPI устройствами и возвращаемся позже -И ВНИМАНИЕ это было досадным заблуждением. Как оказалось DO карты после окончания внутренней операции остается в 0 низком уровне неограниченное количество времени до подачи в неё 0xFF. В высокий DO переходит только после окончания внутренней операции и после подачи 0xFF байта в карту. После подачи долго обрабатываемой команды, например записи или стирания блока/блоков данных, можно отключаться от карты для работы с другими SPI устройствами. DO карты после установки CS карты в высокий уровень перейдёт в третье состояние -это действительно так, проверено, на всякий пожарный, после установки CS в высокий подаём 0xFF в карту. Отсюда универсальный способ подключения к карте при работе с несколькими устройствами на SPI шине: после подключения к карте -установке CS в 0, подаём в карту 0xFF, и если в ответ приняли не 0x00 значит карта свободна, можно подавать команды. Это справедливо при работе с любыми командами требующими времени для обработки. R2 двухбайтный ответ со статусом карты, первый байт также R1 + 8 бит со статусом. R3 ответ на команду CMD58 с данными OCR регистра, первый байт как обычо R1 далее 32 бита OCR. Ответов R4 и R5 в SPI нет, есть только в SD режиме обмена данными. R7 -первый байт R1 далее 32 бита версия карты и диапазон рабочих напряжений. Для реализации алгоритма удобно думать что ответ на любую команду это либо только R1 -один байт либо R1 + какое-то количество байт определяемое командой, а также R1b это R1 + индикация занятости карты через установку её DO в низкий уровень.
Правильный алгоритм должен анализировать первый байт любого ответа R1 и предпринимать действия согласно ситуации, учитывать все ситуации сложно, поэтому контролируются только важные флаги соответствующие смыслу команды. Будем считать что карта безотказная, не будет ошибок обмена, респонсы всегда правильные, предварительно карта будет полностью протестирована.
Принципиальная схема подключения 3.3V SDHC карты к 5V 8bit AVR микроконтрорллеру через резистивный делитель:
1, 8 выводы microSDHC не используются и подтянуты через 12k к +3.3V. 7 DO и 5 SCLK через делителдь заведены на MISO и SCK микроконтроллера соответственно и после подачи питания, гарантированно будет низкий уровень на SCLK и высокий на DO -высокий уровень даст сама карта. При подаче питания на микроконтроллер его выводы до инициализации находятся в третьем состоянии. Есть вероятность что карту может "заглючить", если её выводы какое-то время будут в третьем состоянии. DI карты зваодится на MOSI микроконтроллера через делитель, также CS карты заводится на PB2 контроллера через делитель. Помимо всего MOSI и PB2 подтянуты к +5V через 1.8k. Это важный момент здесь как раз используем информацию из документации на карту минимального уровня логической единицы = 0.625*Vdd = 2.1V. Таким образом на DI и CS карты после подачи питания гарантированно 2.39V т.е. логическая единица.
Принципиальная схема подключения 3.3V SDHC карты к 5V 8bit AVR микроконтрорллеру через неинвертирующий буфер с открытым стоком 74LVC2G07G:
Схему подключения 3.3V SDHC карты к 5V 8bit AVR микроконтрорллеру через четырехканальный двунаправленный преобразователь уровней можно найти в сети, но она не решает проблему DO выхода SDHC, если на SPI шине "висит" несколько устройств. Привожу разработанную финальную схему подключения SDHC к микроконтроллеру решающую все проблемы:
Общая частичная схема устройства:
Прошивка пишется на Assembler. Приводятся только фрагменты кода, которые позволят разобраться как начать работать с SDHC по SPI. Инициализация microSDHC:
Параметры настройки SPI AVR 8bit для подключения microSDHC: MSB first, Master, SPI Mode 0 CPHA=0 CPOL=0, SCLK = 20MHz/64 = 312.5kHz. Порты ввода вывода для AtMega88pa настраиваем соответствующим образом:
|
Длина команд от контроллера к карте всегда 6 байт, ответ разной длины от 1 байта. После каждой команды всегда ожидаем ответа от карты, ждать от 0 до 8 байт. Т.е. передали команду и за командой передаём 0xFF до тех пор пока в ответ по DO карты не получим байт !=0xFF. И байт !=0xFF и будет ответом или началом ответных байт следующих за первым байтом !=0xFF, длина ответа зависит от команды. Это основная логика работы. Также в алгоритме работы задействуется watchdog микроконтроллера. Словами описать алгоритм точно и однозначно сложно, поэтому смотрим рабочий код там все по полкам.
|
Алгоритм учитывает, что после получения response на команду и перед передачей следующей команды нужно передать 8 SCLK тактов, а также необходимость передачи 8 SCLK тактов после установке CS в 0 или 1 при подключении отключении карты от SPI. Нужно отключать передачу 0xff после получения response для команд CMD24 CMD17 и включить функцию ожидания токена 0xfe для CMD17, это реализованно в приведённом выше алгоритме. Включать функцию ожидания токена 0xFE от контроллера карты нужно и для некоторых команд чтения сервисных регистров карты, длина которых отличается от стандартных response. Если карта занята внутренними операциями, то она устанавливает свой DO в низкий уровень, например во время стирания/записи блока, и можно отключать карту от SPI шины и работать с другим SPI устройством, при каждом подключении к SPI шине карты после CS = 0 всегда нужно подавать 0xff и проверять её занятость по состоянию её DO, если DO в низком карта занята и либо ждем либо подключаемся позже. Унгиверсальней будет проверять занятость карты перед подачей любой команды, мало ли какая карта как устроена. Проверка CRC в режиме SPI по умолчанию отключается, при необходимости можно включить, придется вычислять CRC. Если CRC отключена, то карта все равно вычисляет и присылает CRC, а в карту нужно передавать 1 или 2 байта CRC с любым содержимым. После подачи питания карта по умолчанию в SD режиме, CRC по умолчанию включена, команды подаём с правильной CRC. Переводим карту в SPI режим на скорости 20MHz/64 = 312.5kHz. В SPI, CRC по спецификации должна по умолчанию отключается и правильная CRC нужна для первых двух CMD0 CMD8, так может быть не всегда, на всякий, до инициализации карты используем правильную CRC для каждой команды.
После подачи питания настраиваем потры контроллера/хоста управляющего картой, watchdog, ждём от 300ms на установку питающего напряжений на карте, настраиваем USART на 2.5 мегабита работаем через cp2104 у неё по документации максимум 2 мегабита, но и 2.5 работают нормально, USART используем для отладки, на него response от карты передаём, по экрану осциллографа respons ответы неудобно контролировать, настраиваем SPI 100-400kHz как описано выше, DI и CS карты в высоком, подаём 80 единиц или 10шт 0xFF точнее тактов на SCLK карты, устанавливаем CS в низкий, передаём CMD0 =0x400000000095 команда сброса с правильной CRC, затем передаём в бесконечном цикле 0xFF пока не получим от карты первый и единственный response байт !=0xFF, бесконечный цикл будет длится 0-8 байт или пока не сработает watchdog, при отладке response засылаем в USART для контроля, проверяем если байт ответа =0x01 то всё в порядке idle режим, иначе бесконечное зацикливание для ухода на перезапуск через watchdog.
watchdog перезапускает микроконтроллер, если от карты не будет получен правильный ответ после CMD0 и в ряде других случаев. Разрабатываемое устройство подразумевает безусловную работу sdhc карты, поэтому если карта не работает, то устройство не работает.
Дальше передаём CMD8 =0x48000001aa87 с правильной CRC, это проверка поддерживаемого картой напряжения питания, для UHS-I обязательная команда, в ответ должны получить 0x01000001aa, проверяем, чтобы последние 2 байта = 0x01aa иначе уход на перезапуск по watchdog. При штатной работе, для разрабатываемого устройства со впаянной microSDHC, можно response не проверять, достаточно проверки ответа CMD0. Уточнение: устройство затачивается для работы с конкретным типом/классом microSDHC по SPI, универсальность не нужна.
Передаем CMD55(0x770000000065) + ACMD41(0x694000000077) с установленным 30:HCS битом для запуска процесса инициализации. От CMD55 ответом будет один response байт R1 = 0x01 idle режим, от ACMD41 по началу ответ R1=0x01, после окончания инициализации R1=0x00. Чтобы увидеть R1=0x00 нужно зациклиить передачу команд CMD55 + ACMD41 с выходом из цикла при ACMD41:R1=0x00. Это занало буквально одну итерацию цикла, т.е. после повторной подачи CMD55 + ACMD41 уже ACMD41:R1=0x00. Подробнгости в листинге кода. Реальные Response ответы принятые по USART при инициализации:
|
Повторюсь CRC у всех команд правильные, несмотря на то что после CMD0 CMD8 при переходе в SPI можно CRC не расчитывать. Минимум у Transcend по по этому вопросу есть пунктик или так показалось. На всякий проверяем, чтобы OCR:31 =1 через подачу CMD58 и также на всякий отключаем отключенную по умолчанию CRC командой CMD59.
Поскольку затачиваемся на работу с конкретными типами карт, то с инициализацией заканчиваем, всё остальное итак известно, и оно по дефолту такое какое нужно. Именно размер читаемого, записываемого блока/сектора = 512 байт, минимальный размер стираемого блока/сектора также 512 байт. Чтение запись исключительно поблочная по 512 байт, одновременной записи нескольких блоков не бует, такой алгоритм, нужно успевать работать с другими SPI устройствами. Чтение сервисных регистров в штатном режиме работы не понадобится всю информацию берем из документации на описываемую карту, или из регистров читаемых однократно в отладочном режиме и занесением нужной информации во флеш память AVR контрроллера. Реально понадобится размер карты в блоках. Далее увеличиваем частоту SPI SCLK до 10MHz и реализуем циклический поблочный алгоритм записи данных на карту из буфера.
Вывод содержимого всех доступных сервисных/информационных регистров для Transcend microSDHC UHS-I 16GB Class 10
По документации для Transcend microSDHC UHS-I 16GB Class 10 предусмотрены регистры OCR, CID, CSD, RCA, DSR и SCR про SSR, CSR ничего не сказано по спецификации SD Association должны быть. RCA в режиме SPI не используется, DSR опционален, у Transcend DSR есть, но не используется в SPI скорость обмена низкая 10MHz SCLK -это максимальная по документации частота выдаваемая микроконтроллером на частоте кварца 20MHz. Если для тестов или для стенда, то можно поставить кварцевый генератор 30MHz на AVR и получим 15MHz SCLK на SPI. Предельная неофициальная частота работы флеш памяти AVR микроконтроллера 33MHz, на 40 уже не работает. Максимальная SPI частота карты 25MHz смотрим документацию
Имя | Ответных бит | Описание |
CID | R1+"чего-то 0xff разной длины"+128+CRC-16/XMODEM(CCITT) | Ответ на CMD10. Индивидуальный идентификационный номер карты. С чтением регистра та же история что и для SCR SSR и CSD |
RCA | 16* | В SPI режиме не используется. Содержит адрес карты, используется при подключении нескольких карт к одной SDIO шине. При подаче питания адрес каждой карты RCA=0x0000 |
DSR | 16* | Регистр конфигурирования выходных драйверов выводов карты, чтобы на высоких скоростях передачи с фронтами сигналов было все впорядке, и вероятность ошибки была меньше. Регистр опционален, у Transcend есть. При работе по SPI не торогаем. По умолчанию у Transcend =0x0404. Для записи в DSR используется CMD4, по спецификации в SPI команда не используется |
CSD | R1+"чего-то разной длины"+128+CRC-16/XMODEM | Ответ на CMD9. Данные, специфические для конкретной карты, размеры всевозможных блоков времена доступа, разрешения и пр. С чтением регистра та же история что и для SCR и SSR |
SCR | R1+"чего-то разной длины"+64+CRC-16/XMODEM | Ответ на ACMD51. Конфигурационный регистр карты, информация о специальных функциях возможностях карты. С чтением регистра такая же история как и с SSR |
OCR | R1+32 | Ответ на CMD58 R3. Индицирует напряжение питания карты, 31 бит индицирует факт окончания инициализации питающего напряжения. Если 30 бит =0 то карта SDSC, если =1 то SDHC или SDXC |
SSR | R1+"чего-то разной длины"+512+CRC-16/XMODEM | Ответ на ACMD13. SD Status, информация о функциях, размерах тех или иных информационных единиц, особенностях карты. Алгоритм чтения нигде не описан, а он может оказаться с нюансом, описание ниже. "чего-то разной длины" зависит от частоты SPI чем выше, тем этого "чего-то" 0xFF больше, судя по всему есть фиксированная временная задержка после которой выдается SSR |
CSR | R1+8 | Ответ на CMD13 R2. Статус карты. В ответ приходит 2 байта, первый R1 второй разная статусная информация относящаяся к предыдущей команде, если не сказано другое. Команду можно слать в любой момент, например в цикле чтобы определить занятость карты. Есть противоречие, в официальной SD Association документации ответ на CMD13 это R1+4 байта, возможно это ответ в SD режиме |
* -с регистрами RCA DSR не работал, информацию проверяйте
CSR
По SD Association документации есть 3 типа статуса состояния SD карты Card Status Task Status и SD Status. R1 -это Card Status первый ответный байт на любую команду. Если в аргументе CMD13 [15] байт =0 то будет возвращен Card Status, если =1 то Task Status -но это вроде если используется режим многопоточной обработки команд CQ mode. Третий статус состояний это SD Status поле из 512 бит содержащее индивидуальные особенности карты это вроде и есть регистр SSR. Первый протокол/режим SD, представленный в 2000, позволял выполнение одной команды за раз. В 2016 SDA (SD Association) представила поддержку Command Queuing (CQ) для интерфейса SD, это позволяет выполнять до 32 команд. У нас речь про SPI, аргумент CMD13 =0x00000000 и речь только о Card Status, будет только 2 ответных байта.
Все нюансы с чтением регистров пришлось досканально выяснять чтобы убедиться в правильности работы разрабатываемых алгоритмов обмена с картой по SPI.
SSR
Transcend microSDHC UHS-I 16GB Class 10 выдаёт следующее в зависимости от частоты SPI:
|
Выдается разное количество байт 0xFF в начале, это не ошибки чтения. Связано с ожиданием чего-то, чем больше SPI частота, тем больше 0xFF перед маркером/токеном 0xFE начала 512 битного блока данных. Учитывая что длина SSR 512 бит = 64 байта, а последние 2 байта допустим CRC16, и также допустим что 0xFE это некий маркер начала SSR регистра к нему не относящийся. Далее через онлайн сервис вычисления разнообразных CRC16 сумм выясняем что если 0xC9A5 это CRC16 и CRC16 вычисляется по алгоритму CRC-16/XMODEM, то SSR = 00 00 00 00 04 00 00 00 04 00 90 00 08 11 19 0A 00 18 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00. Пока это очень правдоподобная фантазия. Сопоставим содержимое регистра с описанием. От 0 до 312 бит = 39 байт зарезервированно там 0x00, доходим до "00 18" -это 383:378 зарезервированные + 377:368 10 бит VSV_AU_SIZE = 0x18 = 24 мегабайта, цифра реалистичная, смотрим дальше, 391:384 байт VIDEO_SPEED_CLASS = 0x0A = 10 цифра в точку, Class 10 на карте написано. Соответствий много, полученные данные и есть SSR, но подобное "пребайтие" при чтении регистра нигде не описано. Информации достаточно для написания алгоритма извлечения SSR, видно что 0xFE некий стартовый байт скорее всего токен, после него 64 байта SSR + CRC16. Возможно у других карт по другому, или какой-нибудь где-нибудь "секурный" бит стоит. Если информация из регистров будет прочитана неправильно то неправильные данные могут повлиять на работу хоста с картой, вплоть до повреждения данных, поэтому если нужно статичное содержимое сервисных регистров карты, читайте их на низкой скорости при инициализации карты, проверяйте CRC.
OCR
Ответ на CMD58. Значения бит актуальны только после того как OCR:31 бит установится картой в 1 после инициализации питания:
OCR бит | Описание |
31 | 1 индицирует факт окончания инициализации питающего напряжения |
30 | Если 30 бит =0 то карта SDSC, если =1 то SDHC или SDXC |
29..24 | Зарезервировано |
23 | 3.5V..3.6V если 1 то поддерживается |
22 | 3.4V..3.5V |
21 | 3.3V..3.4V |
20 | 3.2V..3.3V |
19 | 3.1V..3.2V |
18 | 3.0V..3.1V |
17 | 2.9V..3.0V |
16 | 2.8V..2.9V |
15 | 2.7V..2.8V |
14..8 | Зарезервировано |
7 | Зарезервировано для диапазона низких напряжений питания |
6..0 | Зарезервировано |
Ответ от Transcend microSDHC UHS-I 16GB Class 10: "00(R1) C0 FF 80 00" означает поддержку всех питающих напряжений 2.7-3.6V + инициализация питания окончена + карта SDHC или SDXC всё бьется. OCR = C0 FF 80 00
SCR
Ответ на команду ACMD51. Конфигурационный регистр карты, информация о специальных функциях возможностях карты. С чтением регистра такая же история как и с SSR повторять её не будем:
SPI_SCLK = 312.5kHz 01[CMD0] 01 00 00 01 AA[CMD8] 01[CMD55] 01[ACMD41] 01[CMD55] 00[ACMD41] SPI_SCLK = 312.5kHz всё что дальше ответ на ACMD51 с буфером 70 байт 00 00 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FE 02 35 80 43 00 00 00 00 84 16 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF |
Тоже что и для SSR после ожидания и байта 0xFE идёт 64 бита SCR + 2 байта CRC-16/XMODEM. В таблице выше 2 строки это полный вывод response от команд при инициализации карты и запроса SCR. В верхней строке инициализация и ACMD51 на SCLK SPI = 312.5kHz в нижней инициализация на 312.5kHz, а ACMD51 подавалась на 1.25MHz соответственно видим одинаковую задержку перед выдачей SCR. Количество читаемых байт из карты, после подачи ACMD51 установлено в 70. Алгорим чтения специализированных регистров для Transcend microSDHC UHS-I 16GB Class 10 будет одинаковым. SCR = 02 35 80 43 00 00 00 00
CSD
Ответ на CMD9. CMD9 подавалась на 1.25MHz. Ответ на CMD9 начинается после байта 0xFE, после CMD9 на всякий избыточно читается 30 байт:
01 01 00 00 01 AA 01 01 01 00 00 FE 40 0E 00 32 5B 59 00 00 76 ED 7F 80 0A 40 00 D5 DD AB FF FF FF FF FF FF FF FF FF FF |
CSD = 40 0E 00 32 5B 59 00 00 76 ED 7F 80 0A 40 00 D5
Объём SDHC карты: в кластерах = CSD:69:48bit = 22 бита = C_SIZE = 0x0076ED = 30445 кластеров. memory capacity = (C_SIZE+1) * 512K byte = 15588352k * 1024 = 15962472448 байт, виндовс при FAT32 разметке показывает размер в 15954083840 байт. Размер SDHC в 512 байтных блоках = 15962472448 / 512 = 31176704 блоков -эту цифру используем для работы с картой при циклической непрерывной записи данных.
memory capacity = (C_SIZE+1) * 512K byte формула взята из документа Transcend SDHC10 Card series 4~32GB High Capacity Secure Digital Card
CID
Ответ на CMD10. CMD10 подавалась на 1.25MHz. Ответ на CMD10 начинается после байта 0xFE, после CMD10 избыточно читается 30 байт из карты:
01 01 00 00 01 AA 01 01 01 00 00 FE 74 4A 60 55 53 44 55 31 20 42 8C B9 14 01 22 AD 2F 28 FF FF FF FF FF FF FF FF FF FF |
CID = 74 4A 60 55 53 44 55 31 20 42 8C B9 14 01 22 AD
Увеличиваем частоту SPI до 10MHz:
|
Для быстрой записи 512 байтного блока в карту сначала нужно стереть блок на карте, используем CMD32 CMD33 CMD38, для рассматриваемой карты стирать можно от одного блока, но практичнее стирать сразу несколько блоков, например 128 одновременно, причина во времени требующемся карте на операцию стирания. Для рассматриваемой карты стирание одного 512 байтного блока занимает 3.4ms -это реальное измеренное осциллографом значение. Кластер в 128 блоков 64k стирается за 2.5ms и 3.2ms первый раз после подачи питания, в 512 блоков 256k за 2.5ms, 513 блоков за 4.1ms, 1024 блока за 2.6ms(3.2ms при первом стирании после подачи питания), 1025 блоков за 4.3ms, 2048 блоков за 2.8ms, 2049 блока 4.4ms и при первом стирании кластера после подачи питания 5ms, 4096 за 3.1ms, 4097 за 4.7ms 5.4ms при первом стирании после подачи питания, 16384 за 5.3ms, 16385 блоков за 6.9ms, 32768 за 8.1ms, 32769 блоков за 9.9ms, 65536 за 6.4ms, 65537 блоков или 32мегабайта за 8.5ms, 1048576 за 30.03ms, 1048577 блоков 512 мегабайт за 31ms, 15728640 за 360ms, 15728641 блоков 7680 мегабайт за 370ms(триста семьдесят). 64 блока 2.6ms, 128 блоков 2.5ms, 32 блока 2.6ms, 256 блоков 2.5ms, 512 блоков 2.5ms. Обращаем внимание на 64 килобайта и 32 мегабайта -"волшебные". 131072 блока 64 мегабайта 10.5ms. Команды на стирание CMD32 CMD33 CMD38 по времени занимают ничего, выше речь идёт о времени выполнеия самой картой операции стирания, т.е. подали команды стирания кластера и отключаем карту от SPI, при подключении карты к SPI проверяем её занятость как описано несколько раз выше.
Будем стирать кластерами по 1024 блока по 512килобайта 2.6ms. Удобно написать алгоритм определения оптимального размера кластера для минимизации времени стирания. Также нужен алгоритм проверки времени стирания каждого кластера и времени записи каждого блока. С операциями стирания записи на карту проблем почти не было. С чтением были, ситуация такая же, как и с чтением сервисных регистров, сначала идёт неопределённое количество 0xFF зависящее от рабочиз частот, затем, судя по всему, некий токен 0xFE, за ним 512 байт данных + CRC16. Пришлось в очередной раз дорабатывать алгоритм для реализации опции ожидания 0xFE перед чтением данных из карты, также пригодится для чтения некоторых сервисных регистров. Добавлен конфигурационный регистр к каждой команде с соответствующим флагом. Получается всё не относящееся к response ответам из карты будет передаваться как: некоторое количество 0xFF, затем маркер начала блока данных токен 0xFE за ним сами данные, это относится и к половине сервисных регистров.
Запись 512 байт блока в карту: после подачи CMD24 с адресом блока и получения response R1 байта, подаём 0xFE дата токен начала 512 байтного блока данных, затем подаём 512 байт БЕЗ CRC, и ожидаем response data token, должен быть 0xE5 -данные приняты.
Чтение 512 байт блока из карты: после подачи CMD17 с адресом блока и получения response R1 байта, выбираем байты из карты 0xFF, пока не получим 0xFE, читаем следующие 512 байт данных из карты + 2 байта CRC.
Стирание кластера. Именно кластер стираем чтобы уменьшить время записи данных на карту и уменьшить общее время взаимодействия с картой, для увеличения времени работы с другими SPI устройствами на одной шине. Выбор размера кластера в 1024 байта описан выше и обусловлен оптимальным временем стирания. Подаём CMD32 CMD33 CMD38 и отключаем карту от SPI или ждём пока DO карты не установится в 1 после подачи 0xFF в карту. Данные на карте после стирания будут нулями или единицами, в зависимости от производителя карты. Регистр SCR, бит DATA_STAT_AFTER_ERASE, номер бита 55 определяет что это будут за данные после стирания - либо 0, либо 1. У Transcend это "0".
Всё что касается взаимодействия с картой описано. Дальше реализация самого алгоритма циклической записи данных с контролем отсутствия пропусков при максимальной нагрузке. Разумеется реализация алгорима частичной передачи 512 байтного блока в карту, для реализации окон выбора приёмных буферов двух внешних CAN устройств на той же SPI шине.
По итогу всё получилось максимально чётко, даже с существеным запасом по быстродействию микроконтроллера.
CS чип селект, работает как обычно, в разных источниках советуют до или после передавать 0xFF -ерунда нужно сделать нормальное согласование уровней.
Некоторые карты могут требовать большого и не предсказуемого времени для записи блока данных. После приема блока данных и завершения проверки CRC, карта начнет запись и удерживать сигнал DAT0 в лог. 0, если её буфер записи будет заполнен, и новые данные не будут доступны от новой команды WRITE_BLOCK. Хост может опрашивать состояние карты командой SEND_STATUS (CMD13) в любой момент времени, и карта ответит информацией о своем статусе. Бит статуса READY_FOR_DATA показывает, готова ли карта принять новые данные, или процесс записи все еще продолжается. Хост может снять выбор карты выдачей команды CMD7 (чтобы выбрать другую карту) что поместит эту карту в отключенное состояние (Disconnect State), и освободит линию DAT без обрыва операции записи. Когда карта будет выбрана снова, будет повторно активирована индикация занятости переводом DAT в лог. 0, если программирование все еще продолжается, и буфер записи пока недоступен. В действительности хост может выполнить одновременно операцию записи в несколько карт, если проводить запись с чередованием между картами. Чередование может быть осуществлено путем доступа к каждой карте по отдельности - пока другие карты находятся в занятом состоянии, манипуляции происходят со свободными картами. Этот процесс может быть осуществлен правильной манипуляцией CMD и линией DAT0-DAT3 (отключение занятых карт).
Ну как бы вот, если нужно надёжное устройство с использованием SDHC карт, обращайтесь разработаю, при необходимости будет организовано производство устройств на своих производственных мощностях.