реклама на сайте
подробности

 
 
3 страниц V   1 2 3 >  
Reply to this topicStart new topic
> Bootloader для MSP430, как написать бутлоадер для МСП430
asket
сообщение Oct 15 2007, 10:09
Сообщение #1


Частый гость
**

Группа: Участник
Сообщений: 91
Регистрация: 24-08-06
Из: Москва
Пользователь №: 19 809



Я в этом деле новичок, недавно начал заниматься этой деятельностью, мне поручили написать Bootloader. Задача: имеется шина, будь это COM-порт или собственная шина, не важно какая, нужно по данной шине закачать с компьютера прошивку и залить его во флеш в целях ее обновления, вопрос: как это сделать это по умному? Кто и что посоветует? Может примерчик какой-нить.. К сожалению в отличии от других процев у MSP430 встроенных бутлоадеров я так понимаю нету. Компилятор IAR 3.42.

Заранее благодарен.
Go to the top of the page
 
+Quote Post
VAI
сообщение Oct 15 2007, 10:36
Сообщение #2


Профессионал
*****

Группа: Модераторы
Сообщений: 1 120
Регистрация: 17-06-04
Пользователь №: 37



Цитата
К сожалению в отличии от других процев у MSP430 встроенных бутлоадеров я так понимаю нету.

Плохо понимаете. Есть Bootstrap Loader.
Последний абзац п.п.21 FAQ http://www.gaw.ru/html.cgi/txt/doc/micros/msp430/faq.htm#21

http://focus.ti.com/mcu/docs/mcusupporttec...ctName=slaa089d
http://focus.ti.com/mcu/docs/mcusupporttec...ctName=slaa096d

На русском, немного устарело.. http://www.gaw.ru/html.cgi/txt/app/micros/msp430/slaa089.htm


--------------------
Если зайца бить, его можно и спички научить зажигать
Сколько дурака не бей - умнее не будет. Зато опытнее
Go to the top of the page
 
+Quote Post
asket
сообщение Oct 15 2007, 11:12
Сообщение #3


Частый гость
**

Группа: Участник
Сообщений: 91
Регистрация: 24-08-06
Из: Москва
Пользователь №: 19 809



Цитата(VAI @ Oct 15 2007, 14:36) *


Это то понятно, там целое шаманство производить надо и со схемкой, и с программкой, чтоб программить с командной строки, а у меня задача другая стоит: на объекте используется аппарат, который висит на собственной шине, чтоб не ездить за обновлением прошивки, пользователь скачивает из интернета hex, и с помошью нашей же программы закачивает удаленно прошивку по адресу этого устройства, далее я понимаю так, что эту прошивку надо собирать в отдельном файле, проверить контрольную сумму и запустить программный бутлоадер, чтоб он эту прошивку залил, но возможна ситуация, когда на шине пропадает питание, здесь на помошь приходит опять таки бутолоадер, который проверяет CRC прошивки и выдает код ошибки пользователю, то етсь таким образом устройство продолжает работу дальше.. Проблема здесь в том, что как это сделать правильно, у меня попытка очистить флеш по адресу 0x1100 и залить туда код с оперативки (традиционным способом) не увенчалось успехом, после перезагрузки проц вообще перестал работать, приходится перепрошивать чеез JTAG.. Прошивку из шины я пытаюсь сохранять во внешней EEPROM, ибо 64 Кб - маловато для этих целей.. Забыл про проц MSP430f149.

Спасибо.
Go to the top of the page
 
+Quote Post
rezident
сообщение Oct 15 2007, 12:11
Сообщение #4


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



asket, вы сначала разберитесь как внутрипрограммно программировать Flash MSP430 в принципе. Когда разберетесь с принципом (на INFO тренируйтесь), то тогда и приступайте к написанию своего BootLoader. Только предполагаю, что вы наверняка наступите на грабли НЕперемещаемых векторов прерываний. Поищите здесь тему про то как в MSP430 организуются перемещаемые вектора. Оно точно тут было год-полтора назад.
Go to the top of the page
 
+Quote Post
asket
сообщение Oct 15 2007, 12:50
Сообщение #5


Частый гость
**

Группа: Участник
Сообщений: 91
Регистрация: 24-08-06
Из: Москва
Пользователь №: 19 809



Цитата(rezident @ Oct 15 2007, 16:11) *
asket, вы сначала разберитесь как внутрипрограммно программировать Flash MSP430 в принципе. Когда разберетесь с принципом (на INFO тренируйтесь), то тогда и приступайте к написанию своего BootLoader. Только предполагаю, что вы наверняка наступите на грабли НЕперемещаемых векторов прерываний. Поищите здесь тему про то как в MSP430 организуются перемещаемые вектора. Оно точно тут было год-полтора назад.


