Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Начальная инициализация статических переменных.
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > ARM, 32bit
Вячик13
Среда - Keil Arm. Контроллер STM32F103.
В Keil имеется функция SystemInit(), которая выполняется перед main().

Описание эффекта.
В функции SystemInit() инициализируется несколько указателей-параметров объекта. При входе в функцию main() эти параметры обнуляются.

Вопрос.
Что это? Возможно начальная инициализация статических переменных происходит после выполнения SystemInit()? Не похоже. Какие-то "заморочки со стеком?" может я какую-то "галочку" в опциях проекта не поставил?
ViKo
Цитата(Вячик13 @ Jul 9 2012, 09:36) *
В функции SystemInit() инициализируется несколько указателей-параметров объекта.

Например?
Вячик13
Цитата(ViKo @ Jul 9 2012, 09:49) *
Например?


typedef struct TExtADCResult {
bool Exist;
unsigned long Value;
} TExtADCResult;

typedef struct TExtADC {
TSPI *SPIPtr;
void (*Select)(void);
void (*Unselect)(void);
void (*Start)(void);
void (*Stop)(void);
bool (*Ready)(void);
void (*Reset)(void);
TExtADCResult Result[8];
bool Exist;
} TExtADC;

#define ExtADC_CHAN_NUMBER 2

TExtADC ExtADCChanel[ExtADC_CHAN_NUMBER];

void SystemInit(void) {
PeriferInit();
}

void PeriferInit(void) {
TExtADC_Create(&ExtADCChanel[0],&SPIChanel[0],&ExtADC1_Select,&ExtADC1_Unselect,&ExtADC_Start,&ExtADC_Stop,ExtADC1_Ready,ExtADC_Reset);
TExtADC_Create(&ExtADCChanel[1],&SPIChanel[0],&ExtADC2_Select,&ExtADC2_Unselect,&ExtADC_Start,&ExtADC_Stop,ExtADC2_Ready,ExtADC_Reset);
}

В TExtADC_Create() идёт обыкновенное присвоение указателям ссылок на функции. Смотрю объект ExtADCChanel[0].

ViKo
Смотрите, что есть в startup.
Код
Reset_Handler    PROC
                 EXPORT  Reset_Handler             [WEAK]
        IMPORT  SystemInit
        IMPORT  __main
                 LDR     R0, =SystemInit
                 BLX     R0
                 LDR     R0, =__main
                 BX      R0
                 ENDP

Видите __main - вот там все и устанавливается.
Вы сами добавили кода в SystemInit()? А чем не устроило сделать это в main?
Вячик13
Цитата(ViKo @ Jul 9 2012, 10:30) *
Смотрите, что есть в startup.
Код
Reset_Handler    PROC
                 EXPORT  Reset_Handler             [WEAK]
        IMPORT  SystemInit
        IMPORT  __main
                 LDR     R0, =SystemInit
                 BLX     R0
                 LDR     R0, =__main
                 BX      R0
                 ENDP

Видите __main - вот там все и устанавливается.
Вы сами добавили кода в SystemInit()? А чем не устроило сделать это в main?


Вот мой startup:

Reset_Handler PROC
EXPORT Reset_Handler [WEAK]
IMPORT __main
IMPORT SystemInit
LDR R0, =SystemInit
BLX R0
LDR R0, =__main
BX R0
ENDP
По-моему не отличается ничем.
ViKo
Цитата(Вячик13 @ Jul 9 2012, 10:36) *
По-моему не отличается ничем.

И это правильно. Еще раз прочитайте мой ответ.

Цитата(Вячик13 @ Jul 9 2012, 09:36) *
Возможно начальная инициализация статических переменных происходит после выполнения SystemInit()? Не похоже.

Не "не похоже", а именно так!
Вячик13
Цитата(ViKo @ Jul 9 2012, 10:50) *
И это правильно. Еще раз прочитайте мой ответ.


Не "не похоже", а именно так!


