|
|
  |
Bootloader для MSP430, как написать бутлоадер для МСП430 |
|
|
|
Oct 29 2007, 20:53
|
Гуру
     
Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882

|
Цитата(CAHTA_1939 @ Oct 30 2007, 01:36)  я тут в msp430x1xx_user_guide прочитал что флеш память можно программировать если программа находится в ОЗУ... Совсем не обязательно. Программа программирования Flash может работать прямо из самой Flash. Только естественно, не из того же сектора, который в данный момент программируется. В MSP430 реализован автомат (контроллер Flash-памяти), который на время стирания/записи Flash сам тактирует ядро и подменяет текущую команду, выбираемую из Flash, командой "пустого" перехода - JMP PC. Если вы читали User's Guide, то вопрос странный. Если не читали, то стоит почитать. http://www.gaw.ru/html.cgi/txt/doc/micros/msp430/arh/5.htmЦитата(CAHTA_1939 @ Oct 30 2007, 01:36)  а кук туда ее записать? сорри если туплю... я в этом новичек и учусь... Дык банальным копированием  - скопировали код в ОЗУ и передали ему управление. Только этот кусок кода должен быть перемещаемым, т.е. работать с относительными локальными метками переходов. Ну и не быть слишком большим конечно же, помещаться в имеющийся на кристалле объем ОЗУ.
|
|
|
|
|
Nov 1 2007, 13:39
|
Участник

Группа: Участник
Сообщений: 36
Регистрация: 4-03-05
Из: Киев
Пользователь №: 3 078

|
Цитата(asket @ Oct 23 2007, 17:48)  Это мне понятно, дело здесь в другом, допустим у нас несколько сегментов:
-Z(CODE)CODE=1100-1200 -Z(CODE)MYCODE=1200-1500
По умолчанию компилятор IAR помещает стандартные и служебные функции в сегмент CODE, то есть это означает, что если программист забыл указать сегмент, то компилятор автоматом поместит в сегмент --Z(CODE)CODE, то есть мне не хотелось сильно зависеть от данного сегмента, ибо большинство функции находятся в сегменте MYCODE, придется тогда над каждой функцией писать #pragma location="MYCODE". В старой версии IAR мне понравилось тем, что распределение по сегментам определяется один раз, достаточно наверху с помошью прагмы указать сегмент и тогда все функции данного модуля окажутся в этом сегменте, а новой версии этого почему-то не нашел, приходится объявлять сегмент каждой функции, что не есть хорошо.. для Си void func_name ( void ) @ "MYCODE" { _NOP(); } недочитал %), ответ не по вопросу ...
Сообщение отредактировал NoName - Nov 1 2007, 14:12
|
|
|
|
|
Oct 5 2011, 07:31
|

Знающий
   
Группа: Свой
Сообщений: 604
Регистрация: 5-05-06
Из: Нижегородская обл.
Пользователь №: 16 819

|
Здравствуйте. Собрался писать загрузчик. Т.к. в MSP430F2410 выводы своего загрузчика находятся на P1.1 и P2.2, которые заняты. Почитав форум узнал: - что лучше делать 2 проекта (один загрузчик, другой рабочий проект), получается 2 hex файла? Первый – загрузчик - прошивается через JTAG? А после, через интерфейс загрузчика? - что-то делается с таблицами векторов. Так называемый remapping. Но так и не понял как это делается. Смею предположить, что переписывается всего лишь xcl файл. С программированием флеш памяти (INFO) знаком. Написал функцию прошивальщика с общением по UART.(Прикрепил) Правда ещё не проверял в действии. Вопросы: с чего продолжить? Как оформить таблицу векторов? Как оформить функцию прошивальщик.
--------------------
Кризис - это не отсутствие денег, а отсутствие идей! Учитесь и никаких кризисов не будет.
|
|
|
|
|
Oct 5 2011, 17:26
|
Гуру
     
Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882

|
Цитата(KARLSON @ Oct 5 2011, 12:31)  - что лучше делать 2 проекта (один загрузчик, другой рабочий проект), получается 2 hex файла? Да. Цитата(KARLSON @ Oct 5 2011, 12:31)  Первый – загрузчик - прошивается через JTAG? А после, через интерфейс загрузчика? Не обязательно. Можно обе прошивки hex-файла объединить. Ведь пересекаться по расположению в памяти они не должны. Цитата(KARLSON @ Oct 5 2011, 12:31)  - что-то делается с таблицами векторов. Так называемый remapping. Но так и не понял как это делается. Смею предположить, что переписывается всего лишь xcl файл. Не совсем так. В xcl-файле проекта пользовательского исходника нужно объявить сегмент, который компилятор не должен использовать для размещения кода. В исходнике же бутлоадера - наоборот, компилятор должен использовать только этот выделенный сегмент. На месте векторов прерываний должны быть адреса переходов. А сами обработчики прерываний располагаются где-то в другом месте (в неперезаписываемом сегменте Flash или в ОЗУ). Хотя по-моему в бутлоадере использовать прерывания это моветон, да и незачем, если только у вас нет жесткого требования обновления firmware прямо во время работы программы без прерывания ее функционирования. Хотя в этом случае образец новой firmware предварительно еще где-то сохранить нужно, проверив его на валидность. Работать в бутлоадере с UART можно и без прерываний, по опросу флагов готовности.
|
|
|
|
|
Oct 10 2011, 06:57
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
QUOTE (KARLSON @ Oct 10 2011, 08:20)  А при включении контроллера запускаться должна рабочая программа? А если ее нет или она записалась не до конца? Как раз наоборот - при включении питания запускается загрузчик, проверяет целостность рабочей программы, и если она признана живой - запускает ее. Если нет - ожидает поступления по UART (или другому интерфейсу перепрошивки) команды перепрошивки. QUOTE (KARLSON @ Oct 10 2011, 08:20)  И по команде по UART вызываться функция бутлоадера, вернее переход на адрес во флешь? Это да. Если приложение запущено, то оно запускает загрузчик по команде. Но не переходом на его main(), а переходом на начало его стартап-кода, который штатно подготовит ОЗУ для запуска main() загрузчика.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Oct 10 2011, 11:34
|

Знающий
   
Группа: Свой
Сообщений: 604
Регистрация: 5-05-06
Из: Нижегородская обл.
Пользователь №: 16 819