Благодарю за совет!) Буду разбираться, правда, время поджимает, судя по ответам похоже этим либо занимались либо редко, либо никто.. А вот по поводу перемешаемых векторов я как то не подумал, спасибо, что обратили внимание на этот факт...)
Go to the top of the page
 
+Quote Post
VAI
сообщение Oct 15 2007, 13:21
Сообщение #6


Профессионал
*****

Группа: Модераторы
Сообщений: 1 120
Регистрация: 17-06-04
Пользователь №: 37



Нашел на http://tech.groups.yahoo.com/group/msp430/
Коментарий: "Code for an ISR jump table in RAM"
может поможет.
Прикрепленные файлы
Прикрепленный файл  vectors.zip ( 4.73 килобайт ) Кол-во скачиваний: 206
 


--------------------
Если зайца бить, его можно и спички научить зажигать
Сколько дурака не бей - умнее не будет. Зато опытнее
Go to the top of the page
 
+Quote Post
asket
сообщение Oct 15 2007, 13:56
Сообщение #7


Частый гость
**

Группа: Участник
Сообщений: 91
Регистрация: 24-08-06
Из: Москва
Пользователь №: 19 809



Цитата(VAI @ Oct 15 2007, 17:21) *
Нашел на http://tech.groups.yahoo.com/group/msp430/
Коментарий: "Code for an ISR jump table in RAM"
может поможет.


Огромное Вам спасибо за помощь!

И еще вопрос: где бы найти описание формата пакета с прошивками например Intel Standart или Intel Extended? Там конечно разбираться то нечего, только вот хотелось бы понять по какому алгоритму считают CRC и что за байт кроется между адресом и данными?

Вот первая строчка откомпилированного кода по стандарту hex-Extended:
101100003140000A3C401A023E407E05B012B4E76E, я понял так что
0x10 - длина данных,
0x1100 - адрес
0x00 - ?
данные - сама прошивка 16 байт
0x6E - CRC
Go to the top of the page
 
+Quote Post
rezident
сообщение Oct 15 2007, 18:40
Сообщение #8


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



Цитата(asket @ Oct 15 2007, 19:56) *
И еще вопрос: где бы найти описание формата пакета с прошивками например Intel Standart или Intel Extended? Там конечно разбираться то нечего, только вот хотелось бы понять по какому алгоритму считают CRC и что за байт кроется между адресом и данными?

Дык как обычно Гугель рулит wink.gif
http://pages.interlog.com/~speff/usefulinfo/Hexfrmt.pdf
Go to the top of the page
 
+Quote Post
asket
сообщение Oct 19 2007, 08:10
Сообщение #9


Частый гость
**

Группа: Участник
Сообщений: 91
Регистрация: 24-08-06
Из: Москва
Пользователь №: 19 809



Цитата(rezident @ Oct 15 2007, 22:40) *
Дык как обычно Гугель рулит wink.gif
http://pages.interlog.com/~speff/usefulinfo/Hexfrmt.pdf


Окей, спасибо огромное! Кое что стало проясняться.. Еще один вопрос, извиняюсь, чисто ламерский: каким способом программно определить размер той или иной функции? Допустим знаем адрес раположения этой функции, и нужно будет определить размер этой функции, пробывал использовать sizeof(), ругается что операнд не может быть функцией, каким способом можно определить?
Go to the top of the page
 
+Quote Post
asket
сообщение Oct 19 2007, 14:56
Сообщение #10


Частый гость
**

Группа: Участник
Сообщений: 91
Регистрация: 24-08-06
Из: Москва
Пользователь №: 19 809



Неужели останусь без ответа и привета?wink.gif

Сообщение отредактировал asket - Oct 19 2007, 14:57
Go to the top of the page
 
+Quote Post
SSerge
сообщение Oct 19 2007, 19:16
Сообщение #11


Профессионал
*****

Группа: Свой
Сообщений: 1 719
Регистрация: 13-09-05
Из: Novosibirsk
Пользователь №: 8 528



Узнать размер именно функции нельзя.
Но можно указать компилятору разместить интересующую функцию в отдельном сегменте
#pragma location="MYSEGMENT"

и потом вычислить размер сегмента.

У IAR для этого есть встроенные псевдо-функции
__segment_begin(segment) и __segment_end(segment)

Кроме того потребуется объяснить линкеру в .xcl-файле что у него появился ещё один сегмент кода
-Z(CODE)MYSEGMENT=....

Читайте EW430_CompilerReference.pdf


--------------------
Russia est omnis divisa in partes octo.
Go to the top of the page
 
+Quote Post
msalov
сообщение Oct 22 2007, 06:19
Сообщение #12


Знающий
****

Группа: Свой
Сообщений: 526
Регистрация: 24-08-07
Из: Беларусь, Минск
Пользователь №: 30 045



Цитата(asket @ Oct 19 2007, 11:10) *
Окей, спасибо огромное! Кое что стало проясняться.. Еще один вопрос, извиняюсь, чисто ламерский: каким способом программно определить размер той или иной функции? Допустим знаем адрес раположения этой функции, и нужно будет определить размер этой функции, пробывал использовать sizeof(), ругается что операнд не может быть функцией, каким способом можно определить?


Если программа написана на ассемблере, то размер можно узнать:
поставить метки в начале и конце функции, а где необходимо -- вычислить разность меток, это и будет "размер" или точнее "размер кода" функции. Пример:
Код
    mov #STOP,R7
    sub #START,R7
START:        ; просто любая функция
    push R4
    push R5
    mov R5,R4
    pop R5
    pop R4
STOP:
    ret


В R7 -- результат

Сообщение отредактировал gotty - Oct 22 2007, 06:20
Go to the top of the page
 
+Quote Post
asket
сообщение Oct 23 2007, 13:27
Сообщение #13


Частый гость
**

Группа: Участник
Сообщений: 91
Регистрация: 24-08-06
Из: Москва
Пользователь №: 19 809



Еще такой вопрос по поводу сегментации флеш-памяти, компилер IAR по умолчанию ставит сегмент CODE и размещает туда все функции, если они явно пользователем не указаны в каком сегменте их расположить, но мне не понравилось тот факт, что IAR без ведома пихает стандартные функции, и если его стереть, то фактически программа без них не будет нормально работать. Как указать компилятору в какой сегмент нужно раположить эти функции?
Go to the top of the page
 
+Quote Post
msalov
сообщение Oct 23 2007, 14:16
Сообщение #14


Знающий
****

Группа: Свой
Сообщений: 526
Регистрация: 24-08-07
Из: Беларусь, Минск
Пользователь №: 30 045



Цитата(asket @ Oct 23 2007, 16:27) *
Еще такой вопрос по поводу сегментации флеш-памяти, компилер IAR по умолчанию ставит сегмент CODE и размещает туда все функции, если они явно пользователем не указаны в каком сегменте их расположить, но мне не понравилось тот факт, что IAR без ведома пихает стандартные функции, и если его стереть, то фактически программа без них не будет нормально работать. Как указать компилятору в какой сегмент нужно раположить эти функции?


Можно изменить сегмент CODE (начальный и конечный адреса), таким образом, что бы он отвечал Вашим требованиям. Это можно проделать при помощи параметра линкера:
Код
-Z(CODE)MYCODE=4000-5000


Сообщение отредактировал gotty - Oct 23 2007, 14:28
Go to the top of the page
 
+Quote Post
asket
сообщение Oct 23 2007, 15:48
Сообщение #15


Частый гость
**

Группа: Участник
Сообщений: 91
Регистрация: 24-08-06
Из: Москва
Пользователь №: 19 809



Цитата(gotty @ Oct 23 2007, 18:16) *
Можно изменить сегмент CODE (начальный и конечный адреса), таким образом, что бы он отвечал Вашим требованиям. Это можно проделать при помощи параметра линкера:
Код
-Z(CODE)MYCODE=4000-5000


Это мне понятно, дело здесь в другом, допустим у нас несколько сегментов:

-Z(CODE)CODE=1100-1200
-Z(CODE)MYCODE=1200-1500

По умолчанию компилятор IAR помещает стандартные и служебные функции в сегмент CODE, то есть это означает, что если программист забыл указать сегмент, то компилятор автоматом поместит в сегмент --Z(CODE)CODE, то есть мне не хотелось сильно зависеть от данного сегмента, ибо большинство функции находятся в сегменте MYCODE, придется тогда над каждой функцией писать #pragma location="MYCODE". В старой версии IAR мне понравилось тем, что распределение по сегментам определяется один раз, достаточно наверху с помошью прагмы указать сегмент и тогда все функции данного модуля окажутся в этом сегменте, а новой версии этого почему-то не нашел, приходится объявлять сегмент каждой функции, что не есть хорошо..
Go to the top of the page
 
+Quote Post
CAHTA_1939
сообщение Oct 29 2007, 20:36
Сообщение #16


Частый гость
**

Группа: Участник
Сообщений: 142
Регистрация: 11-08-07
Пользователь №: 29 713



я тут в msp430x1xx_user_guide прочитал что флеш память можно программировать если программа находится в ОЗУ...
а кук туда ее записать?
сорри если туплю... я в этом новичек и учусь...
Go to the top of the page
 
+Quote Post
rezident
сообщение Oct 29 2007, 20:53
Сообщение #17


Гуру
******