Не понял, а где именно выполняется инициализация переменных? Где вызов подпрограммы? В приведенном ассемблерном коде я его не вижу. Ну и что из того, что сначала выполняется SystemInit(), а потом main()? Или инициализация выполняется в начале работы main()?
ViKo
Цитата(Вячик13 @ Jul 9 2012, 11:05) *
Не понял, а где именно выполняется инициализация переменных? Где вызов подпрограммы? В приведенном ассемблерном коде я его не вижу. Ну и что из того, что сначала выполняется SystemInit(), а потом main()? Или инициализация выполняется в начале работы main()?

где же main(), если __main()?
Вячик13
Цитата(ViKo @ Jul 9 2012, 11:11) *
где же main(), если __main()?


А... Теперь понял. Спасибо, учту в программе.
kan35
в 20х числах июня, Томас Дреслер из ST совместно с дистрибьюторами проводил семинары (Москва, Питер, Ебург) на тему STM32F4... и как раз это все разжевал. Многие при этом возмущались - зачем типа нам это все знать.
В том числе почему SystemInit вызывается до __main и что еще инициализируется в __main...
Вячик13
Цитата(kan35 @ Jul 10 2012, 13:16) *
в 20х числах июня, Томас Дреслер из ST совместно с дистрибьюторами проводил семинары (Москва, Питер, Ебург) на тему STM32F4... и как раз это все разжевал. Многие при этом возмущались - зачем типа нам это все знать.
В том числе почему SystemInit вызывается до __main и что еще инициализируется в __main...

С удовольствием съездил бы послушал. Но попасть на эти семинары в те города, которые Вы перечислили, из моего провинциального украинского городка и небольшой частной фирмы - это всё равно, что слетать на Луну. Так что пока единственное спасение - это вот такие конференции и бескорыстная помощь моих уважаемых коллег.
ViKo
Цитата(kan35 @ Jul 10 2012, 13:16) *
В том числе почему SystemInit вызывается до __main и что еще инициализируется в __main...

И почему, и что? Как там на семинаре объясняли? Не доложите вкратце?
По-моему - зря функцию установки тактовой частоты назвали SystemInit.
kan35
SystemInit или собственно говоря установка частоты процессора и памяти делается в первую очередь так как происходящее в __main инициализация глобалных и статических переменных на дефолтной частоте может занять ощутимо много времени, если это критично конечно.
Еще, если вы используете массивы в RAM и если они значительные, то для экономии flash (из которой эти данные перегружаются) можно самостоятельно инициализировать их (не в __main), например применяя архивацию данных. Еще в __main инициализируется heap. это все что я вспомнил))
AHTOXA
А по-моему, всё гораздо проще.
SystemInit - это от ST, а __main - от кейла. И ST банально не может вызвать SystemInit после __main, потому что оттуда нет возврата laughing.gif
Косвенно это подтверждается тем фактом, что в стартапе для GCC (TrueSTUDIO) сделано по уму - сначала инициализация data и bss, и только потом - вызов SystemInit.
kan35
Цитата(AHTOXA @ Jul 12 2012, 01:10) *
А по-моему, всё гораздо проще.
SystemInit - это от ST, а __main - от кейла. И ST банально не может вызвать SystemInit после __main, потому что оттуда нет возврата laughing.gif

Эти рассуждения не выдерживают никакой критики. Почему бы тогда по вашей логиге банально не вызывать SystemInit в сомом main()? Инициализация на 16МГц и на 168МГц - чувствуете разницу?
AHTOXA
Цитата(kan35 @ Jul 12 2012, 10:11) *
Почему бы тогда по вашей логиге банально не вызывать SystemInit в сомом main()?
Потому что main - это уже пользовательское приложение. А ST пыталась сделать шаблон. Как раз для того, чтобы пользователю в main ничего не надо было писать.
Цитата(kan35 @ Jul 12 2012, 10:11) *
Инициализация на 16МГц и на 168МГц - чувствуете разницу?

