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

Самописный бутлоадер stm32f429

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

 

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

 

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

 

#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 в результате моих манипуляций:

 

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");
}
 

 

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

 

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 совпадают (за вычетом служебных данных). Я не могу понять, что я упустил. Есть у кого соображения, поделитесь если не трудно?

Изменено пользователем haker_fox
Уточнил название темы, добавил теги, переместил в нужный раздел.

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


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

Дебаг в ассемблере?

Прошивка-то гарантированно рабочая? Если отладчиком залить по нужным адресам, а потом отладчиком установить msp и pc работать будет? Запретов прерывания и отключения использованной переферии нигде не видно, может в основной прошивке оно сразу в обработчик прерывания улетает?

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


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

Дебаг в ассемблере?

Прошивка-то гарантированно рабочая? Если отладчиком залить по нужным адресам, а потом отладчиком установить msp и pc работать будет? Запретов прерывания и отключения использованной переферии нигде не видно, может в основной прошивке оно сразу в обработчик прерывания улетает?

 

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

 

было:

 

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

 

стало:

 

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

 

Компилирую без смещения, зашиваю - работает. Такая проверка достаточна или непременно нужно отладчиком менять указатели?

 

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


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

Это не проверка на 100%, соответственно уверенности в том что прошивка работает со смешением нет. По поводу прерываний в бутлоадере - как оно у вас сделано? Всё таки просто пройдитесь в режиме асемблера отладчиком - сразу станет понятно что происходит с чипом.

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


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

Может Вы периферию успеваете в отладчике настроить? Или улетаете в прерывание в процессе переключения?

Вообще есть правило, которое я считаю хорошим:

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

Если ключ есть, то переключаемся в программу пользователя, ключа нет - передаем управление загрузчику.

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

А для перехода в режим загрузчика стираем ключ и перегружаемся.

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

Я для этого использую заглушку с перемычкой на разъёме JTAG(SWD). Проинициализировать пару выводов, опросить, а потом вернуть их в исходное состояние несложно.

 

По коду переключения:

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

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

Происходит что-то вроде этого:

SCB->VTOR = (int32u)&__vector_table; // Vector Table Relocation

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

 

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

Нельзя быть уверенным, что в процессе инициализации эти библиотеки что-нибудь Вам не настроят. А потом будете ловить непонятные глюки с периферией в программе пользователя.

 

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


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

Или улетаете в прерывание в процессе переключения?

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

 

P.S. Глянул, как у меня с этим. Такие строчки перед переходом на новую прошивку:

        Deinit_Peripherals();
        SysTick->CTRL &= ~(SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk);

Под Deinit_Peripherals(); можно развернуться, насколько собственная фантазия позволит. А вот убиение SysTick было просто необходимо.

Изменено пользователем KnightIgor

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


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

__disable_irq();
....
__set_MSP(*(__IO uint32_t*) USER_APP_START_ADR);
__set_CONTROL(0x00000000); // switch to "main" stack pointer - ну по идее это должно вообще лежать где-нибудь в __Init_Data()
jumpToApp();

1. Отключать прерывания обязательно - мало ли как вы попали в загрузчик ;)

2. То же самое касается стека.

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

а) отключается PLL;

б) настраивается PLL;

в) клок переключается на PLL;

тогда после возврата от в) к а) процессор тупо остановится :) В общем, посмотрите ещё в сторону инициализации клоков!

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


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

...Всё таки просто пройдитесь в режиме асемблера отладчиком - сразу станет понятно что происходит с чипом.

 

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

 

SCB->VTOR = (int32u)&__vector_table; // Vector Table Relocation

 

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

 

__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. Сейчас все работает, спасибо большое всем за помощь!

 

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


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

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

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

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

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

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

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

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

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

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