Группа: Свой
Сообщений: 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) *
а кук туда ее записать?
сорри если туплю... я в этом новичек и учусь...

Дык банальным копированием smile.gif - скопировали код в ОЗУ и передали ему управление. Только этот кусок кода должен быть перемещаемым, т.е. работать с относительными локальными метками переходов. Ну и не быть слишком большим конечно же, помещаться в имеющийся на кристалле объем ОЗУ.
Go to the top of the page
 
+Quote Post
АДИКМ
сообщение Oct 30 2007, 13:13
Сообщение #18


Знающий
****

Группа: Свой
Сообщений: 630
Регистрация: 2-08-05
Пользователь №: 7 294



Если Вам надо быстрое блочное программирование, тогда программа должна выполняться только из рам.
Если достаточно байтового/пословного программирования, тогда можно выполнять из флеш.


--------------------
летаю на пепелаце...
Go to the top of the page
 
+Quote Post
NoName
сообщение Nov 1 2007, 13:39
Сообщение #19


Участник
*

Группа: Участник
Сообщений: 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
Go to the top of the page
 
+Quote Post
KARLSON
сообщение Oct 5 2011, 07:31
Сообщение #20


Знающий
****

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



Здравствуйте. Собрался писать загрузчик. Т.к. в MSP430F2410 выводы своего загрузчика находятся на P1.1 и P2.2, которые заняты.
Почитав форум узнал:
- что лучше делать 2 проекта (один загрузчик, другой рабочий проект), получается 2 hex файла? Первый – загрузчик - прошивается через JTAG? А после, через интерфейс загрузчика?
- что-то делается с таблицами векторов. Так называемый remapping. Но так и не понял как это делается. Смею предположить, что переписывается всего лишь xcl файл.
С программированием флеш памяти (INFO) знаком.
Написал функцию прошивальщика с общением по UART.(Прикрепил) Правда ещё не проверял в действии.
Вопросы: с чего продолжить? Как оформить таблицу векторов? Как оформить функцию прошивальщик.

Прикрепленные файлы
Прикрепленный файл  Program_FLASH.rar ( 1.3 килобайт ) Кол-во скачиваний: 51
 


--------------------
Кризис - это не отсутствие денег, а отсутствие идей! Учитесь и никаких кризисов не будет.
Go to the top of the page
 
+Quote Post
rezident
сообщение Oct 5 2011, 17:26
Сообщение #21


Гуру
******

Группа: Свой
Сообщений: 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 можно и без прерываний, по опросу флагов готовности.
Go to the top of the page
 
+Quote Post
KARLSON
сообщение Oct 10 2011, 05:20
Сообщение #22


Знающий
****

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



При двух проектах, ведь будет две функции main();
А при включении контроллера запускаться должна рабочая программа? И по команде по UART вызываться функция бутлоадера, вернее переход на адрес во флешь?


--------------------
Кризис - это не отсутствие денег, а отсутствие идей! Учитесь и никаких кризисов не будет.
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Oct 10 2011, 06:57
Сообщение #23


Гуру
******

Группа: Модераторы
Сообщений: 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)
Go to the top of the page
 
+Quote Post
KARLSON
сообщение Oct 10 2011, 11:34
Сообщение #24


Знающий
****

Группа: Свой
Сообщений: 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





--------------------
Кризис - это не отсутствие денег, а отсутствие идей! Учитесь и никаких кризисов не будет.
Go to the top of the page
 
+Quote Post
rezident
сообщение Oct 10 2011, 19:44
Сообщение #25


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



Цитата(KARLSON @ Oct 10 2011, 16:34) *
И так. Создаю пример.
Bootloader на плюсах? wacko.gif Весьма оригинально!
Цитата(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 я ни разу не использовал.
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Oct 11 2011, 06:12
Сообщение #26


Гуру
******

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



QUOTE (rezident @ Oct 10 2011, 22:44) *
Bootloader на плюсах? wacko.gif Весьма оригинально!
Ой, да бросьте. Гораздо удобнее чем на обычных Сях. Накладных расходов нет, если пользоваться головой.
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)
Go to the top of the page
 
+Quote Post
rezident
сообщение Oct 11 2011, 15:08
Сообщение #27


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



Цитата(Сергей Борщ @ Oct 11 2011, 11:12) *
Зачем? Достаточно перейти по тому адресу, который находится в векторе Reset приложения. И все необходимые действия (cstartup) будут выполнены, и адрес этого вектора известен.
В векторе сброса располагается адрес старта бутлоадера, а не пользовательского приложения. Или я что-то не понимаю? laughing.gif
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Oct 11 2011, 17:32
Сообщение #28


Гуру
******

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



