Gar_Ri 0 6 мая, 2009 Опубликовано 6 мая, 2009 · Жалоба Проблема такая. Имеется мое устройство и к нему может подключаться большое число других приборов. Процедура обработки и режимы работы при подключении разных приборов различаются. Соответственно требуется и разные программа для них. Программа у меня делится на общую часть характерную для всех приборов и часть для работы с конкретным прибором. Я хочу общую часть программы загружать из флешки которая на плате, а дополнительную часть программы загружать уже после через USB. Вопрос как прикрутить эту дополнительную часть программы к общей? Защить ее во внутренее озу я смогу, а вот как их правильно написать, чтобы обе части нормально между собой работали. Т.е. вопрос в том как правильно пишуться такие вещи. Пищу в CCS 3.3 под 5509A. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
SM 0 6 мая, 2009 Опубликовано 6 мая, 2009 · Жалоба Вопрос как прикрутить эту дополнительную часть программы к общей? Защить ее во внутренее озу я смогу, а вот как их правильно написать, чтобы обе части нормально между собой работали. Т.е. вопрос в том как правильно пишуться такие вещи. Я реализовывал такую задачу, и именно на таком процессоре. Делается крайне просто - по какому-то фиксированному адресу в "ядре" располагается таблица переходов, через которую вызываются функции ядра (например подключение подпрограммы к прерыванию, педерача блока по УСБ, подключение подпрограммы в цепочку подпрограмм обработки управляющих запросов от хоста, ну и т.д.). Ну функций у ядра может быть много. В загружаемом модуле - точно также - в самом начале модуля (например) имеются все необходимые точки входа, по которым может вызывать ядро этот модуль. Например начальная инициализация после загрузки, вход по idle из основного цикла, и т.п. Далее, у проекта ядра - эта таблица переходов просто описана как секция с переходами. У проекта модуля - эта секция описана точно так же, но только она не линкуется в выходной файл. То есть линкуется, но не входит в состав таблицы загрузки модуля. Таким образом модуль корректно обращается к ядру, при загрузке его не портя. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Gar_Ri 0 13 мая, 2009 Опубликовано 13 мая, 2009 · Жалоба Я реализовывал такую задачу, и именно на таком процессоре. Делается крайне просто - по какому-то фиксированному адресу в "ядре" располагается таблица переходов, через которую вызываются функции ядра (например подключение подпрограммы к прерыванию, педерача блока по УСБ, подключение подпрограммы в цепочку подпрограмм обработки управляющих запросов от хоста, ну и т.д.). Ну функций у ядра может быть много. В загружаемом модуле - точно также - в самом начале модуля (например) имеются все необходимые точки входа, по которым может вызывать ядро этот модуль. Например начальная инициализация после загрузки, вход по idle из основного цикла, и т.п. Далее, у проекта ядра - эта таблица переходов просто описана как секция с переходами. У проекта модуля - эта секция описана точно так же, но только она не линкуется в выходной файл. То есть линкуется, но не входит в состав таблицы загрузки модуля. Таким образом модуль корректно обращается к ядру, при загрузке его не портя. т.е. основной смысл работать через фиксированные адреса ? а как передавать параметры процедур между модулем и ядром и обратно, также через какой-то один фиксированный адрес? Ведь, если я правильно понял, таблица переходов представляет собой таблицу адресов процедур без параметров. Вот, например, нам в модуле надо вызвать такую процедуру ядра: proc1(Ptr param1,int param2); как я понял в модуле мы записываем param1 и param2 по конкретному адресу addr_param и вызываем переходную процедуру ядра proc1_1 (расположенную по фиксированному адресу addr_proc). proc1_1 извлекает эти параметры из адреса addr_param и уже потом вызывает proc1(Ptr param1,int param2). Но честно говоря, есть подозрения что я туплю где-то, хотелось бы узнать где. Может я не правильно понимаю что такое таблица переходов. Если можешь скинь пожалуйста как выглядит у тебя эта таблица, и как в модуле ты осуществляешь обращение к процедурам ядра. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
SM 0 13 мая, 2009 Опубликовано 13 мая, 2009 · Жалоба а как передавать параметры процедур между модулем и ядром и обратно, также через какой-то один фиксированный адрес? Ведь, если я правильно понял, таблица переходов представляет собой таблицу адресов процедур без параметров. Нет, не надо параметры по фикс. адресу передавать. Достаточно следовать соглашению о передаче параметров, принятому в C для этого процессора. Вот, например, нам в модуле надо вызвать такую процедуру ядра: proc1(Ptr param1,int param2); Просто вызываете "proc1(param1, param2). Дальше все дело линкера. файл "wrappers.asm" в проекте ядра: .arms_on .cpl_on .c54cm_off .ref __TerminalWrite, __TerminalRead,__SendControlData .global _TerminalWrite, _TerminalRead,_SendControlData .sect ".wrappers" .vli_off _TerminalWrite: b __TerminalWrite _TerminalRead: b __TerminalRead _SendControlData: b __SendControlData .end kernel.cmd: MEMORY { VECS ( IX) : origin = 000200h, length = 00300h WRAPPERS ( IX) : origin = 000500h, length = 00100h ....... SECTIONS { ....... .wrappers > WRAPPERS ...... Соответственно из модулей теперь надо вызывать к примеру TerminalWrite, а в ядре описать функцию _TerminalWrite, ну а wrappers обеспечивает переход при вызове первой на вторую. файл "wrappers.asm" в проекте модуля: .arms_on .cpl_on .c54cm_off .global _TerminalWrite, _TerminalRead .sect ".wrappers" .vli_off _TerminalWrite: nop nop nop nop _TerminalRead: nop nop nop nop _SendControlData: nop nop nop nop .end wrappers.h для модуля short TerminalWrite(short *pData, short size); short TerminalRead(short *pData, short size, short *cData); short SendControlData(PCONTROLDATA pData); линкерный cmd для модуля: MEMORY { VECS ( IX) : origin = 000200h, length = 00300h WRAPPERS ( IX) : origin = 000500h, length = 00100h ...... SECTIONS { ....... .wrappers > WRAPPERS } hex-генераторный .cmd для модуля: debug\firmware.out -i -memwidth 8 -serial8 -v5510:2 -e _c_int00 SECTIONS { .text:boot, .cinit:boot, .const:boot} Таким образом модуль линкуется корректно с вызовами нужных функций, (команда "b" и 4 нопа занимают одинаковое место) но в выходной hex-файл модуля секция wrappers не попадает, обеспечивая целостность этой секции в ядре. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
evg123 0 13 мая, 2009 Опубликовано 13 мая, 2009 · Жалоба Я реализовывал такую задачу... С вашей идеей понятно, а вот с реализацией - я не совсем понимаю как это сделать. Поэтому есть следующий вопрос: У нас в соседнем отделе (тот же проц.) возникла та же проблема. Есть прибор, который имеет "ядро" и несколько "оверлеев". "Оверлей" - этот в моём понятии - тот самый подгружаемый модуль. Их мож. быть несколько, но располагаются они по одним и тем же адресам, т.к. никогда не могут одновременно находиться в процессоре. Как сделать этот "менеджер оверлеев"? Тем более, что у нас эти оверлеи должны переключаться на лету (т.е. в процессе работы, а не в процессе загрузки), хотя и достаточно редко. Проект ядра кладётся во флэш по нулевому сектору. Проет первого оверлея - по первому сектору, проект второго - по второму. Так что я всегда знаю какой оверлей где лежит. Для певого оверлея - линкую его секции в MEMORY { PAGE 0: SARAM... }, для второго оверлея - линкую его секции в MEMORY { PAGE 1: SARAM... } и ядро линкую в MEMORY { PAGE 0: DARAM... }. Теперь из полученного исполняемого proj_name.out файла утилитой hex55 делаю три загрузочных модуля. Один - который содержит секции ядра, второй - секции овелея_1, третий - секции овелея_2. Прошиваю эти модули по нужным секторам во флэш. При загрузке - загружается только "ядро"; если оно соображает, что надо загрузить оверлей_2 - то своим "внутренним" загрузчиком загружает оверлей_2, и вызывает необходимую функцию оверлея_2 (по таблице переходов, или, возможно, напрямую, без таблицы). Далее в какой-то момент "ядро" узнаёт, что надо загрузить оверлей_1, оно своей "внутренней", "ядерной" функцией вызывает загрузчик, который загружает "оверлей_1" и потом вызывает необходимую функцию оверлея_1. И т.д. Естесственно - нельзя вызывать функции первого оверлея из второго. Я правильно рассуждаю или где-то есть грубые ошибки или подводные камни? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Gar_Ri 0 13 мая, 2009 Опубликовано 13 мая, 2009 · Жалоба to SM : Большое спасибо. Все гениальное просто, я действительно размышлял не в том направлении. Только мне кажется строчка -e _c_int00 в hex-генераторным .cmd для модуля не нужна. Мне ведь не надо, чтобы модуль сразу начал выполнялся. Мне надо,чтобы он загрузился в память и ждал своего часа. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
SM 0 13 мая, 2009 Опубликовано 13 мая, 2009 · Жалоба Только мне кажется строчка -e _c_int00 в hex-генераторным .cmd для модуля не нужна. Я использую точку входа как основную функцию модуля - таким образом я передаю ядру, что нужно вызывать у модуля во всех случаях жизни (а уже в зависимости от переданного ей параметра я там разбираюсь, что это было - начальная инициализация, или вызов по idle из основного цикла, или еще что). Ну, соответственно, стартап у модулей я переписал на свой лад, то есть ту самую _c_int00, чтобы она работала в модулях так, как мне надо, в случае вызова по инициализации выполняла С-шную инициализацию, потом main, а потом обязательно возвращалась (родная виснет в бесконечном цикле), ну и чтобы регистры стека не трогала, и прочее критичное. А в случае всех остальных вызовов - выполняла другую функцию, _kernel_call. Исходники рантайм-либы идут с композером, так что это без проблем. Второй вариант был - что _c_int00 это только инициализация, а ф-ция main возвращает ядру адрес таблицы переходов на свои функции, которые должны вызываться из ядра. Мне ведь не надо, чтобы модуль сразу начал выполнялся. Ну и не выполняйте, а просто в момент загрузки запомните точку входа. А выполните когда нибудь потом. Зато будете знать, что именно выполнять :) Я правильно рассуждаю или где-то есть грубые ошибки или подводные камни? Правильно. Только вот вовсе не стоит все в одном проекте держать, и потом разбирать его на несколько кусков. Имея такую секцию wrappers с переходами на все ф-ции ядра, можно сделать кажному оверлею свой проект. Ну и все вызовы делать через точку входа. Хранить же оверлеи есть смысл в стандартном формате TI Boot Table, который делает hex55, чтобы ядро его разбирало и грузило, сразу понимая, и где точка входа у оверлея, и куда что загрузить. Соответственно каждый оверлей тогда имеет свои .bss, .data, .const, .cinit и требует инициализации перед первым вызовом. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться