Например TDA7294

Форум РадиоКот • Просмотр темы - uVision Keil. Помогите разобраться с компиляторами.
Форум РадиоКот
Здесь можно немножко помяукать :)





Текущее время: Вт апр 23, 2024 19:43:54

Часовой пояс: UTC + 3 часа


ПРЯМО СЕЙЧАС:



Начать новую тему Ответить на тему  [ Сообщений: 37 ]  1,  
Автор Сообщение
Не в сети
 Заголовок сообщения: uVision Keil. Помогите разобраться с компиляторами.
СообщениеДобавлено: Чт янв 24, 2019 17:00:51 
Первый раз сказал Мяу!

Зарегистрирован: Вт июн 04, 2013 20:25:13
Сообщений: 27
Рейтинг сообщения: 0
Доброго всем дня.
Пишу код под микроконтроллеры STM32 в среде uVision Keil и захотелось плюшек, доступных в стандарте C++11.
Немного погуглив, наткнулся на следующую страницу, в которой для поддержки C++11 рекомендуется использовать компилятор V6.8 или новее (armclang).
http://www.keil.com/support/docs/3696.htm
Вернее в версии 5.05 (armcc) C++11 поддерживается, но динамический анализ синтаксиса будет работать не корректно, что не очень удобно.

До сего момента всегда использовал включенный по умолчанию 5.06 (armcc) и даже не задумывался о том, что компиляторов в Keil'е несколько. Отсюда вытекает мой первый комплект вопросов:
Какие вообще существуют компиляторы для ARM? Я так понимаю, ядро одно, значит и компиляторы одни и теже в пределах одного семейства.
Какие у них преимущества/недостатки?
Почему Keil по умолчанию использует компилятор, который они сами называют устаревшим (по крайней мере для серии STM32F10x)?

Второй вопрос относится к самому Keil'у. У меня стоит версия 5.25.2.0
Попробовал новый компилятор, всё отлично работало до тех пор, пока вся программа находилась в одном файле "main.cpp".
Создал заголовочный файл "MyLib.h", перетащил туда часть кода, однако динамический анализ синтаксиса начал ругаться на всё, что относится к синтаксису C++ (ключевые слова class, namespace и т.д.), а также на новый синтаксис подключения заголовочных файлов типа "#include <cstdint>"
Если переименовать заголовочный файл в "MyLib.hpp", на ключевые слова C++ ругаться перестаёт, но продолжает ругаться на "#include <cstdint>".
Причём, если не обращать внимания на ошибки, всё отлично компилируется, шьётся в контроллер и работает.
Чем объясняется такое странное поведение и как с этим бороться?


Вернуться наверх
 
Не в сети
 Заголовок сообщения: Re: uVision Keil. Помогите разобраться с компиляторами.
СообщениеДобавлено: Чт янв 24, 2019 17:46:28 
Электрический кот
Аватар пользователя

Карма: 4
Рейтинг сообщений: 135
Зарегистрирован: Сб мар 09, 2013 11:29:22
Сообщений: 1020
Откуда: 40RUS, Жуков
Рейтинг сообщения: 0
Зачем темы плодить ? Есть же https://radiokot.ru/forum/viewtopic.php ... 01bb313f44 . АДМИН куда смотришь ?

_________________
IVL ex UA6PJ OSC_F303


Вернуться наверх
 
Не в сети
 Заголовок сообщения: Re: uVision Keil. Помогите разобраться с компиляторами.
СообщениеДобавлено: Чт янв 24, 2019 18:53:04 
Поставщик валерьянки для Кота
Аватар пользователя

Карма: 18
Рейтинг сообщений: 403
Зарегистрирован: Вт май 01, 2018 19:44:47
Сообщений: 2479
Рейтинг сообщения: 0
Satarych, если решил С++ заняться, то выкидывай Keil, его туда толком не завезли. Переходи на что-нибудь на основе GCC, там C++17 отлично работает. Посмотри VisualGDB, например.


Вернуться наверх
 
PCBWay - всего $5 за 10 печатных плат, первый заказ для новых клиентов БЕСПЛАТЕН

Сборка печатных плат от $30 + БЕСПЛАТНАЯ доставка по всему миру + трафарет

Онлайн просмотровщик Gerber-файлов от PCBWay + Услуги 3D печати
Не в сети
 Заголовок сообщения: Re: uVision Keil. Помогите разобраться с компиляторами.
СообщениеДобавлено: Чт янв 24, 2019 18:59:49 
Друг Кота
Аватар пользователя

Карма: 1
Рейтинг сообщений: 157
Зарегистрирован: Пн окт 11, 2010 19:00:08
Сообщений: 3328
Рейтинг сообщения: 0
Satarych писал(а):
Какие вообще существуют компиляторы для ARM?
GCC например. В отличие от компилятора кейла, полностью бесплатный и без ограничений.


Вернуться наверх
 
Выбираем схему BMS для заряда литий-железофосфатных (LiFePO4) аккумуляторов

Обязательным условием долгой и стабильной работы Li-FePO4-аккумуляторов, в том числе и производства EVE Energy, является применение специализированных BMS-микросхем. Литий-железофосфатные АКБ отличаются такими характеристиками, как высокая многократность циклов заряда-разряда, безопасность, возможность быстрой зарядки, устойчивость к буферному режиму работы и приемлемая стоимость. Но для этих АКБ очень важен контроль процесса заряда и разряда для избегания воздействия внешнего зарядного напряжения после достижения 100% заряда. Инженеры КОМПЭЛ подготовили список таких решений от разных производителей.

Подробнее>>
Не в сети
 Заголовок сообщения: Re: uVision Keil. Помогите разобраться с компиляторами.
СообщениеДобавлено: Чт янв 24, 2019 22:38:41 
Опытный кот
Аватар пользователя

Карма: 4
Рейтинг сообщений: 11
Зарегистрирован: Вт окт 23, 2012 13:17:25
Сообщений: 823
Откуда: Киселевск
Рейтинг сообщения: 0
В KEIL можно подключать GCC кому это нужно.

_________________
Инженер R@D

Telegram чат: https://t.me/radiowolf или в поиске приложения @radiowolf. Личка:@cncoxford


Вернуться наверх
 
Новый аккумулятор EVE серии PLM для GSM-трекеров, работающих в жёстких условиях (до -40°С)

Компания EVE выпустила новый аккумулятор серии PLM, сочетающий в себе высокую безопасность, длительный срок службы, широкий температурный диапазон и высокую токоотдачу даже при отрицательной температуре. Эти аккумуляторы поддерживают заряд при температуре от -40/-20°С (сниженным значением тока), безопасны (не воспламеняются и не взрываются) при механическом повреждении (протыкание и сдавливание), устойчивы к вибрации. Они могут применяться как для автотранспорта (трекеры, маячки, сигнализация), так и для промышленных устройств мониторинга, IoT-устройств.

Подробнее>>
Не в сети
 Заголовок сообщения: Re: uVision Keil. Помогите разобраться с компиляторами.
СообщениеДобавлено: Пт янв 25, 2019 20:05:37 
Первый раз сказал Мяу!

Зарегистрирован: Вт июн 04, 2013 20:25:13
Сообщений: 27
Рейтинг сообщения: 0
Зачем темы плодить ? Есть же https://radiokot.ru/forum/viewtopic.php ... 01bb313f44 . АДМИН куда смотришь ?
Я не частый гость на форумах, поэтому не особо знаю как тут устроена кухня. Учитывая, что за сутки админ не высказал никаких претензий, видимо, всё в порядке. К тому же, тема уже за пару сообщений вышла за рамки своего названия.

VladislavS писал(а):
Satarych, если решил С++ заняться, то выкидывай Keil, его туда толком не завезли. Переходи на что-нибудь на основе GCC, там C++17 отлично работает. Посмотри VisualGDB, например.
Вообще на Keil'е сидел только потому, что им пользовался человек, который меня с STM'ками знакомил. Так больше исторически сложилось) Попробовал VS+VisualGDB, вполне неплохо, пока всё нравится. Есть только одно но, у меня другой товарищ на Линуксе сидит и пользуется Эклипсом. Я его тоже попробую, но почитав отзывы, не проникся. Раз уж решился менять IDE, то хотелось бы, чтоб она на Линуксе заводилась, чтоб в одной среде работать. Может кто подскажет ещё мультиплатформенные варианты, кроме Эклипса?


Отвечая на свой второй вопрос:
http://www.keil.com/support/docs/3973.htm
В самом низу они пишут
Цитата:
If user wants C++ code to be evaluated inside a header file, there are two ways. If a cpp file includes the header file, then it will be evaluated as C++. Alternatively, go to the Project dialog and right click on a source group folder. Add the header file as an existing file. Then in the Project dialog, right click on the file. Go to Options for File... => Properties tab => File Type field. Set the type to C++ Source file. User may receive a fatal error message, if DSC is turned on and the file type is not set to C++.
Как по мне, добавлять заголовочники в проект это уже совсем костыли, но вдруг кому пригодится.


Вернуться наверх
 
Не в сети
 Заголовок сообщения: Re: uVision Keil. Помогите разобраться с компиляторами.
СообщениеДобавлено: Пт янв 25, 2019 22:17:09 
Друг Кота
Аватар пользователя

Карма: 1
Рейтинг сообщений: 157
Зарегистрирован: Пн окт 11, 2010 19:00:08
Сообщений: 3328
Рейтинг сообщения: 0
Satarych писал(а):
Раз уж решился менять IDE, то хотелось бы, чтоб она на Линуксе заводилась
Под линукс не так много IDE и почти все они на эклипсе. Посмотрите еще бесплатную IDE EmBitz. Она для винды, но под вайном в линуксе скорее всего будет работать, исключая разве что отладку, потому что нужен доступ к USB, и под вайном не факт что заработает.