А при использовании GCC, по вашей "логиге", проц стартует сразу на 168МГц? sm.gif
Я понимаю, что вы послушали "спецов" из ST, и прониклись. Но голову-то включать иногда надо?
kan35
Вы сказали, что в GCC сначала происходит инициализация, а "SystemInit"после. Если это так, то это неправильно как раз. Производить инициализацию в 10 раз медленнее чем позволяет проц - не всегда позволительно.
А то, что это делается чтобы в main ничего не писать - хм... логики не вижу. Ну и пусть бы на 16МГц работал на старте, вообще бы никаких SystemInit не было - какой в этом криминал, в конце концов далеко не всем нужна максимальная частота (или не всегда максимальная). В общем я проникся, вы правы :-)
редактор
SystemInit() от STM приводит контроллер в исходное состояние (включает HSI, запрещает прерывания и проч). И правильнее это сделать до вызова main(), а не после этого.
Скорее всего прав АНТОХА. Вызывать свою функцию из библиотеки Keil нельзя, а вот перед ее выполнением легко. STM упростило себе и начинающим жизнь, а гуру все равно под себя переделают.
kan35
Цитата(редактор @ Jul 12 2012, 16:19) *
SystemInit() от STM приводит контроллер в исходное состояние (включает HSI, запрещает прерывания и проч).

А вы уверены что SystemInit делает то что вы написали?
Мне показалось я АНТОХу только что убедил, а тут Вы нарисовались smile3046.gif
AHTOXA
Цитата(kan35 @ Jul 12 2012, 17:45) *
Вы сказали, что в GCC сначала происходит инициализация, а "SystemInit"после. Если это так, то это неправильно как раз. Производить инициализацию в 10 раз медленнее чем позволяет проц - не всегда позволительно.

Суть в том, что в трёх вариантах из пяти сделано так. То есть, при наличии возможности выбрать, что делать сначала, инициализацию переменных или вызов SystemInit() (это gcc_ride7, TASKING и TrueSTUDIO) -- сначала идёт инициализация переменных. А в двух случаях, где этого выбора нет (keil и IAR) - сделали как смогли.
И получилось, кстати, не по стандарту Си. (Но тут я не особо силён, и могу ошибаться.)

Так что товарищ из ST, который вам это обосновывал - скорее всего "импровизировал" sm.gif
kan35
Ну и отвлекаясь от обсуждения квалификации инженера из ST, с вашего позволения подытожу, что все перечисленные - gcc_ride7, TASKING и TrueSTUDIO в >10 раз медленнее выводят контроллер на рабочий код, чем компиляторы iar и keil, с этим вы спорить будете? ;-)
AHTOXA
То есть, по поводу квалификации инженера из ST у нас уже консенсус? sm.gif
Конечно буду sm.gif
В случае этой троицы разработчик имеет полный контроль. Надо ускорить запуск - ничто не мешает переписать стартап. По крайней мере это будет осознанное решение.
редактор
Цитата
А вы уверены что SystemInit делает то что вы написали?

Да уверен. Я посмотрел исходник от ST из комплекта Keil (v4.23) для серии ST32F10X.
Не особо вдаваясь в код, бегло просмотрел коментарии и сделал выводы.

Насчет HSI поторопился немного. Сперва сбрасывается на внутренний генератор, затем выставляется системная частота в зависимости от дефайна.

Цитата
И получилось, кстати, не по стандарту Си.

Поскольку стандарт описывает поведение программы, а не поведение железа, то предварительную (дефолтовую) ноастройку можно отнести как к подготовительным операциям (типа инициализации статических переменных), так и к исполнению пользовательского кода.
Инженеры ST придерживаются первого варианта.
ViKo
Напомню, что переменные могут располагаться и во внешней памяти. А встроенный контроллер к ней перед этим нужно еще инициализировать. Иначе - никак.
Поэтому объяснение инженера из ST мне представляется верным. Поддерживаю kan35.
AHTOXA
Цитата(ViKo @ Jul 14 2012, 21:07) *
Напомню, что переменные могут располагаться и во внешней памяти. А встроенный контроллер к ней перед этим нужно еще инициализировать. Иначе - никак.
Поэтому объяснение инженера из ST мне представляется верным. Поддерживаю kan35.

А в случае с gcc_ride7, TASKING и TrueSTUDIO объяснения инженера из ST надо просто инвертировать? sm.gif
Если честно, то не ожидал, что моё очевидное наблюдение вызовет столько возражений.
Ещё раз: да, могут быть случаи, когда надо сначала инициализировать тактирование и/или внешнюю память, а уже потом - статические переменные. Но, (и это - соль моего наблюдения) программисты из ST совершенно не думали ни о чём таком. Если бы думали, то сделали бы во всех вариантах одинаковый порядок.
kan35
АНТОХА, действительно, разница в шаблонах имеется, сейчас я специально тоже посмотрел. И обратил внимание, что в TASKING сделано как в IAR и KEIL, хотя можно было сделать как в GCC, но не было сделано!
Из всех тобою перечисленных только GCC (TRUEStudio и gcc_ride7 - одно и то же, даже sturtup у них практически копии). Итого пропорция складывается 3:1 не в твою пользу и не в пользу бесплатного средства. И, конечно остается вопрос, почему ST в варианте GCC сделали иной порядок, возможно для GCC пишут не те же программеры, что для коммерческих сред. Правдоподобно?
AHTOXA
Да, точно, с TASKING-ом я был невнимателен. Тогда соглашусь, скорее всего писали разные люди.
_Артём_
Цитата(AHTOXA @ Jul 15 2012, 00:06) *
да, могут быть случаи, когда надо сначала инициализировать тактирование и/или внешнюю память, а уже потом - статические переменные.

Почему "могут быть"?
Разве такая последовательность ( 1. инициализация тактирование, 2. инициализация внешней памятиб если она есть 3. инициализация переменых) не наиболее логична? Просто обычно не критично на какой тактовой она выполнится.
AHTOXA
Потому что при вызове сишной функции SystemInit() мы должны обеспечить инициализированные статические переменные и обнулённые неинициализированные. Это вроде как по стандарту языка Си.
редактор
Если бы сишная функция была включена в стартап в виде ассемблерного модуля, этот диалог не состоялся бы.
ViKo
Все, что делается до main, принадлежит операционной системе. В микроконтроллерах в данном случае от нее - только SystemInit() да __main. А мог бы быть и Линукс какой-нибудь. Или Keil RTX.
Вообще, не вижу предмета для разговора, тем более, спора.
AHTOXA
Цитата(ViKo @ Jul 16 2012, 13:59) *
Все, что делается до main, принадлежит операционной системе.

Язык Си совершенно ортогонален операционной системе. Вы наверное имели в виду что-то типа "принадлежит библиотеке времени исполнения языка си, aka CRT"? Тогда да. Но тут опять-таки возникает вопрос, допустимо ли писать эту библиотеку на си? Вернее, можно ли писать на си её функции, которые будут вызываться до инициализации статических переменных и bss? Мне кажется, что это не совсем корректно.
Цитата(ViKo @ Jul 16 2012, 13:59) *
Вообще, не вижу предмета для разговора, тем более, спора.

Но вы же зачем-то разговариваете? sm.gif
ViKo
Цитата(AHTOXA @ Jul 16 2012, 12:55) *
Язык Си совершенно ортогонален операционной системе. Вы наверное имели в виду что-то типа "принадлежит библиотеке времени исполнения языка си, aka CRT"? Тогда да. Но тут опять-таки возникает вопрос, допустимо ли писать эту библиотеку на си? Вернее, можно ли писать на си её функции, которые будут вызываться до инициализации статических переменных и bss? Мне кажется, что это не совсем корректно.

Имел в виду что-то типа http://en.wikipedia.org/wiki/Run-time_system
Насчет допустимости - если представить, что SystemInit - это часть RTS, а main и остальное - свой отдельный проект, то и противоречий не наблюдается.
AHTOXA
Если SystemInit написать на ассемблере, то не наблюдается. Иначе - противоречие есть.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.