Кто любит RISC в жизни, заходим, не стесняемся.
Ответить

Re: uVision Keil. Помогите разобраться с компиляторами.

Вс фев 03, 2019 17:00:07

и это решило проблему в Keil'е, его компилятор сразу размещал константные экземпляры класса во Flash, используя значения, предоставленные в списке инициализации.

Keil это всё компилировал, но контроллер по факту вываливался в Hard Fault.

Сомневаюсь, что новый компилятор Clang скомпилировал бы подобный код приводящий к Hard Fault, скорее это их старый самописный компилятор поддерживающий максимум С++03. И с тех пор определение POD сильно изменилось, даже статья на вики разделена на POD до и после С++11, а в С++20 POD вообще уже deprecated и вместо него появились две новые категории с новыми нюансами. Я бы с этим сильно не заморачивался, не важно дело в конкретном компиляторе или новых стандартах языка, пытаясь разместить классы во флеш все равно много не сэкономишь, лучше сконцентрироваться на том почему при использовании наследования прошивка вырастает до 70KB :)

Re: uVision Keil. Помогите разобраться с компиляторами.

Вс фев 03, 2019 18:29:17

и это решило проблему в 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 - это только при нулевой оптимизации и использовании наследования, так что не слишком страшно, но, как по мне, странно.
Вложения
Тест шаблонов STM32.zip
(96.15 KiB) Скачиваний: 229

Re: uVision Keil. Помогите разобраться с компиляторами.

Вс фев 03, 2019 20:11:18

Тестируемый проект для 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.

Re: uVision Keil. Помогите разобраться с компиляторами.

Вс фев 03, 2019 23:38:47

Тестируемый проект для Keil'а прилагаю. IDE-Version: µVision V5.25.2.0, C Compiler: ArmClang.exe V6.9

Понятно, компилятор таки новый, просто я как-то компилировал такую конструкцию с передачей GPIO_TypeDef* в шаблон под clang и выдавало ошибку, а сейчас проверил и ошибка действительно есть, но только в режиме С++17, а gcc выдает ошибку в любом случае. Похоже это баг clanga, по правилам можно передавать целочисленные константы или указатели/ссылки на объекты или функции, собственно gcc и пишет, что не может взять адрес... Если бы компилировалось и работало, то можно было поспорить, а так :)
В файле CMSIS stm32f10x.h объявлен следующий тип данных
Код:
typedef struct
{
  __IO uint32_t CRL;
  __IO uint32_t CRH;
  __IO uint32_t IDR;
  __IO uint32_t ODR;
  __IO uint32_t BSRR;
  __IO uint32_t BRR;
  __IO uint32_t LCKR;
} GPIO_TypeDef;
Соответственно 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>;

Re: uVision Keil. Помогите разобраться с компиляторами.

Пн фев 04, 2019 02:21:22

Не могу понять, чем "&GPIO_1" отличается от "(GPIO_TypeDef *)0x40010800" с точки зрения типа данных?

GPIO_1 отличается тем, что это реальный объект, причем даже к нему предъявляется ряд требований, например, касательно линковки. Единственную константу которую можно в таком случае передать - это (GPIO_TypeDef*)0, т.е. обозначающую нулевой указатель.

PS Ваш вариант использовать GPIOx_BASE мне не очень нравится потому что обязывает заранее создать шаблоны для всех GPIO, что по сути дублирует CMSIS.

Не понял, класс GpioA дублирует GPIOA из CMSIS? Потому что имена похожи? Так это вроде наоборот хорошо... А функционал у моего класса примерно как и у твоего, так что никакого дублирования я не вижу, тем более совсем не обязательно создавать псевдонимы для каждого порта, можно сделать хоть так:
Код:
Pin<'A', 1> led;

Или так:
Код:
enum {PA, PB, PC... };
Gpio<PB, 0x0FF0> port8;

Re: uVision Keil. Помогите разобраться с компиляторами.

Пн фев 04, 2019 17:34:58

Не понял, класс 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 в своём объявлении.

Re: uVision Keil. Помогите разобраться с компиляторами.

Пн фев 04, 2019 20:32:47

Возможно я не совсем правильно выразился. Я не имел ввиду, что функции класса дублируют возможности CMSIS. Я имею ввиду что в CMSIS'е идёт объявление доступной периферии (GPIOx, SPIx, I2Cx и пр.) и ваш подход предполагает в том или ином виде сделать аналогичное объявление (с помощью частично специализированных шаблонов или перечисления).

Как функции класса могут дублировать возможности CMSIS, если в нем таких функций просто нет? Зато по функционалу твой класс GPIO мало чем отличается от моего, значит и у тебя есть такое дублирование :)

Касательно constexpr... Конечно можно сделать класс с constexpr конструктором и даже будет работать:
Код:
class Gpio
{
public:
   auto base() const { return (GPIO_TypeDef*)gpio; }
   constexpr Gpio(int gpio, uint16_t pinsMask) : gpio(gpio), pinsMask(pinsMask) {}
   void write(uint16_t value) const { base()->BSRR = (pinsMask << 16) | value; }

private:
   int gpio;
   uint16_t pinsMask;
};

   constexpr Gpio g1(GPIOA_BASE, 0x0FF0);
   g1.write(123);

Но нельзя сделать даже банальное
Код:
constexpr auto mask = pinsMask;

