Что хранится в spi flash телевизора

Обновлено: 13.05.2024

Микроконтроллеры STM32: работа с SPI на примере флеш-памяти AT45DB161E

Благодаря заметке Микроконтроллеры STM32: работа с внешним EEPROM мы научились работать с внешней EEPROM-памятью с I2C-интерфейсом. Сегодня же мы научимся использовать флеш-память с SPI-интерфейсом на примере популярных чипов AT45DBxx. Существуют разные модификации этих чипов, отличающиеся в основном объемом памяти. При написании этой заметки я использовал AT45DB161E объемом 16 Мбит (2 Мб). Но, по идее, все описанное ниже справедливо и для других чипов этой серии.

Пожалуй, наиболее очевидное преимущество чипов AT45DBxx перед рассмотренными ранее 24Cxx заключается в существенно большем объеме памяти. У первых я видел модификации, хранящие 8 Мб данных (AT45DB641E), и теоретически протокол позволяет работать с объемами данных до 16 Мб. Вторые же предлагают максимум 256 Кб. AT45DB161E поддерживает передачу данных с тактовой частотой до 85 МГц, против 400 КГц у 24LC64. То есть, чипы AT45DBxx позволяют передавать данные намного быстрее. Но при этом следует учитывать время выполнения конкретных операций. Например, операция очистки и записи одной страницы в случае AT45DBxx занимает десятки миллисекунд.

EEPROM хорош тем, что он более долговечен. Даташит 24LC64 [PDF] сообщает, что чип переживает более 1 миллиона циклов очистки-записи, и что данные будут хранится более 200 лет. Для сравнения, согласно даташиту AT45DB161E, гарантируется только 100 000 циклов очистки-записи, и данные хранятся лишь 20 лет. Кроме того, чипы 24Cxx заметно дешевле. Розничные цены в России на них начинаются где-то от 0.1$, против 0.6$ у чипов AT45DBxx. Наконец, как мы скоро убедимся, работать с AT45DBxx несколько сложнее, хотя эта сложность и может быть завернута в библиотеку.

Вот что должно получиться:

Настройка SPI в STM32CubeMX

В случае подключения Arduino-шилда к плате Nucleo расположение пинов будет следующее: пины (D13, D12, D11, D10) шилда = пины (PA5, PA6, PA7, PB6) микроконтроллера = пины (SCK, MISO, MOSI, CS) шины SPI. Далее генерируем проект, правим немного Makefile — все как обычно. Можно взять за основу Makefile из предыдущего проекта, убрав из списка C_SOURCES все лишнее (например, про I2C) и добавив в него строчку:

Взглянем на распиновку AT45DB161E (иллюстрация из даташита [PDF]):

Распиновка SPI-flash памяти AT45DB161E

Питание подается через пины VCC и GND, нужно от 2.5 В до 3.6 В. Общение с чипом по SPI производится через пины SI, SO, SCK и CS. Подключаем их к соответствующим пинам отладочной платы. Пин WP — это write protection. Если WP подключен к плюсу, разрешено и чтение и запись. Если же пин подключен к минусу, разрешено только чтение. По умолчанию WP уже подтянут к плюсу, поэтому можно оставить его висящим. Тем не менее, даташит рекомендуется по возможности дополнительно подключать его к VCC. Наконец, подача низкого напряжения на пин RESET сбрасывает внутреннее состояние чипа. Если эта возможность не используется, даташит рекомендует подключить пин к VCC.

С учетом всего вышесказанного, у меня получился такой сэндвич:

Подключение SPI-flash памяти к отладочной плате Nucleo

На этом работа с железной частью завершена, переходим к софтверной. Даташит содержит подробное описание множества команд, поддерживаемых чипом. Рассмотрим некоторые из них.

Самая простая команда, это, пожалуй, получение device id. Я бы советовал выполнить ее в первую очередь, чтобы убедиться в правильности подключения и всего такого. Команда имеет код 0 x 9F и принимает в ответ 5 байт:

HAL_StatusTypeDef res1 , res2 ;
uint8_t devid_cmd [ 1 ] = < 0x9F >;
uint8_t devid_res [ 5 ] ;

HAL_GPIO_WritePin ( GPIOB , GPIO_PIN_6 , GPIO_PIN_RESET ) ;
res1 = HAL_SPI_Transmit ( & hspi1 , devid_cmd , sizeof ( devid_cmd ) ,
HAL_MAX_DELAY ) ;
res2 = HAL_SPI_Receive ( & hspi1 , devid_res , sizeof ( devid_res ) ,
HAL_MAX_DELAY ) ;
HAL_GPIO_WritePin ( GPIOB , GPIO_PIN_6 , GPIO_PIN_SET ) ;

if ( ( res1 != HAL_OK ) || ( res2 != HAL_OK ) ) <
char msg [ 256 ] ;
snprintf (
msg , sizeof ( msg ) ,
"Error during getting the device id, res1 = %d, res2 = %d \r \n " ,
res1 , res2 ) ;
HAL_UART_Transmit ( & huart2 , ( uint8_t * ) msg , strlen ( msg ) ,
HAL_MAX_DELAY ) ;
return ;
>

<
char msg [ 256 ] ;
snprintf ( msg , sizeof ( msg ) ,
"Manufacturer ID: 0x%02X \r \n "
"Device ID (byte 1): 0x%02X \r \n "
"Device ID (byte 2): 0x%02X \r \n "
"Extended device information (EDI) string length: 0x%02X \r \n "
"EDI byte 1: 0x%02X \r \n "
"-------- \r \n " ,
devid_res [ 0 ] , devid_res [ 1 ] , devid_res [ 2 ] ,
devid_res [ 3 ] , devid_res [ 4 ] ) ;
HAL_UART_Transmit ( & huart2 , ( uint8_t * ) msg , strlen ( msg ) ,
HAL_MAX_DELAY ) ;
>

Ответ должен быть следующим:

Manufacturer ID: 0x1F
Device ID (byte 1): 0x26
Device ID (byte 2): 0x00
Extended device information (EDI) string length: 0x01
EDI byte 1: 0x00

Чтобы записать данные через буфер 1 с предварительной очисткой страницы, воспользуемся командой 0 x 82. Следом за кодом команды должны следовать три байта, содержащие адрес, по которому мы хотим осуществить запись, а затем и сами данные. О том, что передача данных завершилась, устройство узнает по исчезновению низкого напряжения с пина CS:

uint16_t pageAddr = 0x123 ;
const char wmsg [ ] = "This is a test message" ;

uint8_t wcmd [ 4 ] ;
// opcode
wcmd [ 0 ] = 0x82 ; // 0x82 for buffer 1, 0x85 for buffer 2
// for 512 bytes/page chip address is transfered in form:
// 000AAAAA AAAAAAAa aaaaaaaa
// wcmd[1] = (pageAddr >> 7) & 0x1F;
// wcmd[2] = (pageAddr
// wcmd[3] = 0x00;

// 00PPPPPP PPPPPPBB BBBBBBBB
wcmd [ 1 ] = ( pageAddr >> 6 ) & 0x3F ;
wcmd [ 2 ] = ( pageAddr 2 ) & 0xFC ;
wcmd [ 3 ] = 0x00 ;

HAL_GPIO_WritePin ( GPIOB , GPIO_PIN_6 , GPIO_PIN_RESET ) ;
res1 = HAL_SPI_Transmit ( & hspi1 , wcmd , sizeof ( wcmd ) ,
HAL_MAX_DELAY ) ;
res2 = HAL_SPI_Transmit ( & hspi1 , ( uint8_t * ) wmsg , sizeof ( wmsg ) ,
HAL_MAX_DELAY ) ;
HAL_GPIO_WritePin ( GPIOB , GPIO_PIN_6 , GPIO_PIN_SET ) ;

if ( ( res1 != HAL_OK ) || ( res2 != HAL_OK ) ) <
char msg [ 256 ] ;
snprintf (
msg , sizeof ( msg ) ,
"Error during writing the data, res1 = %d, res2 = %d \r \n " ,
res1 , res2 ) ;
HAL_UART_Transmit ( & huart2 , ( uint8_t * ) msg , strlen ( msg ) ,
HAL_MAX_DELAY ) ;
return ;
>

Выполнение команды происходит не моментально. Поэтому если сразу после записи мы попытаемся прочитать данные, то, скорее всего, увидим мусор. Можно просто сделать HAL_Delay , скажем, на 20 мс, но, строго говоря, такой вызов не гарантирует, что при возвращении из него запись данных будет обязательно завершена. Действительно работающее решение заключается в чтении status register устройства и проверки его флага RDY. Соответствующая команда имеет код 0 x D7 и получает в ответ два байта с содержимым регистра. Если после выполнения команды не вернуть высокое напряжение на CS, устройство продолжит посылать обновленные значения регистра. Пример кода:

uint32_t delta = HAL_GetTick ( ) ;
uint32_t cnt = 0 ;

uint8_t status_cmd [ 1 ] = < 0xD7 >;
uint8_t status_res [ 2 ] ;
HAL_GPIO_WritePin ( GPIOB , GPIO_PIN_6 , GPIO_PIN_RESET ) ;
HAL_SPI_Transmit ( & hspi1 , status_cmd , sizeof ( status_cmd ) ,
HAL_MAX_DELAY ) ;
do <
cnt ++;
res1 = HAL_SPI_Receive ( & hspi1 , status_res , sizeof ( status_res ) ,
HAL_MAX_DELAY ) ;
if ( res1 != HAL_OK )
break ;
> while ( ! ( status_res [ 0 ] & 0x80 ) ) ; // check RDY flag

HAL_GPIO_WritePin ( GPIOB , GPIO_PIN_6 , GPIO_PIN_SET ) ;

delta = HAL_GetTick ( ) - delta ;
uint8_t protect = ( status_res [ 0 ] >> 1 ) & 0x01 ;
uint8_t page_size = ( status_res [ 0 ] ) & 0x01 ;
uint8_t epe = ( status_res [ 1 ] >> 5 ) & 0x01 ;
uint8_t sle = ( status_res [ 1 ] >> 3 ) & 0x01 ;
char msg [ 256 ] ;
snprintf ( msg , sizeof ( msg ) ,
"Await loop took %ld ms, %ld iterations \r \n "
"Sector protection status: %s \r \n "
"Page size: %d bytes \r \n "
"Erase/program error: %s \r \n "
"Sector lockdown command: %s \r \n "
"-------- \r \n " ,
delta , cnt ,
protect ? "enabled" : "disabled" ,
page_size ? 512 : 528 ,
epe ? "ERROR!" : "no error" ,
sle ? "enabled" : "disabled" ) ;
HAL_UART_Transmit ( & huart2 , ( uint8_t * ) msg , strlen ( msg ) , HAL_MAX_DELAY ) ;

Await loop took 10 ms, 1750 iterations
Sector protection status: disabled
Page size: 528 bytes
Erase/program error: no error
Sector lockdown command: enabled

Дождавшись завершения записи, можно попытаться и прочитать только что записанные данные. Для этого существуют команды 0 x 0B и 0 x 1B. Последняя, насколько я смог выяснить, появилась лишь в более поздних чипах производства Adesto (компания купила эту часть бизнеса у Atmel в 2012 году), и не упоминается в даташитах более старых устройств, например AT45DB161D [PDF]. Поэтому рассмотрим более переносимую команду 0 x 0B. Как и в случае с записью, за ней должны следовать три байта, содержащие адрес, который мы читаем. Кроме того, должен следовать один байт, значение которого будет проигнорировано. Пример кода:

char rmsg [ sizeof ( wmsg ) ] = < 0 >;

uint8_t rcmd [ 5 ] ;
// opcode
rcmd [ 0 ] = 0x0B ;

// for 512 bytes/page chip address is transfered in form:
// rcmd[1] = (pageAddr >> 7) & 0x1F;
// rcmd[2] = (pageAddr
// rcmd[3] = 0x00;

// 00PPPPPP PPPPPPBB BBBBBBBB
rcmd [ 1 ] = ( pageAddr >> 6 ) & 0x3F ;
rcmd [ 2 ] = ( pageAddr 2 ) & 0xFC ;
rcmd [ 3 ] = 0x00 ;

// one dummy byte
rcmd [ 4 ] = 0x00 ;

HAL_GPIO_WritePin ( GPIOB , GPIO_PIN_6 , GPIO_PIN_RESET ) ;
res1 = HAL_SPI_Transmit ( & hspi1 , rcmd , sizeof ( rcmd ) ,
HAL_MAX_DELAY ) ;
res2 = HAL_SPI_Receive ( & hspi1 , ( uint8_t * ) rmsg , sizeof ( rmsg ) ,
HAL_MAX_DELAY ) ;
HAL_GPIO_WritePin ( GPIOB , GPIO_PIN_6 , GPIO_PIN_SET ) ;

