Перейти к содержанию
    

ПО для перепрошивки 8051

Встала задача по созданию программного обеспечения для обновления ПО 8051. Особенностью создаваемого устройства является то, что в процессе эксплуатации может потребоваться неоднократное обновление программного обеспечение. В связи с этим хочу спросить две вещи:

1. Можно ли вообще написать модуль ПО перепрошивки на Си? В проекте стоит опция максимальной оптимизации по размеру кода, при которой Кеil по идее может сам находить похожие куски кода и выделять их в подпрограммы. И тогда код, расположенный в ПО перепрошивки, будет вызывать код, который лежит за пределами области памяти программ перепрошивщика, что недопустимо. Остается только ассемблер?

2. Если все же писать на Си, то как жестко разместить программу перепрошивки с заданного адреса? Например 0xF800. И как это сделать в варианте на ассемблере.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Встала задача по созданию программного обеспечения для обновления ПО 8051. Особенностью создаваемого устройства является то, что в процессе эксплуатации может потребоваться неоднократное обновление программного обеспечение. В связи с этим хочу спросить две вещи:

1. Можно ли вообще написать модуль ПО перепрошивки на Си? В проекте стоит опция максимальной оптимизации по размеру кода, при которой Кеil по идее может сам находить похожие куски кода и выделять их в подпрограммы. И тогда код, расположенный в ПО перепрошивки, будет вызывать код, который лежит за пределами области памяти программ перепрошивщика, что недопустимо. Остается только ассемблер?

2. Если все же писать на Си, то как жестко разместить программу перепрошивки с заданного адреса? Например 0xF800. И как это сделать в варианте на ассемблере.

1. Можно, какая разница на чем писать.

2. В кейле project->options for target->bl51 locate. В asm это делается с помощью например ORG или смотрите далее. Найдите ее описание.

 

Но в общем Вы ничего не написали о том как хотите обновлять прошивку. Если предположить, что Вы хотите по UART присылать новую прошиву и полностью переписывать содержимое внутренней flash-памяти программ, относящейся к основной программе. Следует прочитать "AN-112 UART IN-APPLICATION CODE LOADING EXAMPLES" у silabs. Я делал следующим образом. Создал 2 проекта - основной и bootloader. Основная прога ложится в память начиная, например, с адреса 0x100 (задается установками линкера). Естественно, вектора прерывания находятся по своим местам ниже этой точки. В проекте бутлоадера делаем установки линкера размещать код с выбранного Вами адреса 0xf800. Далее, в оба проекта явно добавляем копии стандартного startup.a51. Далее немного модифицируем эти копии. Для основного проекта:

        PUBLIC    ?C_STARTUP

        CSEG    AT    100h      <-измененный адрес!
?C_STARTUP:    LJMP    STARTUP1

        RSEG    ?C_C51STARTUP

для бутлоадера:

        CSEG    AT    0;делаем переход на нужный адрес 0xf800
      LJMP    0f800h
        CSEG    AT    0f800h; теперь прога начинается с этой позиции
?C_STARTUP:    LJMP    STARTUP1

Теперь при старте начинает выполняться бутлоадер. Если для него работы нет, то он передает управление основной программе вызовом application(); имеющей только прототип void (*application)(void)=(void code *)0x0100;

Основная программа при выполнении получает новую прошиву, размещает ее во внешней памяти, выставляет какой нибудь флаг. После этого сбрасывает контроллер или переходит на выполнение строки по 0-му адресу, бутлоадер видит флаг и начинается ...

Можно и самим бутлоадером получать прошиву. Зависит от Ваших требований. Описывайте подробнее желаемое. Можно и основную прогу начинать по 0-му адресу, а из нее вызывать бутлоадер. Но в моем варианте критическим является переписывание только 0-го сектора. Даже если в процессе перезаписи произошел сбой, пропадание питания или еще что-нибудь, бутлоадер начнет сначала.

Для обоих проектов создаем HEX-файлы и объеденяем их в один, не забывая удалить в одном из них строку окончания файла. Получившийся файл загружаем в камень при первой прошивке.