Вернуться наверх
 
Не в сети
 Заголовок сообщения: Re: uVision Keil. Помогите разобраться с компиляторами.
СообщениеДобавлено: Сб янв 26, 2019 06:08:16 
Поставщик валерьянки для Кота
Аватар пользователя

Карма: 18
Рейтинг сообщений: 403
Зарегистрирован: Вт май 01, 2018 19:44:47
Сообщений: 2479
Рейтинг сообщения: 0
Может кто подскажет ещё мультиплатформенные варианты, кроме Эклипса?
Ну тогда SES от Segger.


Вернуться наверх
 
Не в сети
 Заголовок сообщения: Re: uVision Keil. Помогите разобраться с компиляторами.
СообщениеДобавлено: Сб янв 26, 2019 09:09:39 
Друг Кота
Аватар пользователя

Карма: 32
Рейтинг сообщений: 482
Зарегистрирован: Сб сен 10, 2011 17:46:25
Сообщений: 3832
Рейтинг сообщения: 0
Keil-ы всякие в Linux под вайном работают - без инсталляции, просто скопированные с виндовс ПК. Для компиляции можно использовать make. Для редактирования и компиляции - продвинутые редакторы типа sublime text/visual studio code. Отладка под вайном пока не работает. Отладку, если нужна редко, можно сделать в виртуальной машине или на ноутбуке с виндовс.
Изображение
з.ы. под линух есть собрат EmBitz - Codeblocks - арм плагин там был вроде.


Вернуться наверх
 
Не в сети
 Заголовок сообщения: Re: uVision Keil. Помогите разобраться с компиляторами.
СообщениеДобавлено: Сб янв 26, 2019 09:57:41 
Поставщик валерьянки для Кота
Аватар пользователя

Карма: 18
Рейтинг сообщений: 403
Зарегистрирован: Вт май 01, 2018 19:44:47
Сообщений: 2479
Рейтинг сообщения: 0
oleg110592, это называется сексом стоя в гамаке.


Вернуться наверх
 
Не в сети
 Заголовок сообщения: Re: uVision Keil. Помогите разобраться с компиляторами.
СообщениеДобавлено: Пн янв 28, 2019 13:58:55 
Друг Кота
Аватар пользователя

Карма: 32
Рейтинг сообщений: 482
Зарегистрирован: Сб сен 10, 2011 17:46:25
Сообщений: 3832
Рейтинг сообщения: 0
для автора: в тему использования Линукс для разработки, свежая статья
Настройка VSCODE под разработку для ARM на примере отладочной платы...
Цитата:
Можно посмотреть стек вызовов, а также просматривать и модифицировать регистры и память, ставить и удалять брейкпойнты, вычислять выражения и всё то же самое, что обычно при отладке можно.

https://habr.com/ru/post/437760/?utm_so ... ign=437760
з.ы. в кубе можно создавать makefile проект, после создания удаляем внутри папку с HAL, вычищаем от HAL файл main.c, немного правим сам make файл и получаем проект с самым свежим CMSIS. Открываем получившуюся папку в VS Code - создаем код, используя фишки современных IDE, и отлаживаем...


Вернуться наверх
 
Не в сети
 Заголовок сообщения: Re: uVision Keil. Помогите разобраться с компиляторами.
СообщениеДобавлено: Пн янв 28, 2019 14:14:08 
Друг Кота
Аватар пользователя

Карма: 30
Рейтинг сообщений: 155
Зарегистрирован: Пн июл 28, 2008 22:12:01
Сообщений: 3604
Рейтинг сообщения: 0
oleg110592, весьма сомнительное рукоблудство, Ставь лучше SES , все работает сразу искарапки ...


Вернуться наверх
 
Не в сети
 Заголовок сообщения: Re: uVision Keil. Помогите разобраться с компиляторами.
СообщениеДобавлено: Пн янв 28, 2019 14:40:07 
Друг Кота
Аватар пользователя

Карма: 32
Рейтинг сообщений: 482
Зарегистрирован: Сб сен 10, 2011 17:46:25
Сообщений: 3832
Рейтинг сообщения: 0
ставил уже давно SES - отличная штука - у меня еще много прошивок stm8 ст-линком, придется еще один дебагер/программатор - итак на столе жмут кабелей с дебагерами в хаб - пылесосить не удобно. На работе на ПК лучше на всяк не ставить (FREE for any non-commercial use).
p/s/ SES вроде на основе кроссплатформенного Crossworks, а он вроде ст-линк поддерживает, за 100уе можно купить, пургену не видать.


Вернуться наверх
 
Не в сети
 Заголовок сообщения: Re: uVision Keil. Помогите разобраться с компиляторами.
СообщениеДобавлено: Вт янв 29, 2019 17:15:22 
Первый раз сказал Мяу!

