‮Сдвиг по фазе (kincajou) wrote,
‮Сдвиг по фазе
kincajou

worklog: "Ты ж смотри, нашёл!"

Первое открытие.

И ведь наверняка в стандарте языка это описано. А если не определено там, то определено в документации на gcc. Но кто ж её читает?
Это я сам себе делаю выговор за то, что в структуре с битовыми полями (bitfield) допустил малозаметную, но коварную ошибку.
Дело в том, что когда объявляешь каждое новое поле новым оператором (см. пример 1), то они идут "снизу вверх" (от младшего адреса к старшему) - это логично и ожидаемо. А вот ежели описываешь их одним оператором (см. пример 2), то они меняются местами. Во всяком случае, для битфилдов gcc ARM Cortex-M7 это так.

Пример 1:
typedef struct {
  uint8_t field1:3;
  uint8_t field2:5;
  uint8_t field3;
} struct1;

Здесь поле field1 займёт младшие 3 бита в первом байте, field2 займёт старшие 5 бит, field3 займёт следующий байт. Упаковка в памяти зависит от опций компиляции, я для таких структур (отображаемых на железо или же на какой-то протокол -- т.е. вольности недопустимы) всегда использую байтовую упаковку.

Пример 2:
typedef struct {
  uint8_t
    field1:3, 
    field2:5;
  uint8_t field3;
} struct1;

Казалось бы, всё то же самое. Но нихрена! тут field1 попадёт в СТАРШИЕ три бита первого байта и, соотв., field2 займёт младшие 5 бит.

Хер такое поймаешь, пока не распотрошишь весь код до самых низов. Потому что симптом выглядел так: хост слал запрос на снятие состояния STALL для конечной точки с адресом 0x81 - я снимал это состояние (точно снимал! дебаггером смотрел - снимается!), а хост снова слал этот запрос. Причина оказалась абсолютно неочевидной и спрятанной совсем в другом месте.

Второе открытие.

USB -- очень хитрованская штука. В протоколе есть так называемые toggle-биты, служащие для простейшей проверки целостности потока кадров. Эти биты чередуются (условно говоря, 0-1-0-1), но из этой последовательности есть строго оговорённые исключения. Когда я писал функции отправки данных, то зачем-то вбил установку этого бита в состояние DATA0 для КАЖДОГО кадра данных, что неправильно, если в транзакции передачи таких кадров больше одного: стандарт требует чередование, а у меня все они промаркированы как DATA0. Хост видит первый, затем видит кривой и полностью игнорирует его (даже в сниффере не видно). Просто убрал установку этого бита (он включается один раз при разрешении работы конечной точки, а дальше железо само следит, когда-что) и вот...

Оно ещё не работает (нет функций для работы с собственно накопителем), но минимально-необходимый скелет готов. Устройство опознаётся, отдаёт все нужные репорты, лепота!
Tags: приключения Электроника
Subscribe

Recent Posts from This Journal

  • Post a new comment

    Error

    Anonymous comments are disabled in this journal

    default userpic

    Your reply will be screened

    Your IP address will be recorded 

  • 14 comments

Recent Posts from This Journal