|
И так. Создаю пример. Вопрос: правильно ли прописаны xcl файлы? Как вызвать в загрузчике приложение и наоборот))Msp430F2410 описание памяти: // Interrupt vectors: 32 // Peripheral units: 0-01FF // Information memory (FLASH): 1000-10FF // Read/write memory (RAM): 1100-20FF // Read-only memory (FLASH): 2100-FFFF Bootloader Код #include <io430.h> #include "Titl.h" #include "function.cpp" #include "UART0.cpp"
void main( void ) { WDTCTL = WDTPW + WDTHOLD; Init_DCO_16MHz(); Init_USCI_A0(); Init_FLASH(); P3OUT = 0; P3DIR = BIT3; if (Check_Flash()) {// проверка прошла удачно // переход в приложение } else {// неудачная проверка // ждём команду по UART перепрошивки _EINT(); while(1) { for(unsigned int i=0; i<65000; i++); for(unsigned int i=0; i<65000; i++); P3OUT ^= BIT3; } } } xcl файл Bootloader Код // ------------------------------------- // Code // -Z(CODE)CSTART,ISR_CODE,CODE_ID=EC00-FFBF -P(CODE)CODE=EC00-FFBF
// ------------------------------------- // Interrupt vectors // -Z(CODE)INTVEC=FFC0-FFFF -Z(CODE)RESET=FFFE-FFFF Приложение Код #include <io430.h> #include "Titl.h" #include "function.cpp" #include "UART0.cpp"
void main( void ) { WDTCTL = WDTPW + WDTHOLD; Init_DCO_16MHz(); Init_USCI_A0(); P3OUT = 0; P3DIR = BIT3; _EINT(); while(1) {// приложение for(unsigned int i=0; i<65000; i++); for(unsigned int i=0; i<65000; i++); P3OUT ^= BIT3; } }
#pragma vector = USCIAB0RX_VECTOR __interrupt void USCIA0_RX(void) {//1 if(UCA0STAT&UCADDR) {//2 Clovo_Data_RX0=0; //--------------------------------------------------- switch(UCA0RXBUF) { case 0: // команда для прошивке // переход на прошивку UCA0CTL1 &=~ UCDORM; //Переключиться на прием неадресных символов break; default: break; } }//2 }// 1 xcl файл Приложения Код // ------------------------------------- // Code //
-Z(CODE)CSTART,ISR_CODE,CODE_ID=2200-EBFF -P(CODE)CODE=2200-EBFF
// ------------------------------------- // Interrupt vectors //
-Z(CODE)INTVEC=21C0-21FF -Z(CODE)RESET=21FE-21FF
--------------------
Кризис - это не отсутствие денег, а отсутствие идей! Учитесь и никаких кризисов не будет.
|
|
|
|
|
Oct 10 2011, 19:44
|
Гуру
     
Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882

|
Цитата(KARLSON @ Oct 10 2011, 16:34)  И так. Создаю пример. Bootloader на плюсах?  Весьма оригинально! Цитата(KARLSON @ Oct 10 2011, 16:34)  Вопрос: правильно ли прописаны xcl файлы? Как вызвать в загрузчике приложение и наоборот)) main для приложения должена компилироваться как функция по заранее определенному адресу. Тогда не составляет сложности вызвать эту функцию по указателю. О том, как разместить функцию по определенному адресу, написано в разделах Placing code and data и Pragma directives документа EW430_CompilerReference.pdf. Обязательно следует учитывать, что еще до вызова функции main в скомпилированной программе сначала выполняется установка/инициализация указателя стека, затем вызывается функция low_level_init, а потом выполняется функция очистки и начальной инициализации глобальных и статических переменных (?cstart_init_zero). Так что если вы будете вызывать пользовательскую программу по адресу main, то вышеописанные функции вам придется реализовывать "вручную". Ну либо ищите как можно узнать или зарезервировать адрес метки __program_start (?cstart_begin в случае С), которая располагается по адресу перехода от вектора прерывания RESET и с которой начинается выполнение программы. Обычно эта метка совпадает с началом сегмента CODE. Все это справедливо лишь для "чистого" Си. C++ для программирования MSP430 я ни разу не использовал.
|
|
|
|
|
Oct 11 2011, 06:12
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
QUOTE (rezident @ Oct 10 2011, 22:44)  Bootloader на плюсах?  Весьма оригинально! Ой, да бросьте. Гораздо удобнее чем на обычных Сях. Накладных расходов нет, если пользоваться головой. QUOTE (rezident @ Oct 10 2011, 22:44)  main для приложения должена компилироваться как функция по заранее определенному адресу. Тогда не составляет сложности вызвать эту функцию по указателю. Зачем? Достаточно перейти по тому адресу, который находится в векторе Reset приложения. И все необходимые действия (cstartup) будут выполнены, и адрес этого вектора известен. KARLSON: Включать .cpp в другие файлы - путь в корне неправильный. Вам необходимо почитать про заголовочные (header) файлы и раздельную компиляцию. CODE -Z(CODE)INTVEC=FFC0-FFFF -Z(CODE)RESET=FFFE-FFFF Бить область векторов на две (выделать вектор сброса в отдельную область) не обязательно. Мне кажется вторая строка лишняя - вектор сброса компилятор тоже кладет в INTVEC. Во втором файле то же самое. Но идею вы ухватили верно. И подумайте, как быть с прерываниями - у приложения будут свои обработчики и их надо вызывать, а "настоящие" вектора находятся в области загрузчика. Я на GCC делал так: CODE __attribute__ ((section(".app_vectors"))) struct { flash_t::address_t App_image_size; void *Vectors[INT_VECTORS_COUNT - 1]; void (*ResetVector)(); } Application;
#define TRAMP(name, vector) \ extern "C" __attribute__((__naked__)) void Tramp_##name() \ { \ asm volatile("BR %0\n\t" ::"m"(InterruptVectors[vector])); \ }
TRAMP(DAC12, 0); TRAMP(DMA, 1); TRAMP(USCIAB1TX_VECTOR, 2); TRAMP(USCIAB1RX_VECTOR, 3); ..... typedef void (*vector_t)();
__attribute__ ((section(".vectors"))) extern vector_t const VectorTable[INT_VECTORS_COUNT] = { Tramp_DAC12, Tramp_DMA, Tramp_USCIAB1TX_VECTOR, Tramp_USCIAB1RX_VECTOR, Вы можете сделать что-то подобное в отдельном асм-файле. Если загрузчику тоже нужны обработчики прерываний, то надо копировать вектора нужной части программы в ОЗУ и адрес для этого перехода брать из ОЗУ: CODE if (!crc) // Application Section crc ok { DRIVER(MANUAL_BOOT, OUTPUT); // set MANUAL_PROG as output uint_fast8_t i = INT_VECTORS_COUNT - 1; // do not copy reset vector while(i--) { InterruptVectors[i] = Application.Vectors[i]; } Application.ResetVector(); } Не забудьте запретить прерывания перед переходом из приложения в загрузчик.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Oct 11 2011, 17:32
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
QUOTE (rezident @ Oct 11 2011, 18:08)  В векторе сброса располагается адрес старта бутлоадера, а не пользовательского приложения. Или я что-то не понимаю?  В векторе Reset приложения. Приложение ведь имеет свой полный комплект векторов, в том числе и вектор Reset c адресом перехода как раз в нужную точку старта. У меня так
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Oct 11 2011, 22:32
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
QUOTE (rezident @ Oct 11 2011, 20:59)  Дык ведь тогда вектора RESET бутлоадера и приложения будут наложены друг на друга. Ну почему же? Посмотрите сообщение №24 - две программы, две таблицы векторов по разным адресам. А... кажется понял. У нас несколько разная трактовка понятия "вектор". Я под вектором подразумеваю содержимое, т.е. сам адрес "куда переходить", а не саму ячейку, т.е. "адрес, из которого процессор берет адрес перехода". Поэтому и таблица "моих" векторов у приложения может быть своя, совершенно независимая. Да, адреса из таблицы приложения берутся не аппаратно, а посредством функций-помошников ("трамплинов"), указатели на которые сидят на "железных", "ваших"  векторах. Во всяком случае такой подход позволяет ценой одного дополнительного косвенного перехода и двух байт ОЗУ на каждый вектор иметь совершенно независимые обработчики у приложения и загрузчика. Причем в целях экономии ОЗУ таким образом можно охватить не всю таблицу, а лишь физически реализованные в процессоре прерывания.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
  |
2 чел. читают эту тему (гостей: 2, скрытых пользователей: 0)
Пользователей: 0
|
|
|