реклама на сайте
подробности

 
 
> работа scmRTOS из RAM и несколько вопросов, GCC, STM32F10x
Aaron
сообщение Feb 26 2014, 11:35
Сообщение #1


Местный
***

Группа: Свой
Сообщений: 243
Регистрация: 5-10-06
Из: Зеленоград
Пользователь №: 21 007



Создал загрузчик для STM32F10x, работающий в двух процессах ОС.
Все функции загрузчика объявлены в классе, размещаются в .ramfunc секции:
Код
void erasePage(const uint32_t * const page_addr) __attribute__ ((section(".ramfunc")));
void writePage(const uint32_t * const page_addr, const uint8_t * const pagebuf) __attribute__ ((section(".ramfunc")));
uint8_t read(const uint8_t * const addr) __attribute__ ((section(".ramfunc")));

Соответственно, секция в линковщике определяется перед .data:
Код
    .text.align :
    {
        . = ALIGN(8);
        _etext = .;
        _sidata = _etext;        /* start of initialized data label */
    } > FLASH

    /* RAM functions section */
    .ramfunc :                    
    {
        . = ALIGN(8);
        _sdata = .;                    /* start of .data label */
        KEEP( *(.ramfunc) )
        KEEP( *(.ramfunc.*) )
    } > RAM AT > FLASH

    .data :                        /* AT makes the LMA follow on in the binary image */
    {
        . = ALIGN(4);
        KEEP( *(.data) )
        KEEP( *(.data.*) )
        . = ALIGN(4);
        _edata = .;                /* end of .data label */
    } > RAM AT > FLASH
...

Вопрос 1: Что надо сделать, чтобы загрузчик мог обновлять помимо пользовательской прошивки в том числе и себя.
Предположение: для этого необходимо все функции ОС выделить в отдельную секцию, например .scmRTOS, и секцию поместить в RAM по аналогии с .ramfunc.
Насколько это легко осуществимо? Или мне надо оставить всё в секции .text и её целиком в RAM пихать, т.к. есть ещё глобальные объекты со своими функциями? Ни разу так не пробовал ещё...

Вопрос 2: возможно ли использовать какую-то #pragma, чтобы пихать содержимое всего файла или части файла в отдельную секцию? Сейчас каждый раз перед телом функции пишу атрибут:
Код
__attribute__ ((section(".ramfunc"))) void flashdrv_t::erase (void) { ... }
Предположение: я неверно понимаю использование атрибута section и его достаточно 1 раз написать в начале файла.

Вопрос 3: возможно ли как-нибудь остановить выполнение ОС и продолжить нормальное выполнение кода, находящегося после строчки OS::run(); ?
Предположение: запретить pensv, systick, и осуществить переход goto label по прямой ссылке.
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов
Aaron
сообщение Mar 25 2014, 04:44
Сообщение #2


Местный
***

Группа: Свой
Сообщений: 243
Регистрация: 5-10-06
Из: Зеленоград
Пользователь №: 21 007



Вернулся наконец-то к загрузчику, доделал. Начал тестировать и столкнулся неожиданно с проблемами. Пытаюсь вкурить, где косяк, но никак не могу докопаться.
Суть в следующем: загрузчик передаёт управление пользовательской прошивке, и она сразу вываливается в HardFault_Handler.
Передача управления из загрузчика стандартная на основе AN2557 для stm32f1:
Код
static void JumpToApplication(uint32_t addr)
{
    typedef  void (*pFunction)(void);
    pFunction Jump_To_Application;
    uint32_t JumpAddress;
    if(addr < ADDR_USER_START) {
        printf("Try to start User App from BL code area!\r\n");
        return;
    }
    /* Test if user code is programmed starting from our address */
    if (((*(__IO uint32_t*)addr) & 0x2FFE0000) == SRAM_BASE) {
        __disable_irq();
        NVIC_SetVectorTable(NVIC_VectTab_FLASH, FLASH_BL_SIZE);
        JumpAddress = *(__IO uint32_t*) (addr + 4);
        Jump_To_Application = (pFunction) JumpAddress;
        /* Initialize user application's Stack Pointer */
        __set_MSP(*(__IO uint32_t*) addr);
        Jump_To_Application();
    } else {
        printf("User App detect failed!\r\n");
    };
}