Зарегистрирован: Вт июн 04, 2013 20:25:13
Сообщений: 27
Рейтинг сообщения: 0
Всем спасибо за советы. Остановился пока на связке VS+VisualGDB.
Появились новые вопросы:

1. При отключённой оптимизации, GCC компилятор генерирует огромное количество лишнего кода (около 70kB Flash и 2,5kB SRAM) из стандартной библиотеки, когда я начинаю использовать наследование. Кажется, что он вообще всю стандартную библиотеку включил в прошивку. Зачем он это делает? Функции strlen, malloc, calloc и др. нигде не используются даже скрыто (или используются, но я чего-то не понимаю?), ведь при включённой оптимизации он от них избавился. Копмилятор Keil'а так себя не вёл. Практической цели вопрос не несёт, просто любопытно.

2. Пол года назад я уже задавал этот вопрос в теме https://radiokot.ru/forum/viewtopic.php?f=59&t=156603
Коротко он формулируется так: "Как заставить компилятор располагать константные экземпляры классов во Flash, а не в оперативке?"
На тот момент я не до конца понимал смысл ответов и ушёл неспешно читать литературу на тему, заполняя дыры в знаниях.
В итоге воспользовался советом andryblack и сделал пустой конструктор со списком инициализации.
Конструктор не пустой, следовательно его нужно вызвать, следовательно экземпляр нельзя разместить в rom, он размещается в ram и генерируется вызов конструктора на этапе инициализации. Замените присвоение в конструкторе на список инициализации.
И этот вариант меня полностью удовлетворил, компилятор Keil'a (ArmClang) константные экземпляры классов помещал во Flash. В этот раз я это определил однозначно, посмотрев в отладчике адреса объектов, у константного - 0x0800039C, у не константного - 0x20000000.

Однако компилятору GCC этого не достаточно. Он и константные, и неконстантные экземпляры классов пихает в оперативку.
Более того, если я просто объявлю глобальную константу, в отладчике её адрес недоступен (пишет Attempt to take address of register or constant). Окей, возможно её порезала оптимизация, добавляю ей атрибут volatile - компилятор пихает её в оперативку. Я явно чего-то не понимаю. Может нужно как-то явно указывать в какую область памяти я хочу определить переменную?


Вернуться наверх
 
Не в сети
 Заголовок сообщения: Re: uVision Keil. Помогите разобраться с компиляторами.
СообщениеДобавлено: Вт янв 29, 2019 17:36:40 
Поставщик валерьянки для Кота
Аватар пользователя

Карма: 18
Рейтинг сообщений: 403
Зарегистрирован: Вт май 01, 2018 19:44:47
Сообщений: 2479
Рейтинг сообщения: 0
Практической цели вопрос не несёт, просто любопытно.
Удовлетворить своё любопытство можешь прочитав map-файл.

Может нужно как-то явно указывать в какую область памяти я хочу определить переменную?
Для начало надо определиться, константа это или переменная. В принципе, под простую константу может и не выделяться память, если она где-то в простой формуле или пересылке используется - компилятор просто подставит её в код где надо.


Вернуться наверх
 
Не в сети
 Заголовок сообщения: Re: uVision Keil. Помогите разобраться с компиляторами.
СообщениеДобавлено: Сб фев 02, 2019 22:11:32 
Первый раз сказал Мяу!

Зарегистрирован: Вт июн 04, 2013 20:25:13
Сообщений: 27
Рейтинг сообщения: 0
Удовлетворить своё любопытство можешь прочитав map-файл.
Открыл блокнотом, посмотрел, но не могу похвастаться пониманием его содержимого)) О каких-то вещах догадываюсь, но это нельзя назвать пониманием.

Для начало надо определиться, константа это или переменная. В принципе, под простую константу может и не выделяться память, если она где-то в простой формуле или пересылке используется - компилятор просто подставит её в код где надо.
Могу немного косячить с терминами, ибо не программист по образованию, а так, самоучка. В моём понимании переменная - область памяти, в которой хранится число. Соответственно, константа - переменная, значение которой запрещено менять. Следующим код должен пояснить, что я имел ввиду:
Спойлер
Код:
 // Возможные режимы работы Gpio в Stm32f10x
enum class Stm32GpioMode
{
   // Inputs
   Analog_Inp           = 0x0,    //   0b0000
   Floating_Inp         = 0x4,    //   0b0100
   Pull_Dn_Inp         = 0x08,    // 0b01000
   Pull_Up_Inp         = 0x18,    // 0b11000
   // Output 10MHz
   GP_PP_10MHzOut      = 0x1,    //   0b0001
   GP_OD_10MHzOut      = 0x5,    //   0b0101
   AF_PP_10MHzOut      = 0x9,    //   0b1001
   AF_OD_10MHzOut      = 0xD,    //   0b1101
   //   Outputs 2MHz
   GP_PP_2MHzOut      = 0x2,    //   0b0010
   GP_OD_2MHzOut      = 0x6,    //   0b0110
   AF_PP_2MHzOut      = 0xA,    //   0b1010
   AF_OD_2MHzOut      = 0xE,    //   0b1110
   //   Outputs 50MHz
   GP_PP_50MHzOut      = 0x3,    //   0b0011
   GP_OD_50MHzOut      = 0x7,    //   0b0111
   AF_PP_50MHzOut      = 0xB,    //   0b1011
   AF_OD_50MHzOut      = 0xF,    //   0b1111
   //   Исходное состояние выхода
   log0_InitOut      = 0x00,    // 0b00000
   log1_InitOut      = 0x10   // 0b10000
};