QUOTE (rezident @ Oct 11 2011, 18:08) *
В векторе сброса располагается адрес старта бутлоадера, а не пользовательского приложения. Или я что-то не понимаю? laughing.gif
В векторе Reset приложения. Приложение ведь имеет свой полный комплект векторов, в том числе и вектор Reset c адресом перехода как раз в нужную точку старта.
У меня так laughing.gif


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
rezident
сообщение Oct 11 2011, 17:59
Сообщение #29


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



Цитата(Сергей Борщ @ Oct 11 2011, 22:32) *
В векторе Reset приложения. Приложение ведь имеет свой полный комплект векторов, в том числе и вектор Reset c адресом перехода как раз в нужную точку старта.
Дык ведь тогда вектора RESET бутлоадера и приложения будут наложены друг на друга.
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Oct 11 2011, 22:32
Сообщение #30


Гуру
******

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



QUOTE (rezident @ Oct 11 2011, 20:59) *
Дык ведь тогда вектора RESET бутлоадера и приложения будут наложены друг на друга.
Ну почему же? Посмотрите сообщение №24 - две программы, две таблицы векторов по разным адресам.
А... кажется понял. У нас несколько разная трактовка понятия "вектор". Я под вектором подразумеваю содержимое, т.е. сам адрес "куда переходить", а не саму ячейку, т.е. "адрес, из которого процессор берет адрес перехода". Поэтому и таблица "моих" векторов у приложения может быть своя, совершенно независимая. Да, адреса из таблицы приложения берутся не аппаратно, а посредством функций-помошников ("трамплинов"), указатели на которые сидят на "железных", "ваших" wink.gif векторах. Во всяком случае такой подход позволяет ценой одного дополнительного косвенного перехода и двух байт ОЗУ на каждый вектор иметь совершенно независимые обработчики у приложения и загрузчика. Причем в целях экономии ОЗУ таким образом можно охватить не всю таблицу, а лишь физически реализованные в процессоре прерывания.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
rezident
сообщение Oct 11 2011, 23:16
Сообщение #31


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



Нет, Сергей, как сделать "перемещаемые" вектора прерываний я лично понимаю. Для пользовательского приложения "аппаратные" вектора прерываний как таковые вообще не используются. Пишутся лишь функции-обработчики прерываний, адреса которых "раскладываются" в таблицу переходов, расположенную в ОЗУ.
У ТС же возник вопрос по совмещению двух проектов/прошивок в одном кристалле и вызове одного из другого. Как я понял, ты предлагаешь замещать вектор сброса тем, который генерируется при компиляции именно бутлоадера. А то содержимое вектора RESET, которое компилируется в пользовательском приложении из прошивки выкинуть, использовав его лишь как адрес для старта приложения. Так?
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Oct 12 2011, 06:14
Сообщение #32


Гуру
******

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



QUOTE (rezident @ Oct 12 2011, 02:16) *
Нет, Сергей, как сделать "перемещаемые" вектора прерываний я лично понимаю. Для пользовательского приложения "аппаратные" вектора прерываний как таковые вообще не используются. Пишутся лишь функции-обработчики прерываний, адреса которых "раскладываются" в таблицу переходов, расположенную в ОЗУ.
Верно. И раскладывает их туда загрузчик перед тем, как запустить приложение. И берет он их из таблицы, которая расположена в фиксированном месте приложения. И таблицей этой является содержимое сегмента INTVEC приложения.
QUOTE (rezident @ Oct 12 2011, 02:16) *
У ТС же возник вопрос по совмещению двух проектов/прошивок в одном кристалле и вызове одного из другого. Как я понял, ты предлагаешь замещать вектор сброса тем, который генерируется при компиляции именно бутлоадера. А то содержимое вектора RESET, которое компилируется в пользовательском приложении из прошивки выкинуть, использовав его лишь как адрес для старта приложения. Так?
Зачем же выбрасывать и замещать? Пусть он лежит в таблице векторов приложения. Тогда загрузчик точно будет знать, откуда его брать. Вот смотрите, я в сообщении №26 давал пример. Вот структура таблицы векторов приложения, т.е. полное содержимое сегмента INTVEC приложения:
CODE
__attribute__ ((section(".app_vectors"))) struct
{
    void *Vectors[INT_VECTORS_COUNT - 1];
    void (*ResetVector)();
} Application;
Тут и все вектора прерываний и вектор сброса.

Вот загрузчик копирует эту таблицу в ОЗУ, в то место, откуда берут адреса функции-трамплины:
CODE
        uint_fast8_t i = INT_VECTORS_COUNT - 1; // do not copy reset vector
        while(i--)
        {
            InterruptVectors[i] = Application.Vectors[i];
        }

А вот из этой же таблицы берется адрес, на который надо перейти для старта приложения:
CODE
Application.ResetVector();


