Stm32f4 Discovery Interrupt с программой в ОЗУ

Я пытаюсь сделать ОСРВ, которую мы использовали в школе для работы над моей доской для открытий. В школе мы использовали некоммерческую плату, а ОСРВ загружалась в оперативную память. Мне удалось загрузить это в ОЗУ на плате обнаружения, но у меня проблемы с прерыванием таймера. Я не вижу нигде в RTOS-коде, где процессору сказано перейти к определенному адресу, когда таймер вызывает прерывание. Однако есть адреса и указатели функций, инициализированные этими адресами. Но как процессор знает, как переходить по этим адресам? ОСРВ не использует SCB-> VTOR для перемещения вектора прерывания.

Я удалил весь ненужный (я думаю и надеюсь) код, чтобы показать проблему в меньшем файле. Чтобы еще больше упростить, я мигаю светодиодом на прерывании таймера.

Если я смогу заставить эту небольшую программу работать, то, возможно, я смогу заставить работать RTOS, поэтому любая помощь будет очень признательна. Я сделал несколько комментариев в коде. Итак, чего не хватает в приведенном ниже коде для запуска обработчика прерывания?

#include "stm32f4xx.h"
#include "stm32f4xx_rcc.h"
#include "stm32f4xx_gpio.h"
#include "stm32f4xx_tim.h"

void timer5_init(void);
void led_init();
void init_all(void);

void startup(void) __attribute__((naked)) __attribute__((section (".start_section")) );

#define TIM5_IRQ_VECTOR         (0x2001C000+0x108)
#define TIMER5_INTERRUPT    void vect_TIM5( void ) 

TIMER5_INTERRUPT;

void startup(void) {
    asm volatile(
        " NOP\n"
        " LDR SP,=0x2001C000\n" // Set stack
        " BL main\n"
        ".L1: B .L1\n"  
            );
}

void main() {
    init_all();

    while (1) {
        // Toggle blue led
        GPIO_ToggleBits(GPIOD, GPIO_Pin_15); // This works.   
        ms_delay2(250); 
    }
}

void init_all() {
    led_init();
    timer5_init();
}

TIMER5_INTERRUPT {

    if (TIM_GetITStatus(TIM5, TIM_IT_Update)) {
        // Toggle orange led
        GPIO_ToggleBits(GPIOD, GPIO_Pin_13);
    TIM_ClearITPendingBit(TIM5, TIM_IT_Update);
    }

}

void timer5_init() {
    RCC_APB1PeriphClockCmd( RCC_APB1Periph_TIM5, ENABLE);
    RCC_APB1PeriphClockLPModeCmd( RCC_APB1Periph_TIM5, ENABLE);

    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;  
    TIM_DeInit(TIM5);
    TIM_TimeBaseStructInit(&TIM_TimeBaseInitStructure);
    TIM_TimeBaseInitStructure.TIM_Prescaler = 840-1; 
    TIM_TimeBaseInit(TIM5, &TIM_TimeBaseInitStructure);

    *((void (**)(void) ) TIM5_IRQ_VECTOR ) = vect_TIM5;// Why are they using vect_TIM5 here,
                                                         // instead of TIMER5_INTERRUPT? 
                                                        // Insn't vect_TIM5 just the definition
                                                       // of the macro? Why is this working?
    NVIC_SetPriority( TIM5_IRQn, 0x00);

    NVIC_EnableIRQ( TIM5_IRQn);
    TIM_SetCounter(TIM5, 0);    
    TIM_Cmd( TIM5, ENABLE);
    TIM_ITConfig( TIM5, TIM_IT_CC1, ENABLE);    
 }

void led_init() {
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
    GPIO_InitTypeDef GPIO_InitDef;
    GPIO_InitDef.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_15;
    GPIO_InitDef.GPIO_Mode = GPIO_Mode_OUT;
    GPIO_InitDef.GPIO_OType = GPIO_OType_PP;
    GPIO_InitDef.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_InitDef.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOD, &GPIO_InitDef);
}

ЛИНКЕРНЫЙ СЦЕНАРИЙ:

MEMORY
{
    RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 112K
}

SECTIONS
{

    .text :
    {
        . = ALIGN(4);

        *(.start_section)          
        *(.text)                   
        *(.text.*)
        *(.rodata)                 
        *(.rodata*)
        *(.glue_7)
        *(.glue_7t)

         . = ALIGN(4);
     } >RAM


     .data  :
     {
        . = ALIGN(4);

         *(.data)
         *(.data.*)

         . = ALIGN(4);
     } >RAM


     .bss :
     {
         . = ALIGN(4);

          _sbss = .;

        *(.bss)
            *(.bss.*)
         *(COMMON)

         . = ALIGN(4);

        _ebss = . ;
     } >RAM

     PROVIDE ( end = _ebss );
     PROVIDE ( _end = _ebss );
 }

Разве вам не нужно иметь код загрузчика в стартовой сборке, которая копирует код main из флэш-памяти в ОЗУ, чтобы там можно было выполнить? Если между обработчиком сброса и main() нет кода, который это делает, то это не будет выполнено. И да, вам нужно будет указать NVIC использовать векторы в ОЗУ.

unwind 20.09.2018 15:52

«Э, разве вам не обязательно иметь код загрузчика в стартовой сборке, который копирует основной код из флэш-памяти в ОЗУ для выполнения там?» Я забыл упомянуть, что я использую gdb для загрузки программы в оперативную память. Не знаю, почему это работает.

Lars Logik 20.09.2018 16:02

@unwind Нет никакой таблицы векторов. Там почти все не так. Они пытаются делать что-то, что выходит за рамки их знаний. Сначала они должны узнать, как работает микроконтроллер, а затем попытаться сделать сложные системные вещи.

0___________ 20.09.2018 23:39

Хорошо, тогда я, должно быть, слишком удалил исходный код. Спасибо.

Lars Logik 21.09.2018 00:54
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
4
216
0

Другие вопросы по теме