class Stm32Gpio
{
public:
   Stm32Gpio() = delete;
   Stm32Gpio(GPIO_TypeDef *const gpio, const uint16_t pinMask);

   void   init(Stm32GpioMode gpioMode) const;    // Функция настройки (инициализации) пинов GPIO
   void   set() const;                  // Функция включения ножки на лог "1"
   void   clr() const;                  // Функция выключения ножки на лог "0"
   void   tgl() const;                  // Функция изменяет состояние ножки на противоположное
   bool   get() const;                  // Функция возвращает текущее состояние ножек

   private :
   GPIO_TypeDef *const m_gpio;
   const uint16_t      m_pinMask;
};

// Конструктор
Stm32Gpio::Stm32Gpio(GPIO_TypeDef *const gpio, const uint16_t pinMask)
   : m_gpio (gpio), m_pinMask (pinMask)   {}


// Функция настройки (инициализации) ножек порта GPIO
void Stm32Gpio::init(Stm32GpioMode gpioMode) const
{
   // Включаем тактирование порта
   //using namespace stm32Rcc_Ns;
   //coreRcc.enableHardwareClock (m_gpio);
   
   // !NOTE! Временная затычка, пока не починю верхние 2 строки
   if (m_gpio == GPIOA)   RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
   if (m_gpio == GPIOB)   RCC->APB2ENR |= RCC_APB2ENR_IOPBEN;
   if (m_gpio == GPIOC)   RCC->APB2ENR |= RCC_APB2ENR_IOPCEN;
   if (m_gpio == GPIOD)   RCC->APB2ENR |= RCC_APB2ENR_IOPDEN;
   if (m_gpio == GPIOE)   RCC->APB2ENR |= RCC_APB2ENR_IOPEEN;
   //if (m_gpio == GPIOF)   RCC->APB2ENR |= RCC_APB2ENR_IOPFEN;
   //if (m_gpio == GPIOG)   RCC->APB2ENR |= RCC_APB2ENR_IOPGEN;
   
   // 5-й бит аргумента gpioMode содержит исходное состояние ножек
   // Если там лог "1" - инициализируем на лог "1"
   if((uint32_t)gpioMode & 0x10)
      m_gpio->BSRR = m_pinMask;
   // Иначе, если лог "0" - инициализируем на лог "0"
   else
      m_gpio->BRR  = m_pinMask;
   // Стираем 5-й бит в аргументе pinMode
   gpioMode = (Stm32GpioMode)((uint32_t)gpioMode & 0xF);
   
   // Перебираем первые 8 ножек
   for(uint8_t pinNum = 0 ; pinNum < 8 ; ++pinNum)
   {
      // Если нужно настроить данную ножку
      if(m_pinMask & (0x1 << pinNum))
      {
         // Настройки каждой ножки занимают по 4 бита в регистре
         // Преобразуем номер ножки в необходимое смещение в регистре
         // Зачищаем редактируемую часть регистра
         m_gpio->CRL &= ~(0xF << (pinNum * 4));
         // Выставляем нужный режим работы ножки
         m_gpio->CRL |= ((uint32_t)gpioMode << (pinNum * 4));
      }
   }

   // Перебираем последние 8 ножек
   for(uint8_t pinNum = 0 ; pinNum < 8 ; ++pinNum)
   {
      // Если нужно настроить данную ножку
      if(m_pinMask & (0x1 << (pinNum + 8)))
      {
         // Настройки каждой ножки занимают по 4 бита в регистре
         // Преобразуем номер ножки в необходимое смещение в регистре
         // Зачищаем редактируемую часть регистра
         m_gpio->CRH &= ~(0xF << (pinNum * 4));
         // Выставляем нужный режим работы пина
         m_gpio->CRH |= ((uint32_t)gpioMode << (pinNum * 4));
      }
   }
}

// Функция включения ножки на лог "1"
void Stm32Gpio::set() const
{
   m_gpio->BSRR = m_pinMask;
}

// Функция выключения ножки на лог "0"
void Stm32Gpio::clr() const
{
   m_gpio->BRR = m_pinMask;
}

// Функция изменяет состояние ножки на противоположное
void Stm32Gpio::tgl() const
{
   m_gpio->ODR ^= m_pinMask;
}

