b707, ну с прерываниями оно, наверное, так и должно быть. Но можно и без прерываний тоже самое сделать. Один таймер "мастер" считает некоторое кол-тактов разрешая в это время работу другому, а потом некоторое кол-во запрещая. Другой просто генерит 1МГц, подчиняясь указанием "мастера" когда можно генерить, когда нельзя. Пример, тут 10 микросекунд разрешено и 5 запрещено. На осцилле аккуратные пачки по 10 импульсов.
Попробовал, все отлично, четкие пачки по 138 импульсов. Отмечу только важные нюансы в верхнем коде:
- для точной синхронизации слейв должен запускаться до Мастера (строчки 15 и 16 нужно поменять местами)
- значение регистра сранения задется точно, а не N-1, в отличии от прескалера или ARR. В данном случае это важно. так как разница в единицу дает рассинхронизацию мастера и слейва, которая накапливается от цикла к циклу, меняя фазу сигнала
Когда это поправил - все работает очень четко, число импульсов строго одинаковое, все задержки стабильные.
Но проблемы еще остались. По ходу программы мне нужно эту связку таймеров включать и выключать. Если просто выключить мастер таймер, а потом запустить заново, обнулив при старте счетчики мастера и слейва - в первой пачке будет 141 импульс. Не знаю почему так, но видимо придется при каждом рестарте таймера конфигурировать все регистры заново.
b707, а можно и на одном таймере и ДМА. Таймер тактирует ДМА, а тот кидает ему в регистр CCR каждый раз новое значение, задающее скважность. Когда сигнал не нужен даём нулевую скважность. В итоге имеем ровные пачки импульсов:
Вопрос - а почему у меня упорно засело в голове, что сконфигурировать ДМА-перенос из памяти в GPIO можно только на таймере1 ? - сиху читаю даташит, не вижу таких ограничений
добавка - запустил на таймере3 - все отлично работает. Еще раз спасибо dimax за пример.
Все-таки не понятно, почему "в интернетах" упорно натыкаюсь на сообщения, что работать с GPIO можно тактируя ДМА исключительно первым таймерм?
нормально работает(мигает лампочкой), пока размер куска отведенной динамической памяти не превышает примерно 61-62к, потом виснет, что вполне согласуется с заявленным обьемом RAM 64к
Пытаюсь запустить готовый проект, работающий на F103 - на MK F401.
1 malloc() не работает. Попытки выделить функцией malloc() динамическую область памяти более чем 50-100 байт - терпят неудачу. Причем сама функция, как водится, ошибок не вызывает - но попытки обращения к выделенной памяти приводят к зависанию программы. При этом статически можно выделить память практически любого размера вплоть до полного размера RAM.
2. функция pinMode() не работает в конструкторе глобального обьекта, при этом в setup() и в основной программе работает. Возможно, причина в том, что в конструкторе еще "слишком рано" и инициализация портов GPIO не закончена, а к сетапу она завершается. Пробовал вставлять свою инициализацию шины и GPIO порта до первого pinMode() - не помогло.
это не считая несовместимости по регистрам BRR и BSRR, которую я легко обошел.
2. функция pinMode() не работает в конструкторе глобального обьекта, при этом в setup() и в основной программе работает. Возможно, причина в том, что в конструкторе еще "слишком рано" и инициализация портов GPIO не закончена, а к сетапу она завершается.
Именно.
Собственно, не "не закончена", а "еще не начиналась". По стандарту сначала происходит инициализация всех глобальных переменных, и только потом - выполняется первый исполняемый оператор программы, в данном случае - блока инициализации железа.
Поэтому инициализацию железа в Ардуино принято производить не в конструкторе, а в специальном методе init() или setup().
PS. Кстати, malloc() часом вызывается не из конструктора?
По стандарту сначала происходит инициализация всех глобальных переменных, и только потом - выполняется первый исполняемый оператор программы, в данном случае - блока инициализации железа.
Нет. Порядок запуска программы полностью под контролем программиста. Ничто не мешает написать что угодно перед "call static constructors"
/* Call the clock system initialization function.*/
bl SystemInit
/* Call static constructors */
bl __libc_init_array
/* Call the application's entry point.*/
bl main
bx lr
Собственно, не "не закончена", а "еще не начиналась". По стандарту сначала происходит инициализация всех глобальных переменных, и только потом - выполняется первый исполняемый оператор программы, в данном случае - блока инициализации железа.
Поэтому инициализацию железа в Ардуино принято производить не в конструкторе, а в специальном методе init() или setup().
как ни странно, на F103 внутри конструктора pinMode() отрабатывает нормально
Мне, конечно, нетрудно всю инициализацию железа перетащить в class.init() - но хотелось бы понять, почему и на ардуино Нано/Мега. и на обычном блюпилле это все работало и в конструкторе, а в F401 нет
Цитата:
PS. Кстати, malloc() часом вызывается не из конструктора?
Для тех, кто в танке: в Ардуино используется язык программирования С++, и речь в данном контексте шла именно о нем.
в Ардуино используется ядро, написанное программистом, и содержащее такой фрагмент кода. Если бы программист напряг мозги, он бы настроил ядро правильно.
сорри, но видимо я до этого еще не дорос... Единственное, что мне пришло в голову - сравнить этот файл из ветки STM32F4 с аналогичным для STM32F1, чтобы попытаться понять, почему проблема с инициализацией возникает только в STM32F4.
Но в ветке STM32F1 аналогичного файла вообще нет... или этот код где-то еще, или как-то обходятся без указания порядка инициализации...
Для тех, кто в танке: в Ардуино используется язык программирования С++, и речь в данном контексте шла именно о нем.
в Ардуино используется ядро, написанное программистом, и содержащее такой фрагмент кода. Если бы программист напряг мозги, он бы настроил ядро правильно.
В Ардуино не используется ядро, в Ардуино используется концепция, т.к. Ардуино - это не конкретный МК, а система, позволяющая единообразно подходить к программированию разных МК, существенно различающихся по своим свойствам.
Да и вообще, квалификация любого специалиста определяется умением пользоваться имеющимся инструментом, а не умением настроить молоток так, чтобы им можно было заворачивать шурупы.
Я, смотрите, старательно вас развожу, задаю каждому вопрос отдельно :) Ответьте лучше мне про malloc() в конструкторе...
Ну, стартовая настройка МК предполагает помимо инициализации периферии также настройку стека, кучи и пр. Опять же, при инициализации аппаратуры, как правило, возникает необходимость в выделении памяти. А выделение памяти стандартным образом из кучи сопровождается накладными расходами. Почему бы, скажем, не зафиксировать буфер Serial по стандартному адресу в обход менеджера кучи?
В общем, нужно либо разбираться с тонкостями реализации, а они, эти тонкости, могут существенно различаться для разных камней (хотя бы потому, что авторы кода - разные), либо попытаться выработать общие подходы, которые будут работать независимо от того, как реализовал блок инициализации тот или иной автор. Отказ от инициализации и распределения памяти в конструкторе и применение вместо этого явные методы инициализации (init или setup) я рассматриваю в качестве таких подходов. Потому как считаю, что следует выбирать камень под задачу, а задачи у меня бывают ох какими разными. Следовательно, детальное изучение особенностей реализации блока инициализации для каждого конкретного камня, на мой взгляд, непроизводительная трата времени.
Например на stm я написал программу, которая распечатывает мне содержимое регистров включенных устройств - и этой информации мне достаточно, чтобы потом перестраивать режимы работы под себя. А разбираться, когда именно и в какой последовательности эта инициализация была проведена - мне не интересно.
сорри, но видимо я до этого еще не дорос... Единственное, что мне пришло в голову - сравнить этот файл из ветки STM32F4 с аналогичным для STM32F1, чтобы попытаться понять, почему проблема с инициализацией возникает только в STM32F4.
Но в ветке STM32F1 аналогичного файла вообще нет... или этот код где-то еще, или как-то обходятся без указания порядка инициализации...
Надо детально смотреть весь код. Это много где может быть реализовано, на самом деле. Я просто привел пример того, что можно элементарно выполнять код до инициализации глобальных переменных.
Все-таки не понятно, почему "в интернетах" упорно натыкаюсь на сообщения, что работать с GPIO можно тактируя ДМА исключительно первым таймерм?
Патамушта в тырнетах тупо копировали у друг друга... без малейшего понимания... что к чему...
Смотреть надо референс... а не даташит... Там есть таблица эвентов для ДМА...
И кстати... Там хоть и написано... что можно юзать только один эвент на канал... но на самом деле... если эвенты синхронизированы и не одновременны... то можно юзать и несколько... если это нужно и соответствует задаче...
И ещё... из того что ещё помню... В Ф4хх... два модуля ДМА... один из них не работает с ЖПИО по определению...
Серия 32Ж тоже не работает по ДМА с ЖПИО... от рождения своего...
+++++++++
И да... ДМА не тактируется таймером... он получает эвенты от таймера...
Такой вопросик - отладку в каком-нибудь из аддонов есть возможность использовать? Ну там расставить точки останова, посмотреть значения переменных во время выполнения?
Понятно, что не в Ардуино ИДЕ, а например в V-Micro ?
В родном STMовском отлаживает. А мне больше нравиться в IAR. Там вообще всё можно смотреть и менять на любом шаге.
вчера весь вечер протрахался с этим, в V-micro c кларковским аддоном так и не смог запустить... То OpenOCD сервер не запускается, пишет "неверные аргументы", Как ни искал - не нашел, где эти аргументы менять...
Потом вообще Ст-линк перестал определяться, насилу вылечил...
Возможно дело не в аддоне и не в Микро, а в том что у меня винда уже слишком замусорена... Например, у меня два компа, на одном СТ-линк работает, а на другом вообще никак
(обратите внимание, что этот конфиг только для комбинации stm32F103C8 + St-link-v2, под другой МК и другой программатор нужно подбирать конфиг отдельно)
Единственное, что осталось не до конца понятным - после загрузки скетча и запуска отладчика обязательно нужно вручную нажать ресет на плате, иначе отладка не стартует. Кто пользуется отладкой в Вмикро - поделитесь, у вас тоже так? Может есть какой-то способ заставить плату перегружаться автоматом?
И еще - некоторые переменные в Watch посмотреть нельзя - пишет "optimezed out". Правильно ли я понял, что это означает что переменная выкинута оптимизатором как неиспользуемая? - странно, я думал в дебаг-режиме всякая оптимизация отключается...
И еще - некоторые переменные в Watch посмотреть нельзя - пишет "optimezed out". Правильно ли я понял, что это означает что переменная выкинута оптимизатором как неиспользуемая? - странно, я думал в дебаг-режиме всякая оптимизация отключается...
1. Переменная выкинута только из памяти, т.е. на нее не распределяется место в стеке/куче. Вместо этого переменная хранится в регистрах и, соответственно, не имеет адреса.
2. Вообще-то режим отладки подразумевает помещение в код дополнительной информации, а не отключение оптимизации. Возможно, это вещи в какой-то степени связанные, но точно не эквивалентные.
Да, насчет переменных уже разобрался, "optimized out" означает, что переменная относится к другому блоку программы и в этом недоступна. Сейчас столкнулся с другой проблемой - в режиме отладки выполнение программы происходит в сотни, а то и в тысячи раз медленнее, чем в релизе, реально просто не могу дойти до места, которое нужно отлаживать. О том, чтобы запускать отладку на том же коде, что и релиз - нечего и думать, приходится убирать все лишнее, сокращать циклы, выкидывать задержки и миллис.
Понимаю, что так быть не должно... пытаюсь найти причину.
На этот случай в отладчиках есть точка останова. До неё обычно в режиме отладки программа добирается с нормальной скоростью.
почему-то не работает. (вообще я знаю, что такое точки останова, это не первый мой дебаг, если что :)
Я уже все прерывания остановил - все равно . "Продолжить до сдедующей точки останова" - идет со скоростью примерно 10-20 ассемблерных инструкций в секунду. то есть очень медленно. Если идти по шагам - скорость нормальная, если не считать того, что каждую строчку пройти надо вручную.
Нашел описание этого бага в инете в паре мест, решения там нет
Для информации - в настройках аддона в режиме Debug стоит какая-то странная опция компилятора -Og
В мане GCC я такой опции не нашел, написано только, что опции оптимизации -Ox можно комбинировать с опциями дебага -gx. но что означает комбинация -Og - не написано.
В итоге поменял эту непонятную опцию на комбинацию -O0 -g3 -ggdb и все поехало.
Возможно опция -g3 избыточна в моем случае, но пока размер прошивки не превышает флеша МК - это не особо важно.
Optimize debugging experience. -Og should be the optimization level of choice for the standard edit-compile-debug cycle, offering a reasonable level of optimization while maintaining fast compilation and a good debugging experience. It is a better choice than -O0 for producing debuggable code because some compiler passes that collect debug information are disabled at -O0.
Like -O0, -Og completely disables a number of optimization passes so that individual options controlling them have no effect. Otherwise -Og enables all -O1 optimization flags except for those that may interfere with debugging:
продолжаю разбираться с F401 в аддоне Кларка. Хочется понять, почему при попытке выделить даже минимальный блок памяти с помощью malloc() все виснет?
Есть те, кто понимает в ld скриптах? Вот скрипт от F401 из аддона Кларка:
/*
* Linker script for libmaple.
*
* Original author "lanchon" from ST forums, with modifications by LeafLabs.
*/
OUTPUT_FORMAT ("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
/*
* Configure other libraries we want in the link.
*
* libgcc, libc, and libm are common across supported toolchains.
* However, some toolchains require additional archives which aren't
* present everywhere (e.g. ARM's gcc-arm-embedded releases).
*
* To hack around this, we let the build system specify additional
* archives by putting the right extra_libs.inc (in a directory under
* toolchains/) in our search path.
*/
GROUP(libgcc.a libc.a libm.a)
INCLUDE extra_libs.inc
/*
* These force the linker to search for vector table symbols.
*
* These symbols vary by STM32 family (and also within families).
* It's up to the build system to configure the link's search path
* properly for the target MCU.
*/
INCLUDE vector_symbols.inc
/* STM32 vector table. */
EXTERN(__stm32_vector_table)
/* C runtime initialization function. */
EXTERN(start_c)
/* main entry point */
EXTERN(main)
/* Initial stack pointer value. Relocated to RAM */
EXTERN(__msp_init)
PROVIDE(__msp_init = ORIGIN(ram) + LENGTH(ram));
/* Reset vector and chip reset entry point */
EXTERN(__start__)
ENTRY(__start__)
PROVIDE(__exc_reset = __start__);
/* Heap boundaries, for libmaple */
EXTERN(_lm_heap_start);
EXTERN(_lm_heap_end);
SECTIONS
{
.text :
{
__text_start__ = .;
/*
* STM32 vector table. Leave this here. Yes, really.
*/
*(.stm32.interrupt_vector)
/*
* Program code and vague linking
*/
*(.text .text.* .gnu.linkonce.t.*)
*(.plt)
*(.gnu.warning)
*(.glue_7t) *(.glue_7) *(.vfp11_veneer)
*(.ARM.extab* .gnu.linkonce.armextab.*)
*(.gcc_except_table)
*(.eh_frame_hdr)
*(.eh_frame)
. = ALIGN(4);
KEEP(*(.init))
. = ALIGN(4);
__preinit_array_start = .;
KEEP (*(.preinit_array))
__preinit_array_end = .;
. = ALIGN(4);
__init_array_start = .;
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array))
__init_array_end = .;
. = ALIGN(0x4);
KEEP (*crtbegin.o(.ctors))
KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*crtend.o(.ctors))
. = ALIGN(4);
KEEP(*(.fini))
. = ALIGN(4);
__fini_array_start = .;
KEEP (*(.fini_array))
KEEP (*(SORT(.fini_array.*)))
__fini_array_end = .;
KEEP (*crtbegin.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*crtend.o(.dtors))
} > REGION_TEXT
/*
* End of text
*/
.text.align :
{
. = ALIGN(8);
__text_end__ = .;
} > REGION_TEXT
/*
* .ARM.exidx exception unwinding; mandated by ARM's C++ ABI
*/
__exidx_start = .;
.ARM.exidx :
{
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
} > REGION_RODATA
__exidx_end = .;
/*
* Read-only data
*/
.rodata :
{
*(.rodata .rodata.* .gnu.linkonce.r.*)
/* .USER_FLASH: We allow users to allocate into Flash here */
*(.USER_FLASH)
/* ROM image configuration; for C startup */
. = ALIGN(4);
_lm_rom_img_cfgp = .;
LONG(LOADADDR(.data));
/*
* Heap: Linker scripts may choose a custom heap by overriding
* _lm_heap_start and _lm_heap_end. Otherwise, the heap is in
* internal SRAM, beginning after .bss, and growing towards
* the stack.
*
* I'm shoving these here naively; there's probably a cleaner way
* to go about this. [mbolivar]
*/
_lm_heap_start = DEFINED(_lm_heap_start) ? _lm_heap_start : __data_end__;
_lm_heap_end = DEFINED(_lm_heap_end) ? _lm_heap_end : __msp_init;
} > REGION_RODATA
/*
* .data
*/
.data :
{
. = ALIGN(8);
__data_start__ = .;
*(.got.plt) *(.got)
*(.data .data.* .gnu.linkonce.d.*)
. = ALIGN(8);
__data_end__ = .;
} > REGION_DATA AT> REGION_RODATA
/*
* .bss
*/
.bss :
{
. = ALIGN(8);
__bss_start__ = .;
*(.bss .bss.* .gnu.linkonce.b.*)
*(COMMON)
. = ALIGN (8);
__bss_end__ = .;
_end = __bss_end__;
} > REGION_BSS
/*
* Debugging sections
*/
.stab 0 (NOLOAD) : { *(.stab) }
.stabstr 0 (NOLOAD) : { *(.stabstr) }
/* DWARF debug sections.
* Symbols in the DWARF debugging sections are relative to the beginning
* of the section so we begin them at 0. */
/* DWARF 1 */
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2 */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2 */
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
/* SGI/MIPS DWARF 2 extensions */
.debug_weaknames 0 : { *(.debug_weaknames) }
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
.note.gnu.arm.ident 0 : { KEEP (*(.note.gnu.arm.ident)) }
.ARM.attributes 0 : { KEEP (*(.ARM.attributes)) }
/DISCARD/ : { *(.note.GNU-stack) }
}
Обратите внимание на строчки 152 и 153, которые устанавливают границы кучи. Верх кучи установлен на метку __msp_init, которая в строке 43 приравнена верху RAM. Тут вроде все хорошо.
А вот низ кучи указывает на окончание секции .data (на метку __data_end__) - а ведь секция data располается не в RAM. а во флеше, да к тому же весьма далеко от адресов, по которым в едином пространстве адресов СТМ расположена оперативка. - Не ошибка ли это?
Если сравнить этот файл с аналогичным для блюпилл,(там malloc() работает) - у блюпилл куча располается между верхом RAM и секцией bss - как описано во всех учебниках.
Короче, я просто взял и заменил в строке 152 метку __data_end__ на __bss_end__ :
a5021, спасибо за инфо. Судя по выделенному куску, с использованием -Og некоторая оптимизация продолжает применяться. Вероятно, именно это и приводило к конфликту с дебаггером, раз при полном отключении оптимизации опцией -O0 дебаггер начал работать.
Не получится легко это сделать. Библиотека завязана на хардверные прерывания и их надо переопределять с авр на стм. Или искать библиотеку где это уже сделали.
Бред околособачий! CPU в гаджетах это одно, а MCU в новых разработках это другое. Пройдёт ещё 3-5 лет и атмэла в новых разработках вообще не будет, от слова совсем.
Ну, не знаю, в своих проектах я пользуюсь исключительно своими библиотеками, поэтому опыта работы с более или менее стандартными не имею.
Хотя, стандартные я нередко использую, когда надо быстро убедиться в работоспособности только что полученного экрана. А т.к экраны я последнее время покупаю в основном 3-вольтовые, думаю, что поддержка stm32f103 мне, скорее всего, где-то попадалась. На чем-то же я их проверял!
b707, ну с прерываниями оно, наверное, так и должно быть. Но можно и без прерываний тоже самое сделать. Один таймер "мастер" считает некоторое кол-тактов разрешая в это время работу другому, а потом некоторое кол-во запрещая. Другой просто генерит 1МГц, подчиняясь указанием "мастера" когда можно генерить, когда нельзя. Пример, тут 10 микросекунд разрешено и 5 запрещено. На осцилле аккуратные пачки по 10 импульсов.
dimax, спасибо, о таком варианте не подумал.
Попробовал, все отлично, четкие пачки по 138 импульсов. Отмечу только важные нюансы в верхнем коде:
- для точной синхронизации слейв должен запускаться до Мастера (строчки 15 и 16 нужно поменять местами)
- значение регистра сранения задется точно, а не N-1, в отличии от прескалера или ARR. В данном случае это важно. так как разница в единицу дает рассинхронизацию мастера и слейва, которая накапливается от цикла к циклу, меняя фазу сигнала
Когда это поправил - все работает очень четко, число импульсов строго одинаковое, все задержки стабильные.
Но проблемы еще остались. По ходу программы мне нужно эту связку таймеров включать и выключать. Если просто выключить мастер таймер, а потом запустить заново, обнулив при старте счетчики мастера и слейва - в первой пачке будет 141 импульс. Не знаю почему так, но видимо придется при каждом рестарте таймера конфигурировать все регистры заново.
b707, а можно и на одном таймере и ДМА. Таймер тактирует ДМА, а тот кидает ему в регистр CCR каждый раз новое значение, задающее скважность. Когда сигнал не нужен даём нулевую скважность. В итоге имеем ровные пачки импульсов:
b707, а можно и на одном таймере и ДМА.
отлично, спасибо. Это мне как раз на следующую задачку, у меня еще нужно данные грузить в регистры максимально быстро :) ДМА в самый раз для этого
...максимально быстро ... ДМА ...
Знак "=" поставить никак нельзя к сожалению ...
...максимально быстро ... ДМА ...
Знак "=" поставить никак нельзя к сожалению ...
да, знаю.... ногодрыгом быстрее.
Вопрос - а почему у меня упорно засело в голове, что сконфигурировать ДМА-перенос из памяти в GPIO можно только на таймере1 ? - сиху читаю даташит, не вижу таких ограничений
добавка - запустил на таймере3 - все отлично работает. Еще раз спасибо dimax за пример.
Все-таки не понятно, почему "в интернетах" упорно натыкаюсь на сообщения, что работать с GPIO можно тактируя ДМА исключительно первым таймерм?
b707, касательно мк F401 я и сам про это писал , а вот с F103 уже не помню была ли такая особенность.
b707, касательно мк F401 я и сам про это писал , а вот с F103 уже не помню была ли такая особенность.
На F103 работает. Надо будет на 401 проверить.
В даташите на F401 вроде тоже не вижу запрета на использование DMA1 для загрузки данных в регистры GPIO.
вопрос про F401.
Черная плата BlackPill с Али, контроллер STM32F401CC
Вот такой простенький скетч
нормально работает(мигает лампочкой), пока размер куска отведенной динамической памяти не превышает примерно 61-62к, потом виснет, что вполне согласуется с заявленным обьемом RAM 64к
Но если мигать лампой через прерывание таймера:
все виснет уже при попытке выделить динамическю память всего в 1к ! 800 байт работает - 1000 - уже нет.
WTF?
аддон Кларка.
У кого есть F401 - прверьте в обоих аддонах, плиз
Итак, дополнение по проблемам из сообщения #509.
Пытаюсь запустить готовый проект, работающий на F103 - на MK F401.
1 malloc() не работает. Попытки выделить функцией malloc() динамическую область памяти более чем 50-100 байт - терпят неудачу. Причем сама функция, как водится, ошибок не вызывает - но попытки обращения к выделенной памяти приводят к зависанию программы. При этом статически можно выделить память практически любого размера вплоть до полного размера RAM.
2. функция pinMode() не работает в конструкторе глобального обьекта, при этом в setup() и в основной программе работает. Возможно, причина в том, что в конструкторе еще "слишком рано" и инициализация портов GPIO не закончена, а к сетапу она завершается. Пробовал вставлять свою инициализацию шины и GPIO порта до первого pinMode() - не помогло.
это не считая несовместимости по регистрам BRR и BSRR, которую я легко обошел.
Интересно, кто-нибудь еще с пп 1 и 2 сталкивался?
2. функция pinMode() не работает в конструкторе глобального обьекта, при этом в setup() и в основной программе работает. Возможно, причина в том, что в конструкторе еще "слишком рано" и инициализация портов GPIO не закончена, а к сетапу она завершается.
Именно.
Собственно, не "не закончена", а "еще не начиналась". По стандарту сначала происходит инициализация всех глобальных переменных, и только потом - выполняется первый исполняемый оператор программы, в данном случае - блока инициализации железа.
Поэтому инициализацию железа в Ардуино принято производить не в конструкторе, а в специальном методе init() или setup().
PS. Кстати, malloc() часом вызывается не из конструктора?
По стандарту сначала происходит инициализация всех глобальных переменных, и только потом - выполняется первый исполняемый оператор программы, в данном случае - блока инициализации железа.
Нет. Порядок запуска программы полностью под контролем программиста. Ничто не мешает написать что угодно перед "call static constructors"
Собственно, не "не закончена", а "еще не начиналась". По стандарту сначала происходит инициализация всех глобальных переменных, и только потом - выполняется первый исполняемый оператор программы, в данном случае - блока инициализации железа.
Поэтому инициализацию железа в Ардуино принято производить не в конструкторе, а в специальном методе init() или setup().
как ни странно, на F103 внутри конструктора pinMode() отрабатывает нормально
Мне, конечно, нетрудно всю инициализацию железа перетащить в class.init() - но хотелось бы понять, почему и на ардуино Нано/Мега. и на обычном блюпилле это все работало и в конструкторе, а в F401 нет
именно там.
Нет. Порядок запуска программы полностью под контролем программиста. Ничто не мешает написать что угодно перед "call static constructors"
И что это было?
Для тех, кто в танке: в Ардуино используется язык программирования С++, и речь в данном контексте шла именно о нем.
И что это было?
Для тех, кто в танке: в Ардуино используется язык программирования С++, и речь в данном контексте шла именно о нем.
в Ардуино используется ядро, написанное программистом, и содержащее такой фрагмент кода. Если бы программист напряг мозги, он бы настроил ядро правильно.
https://github.com/rogerclarkmelbourne/Arduino_STM32/blob/master/STM32F4...
PS. Кстати, malloc() часом вызывается не из конструктора?
все-таки уточните, что вы имели в виду?
https://github.com/rogerclarkmelbourne/Arduino_STM32/blob/master/STM32F4...
сорри, но видимо я до этого еще не дорос... Единственное, что мне пришло в голову - сравнить этот файл из ветки STM32F4 с аналогичным для STM32F1, чтобы попытаться понять, почему проблема с инициализацией возникает только в STM32F4.
Но в ветке STM32F1 аналогичного файла вообще нет... или этот код где-то еще, или как-то обходятся без указания порядка инициализации...
И что это было?
Для тех, кто в танке: в Ардуино используется язык программирования С++, и речь в данном контексте шла именно о нем.
в Ардуино используется ядро, написанное программистом, и содержащее такой фрагмент кода. Если бы программист напряг мозги, он бы настроил ядро правильно.
Да и вообще, квалификация любого специалиста определяется умением пользоваться имеющимся инструментом, а не умением настроить молоток так, чтобы им можно было заворачивать шурупы.
andriano, нафига вам ругаться с РКИТом?
Я, смотрите, старательно вас развожу, задаю каждому вопрос отдельно :) Ответьте лучше мне про malloc() в конструкторе...
andriano, нафига вам ругаться с РКИТом?
Я, смотрите, старательно вас развожу, задаю каждому вопрос отдельно :) Ответьте лучше мне про malloc() в конструкторе...
Ну, стартовая настройка МК предполагает помимо инициализации периферии также настройку стека, кучи и пр. Опять же, при инициализации аппаратуры, как правило, возникает необходимость в выделении памяти. А выделение памяти стандартным образом из кучи сопровождается накладными расходами. Почему бы, скажем, не зафиксировать буфер Serial по стандартному адресу в обход менеджера кучи?
В общем, нужно либо разбираться с тонкостями реализации, а они, эти тонкости, могут существенно различаться для разных камней (хотя бы потому, что авторы кода - разные), либо попытаться выработать общие подходы, которые будут работать независимо от того, как реализовал блок инициализации тот или иной автор. Отказ от инициализации и распределения памяти в конструкторе и применение вместо этого явные методы инициализации (init или setup) я рассматриваю в качестве таких подходов. Потому как считаю, что следует выбирать камень под задачу, а задачи у меня бывают ох какими разными. Следовательно, детальное изучение особенностей реализации блока инициализации для каждого конкретного камня, на мой взгляд, непроизводительная трата времени.
Например на stm я написал программу, которая распечатывает мне содержимое регистров включенных устройств - и этой информации мне достаточно, чтобы потом перестраивать режимы работы под себя. А разбираться, когда именно и в какой последовательности эта инициализация была проведена - мне не интересно.
сорри, но видимо я до этого еще не дорос... Единственное, что мне пришло в голову - сравнить этот файл из ветки STM32F4 с аналогичным для STM32F1, чтобы попытаться понять, почему проблема с инициализацией возникает только в STM32F4.
Но в ветке STM32F1 аналогичного файла вообще нет... или этот код где-то еще, или как-то обходятся без указания порядка инициализации...
Надо детально смотреть весь код. Это много где может быть реализовано, на самом деле. Я просто привел пример того, что можно элементарно выполнять код до инициализации глобальных переменных.
Все-таки не понятно, почему "в интернетах" упорно натыкаюсь на сообщения, что работать с GPIO можно тактируя ДМА исключительно первым таймерм?
Патамушта в тырнетах тупо копировали у друг друга... без малейшего понимания... что к чему...
Смотреть надо референс... а не даташит... Там есть таблица эвентов для ДМА...
И кстати... Там хоть и написано... что можно юзать только один эвент на канал... но на самом деле... если эвенты синхронизированы и не одновременны... то можно юзать и несколько... если это нужно и соответствует задаче...
И ещё... из того что ещё помню... В Ф4хх... два модуля ДМА... один из них не работает с ЖПИО по определению...
Серия 32Ж тоже не работает по ДМА с ЖПИО... от рождения своего...
+++++++++
И да... ДМА не тактируется таймером... он получает эвенты от таймера...
Такой вопросик - отладку в каком-нибудь из аддонов есть возможность использовать? Ну там расставить точки останова, посмотреть значения переменных во время выполнения?
Понятно, что не в Ардуино ИДЕ, а например в V-Micro ?
В родном STMовском отлаживает. А мне больше нравиться в IAR. Там вообще всё можно смотреть и менять на любом шаге.
да по моему во всех есть, кроме Ардуино ИДЕ, я вот родной CubeIDE пользуюсь, не понимаю что все так от нее плюются.
В родном STMовском отлаживает. А мне больше нравиться в IAR. Там вообще всё можно смотреть и менять на любом шаге.
вчера весь вечер протрахался с этим, в V-micro c кларковским аддоном так и не смог запустить... То OpenOCD сервер не запускается, пишет "неверные аргументы", Как ни искал - не нашел, где эти аргументы менять...
Потом вообще Ст-линк перестал определяться, насилу вылечил...
Возможно дело не в аддоне и не в Микро, а в том что у меня винда уже слишком замусорена... Например, у меня два компа, на одном СТ-линк работает, а на другом вообще никак
Запустил-таки отладку в Vmicro версии 19.30 для блюпила с кларковским аддоном.
Необходимые настройки для stm32F103C8 и St-link-v2
- В опциях проекта Vmicro включить Micro Debug - Full
- Поменять опции компиляции с оптимизации на Debug -g
- В файл boards в папке ....Arduino\hardware\Arduino_STM32\STM32F1\ в секцию genericSTM32F103C добавить строчку:
(обратите внимание, что этот конфиг только для комбинации stm32F103C8 + St-link-v2, под другой МК и другой программатор нужно подбирать конфиг отдельно)
Единственное, что осталось не до конца понятным - после загрузки скетча и запуска отладчика обязательно нужно вручную нажать ресет на плате, иначе отладка не стартует. Кто пользуется отладкой в Вмикро - поделитесь, у вас тоже так? Может есть какой-то способ заставить плату перегружаться автоматом?
И еще - некоторые переменные в Watch посмотреть нельзя - пишет "optimezed out". Правильно ли я понял, что это означает что переменная выкинута оптимизатором как неиспользуемая? - странно, я думал в дебаг-режиме всякая оптимизация отключается...
И еще - некоторые переменные в Watch посмотреть нельзя - пишет "optimezed out". Правильно ли я понял, что это означает что переменная выкинута оптимизатором как неиспользуемая? - странно, я думал в дебаг-режиме всякая оптимизация отключается...
1. Переменная выкинута только из памяти, т.е. на нее не распределяется место в стеке/куче. Вместо этого переменная хранится в регистрах и, соответственно, не имеет адреса.
2. Вообще-то режим отладки подразумевает помещение в код дополнительной информации, а не отключение оптимизации. Возможно, это вещи в какой-то степени связанные, но точно не эквивалентные.
Да, насчет переменных уже разобрался, "optimized out" означает, что переменная относится к другому блоку программы и в этом недоступна. Сейчас столкнулся с другой проблемой - в режиме отладки выполнение программы происходит в сотни, а то и в тысячи раз медленнее, чем в релизе, реально просто не могу дойти до места, которое нужно отлаживать. О том, чтобы запускать отладку на том же коде, что и релиз - нечего и думать, приходится убирать все лишнее, сокращать циклы, выкидывать задержки и миллис.
Понимаю, что так быть не должно... пытаюсь найти причину.
На этот случай в отладчиках есть точка останова. До неё обычно в режиме отладки программа добирается с нормальной скоростью.
На этот случай в отладчиках есть точка останова. До неё обычно в режиме отладки программа добирается с нормальной скоростью.
Я уже все прерывания остановил - все равно . "Продолжить до сдедующей точки останова" - идет со скоростью примерно 10-20 ассемблерных инструкций в секунду. то есть очень медленно. Если идти по шагам - скорость нормальная, если не считать того, что каждую строчку пройти надо вручную.
Нашел описание этого бага в инете в паре мест, решения там нет
ссылка https://www.openstm32.org/forumthread1369
добил, все работает.
Для информации - в настройках аддона в режиме Debug стоит какая-то странная опция компилятора -Og
В мане GCC я такой опции не нашел, написано только, что опции оптимизации -Ox можно комбинировать с опциями дебага -gx. но что означает комбинация -Og - не написано.
В итоге поменял эту непонятную опцию на комбинацию -O0 -g3 -ggdb и все поехало.
Возможно опция -g3 избыточна в моем случае, но пока размер прошивки не превышает флеша МК - это не особо важно.
Надеюсь, кому-то эта информация будет полезной.
-Og
Like -O0, -Og completely disables a number of optimization passes so that individual options controlling them have no effect. Otherwise -Og enables all -O1 optimization flags except for those that may interfere with debugging:
продолжаю разбираться с F401 в аддоне Кларка. Хочется понять, почему при попытке выделить даже минимальный блок памяти с помощью malloc() все виснет?
Есть те, кто понимает в ld скриптах? Вот скрипт от F401 из аддона Кларка:
Обратите внимание на строчки 152 и 153, которые устанавливают границы кучи. Верх кучи установлен на метку __msp_init, которая в строке 43 приравнена верху RAM. Тут вроде все хорошо.
А вот низ кучи указывает на окончание секции .data (на метку __data_end__) - а ведь секция data располается не в RAM. а во флеше, да к тому же весьма далеко от адресов, по которым в едином пространстве адресов СТМ расположена оперативка. - Не ошибка ли это?
Если сравнить этот файл с аналогичным для блюпилл,(там malloc() работает) - у блюпилл куча располается между верхом RAM и секцией bss - как описано во всех учебниках.
Короче, я просто взял и заменил в строке 152 метку __data_end__ на __bss_end__ :
и все заработало!
Теперь вопрос - мое исправление верное или это какой-то костыль?
-Og
Otherwise -Og enables all -O1 optimization flags except for those that may interfere with debugging:a5021, спасибо за инфо. Судя по выделенному куску, с использованием -Og некоторая оптимизация продолжает применяться. Вероятно, именно это и приводило к конфликту с дебаггером, раз при полном отключении оптимизации опцией -O0 дебаггер начал работать.
Напомните плиз, кто-то писал, что аддоны СТМ и Кларка не ставятся одновременно. Есть какие-то хаки, как их заставить не мешать друг другу?
b707, это я писал в начале темы, были глюки, не помню уже какие конкретно. Может за давностью времени уже не актуально..
b707, это я писал в начале темы, были глюки, не помню уже какие конкретно. Может за давностью времени уже не актуально..
Димакс, спасибо за отклик. Попробую сам.
А по линкер скриптам (сообщение 535) не подскажете?
У меня стоят оба рядом. Работает тот что выбрал. Глюки связаны только с разной семантикой выражений. НАL не дружит с Кларком.
nik182. спасибо
Не получится легко это сделать. Библиотека завязана на хардверные прерывания и их надо переопределять с авр на стм. Или искать библиотеку где это уже сделали.
Бред околособачий! CPU в гаджетах это одно, а MCU в новых разработках это другое. Пройдёт ещё 3-5 лет и атмэла в новых разработках вообще не будет, от слова совсем.
...прошло 3-5 лет...
вопрос, кому-нибудь удалось адаптировать библиотеку UTFT под STM32F103?
А что, разве она еще не адаптирована?
А что, разве она еще не адаптирована?
из тех, что нашёл, нет, сам удивляюсь
Ну, не знаю, в своих проектах я пользуюсь исключительно своими библиотеками, поэтому опыта работы с более или менее стандартными не имею.
Хотя, стандартные я нередко использую, когда надо быстро убедиться в работоспособности только что полученного экрана. А т.к экраны я последнее время покупаю в основном 3-вольтовые, думаю, что поддержка stm32f103 мне, скорее всего, где-то попадалась. На чем-то же я их проверял!
На чем-то же я их проверял!
я что за UTFT вцепился, там поддержка большого количества контроллеров, лёгкость перехода на экран иного размера