Переход между приложениями на STM32F1 - PullRequest
0 голосов
/ 30 апреля 2018

Фон

Я пытаюсь реализовать переход между приложениями на микроконтроллере STM32F1. Я использую qemu (предоставленный GNU MCU Eclipse) для эмуляции платы Olimex-H103, в которой используется микроконтроллер STM32F103RBT6. Я использую «голубую таблетку», которую я купил на Ebay, чтобы проверить ее на реальном оборудовании. Синяя таблетка оснащена микроконтроллером STM32F103C8T6. Два микроконтроллера очень похожи и даже используют таблицы из некоторых источников.

STM32F103RBT6 Header board STM32F103RBT6 Заголовок Olimex

STM32F103C8T6 BluePill STM32F103C8T6 BluePill

Мои приложения - это одно основное приложение, которое загружает второе в память, а затем переходит к нему. Основное приложение компилируется и связывается как проект STM32F1 по умолчанию с помощью GNU MCU Eclipse, а второе - это программа на C, скомпилированная и связанная с помощью скрипта связывания (просто указывающего области памяти и размеры), поэтому выравнивание для таблицы векторов отсутствует. Второе приложение связано с основным приложением в виде массива char, который копируется в память. Основное приложение также имеет таблицу поиска для приложений, которые должны быть доступны для дополнительного приложения.

void hello_world();

unsigned int lookup_table[] = {
      (unsigned int)&hello_world
};

После того, как вторичное приложение помещено в память (и проверено, что оно правильно скопировано), основное приложение переходит к нему и передает ссылку на свою справочную таблицу:

typedef int(*AppFunc)(unsigned int);
// Application is compiled with -mthumb, hence the +1 to the address
AppFunc appFunc = (AppFunc)(((uint32_t)0x20003000) + 1);
appFunc((unsigned int)&lookup_table);

Вторичное приложение должно иметь возможность вызывать функции из ссылок в таблице поиска.

void start(unsigned int *lookup_table)
{
    typedef void(*void_f)();
    static void_f hello_func = (void_f)*(lookup_table);

    hello_func();
}

Когда приложение закончено, выполнение должно вернуться к основному приложению (так как адрес возврата находится в стеке?).

Для пояснения: Я (в настоящее время) не изменяю таблицу векторов или указатель стека, поскольку я хотел бы, чтобы они были согласованными (если это возможно).


Проблема

Все это прекрасно работает с qemu, но не с реальным оборудованием. В qemu он переходит ко второму приложению, выполняет функции в главном приложении, а после завершения возвращается к основному приложению. Однако на реальном оборудовании он останавливается после перехода, если start () вызывает методы из таблицы поиска, в противном случае он работает нормально (пустой start ()), но я хочу иметь возможность вернуться назад в основное приложение и выполнять там функции.

Это ошибка в qemu, которая заставляет его работать? Это аппаратная проблема или код? Я не совсем понимаю, в чем проблема, поскольку qemu безупречно запускает приложения.

Заранее спасибо!

Ответы [ 2 ]

0 голосов
/ 02 мая 2018

Я использую следующую функцию для коры

typedef void (application_t)(void);

typedef struct vector
{
    uint32_t        stack_addr;     // intvec[0] is initial Stack Pointer
    application_t*   func_p;        // intvec[1] is initial Program Counter
} vector_t;

void jump_to(const uint32_t addr)
{
    const vector_t* vector_p = (vector_t*)addr;

    // TODO peripheral deinit

    /* Disable interrupt */
    NVIC->ICER[0]=0xFFFFFFFF;
    NVIC->ICPR[0]=0xFFFFFFFF;
#if defined(__NRF_NVIC_ISER_COUNT) && __NRF_NVIC_ISER_COUNT == 2
    NVIC->ICER[1]=0xFFFFFFFF;
    NVIC->ICPR[1]=0xFFFFFFFF;
#endif

    /* Set new vector table */
    SCB->VTOR = (uint32_t)addr;

    /* Jump, used asm to avoid stack optimization */
    asm("\n\
        msr msp, %0; \n\
        bx %1;" : : "r"(vector_p->stack_addr), "r"(vector_p->func_p));
}
0 голосов
/ 01 мая 2018

Знает ли компоновщик второго приложения, где он находится в памяти? Вы не можете связать его так, как если бы он запускался с флэш-памяти, затем скопируйте его в другое адресное пространство и ожидайте, что он будет работать правильно.

Первое местоположение в таблице векторов - это адрес вершины стека. Вам нужно изменить AppFunc appFunc = (AppFunc)(((uint32_t)0x20003000) + 1); на AppFunc appFunc = (AppFunc)(((uint32_t)0x20003004));, чтобы получить адрес обработчика сброса.

Вам не нужно +1 к адресу, который обработал для вас компилятор. У вашего адреса есть указатель на вектор сброса.

...