// Функция возвращает текущее состояние ножек
bool Stm32Gpio::get() const
{
   return m_gpio->IDR & m_pinMask;
}
Создаём 2 глобальных объекта (ножки, на которых висят светодиоды) и используем их в main
Спойлер
Код:
const Stm32Gpio led0 (GPIOA, 1<<8);
const Stm32Gpio led1 (GPIOD, 1<<2);

int main()
{
   led0.init (Stm32GpioMode::GP_PP_2MHzOut);
   led1.init (Stm32GpioMode::GP_PP_2MHzOut);
   
   for (;;)
   {
      led0.clr();
      led1.set();
      Delay();
      led0.set();
      led1.clr();
      Delay();
   }
}
Всё работает, НО оба объекта в оперативке, причём компилятор суёт их в область ".bss". Тоесть при старте контроллера переменные объекта содержат нули, вызываются конструкторы объектов и переменные заполняют нужными значениями. Хотя конструктор пустой и все значения переменных доступны компилятору в списке инициализации. Почему компилятор не может сразу расположить этот объект в той части Flash памяти, из которой он будет их копировать в конструкторе?

На дурака решил провести следующий эксперимент:
Спойлер
Код:
// Описываем структуру, идентичную нашему классу по содержанию переменных
struct GpioStruct
{
   GPIO_TypeDef *m_gpio;
   uint16_t m_pinMask;
};

// Создаём её глобальный константный экземпляр
const GpioStruct led1 = {GPIOD, 1<<2};

// Довольно варварски преобразуем тип и подсовываем вместо исходного класса
int main()
{
   led0.init(Stm32GpioMode::GP_PP_2MHzOut);
   ((const Stm32Gpio*)&led1)->init(Stm32GpioMode::GP_PP_2MHzOut);
   
   for (;;)
   {
      led0.clr();
      ((const Stm32Gpio*)&led1)->set();
      Delay();
      led0.set();
      ((const Stm32Gpio*)&led1)->clr();
      Delay();
   }
}
Понятно, что это дичайший костыль и нормальные люди так делать не будут, но в данном случае led1 уже находится во Flash и оно работает.


Вернуться наверх
 
Не в сети
 Заголовок сообщения: Re: uVision Keil. Помогите разобраться с компиляторами.
СообщениеДобавлено: Сб фев 02, 2019 22:58:34 
Поставщик валерьянки для Кота

Карма: 20
Рейтинг сообщений: 253
Зарегистрирован: Вс июн 19, 2016 09:32:03
Сообщений: 2090
Рейтинг сообщения: 0
Почему компилятор не может сразу расположить этот объект в той части Flash памяти, из которой он будет их копировать в конструкторе?

Я тебе уже в старой теме писал, что класс с приватными полями или конструкторами не является POD и такие объекты нельзя копировать к конструкторе. Чтоб было понятнее, в структуре фиксированный порядок полей, но если в классе есть публичные и приватные поля, то внутри них порядок фиксированный, но сами эти группы могут идти в том порядке, какой компилятор сочтет более подходящим. Это во-первых, а во-вторых, и я тоже об этом уже писал, если хочешь добиться максимальной эффективности, то нужно
использовать шаблоны, тогда будут одни константы которые, естественно, попадут во флеш, если не напрямую в регистры.
Спойлер
Код:
template<uint32_t gpioBase, uint32_t pin, uint32_t af>
class PinT
{
public:
   static constexpr uint32_t pinMask = 1 << pin;
   static _always_inline_ auto base() { return reinterpret_cast<GPIO_TypeDef*>(gpioBase); }

   PinT() {}
   PinT(PinMode mode) { ... }

   static void set() { base()->BSRR = pinMask; }
   static void clear() { base()->BSRR = 0x10000 << pin; }
   static void toggle() { base()->BSRR = (0x10000 << pin) | (~base()->ODR & pinMask); }
   static void write(bool data) { base()->BSRR = (0x10000 | data) << pin; }
   static bool read() { return base()->IDR & pinMask; }
};

template<uint32_t pin, uint32_t af = 0>
using PinA = PinT<GPIOA_BASE, pin, af>;

template<uint32_t pin, uint32_t af = 0>
using PinB = PinT<GPIOB_BASE, pin, af>;

PinA<5> led1;
using led2 = PinB<3>;

led1.set();
led2::toggle();


Добавлено after 16 minutes 52 seconds:
Код:
// Функция изменяет состояние ножки на противоположное
void Stm32Gpio::tgl() const
{
   m_gpio->ODR ^= m_pinMask;
}

Распространенная ошибка. В регистр читается значение ODR, потом вызывается прерывание или переключается задача и там что-то пишется в тот же порт, по возвращению в ODR сохраняется старое значение с измененным битом...


Вернуться наверх
 
Не в сети
 Заголовок сообщения: Re: uVision Keil. Помогите разобраться с компиляторами.
СообщениеДобавлено: Вс фев 03, 2019 14:10:07 
Первый раз сказал Мяу!

