Перейти к содержанию
    

AHTOXA

Свой
  • Постов

    4 027
  • Зарегистрирован

  • Посещение

  • Победитель дней

    3

AHTOXA стал победителем дня 18 января

AHTOXA имел наиболее популярный контент!

Репутация

14 Хороший

5 Подписчиков

Информация о AHTOXA

  • Звание
    фанат дивана
    Гуру
  • День рождения 04.09.1970

Информация

  • Город
    Array

Посетители профиля

15 147 просмотров профиля
  1. На VL (value line) отдельный RM, RM041. Это сильно урезанные контроллеры, без USB, и с частотой до 24МГц (пишу по памяти) Это STM32F10X_MD.
  2. Я судил по изменениям в inline-ассемблере IAR-а. Сейчас он выглядит вот так: __attribute__((__always_inline__)) inline void set_interrupt_state(status_reg_t status) { asm volatile ( "MSR PRIMASK, %0\n" : : "r"(status) :"memory" ); } Ну то есть один-в-один gcc. Этож-ж-ж неспроста? 🙂 Короче, мысль моя вот в чём: в 90% случаев должно хватить простого reg; или, для большей понятности (void)reg; Но на всякий случай лучше проверить дизассемблер.
  3. Жуть какая! 🙂 Интересно, с 2010 года хоть какие-то из компиляторов, которые отбрасывают чтение volatile-переменной поменяли своё мнение? (Подозреваю, что IAR поменял, он же теперь вроде бы на LLVM сделан).
  4. Я думаю, это изменение скорости (минус 100Кб/с).
  5. Это стили кодирования пишут для групп программистов. Когда в одном проекте несколько человек. Когда пишешь один - вообще пофиг как именуешь и форматируешь. Главное чтоб тебе самому было понятно. Но даже для себя одного полезно сформулировать эти правила, чтобы потом их придерживаться. Это поможет потом поддерживать проект, когда нужно будет вернуться к нему через год-другой. Из этого тоже можно извлечь пользу: сразу видно, что идёт вызов библиотечного кода 🙂
  6. Ну да, блоком. Или вынести этот кусок в inline-функцию.
  7. А они редакторе подсвечиваются по-разному. (Я использую Eclipse для embedded-проектов, QtCreator для ПК-проектов). Префиксы мне не нравятся. Нет гарантий, что префикс соответствует реальному типу. Сменил тип - забыл про префикс. Гораздо надёжнее не полагаться на префиксы, а использовать возможности современных IDE. Навёл мышку на название типа - получил всплывающую подсказку с кусочком объявления. Если там doxigen- комментарий перед типом, то и он отобразится. Единственное место, где я оставил префиксы - это переменные-члены класса. Они у меня называются m_var; Если интересно, вот рекомендации по кодированию одного из моих старых проектов. Вот, кстати, идеальное место для применения RAII. Создаётся тип CriticalSection, в конструкторе вызываются cpu_alloc_critical_section_context(csc) и cpu_entry_critical_section(csc), а в деструкторе - cpu_leave_critical_section(csc). Тогда функция будет выглядеть так: inline void init() { CriticalSection cs(csc); SPI3->CR1 = SPI_CR1_PRESET_VAL; SPI3->CR2 = SPI_CR2_RXDMAEN | SPI_CR2_TXDMAEN; SPI3->SR = 0x0; SPI3->CRCPR = 0x0; SPI3->I2SCFGR = 0x0; SPI3->I2SPR = 0x0; __DSB(); } Это немного короче, но главное - нет шанса забыть освободить критическую секцию. Даже если где-то посреди функции сделать return;
  8. Если поместить конструкцию using namespace в функцию, то область её действия заканчивается в конце функции: namespace Test { struct Foo { int flag }; } auto makeFoo() { using namespace Test; return Foo {1}; } int main() { auto foo = makeFoo(); // здесь не действует using namespace Test } А в целом, идеологически, все эти пространства имён для того и делались, чтобы виртуально "удлиннить" идентификаторы. Поэтому логично, что запись получается более многословной. Можно от этого огорчаться, можно пытаться сократить запись, а можно просто принять это, и использовать. Запись вида sGPIOCmdDesc descriptor = {sGPIOCmdDesc::GPIO_CTRL, sGPIOCmdDesc::SET_EN_DISPLAY}; не выглядит ужасной, зато сразу видно, что мы не перепутали enum-ы. А если вместо enum использовать enum class, то мы также можем быть уверены, что мы не перепутали местами аргументы.
  9. Это если он не нагружен. Если же нагружен, то при обесточивании он может остаться в том положении, в котором он был на момент обесточивания (типа, на 3/16 шага). В этом случае при возобновлении подачи питания он может сместиться в положение полного шага, которое ему даст драйвер при включении. Но даже в этом случае пара двигателей скорее всего сместится синхронно, потому что в момент обесточивания она с большой вероятностью была в одинаковом положении. У меня у 3D-принтера на оси Z такая конструкция - два мотора. Ничего вроде не перекашивается.
  10. Это всё понятно. Но всё же, реальная-то память под эти элементы массива где-то выделена? То есть, по сути, мы "наводим" наш "безразмерный массив" на лежащий где-то реальный массив. Поэтому я предложил два варианта: либо вместо массива без указания размера указать его максимальный размер (да хоть стопиццот, нам без разницы, потому что реальная длина указана в структуре), либо использовать современный класс span, специально заточенный для таких целей (по сути это и есть указатель + длина). то есть или так: struct sUDPAckReadFIFOCAN1{ Header header; size_t frameSize; sCANFrame frame[100500]; }; или так: struct sUDPAckReadFIFOCAN1{ Header header; std::span<sCANFrame> frames; }; ЗЫ. Во втором случае, конечно не удастся просто привести указатель на буфер приёма/передачи к этой структуре. Это может быть как минусом, так и плюсом, в зависимости от обстоятельств.
  11. А зачем "псевдо"? Ведь данные всё равно лежат в реальном массиве. Его и используйте. Если есть несколько таких структур, различающихся только размерами массивов, можно приводить к максимальному. Ну или взять std::span из c++20. Хотя это не отменяет надобности в массиве для собственно хранения данных.
  12. Тут согласен, иногда хочется иметь какой-то базовый класс со значениями по умолчанию. В принципе, можно сделать вот так: struct CommandInfoTwoParam { struct Params { uint32_t param1; uint32_t param2; }; }; template <> struct CommandInfo<Command::SendData> : public CommandInfoTwoParam {}; Это почти идеально: лишнее дублирование (почти) отсутствует, но тем не менее каждая команда явно описана.
  13. То, что вы описали, почти всегда не нужно. А нужно - чёткое и консистентное описание протокола обмена. Можно составить документ, таблицу, типа код команды - структура параметров запроса - структура параметров ответа. И потом надеяться, что не забудешь внести в неё изменения при добавлении/изменении команды. А можно сделать самодокументирующийся код, как я описал выше. Там всё сразу в одном месте. И никак не получится при добавлении команды "забыть" добавить реализацию шаблона. Будет ошибка компиляции. Меня такой подход многократно выручал. Особенно он удобен, когда приходится возвращаться к проекту после длительного перерыва, и всё уже полностью выветрилось из головы.
  14. Я как раз и агитирую за отдельные структурки. Чтобы для каждой команды было чётко указано, какова структура параметров. Всё это можно вынести в один *.h - файл, и получить самодокументированный код. Кстати, и в этом подходе можно вынести одинаковые структуры "за скобки": struct OneParam { uint32_t param1; } template <> struct CommandInfo<Command::GetInfo> { using Params = OneParam; };
  15. Почему "нет конечно". Конечно да:) Потому что потом, при необходимости изменить структуру sTxSendCAN не придётся искать все её псевдонимы и дорабатывать их. Лучше уж сразу для каждой команды прописать подходящую структуру. Можно использовать плюсовый механизм traits. Типа такого: // перечень всех команд enum Command : uint32_t { Reset = 0, GetInfo = 1, SendData = 2, }; // шаблон структуры, содержащей информацию о команде template<Command cmd> struct CommandInfo; // специализации шаблона для каждой команды (можно туда добавлять всё что угодно: тайм-аут обработки, структуры-параметры и так далее) template <> struct CommandInfo<Command::Reset> { struct Params {}; }; template <> struct CommandInfo<Command::GetInfo> { struct Params { uint32_t param1; }; }; template <> struct CommandInfo<Command::SendData> { struct Params { uint32_t param1; uint32_t param2; }; }; void send(...) { } // и вот как будет выглядеть выбор нужной структуры для заданной команды: void sendData() { using CommandData = CommandInfo<Command::SendData>; using Params = typename CommandData::Params; Params params; send(Command::SendData, &params, sizeof(Params)); } При добавлении новой команды для неё сразу же создаём специализацию шаблона, содержащего инфу о команде. И далее оперируем этой информацией (на обоих концах протокола обмена).
×
×
  • Создать...