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

Ещё раз о бутлоадере

Задумка такая.

 

По старту попадаем в бут. Там считаем CRC и если Ok - выходим на саму приложение. Если не Ok то переходим на сам лодырь.

 

В приложении по команде переходим непосредственно на лоадырь.

 

 

То есть мне надо две точки входа. По сбросу и по команде. Хотелось бы использовать незадействованные вектора бутлоадера. Например +2. Как это сделать. Если использовать pragma location, то наверняка будет linker ругаться.

 

Конечно можно упростить задачу и использовать какой нибудь признак в EEPROM. Или портить CRC к примеру, но что-то мне не нравится такой подход.

 

А кто как делает?

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


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

Хотелось бы использовать незадействованные вектора бутлоадера. Например +2. Как это сделать. Если использовать pragma location, то наверняка будет linker ругаться.

Конечно можно упростить задачу и использовать какой нибудь признак в EEPROM. Или портить CRC к примеру, но что-то мне не нравится такой подход.

Есть некая нога, которую приложение всегда настраивает на вывод. Например выход USART или нога, на которой висит светодиод. После сброса все порты гарантировано настроены на ввод. Значит, используюя даже одну точку входа по направлению этой ноги можем судить - мы попали по сбросу или по переходу из приложения. По второму вопросу: в коде пишем
extern void BootLoader();

В командной строке линкера добавляем -DBootLoader=0x1800 или в .xcl дописываем -DBootLoader=0x1800. Все. в приложении делаем dir_out(MANUAL_PROG); __disable_interrupt(); BootLoader();

На всякий случай в __low_level_init() лодыря сразу же запретить прерывания и переключить вектора на лодырь (если используются).

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


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

Спасибо Сергей. Всё доступно объяснил. :) Подходят оба варианта.

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


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

а почему бы не объявить переменную в озу в загрузчике и основной программе по одному и тому же адресу.

В загрузчике ей присваевается значение (не 0 или FF) по результатам проверки срс, а в основной проге считывается значение. и по значению делаем выводы.

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


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

В загрузчике ей присваевается значение (не 0 или FF) по результатам проверки срс, а в основной проге считывается значение. и по значению делаем выводы.
Потому что содержимое ОЗУ по включению питания не определено. Там может случайно оказаться и "магическое" число. А направление портов четко оговорено, к тому же такой метод не требует дополнительных затрат ОЗУ - жаба душит выдлять ячейку, которая используется только один раз при включении :)

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


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

Задумка такая.

 

По старту попадаем в бут. Там считаем CRC и если Ok - выходим на саму приложение. Если не Ok то переходим на сам лодырь.

 

В приложении по команде переходим непосредственно на лоадырь.

То есть мне надо две точки входа. По сбросу и по команде. Хотелось бы использовать незадействованные вектора бутлоадера. Например +2. Как это сделать. Если использовать pragma location, то наверняка будет linker ругаться.

 

Конечно можно упростить задачу и использовать какой нибудь признак в EEPROM. Или портить CRC к примеру, но что-то мне не нравится такой подход.

 

А кто как делает?

 

Добавлю и я свои наработки:

1. Использовать ногу процессора - метод надежный, но IMHO это будет "жирновато", ног не всегда

хватает+на плате надо вешать на эту ногу резюк, кроме того в разных проектах это могут быть

разные ноги.

2. Вариант с EEPROM более предпочтителен, поскольку 1-й старт после прошивки программатором

BootLoader-a всегда будет на него. Тогда при отладке приложения работа будет такой:

а) - загрузка приложения

б) подача BootLoader-у команды передать управление на приложение, т.е. на адрес 0x0000

После отладки - прописать в EEPROM признак: сразу после Reset передавать управление на

приложение.

Правда здесь есть один подводный камень - зависание приложения или необходимость его

коррекции. Здесь можно использовать такой метод:

Если в течении, например 1-ой минуты проходит не менее 10-ти горячих рестартов, то в

EEPROM устанавливается признак блокировки перехода на приложение.

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


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

1. Использовать ногу процессора - метод надежный, но IMHO это будет "жирновато", ног не всегда хватает+на плате надо вешать на эту ногу резюк, кроме того в разных проектах это могут быть разные ноги.
Используется нога, которая в приложении выполняет какую-либо функцию. Например выход UART или выход на светодиод. Подтяжка желательна, но это может быть штатная подтяжка (например подтяжка CS внешнего устройства или тот же светодиод). В разных проектах пишется #define MANUAL_PROG C,3,L или #define MANUAL_PROG B,0,H

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


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