Ну и еще можно добавить в бутлоадер функции по расшифровке полученного перед записью во флэш и тогда можно прошивки передавать через третьих лиц :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Обновление ПО представляю так: От компьютера по стандартному протоколу передачи данных через UART подается определенная команда, после которой происходит переход в программу перепрошивки, которая уже далее принимает по своему специальному протоколу пакеты с данными, содержащими код программы, и по мере поступления происывает их в память программ. Аварийный выход в программу перепрошивки только при включении питания при определенном нажатии кнопок (есть еще и такие).

 

А вообще спасибо за столь объемный ответ. Действительно, стало понятнее. Но надо будет еще самому подумать и все проверить.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Можно и самим бутлоадером получать прошиву.

не можно, а даже нужно! Следует исходить из того, что основная часть прошивки может испортиться как угодно. Поэтому для живучести надо стартовать в бутлоадер (для силабсов - в последний сектор), там посчитать контрольную сумму и проверить спецножку контроллера. Если сумма испорчена или ножка зажата в ноль - аварийно ждать прошивку и шить. При нормальной сумме и свободной ноге - переходить на основную программу, оттуда тоже должна быть возможность перейти на перепрошивку - это штатный способ обновления FW.

Еще важный трюк: по адресу 0x0200 следует расположить еще один ljmp на бутлоадер. Для того, чтобы сброс контроллера при стертом первом секторе вывел на аварийную загрузку прошивки. А стереться первый сектор может как штатно (при неоконченной его перешивке), так и случайно по сбою.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Я размещаю загрузчик с 0 адреса, тогда он гарантировано стартует при сбросе.

С векторами прерываний заморочек нет, поскольку НА ВСЕ вектора (кроме того, по которому загрузчик работает)

ставлю команды перехода (LJMP $+Offset где Offset - адрес начала приложения).

В опциях проекта Приложения указываю смещение векторов прерывания и начальный адрес приложения.

Таким образом обработка прерывания происходит всего на одну команду перехода дольше.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

не можно, а даже нужно! Следует исходить из того, что основная часть прошивки может испортиться как угодно.

И Вы тоже правы. Но я описывал свой алгоритм, не указав, что прошивку я получаю основной прогой через GPRS. Соответственно обучать бутлоадер работать с модемом накладно.Однако, при указанной позже топикстартером вводной , Ваш алгоритм становится единственно правильным. А за переход 0x200 спасибо, сам не догадался.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Доброго времени суток!!!

 

Столкнулся с такой-же задачей - программно прошивать CC1010. У контроллера CC1010 есть функция перепрошивки себя любимого, но, в отличае от Атмелов, у него нет "аппаратного" bootloader'а.

Поделюсь своими мыслями по повод решения данной задачи и с удовольствием вышлушаю Вашу критику.

Загрузчин думаю разместить с 0-го адреса, тогда при загрузки сразу будет запускаться bootloader. После загрузки он в течении некоторого времени "слушает" UART. Если по UART'у пришла команда перехода в режим программирования, то по тому-же UART'у кусками принемаем прошивку и шьем ее во флеш начиная с определенного адреса. Т.к. прошивается флеш по страницам в 128 байт, то адрес начала основной программы будет определяться так: адрес начала следующей, после конца bootloader'а, страницы (если bootloader заканчивается на середине третьей страницы, то основная программа начинается с четвертой). Если по UART'у команда перехода в режим программирования не пришла, пришла не та команда или уже все прошили, то прыгаем на адрес начала основной программы программы.

Если действительно можно приказать Кейлу, чтобы он собирал hex начиная с определенного адреса так, чтобы вся программа, включая таблицу векторов прерывания, была тупо смещена, то проблем не должно быть.

 

Что скажите Господа? Кейл правда умеет такое делать?

Заранее спасибо.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Если действительно можно приказать Кейлу, чтобы он собирал hex начиная с определенного адреса так, чтобы вся программа, включая таблицу векторов прерывания, была тупо смещена, то проблем не должно быть.