А "железный" вектор RESET указывает на старт загрузчика. Тогда и приложение знает, как запустить загрузчик - адрес его точки входа всегда лежит в ячейках по адресу 0xFFFE.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
KARLSON
сообщение Oct 12 2011, 12:42
Сообщение #33


Знающий
****

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



А что делает запись ((void(*)() )0x2200)();?
Если после программировании в бутлоадере с помощью этой записи обратиться к инструкции по адресу 0x2200 ( от куда и начинается приложение) старт приложения с инициализацией произойдёт?


--------------------
Кризис - это не отсутствие денег, а отсутствие идей! Учитесь и никаких кризисов не будет.
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Oct 12 2011, 13:07
Сообщение #34


Гуру
******

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



QUOTE (KARLSON @ Oct 12 2011, 15:42) *
А что делает запись ((void(*)() )0x2200)();?
Вызов функции вида void func(void), расположенной по адресу 2200.
QUOTE (KARLSON @ Oct 12 2011, 15:42) *
Если после программировании в бутлоадере с помощью этой записи обратиться к инструкции по адресу 0x2200 ( от куда и начинается приложение) старт приложения с инициализацией произойдёт?
Если по адресу 0x2200 расположена первая инструкция стартапа. Если же там располагается указатель на адрес точки входа (как было бы, если бы там располагался) вектор сброса, то запись должна была бы быть несколько иной: ((void(**)() )0x2200)().


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
KARLSON
сообщение Oct 13 2011, 06:35
Сообщение #35


Знающий
****

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



Захотел я сделать прошивку с переходами между приложениями пока без использовании прерываний:
приложение 1
Код
#include "io430.h"

void main( void )
{
  // Stop watchdog timer to prevent time out reset
  WDTCTL = WDTPW + WDTHOLD;
  P1DIR = BIT0;
  P1OUT = BIT0;
  char j=0;
  unsigned int k = 40000, z=2;
  
  while(1)
  {
    for(unsigned int i=0; i<k; i++);
    for(unsigned int i=0; i<z; i++);
    P1OUT ^= BIT0;
    ++j;
    if(j == 30)
    {
      ((void(*)() )0x2200)();
    }
  }
}

xcl файл приложения 1
Код
// -----------------------------------------------
// Read/write memory
//

-Z(DATA)DATA16_I,DATA16_Z,DATA16_N,DATA16_HEAP+_DATA16_HEAP_SIZE=1100-20FF
-Z(DATA)CODE_I
-Z(DATA)CSTACK+_STACK_SIZE#

// -------------------------------------
// Constant data
//

-Z(CONST)DATA16_C,DATA16_ID,DIFUNCT,CHECKSUM=2100-FFBF

// -------------------------------------
// 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

прошивка приложения 1
Код
@EC00
31 40 00 21 B0 12 0C EC B0 12 4E EC 0A 12 0B 12
08 12 B2 40 80 5A 20 01 D2 43 22 00 D2 43 21 00
4A 43 3B 40 40 9C 28 43 0B 3C 1F 53 0F 98 FD 2B
D2 E3 21 00 5A 53 7A 90 1E 00 02 20 B0 12 00 22
0F 43 01 3C 1F 53 0F 9B FD 2B 0F 43 EF 3F 30 40
52 EC 30 40 56 EC FF 3F
@FFFE
00 EC


приложение 2
Код
#include "io430.h"

void main( void )
{
  // Stop watchdog timer to prevent time out reset
  WDTCTL = WDTPW + WDTHOLD;
  P1DIR = BIT0;
  P1OUT = BIT0;
  char j=0;
  unsigned int k = 65535, z=65535;
  
  while(1)
  {
    for(unsigned int i=0; i<k; i++);
    for(unsigned int i=0; i<z; i++);
    P1OUT ^= BIT0;
    ++j;
    if(j == 30)
    {
      ((void(*)() )0xEC00)();
    }
  }
}


xcl файл приложения 2
Код
// -----------------------------------------------
// Read/write memory
//

-Z(DATA)DATA16_I,DATA16_Z,DATA16_N,DATA16_HEAP+_DATA16_HEAP_SIZE=1100-20FF
-Z(DATA)CODE_I
-Z(DATA)CSTACK+_STACK_SIZE#

// -------------------------------------
// Constant data
//

-Z(CONST)DATA16_C,DATA16_ID,DIFUNCT,CHECKSUM=2200-9FBF

// -------------------------------------
// Code
//
-Z(CODE)CSTART,ISR_CODE,CODE_ID=2200-9FBF
-P(CODE)CODE=2200-9FBF

// -------------------------------------
// Interrupt vectors
//
-Z(CODE)INTVEC=9FC0-9FFF
-Z(CODE)RESET=9FFE-9FFF