Зарегистрирован: Вт июн 04, 2013 20:25:13
Сообщений: 27
Рейтинг сообщения: 0
Начну с простого
Код:
// Функция изменяет состояние ножки на противоположное
void Stm32Gpio::tgl() const
{
   m_gpio->ODR ^= m_pinMask;
}
Распространенная ошибка. В регистр читается значение ODR, потом вызывается прерывание или переключается задача и там что-то пишется в тот же порт, по возвращению в ODR сохраняется старое значение с измененным битом...
Да, согласен. Мигрировало из интернетных примеров, когда только осваивал STM'ки. По факту никогда не натыкался на подобное только потому, что обычно использовал отдельные set() и clr(). Посему и не замечал, но да, поправить нужно.

Я тебе уже в старой теме писал, что класс с приватными полями или конструкторами не является POD и такие объекты нельзя копировать к конструкторе. Чтоб было понятнее, в структуре фиксированный порядок полей, но если в классе есть публичные и приватные поля, то внутри них порядок фиксированный, но сами эти группы могут идти в том порядке, какой компилятор сочтет более подходящим. Это во-первых, а во-вторых, и я тоже об этом уже писал, если хочешь добиться максимальной эффективности, то нужно использовать шаблоны, тогда будут одни константы которые, естественно, попадут во флеш, если не напрямую в регистры.
Не спорю насчёт эффективности, в этом отношении вариант с шаблонами определённо лучше. Минус пара тактов на чтение из переменных, а то и вообще минус вызов функции, если оптимизатор её встроит, это всё понятно, но вопрос не в этом. Для реализации этого варианта не обязательно сводить класс к POD. В частности, я хочу использовать виртуальные функции (зачем - отдельная тема), а это добавляет в класс указатель на таблицу виртуальных функций __vptr, тоесть класс с виртуальными функциями автоматически не будет являться POD. Итого - каждый объект за зря будет занимать по 4 байта в оперативке.

Как я писал выше, воспользовался советом andryblack
Конструктор не пустой, следовательно его нужно вызвать, следовательно экземпляр нельзя разместить в rom, он размещается в ram и генерируется вызов конструктора на этапе инициализации. Замените присвоение в конструкторе на список инициализации.
и это решило проблему в Keil'е, его компилятор сразу размещал константные экземпляры класса во Flash, используя значения, предоставленные в списке инициализации. Если бы не этот факт, забил бы. А т.к. компилятор Keil'а умеет так делать, значит технических препятствий нет. Значит ключ к решению проблемы кроется в gcc компиляторе, либо он так делать не умеет, либо просто я не знаю как его об этом попросить.

Насчёт шаблонов. Я пробовал их использовать, но, видимо, до конца в них не разобрался.
Спойлер
Код:
template <GPIO_TypeDef *m_gpio, uint16_t m_pinMask>
class Stm32Gpio
{
public:
   void         init(Stm32GpioMode gpioMode) const;    // Функция настройки (инициализации) пинов GPIO
   virtual void   set() const;                 // Функция включения ножки на лог "1"
   virtual void   clr() const;                 // Функция выключения ножки на лог "0"
   virtual void   tgl() const;                 // Функция изменяет состояние ножки на противоположное
   virtual bool   get() const;                 // Функция возвращает текущее состояние ножек
};


// Функция настройки (инициализации) ножек порта GPIO
template <GPIO_TypeDef *m_gpio, uint16_t m_pinMask>
void Stm32Gpio <m_gpio, m_pinMask>::init(Stm32GpioMode gpioMode) const
{
   // Включаем тактирование порта
   //using namespace stm32Rcc_Ns;
   //coreRcc.enableHardwareClock (m_gpio);
   
   // !NOTE! Временная затычка, пока не починю верхние 2 строки
   if (m_gpio == GPIOA)   RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
   if (m_gpio == GPIOB)   RCC->APB2ENR |= RCC_APB2ENR_IOPBEN;
   if (m_gpio == GPIOC)   RCC->APB2ENR |= RCC_APB2ENR_IOPCEN;
   if (m_gpio == GPIOD)   RCC->APB2ENR |= RCC_APB2ENR_IOPDEN;
   if (m_gpio == GPIOE)   RCC->APB2ENR |= RCC_APB2ENR_IOPEEN;
   //if (m_gpio == GPIOF)   RCC->APB2ENR |= RCC_APB2ENR_IOPFEN;
   //if (m_gpio == GPIOG)   RCC->APB2ENR |= RCC_APB2ENR_IOPGEN;
   
   // 5-й бит аргумента gpioMode содержит исходное состояние ножек
   // Если там лог "1" - инициализируем на лог "1"
   if((uint32_t)gpioMode & 0x10)
      m_gpio->BSRR = m_pinMask;
   // Иначе, если лог "0" - инициализируем на лог "0"
   else
      m_gpio->BRR  = m_pinMask;
   // Стираем 5-й бит в аргументе pinMode
   gpioMode = (Stm32GpioMode)((uint32_t)gpioMode & 0xF);
   
   // Перебираем первые 8 ножек
   for(uint8_t pinNum = 0 ; pinNum < 8 ; ++pinNum)
   {
      // Если нужно настроить данную ножку
      if(m_pinMask & (0x1 << pinNum))
      {
         // Настройки каждой ножки занимают по 4 бита в регистре
         // Преобразуем номер ножки в необходимое смещение в регистре
         // Зачищаем редактируемую часть регистра
         m_gpio->CRL &= ~(0xF << (pinNum * 4));
         // Выставляем нужный режим работы ножки
         m_gpio->CRL |= ((uint32_t)gpioMode << (pinNum * 4));
      }
   }

   // Перебираем последние 8 ножек
   for(uint8_t pinNum = 0 ; pinNum < 8 ; ++pinNum)
   {
      // Если нужно настроить данную ножку
      if(m_pinMask & (0x1 << (pinNum + 8)))
      {
         // Настройки каждой ножки занимают по 4 бита в регистре
         // Преобразуем номер ножки в необходимое смещение в регистре
         // Зачищаем редактируемую часть регистра
         m_gpio->CRH &= ~(0xF << (pinNum * 4));
         // Выставляем нужный режим работы пина
         m_gpio->CRH |= ((uint32_t)gpioMode << (pinNum * 4));
      }
   }
}