Кейл правда умеет такое делать?

Чисто теоритически - такое проделать, имхо, возможно: переопределить начало всех сегментов, размещаемых в памяти программ командами линкера...

Сам я делал иначе. Делал так:

Загрузчик располагал в конце памяти программ. Загрузчик работает исключительно по готовности (не использует прерывания). Тогда в таблице векторов на загрузчик указывает только команда по вектору 0. При записи в память программ прикладной программы загрузчик контролирует запись в этот (нулевой) вектор и сохраняет его неизменным, но "выкусывает" из загружаемай программы адрес перехода из команды по нулевому адресу и сохраняет его в выделенном месте памяти программ. Это "выкусывание" и сохранение адреса используется для последующего запуска прикладной программы.

Приимущества: прикладную программу не нужно "корёжить". Единственное ограничение - прикладная программа должна использовать хоть один вектор прерывания, тогда по нулевому адресу Keil поместит команду JMP, из которой бутлоадер "выкусит" адрес старта прикладной программы.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Доброго времени суток!!!

 

Вчера попробовал сместить адреса в Кейле. Делается это, как описывает уважаемый barabek: project->options for target->bl51 locate снимаем галачку "Use Memory Layuot..." в поле "Code Range" изменяем первый адрес на тот, который нужно. В моем случае, для CC1010, адрес можно менять на число байт, кратное 128, это следует из страничной организации памяти программ этого контроллера (256 страниц по 128 байт в каждой). Hex генерируется что надо, но таблица векторов прерывания все равно идет с нулегого адреса, что не удивительно:

 

БЫЛО:

 

:020000020000FC

:100000000211E1000000000000000002114E4B2F21

:100010000E58000041FC9C0280604844810AFFC0E9

:10002000000000020FB2EF4E70038D9922AF058FD2

:10003000C12200000000000000000002108000004B

:10004000000000020EDEBB010689828A83E0225096

:1000500002E722BBFE02E32289828A83E49322BB69

:10006000010CE58229F582E5833AF583E02250060A

:10007000E92582F8E622BBFE06E92582F8E222E5C0

:100080008229F582E5833AF583E49322BB01068950

:10009000828A83F0225002F722BBFE01F322F8BBD2

:1000A000010DE58229F582E5833AF583E8F02250D7

:1000B00006E92582C8F622BBFE05E92582C8F222A0

 

 

СТАЛО:

 

:020000020000FC

:1000000002121B0000000000000000021188000026

:1000100000000000000000000000000000000000E0

:10002000000000020FEC00000000000000000000D3

:1000300000000000000000000000000210BA0000F4

:10004000000000020F180000000000000000000087

:1000500000000000000000000000000000000000A0

:100060000000000000000000000000000000000090

:100070000000000000000000000000000000000080

:10008000BB010689828A83E0225002E722BBFE027E

:10009000E32289828A83E49322BB010CE58229F55D

:1000A00082E5833AF583E0225006E92582F8E622CC

:1000B000BBFE06E92582F8E222E58229F582E58386

 

Правда в hex'нике изначальном в начале, где вектора прерывания, еще что-то есть, но я не знаю что это (например адрес 0x000E)

 

Щас думаю как в сложившейся ситуации разместить bootloader и как что будет работать.

 

Уважаемый Палыч, не понял фразу "загрузчик работает исключительно по готовности" это как, нельзя ли описать по подробнее? И еще, как вы принемаете прошивку, если bootloader работает не по прерываниям?

Думаю, что в моем случае не получится реализовать Ваше решение из-за страничной организации памяти.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Сместить вектора прерывания в программе не проблема

На вкладке С51 есть галочка "Interrupt vector at adress" напротив нее поле где ввести адрес смещения для векторов прерывания.

Далее необходимо переопределить таблицу прерываний в стартапе.

Если загрузчик в младших адресах, то разместить команды перехода обработки прерываний на новые адреса по принципу

org 0x3 // прерывание INT0

LJMP $+Offset // переход на новый адрес обработки прерывания

и т.д. для всех векторов

Далее в стандартном стартапе приложения расположенного в старшей области памяти при необходимости изменить директиву начального адреса программы (если не менять то загружаться будет приложение, если изменить , то сперва заработает загрузчик)

ORG 0 -> заменит на ORG Offset

 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Уважаемый Палыч, не понял фразу "загрузчик работает исключительно по готовности" это как, нельзя ли описать по подробнее? И еще, как вы принемаете прошивку, если bootloader работает не по прерываниям?
При работе загрузчика прерывания запрещены. Прошивка принимается по UART. В загрузчике проверяются флаги TI и RI регистра SCON: есть флаг - забираем/передаём очередной байт, сбрасываем флаг; принята очередная порция информации для записи в память программ - производим запись.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Доброго времени суток!!!

 

А может быть в памяти программ 2 таблицы векторов прерываний (одна bootloader'a вторая прикладной программы)?

Так, что бы пока bootloader работает, выполнялись его обработчики прерываний, а когда выполняется прикладная программа, то исполняются ее обработчики.

 

2Редактор А нельзя ли поподробнее о STARTUP'е, а то я не догоню что-то. :help:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Доброго времени суток!!!

 

А может быть в памяти программ 2 таблицы векторов прерываний (одна bootloader'a вторая прикладной программы)?

Так, что бы пока bootloader работает, выполнялись его обработчики прерываний, а когда выполняется прикладная программа, то исполняются ее обработчики.

 

2Редактор А нельзя ли поподробнее о STARTUP'е, а то я не догоню что-то. :help:

Было бы хорошо иметь несколько таблиц, но чудес не бывает. В своей программе Вы можете прописать обработчики прерываний по любым адресам ( при большом желании ) . Однако в железе при приходе прерывания переход будет осуществлен на строго определенный НЕИЗМЕНЯЕМЫЙ адрес, прописаный в документации. Не пытайтесь никак это изменить, не получится.

А по второму вопросу. В каждый проект на С добавляется файл startup.a51, который исполняется после сброса контроллера до перехода на Вашу функцию main. Поиском найдете у себя на компе. При желании можете его менять под свои нужды. Как? Найдите недавно был пост типа "не могу записать в xdata". Извините, пишу с телефона и мне нужно бежать :-). Потом если что ...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Доброго времени суток!!!

 

Думаю поступить так: bootloader расположить в начальных адресах. В стартапе bootloader'а переопределить все вектора прерывания (кроме тех, что используются в bootloader'е) на адреса, где во флеше будет таблица прерываний прикладной программы. Тогда по прерыванию контроллер идет по адресу прописаному в документации, а там ему говорят иди по новому адресу. Придя по новому адресу он обрабатывает прерывание. Но получается, что если я в bootloader'е буду использовать прерывания по UART'у и таймеру, то в прикладной программе их юзать уже на получится?

 

Еще вариант расположить bootloader в последних адресах. Тогда прикладная программа при прерываниях не будет скакать по адресам, но там другие загвоздки есть.

 

Я правильно уловил логику "колдования" со стартапом?

 

Уважаемый barabek, не могли бы Вы написать о стартапе или дать ссылку.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Но получается, что если я в bootloader'е буду использовать прерывания по UART'у и таймеру, то в прикладной программе их юзать уже на получится?
Ну, почему же - не получится... Просто переход по прерыванию в прикладной программе получится длиннее: нужна будет переменная - флаг работы прикладной программы. При прерываниях по UART и таймеру придётся её проверять и переходить на переопределённый вектор или выполнять некие действия для бутлоадера.

Еще вариант расположить bootloader в последних адресах. Тогда прикладная программа при прерываниях не будет скакать по адресам, но там другие загвоздки есть.
Это какие загвоздки? Работа бутлоадера по-готовности устройств? Проверять циклически несколько флагов в регистрах - это разве так сложно?

... не могли бы Вы написать о стартапе или дать ссылку.
Что Вы хотите узнать о стартапе? Посмотрите на стартап сами - файлы для разных МК лежат в Keil/C51/Lib

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...