прошивка приложения 2
Код
@2200
31 40 00 21 B0 12 0C 22 B0 12 4C 22 0A 12 0B 12
08 12 B2 40 80 5A 20 01 D2 43 22 00 D2 43 21 00
4A 43 3B 43 38 43 0B 3C 1F 53 0F 98 FD 2B D2 E3
21 00 5A 53 7A 90 1E 00 02 20 B0 12 00 EC 0F 43
01 3C 1F 53 0F 9B FD 2B 0F 43 EF 3F 30 40 50 22
30 40 54 22 FF 3F
@9FFE
00 22
q


общая прошивка
Код
@2200
31 40 00 21 B0 12 0C 22 B0 12 4C 22 0A 12 0B 12
08 12 B2 40 80 5A 20 01 D2 43 22 00 D2 43 21 00
4A 43 3B 43 38 43 0B 3C 1F 53 0F 98 FD 2B D2 E3
21 00 5A 53 7A 90 1E 00 02 20 B0 12 00 EC 0F 43
01 3C 1F 53 0F 9B FD 2B 0F 43 EF 3F 30 40 50 22
30 40 54 22 FF 3F
@9FFE
00 22
@EC00
31 40 00 21 B0 12 0C EC B0 12 4E EC 0A 12 0B 12
08 12 B2 40 80 5A 20 01 D2 43 22 00 D2 43 21 00
4A 43 3B 40 40 9C 28 43 0B 3C 1F 53 0F 98 FD 2B
D2 E3 21 00 5A 53 7A 90 1E 00 02 20 B0 12 00 22
0F 43 01 3C 1F 53 0F 9B FD 2B 0F 43 EF 3F 30 40
52 EC 30 40 56 EC FF 3F
@FFFE
00 EC
q


Прошил. Вроде работает. Первая прошивка часто моргает (~3Гц), затем переходит на вторую прошивку, моргает медленно (~1.5 Гц). И так бесконечно.
Я всё правильно сделал? Есть ли минусы?

Кстати, Сергей, пробовал делать переход на адрес вектора ((void(**)() )0x9FFE)(); в одном и ((void(**)() )0xFFFE)(); в другом приложении. Компилятор ругнулся на эти записи "Error[Pe109]: expression must have (pointer-to-) function type "

Сообщение отредактировал KARLSON - Oct 13 2011, 10:11
Прикрепленные файлы
Прикрепленный файл  perehod_po_prilogeniyam.rar ( 39.68 килобайт ) Кол-во скачиваний: 29
 


--------------------
Кризис - это не отсутствие денег, а отсутствие идей! Учитесь и никаких кризисов не будет.
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Oct 13 2011, 15:56
Сообщение #36


Гуру
******

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



QUOTE (KARLSON @ Oct 13 2011, 09:35) *
Кстати, Сергей, пробовал делать переход на адрес вектора ((void(**)() )0x9FFE)(); в одном и ((void(**)() )0xFFFE)(); в другом приложении. Компилятор ругнулся на эти записи "Error[Pe109]: expression must have (pointer-to-) function type "
Да, это я лопухнулся. (*((void(**)() )0xFFFE))();


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
Kurt
сообщение Oct 21 2011, 04:49
Сообщение #37


Участник
*

Группа: Свой
Сообщений: 63
Регистрация: 16-06-04
Из: Россия, Уфа
Пользователь №: 31



Мои пять копеек.
Вариант, если в устройстве есть внешняя память (в моем случае AT45DB или FRAM33). Посредством основной программы по существующему протоколу связи заливаем образ прошивки во внешнюю память (с проверкой версии прошивки, аппаратуры, контрольных сумм и пр.). Затем передаем управление ассемблерной процедуре, которая копирует себя в ОЗУ и затем оттуда быстро и тупо копирует образ из внешней памяти во FLASH.

Исходник для msp430f2x и at45db:

CODE

#include <msp430.h>
#include "hardware_config.h"
#include "fwupdate.h"

// Forward declarations of segments.
RSEG CSTACK:DATA:NOROOT
RSEG DATA16_I:DATA:NOROOT
MODULE FW_UPDATE_ROUTINES
PUBLIC fw_at45_update

WD_EXT_STB MACRO
xor.b #(1<<PIN_WD_STROBE), &WD_EXT_PORT
ENDM

AT45_ENABLE MACRO
bic.b #(1<<PIN_AT45_CS), &AT45_CS_PORT
ENDM

AT45_DISABLE MACRO
bis.b #(1<<PIN_AT45_CS), &AT45_CS_PORT
ENDM

SPI_WRITE MACRO N
mov.b N, r12
call r8
ENDM