Соответственно также нельзя использовать constexpr if и constexpr функции. У меня в либе для F1 есть такой код:
Код:
if constexpr (pinsMask & 0x00FF)
{
    static constexpr uint32_t mask = qmask(pinsMask);
    base()->CRL = base()->CRL & ~mask | (uint32_t(mode) & mask);
}
if constexpr (pinsMask & 0xFF00)
{
    static constexpr uint32_t mask = qmask(pinsMask >> 8);
    base()->CRH = base()->CRH & ~mask | (uint32_t(mode) & mask);
}

Qmask() берет маску пинов и рекурсивно получает из нее четверную маску, причем это гарантированно будет константа времени компиляции, даже для -O0. У тебя в коде в этом месте два цикла, вот у меня без constexpr тоже с -O2 будут циклы, -O3 не всегда, но помогает, только из-за него существенно вырастет размер остального кода. Так что с точки зрения эффективности шаблоны все равно лучше, хотя у constexpr классов преимущество в том, что их можно как обычные параметры передавать...

Re: uVision Keil. Помогите разобраться с компиляторами.

Вт фев 05, 2019 22:15:52

Как функции класса могут дублировать возможности CMSIS, если в нем таких функций просто нет?
Но я и писал, что НЕ имею это в виду)))

Так что с точки зрения эффективности шаблоны все равно лучше, хотя у constexpr классов преимущество в том, что их можно как обычные параметры передавать...
Да я на шаблонах и буду реализовывать по итогу, только с наследованием. Тот код, что я тут выкладывал, был эксперимента ради. В любом случае, спасибо за советы.

PS
Код:
static void set() { base()->BSRR = pinMask; }
static void clear() { base()->BSRR = 0x10000 << pin; } // Почему не base()->BRR = pinMask; ?
Компилятор сам всё посчитает и сведёт выражение в правой части присваивания к константе? Или в этой серии контроллеров банально нет этого регистра? Работал только с F1 и L0.

И ещё один вопрос, весьма наивный, но вдруг) В векторе прерываний на каждое прерывание отводится по 4 байта, ровно под указатель на обычную C функцию. Я правильно понимаю, что вызов метода класса (не статический) туда не впихнуть, ибо он банально не влезет в 4 байта?

Re: uVision Keil. Помогите разобраться с компиляторами.

Вт фев 05, 2019 22:47:29

Компилятор сам всё посчитает и сведёт выражение в правой части присваивания к константе? Или в этой серии контроллеров банально нет этого регистра? Работал только с F1 и L0.

BRR есть не везде, например, нет у F4.

И ещё один вопрос, весьма наивный, но вдруг) В векторе прерываний на каждое прерывание отводится по 4 байта, ровно под указатель на обычную C функцию. Я правильно понимаю, что вызов метода класса (не статический) туда не впихнуть, ибо он банально не влезет в 4 байта?

Не влезет, но даже если бы можно было запихнуть туда 8 байт, мк все равно не смог бы этот адрес правильно обработать.

Re: uVision Keil. Помогите разобраться с компиляторами.

Пт фев 08, 2019 17:23:32

Reflector, а не могли ли бы вы пояснить про используемый вами атрибут "_always_inline_"? Это что-то подобное?
Код:
#define   _always_inline_   __attribute__((always_inline))
Если да, то есть ли какие-то стандарты или общепринятые принципы именования пользовательских атрибутов?

Re: uVision Keil. Помогите разобраться с компиляторами.

Пт фев 08, 2019 17:50:38

Это что-то подобное?

Конкретно у меня оно объявлено как
Код:
#define _inline_ __attribute__((always_inline)) inline

причем обычный inline там тоже нужен, без него местами даже не компилируется...
Про общепринятые принципы именования ничего не скажу, в том же CMSIS есть всякие __STATIC_INLINE, но я такое точно в свои проекты не вставлю :)

Re: uVision Keil. Помогите разобраться с компиляторами.

Сб фев 09, 2019 18:47:38

А есть ли тут люди, использующие связку 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.
В GCC с сайта ARM год исправили на 2018))

Re: uVision Keil. Помогите разобраться с компиляторами.

Вс фев 10, 2019 06:21:48

Помнится мне, CMSIS внутри где-то stdint.h подключает.

Re: uVision Keil. Помогите разобраться с компиляторами.

Вс фев 10, 2019 14:17:08

Это да, но я проверял без подключения CMSIS, пустой cpp файл с приведённым выше кодом.

Re: uVision Keil. Помогите разобраться с компиляторами.

Ср фев 20, 2019 18:34:36

Подскажите еще, где в Кейле включить в Дебаге просмотр собственных переменных? Вроде было такое окно, а сейчас уже все перетыкал, не могу найти.

Добавлено after 2 minutes 45 seconds:
Ой. все, вроде разобрался. Есть там окно симболс. С которого можно отправить переменные из файла мэин.С в окно Вотч. )

Re: uVision Keil. Помогите разобраться с компиляторами.

Пн фев 05, 2024 12:08:14

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.
Изображение А где он изначально объявлялся то, реально нигде не находит.

Re: uVision Keil. Помогите разобраться с компиляторами.

Пн фев 05, 2024 17:38:24

Смотри core_cm3.h В CMSIS 6.0 он как IPR определён.
Ответить