if ( ( res1 != HAL_OK ) || ( res2 != HAL_OK ) ) <
char msg [ 256 ] ;
snprintf (
msg , sizeof ( msg ) ,
"Error during reading the data, res1 = %d, res2 = %d \r \n " ,
res1 , res2 ) ;
HAL_UART_Transmit ( & huart2 , ( uint8_t * ) msg , strlen ( msg ) ,
HAL_MAX_DELAY ) ;
return ;
>

if ( memcmp ( rmsg , wmsg , sizeof ( rmsg ) ) == 0 ) <
const char result [ ] = "Test passed! \r \n " ;
HAL_UART_Transmit ( & huart2 , ( uint8_t * ) result , sizeof ( result ) - 1 ,
HAL_MAX_DELAY ) ;
> else <
char msg [ 256 ] ;
snprintf (
msg , sizeof ( msg ) ,
"Test failed: wmsg = '%s', rmsg = '%s' \r \n " ,
wmsg , rmsg ) ;
HAL_UART_Transmit ( & huart2 , ( uint8_t * ) msg , strlen ( msg ) ,
HAL_MAX_DELAY ) ;
>

Итак, теперь мы знаем, как осуществлять чтение и запись. Этих знаний должно вполне хватить для решения 99% практических задач.

Важно! Обратите внимание, что процедуры HAL_SPI_* принимают размер данных в виде типа uint16_t . То есть, если вам когда-нибудь понадобится передать или принять по SPI больше 64 Кб, данные придется нарезать на куски.

Полную версию исходного кода, как обычно, вы найдете на GitHub. Напомню, что в настоящем, боевом коде вы, вероятно, захотите более серьезно отнестись к проверьке кодов возврата, чем это делал я. Кроме того, я бы советовал хранить вместе с данными их контрольную сумму. За более подробной информацией по чипу AT45DB161E обращайтесь к даташиту [PDF], он классный. Что же касается работы с SPI, стоит отметить, что за кадром осталось использование его совместно с прерываниями и DMA. Но об этом уж как-нибудь в другой раз.

А доводилось ли вам работать с чипами AT45DBxx или чем-то аналогичным? Возникали ли у вас с ними какие-то проблемы? Если не секрет, что именно вы в них хранили?

SPI (англ. Serial Peripheral Interface, SPI bus — последовательный периферийный интерфейс, шина SPI) — последовательный синхронный стандарт передачи данных в режиме полного дуплекса, разработанный компанией Motorola для обеспечения простого и недорогого сопряжения микроконтроллеров и периферии. SPI также иногда называют четырёхпроводным (англ. four-wire) интерфейсом.



В SPI используются четыре цифровых сигнала:

MOSI (SI, DO, SDO, DOUT) — выход ведущего, вход ведомого (англ. Master Out Slave In). Служит для передачи данных от ведущего устройства ведомому.

MISO (SO, DI, SDI, DIN) — вход ведущего, выход ведомого (англ. Master In Slave Out). Служит для передачи данных от ведомого устройства ведущему.

SCLK (DCLOCK, CLK, SCK) — последовательный тактовый сигнал (англ. Serial Clock). Служит для передачи тактового сигнала для ведомых устройств.

CS или SS — выбор микросхемы, выбор ведомого (англ. Chip Select, Slave Select).

Установка данных при передаче и выборка при приеме всегда выполняются по противоположным фронтам синхронизации. Это необходимо для гарантирования выборки данных после надежного их установления. Если к этому учесть, что в качестве первого фронта в цикле передачи может выступать нарастающий или падающий фронт, то всего возможно четыре варианта логики работы интерфейса SPI. Эти варианты получили название режимов SPI и описываются двумя параметрами:

  • CPOL=0 показывает, что сигнал синхронизации начинается с низкого уровня, так что передний фронт является нарастающим, а задний — падающим.
  • CPOL=1, показывает, что сигнал синхронизации начинается с высокого уровня, таким образом передний фронт является падающим, а задний — нарастающим.
  • CPHA=0 показывает, что необходимо производить выборку по переднему фронту
  • CPHA=1 показывает, что выборку данных необходимо производить по заднему фронту.

Пунктирной линией показывает момент передачи данных.

Режим 0 / Mode 0


Режим 1 / Mode 1


Режим 2 / Mode 2


Режим 3 / Mode 3


От теории перейдем к практике.

Как всегда начнем с объявления необходимых переменных.