Есть некая нога, которую приложение всегда настраивает на вывод. Например выход USART или нога, на которой висит светодиод. После сброса все порты гарантировано настроены на ввод. Значит, используюя даже одну точку входа по направлению этой ноги можем судить - мы попали по сбросу или по переходу из приложения.

 

А какой смысл возврата в BootLoader из приложения?

Как я понимаю, по Reset всегда на BL а далее разбор:

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

Может я что-то "не догоняю".

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


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

А какой смысл возврата в BootLoader из приложения?
Чтобы обновлять ПО по команде извне по интерфейсу связи. Это удобно как для устройств, находящихся в труднодоступных местах, так и для устройств на столе - для перепрошивки их не нужно вскрывать чтобы замкнуть джампер. Протокол связи поддерживается приложением, оно получает команду "обновление", передает управление в загрузчик, загрузчик формирует ответ "к загрузке готов" в соответствии с протоколом связи. Если же мы стартанули загрузчик принудительно или приложения нет/не сошлась контрольная сумма, то загрузчик сам ожидает команду "обновление" (и это единственная команда из всего протокола, которая в нем реализована).

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


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

Чтобы обновлять ПО по команде извне по интерфейсу связи. Это удобно как для устройств, находящихся в труднодоступных местах, так и для устройств на столе - для перепрошивки их не нужно вскрывать чтобы замкнуть джампер. Протокол связи поддерживается приложением, оно получает команду "обновление", передает управление в загрузчик, загрузчик формирует ответ "к загрузке готов" в соответствии с протоколом связи. Если же мы стартанули загрузчик принудительно или приложения нет/не сошлась контрольная сумма, то загрузчик сам ожидает команду "обновление" (и это единственная команда из всего протокола, которая в нем реализована).

Логично! :beer:

Но есть один недостаток: приложение должно поддерживать протокол (иметь возможно лишний программный код) . А если приложение пишет другой программист, не разработчик BL или вообще

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

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


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

Но есть один недостаток: приложение должно поддерживать протокол (иметь возможно лишний программный код).
Да, есть такое. Но если какой-то интерфейс с внешним миром есть, обычно поверх него есть и какой-то протокол. Добавить в него одну команду обычно несложно. Если интерфейса нет (точнее он не выведен наружу) - ну остается джампер на плате.
А если приложение пишет другой программист, не разработчик BL или вообще в другой конторе (например у потребителя устройства). Ему же надо все описать, что он должен сделать.
Да. Описываю так: 1) запретить прерывания 2)настроить ногу X на вывод. 3) перейти по адресу 0x1800.

В общем главное - что мы друг друга поняли.

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


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

Сергей, всётаки по коду не уложился в 2к. Со своим WakeUp-ом. Там ещё некоторые приколы есть. У меня должно осуществляться обновление прямо в сети. Соответственно при обновлении требуется сверять серийный номер устройства. Его я не хочу записывать в лоадер, дабы лоадер унифицированный был. Поэтому при перепрошивке вытаскиваю номер перепрошиваю и сохраняю номер. :)

 

Короче впрямую в 2к не влез. В связи с тем, что сам протокол Wake, если работать ч/з прерывания, практически не связан с лоадером - переписал его на ASM. Думаю так влезу.

 

Но вот возник вопрос.

 

там есть конструкция в лоадере если помнишь.

 

typedef union

{

struct

{

uint8_t m_rxBuffer[bUFFER_SIZE]; // Receive buffer

uint8_t m_pageBuffer[PAGE_SIZE]; // Page is assembled here before

// getting programmed to flash mem

} part1;

 

#define rxBuffer sharedbufs.part1.m_rxBuffer

 

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

 

Но у меня с ней проблемы на ASM. Не могу понять как на ASM указать адрес начала буфера приёмного (rxBuffer)???

 

 

Сори. :) Разобрался.

 

Просто как-то в голове не укладывается как в ассемблере имена структур фигурируют. Понятно что потом линкер их к адресам приводит, но всё равно несколько диковато. :)

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


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