// Функция включения ножки на лог "1"
template <GPIO_TypeDef *m_gpio, uint16_t m_pinMask>
void Stm32Gpio <m_gpio, m_pinMask>::set() const
{
   m_gpio->BSRR = m_pinMask;
}

// Функция выключения ножки на лог "0"
template <GPIO_TypeDef *m_gpio, uint16_t m_pinMask>
void Stm32Gpio <m_gpio, m_pinMask>::clr() const
{
   m_gpio->BRR = m_pinMask;
}

// Функция изменяет состояние ножки на противоположное
template <GPIO_TypeDef *m_gpio, uint16_t m_pinMask>
void Stm32Gpio <m_gpio, m_pinMask>::tgl() const
{
   m_gpio->ODR ^= m_pinMask;
}

// Функция возвращает текущее состояние ножек
template <GPIO_TypeDef *m_gpio, uint16_t m_pinMask>
bool Stm32Gpio <m_gpio, m_pinMask>::Stm32Gpio::get() const
{
   return m_gpio->IDR & m_pinMask;
}
Keil это всё компилировал, но контроллер по факту вываливался в Hard Fault. Gcc выдавал ошибку следующего содержания, когда я пытался создать объекты
Код:
Stm32Gpio <GPIOD, 1<<2> led1;
'(GPIO_TypeDef*)((1073741824 + 65536) + 5120)' is not a valid template argument for 'GPIO_TypeDef*' because it is not the address of a variable
Благодаря вашему примеру, кажется понял что именно было не так. Видимо, пользовательский тип не может быть non-type параметром. Нужно мне побольше почитать про non-type параметры.


Вернуться наверх
 
Не в сети
 Заголовок сообщения: Re: uVision Keil. Помогите разобраться с компиляторами.
СообщениеДобавлено: Вс фев 03, 2019 14:23:54 
Друг Кота
Аватар пользователя

Карма: 1
Рейтинг сообщений: 157
Зарегистрирован: Пн окт 11, 2010 19:00:08
Сообщений: 3328
Рейтинг сообщения: 0
Satarych писал(а):
нормальные люди так делать не будут
Почему? Массив структур имеет смысл. Лучше чем множество дефайнов и код короче и понятней.


Вернуться наверх
 
Не в сети
 Заголовок сообщения: Re: uVision Keil. Помогите разобраться с компиляторами.
СообщениеДобавлено: Вс фев 03, 2019 14:38:55 
Первый раз сказал Мяу!

Зарегистрирован: Вт июн 04, 2013 20:25:13
Сообщений: 27
Рейтинг сообщения: 0
Satarych писал(а):
нормальные люди так делать не будут
Почему? Массив структур имеет смысл. Лучше чем множество дефайнов и код короче и понятней.
Я тут больше имел ввиду преобразование структуры в класс.
Во первых, в реальности мне в эту структуру нужно ещё как-то добавить __vptr.
Во вторых, как сказал Reflector, компилятор может приватные и публичные поля располагать в том порядке, какой ему больше понравится. Можно и не угадать)) Опасно так нагло преобразовывать типы.


Вернуться наверх
 
Показать сообщения за:  Сортировать по:  Вернуться наверх
Начать новую тему Ответить на тему  [ Сообщений: 37 ]  1,  

Часовой пояс: UTC + 3 часа


Кто сейчас на форуме

Сейчас этот форум просматривают: mab72 и гости: 31


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Перейти:  


Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
Русская поддержка phpBB
Extended by Karma MOD © 2007—2012 m157y
Extended by Topic Tags MOD © 2012 m157y