Я пытаюсь использовать SysTick_Handler
в SW4STM32 для Linux, но всякий раз, когда срабатывает прерывание SysTick, выполнение переходит куда-то в системную память. Насколько я понимаю, он должен перейти в void SysTick_Handler(void)
, который я объявил, или в противном случае, в Default_Handler
, объявленный в startup_stm32.s, где определена таблица векторов прерываний. Я установил точку останова в своем SysTick_Handler
, но она никогда не достигается. В приведенном ниже коде он проходит через init_systick()
и остается в бесконечном цикле for
, если я не включаю SysTick_CTRL_TICKINT_Msk
, как ожидалось, но когда я его включаю, отладчик говорит мне, что он заканчивается где-то около адреса 0x1fffda7c.
main.c:
#include "stm32f0xx.h"
volatile uint32_t ticks = 0;
void SysTick_Handler(void) {
ticks++;
}
void init_systick(void) {
SysTick->LOAD = 43999;
SCB->SHP[1] |= 0x40000000L;
SysTick->VAL = 0;
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk;
}
int main(void)
{
init_systick();
for(;;);
}
Я подтвердил из файла .map
, что компоновщик использует объявленный SysTick_Handler
вместо Default_Handler
.
Я также попробовал следующий вариант, чтобы использовать стандартную периферийную библиотеку для настройки, наряду с другими значениями приоритета прерывания, с такими же результатами:
#include "stm32f0xx.h"
volatile uint32_t ticks = 0;
void SysTick_Handler(void) {
ticks++;
}
void init_systick(void) {
SysTick_Config(44000);
NVIC_EnableIRQ(SysTick_IRQn);
NVIC_SetPriority(SysTick_IRQn, 0);
}
int main(void)
{
init_systick();
for(;;);
}
Это не должно относиться к делу, но поскольку у цели нет временного кристалла, я также изменил void SetSysClock(void)
в system_stm32f0xx.c, чтобы использовать часы HSI и PLL, которые, кажется, работают правильно:
static void SetSysClock(void)
{
RCC->CFGR = (RCC->CFGR & ~RCC_CFGR_SW) | RCC_CFGR_SW_HSI;
while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_HSI) ;
FLASH->ACR = FLASH_ACR_PRFTBE | FLASH_ACR_LATENCY;
RCC->CR &= ~RCC_CR_PLLON;
while (RCC->CR & RCC_CR_PLLRDY) ;
RCC->CFGR = (RCC->CFGR & ~RCC_CFGR_PLLMUL & ~RCC_CFGR_PLLSRC) | RCC_CFGR_PLLMUL11; // PLL takes 8 MHz HSI / 2 as input
RCC->CR |= RCC_CR_PLLON;
while (!(RCC->CR & RCC_CR_PLLRDY)) ;
RCC->CFGR = (RCC->CFGR & ~RCC_CFGR_SW) | RCC_CFGR_SW_PLL;
while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL) ;
}
- РЕДАКТИРОВАТЬ: Дополнительная информация запрашивается в комментариях -
Это ядро M0, поэтому оно не имеет перемещения векторной таблицы. Из справочного руководства, раздел 2.5 (стр. 44):
В отличие от Cortex ® M3 и M4, процессор M0 не поддерживает перемещение векторной таблицы.
Адрес 0x00000000 должен быть сопоставлен либо с флэш-памятью по адресу 0x08000000, системной памятью по адресу 0x1fffd800, либо с SRAM по адресу 0x20000000. Память по адресу 0x00000000 совпадает с системной памятью по адресу 0x1fffd800, хотя SYSCFG_CFGR1 MEM_MODE установлен в 00, что должно отображать флэш-память там. Основная флэш-память по адресу 0x08000000 содержит правильную таблицу векторов, но адрес 0x00000000 заполняется адресом 0x1fffd99d для вектора SysTick (и всех других ненулевых векторов, кроме вектора сброса, который равен 0x1fffdc41); векторы, показанные отладчиком по адресу 0x00000000, соответствуют наблюдаемому поведению. Вся эта информация была собрана во время паузы в точке останова по адресу 0x08000298 (правильная позиция во флэш-памяти, куда был загружен правильный код) перед выполнением прерывания.