Соответственно, пользовательский код линкуется в stm32f107 со смещением (прошивка с дефолтным нулевым смещением работает нормально, проверено), никаких дополнительных манипуляций в коде не делается:
Код
MEMORY
{
    RAM (xrw)    : ORIGIN = 0x20000000, LENGTH =  64K
    FLASH (rx)    : ORIGIN = 0x0800A000, LENGTH = 216K    /* bootloader version. FLASH_BL_SIZE = 0xA000 */
}

Подробности анализа пользовательской прошивки при падении:
Цитата
---- SP registers ------
R0 : 0x20003094 адрес Process_ADC object
R1 : 0x20003168 адрес внутри Process_ADC object
R2 : 0x0000ABBA scmRTOS_STACK_PATTERN
R3 : 0x20003128 адрес внутри Process_ADC object
R12: 0x888344B4
LR : 0x0800B2DB ссылка на конец функции void OS::TKernel::register_process(OS::TBaseProcess* const p) :
800b2da: mov r0, r4
800b2dc: pop {r4, r5, r6, pc}
PC : 0x0000ABBA scmRTOS_STACK_PATTERN
PSR: 0x60000000

Stack at : 0x20003098 reg_PSP (Process Stack Pointer)

----
PSR: 0x60000000, Program Status Register, expanding:
Z = 1 Zero condition
C = 1 Carry or borrow condition
ICI/IT = 0 (saved IT state): ICI
reg# = 0 (used)
T = 0 ARM mode
ISR Vector = 0: &_estack (program entry point)
Vector addr: 0x2000FFF8 - соответствует ld-файлу: PROVIDE (_estack, ALIGN (((ORIGIN (RAM) + 0x10000) - 0x8), 0x8))

---- Fault Status ------
SCB->CFSR: 0x00020000 Configurable Fault Status Register, expanding:
INVSTATE: 1 Invalid combination of EPSR and instruction

SCB->VTOR: 0x0800A000 Vector table offset register

Остальные регистры не содержат интересной информации.
Это нормально, что в PC содержится паннерн для анализа стека?
Я так понимаю, это ещё не важно, т.к. ISR Vector = 0: &_estack (program entry point) - то есть падение происходит на первой же строчке пользовательской прошивке? Я правильно понимаю?
Посоветуйте плз, куда ещё копать, почему пользовательская прошивка не стартует нормально? Проблемы со стеком? help.gif
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Mar 25 2014, 08:45
Сообщение #3


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



Судя по содержимому PC, в него вместо адреса возврата из стека заносится код-заполнитель свободного пространства стека одной из задач ОС. OS::TKernel::register_process() вызывается из консруктпроцессор как раз перед заполением стека этим кодом. Похоже у вас основной стек налезает на область даннных, в которой и хранятся стеки процессов. Похоже, где-то вы пожалели стека для main(). И что интересно - в загрузчике вы корректно загружаете MSP, а в точке вылета почему-то используется PSP, хотя в scmRTOS переключение на него происходит при старте первого процесса. Возможно ваш загрузчик где-то переключается на PSP? Тогда надо бы перед передачей управления либо грузить его вместо MSP, либо, что более идеологически правильно, переключаться обратно на MSP после его загрузки.

Да, кстати - не факт, что используется PSP. Это я так подумал исходя из его упоминания в вашем анализе и вполне адекватного значения в нем. Чтобы убедиться надо бы посмотртеть содержимое первого бита регистра CONTROL.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post



Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 25th July 2025 - 21:05
Рейтинг@Mail.ru


Страница сгенерированна за 0.02068 секунд с 7
ELECTRONIX ©2004-2016