и это решило проблему в Keil'е, его компилятор сразу размещал константные экземпляры класса во Flash, используя значения, предоставленные в списке инициализации.
Keil это всё компилировал, но контроллер по факту вываливался в Hard Fault.
Сомневаюсь, что новый компилятор Clang скомпилировал бы подобный код приводящий к Hard Fault, скорее это их старый самописный компилятор поддерживающий максимум С++03. И с тех пор определение POD сильно изменилось, даже статья на вики разделена на POD до и после С++11, а в С++20 POD вообще уже deprecated и вместо него появились две новые категории с новыми нюансами. Я бы с этим сильно не заморачивался, не важно дело в конкретном компиляторе или новых стандартах языка, пытаясь разместить классы во флеш все равно много не сэкономишь, лучше сконцентрироваться на том почему при использовании наследования прошивка вырастает до 70KB
и это решило проблему в Keil'е, его компилятор сразу размещал константные экземпляры класса во Flash, используя значения, предоставленные в списке инициализации.
Keil это всё компилировал, но контроллер по факту вываливался в Hard Fault.
Сомневаюсь, что новый компилятор Clang скомпилировал бы подобный код приводящий к Hard Fault, скорее это их старый самописный компилятор поддерживающий максимум С++03. И с тех пор определение POD сильно изменилось, даже статья на вики разделена на POD до и после С++11, а в С++20 POD вообще уже deprecated и вместо него появились две новые категории с новыми нюансами. Я бы с этим сильно не заморачивался, не важно дело в конкретном компиляторе или новых стандартах языка, пытаясь разместить классы во флеш все равно много не сэкономишь, лучше сконцентрироваться на том почему при использовании наследования прошивка вырастает до 70KB
Как то вы немного странно меня процитировали, ну да ладно)) Тестируемый проект для Keil'а прилагаю. IDE-Version: µVision V5.25.2.0, C Compiler: ArmClang.exe V6.9 Результат смотрю через отладчик китайским ST-Link V2.0 Вылаетает в HardFault на всех уровнях оптимизации кроме нулевого. Как мне показалось, компилятор не генерирует 2 варианта всех функций шаблонного класса, а создаёт один "универсальный", у которого вместо GPIOA/GPIOD указано NullPtr и при попытке записи по нулевому адресу он вылетает в HardFault. Что происходит на нулевом я вообще не понял. Если в HardFault в отладчике было видно, что States увеличивается, то тут даже этого не просходит.
По поводу 70KB - это только при нулевой оптимизации и использовании наследования, так что не слишком страшно, но, как по мне, странно.
Тестируемый проект для Keil'а прилагаю. IDE-Version: µVision V5.25.2.0, C Compiler: ArmClang.exe V6.9
Понятно, компилятор таки новый, просто я как-то компилировал такую конструкцию с передачей GPIO_TypeDef* в шаблон под clang и выдавало ошибку, а сейчас проверил и ошибка действительно есть, но только в режиме С++17, а gcc выдает ошибку в любом случае. Похоже это баг clanga, по правилам можно передавать целочисленные константы или указатели/ссылки на объекты или функции, собственно gcc и пишет, что не может взять адрес... Если бы компилировалось и работало, то можно было поспорить, а так
Цитата:
По поводу 70KB - это только при нулевой оптимизации и использовании наследования, так что не слишком страшно, но, как по мне, странно.
Вопрос в том для какого по размеру проекта получатся эти 70КВ, потому что можно вместо newlib-nano выбрать стандартную библиотеку и словить пару десятков KB на одном printf Вообще на достаточно больших проектах -O0 может легко обгонять по размеру -O2 и тем более еще больше любящего инлайнить -O3.
Тестируемый проект для Keil'а прилагаю. IDE-Version: µVision V5.25.2.0, C Compiler: ArmClang.exe V6.9
Понятно, компилятор таки новый, просто я как-то компилировал такую конструкцию с передачей GPIO_TypeDef* в шаблон под clang и выдавало ошибку, а сейчас проверил и ошибка действительно есть, но только в режиме С++17, а gcc выдает ошибку в любом случае. Похоже это баг clanga, по правилам можно передавать целочисленные константы или указатели/ссылки на объекты или функции, собственно gcc и пишет, что не может взять адрес... Если бы компилировалось и работало, то можно было поспорить, а так
В файле CMSIS stm32f10x.h объявлен следующий тип данных
Соответственно GPIO_TypeDef - тип, GPIO_TypeDef* - тип "указатель на объекты этого типа", а GPIOA, GPIOB и пр. - непосредственно указатели на объекты этого типа. Однако, учитывая тот факт, что GCC компилятор не принимает GPIOx в качестве параметра моего шаблона, очевидно, что я что-то путаю. Поправьте где именно я не прав.
Эксперимента ради:
Код:
Stm32Gpio <GPIOA, 1<<8> led0; // ошибка Stm32Gpio <(GPIO_TypeDef *)0x40010800, 1<<8> led1; // таже самая ошибка GPIO_TypeDef GPIO_1; Stm32Gpio <&GPIO_1, 1<<8> led2; // а вот это, хоть и бессмысленно, но компилируется
Не могу понять, чем "&GPIO_1" отличается от "(GPIO_TypeDef *)0x40010800" с точки зрения типа данных?
PS Ваш вариант использовать GPIOx_BASE мне не очень нравится потому что обязывает заранее создать шаблоны для всех GPIO, что по сути дублирует CMSIS. В противном случае ничто не защитит от написания бессмыслицы типа
Код:
template<uint32_t pin, uint32_t af = 0> using PinX = PinT<I2C1_BASE, pin, af>;
Открыта удобная площадка с выгодными ценами, поставляющая весь ассортимент продукции, производимой компанией MEAN WELL – от завоевавших популярность и известных на рынке изделий до новинок. MEAN WELL.Market предоставляет гарантийную и сервисную поддержку, удобный подбор продукции, оперативную доставку по России.
На сайте интернет-магазина посетители смогут найти обзоры, интересные статьи о применении, максимальный объем технических сведений.
Не могу понять, чем "&GPIO_1" отличается от "(GPIO_TypeDef *)0x40010800" с точки зрения типа данных?
GPIO_1 отличается тем, что это реальный объект, причем даже к нему предъявляется ряд требований, например, касательно линковки. Единственную константу которую можно в таком случае передать - это (GPIO_TypeDef*)0, т.е. обозначающую нулевой указатель.
Цитата:
PS Ваш вариант использовать GPIOx_BASE мне не очень нравится потому что обязывает заранее создать шаблоны для всех GPIO, что по сути дублирует CMSIS.
Не понял, класс GpioA дублирует GPIOA из CMSIS? Потому что имена похожи? Так это вроде наоборот хорошо... А функционал у моего класса примерно как и у твоего, так что никакого дублирования я не вижу, тем более совсем не обязательно создавать псевдонимы для каждого порта, можно сделать хоть так:
Продукция MOSO предназначена в основном для индустриальных приложений, использует инновационные решения на основе более 200 собственных патентов для силовой электроники и соответствует международным стандартам. LED-драйверы MOSO применяются в системах наружного освещения разных отраслей, включая промышленность, сельское хозяйство, транспорт и железную дорогу. В ряде серий реализована возможность дистанционного контроля и программирования работы по заданному сценарию. Разберем решения MOSO
подробнее>>
Satarych
Заголовок сообщения: Re: uVision Keil. Помогите разобраться с компиляторами.
Не понял, класс GpioA дублирует GPIOA из CMSIS? Потому что имена похожи? Так это вроде наоборот хорошо... А функционал у моего класса примерно как и у твоего, так что никакого дублирования я не вижу, тем более совсем не обязательно создавать псевдонимы для каждого порта, можно сделать хоть так:
Код:
Pin<'A', 1> led;
Или так:
Код:
enum {PA, PB, PC... }; Gpio<PB, 0x0FF0> port8;
Возможно я не совсем правильно выразился. Я не имел ввиду, что функции класса дублируют возможности CMSIS. Я имею ввиду что в CMSIS'е идёт объявление доступной периферии (GPIOx, SPIx, I2Cx и пр.) и ваш подход предполагает в том или ином виде сделать аналогичное объявление (с помощью частично специализированных шаблонов или перечисления).
А по поводу размещения объектов классов во Flash я частично разобрался. В отличие от компилятора Keil'а, GCC компилятор рассматривает const объекты как "исходное значение будет известно только во время выполнения программы, но в дальнейшем его будет менять нельзя". Для объектов, чьё "исходное значение должно быть определено на этапе компиляции" следует использовать constexpr. В целом это логичное поведение, в большей степени соответствующее смыслу const и constexpr. Просто после работы в Keil'е (который во флеш клал и const объекты, значение которых по факту было известно на этапе компиляции) оно непривычно лично для меня. Итого:
Код:
class Test { public: constexpr Test (uint16_t number) : m_number(number) {} void setNumber (uint16_t number) {m_number = number;} private: uint16_t m_number; };
Test A(15); // Объект в оперативной памяти A.setNumber (10); // Изменить значение можно
const Test B1(15); // Объект всеравно в оперативной памяти const Test B2(<имя объекта>.getValue();) // Зато можно инициализировать чем угодно, через тот же USART B1.setNumber (10); // Ошибка
constexpr Test C1 (15); // Объект находится во флеше constexpr Test B2(<имя объекта>.getValue();) // По понятным причинам так уже сделать не получится
Но, как и в случае в шаблонами, так сделать не получится:
Код:
class Test { public: constexpr Test (GPIO_TypeDef *number) : m_number(number) {} private: GPIO_TypeDef *m_number; };
constexpr Test A(GPIOA); // Error: constexpr variable 'A' must be initialized by a constant expression
Как по мне, константнее некуда)) Могу предположить, что компилятор рассматривает приведения типов через reinterpret_cast как функцию, которая не имеет ключевого слова constexpr в своём объявлении.
Возможно я не совсем правильно выразился. Я не имел ввиду, что функции класса дублируют возможности CMSIS. Я имею ввиду что в CMSIS'е идёт объявление доступной периферии (GPIOx, SPIx, I2Cx и пр.) и ваш подход предполагает в том или ином виде сделать аналогичное объявление (с помощью частично специализированных шаблонов или перечисления).
Как функции класса могут дублировать возможности CMSIS, если в нем таких функций просто нет? Зато по функционалу твой класс GPIO мало чем отличается от моего, значит и у тебя есть такое дублирование
Касательно constexpr... Конечно можно сделать класс с constexpr конструктором и даже будет работать:
Qmask() берет маску пинов и рекурсивно получает из нее четверную маску, причем это гарантированно будет константа времени компиляции, даже для -O0. У тебя в коде в этом месте два цикла, вот у меня без constexpr тоже с -O2 будут циклы, -O3 не всегда, но помогает, только из-за него существенно вырастет размер остального кода. Так что с точки зрения эффективности шаблоны все равно лучше, хотя у constexpr классов преимущество в том, что их можно как обычные параметры передавать...
Так что с точки зрения эффективности шаблоны все равно лучше, хотя у constexpr классов преимущество в том, что их можно как обычные параметры передавать...
Да я на шаблонах и буду реализовывать по итогу, только с наследованием. Тот код, что я тут выкладывал, был эксперимента ради. В любом случае, спасибо за советы.
Компилятор сам всё посчитает и сведёт выражение в правой части присваивания к константе? Или в этой серии контроллеров банально нет этого регистра? Работал только с F1 и L0.
И ещё один вопрос, весьма наивный, но вдруг) В векторе прерываний на каждое прерывание отводится по 4 байта, ровно под указатель на обычную C функцию. Я правильно понимаю, что вызов метода класса (не статический) туда не впихнуть, ибо он банально не влезет в 4 байта?
Компилятор сам всё посчитает и сведёт выражение в правой части присваивания к константе? Или в этой серии контроллеров банально нет этого регистра? Работал только с F1 и L0.
BRR есть не везде, например, нет у F4.
Цитата:
И ещё один вопрос, весьма наивный, но вдруг) В векторе прерываний на каждое прерывание отводится по 4 байта, ровно под указатель на обычную C функцию. Я правильно понимаю, что вызов метода класса (не статический) туда не впихнуть, ибо он банально не влезет в 4 байта?
Не влезет, но даже если бы можно было запихнуть туда 8 байт, мк все равно не смог бы этот адрес правильно обработать.
причем обычный inline там тоже нужен, без него местами даже не компилируется... Про общепринятые принципы именования ничего не скажу, в том же CMSIS есть всякие __STATIC_INLINE, но я такое точно в свои проекты не вставлю
А есть ли тут люди, использующие связку Visual Studio + VisualGDB? В частности VladislavS, рекомендовавший мне её? Наткнулся на странность в поведении стандартной библиотеки. При подключении файлов библиотеки в новом стиле, все имена автоматически находятся в глобальном пространстве имён. VisualGDB использует файлы стандартной библиотеки, которые он сам же и загрузил вместе с GNU GCC (путь ...\SysGCC\arm-eabi\arm-eabi\sys-include\...).
Отсюда первый вопрос: эти файлы модифицированы создателями VisualGDB? Или это стандартные файлы, распространяемые с GCC компилятором, и с другой IDE, использующей GCC компилятор, будет наблюдаться аналогичное поведение? И второй вопрос: как отучить VisualGDB/GCC от такого поведения?
Код:
#include <cstdint> uint32_t A = 0; // Ок // Но в моём понимании, тут должна выдаваться ошибка, т.к. uint32_t // должен находиться в пространстве имён std, но это компилируется
std::uint32_t B = 0; // Ок using std::uint32_t; // Ок uint32_t C = 0; // Ок
UPD: Попробовал скомпилировать с помощью GCC, который скачивал отдельно для Eclipse с сайта ARM. Результат тот же, содержание файлов стандартной библиотеки практически тоже самое. Разницу заметил только в шапке с лицензией
Цитата:
Copyright (C) 2007-2017 Free Software Foundation, Inc.
Подскажите еще, где в Кейле включить в Дебаге просмотр собственных переменных? Вроде было такое окно, а сейчас уже все перетыкал, не могу найти.
Добавлено after 2 minutes 45 seconds: Ой. все, вроде разобрался. Есть там окно симболс. С которого можно отправить переменные из файла мэин.С в окно Вотч. )
C:/Users/New/AppData/Local/Arm/Packs/Keil/STM32F1xx_DFP/2.4.1/Device/StdPeriph_Driver/src/misc.c(131): error: no member named 'IP' in 'NVIC_Type'
Доброго дня! если не трудно подскажите по компилятору версии 6 в последних версиях Keil. При компиляции проекта не находит элемент IP в misc.c. А где он изначально объявлялся то, реально нигде не находит.
Добрый вечер! Компилирую проект в Keil компилятором v6.22, CMSIS 6.1, компилируется без ошибок. Но на экране дисплея ничего нет, пробежался дебагером зависает на строке
Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 11
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения