STM32F103C8 перенос таблицы прерываний
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.
__set primask(0); // глобальное запрещение прерываний
NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x8004000); // непосредственно перенос таблицы прерываний
__set_PRIMASK(0); // разрешение прерываний
В настройках проекта нужный адрес выставил в Target и Linker.
Достаточно ли этих строчек для переноса или нужно что то еще? Код без EXTI или SysTick без проблем переноситься, а с прерыванием никак не получается.
Сразу говорю, с HAL'ом и STM32CubeMX не работаю. Работаю с SPL.
- VladislavS
- Собутыльник Кота
- Сообщения: 2562
- Зарегистрирован: Вт май 01, 2018 19:44:47
Re: STM32F103C8 перенос таблицы прерываний
Всё гораздо проще. Просто записываешь в SCB->VTOR адрес таблицы векторов прерываний и всё.
Я это обычно вообще в приложении всегда делаю. В GCC и IAR такПриложение само знает где у него таблица прерываний. Мало ли, сегодня с одного адреса его скомпилируешь, завтра с другого. Или вообще в SRAM для отладки будешь грузить. Главное грузить в тот адрес с которого приложение скомпилировано.
Я это обычно вообще в приложении всегда делаю. В GCC и IAR так
Код: Выделить всё
#ifdef __GNUC__
extern void *__vtor;
SCB->VTOR = (uint32_t)&__vtor;
#endif
#ifdef __ICCARM__
#pragma section = ".intvec"
SCB->VTOR = (uint32_t) __section_begin(".intvec");
#endif
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))))();
}
Последний раз редактировалось Myp3ik Вт окт 23, 2018 12:33:28, всего редактировалось 2 раза.
Иван Сусанин - первый полупроводник 
Re: STM32F103C8 перенос таблицы прерываний
[uquote="VladislavS",url="/forum/viewtopic.php?p=3488650#p3488650"]Всё гораздо проще. Просто записываешь в SCB->VTOR адрес таблицы векторов прерываний и всё.
Я это обычно вообще в приложении всегда делаю. В GCC и IAR такПриложение само знает где у него таблица прерываний. Мало ли, сегодня с одного адреса его скомпилируешь, завтра с другого. Или вообще в SRAM для отладки будешь грузить. Главное грузить в тот адрес с которого приложение скомпилировано.[/uquote]
Все равно не работает
Я это обычно вообще в приложении всегда делаю. В GCC и IAR так
Код: Выделить всё
#ifdef __GNUC__
extern void *__vtor;
SCB->VTOR = (uint32_t)&__vtor;
#endif
#ifdef __ICCARM__
#pragma section = ".intvec"
SCB->VTOR = (uint32_t) __section_begin(".intvec");
#endif
Все равно не работает
Re: STM32F103C8 перенос таблицы прерываний
[uquote="settz0r",url="/forum/viewtopic.php?p=3488576#p3488576"]__set primask(0); // глобальное запрещение прерываний
....
__set_PRIMASK(0); // разрешение прерываний.[/uquote]
Ну и где оно запрещает а где разрешает?
....
__set_PRIMASK(0); // разрешение прерываний.[/uquote]
Ну и где оно запрещает а где разрешает?
__enable_irq() эквивалент __set_PRIMASK(0)
__disable_irq() эквивалент __set_PRIMASK(1)
- VladislavS
- Собутыльник Кота
- Сообщения: 2562
- Зарегистрирован: Вт май 01, 2018 19:44:47
Re: STM32F103C8 перенос таблицы прерываний
В CMSIS есть __enable_irq() и __disable_irq(). Куда уж проще?
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]
Последний раз редактировалось settz0r Вт окт 23, 2018 13:59:15, всего редактировалось 3 раза.
- VladislavS
- Собутыльник Кота
- Сообщения: 2562
- Зарегистрирован: Вт май 01, 2018 19:44:47
Re: STM32F103C8 перенос таблицы прерываний
settz0r ,
1. Имей уважение. Портянки в спойлер [спойлер] и [код] оформляй, если хочешь чтобы их читали.
2. Сначала программу отладь без бутлоадера в том месте в котором она должна работать.
3. Отлаживай бутлоадер.
2ALL:, вы внутрь NVIC_SetVectorTable заглядывали? Пишите SCB->VTOR = 0x8004000; и не сношайте себе мозги.
1. Имей уважение. Портянки в спойлер [спойлер] и [код] оформляй, если хочешь чтобы их читали.
2. Сначала программу отладь без бутлоадера в том месте в котором она должна работать.
3. Отлаживай бутлоадер.
2ALL:, вы внутрь NVIC_SetVectorTable заглядывали? Пишите SCB->VTOR = 0x8004000; и не сношайте себе мозги.
- AlanDrakes
- Прорезались зубы
- Сообщения: 236
- Зарегистрирован: Пн июл 04, 2016 16:51:22
- Откуда: Россия, Омск
Re: STM32F103C8 перенос таблицы прерываний
Попробую ответить на самое первое сообщение.
У меня в проекте, загрузчик располагается в начальных адресах и занимает не более 16кБ кода (я ему выделил такую секцию, оставшихся 48кБ от 64кБ общей памяти, для основной прошивки достаточно).
Алгоритм действий (исключая кучу проверок на наличие и корректность прошивки на месте):
1. Отключить ВСЕ задействованные загрузчиком прерывания.
2. Сбросить задействованную загрузчиком периферию.
3. Считать начальные адреса прошивки (AppSect + 0, AppSect + 4)
4. Выполнить:
При выполнении данной процедуры, безвозвратно теряются данные процесса работы и ядро, фактически переходит на вектор запуска.
Опять же, в моём случае, процедура переноса векторов прерывания, происходит прямо в самом приложении (а так же в загрузчике) самостоятельно, потому изначально загрузчику за этим следить не нужно.
Делаю я это так:
Всё. Две инструкции в коде.
Естественно, необходимо следить за тем, чтобы адрес main попадал в секцию.
Как уже говорил выше, таблица прерываний располагается (у меня) в начале секции приложения. Соответсвенно, адрес main будет указывать на нужный диапазон, затем накладывается маска и получается адрес. Это случай с тремя независимыми версиями прошивки во Flash памяти.
Либо же, приложение можно собрать с опцией VECT_TAB_SRAM и тогда начальный код позаботится о том, чтобы таблица векторов прерываний оказалась в начале RAM.
И уже не нужно будет переносить самостоятельно что-то ещё.
У меня в проекте, загрузчик располагается в начальных адресах и занимает не более 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
- Собутыльник Кота
- Сообщения: 2562
- Зарегистрирован: Вт май 01, 2018 19:44:47
Re: STM32F103C8 перенос таблицы прерываний
Вот скажите, в keil хоть что-то можно не пер анус сделать? Нормальные линкеры экспортируют адреса секций и их можно в приложении как константу использовать.
Re: STM32F103C8 перенос таблицы прерываний
AlanDrakes, при компиляции выдает ошибку, SP и PC не идентифицированы. Вопрос, где описаны данные регистры в keil? С ассемблером не особо в ладах.
- VladislavS
- Собутыльник Кота
- Сообщения: 2562
- Зарегистрирован: Вт май 01, 2018 19:44:47
Re: STM32F103C8 перенос таблицы прерываний
Да не лезь ты в ассемблер. Стек устанавливается командой __set_MSP(adr), переход к приложению Jamp_To_Application(); на Си. Осталось только правильные адреса подставить.
- AlanDrakes
- Прорезались зубы
- Сообщения: 236
- Зарегистрирован: Пн июл 04, 2016 16:51:22
- Откуда: Россия, Омск
Re: STM32F103C8 перенос таблицы прерываний
[uquote="settz0r",url="/forum/viewtopic.php?p=3489532#p3489532"]AlanDrakes, при компиляции выдает ошибку, SP и PC не идентифицированы. Вопрос, где описаны данные регистры в keil? С ассемблером не особо в ладах.[/uquote]
Точно, в Keil свои дефайны. Уже отвык после gcc
Попробуйте так:
Точно, в 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
- Собутыльник Кота
- Сообщения: 2562
- Зарегистрирован: Вт май 01, 2018 19:44:47
Re: STM32F103C8 перенос таблицы прерываний
AlanDrakes, вот скажи, ЗАЧЕМ? Зачем тут асм? Единственное что ты поимеешь это геморр при переносе на другой компилятор. Я больше чем уверен, что Си код скомпилируется не хуже, чем эта вставка. К тому же, ТС и так запутался, а ты ему асмом по фэйсу.
-
Alex-Elektron
- Встал на лапы
- Сообщения: 113
- Зарегистрирован: Сб янв 11, 2014 21:25:55
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
Re: STM32F103C8 перенос таблицы прерываний
VladislavS , не получается писать через SCB->VTOR, компилятор не понимает команду __vtor* , так как используется не GCC компил, а стандартный кейловский. А через ассемблеровские команды, так там вообще полный игнор половины команд.
[uquote="VladislavS",url="/forum/viewtopic.php?p=3488650#p3488650"]Всё гораздо проще. Просто записываешь в SCB->VTOR адрес таблицы векторов прерываний и всё.
Я это обычно вообще в приложении всегда делаю. В GCC и IAR такПриложение само знает где у него таблица прерываний. Мало ли, сегодня с одного адреса его скомпилируешь, завтра с другого. Или вообще в SRAM для отладки будешь грузить. Главное грузить в тот адрес с которого приложение скомпилировано.[/uquote]
[uquote="VladislavS",url="/forum/viewtopic.php?p=3488650#p3488650"]Всё гораздо проще. Просто записываешь в SCB->VTOR адрес таблицы векторов прерываний и всё.
Я это обычно вообще в приложении всегда делаю. В GCC и IAR так
Код: Выделить всё
#ifdef __GNUC__
extern void *__vtor;
SCB->VTOR = (uint32_t)&__vtor;
#endif
#ifdef __ICCARM__
#pragma section = ".intvec"
SCB->VTOR = (uint32_t) __section_begin(".intvec");
#endif
- VladislavS
- Собутыльник Кота
- Сообщения: 2562
- Зарегистрирован: Вт май 01, 2018 19:44:47
Re: STM32F103C8 перенос таблицы прерываний
[uquote="settz0r",url="/forum/viewtopic.php?p=3491656#p3491656"]VladislavS , не получается писать через SCB->VTOR, компилятор не понимает команду __vtor* , так как используется не GCC компил, а стандартный кейловский.[/uquote]Да чтож за люди то пошли без толики фантазии. Ну напиши ты SCB->VTOR = 0x08004000; отладься, а потом будешь думать как кеил заставить самому эту константу подставить. Или вали ты с этого кейла, пока не подсел.
-
Alex-Elektron
- Встал на лапы
- Сообщения: 113
- Зарегистрирован: Сб янв 11, 2014 21:25:55
Re: STM32F103C8 перенос таблицы прерываний
VladislavS, что ж ты так на Кейл-то взъелся? Не существует идеального эмбеддерского софта, всё определяется прямизной рук и желанием/умением разобраться в проблеме. Сам сталкивался с тем, что после кейла не хотела прошивка со смещённым адресом стартовать. ТС пробовал мои рекомендации по настройкам линкера и комментированием строк в System_Init()?
Добавлено after 27 minutes 2 seconds:
1)Прошиваем сам загрузчик с ремапом таблицы векторов!
Стопудоворабочийкод:
Далее, настройки основной программы:
2)
3)
4)
5)
Добавлено 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)

Последний раз редактировалось Alex-Elektron Пн окт 29, 2018 10:10:03, всего редактировалось 1 раз.
Re: STM32F103C8 перенос таблицы прерываний
Alex-Elektron,Линкер настроен уже давно, бутлодер такой же, закомменитить код со скрина не могу, т.к. просто напросто не могу его нигде найти.
2)
2)

- VladislavS
- Собутыльник Кота
- Сообщения: 2562
- Зарегистрирован: Вт май 01, 2018 19:44:47
Re: STM32F103C8 перенос таблицы прерываний
Это я то взъёлся?
Взъёлся это когда вот так делают[uquote="AlanDrakes",url="/forum/viewtopic.php?p=3489046#p3489046"]
Всё. Две инструкции в коде.
Естественно, необходимо следить за тем, чтобы адрес main попадал в секцию.[/uquote]вместо
VTOR лучше прямо в приложении перенастраивать. Вы же его до загрузки лоадером всё равно будете отлаживать.
Код: Выделить всё
uint32_t i;
i = (uint32_t)(&main); // Получаем адрес main()
SCB->VTOR = (i & 0xFF030000);
Всё. Две инструкции в коде.
Естественно, необходимо следить за тем, чтобы адрес main попадал в секцию.[/uquote]вместо
Код: Выделить всё
extern uint32_t __Vectors;
SCB->VTOR = (uint32_t) &__Vectors;VTOR лучше прямо в приложении перенастраивать. Вы же его до загрузки лоадером всё равно будете отлаживать.