Для начала проведем настройку линий интерфейса. В принципе все это можно сделать в первоначальной настройке контроллера, но для примера вынесем все в отдельную функцию. Данную функцию можно запустить один раз при настройке контроллера.

Ну и конечно же функции Передачи и Приема.

Память Atmel DataFlash AT45DB081D.

Несколько особенностей при работе с данной памятью.

1. По умолчанию вся память организована по 264 байта на страницу. Ее можно реорганизовать на 256 байт на страницу, НО это возможно сделать только один раз и обратно на 264 сменить не удастся. Так что не будем на этом заморачиваться, тем более что это никак нам не мешает. Также у памяти есть специальные 4 байта в которые можно записать идентификатор (например серийный номер изделия), но запись в них так же однократная и перезаписи не подлежит.

  • RESET — аппаратный сброс микросхемы;
  • WP (Write Protection) — аппаратная защита от перезаписи.

3. Обмен данными происходит по 4-х проводному интерфейсу SPI. Микросхема может работать в режимах SPI 0 и 3, а также двух собственных режимах Atmel. Чтобы во всем этом не разбираться будем использовать обычный SPI mode 0.

5. После подачи питания и перед обращением к памяти необходимо сделать гарантированную задержку в 20 миллисекунд.

Особенности страничной памяти.

  • определить страницу и расположение на странице интересующего нас байта (адресация сквозная так что это не так сложно);
  • считать необходимую страницу во внутренний буфер;
  • прочитать из внутреннего буфера необходимые данные (или весь буфер).

Написано может быть и чуть не понятно, но в общем работа с памятью сводится к последовательному заполнению внутреннего буфера. В случае его полного заполнения производится запись в страницу памяти. В дальнейшем буфер снова заполняется с начала.

Адрес байта в памяти записывается тремя байтами:
x x x P P P P P P P P P P P P B B B B B B B B B
где x x x — резерв (не используется, =0);
P P P P P P P P P P P P — адрес страницы (12 бит), может принимать значения от 0 до 4095;
B B B B B B B B B — адрес байта на странице (9 бит), может принимать значения от 0 до 263/255.

В качестве примера вычислим расположение байта под номером 353 246.
Для определения номера страницы разделим число на 264:
353246 / 264 = 1338,053 = 1338 = 01010 0111010
А теперь определим адрес байта на странице:
353246 — (1338*264) = 353246 — 353232 = 14 = 000001110
Таким образом получается адрес: 00001010 01110100 00001110 или 0Ah 74h 0Eh.

Ну что же приступаем, глядишь на деле все и проясниться.

Оформим это в отдельную функцию.


Использовать ее можно вот так:


А для определения окончания записи, вот так:

Команда очистки памяти.


Этот процесс достаточно длительный и может занимать от 7 до 22 секунд.

Рассмотрим остальные команды на примере чтения пяти байт из памяти, начиная с адреса 353246 (адрес страницы — 1338, адрес байта — 14) в массив unsigned char MEMbuff[5];. Работать будем через Buffer 1.


1 Dummy Byte — 1 пустой (произвольный) байт необходим памяти для подготовки данных, этакая небольшая временная задержка.

После этих двух операций пять считанных байт, начиная с адреса 353246, будут записаны в массив MEMbuff.

А теперь попробуем записать те же пять байт в ту же область памяти. На этот раз работать будем через Buffer 2.


Примечание: если требуется просто записать данные на страницу, не заботясь об уже имеющихся на ней данных, то можно этот этап пропустить. Тогда при записи буфера обратно в страницу все остальные ячейки будут переписаны содержимым буфера.


Хотя в даташите ничего не сказано про 1 Dummy Byte, правильно память заработала только с ним.

3. Записать буфер 2 в страницу памяти.

Проверка.

Так как модели для протеуса не нашлось, будем экспериментировать в железе.

Для индикации работы подключим к RC2 анод светодиода, катод на землю.

Проверочная программа.
1. Зажигает светодиод. Выполняет очистку памяти. После окончания очистки гасит светодиод.
2. Записывает 5 байт в память.
3. Читает 5 байт из памяти.
4. Считанные данные записываются в EEPROM память контроллера. Светодиод начинает мигать.

Для проверки необходимо прошить программу в контроллер, дождаться когда начнет мигать светодиод, выключить контроллер и считать EEPROM.

(2175) 5.00 (4) Оценки, комментарии

2020-03-20 Дата последнего изменения: 2021-03-04

