Comments 26
Объясните, пожалуйста, для чего такое условие:
if(i == 255) return 1;
И из каких соображений выбрано число 255?
Максимальное значение для без знакового 8-ми битного. В цикле не указано крайнее значение, по этому если не использовать данное условие произойдет переполнение переменной и счет продолжится.
Видимо чтоб цикл for не завис в бесконечности при не штатной ситуации.
что бы выскочить из цикла, когда i достигнет 255. (что бы не зависнуть)
так как максимум uint8_t это 255.
Почему именно 255? Думаю методом тыка. Если i = 255, значит точно что-то пошло не так и надо вылить отсюдава.
Предыдущие коментарии все верно сказали:
Это условие сделано на случай если что-то в инициализации RCC пойдет не так. Другой вопрос, что в основном теле программы не предусмотрены действия в случае возникновения ошибок. Но я для этого и сделал дополнение: "она не идеальна, но на данном этапе с задачей справляется". Если пытаться в одной статье объять всё, то она разбухнет до нечитабельных размеров.
Почему именно 255?
Мы выделили под переменную i 1 байт. 255 – это максимальное значение которое может быть у uint8_t (беззнаковой целочисленной переменной размером 1 байт)
Существует стандартная именованная константа UINT8_MAX :)
Возможно, если бы в коде была она, а не просто число 255, вопросов было бы чуть меньше (но не факт, конечно)
Всё это, конечно, синтакический сахар. Но почему бы не написать цикл while или поднять это условие в for. Количество вопросов уменьшиться, а если ещё и магическое число скрыть за осмысленным именем макроса или константы, то и читаемость кода повысится. Можно хотя бы i назвать как timeout, вы же не перебираете массив по индексам, а ждёте.
Вобще странный код на мой взгляд. Обычно для проверки готовности используют подобные конструкции:
while(RCC->CR & RCC_CR_HSIRDY)
Опять же описаная функция инициализации rcc имеет возвращаемое значение, которое никак не обрабатывается при вызове этой самой функции. Может конечно автор планировал сделать какое-то подобие обработчика ошибок?
Обработчик ошибок не сделан с целью уменьшить объем кода и не уходить далеко от разбора переферии CAN.
При такой постонавке:
while(RCC->CR & RCC_CR_HSIRDY)
программа наоборот не выйдет из цикла, а может быть даже не успеет туда зайти т.к. HSI не успеет поднять флаг Ready. Я бы переписал вот так:
while(!(RCC->CR & RCC_CR_HSIRDY)) ...
далее счетчик, и условие при котором заканчиваем цикл и выходим с кодом ошибки.
но уверен есть еще более элегантные решения. В данной статье я решил не заострять на этом внимание.
Ох, ну зачем CMSIS? Не зря ST придумали CubeMX и HAL. Это сейчас понятно, что делают эти строчки:
CAN1->BTR &= ~CAN_BTR_TS1;
CAN1->BTR |= 12U << CAN_BTR_TS1_Pos;
CAN1->BTR &= ~CAN_BTR_TS2;
CAN1->BTR |= 1U << CAN_BTR_TS2_Pos;
А через полгода надо будет каждую строчку разбирать с документацией. Кстати, что за кейворд "-&"? Оно скомпилируется вообще?
При копипасте символы "<" и ">" превратились в < и в >, а " &" в &, как они представлены в HTML То есть приведённый текст читается так:
CAN1->BTR &= ~CAN_BTR_TS1;
CAN1->BTR |= 12U << CAN_BTR_TS1_Pos;
CAN1->BTR &= ~CAN_BTR_TS2;
CAN1->BTR |= 1U << CAN_BTR_TS2_Pos;
Такой текст скомпилируется.
Если работать с CMSIS чуть больше, чем настроить что-то по мануалу из интернетов пару раз, то достаточно быстро регистры запоминаются. Ну и естественно именуются они вменяемо BTR - bit time rigester т.е. эти строчки относятся к настройке таймингов. (в RM не подглядывал)
У вас символы преобразуются некорректно. 32bit_me все верно написал.
А CMSIS на мой взгляд полезен для понимания функционала переферии. Я не призываю везде его использовать, часто это не оптимальное решение. Но опыт работы с регистрами необходим если работаете с HAL, и замечу, что при работе с HAL можно работать и с CMSIS, часть HALа на нём базируется.
Это код из вашей статьи, стоит всё же его поправить.
HAL реализован на некоторых МК с помощью CMSIS, но там хотя бы тестировано и переносимо. По факту, вы написали, что уже было написано. Для обучения — нормально, но для новых проектов, даже для пет-проектов, CMSIS не рекомендуется.
Кстати, HAL позволяет абстрагироваться от тонкостей управления периферией. Нередко, чтобы что-то послать по шине, чтобы все работало, надо дернуть ещё вон тот регистр. С CMSIS это делает вручную. А ты вроде бы всё сделал, но забыл и куришь часами мануал, то ли клок забыл подать, то ли, где ещё какую настройку сделать.
но для новых проектов, даже для пет-проектов, CMSIS не рекомендуется.
Можно где-то об этом прочитать? В моем представлении тот факт, что эта библиотека является стандартизованной, как раз должен говорить об обратном.
К сожалению, с ходу не нашел, где почитать. Считайте, что HAL это условный фреймворк, хотя ST называют его драйвером, поверх фреймворка (стандарта) CMSIS. И если CMSIS это вендоро независимый стандарт для описания МК, то HAL это кристалло-независимая библиотека ST. Если вы пишете под STM, то нецелесообразно применять только CMSIS. Кстати, если примяете HAL, то к регистрам так же можно обращаться с помощью CMSIS, но там это и не нужно.
"Это код из вашей статьи, стоит всё же его поправить."
Попробовал копировать в разные редакторы текста, с кодироками/символами всё в порядке. Судя по всему у других интересующихся тоже всё хорошо отображается. С гитхаба также копируется некорректно?
Не, не, вы не поняли. У вас в статье есть спойлер с полным текстом программы. Под спойлером ужас какой-то отображается, с этими символами.
Затем, что если вам надо будет спрыгнуть с стм32 на какой-нибудь его клон китайский ,т.к. стм32 уже не купить, то через код написанный на cmsis это будет на порядок проще.
Делал CAN год назад на HAL. Была проблема, если PHY физически не подсоединён, в дуплексе, ошибка инициализации будет,
и где часть 2?
Я поменял место работы, сейчас времени на написание, увы, почти нет :-(
Вот тут я экспериментировал, но руки пока не дошли все аккуратно расписать
https://github.com/MViktorE/ARM_CMSIS_HAL_LIBS/blob/main/can_cmsis_m3_mve_v0.h
https://github.com/MViktorE/ARM_CMSIS_HAL_LIBS/blob/main/can_cmsis_m3_mve_v0.c
STM32, CMSIS, CAN, Часть 1 — передача