SPI в STM32F0 как не сесть в лужу или правильная инициализация и отправка данных. Часть 2

   Продолжая тему работы с интерфейсом SPI в микроконтроллерах STM32F0, хотелось бы затронуть не только инициализацию, но и отправку данных. Решение для одной неочевидной проблемы невозможно найти на просторах интернета. Сложно даже сформулировать запрос в гугле на эту тему. Поэтому можно засесть и ломать голову пару дней, а то и неделю.
   Как я уже и говорил, все это не относится к разработчикам, использующим SPL или HAL.

   Предположим, что Вы затактировали, настроили интерфейс SPI и хотите проверить его работу. И вроде бы все очевидно - необходимо просто записать один байт данных в регистр DR, а интерфейс SPI все сделает за Вас. Напишем следующую строку:


   SPI1->DR = 0x5A;

   На логическом анализаторы мы можем наблюдать следующую картину:

STM32F051 SPI
 
   Первая мысль - что-то не так с настройками интерфейса, или просто глюк. Перепроверяем все настройки, но там все очевидно. Сложно запутаться в двух регистрах (уточню, мы используем режим с данными длиной 8 бит). 
   Кажется, будто, используется режим данных 16 бит, и это в принципе, можно проверить. Сконфигурируем CS интерфейса SPI так, чтобы он управлялся железом и генерировал строб между каждой посылкой (читайте в первой части). И снова повторим отправку данных командой, приведенной выше.

STM32F051 SPI

   Выглядит очень странно. Посылка разбивается на 2 байта - сначала отправляется наши данные, а затем загадочный 0x00. Давайте кое что проверим. Отправим в регистр DR слово из 16 бит.

   SPI1->DR = 0x115A;

   Посмотрим что нам покажет анализатор:

STM32F051 SPI

   Теперь совсем все плохо. Интерфейс SPI будто не понимает, что мы используем режим 8 бит и пытается отправить все содержимое регистра DR (регистр имеет длину 16 бит). 
   Давайте разберемся почему так происходит. Для этого нам понадобится дизассемблер. Посмотрим как выглядит наша строка записи данных в регистр DR:

STM32F051 SPI disassembler

STM32F051 SPI disassembler

   Я привел пример для обоих вариантов записи данных в регистр DR (8 и 16 бит) при настройка интерфейса в режиме 8 бит. Обратите внимание на команду STRH - она записывает в регистр периферии (т.е. в нашем случае DR) слово (16 бит) в обоих случаях. Даже если Вы напишите вот так:

   SPI1->DR = (uint8_t)0x5A;

то ничего не изменится. Проблема стала немного яснее. Нужно попробовать записать только один байт в регистр DR. Сделаем это следующим образом:

   *(uint8_t *)&SPI1->DR = 0x5A;

   Теперь посмотрим в дизассемблер:

STM32F051 SPI disassembler

   Видим, что команда STRH заменена на STRB, а это значит, что в регистр DR мы записываем ровно один байт данных, который необходимо отправить. Проверим что получилось.

STM32F051 SPI

   Все работает так, как должно работать. 
   
   Такой неоднозначный функционал интерфейса SPI в режиме 8 бит данных может приводить к ошибкам, которые очень тяжело отыскать. Но с другой стороны, может быть это не баг, а фича? Ведь одной командой мы можем записать сразу два байта на передачу по SPI. Об этом стоит подумать.

Комментарии

Популярные сообщения из этого блога

Разборка ноутбука Xiaomi Mi notebook pro 15.6 (сушим клавиатуру)

Использование UART + DMA при заранее неизветном количестве принимаемых символов (STM32)

Как запрограммировать STM32 без программатора