В статье рассматриваются особенности применения микросхем SPI NAND FLASH (часто их еще называют Serial NAND), методы разметки страниц и управления плохими блоками, даны рекомендации по программированию на программаторах ChipStar.

CОДЕРЖАНИЕ:

1. ТЕОРИЯ

1.1. Коротко об SPI NAND FLASH

Микросхемы SPI NAND или Serial NAND являются разновидностью микросхем FLASH памяти типа NAND. Как и у всех подобных микросхем, их отличительными чертами являются:

  • Очень большой объем памяти.
  • Не гарантированное качество записи (возможно наличие ошибок).
  • Микросхемы могут иметь плохие (сбойные) блоки.
  • Размер страницы записи не является степенью 2.
  • Запись в микросхему осуществляетсятолько страницами, стирание- минимум блоками.

Подробно о классификации микросхем NAND, их видах, внутренней логической структуре подробно написано в нашей первой статье о NAND микросхемах. В этой статье мы больше коснемся особенностей SPI NAND (Serial NAND) и практической работы с ними.

1.2. Отличие микросхем SPI NAND от обычных (параллельных) микросхем NAND FLASH

Основное отличие заключается в том, что SPI NAND используют последовательный (serial) аппаратный интерфейс стандарта SPI (Serial Peripheral Interface).

Использование SPI дает ряд преимуществ:

  • Позволяет сделать корпус микросхем более компактным;
  • Позволяет использовать меньшее количество сигналов для управления микросхемой (4 против минимум 13 у параллельных NAND).

Однако SPI интерфейс при прочих равных условиях более медленный, поэтому микросхемы будут читаться и писаться несколько медленнее, чем традиционные NAND.

Все остальные особенности SPI NAND (логическая организация, управление плохими блоками и исправление ошибок) идентичны используемым у параллельных NAND и подробно рассмотрены в основной статье. Единственное отличие лишь в том, что в SPI NAND более широко используется механизм встроенного вычисления ECC кодов и исправления ошибок сразу внутри микросхемы. По этому признаку SPI NAND относятся к категории Managed NAND (управляемые NAND).

Главной особенностью логической организации SPI NAND является то, что большинство из них поддерживают встроенную генерацию кодов исправления ошибок (ECC) при записи и автоматическое исправление ошибок при чтении:

  • Коды ECC вычисляются непосредственно перед записью страницы;
  • Корректировка происходит сразу после считывания страницы;
  • Коды ЕСС записываются в определенное место SPARE области страницы;
  • Коды ECC вычисляются для всей области данных страницы, но только для некоторой части SPARE области;
  • Разметка SPARE области для разных микросхем разная;
  • Вычисление ECC у большинства микросхем можно временно отключить;
  • У некоторых микросхем часть области SPARE, в которой сохраняются коды ECC, недоступна для пользователя;
  • У некоторых микросхем при включении или выключении внутреннего вычисления ЕСС изменяется размер SPARE области;

Все вышеописанное скорее усложняет, чем упрощает, работу тем, кто занимается ремонтом аппаратуры и заранее не знает, каким образом и в каком режиме ECC используется микросхема в аппаратуре.

2. ПРАКТИКА

2.1. Настройка интерфейса SPI

В большинстве случаев для чтения и записи SPI NAND не требуется каких-либо дополнительных настроек, однако, в некоторых случаях, возможно, потребуется кое-что переключить:


Например, можно уменьшить скорость работы SPI интерфейса или переключить формат адреса в режим совместимости с обычными SPI FLASH.

2.2. Считывание образа SPI NAND

Считывание SPI NAND происходит абсолютно идентично чтению любых других микросхем. После начала чтения сразу открывается окно редактора:

Рисунок: Формат spare области в редакторе программатора

Как и для обычных NAND резервная (spare) область в редакторе показана более тусклым шрифтом, присутствует навигация по страницам, блокам и плохим блокам. Кроме того, часть резервной (spare) области, в которую записываются коды исправления ошибок (ECC), дополнительно выделена бледно-голубым. Это сделано не просто так: такое выделение существенно поможет вам в анализе содержимого образа микросхемы.

Как уже мы писали выше, у разных микросхем spare области имеют разный формат.

Рисунок: Формат spare области в редакторе программатора

Выделение другим цветом части резервной области, предназначенной для записи ECC, существенно облегчает просмотр дампа.

