Форум РадиоКот https://radiokot.ru/forum/ |
|
STM32F103C8 перенос таблицы прерываний https://radiokot.ru/forum/viewtopic.php?f=59&t=158272 |
Страница 1 из 4 |
Автор: | settz0r [ Вт окт 23, 2018 09:44:48 ] |
Заголовок сообщения: | STM32F103C8 перенос таблицы прерываний |
Добрый день, написал самый обычный код в KEIL UVISION с миганием диода и установкой прерывания через EXTI. Хочу запрограммировать плату через бутлодер по адресу 0х8004000(начальный адрес 0х8000000). Для этого пишу такие строчки: __set primask(0); // глобальное запрещение прерываний NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x8004000); // непосредственно перенос таблицы прерываний __set_PRIMASK(0); // разрешение прерываний В настройках проекта нужный адрес выставил в Target и Linker. Достаточно ли этих строчек для переноса или нужно что то еще? Код без EXTI или SysTick без проблем переноситься, а с прерыванием никак не получается. Сразу говорю, с HAL'ом и STM32CubeMX не работаю. Работаю с SPL. |
Автор: | VladislavS [ Вт окт 23, 2018 10:31:37 ] |
Заголовок сообщения: | Re: STM32F103C8 перенос таблицы прерываний |
Всё гораздо проще. Просто записываешь в SCB->VTOR адрес таблицы векторов прерываний и всё. Я это обычно вообще в приложении всегда делаю. В GCC и IAR так Код: #ifdef __GNUC__ Приложение само знает где у него таблица прерываний. Мало ли, сегодня с одного адреса его скомпилируешь, завтра с другого. Или вообще в SRAM для отладки будешь грузить. Главное грузить в тот адрес с которого приложение скомпилировано.
extern void *__vtor; SCB->VTOR = (uint32_t)&__vtor; #endif #ifdef __ICCARM__ #pragma section = ".intvec" SCB->VTOR = (uint32_t) __section_begin(".intvec"); #endif |
Автор: | Myp3ik [ Вт окт 23, 2018 12:15:26 ] |
Заголовок сообщения: | Re: STM32F103C8 перенос таблицы прерываний |
Нужно указать смещение Код: NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x4000); И при вызове из бутлодера Код: #define APPLICATION_ADDRESS ((uint32_t)0x08004000)
/* Адрес стека */ uint32_t stackAddr = (*(__IO uint32_t*)APPLICATION_ADDRESS); /* Проверка сигнатуры */ if ((stackAddr & 0x2FFE0000) == 0x20000000) { /* Инициализация указателя стека */ __set_MSP(stackAddr); /* Запуск программы */ ((void(*)(void))(*(__IO uint32_t*)(APPLICATION_ADDRESS + sizeof(uint32_t))))(); } |
Автор: | settz0r [ Вт окт 23, 2018 12:32:03 ] |
Заголовок сообщения: | Re: STM32F103C8 перенос таблицы прерываний |
Всё гораздо проще. Просто записываешь в SCB->VTOR адрес таблицы векторов прерываний и всё. Я это обычно вообще в приложении всегда делаю. В GCC и IAR так Код: #ifdef __GNUC__ Приложение само знает где у него таблица прерываний. Мало ли, сегодня с одного адреса его скомпилируешь, завтра с другого. Или вообще в SRAM для отладки будешь грузить. Главное грузить в тот адрес с которого приложение скомпилировано.extern void *__vtor; SCB->VTOR = (uint32_t)&__vtor; #endif #ifdef __ICCARM__ #pragma section = ".intvec" SCB->VTOR = (uint32_t) __section_begin(".intvec"); #endif Все равно не работает |
Автор: | dosikus [ Вт окт 23, 2018 12:48:12 ] |
Заголовок сообщения: | Re: STM32F103C8 перенос таблицы прерываний |
__set primask(0); // глобальное запрещение прерываний .... __set_PRIMASK(0); // разрешение прерываний. Ну и где оно запрещает а где разрешает? Цитата: __enable_irq() эквивалент __set_PRIMASK(0)
__disable_irq() эквивалент __set_PRIMASK(1) |
Автор: | VladislavS [ Вт окт 23, 2018 12:59:10 ] |
Заголовок сообщения: | Re: STM32F103C8 перенос таблицы прерываний |
В CMSIS есть __enable_irq() и __disable_irq(). Куда уж проще? |
Автор: | settz0r [ Вт окт 23, 2018 13:08:09 ] |
Заголовок сообщения: | Re: STM32F103C8 перенос таблицы прерываний |
Код: #include "stm32f10x.h" #include "stm32f10x_gpio.h" #include "stm32f10x_rcc.h" #include "stm32f10x_exti.h" #include "misc.h" #include "Uart_lib.h" GPIO_InitTypeDef GPIO_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; EXTI_InitTypeDef EXTI_InitStructure; USART_InitTypeDef USART_InitStructure; uint16_t a = 0, b = 0; void Init_led(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); } //---------- // //---------- void USART1_Init(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE); /*NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority =0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure);*/ /* Configure USART1 Tx (PA.09) as alternate function push-pull */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); /* Configure USART1 Rx (PA.10) as input floating */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, &GPIO_InitStructure); /* Configure the USART1 */ USART_InitStructure.USART_BaudRate = 115200; USART_InitStructure.USART_WordLength = USART_WordLength_8b; USART_InitStructure.USART_StopBits = USART_StopBits_1; USART_InitStructure.USART_Parity = USART_Parity_No; USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; USART_Init(USART1, &USART_InitStructure); USART_ITConfig(USART1, USART_IT_TXE, ENABLE); } //---------- // //---------- /* void USART1_Handler(void) { if (USART_GetFlagStatus(USART1, USART_IT_TXE) == SET) { USART_ClearITPendingBit(USART1, USART_IT_TXE); } }*/ //---------- // //---------- /*void Send_Uart(USART_TypeDef* USARTx, unsigned char c) { while(USART_GetFlagStatus(USARTx,USART_FLAG_TXE) == RESET){} USART_SendData(USARTx, c); while(USART_GetFlagStatus(USARTx,USART_FLAG_TC) == RESET){} } */ //uint32_t flash_read(uint32_t address) { // return (*(__IO uint32_t*) address); // } //---------- // //---------- void EXTI_NVIC_Init () { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_EXTILineConfig(GPIO_PortSourceGPIOC,GPIO_PinSource0); EXTI_InitStructure.EXTI_Line = EXTI_Line0; EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; EXTI_InitStructure.EXTI_LineCmd = ENABLE; EXTI_Init(&EXTI_InitStructure); NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority =0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); } //---------- // //---------- void EXTI0_IRQHandler() { EXTI_ClearITPendingBit(EXTI_Line0); GPIO_ResetBits(GPIOA, GPIO_Pin_1); //a++; //---------- // //---------- } void Led(void) { if(a==1) { while((b<10000)&(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0)==1)) { b++; } if(b==10000) { GPIO_ResetBits(GPIOA, GPIO_Pin_1); } } if (a>1) { a=0; while((b<10000)&(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0)==1)) { b++; } if(b==10000) { GPIO_SetBits(GPIOA, GPIO_Pin_1); } } } //---------- // //---------- int main(void) { NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x4000); Init_led(); EXTI_NVIC_Init(); USART1_Init(); GPIO_SetBits(GPIOA, GPIO_Pin_1); __enable_irq(); while(1) { //Led(); } } выше код программы, здесь код бутлодера. Что не так? [/code] void Go_to_App(void){ uint32_t app_jmp_address; typedef void(*pFunction)(void); pFunction Jamp_To_Application; __disable_irq(); app_jmp_address = *(uint32_t*)(Boot_end +4); Jamp_To_Application = (pFunction)app_jmp_address; __set_MSP(*(__IO uint32_t*)Boot_end); Jamp_To_Application(); }[code] |
Автор: | VladislavS [ Вт окт 23, 2018 13:45:38 ] |
Заголовок сообщения: | Re: STM32F103C8 перенос таблицы прерываний |
settz0r , 1. Имей уважение. Портянки в спойлер [спойлер] и [код] оформляй, если хочешь чтобы их читали. 2. Сначала программу отладь без бутлоадера в том месте в котором она должна работать. 3. Отлаживай бутлоадер. 2ALL:, вы внутрь NVIC_SetVectorTable заглядывали? Пишите SCB->VTOR = 0x8004000; и не сношайте себе мозги. |
Автор: | AlanDrakes [ Вт окт 23, 2018 18:00:30 ] |
Заголовок сообщения: | Re: STM32F103C8 перенос таблицы прерываний |
Попробую ответить на самое первое сообщение. У меня в проекте, загрузчик располагается в начальных адресах и занимает не более 16кБ кода (я ему выделил такую секцию, оставшихся 48кБ от 64кБ общей памяти, для основной прошивки достаточно). Алгоритм действий (исключая кучу проверок на наличие и корректность прошивки на месте): 1. Отключить ВСЕ задействованные загрузчиком прерывания. 2. Сбросить задействованную загрузчиком периферию. 3. Считать начальные адреса прошивки (AppSect + 0, AppSect + 4) 4. Выполнить: Код: jump_app (0x80004000); void jump_app( uint32_t address ) { __asm ("LDR SP, [R0]\n"); // Load new stack pointer address __asm ("LDR PC, [R0, #4]\n"); //Load new program counter address; }; При выполнении данной процедуры, безвозвратно теряются данные процесса работы и ядро, фактически переходит на вектор запуска. Опять же, в моём случае, процедура переноса векторов прерывания, происходит прямо в самом приложении (а так же в загрузчике) самостоятельно, потому изначально загрузчику за этим следить не нужно. Делаю я это так: Код: uint32_t i; i = (uint32_t)(&main); // Получаем адрес main() SCB->VTOR = (i & 0xFF030000); Всё. Две инструкции в коде. Естественно, необходимо следить за тем, чтобы адрес main попадал в секцию. Как уже говорил выше, таблица прерываний располагается (у меня) в начале секции приложения. Соответсвенно, адрес main будет указывать на нужный диапазон, затем накладывается маска и получается адрес. Это случай с тремя независимыми версиями прошивки во Flash памяти. Либо же, приложение можно собрать с опцией VECT_TAB_SRAM и тогда начальный код позаботится о том, чтобы таблица векторов прерываний оказалась в начале RAM. И уже не нужно будет переносить самостоятельно что-то ещё. |
Автор: | VladislavS [ Ср окт 24, 2018 09:11:51 ] |
Заголовок сообщения: | Re: STM32F103C8 перенос таблицы прерываний |
Вот скажите, в keil хоть что-то можно не пер анус сделать? Нормальные линкеры экспортируют адреса секций и их можно в приложении как константу использовать. |
Автор: | settz0r [ Ср окт 24, 2018 12:43:09 ] |
Заголовок сообщения: | Re: STM32F103C8 перенос таблицы прерываний |
AlanDrakes, при компиляции выдает ошибку, SP и PC не идентифицированы. Вопрос, где описаны данные регистры в keil? С ассемблером не особо в ладах. |
Автор: | VladislavS [ Ср окт 24, 2018 14:41:32 ] |
Заголовок сообщения: | Re: STM32F103C8 перенос таблицы прерываний |
Да не лезь ты в ассемблер. Стек устанавливается командой __set_MSP(adr), переход к приложению Jamp_To_Application(); на Си. Осталось только правильные адреса подставить. |
Автор: | AlanDrakes [ Ср окт 24, 2018 18:58:46 ] |
Заголовок сообщения: | Re: STM32F103C8 перенос таблицы прерываний |
AlanDrakes, при компиляции выдает ошибку, SP и PC не идентифицированы. Вопрос, где описаны данные регистры в keil? С ассемблером не особо в ладах. Точно, в Keil свои дефайны. Уже отвык после gcc Попробуйте так: Код: void jump_app( uint32_t address ) {
__asm ("LDR msp, [R0]\n"); // Load new stack pointer address __asm ("LDR R15, [R0, #4]\n"); //Load new program counter address; // Либо "r15" (в нижнем регистре), если так же не будет дефайна // Можно так же выполнить __asm ("BX [R0, #4]\n"); // Аналогичный переход на адрес инструкцией перехода // Не уверен, что так можно делать }; |
Автор: | VladislavS [ Ср окт 24, 2018 20:53:44 ] |
Заголовок сообщения: | Re: STM32F103C8 перенос таблицы прерываний |
AlanDrakes, вот скажи, ЗАЧЕМ? Зачем тут асм? Единственное что ты поимеешь это геморр при переносе на другой компилятор. Я больше чем уверен, что Си код скомпилируется не хуже, чем эта вставка. К тому же, ТС и так запутался, а ты ему асмом по фэйсу. |
Автор: | Alex-Elektron [ Чт окт 25, 2018 10:26:09 ] |
Заголовок сообщения: | Re: STM32F103C8 перенос таблицы прерываний |
Цитата: В настройках проекта нужный адрес выставил в Target и Linker. Достаточно ли этих строчек для переноса или нужно что то еще? Птицу в Use Memory Layout from Target Dialog ставил? П. С. Также надо закомментить в SystemInit() Код: #ifdef VECT_TAB_SRAM
SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM. */ #else SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH. */ #endif |
Автор: | settz0r [ Пт окт 26, 2018 08:53:07 ] |
Заголовок сообщения: | Re: STM32F103C8 перенос таблицы прерываний |
VladislavS , не получается писать через SCB->VTOR, компилятор не понимает команду __vtor* , так как используется не GCC компил, а стандартный кейловский. А через ассемблеровские команды, так там вообще полный игнор половины команд. Всё гораздо проще. Просто записываешь в SCB->VTOR адрес таблицы векторов прерываний и всё.
Я это обычно вообще в приложении всегда делаю. В GCC и IAR так Код: #ifdef __GNUC__ Приложение само знает где у него таблица прерываний. Мало ли, сегодня с одного адреса его скомпилируешь, завтра с другого. Или вообще в SRAM для отладки будешь грузить. Главное грузить в тот адрес с которого приложение скомпилировано.extern void *__vtor; SCB->VTOR = (uint32_t)&__vtor; #endif #ifdef __ICCARM__ #pragma section = ".intvec" SCB->VTOR = (uint32_t) __section_begin(".intvec"); #endif |
Автор: | VladislavS [ Пт окт 26, 2018 09:45:02 ] |
Заголовок сообщения: | Re: STM32F103C8 перенос таблицы прерываний |
VladislavS , не получается писать через SCB->VTOR, компилятор не понимает команду __vtor* , так как используется не GCC компил, а стандартный кейловский. Да чтож за люди то пошли без толики фантазии. Ну напиши ты SCB->VTOR = 0x08004000; отладься, а потом будешь думать как кеил заставить самому эту константу подставить. Или вали ты с этого кейла, пока не подсел.
|
Автор: | Alex-Elektron [ Пн окт 29, 2018 09:20:09 ] |
Заголовок сообщения: | Re: STM32F103C8 перенос таблицы прерываний |
VladislavS, что ж ты так на Кейл-то взъелся? Не существует идеального эмбеддерского софта, всё определяется прямизной рук и желанием/умением разобраться в проблеме. Сам сталкивался с тем, что после кейла не хотела прошивка со смещённым адресом стартовать. ТС пробовал мои рекомендации по настройкам линкера и комментированием строк в System_Init()? Добавлено after 27 minutes 2 seconds: 1)Прошиваем сам загрузчик с ремапом таблицы векторов! Стопудоворабочийкод: Код: #define FLASH_DISK_START_ADDRESS 0x08002800 /* Flash start address */ void GoToUserApp(void){ u32 appJumpAddress; void (*GoToApp)(void); appJumpAddress = *((volatile u32*)(FLASH_DISK_START_ADDRESS + 4)); GoToApp = (void (*)(void))appJumpAddress; __disable_irq(); SCB->VTOR = FLASH_DISK_START_ADDRESS; __enable_irq(); __set_MSP(*((volatile u32*) FLASH_DISK_START_ADDRESS)); //stack pointer (to RAM) for USER app in this address GoToApp(); } Далее, настройки основной программы: 2) 3) 4) 5) |
Автор: | settz0r [ Пн окт 29, 2018 10:04:50 ] |
Заголовок сообщения: | Re: STM32F103C8 перенос таблицы прерываний |
Alex-Elektron,Линкер настроен уже давно, бутлодер такой же, закомменитить код со скрина не могу, т.к. просто напросто не могу его нигде найти. 2) |
Автор: | VladislavS [ Пн окт 29, 2018 10:10:12 ] |
Заголовок сообщения: | Re: STM32F103C8 перенос таблицы прерываний |
Это я то взъёлся? Взъёлся это когда вот так делают Код: uint32_t i; i = (uint32_t)(&main); // Получаем адрес main() SCB->VTOR = (i & 0xFF030000); Всё. Две инструкции в коде. Естественно, необходимо следить за тем, чтобы адрес main попадал в секцию. Код: extern uint32_t __Vectors; SCB->VTOR = (uint32_t) &__Vectors; VTOR лучше прямо в приложении перенастраивать. Вы же его до загрузки лоадером всё равно будете отлаживать. |
Страница 1 из 4 | Часовой пояс: UTC + 3 часа |
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group http://www.phpbb.com/ |