LAS9891 0 12 декабря, 2023 Опубликовано 12 декабря, 2023 · Жалоба Есть проект на 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; - пробовал кратно уменьшить количество потоков, очередей. Ничего не помогло. В чём причина? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
haker_fox 61 12 декабря, 2023 Опубликовано 12 декабря, 2023 · Жалоба 3 hours ago, LAS9891 said: Ничего не помогло. Перенос таблицы векторов и инициализация регистра VTOR выполняются? Вроде у Вас Cortex-M3. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
LAS9891 0 13 декабря, 2023 Опубликовано 13 декабря, 2023 · Жалоба Заработало. Сделал это: В загрузчике перед выходом так: __set_PRIMASK(1); В основной программе перед инициализацией ОС так: __set_PRIMASK(0); Как это повлияло на ОС не очень понятно. Если есть кто компетентный, поясните подробнее. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
haker_fox 61 13 декабря, 2023 Опубликовано 13 декабря, 2023 · Жалоба 14 minutes ago, LAS9891 said: Как это повлияло на ОС не очень понятно. Вы отключили, затем включили прерывания. Глобально. Значит, что-то не так с переинициализацией контроллера прерываний. Не отвергая Ваш способ, скажу, что избегаю так делать. Мне проще сбросить в своём загрузчике микроконтроллер, а потом запустить ПО, записав некую сигнатуру в ОЗУ. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 242 13 декабря, 2023 Опубликовано 13 декабря, 2023 · Жалоба 4 часа назад, LAS9891 сказал: Как это повлияло на ОС не очень понятно. Если есть кто компетентный, поясните подробнее. Очевидно, если пишете загрузчик, то нужно остановить CPU на бряке в самом начале программы, посмотреть состояние всех регистров периферии (в том числе - регистров встроенной периферии ядра). А потом добиться, чтобы после завершения загрузчика (перед передачей управления на рабочее ПО) все эти регистры имели те же самые значения (значения после сброса). 4 часа назад, haker_fox сказал: Мне проще сбросить в своём загрузчике микроконтроллер, а потом запустить ПО, записав некую сигнатуру в ОЗУ. Надо только не забывать её удалять перед передачей управления рабочей прошивке. PS: Это не Вам, Вы это и так знаете. А вот человеку, ожидающему что микроконтроллер может угадывать с какого адреса скомпонована программа и стартовать с этого адреса, а не с прописанного в мануале; и человеку желающему выключать WDT в ходе работы программы - об этом напомнить будет нелишне. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
x893 60 13 декабря, 2023 Опубликовано 13 декабря, 2023 · Жалоба NVIC_SystemReset + custom startup И не надо никаких советов читать. Хоть свой бутлодер, хоть System Bootloader используйте Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
LAS9891 0 15 декабря, 2023 Опубликовано 15 декабря, 2023 (изменено) · Жалоба On 12/13/2023 at 1:08 PM, jcxz said: остановить CPU на бряке в самом начале программы, посмотреть состояние всех регистров периферии Так выглядит NVIC в начале основной программы: Так выглядит NVIC перед выходом из загрузчика: Отличия только в регистре 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), чёт не выходит. А я так понял это прям кардинальный способ, а как не кардинально? Вроде сделал деинициализацию. Что я ещё забыл (ну кроме головы и прочитать Джозефа Ю.)? Изменено 15 декабря, 2023 пользователем LAS9891 Длинный код нужно прятать под спойлер. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться