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

Не запускается CMSIS-RTOS2 после выхода из загрузчика.

Есть проект на GD32F103RBT6. В проекте используется загрузчик, который расположен в начале FLASH, и основная программа. В основной программе используется CMSIS-RTOS2. Проблема следующая. После перехода из загрузчика в основную программу, при попытке провести инициализацию CMSIS-RTOS2, функция возвращает результат osErrorISR:

osStatus = osKernelInitialize(); // Initialize CMSIS-RTOS.
if (osStatus != osOK)
  ERROR_ACTION(KERNEL_ERROR,0);

и соответственно программа сваливается в ERROR_ACTION(KERNEL_ERROR,0).

Что было сделано:

- перед переключением на основную программу, вся используемая периферия отключена, прерывания отключены и сделан ClearPending;

- в основной программе перед инициализацией CMSIS-RTOS2 снова прерывания отключены и сделан ClearPending;

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

Ничего не помогло.

В чём причина?

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


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

3 hours ago, LAS9891 said:

Ничего не помогло.

Перенос таблицы векторов и инициализация регистра VTOR выполняются? Вроде у Вас Cortex-M3.

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


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

Заработало. Сделал это:

В загрузчике перед выходом так: __set_PRIMASK(1);

В основной программе перед инициализацией ОС так: __set_PRIMASK(0);

Как это повлияло на ОС не очень понятно. Если есть кто компетентный, поясните подробнее.

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


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

14 minutes ago, LAS9891 said:

Как это повлияло на ОС не очень понятно.

Вы отключили, затем включили прерывания. Глобально. Значит, что-то не так с переинициализацией контроллера прерываний.

Не отвергая Ваш способ, скажу, что избегаю так делать. Мне проще сбросить в своём загрузчике микроконтроллер, а потом запустить ПО, записав некую сигнатуру в ОЗУ.

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


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

4 часа назад, LAS9891 сказал:

Как это повлияло на ОС не очень понятно. Если есть кто компетентный, поясните подробнее.

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

4 часа назад, haker_fox сказал:

Мне проще сбросить в своём загрузчике микроконтроллер, а потом запустить ПО, записав некую сигнатуру в ОЗУ.

Надо только не забывать её удалять перед передачей управления рабочей прошивке.

 

PS: Это не Вам, Вы это и так знаете. А вот человеку, ожидающему что микроконтроллер может угадывать с какого адреса скомпонована программа и стартовать с этого адреса, а не с прописанного в мануале; и человеку желающему выключать WDT в ходе работы программы - об этом напомнить будет нелишне.  :wink:

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


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

NVIC_SystemReset + custom startup
И не надо никаких советов читать.
Хоть свой бутлодер, хоть System Bootloader используйте

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


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

On 12/13/2023 at 1:08 PM, jcxz said:

остановить CPU на бряке в самом начале программы, посмотреть состояние всех регистров периферии

Так выглядит NVIC в начале основной программы:

(15_12.202310-11-18).thumb.jpg.519b72649f7e5dc9aa1858401d33cbdf.jpg

Так выглядит NVIC перед выходом из загрузчика:

(15_12.202310-15-14).thumb.jpg.f113f887bf4debb6b5f37083df9ea3bc.jpg

 

Отличия только в регистре VTOR. Все остальные прерывания, которых не видно на скринах - все значения (E, P, A) по нулям. Systick перед выходом из загрузчика (на самом деле очень задолго до выхода) выключаю. Вот так выглядит код деинициализации периферии перед выходом из загрузчика:

Spoiler
void BootLoader_Hardware_DeInit (void)
{
//---Выключение периферии---//
SysTickDisable(); // Prohibit SysTick.

RCU_AHBEN &= (~ ( RCU_AHBEN_DMA0EN    |  // DMA0 clock disable.
                  RCU_AHBEN_DMA1EN    |  // DMA1 clock disable.
                  RCU_AHBEN_SRAMSPEN  |  // SRAM clock disable when sleep mode.
                  RCU_AHBEN_FMCSPEN   |  // FMC clock disable when sleep mode.
                  RCU_AHBEN_CRCEN     |  // CRC clock disable.
                  RCU_AHBEN_EXMCEN    |  // EXMC clock disable.
#if (defined(GD32F10X_MD) || defined(GD32F10X_HD) || defined(GD32F10X_XD))
                  RCU_AHBEN_SDIOEN    |  // SDIO clock disable.
#elif defined(GD32F10X_CL)
                  RCU_AHBEN_USBFSEN   |  // USBFS clock disable.
                  RCU_AHBEN_ENETEN    |  // ENET clock disable.
                  RCU_AHBEN_ENETTXEN  |  // Ethernet TX clock disable.
                  RCU_AHBEN_ENETRXEN  |  // Ethernet RX clock disable.
#endif /* GD32F10X_MD and GD32F10X_HD and GD32F10X_XD */
                                     0));


RCU_APB1EN &= (~ ( RCU_APB1EN_TIMER1EN |  // TIMER1 clock disable.
                   RCU_APB1EN_TIMER2EN |  // TIMER2 clock disable.
                   RCU_APB1EN_TIMER3EN |  // TIMER3 clock disable.
                   RCU_APB1EN_TIMER4EN |  // TIMER4 clock disable.
                   RCU_APB1EN_TIMER5EN |  // TIMER5 clock disable.
                   RCU_APB1EN_TIMER6EN |  // TIMER6 clock disable.
#ifdef GD32F10X_XD
                   RCU_APB1EN_TIMER11EN | // TIMER11 clock disable.
                   RCU_APB1EN_TIMER12EN | // TIMER12 clock disable.
                   RCU_APB1EN_TIMER13EN | // TIMER13 clock disable.
#endif /* GD32F10X_XD */
                   RCU_APB1EN_WWDGTEN  |  // WWDGT clock disable.
                   RCU_APB1EN_SPI1EN   |  // SPI1 clock disable.
                   RCU_APB1EN_SPI2EN   |  // SPI2 clock disable.
                   RCU_APB1EN_USART1EN |  // USART1 clock disable.
                   RCU_APB1EN_USART2EN |  // USART2 clock disable.
                   RCU_APB1EN_UART3EN  |  // UART3 clock disable.
                   RCU_APB1EN_UART4EN  |  // UART4 clock disable.
                   RCU_APB1EN_I2C0EN   |  // I2C0 clock disable.
                   RCU_APB1EN_I2C1EN   |  // I2C1 clock disable.
#if (defined(GD32F10X_MD) || defined(GD32F10X_HD) || defined(GD32F10X_XD))
                   RCU_APB1EN_USBDEN   |  // USBD clock disable.
#endif /* GD32F10X_MD and GD32F10X_HD and GD32F10X_XD */
                   RCU_APB1EN_CAN0EN   |  // CAN0 clock disable.
#ifdef GD32F10X_CL
                   RCU_APB1EN_CAN1EN   |  // CAN1 clock disable.
#endif /* GD32F10X_CL */
                   RCU_APB1EN_BKPIEN   |  // backup interface clock disable.
                   RCU_APB1EN_PMUEN    |  // PMU clock disable.
                   RCU_APB1EN_DACEN   )); // DAC clock disable.
                   
RCU_APB2EN &= (~ ( RCU_APB2EN_AFEN      | // alternate function IO clock disable.
                   RCU_APB2EN_PAEN      | // GPIO port A clock disable.
                   RCU_APB2EN_PBEN      | // GPIO port B clock disable.
                   RCU_APB2EN_PCEN      | // GPIO port C clock disable.
                   RCU_APB2EN_PDEN      | // GPIO port D clock disable.
                   RCU_APB2EN_PEEN      | // GPIO port E clock disable.
                   RCU_APB2EN_PFEN      | // GPIO port F clock disable.
                   RCU_APB2EN_PGEN      | // GPIO port G clock disable.
                   RCU_APB2EN_ADC0EN    | // ADC0 clock disable.
                   RCU_APB2EN_ADC1EN    | // ADC1 clock disable.
                   RCU_APB2EN_TIMER0EN  | // TIMER0 clock disable.
                   RCU_APB2EN_SPI0EN    | // SPI0 clock disable.
                   RCU_APB2EN_TIMER7EN  | // TIMER7 clock disable.
                   RCU_APB2EN_USART0EN  | // USART0 clock disable.
#ifndef GD32F10X_CL
                   RCU_APB2EN_ADC2EN    | // ADC2 clock disable.
#endif /* GD32F10X_CL */
#ifdef GD32F10X_XD
                   RCU_APB2EN_TIMER8EN  | // TIMER8 clock disable.
                   RCU_APB2EN_TIMER9EN  | // TIMER9 clock disable.
                   RCU_APB2EN_TIMER10EN | // TIMER10 clock disable.
#endif /* GD32F10X_XD */
                                      0));
//--------------------------//

//---Сброс периферии---//
RCU_APB1RST = ( RCU_APB1RST_TIMER1RST  |  // TIMER1 reset.
                RCU_APB1RST_TIMER2RST  |  // TIMER2 reset.
                RCU_APB1RST_TIMER3RST  |  // TIMER3 reset.
                RCU_APB1RST_TIMER4RST  |  // TIMER4 reset.
                RCU_APB1RST_TIMER5RST  |  // TIMER5 reset.
                RCU_APB1RST_TIMER6RST  |  // TIMER6 reset.
#ifdef GD32F10X_XD
                RCU_APB1RST_TIMER11RST |  // TIMER11 reset.
                RCU_APB1RST_TIMER12RST |  // TIMER12 reset.
                RCU_APB1RST_TIMER13RST |  // TIMER13 reset.
#endif /* GD32F10X_XD */
                RCU_APB1RST_WWDGTRST   |  // WWDGT reset.
                RCU_APB1RST_SPI1RST    |  // SPI1 reset.
                RCU_APB1RST_SPI2RST    |  // SPI2 reset.
                RCU_APB1RST_USART1RST  |  // USART1 reset.
                RCU_APB1RST_USART2RST  |  // USART2 reset.
                RCU_APB1RST_UART3RST   |  // UART3 reset.
                RCU_APB1RST_UART4RST   |  // UART4 reset.
                RCU_APB1RST_I2C0RST    |  // I2C0 reset.
                RCU_APB1RST_I2C1RST    |  // I2C1 reset.
#if (defined(GD32F10X_MD) || defined(GD32F10X_HD) || defined(GD32F10X_XD))
                RCU_APB1RST_USBDRST    |  // USBD reset.
#endif /* GD32F10X_MD and GD32F10X_HD and GD32F10X_XD */
                RCU_APB1RST_CAN0RST    |  // CAN0 reset.
#ifdef GD32F10X_CL
                RCU_APB1RST_CAN1RST    |  // CAN1 reset.
#endif /* GD32F10X_CL */
                RCU_APB1RST_BKPIRST    |  // backup interface reset.
                RCU_APB1RST_PMURST     |  // PMU reset.
                RCU_APB1RST_DACRST     ); // DAC reset.

RCU_APB2RST = ( RCU_APB2RST_AFRST      | // alternate function I/O reset.
                RCU_APB2RST_PARST      | // GPIO port A reset.
                RCU_APB2RST_PBRST      | // GPIO port B reset.
                RCU_APB2RST_PCRST      | // GPIO port C reset.
                RCU_APB2RST_PDRST      | // GPIO port D reset.
                RCU_APB2RST_PERST      | // GPIO port E reset.
                RCU_APB2RST_PFRST      | // GPIO port F reset.
                RCU_APB2RST_PGRST      | // GPIO port G reset.
                RCU_APB2RST_ADC0RST    | // ADC0 reset.
                RCU_APB2RST_ADC1RST    | // ADC1 reset.
                RCU_APB2RST_TIMER0RST  | // TIMER0 reset.
                RCU_APB2RST_SPI0RST    | // SPI0 reset.
                RCU_APB2RST_TIMER7RST  | // TIMER7 reset.
                RCU_APB2RST_USART0RST  | // USART0 reset.
#ifndef GD32F10X_CL
                RCU_APB2RST_ADC2RST    | // ADC2 reset.
#endif /* GD32F10X_CL */
#ifdef GD32F10X_XD
                RCU_APB2RST_TIMER8RST  | // TIMER8 reset.
                RCU_APB2RST_TIMER9RST  | // TIMER9 reset.
                RCU_APB2RST_TIMER10RST | // TIMER10 reset.
#endif /* GD32F10X_XD */
                                      0);
//---------------------//


//---Выключение прерываний от периферии---//
for(uint8_t i=0; i<8; i++) // Applicable to the interrupt number is 16 ~ 255
  {
  NVIC->ICER[i] = 0xFFFFFFFF;// Write 1 Clear Interrupt Enable
  NVIC->ICPR[i] = 0xFFFFFFFF;// Write 1 clear interrupt hang status
  }
//----------------------------------------//
}
//------------------------------------------------------------------------------//

 

Потом делаю собственно переход:

void BootLoader_ChangeProgramCounter (uint32_t address)
{
//---Variables---//
uint32_t app_jump_address;
typedef void(*pFunction)(void); // user type
pFunction Jump_To_Application;  // create variable
//---------------//

//__set_PRIMASK(1); // И ВОТ ЕСЛИ ЭТО ЗАКОММЕНТИТЬ, ТО ОС ВЫДАЁТ ОШИБКУ.
  
BootLoader_Hardware_DeInit(); // Тут собственно делаю деинит.

app_jump_address    = *(uint32_t*)(address + 4);
Jump_To_Application = (pFunction)app_jump_address;
__set_MSP(*(volatile uint32_t*) address);

  
Jump_To_Application();
}
//------------------------------------------------------------------------------//

 

Без использования __set_PRIMASK(1), чёт не выходит. А я так понял это прям кардинальный способ, а как не кардинально? Вроде сделал деинициализацию. Что я ещё забыл (ну кроме головы и прочитать Джозефа Ю.)? 

Изменено пользователем LAS9891
Длинный код нужно прятать под спойлер.

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


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

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

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

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

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

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

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

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

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

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