2.3. Поддержка разных форматов резервной области

Если переключить редактор на закладку NAND, то, кроме информации, характерной для обычных NAND (о размере страницы резервной области и списка плохих блоков), можно еще увидеть информацию о разметке резервной области и отчет об ошибках ECC, если они были обнаружены при чтении:

Рисунок: Отчет о конфигурации NAND в редакторе программатора

  • ECC коды хранятся в резервной (spare) области начиная с адреса 0x840 по адрес 0x87F (конец области) одним непрерывным блоком.
  • В отчете о внутренних ошибках ЕСС видно, что страницы 1 и 2 содержат исправляемые ошибки (менее 8 на сектор для данной микросхемы), а вот ошибок на странице 3 оказалось слишком много, и они не исправлены.

2.4. Запись образа SPI NAND

Рассмотрим несколько примеров. На рисунке ниже показано окно подтверждения начала записи с открытой закладкой ECC в случае, если форматы резервной области и исходного файла и микросхемы совпадают:


На следующем рисунке когда форматы резервной области и исходного файла также совпадают, но формат другой:


Ниже показан случай несовпадения разметки резервных областей:


В этом случае программа выдает предупреждение и блокирует попытку записи такой микросхемы, как заведомо неуспешную.

Попробуем записать файл в микросхему SPI NAND с включенным режимом внутренней генерации ECC. На рисунке ниже показан пример такой записи:


На левой части рисунка представлено окно редактора, которое соответствует тому, что мы писали в микросхему. На правой части отображается то, что было записано и считано в результате работы внутреннего алгоритма ECC.

  1. Основная область страницы в редакторе показана обычным шрифтом;
  2. Резервная (spare) область микросхемы показана тусклым шрифтом, место маркера плохого блока показано на оранжевом фоне;
  3. Резервная (spare) область микросхемы предназначенная для размещения ECC выделена светло-голубым фоном;
  4. Резервная (spare) область микросхемы заполненная кодами ECC (результат внутренней генерации ECC).

Хорошо видно, что часть страницы, предназначенная для ECC, была автоматически ими заполнена и записана. При этом исходное содержимое этой области полностью игнорируется.

Программное обеспечение программатора ChipStar знает о такой особенности этих микросхем и не выдает ошибок при верификации таких микросхем: все различия в области ECC будут учтены в отчете о верификации, но ошибка верификации выдана не будет. А вот при сравнении двух файлов эти области будут отмечены как ошибочные. Таким образом, можно гибко анализировать и сравнивать содержимое микросхем.

2.5. Чтение информации ONFI

SPI NAND, как и параллельные (обычные) микросхемы NAND, поддерживают считывание таблиц конфигурации устройства в соответствии со спецификацией ONFI (Open Nand Flash Interface):

Рисунок: Информация ONFI считанная из микросхемы

В отличие от паралельных NAND у SPI NAND с поддержкой ONFI дела обстоят значительно лучше. Все известные нам микросхемы поддерживают ONFI.

На рисунке выше значение "ширина шины данных" (data bus) в отчете ONFI указывается как 8 бит, хотя, как известно, SPI интерфейс однобитный. В этом нет ничего странного: здесь имеется в виду организация памяти по восемь бит. Также в отчете ONFI указано требование к внешнему алгоритму ECC исправлять 0 ошибок (исправлять не требуется). Однако внутренний алгоритм исправляет до 8 ошибок, поэтому при выключенном внутреннем ECC внешний алгоритм просто обязан исправлять те же восемь ошибок. Поэтому в базе данных программатора прописано именно "8" и это не является ошибкой.

2.6. Как узнать, использует ли целевое устройство встроенную в микросхему коррекцию ошибок (ECC)

Этот практический совет может пригодиться тем, кто занимается ремонтом РЭА . Часто в этом случае на руках имеется только устройство с микросхемой и не ясно, по каким алгоритмам работает программное обеспечение устройства. Поэтому важно правильно считать дамп микросхемы. Но какой дамп будет правильный: считанный с включенной коррекцией ECC или с выключенной?

