Запускаем scmRTOS для Cortex-M3 в среде KEIL uVision4

Что есть сий мануал? Это не инструкция по работе с scmRTOS или средой MDK-ARM. Документ представляет собой инструкцию по переделке порта Cortex-M3 для IAR EWARM в порт Cortex-M3 для Keil uVision4. К сожалению, у меня нет возможности разжевать каждый пункт (пишу ночью на вахте), поэтому данный мануал предназначен больше для тех людей, кто уже знаком с операционной системой реального времени scmRTOS и средой разработки Keil uVision4, и кто, так же как и я, столкнулся с проблемой отсутствия официального порта scmRTOS для кортексов под MDK-ARM. Так что, может, кому-то сие чтиво пригодится…

Ну, не нашёл я порт для Кейла на оффсайте, да и чёрт с ним. Сейчас всё сами сделаем. Пиво можно не открывать, всё произойдёт быстрее, чем ты успеешь допить первую банку. Поехали…

  1. Качаем с оффсайта последний дистрибутив scmRTOS для IAR EWARM – файл scmRTOS.4.00.cortexm3.iar.stm32f1xx.rar (есть внизу топика, если чё).
  2. Создаём папку для нового Keil-проекта. Назовём её RTOS.
  3. Распаковываем ранее скачанный архив и копируем из него папку scmRTOS целиком в созданную нами папку RTOS.
  4. Находим в содержимом архива папку 1-EventFlag, заходим в неё и копируем оттуда папку Src целиком опять же в папку RTOS.
  5. Итого, имеем папку проекта RTOS, а в ней две папки – scmRTOS и Src. Запускаем Keil uVision4 и переходим к созданию нового проекта: Project –> New uVision Project.
  6. Выбираем нашу папку RTOS и придумываем название для файла проекта. Назовём его так же, как и папку проекта – RTOS.uvproj.
  7. Далее выбираем подопытный камень. Пусть это будет STM32F103C8T6, как в DiHalt'овском stm32-модуле к Пинборде-2. Открываем ветку STMicroelectronics и выбираем там наш камень — STM32F103C8.
  8. Визард предлагает нам создать в папке с проектом startup-файл startup_stm32f10x_md.s. Соглашаемся с ним.
  9. В окне проекта жмём правой кнопкой мыши по корню проекта – папке Target1 – и выбираем в выпадающем меню «Add group…», чтобы создать новую группу файлов проекта. Переименовываем только что созданную группу в scmRTOS.
  10. Таким же образом создаём новую группу файлов проекта и называем её Usr.
  11. Двойной клик по группе scmRTOS, чтобы добавить в неё файлы проекта. Откроется проводник проекта, в котором надо выбрать и добавить все файлы из папок внутри папки RTOS/scmRTOS.
  12. Точно так же добавляем все файлы из папки RTOS/Usr (за исключением файлов stm32f10x_it.h, stm32f10x_it.c, stm32f10x_vector.c и stm32f10x_flash.icf) в группу файлов проекта Usr. Должно получиться следующее дерево папок и файлов:



    Можно было, конечно, дать более благозвучные имена для Target1 и Source Group 1, но оставлю это на чужое усмотрение.
  13. Кликаем правой кнопкой мыши по Target1 и выбираем «Options for Target ‘Target1’…».
  14. Откроем вкладку C/C++ и внизу в поле Include Paths добавим пути ко всем папкам нашего проекта. Получится как-то так:



  15. Создадим файл с Intrinsics’ами для KEIL’а. Без него Keil будет ругаться на несуществующие функции __get_interrupt_state(), __set_interrupt_state(), __enable_interrupt(), __disable_interrupt() и __CLZ(), которые есть в IAR’е. Нажимаем Ctrl+N, чтобы создать чистый файл. Вписываем в него следующий код:

    #ifndef _INTRINSICS_H_
    #define _INTRINSICS_H_
    
    #ifdef __cplusplus
     extern "C" {
    #endif
    
    static ASM INLINE status_reg_t __get_interrupt_state(void)
    {
        mrs r0, primask
        bx lr
    }
    
    static ASM INLINE void __set_interrupt_state(status_reg_t StatusReg)
    {
        msr primask, r0
        bx lr
    }
    
    //
    // Keil specific intrinsics.
    //
    
    #define __enable_interrupt() __enable_irq()
    #define __disable_interrupt() __disable_irq()
    #define __CLZ(x) __clz(x)
    
    #ifdef __cplusplus
     }
    #endif
    #endif // _INTRINSICS_H_

    Оставляем последнюю строку пустой, чтобы компилятор не ругался. Сохраняем этот файл под именем intrinsics.h в папке RTOS/Usr и добавляем его в группу файлов проекта Usr.
  16. Открываем файл OS_Target.h. Комментируем строки с 55 по 65, в которых располагаются проверки на тип используемого компилятора и проца. В строке 74 меняем «#define INLINE _Pragma(«inline=forced») inline» на «#define INLINE __inline», а в строке 78 меняем «#define NORETURN __noreturn» на «#define NORETURN __declspec(noreturn)». Далее в строке 96 меняем «#define DUMMY_INSTR() __no_operation()» на «#define DUMMY_INSTR() __nop()». Когда все изменения сделаны, добавим ещё три строчки в секцию Compiler specific attributes. Делаем отступ на 80-й строчке и добавляем:

    #ifndef ASM
    #define ASM __asm
    #endif

    получаем

    //
    //    Compiler specific attributes
    //
    //
    #ifndef INLINE
    #define INLINE __inline
    #endif
    
    #ifndef NORETURN
    #define NORETURN __declspec(noreturn)
    #endif
    
    #ifndef ASM
    #define ASM __asm
    #endif
    
    ...
    
    //
    //    Configuration macros
    //
    //
    #define OS_PROCESS   
    #define OS_INTERRUPT extern "C"
    #define DUMMY_INSTR() __nop()
    #define INLINE_PROCESS_CTOR

  17. Открываем файл OS_Target_asm.s. Keil пока не понимает, что написано в этом файле, т.к. считает, что в S-файлах синтаксис должен быть ассемблерным. Начинаем джедайствовать и переведём для него этот файл. Для начала заменим все двойные слэши – комментарии для C-кода на «точку с запятой» — комментарии для ассемблера. Сделать это проще всего функцией замены Ctrl+H или меню Edit -> Replace. Итак, меняем “//” на “;” во всём файле – Replace All.
  18. Комментируем (уже при помощи «;», помнишь?) строки: 47, 52, 54, 55. В строке 78 меняем «RSEG CODE:CODE(2)» на «PRESERVE8».
  19. Далее идёт код обработчика системного исключения PendSV. С ним мы совершим маленькое шаманство. Так что, копируем весь код обработчика, т.е. строки 110–123 и сохраняем его где-нибудь в пустом файле, чтобы вернуться к нему чуть позже. А весь код обработчика заодно с меткой (т.е. строки 109-123) переводим в комментарии, чтобы под ногами не путались.
  20. В строке 147 содержится логическое выражение «(NVIC_ST_CTRL_CLK_SRC | NVIC_ST_CTRL_INTEN | NVIC_ST_CTRL_ENABLE)». Компилятор выругается на него из-за неверного синтаксиса. Так что, заменяем все «неправильные ИЛИ» (|) на «правильные ИЛИ» для ассемблера (:OR:)

    LDR     R2, =(NVIC_ST_CTRL_CLK_SRC :OR: NVIC_ST_CTRL_INTEN :OR: NVIC_ST_CTRL_ENABLE)

  21. В строке 144 есть команда «LDR R2, =(SYSTICKFREQ/SYSTICKINTRATE-1)», которая задаёт значение регистра перезагрузки для SysTick, т.е. настраивает его частоту срабатывания. В команде используются константы SYSTICKFREQ и SYSTICKINTRATE, которые находятся в файле scmRTOS_TARGET_CFG.h, ныне нами закомментченом. Поэтому добавим их в начало нашего файла перед определениями констант с адресами регистров:

    SYSTICKFREQ EQU 8000000
    SYSTICKINTRATE EQU 500

  22. Теперь оформим функцию os_start() как положено – по-ассемблерски. Выглядеть она будет так:

    AREA    |.text|, CODE, READONLY
    os_start	PROC
    		EXPORT  os_start             [WEAK]
    		LDR     R1, =NVIC_SYSPRI14      ; Set the PendSV exception priority (lowest)
    		LDR     R2, =NVIC_PENDSV_PRI
    		STRB    R2, [R1]
    		LDR     R1, =NVIC_SYSPRI15      ; Set the SysTick exception priority (lowest)
    		LDR     R2, =NVIC_ST_PRI
    		STRB    R2, [R1]
    		
    		LDR     R1, =NVIC_ST_RELOAD     ; Setup SysTick
    		LDR     R2, =(SYSTICKFREQ/SYSTICKINTRATE-1)  
    		STR     R2, [R1]
    		LDR     R1, =NVIC_ST_CTRL       ; Enable and run SysTick
    		LDR     R2, =(NVIC_ST_CTRL_CLK_SRC :OR: NVIC_ST_CTRL_INTEN :OR: NVIC_ST_CTRL_ENABLE)
    		STR     R2, [R1]
    		
    		LDR     R3, [R0, #(4 * 14)]		; Load process entry point into R3
    		ADD     R0, R0, #(4 * 16)       ; emulate context restore
    		MSR     PSP, R0                 ; store process SP to PSP
    		MOV     R0, #2                  ; Switch thread mode stack to PSP
    		MSR     CONTROL, R0
    		ISB                             ; Insert a barrier
    
    		CPSIE   I                       ; Enable interrupts at processor level
    
    		BX      R3                      ; Jump to process exec() function
    		ENDP
    		ALIGN

  23. Открываем файл startup_stm32f10x_md.s. Комментируем строки 132-134. В них находится ссылка на функцию инициализации SystemInit(), которая определена в CMSIS и отсутствует в нашем проекте. Её можно добавить, но, опять же, оставлю это вам.
  24. Ниже в этом файле находим область кода обработчика системного исключения PendSV (строка 174). Помните, в п.19 мы скопировали его код? Теперь вставляем этот код вместо строки 176 «B .». И, чтобы всё заработало правильно, вставляем после строки 175 «EXPORT PendSV_Handler [WEAK]» строку «IMPORT os_context_switch_hook»:

    PendSV_Handler  PROC
                    EXPORT  PendSV_Handler             [WEAK]
    		IMPORT  os_context_switch_hook
    		CPSID   I                 ; Prevent interruption during context switch
    		MRS     R0, PSP           ; PSP is process stack pointer
    		STMDB R0!, {R4-R11}       ; Save remaining regs r4-11 on process stack
    		
    		; At this point, entire context of process has been saved                                                            
    		PUSH    {LR}                           ; Save LR exc_return value
    		LDR     R1, =os_context_switch_hook    ; os_context_switch_hook();
    		BLX     R1
    		
    		; R0 is new process SP;
    		LDMIA R0!, {R4-R11}       ; Restore r4-11 from new process stack
    		MSR     PSP, R0           ; Load PSP with new process SP
    		CPSIE   I
    		POP     {PC}              ; Return to saved exc_return. Exception return will restore remaining context
                    ENDP

    Джедайства закончились.
  25. Заключительный штрих. Открываем файл main.cpp. И оформляем функцию main() следующим образом:

    int main()
    {
        OS::run();
    }

Вот, вроде бы, и всё. Можно жать F7. Если что забыл, исправляйте. Успехов! Благодарю за внимание! :)
  • +6
  • 29 августа 2013, 08:44
  • uRTOS
  • 2

Комментарии (8)

RSS свернуть / развернуть
Предвкушаю новый Холивар.
Производительность VS Время разработки )
0
Полезный холивар.
0
… я бы почитал холливар на тему использование CMSIS-RTOS в качестве HAL для RTOS-ов :)
0
Отличная статья. Кратко, понятно и без лишнего пи.дежа.
0
  • avatar
  • x893
  • 29 августа 2013, 19:29
… можно еще короче, примерно так: «я портировал scmRTOS для Cortex-M3 под uVision. Скачать можно там ..»
+2
Согласен, еще правильнее если ссылки были бы вида github.com/…
0
Отличная работа!
Только надо было брать ось с svn, потому что с момента выхода 4.0 точно были какие-то исправления.
0
статья помогла
0
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.