Сергей, всётаки по коду не уложился в 2к. Со своим WakeUp-ом.
Ты пытаешься засунуть в загрузчик еще какие-то команды кроме UpdateFirmware? У меня Wake-подобный протокол, я сделал так:
static unsigned char busReceiveByte(void) 
{
    uint8_t c = UART_getchar();
    if(c == CTL)
        c = UART_getchar() ^ 0x20;
    return c;
}
__C_task void main(void)
{
.......
    if(!dir(MANUAL_PROG))
    {
        uint8_t command[7];
        command[0] = 0xC0;          // Begin Of Frame
        uint16_t Tmp = SerialNo();
        command[1] = Tmp;
        command[2] = Tmp >> 8;
        command[3] = 0xFF;
        uint8_t *ptr = &command[1];
        Tmp = 0xFFFF;
        Tmp = CRC_XMODEM (*ptr++, Tmp);
        Tmp = CRC_XMODEM (*ptr++, Tmp);
        Tmp = CRC_XMODEM (*ptr++, Tmp);
        command[4] = ~Tmp;
        command[5] = ~(Tmp >> 8);
        command[6] = 0xC1;          // End Of Frame
        uint8_t idx = 0;
        do {
            uint8_t c = busReceiveByte();

            if(c != command[idx])
                idx = 0;
            else
                idx++;
        } while(idx < sizeof(command));        // wait for EOM
    }
    busReplyByte(ERROR_OK);

Т.е. я формирую образ всей команды и сравниваю проходящий поток с образцом. Сгенерить образец гораздо проще, чем реализовывать весь конечный автомат приема. Увы, это проходит только для одной команды.

Соответственно при обновлении требуется сверять серийный номер устройства. Его я не хочу записывать в лоадер, дабы лоадер унифицированный был. Поэтому при перепрошивке вытаскиваю номер перепрошиваю и сохраняю номер. :)
У меня в области загрузчика есть функция
#pragma segment="GET_SERIAL"
#pragma location="GET_SERIAL"
__root uint16_t SerialNo(void) { return ~0;}

При прошивке я указываю AvRealу -c?serno2=1826,serno.txt и он автоматически при программировании подставляет в эту функцию уникальные номера. Номер хранится в загрузчике и не может быть случайно стерт с приложением. Функцию SerialNo() можно вызвать и из приложения, поэтому и приложение становится независимым от серийника. Функция занимает 6 байт, что меньше чем код для чтения 16-битной константы из флеш с помощью LPM

Честно говоря смысл её не всосал. Чтобы к одному и тому же участку памяти под разными именами обращаться, что ли.
Именно так. Для улучшения читабельности. Т.е. "сейчас мы работаем с этим блоком как с буфером приема"
Сори. :) Разобрался.

Просто как-то в голове не укладывается как в ассемблере имена структур фигурируют. Понятно что потом линкер их к адресам приводит, но всё равно несколько диковато. :)

Ну, если не на плюсах писать, то имена как и у обычных переменных. А вот к полям из ассемблера, увы, только вручную указывая смещение от начала структуры.

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


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

Ты пытаешься засунуть в загрузчик еще какие-то команды кроме UpdateFirmware? У меня Wake-подобный протокол, я сделал так:

 

Пытаюсь Сергей. :(

 

Вчера в 3 часа ночи получил результат 2232. :( Если бы надо было байт 50 выжать ещё бы попытался, а так буду пробовать в обход. Я видишь ли с прерываниями завязался. Возможно придётся отказаться. Только вектора занимают 112 байт. Можно конечно их под себя подмять.

 

Короче буду думу думать. Жалко выделять 4к если нехватает совсем чуть чуть.

 

 

Спасибо за рекомендации. Разбираюсь. Пользуюсь. Помагает.

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


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

Пытаюсь Сергей.
. Интересно, какие? Мне пока в голову приходила всего одна команда, полезная в загрузчике - запрос версии. Приложение отвечает свою версию, загрузчик отвечает 0. Тогда центральный узел понимает, что приложение ёк и его надо перешить обязательно. А по ответу приложения о версии центральный узел может определять - нужно ли апгрейдить. Планирую реализовать. Думаю, что второй массив с образцом команды и поиск по нему как в примере выше не сильно раздует код. А на какие запросы у тебя отвечает загрузчик?
Только вектора занимают 112 байт. Можно конечно их под себя подмять.
"Не только мона, но и нуна!" А как в .xcl сегменты распределяются? Я отдаю под код все после последнего используемого вектора:
// Interrupt vectors
-Z(CODE)INTVEC=1800-1825
// Code memory
-Z(CODE)NEAR_F,HUGE_F,SWITCH,INITTAB,DIFUNCT,CODE=1802-1FFF
-Z(CODE)GET_SERIAL,GET_AREA#1802-1FFF

Хм. Скопировал сюда и призадумался - зачем указываю 0x1802, ведь 0x1800 всегда занят... Можно писать 1800-1FFF.

Жалко выделять 4к если нехватает совсем чуть чуть.
"Вам то хорошо..." (с) "Операция "С Новым Годом"". Вот если бы было 2 и не больше, как в m8, это бы еще сильнее стимулировало :)

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


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

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

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

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

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

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

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

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

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

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