RSEG CODE
fw_at45_update
dint
nop
mov.w #(WDTPW|WDTHOLD), &WDTCTL
ftg_w_ready bit #BUSY, &FCTL3
jnz ftg_w_ready

mov #SFE(CSTACK), sp

// copy to RAM
mov.w #FW_INIT, r12
mov.w #SFE(DATA16_I), r14
push.w r14
copy_2_ram: mov.w @r12+, 0(r14)
incd.w r14
cmp.w #FW_UPDATE_END, r12
jnc copy_2_ram
ret

FW_INIT
WD_EXT_STB

// Init DCO
mov.b &CALBC1_12MHZ,&BCSCTL1 // Set DCO to 12MHz
clr.b &BCSCTL2 // MCLK = SMCLK = DCOCLK
mov.b &CALDCO_12MHZ,&DCOCTL

mov.w #(FWKEY|FSSEL_1|FN5), &FCTL2 // Flash clock = MCLK/35 ~ 360kHz

// configure SPI module
mov.b #(UCSSEL_2|UCSWRST), &UCB1CTL1 // SMCLK
mov.b #(UCMST|UCSYNC|UCMSB|UCCKPL), &UCB1CTL0 // 3-pin, 8-bit SPI master
mov.b #1, &UCB1BR0
mov.b #0, &UCB1BR1
bic.b #(1<<2), &P5DIR
bis.b #((1<<1)|(1<<3)), &P5DIR
bis.b #((1<<1)|(1<<2)|(1<<3)), &P5SEL // P5.1,2,3 option select
bic.b #UCSWRST, &UCB1CTL1 // Initialize USCI state machine

// configure AT45DB
AT45_DISABLE
mov #(SFE(DATA16_I) + (spi_wr-FW_INIT)), R8 // R8 = &spi_write

// wait for ready at45db
wait_at45db AT45_ENABLE
SPI_WRITE #0x57
SPI_WRITE #0x00
AT45_DISABLE
bit.b #(1<<7), r12
jnc wait_at45db

// erase main memory
mov.w #3, r12 // erase cycles count
meras_loop mov.w #(FWKEY | MERAS), &FCTL1 // Set Mass Erase bit
mov.w #(FWKEY), &FCTL3 // Clear Lock bit
mov.w #0xFFFF, &fw_at45_update // write stuff byte to flash
meras_wait bit #BUSY, &FCTL3
jnz meras_wait
dec.w r12
jnz meras_loop

WD_EXT_STB

// at45db start read
AT45_ENABLE
SPI_WRITE #0xE8 // Continues Array Read(Legacy Command)
SPI_WRITE #0x00 // upper part of page address
SPI_WRITE #0x04 // lower part of page address and MSB of int.page adr.
mov.b #0, R12
call r8 // LSB byte of internal page address
call r8 // perform 4 dummy writes
call r8 // in order to initiate DataFlash
call r8 // address pointers
call r8 // --

mov.w #FW_FIRST_ADDR, r14
mov.w #FWKEY,&FCTL3 // Clear LOCK

prg_blocks WD_EXT_STB
mov.w #(FWKEY|BLKWRT|WRT),&FCTL1 // Enable block write
prg_bytes SPI_WRITE #0x00 // Read byte from dataflash
mov.b r12, 0(r14) // Write location
prg_wait bit #WAIT, &FCTL3 // Test WAIT
jz prg_wait // Loop while WAIT=0
inc.w r14 // Point to next byte
jz prg_finish
bit.b #0x3F, r14 // end of block (addr % 0x40) == 0
jne prg_bytes
mov.w #(FWKEY|WRT), &FCTL1 // Set BLKWRT=0
prg_busy bit #BUSY, &FCTL3
jnz prg_busy
jmp prg_blocks
prg_finish
mov.w #(FWKEY|WRT), &FCTL1 // Set BLKWRT=0
prg_finb bit #BUSY, &FCTL3
jnz prg_finb
mov.w #FWKEY, &FCTL1 // Clear WRT bit
mov.w #(FWKEY|LOCK), &FCTL3 // Set Lock Bit
AT45_DISABLE

mov.w #0, &WDTCTL // RESET!

spi_wr bit.b #UCB1TXIFG, &UC1IFG
jnc spi_wr
mov.b r12, &UCB1TXBUF
?w_txend: bit.b #UCB1RXIFG, &UC1IFG
jnc ?w_txend
mov.b &UCB1RXBUF, r12
ret
FW_UPDATE_END


ENDMOD
END
Go to the top of the page
 
+Quote Post

3 страниц V   1 2 3 >
Reply to this topicStart new topic
2 чел. читают эту тему (гостей: 2, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 28th July 2025 - 09:31
Рейтинг@Mail.ru


Страница сгенерированна за 0.01794 секунд с 7
ELECTRONIX ©2004-2016