Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Самописный бутлоадер STM32
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
yanvasiij
Доброго времени суток!

Вроде бы тривиальная задача, а вот однако застрял не могу понять, где ошибся. Проц - stm32f429. Суть такая "верхнее" приложение парсит hex-файл, выбрасывая из него все служебные данные, и данные не относящиеся к flash. Далее полученное подобие bin отправляется байт за байтом по последовательному порту в микроконтроллер. Микроконтроллер принимает, зашивает и переключается. Так вот после переключения ничего не происходит, проц зависает непонятно где.

Прошивку принятой программы я делаю так:

CODE


#define AVALIABLE_SECTORS_NUM 17 /**< @brief Общее количество доступных мне секторов */
#define USER_APP_START_ADR 0x08020000 /**< @brief Адрес куда шить программу */

/** Сектора, которые мне доступны */
static const u16 sectors [AVALIABLE_SECTORS_NUM] =
{
FLASH_Sector_5, FLASH_Sector_6, FLASH_Sector_7, FLASH_Sector_8, FLASH_Sector_9,
FLASH_Sector_10, FLASH_Sector_11, FLASH_Sector_12, FLASH_Sector_13, FLASH_Sector_14,
FLASH_Sector_15, FLASH_Sector_16, FLASH_Sector_17, FLASH_Sector_18, FLASH_Sector_19,
FLASH_Sector_20, FLASH_Sector_21
};


/** Тут лежит принятая прошивка (массив в SDRAM) */
static u8 __attribute__((section ("._sdram"))) userApp[MAX_BIN_FILE_LEN];
/** Это счетчик принятых байт */
static u32 byteCount = 0;


void programmUserApp (void)
{
u32 numOfPages = byteCount / PAGE_LEN;
if (byteCount % PAGE_LEN) numOfPages++;
FLASH_Unlock();
FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR|FLASH_FLAG_PGSERR);
/** Стираю необходимые мне сектора */
for (u32 i = 0; i < numOfPages; i++)
{
if (FLASH_EraseSector(sectors[i], VoltageRange_3) != FLASH_COMPLETE)
{
FLASH_Lock();
while (1); /* Стопор на всякий случай */
}
}

/** Далее шью по 4 байта */
u32 * word = (u32*)userApp;
u32 wordCount = byteCount/4;
if (byteCount%4) wordCount++;
u32 adr = USER_APP_START_ADR;
for (u32 i = 0; i < wordCount; i++)
{
if (FLASH_ProgramWord(adr, *(word++)) != FLASH_COMPLETE)
{
FLASH_Lock();
while (1); /* Стопор на всякий случай */
}
adr += 4;
}
FLASH_Lock();
}


Далее, чтобы удостовериться, что я зашил, то что хотел, я считываю и вывожу в последовательный порт данные, которые оказались во flash в результате моих манипуляций:

CODE


void showProgram (void)
{
u8 * p = (u8*) USER_APP_START_ADR;
printf ("\r\n");
for (u32 i = 0, j = 0; i < byteCount; i++, j++)
{
if ( (j>0) && ((j%16) == 0) )
printf ("\r\n");
printf ("%02X", p[i]);
}
printf ("\r\n");
printf ("End\r\n");
}


Переключаю программу вот так:

CODE

typedef void(*VoidFunction)(void);

void jumpToUserApp (void)
{
NVIC_SetVectorTable(NVIC_VectTab_FLASH, (USER_APP_START_ADR & (~(0x08000000))));
u32 jumpAddress = *(__IO uint32_t*) (USER_APP_START_ADR + 4);
VoidFunction jumpToApp = (VoidFunction) jumpAddress;
__set_MSP(*(__IO uint32_t*) USER_APP_START_ADR);
jumpToApp();
}


Так вот, после считыания я вижу, что зашилось именно то, что лежит в hex-файле в полях данных. То есть данные в hex и во flash совпадают (за вычетом служебных данных). Я не могу понять, что я упустил. Есть у кого соображения, поделитесь если не трудно?
Kabdim
Дебаг в ассемблере?
Прошивка-то гарантированно рабочая? Если отладчиком залить по нужным адресам, а потом отладчиком установить msp и pc работать будет? Запретов прерывания и отключения использованной переферии нигде не видно, может в основной прошивке оно сразу в обработчик прерывания улетает?
yanvasiij
Цитата(Kabdim @ Dec 21 2016, 19:22) *
Дебаг в ассемблере?
Прошивка-то гарантированно рабочая? Если отладчиком залить по нужным адресам, а потом отладчиком установить msp и pc работать будет? Запретов прерывания и отключения использованной переферии нигде не видно, может в основной прошивке оно сразу в обработчик прерывания улетает?


Ничего, если я проверю работоспособность прошивки следующим образом. В линкер файле уберу смещение:

было:

Код
...
MEMORY
{
  FLASH (rx)      : ORIGIN = 0x08020000, LENGTH = 1024K
...
}
...


стало:

Код
...
MEMORY
{
  FLASH (rx)      : ORIGIN = 0x08000000, LENGTH = 1024K
...
}
...


Компилирую без смещения, зашиваю - работает. Такая проверка достаточна или непременно нужно отладчиком менять указатели?
Kabdim
Это не проверка на 100%, соответственно уверенности в том что прошивка работает со смешением нет. По поводу прерываний в бутлоадере - как оно у вас сделано? Всё таки просто пройдитесь в режиме асемблера отладчиком - сразу станет понятно что происходит с чипом.
x893
а отладчиком посмотреть ?
amiller
Может Вы периферию успеваете в отладчике настроить? Или улетаете в прерывание в процессе переключения?
Вообще есть правило, которое я считаю хорошим:
При старте bootloadera самым первым делом проверять наличие адекватной прошивки по ранее записанному ключу.
Если ключ есть, то переключаемся в программу пользователя, ключа нет - передаем управление загрузчику.
Соответственно после прошивки записываем ключ и перегружаемся.
А для перехода в режим загрузчика стираем ключ и перегружаемся.
Ну и если программа пользователя виснет, нужно предусмотреть принудительный переход в режим загрузчика.
Я для этого использую заглушку с перемычкой на разъёме JTAG(SWD). Проинициализировать пару выводов, опросить, а потом вернуть их в исходное состояние несложно.

По коду переключения:
Вы сначала устанавливаете начало таблицы векторов, а потом делаете переход в программу пользователя.
Есть подозрение, что в начале выполнения программы пользователя на уровне стартапа начало таблицы векторов переопределяется.
Происходит что-то вроде этого:
SCB->VTOR = (int32u)&__vector_table; // Vector Table Relocation
И если Вы не озаботились установить смещение и для этой константы где-то в файле линкера, то может быть установлена таблица прерываний от загрузчика.

Ну и если Вы взялись за написание загрузчика, то в самом коде переключения надо обходится без библиотек сторонних типа CMSYS.
Нельзя быть уверенным, что в процессе инициализации эти библиотеки что-нибудь Вам не настроят. А потом будете ловить непонятные глюки с периферией в программе пользователя.
KnightIgor
Цитата(amiller @ Dec 22 2016, 06:04) *
Или улетаете в прерывание в процессе переключения?

Присоединяюсь. Надо бы запретить прерывания.

P.S. Глянул, как у меня с этим. Такие строчки перед переходом на новую прошивку:
Код
        Deinit_Peripherals();
        SysTick->CTRL &= ~(SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk);

Под Deinit_Peripherals(); можно развернуться, насколько собственная фантазия позволит. А вот убиение SysTick было просто необходимо.
Aaron
Код
__disable_irq();
....
__set_MSP(*(__IO uint32_t*) USER_APP_START_ADR);
__set_CONTROL(0x00000000); // switch to "main" stack pointer - ну по идее это должно вообще лежать где-нибудь в __Init_Data()
jumpToApp();

1. Отключать прерывания обязательно - мало ли как вы попали в загрузчик wink.gif
2. То же самое касается стека.
Можно ещё чуток пофантазировать. Например, передача управления клоков, настройка PLL. Может, у вас и в загрузчике, и в боевой программе:
а) отключается PLL;
б) настраивается PLL;
в) клок переключается на PLL;
тогда после возврата от в) к а) процессор тупо остановится sm.gif В общем, посмотрите ещё в сторону инициализации клоков!
yanvasiij
Цитата(Kabdim @ Dec 21 2016, 20:00) *
...Всё таки просто пройдитесь в режиме асемблера отладчиком - сразу станет понятно что происходит с чипом.


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

Цитата(amiller @ Dec 22 2016, 09:04) *
SCB->VTOR = (int32u)&__vector_table; // Vector Table Relocation


Вы попали в точку! В SystemInit вторичной программы это действительно было.

Цитата(Aaron @ Dec 23 2016, 17:49) *
Код
__disable_irq();
....
__set_MSP(*(__IO uint32_t*) USER_APP_START_ADR);
__set_CONTROL(0x00000000); // switch to "main" stack pointer - ну по идее это должно вообще лежать где-нибудь в __Init_Data()
jumpToApp();


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

Вообще удалось запустить бутлоадер. Ошибок оказалось много, это во-первых ошибка в парсере hex-файла (тот который отправляет прошивку в микроконтроллер), во-вторых ошибка с неверным переключением смещения таблицы векторов во вторичной программе (про это говорил amiller), ну и в третьих повторная инициализация pll, про которую сказал Aaron. Сейчас все работает, спасибо большое всем за помощь!
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.