SPI - (Serial Peripheral Interface) эспиай, последовательный периферийный интерфейс иногда называемый 4-х проводным интерфейсом, является последовательным синхронным интерфейсом передачи данных. Изобретён компанией Motorola в середине 1980-x. В отличие от I2C и UART, SPI требует больше сигналов для работы, но может работать на более высоких скоростях. Не поддерживает адресацию, вместо этого используется сигнал SS (slave select - выбор ведомого), который также иногда называется CS (chip select), CE (chip enable) или SE (slave enable). Поддерживает только одного ведущего на шине. Ведущий устанавливает скорость обмена данными и другие параметры, такие как полярность и фаза тактирования. Обмен данными происходит в режиме полного дуплекса, что означает устройства на шине могут одновременно передавать и принимать данные. Интерфейс использует следующие сигналы (в номенклатуре AVR, для получения точного названия сигналов обратитесь к технической документации микросхемы, с которой работаете):

  • MISO (master in slave out) - вход ведущего, выход ведомого
  • MOSI (master out slave in) - выход ведущего, вход ведомого
  • SCK (serial clock) - сигнал тактирования
  • SS (slave select) - сигнал выбор ведомого.

Несмотря на то, что интерфейс называется 4-х проводным, для подключения нескольких ведомых понадобится по одному проводу SS для каждого ведомого (в полнодуплексной реализации). Сигналы MISO, MOSI и SCK являются общими для всех устройств на шине. Ведущий посылает сигнал SS для того ведомого, обмен данными с которым будет осуществляться. Простыми словами, все ведомые, кроме выбранного ведущим будут игнорировать данные на шине. SS является инверсным (active-low), что означает что ведущему необходимо прижать эту линию для выбора ведомого.

Подключение:

SPI на Arduino:

Arduino UNO/Piranha UNO/Arduino ULTRA

На Arduino UNO/Piranha UNO/Arduino ULTRA выводы аппаратного SPI расположены на 10, 11, 12 и 13 выводах, а так же эти выводы соединены с колодкой ICSP (in circuit serial programmer):


Сигнал Вывод
SS 10
MOSI 11
MISO 12
SCK 13

Arduino MEGA

На Arduino MEGA выводы аппаратного SPI расположены на 50, 51, 52 и 53 выводах, а так же эти выводы соединены с колодкой ICSP (in circuit serial programmer):


Сигнал Вывод
SS 53
MOSI 51
MISO 50
SCK 52

Пример для Arduino

В этих примерах мы соединим две Arduino по SPI по следующей схеме:


В одну плату необходимо загрузить скетч ведущего, а в другую скетч ведомого. Для проверки работы необходимо открыть проследовательный монитор той платы, в которую загружен скетч ведомого.

Arduino UNO в качестве ведущего:

Arduino UNO в качестве ведомого:

SPI на Raspberry Pi

На Raspberry Pi выводы аппаратного SPI расположены на выводах GPIO7, GPIO8, GPIO9, GPIO10, GPIO11:


Перед работой с SPI необходимо его включить. Сделать это можно из эмулятора терминала командой sudo raspi-config -> Interfacing options -> Serial -> No -> Yes -> OK -> Finish или из графической среды в главном меню -> Параметры -> Raspberry Pi Configuration -> Interfaces -> SPI

Подробное описание как это сделать можно посмотреть по ссылке Raspberry Pi, включаем I2C, SPI

Пример работы с SPI на Python:

В отличие от Arduino для Raspberry не существует простых решений для работы в режиме ведомого. Подробней ознакомиться с работой чипа BCM Raspberry можно в технической документации на официальном сайте, стр. 160.

Для проверки работы сценария можно подключить Raspberry по SPI к Arduino со скетчем из примера выше через преобразователь уровней или Trema+Expander Hat:


Подробнее о SPI

Параметры

Существуют четыре режима работы SPI, зависящие от полярности (CPOL) и фазы (CPHA) тактирования:

Режим Полярность Фаза Фронт тактирования Фронт установки бита данных
SPI_MODE0 0 0 Спадающий Нарастающий
SPI_MODE1 0 1 Нарастающий Спадающий
SPI_MODE2 1 0 Нарастающий Спадающий
SPI_MODE3 1 1 Спадающий Нарастающий

В Arduino IDE для установки режима необходимо передать функции, возвращающей объект настроек параметр режима работы SPI_MODE, например:

Для выбора режима работы SPI на Raspberry Pi необходимо вызвать дескриптор объекта SpiDev().mode и присвоить ему битовые значения CPOL и CPHA, например:

Скорость передачи данных

Скорость передачи данных устанавливается ведущим и может меняться "на лету". Программист в силах указать лишь максимальную скорость передачи данных.

Читайте также: