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

В функции SystemInit() инициализируется несколько указателей-параметров объекта.
Например?
Вячик13
Jul 9 2012, 07:09
Цитата(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].
Смотрите, что есть в 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
Jul 9 2012, 07:36
Цитата(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
По-моему не отличается ничем.
Цитата(Вячик13 @ Jul 9 2012, 10:36)

По-моему не отличается ничем.
И это правильно. Еще раз прочитайте мой ответ.
Цитата(Вячик13 @ Jul 9 2012, 09:36)

Возможно начальная инициализация статических переменных происходит после выполнения SystemInit()? Не похоже.
Не "не похоже", а именно так!
Вячик13
Jul 9 2012, 08:05
Цитата(ViKo @ Jul 9 2012, 10:50)

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

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

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

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

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

А по-моему, всё гораздо проще.
SystemInit - это от ST, а __main - от кейла. И ST банально
не может вызвать SystemInit после __main, потому что оттуда нет возврата

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

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

Инициализация на 16МГц и на 168МГц - чувствуете разницу?
А при использовании GCC, по вашей "логиге", проц стартует сразу на 168МГц?

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

SystemInit() от STM приводит контроллер в исходное состояние (включает HSI, запрещает прерывания и проч).
А вы уверены что SystemInit делает то что вы написали?
Мне показалось я АНТОХу только что убедил, а тут Вы нарисовались
AHTOXA
Jul 12 2012, 19:42
Цитата(kan35 @ Jul 12 2012, 17:45)

Вы сказали, что в GCC сначала происходит инициализация, а "SystemInit"после. Если это так, то это неправильно как раз. Производить инициализацию в 10 раз медленнее чем позволяет проц - не всегда позволительно.
Суть в том, что в трёх вариантах из пяти сделано так. То есть, при наличии возможности выбрать, что делать сначала, инициализацию переменных или вызов SystemInit() (это gcc_ride7, TASKING и TrueSTUDIO) -- сначала идёт инициализация переменных. А в двух случаях, где этого выбора нет (keil и IAR) - сделали как смогли.
И получилось, кстати, не по стандарту Си. (Но тут я не особо силён, и могу ошибаться.)
Так что товарищ из ST, который вам это обосновывал - скорее всего "импровизировал"
Ну и отвлекаясь от обсуждения квалификации инженера из ST, с вашего позволения подытожу, что все перечисленные - gcc_ride7, TASKING и TrueSTUDIO в >10 раз медленнее выводят контроллер на рабочий код, чем компиляторы iar и keil, с этим вы спорить будете? ;-)
AHTOXA
Jul 13 2012, 08:08
То есть, по поводу квалификации инженера из ST у нас уже консенсус?

Конечно буду

В случае этой троицы разработчик имеет полный контроль. Надо ускорить запуск - ничто не мешает переписать стартап. По крайней мере это будет осознанное решение.
редактор
Jul 13 2012, 11:50
Цитата
А вы уверены что SystemInit делает то что вы написали?
Да уверен. Я посмотрел исходник от ST из комплекта Keil (v4.23) для серии ST32F10X.
Не особо вдаваясь в код, бегло просмотрел коментарии и сделал выводы.
Насчет HSI поторопился немного. Сперва сбрасывается на внутренний генератор, затем выставляется системная частота в зависимости от дефайна.
Цитата
И получилось, кстати, не по стандарту Си.
Поскольку стандарт описывает поведение программы, а не поведение железа, то предварительную (дефолтовую) ноастройку можно отнести как к подготовительным операциям (типа инициализации статических переменных), так и к исполнению пользовательского кода.
Инженеры ST придерживаются первого варианта.
Напомню, что переменные могут располагаться и во внешней памяти. А встроенный контроллер к ней перед этим нужно еще инициализировать. Иначе - никак.
Поэтому объяснение инженера из ST мне представляется верным. Поддерживаю kan35.
AHTOXA
Jul 14 2012, 21:06
Цитата(ViKo @ Jul 14 2012, 21:07)

Напомню, что переменные могут располагаться и во внешней памяти. А встроенный контроллер к ней перед этим нужно еще инициализировать. Иначе - никак.
Поэтому объяснение инженера из ST мне представляется верным. Поддерживаю kan35.
А в случае с gcc_ride7, TASKING и TrueSTUDIO объяснения инженера из ST надо просто инвертировать?

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

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

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

Вообще, не вижу предмета для разговора, тем более, спора.
Но вы же зачем-то разговариваете?
Цитата(AHTOXA @ Jul 16 2012, 12:55)

Язык Си совершенно ортогонален операционной системе. Вы наверное имели в виду что-то типа "принадлежит библиотеке времени исполнения языка си, aka CRT"? Тогда да. Но тут опять-таки возникает вопрос, допустимо ли писать эту библиотеку на си? Вернее, можно ли писать на си её функции, которые будут вызываться до инициализации статических переменных и bss? Мне кажется, что это не совсем корректно.
Имел в виду что-то типа
http://en.wikipedia.org/wiki/Run-time_systemНасчет допустимости - если представить, что SystemInit - это часть RTS, а main и остальное - свой отдельный проект, то и противоречий не наблюдается.
AHTOXA
Jul 16 2012, 12:18
Если SystemInit написать на ассемблере, то не наблюдается. Иначе - противоречие есть.
Для просмотра полной версии этой страницы, пожалуйста,
пройдите по ссылке.