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. Об этом стоит подумать.

Комментарии

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

О том, как правильно использовать датчик пыли DSM501(A)

Создание проекта для STM8 в IAR EWSTM8

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