Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: scmRTOS. Вопросы и ответы.
Форум разработчиков электроники ELECTRONIX.ru > Cистемный уровень проектирования > Операционные системы
Страницы: 1, 2
alexander55
Из-за того, что мои предложения повисли в воздухе, решил открыть тему здесь.
У меня вопросы по scmRTOS (извините, если они покажутся дилетанскими, я только начал мучить ОС). Раньше считал, что в uC OS лишняя заморочка, сейчас уже так не считаю.
Общие вопросы для общего развития. smile.gif
1. Зачем понадобилось иметь порядок приоритетов сверху вниз (насколько я понял из-за Blackfin только). a&-a немногим проигрывает.
2. Я хочу ограничиться
#if scmRTOS_CONTEXT_SWITCH_SCHEME == 0,
т.е. использовать всегда программное прерывание.
Правильно ли это ?
3. Про OS::TChannel сказано, что этот объект оставлен для совместимости с версией 1. Рекомендуется пользоваться OS::channel.
Мне же показалось, несмотря на универсальность OS::channel, применение его для байтовых каналов слишком расточительным. Я бы рассматривал бы как чистый FIFO буфер, как-то так
#define TFIFO OS::Channel
и изменил он нем представление как об атавизме. Или я чего-то не понял ?

Платформозависимые вопросы.
Я использую LPC2148 с IAR 5.10. Использовал порт Сергея Борщ с незначительными собственными доработками.
1. Интересует особенности использования векторных прерываний, кроме системного времени. На что следует обращать внимание.
2. Или их использовать нежелательно.
PS. Не считайте мои вопросы наездом, scmRTOS - замечательная вещь. a14.gif
dxp
Цитата(alexander55 @ Oct 1 2007, 16:35) *
1. Зачем понадобилось иметь порядок приоритетов сверху вниз (насколько я понял из-за Blackfin только). a&-a немногим проигрывает.

Не понял, что дает a & -a. У Blackfin'a есть специальная команда, которая сразу вычисляет позицию первого ненулевого бита. Оба порядка приоритетов сущестувуют, чтобы можно было оптимизировать операцию вычисления приоритета для конкретного процессора. Пока это только Blackfin. Но кто знает, может есть и еще какие. Кажется у FR32 (Fujitsu) тоже есть такая аппаратная возможность.

Цитата(alexander55 @ Oct 1 2007, 16:35) *
2. Я хочу ограничиться
#if scmRTOS_CONTEXT_SWITCH_SCHEME == 0,
т.е. использовать всегда программное прерывание.
Правильно ли это ?

Надо указать в конфиге:
#define scmRTOS_CONTEXT_SWITCH_SCHEME 1.

Цитата(alexander55 @ Oct 1 2007, 16:35) *
3. Про OS::TChannel сказано, что этот объект оставлен для совместимости с версией 1. Рекомендуется пользоваться OS::channel.
Мне же показалось, несмотря на универсальность OS::channel, применение его для байтовых каналов слишком расточительным. Я бы рассматривал бы как чистый FIFO буфер, как-то так
#define TFIFO OS::Channel
и изменил он нем представление как об атавизме. Или я чего-то не понял ?

Вы сравнили производительность OS::TChannel и OS::channel<byte> и она оказалась в пользу первого? Или на основании чего такая оценка?
Сергей Борщ
Цитата(alexander55 @ Oct 1 2007, 12:35) *
Из-за того, что мои предложения повисли в воздухе, решил открыть тему здесь.
А это всегда так. Чтобы что-то сдвинулось - надо сделать это самому smile.gif
Цитата(alexander55 @ Oct 1 2007, 12:35) *
1. Зачем понадобилось иметь порядок приоритетов сверху вниз (насколько я понял из-за Blackfin только). a&-a немногим проигрывает.
Не только для blackfin. Это для любого процессора, у которого есть встроенная инструкция clz - подсчета количества ведущийх нулей. Тогда нахождение самого приоритетного процесса, ожидающего выполнения сводится к одной этой команде. Такой же подход, если не изменяет память, реализован в порте для фуджиков. Ядро ARM имеет такую команду начиная с v5, поэтому для таких ARMов обратный порядок приоритетов будет давать выигрыш в объеме кода и, главное, времени переключения контекста. В текущем порте для ARM поддержка обратного порядка приоритетов является атавизмом, тянущемся со второй версии, когда для обратного порядка приоритетов pr0 был самым низкоприоритетным процессом. Тогда я реализовал поддержку обратного порядка для упрощения портирования между платформами. В третьей версии мы придумали простой способ объявлять pr0 самым высоким приоритетом вне зависимости от прямого/обратного порядка. Наверное нужно в следующем релизе поддержку обратного порядка из порта исключить, а задание scmRTOS_PRIORITY_ORDER перенести из пользовательских исходников в исходники порта, тем более что для количества процессов меньше 6 GetPrioTag() вычисляется таблично и разницы нет ни по времени, ни по объему, а для большего кол-ва процессов вычисление для прямого порядка компилируется в более эффективный код.
Цитата(alexander55 @ Oct 1 2007, 12:35) *
2. Я хочу ограничиться
#if scmRTOS_CONTEXT_SWITCH_SCHEME == 0,
т.е. использовать всегда программное прерывание.
Правильно ли это ?
Программное прерывание это #define scmRTOS_CONTEXT_SWITCH_SCHEME 1. Да, это более эффективный метод - весь контекст сохранятется/восстанавливается только когда необходимо перепланирование, а не в каждом прерывании - но, к сожалению, он не работает на кристаллах без контроллера прерываний (ADuC). В любом случае вы всегда можете его изменить, сравнить результаты и выбрать более подходящий.

Про TCannel лучше ответит dxp.
Цитата(alexander55 @ Oct 1 2007, 12:35) *
Платформозависимые вопросы.
1. Интересует особенности использования векторных прерываний, кроме системного времени. На что следует обращать внимание.
1)Не забывать в прерываниях, которые используют сервисы ОС заводить в начале обработчика объект типа OS::TISRW
2) Не забывать, что некоторые сервисы (тот же channel) при отсутствии/избытке данных могут захотеть перевести текущий процесс в спячку, что для прерывания невозможно.
3) Пока не реализована поддержка вложенных прерываний. Я с трудом представляю, с какой стороны к этому подступиться. Если реализуете - не забудьте поделиться smile.gif
Других ограничений вроде как нет.

P.S. и не стесняйтесь склонять мою фамилию beer.gif
alexander55
Цитата(dxp @ Oct 1 2007, 15:11) *
Вы сравнили производительность OS::TChannel и OS::channel<byte> и она оказалась в пользу первого? Или на основании чего такая оценка?

Приведите, пожалуйста, пример аналога Push-Pop для channel.
dxp
Цитата(alexander55 @ Oct 1 2007, 19:49) *
Приведите, пожалуйста, пример аналога Push-Pop для channel.

Не понял вопроса. В чем затруднение? Все аналогично:

Код
OS::channel<byte, 16> queue; // очередь на 16 байт

...
queue.push(10);

...

byte x;
queue.pop(x);

Отличия, конечно, имеются - OS::channel::pop(), в частности, поддерживает таймауты, поэтому будет работать чуть медленнее.

Мне не совсем понятна суть исходного вопроса. Если имеелось в виду, почему рекомендуется шаблонный сервис, то ответ такой:
  1. OS::TCannel использует макроподстановки, что не есть гуд.
  2. OS::channel имеет расширенную функциональность (таймауты и возможность, например, помещать элемент не только в конец очереди, но и в начало).
  3. Для единства стиля.
alexander55
Цитата(Сергей Борщ @ Oct 1 2007, 15:42) *
В третьей версии мы придумали простой способ объявлять pr0 самым высоким приоритетом вне зависимости от прямого/обратного порядка. Наверное нужно в следующем релизе поддержку обратного порядка из порта исключить

У меня нюх как у собаки. smile.gif

Цитата(Сергей Борщ @ Oct 1 2007, 15:42) *
Программное прерывание это #define scmRTOS_CONTEXT_SWITCH_SCHEME 1.

Я считал также, но в Вашем порте сделано наоборот, поэтому я так и решил. Но это не принципиально.

Цитата(Сергей Борщ @ Oct 1 2007, 15:42) *
Да, это более эффективный метод - весь контекст сохранятется/восстанавливается только когда необходимо перепланирование, а не в каждом прерывании - но, к сожалению, он не работает на кристаллах без контроллера прерываний (ADuC). В любом случае вы всегда можете его изменить, сравнить результаты и выбрать более подходящий.

Это соответствует моим представлениям.

Цитата(Сергей Борщ @ Oct 1 2007, 15:42) *
1)Не забывать в прерываниях, которые используют сервисы ОС заводить в начале обработчика объект типа OS::TISRW

Понял, также как с системным таймером.

Цитата(Сергей Борщ @ Oct 1 2007, 15:42) *
2) Не забывать, что некоторые сервисы (тот же channel) при отсутствии/избытке данных могут захотеть перевести текущий процесс в спячку, что для прерывания невозможно.

Хочется поподробнее осветить этот момент.

Цитата(Сергей Борщ @ Oct 1 2007, 15:42) *
3) Пока не реализована поддержка вложенных прерываний. Я с трудом представляю, с какой стороны к этому подступиться. Если реализуете - не забудьте поделиться smile.gif
Других ограничений вроде как нет.

Насколько я знаю по Keil, вложенные прерывания реализуются через макросы при входе и выходе из прерывания, но т.к. на возврат используется один регистр приходится пользоваться стеком, чтобы не затереть. Вложенные прерывания, на мой взгляд, извращение (но я не догматик). Тем более создатели ARM, я надеюсь, солидарны со мной. smile.gif

Цитата(Сергей Борщ @ Oct 1 2007, 15:42) *
P.S. и не стесняйтесь склонять мою фамилию beer.gif

Спасибо dxp и Сергею Борщу за оперативность (я тоже исправляюсь). biggrin.gif

Цитата(dxp @ Oct 1 2007, 17:10) *
Не понял вопроса. В чем затруднение? Все аналогично:

Код
OS::channel<byte, 16> queue; // очередь на 16 байт

...
queue.push(10);

...

byte x;
queue.pop(x);

Отличия, конечно, имеются - OS::channel::pop(), в частности, поддерживает таймауты, поэтому будет работать чуть медленнее.

Понял, это мой глюк.

Цитата(dxp @ Oct 1 2007, 17:10) *
Мне не совсем понятна суть исходного вопроса. Если имеелось в виду, почему рекомендуется шаблонный сервис, то ответ такой:
  1. OS::TCannel использует макроподстановки, что не есть гуд.
  2. OS::channel имеет расширенную функциональность (таймауты и возможность, например, помещать элемент не только в конец очереди, но и в начало).
  3. Для единства стиля.

А это как раз понятно. biggrin.gif
Сергей Борщ
Цитата(alexander55 @ Oct 1 2007, 16:36) *
Хочется поподробнее осветить этот момент.
Ну например прерывание передачи по UART забирает данные из OS:channel<uint8_t>. А данные там кончились... В этом случае pop() попытается передать управление другой задаче, и это приведет к краху. Поэтому прежде чем вызвать pop() надо проверить - а есть ли данные. Аналогично для push().
Для TEventFlag есть специальная функция SignalISR() - ее можно использовать в прерываниях без опаски. Она при необходимости может поставить какую-либо задачу в очередь готовых к выполнению, но саму перепланировку не выполняет - перепланировка будет выполнена после выхода из прерывания.


Цитата(alexander55 @ Oct 1 2007, 16:36) *
Я считал также, но в Вашем порте сделано наоборот, поэтому я так и решил. Но это не принципиально.
В каком месте? Покажите, может там ошибка...
alexander55
Цитата(Сергей Борщ @ Oct 1 2007, 18:53) *
Ну например прерывание передачи по UART забирает данные из OS:channel<uint8_t>. А данные там кончились... В этом случае pop() попытается передать управление другой задаче, и это приведет к краху. Поэтому прежде чем вызвать pop() надо проверить - а есть ли данные. Аналогично для push().
Для TEventFlag есть специальная функция SignalISR() - ее можно использовать в прерываниях без опаски. Она при необходимости может поставить какую-либо задачу в очередь готовых к выполнению, но саму перепланировку не выполняет - перепланировка будет выполнена после выхода из прерывания.

Понял.

Цитата(Сергей Борщ @ Oct 1 2007, 18:53) *
В каком месте? Покажите, может там ошибка...

Откуда я залил уже не помню.
Файл OS_Target_asm.s79
Дата файла от 08.02.07
//******************************************************************************
//*
//* FULLNAME: Single-Chip Microcontroller Real-Time Operating System
//*
//* NICKNAME: scmRTOS
//*
//* PROCESSOR: ARM7
//*
//* TOOLKIT: EWARM (IAR Systems)
//*
//* PURPOSE: Target Dependent Low-Level Stuff
//*
//* Version: 3.00-beta
//*
//* $Revision: 31 $
//* $Date: 2007-02-08 18:51:14 +0600 (╨є╤й, 08 ╤д╨╡╨▓ 2007) $
//*
//* Copyright © 2003-2006, Harry E. Zhurov
//*
//* Permission is hereby granted, free of charge, to any person
//* obtaining a copy of this software and associated documentation
//* files (the "Software"), to deal in the Software without restriction,
//* including without limitation the rights to use, copy, modify, merge,
//* publish, distribute, sublicense, and/or sell copies of the Software,
//* and to permit persons to whom the Software is furnished to do so,
//* subject to the following conditions:
//*
//* The above copyright notice and this permission notice shall be included
//* in all copies or substantial portions of the Software.
//*
//* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
//* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
//* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
//* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
//* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
//* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
//* THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//*
//* =================================================================
//* See http://scmrtos.sourceforge.net for documentation, latest
//* information, license and contact details.
//* =================================================================
//*
//******************************************************************************
//* ARM port by Sergey A. Borshch, Copyright © 2006


#include "scmRTOS_CONFIG.h"
#include "scmRTOS_TARGET_CFG.h"
#include "OS_Target_core.h"

module scmRTOS_Asm


#define MODE_USER 0x10
#define MODE_FIQ 0x11
#define MODE_IRQ 0x12
#define MODE_SVC 0x13
#define MODE_ABORT 0x17
#define MODE_UND 0x1B
#define MODE_SYS 0x1F

#define NIRQ (1<<7)
#define NFIQ (1<<6)
#define THUMB (1<<5)

// Context structure:
// lo address
// CPSR
// R14 (LR)
// R0
// R1
// R2
// R3
// R4
// R5
// R6
// R7
// R8
// R9
// R10
// R11
// R12
// Process interrupt point (return address)
// hi address

CODE32
;-------------------------------------------------------------------------------

#if scmRTOS_CONTEXT_SWITCH_SCHEME == 0
COMMON INTVEC:CODE:ROOT
org 0x00000008
LDR PC, Context_Switcher_Adr ; Branch to swi_handler
org 0x00000018
LDR PC, IRQ_Wrapper_Adr
org 0x00000020

org 0x00000028
Context_Switcher_Adr:
DC32 Context_Switcher

org 0x00000038
IRQ_Wrapper_Adr:
DC32 IRQ_Wrapper

;-------------------------------------------------------------------------------
RSEG ICODE:CODE

IRQ_Wrapper:
MSR CPSR_c, #(NIRQ | MODE_SYS) ; switching to System mode, because context has to be saved
; on top of user mode stack, enable FIQ
STMFD SP!, {R0-R12,LR} ; store R0_R12, dummy store LR to reserve space in context
STMFD SP!, {R1,LR} ; reserve space for CPSR, store LR_user on top of context

MOV R0, SP ; store context pointer in non-banked register
MSR CPSR_c, #(NIRQ | MODE_IRQ) ; switching back to IRQ mode
SUB LR, LR, #4 ; adjusting return address
STR LR, [R0, #4*15] ; store return address in reserved space (instead of saved LR_user)
MRS R1, SPSR ; move stored CPSR of process to non-banked register
STR R1, [R0] ; store SPSR in reserved space (instead of saved R1)

IRQ_SWITCH ; call IRQ handler

MSR CPSR_c, #(NIRQ | MODE_SYS) ; switching to System mode, because context has to be restored
; from user mode stack, enable FIQ
MOV R0, SP
B ContextRestore ; restore saved IRQ context

RSEG ICODE:CODE
PUBLIC SaveSP
PUBLIC Set_New_SP

SaveSP:
// __arm void SaveSP(TStackItem** Curr_SP)
MSR CPSR_c, #(NIRQ | MODE_SYS) ; switching to System mode, to get access to sp_user
STR SP, [R0]
MSR CPSR_c, #(NIRQ | MODE_IRQ) ; switching back to IRQ mode
BX LR
Set_New_SP:
// __arm void SetNewSP(TStackItem* New_SP)
MSR CPSR_c, #(NIRQ | MODE_SYS) ; switching to System mode, to get access to sp_user
MOV SP, R0
MSR CPSR_c, #(NIRQ | MODE_IRQ) ; switching back to IRQ mode
BX LR

;-------------------------------------------------------------------------------
// __swi __arm void OS_ContextSwitcher(TStackItem** Curr_SP, TStackItem* Next_SP);
Context_Switcher:
MSR CPSR_c, #(NIRQ | MODE_SYS) ; switching to System mode, because context has to be saved
; on top of user mode stack, enable FIQ
STMFD SP!, {R0-R12,LR} ; store R0_R12, dummy store LR to reserve space in context

SUB R2, SP, #4*2 ; store context pointer in non-banked register (reserve space for CPSR, LR)
MSR CPSR_c, #(NIRQ | MODE_SVC) ; switching back to supervisor mode
STR LR, [R2, #4*15] ; store return address in reserved space (instead of saved LR_user)
MRS R3, SPSR ; move stored CPSR of process to non-banked register
MSR CPSR_c, #(NIRQ | MODE_SYS) ; switching back to System mode

STMFD SP!, {R3,LR} ; store CPSR, LR_user on top of context and adjust SP_user
STR SP,[R0]
MOV R0, R1
ContextRestore
LDMFD R0!, {R1, LR} ; restoring LR_user, saved CPSR_user
ADD SP, R0, #4*14 ; set process SP

MSR CPSR_c, #(NIRQ | MODE_IRQ) ; switch to IRQ mode to get access to SPSR_irq
MSR SPSR_cxsf, R1 ; store process CPSR to SPSR_irq to restore at return from irq

LDMFD R0, {R0-R12,PC}^ ; restoring remaining context, CPSR and reti

#else //if scmRTOS_CONTEXT_SWITCH_SCHEME == 1;
-------------------------------------------------------------------------------
COMMON INTVEC:CODE:ROOT

org 0x00000018
IRQ_SWITCH ; ∩σ≡σ⌡εΣ ∩ε αΣ≡σ±≤ Φτ ΓσΩ≥ε≡φεπε Ωεφ≥≡εδδσ≡α
;-------------------------------------------------------------------------------
RSEG ICODE:CODE
// TStackItem* OS_ContextSwitchHook(TStackItem* sp);
EXTERN OS_ContextSwitchHook
PUBLIC ContextSwitcher_ISR
ContextSwitcher_ISR:
MSR CPSR_c, #(NIRQ | MODE_SYS) ; switching to System mode, because context has to be saved
; on top of user mode stack, enable FIQ
STMFD SP!, {R0-R12,LR} ; store R0_R12, dummy store LR to reserve space in context

SUB R0, SP, #4*2 ; store context pointer in non-banked register (reserve space for CPSR, LR)
MSR CPSR_c, #(NIRQ | MODE_IRQ) ; switching back to IRQ mode
SUB LR, LR, #4 ; adjusting return address
STR LR, [R0, #4*15] ; store return address in reserved space (instead of saved LR_user)
MRS R1, SPSR ; move stored CPSR of process to non-banked register
MSR CPSR_c, #(NIRQ | MODE_SYS) ; switching back to System mode

STMFD SP!, {R1,LR} ; store CPSR, LR_user on top of context and adjust SP_user
; to use process stack in OS_ContextSwitchHook
_BLF OS_ContextSwitchHook, Hook_Relay ; store context pointer(R0), get new context pointer(R0)
IRQ_DONE ; reset interrupt controller
ContextRestore
LDMFD R0!, {R1, LR} ; restoring LR_user, saved CPSR_user
ADD SP, R0, #4*14 ; set process SP

MSR CPSR_c, #(NIRQ | MODE_IRQ) ; switch to IRQ mode to get access to SPSR_irq
MSR SPSR_cxsf, R1 ; store process CPSR to SPSR_irq to restore at return from irq

LDMFD R0, {R0-R12,PC}^ ; restoring remining context, CPSR and reti

RSEG ICODE:CODE
Hook_Relay:
LDR R1, =OS_ContextSwitchHook ; call Thumb mode routine
BX R1
#endif


;-------------------------------------------------------------------------------
RSEG CSTACK:DATA
RSEG ICODE:CODE
// Set SP_irq to main() stack, restore context referenced by R0

// void OS_Start(TStackItem* sp);
PUBLIC OS_Start
OS_Start:
MSR CPSR_c, #(NIRQ | NFIQ | MODE_IRQ) ; switching to IRQ mode, disable FIQ & IRQ
LDR SP, =SFE(CSTACK) & 0xFFFFFFF8 ; End of CSTACK
MSR CPSR_c, #(NIRQ | NFIQ | MODE_SYS) ; switching back to System mode, disable FIQ & IRQ
; ContextRestore typically called from System mode

B ContextRestore ; Restore context = run process
;-------------------------------------------------------------------------------
ENDMOD

END
PS. Я в тесте выделил красным и зеленым цветом места.
Я текст исходный.
Сергей Борщ
Цитата(alexander55 @ Oct 2 2007, 07:43) *
PS. Я в тесте выделил красным и зеленым цветом места.
Нет, это не то. В scmRTOS под "программным прерыванием" понимается обычное прерывание, которое генерится из программы:
Код
#if scmRTOS_CONTEXT_SWITCH_SCHEME == 1
// #define used instead of inline function to ensure inlining to both ARM and THUMB functions.
#define RaiseContextSwitch()                                \
    do                                                      \
    {                                                       \
        AT91C_BASE_AIC->AIC_ISCR = (1<<CONTEXT_SWITCH_INT); \
    }                                                       \
    while (0) // set flag and enable interrupt
#endif
...
#else   //if scmRTOS_CONTEXT_SWITCH_SCHEME == 1
;-------------------------------------------------------------------------------
        PUBLIC  ContextSwitcher_ISR
ContextSwitcher_ISR:
        MSR     CPSR_c, #(NIRQ | MODE_SYS) ; switching to System mode, because context has to be saved
                                           ; on top of user mode stack, enable FIQ
Его преимущество именно в том, что даже если его сгенерировать внутри прерывания, в обработчик мы попадем "с чистого листа", т.е. из фона, когда на стеке нет данных из обработчиков других прерываний. Это сильно упрощает процесс переключения контекста. Поскольку swi не маскируется - его использовать для этой цели не получилось. А в нулевом варианте swi используется просто как быстрый способ вызвать функцию с переходом в ARM-режим.
alexander55
[quote name='Сергей Борщ' date='Oct 2 2007, 11:57' post='301622']
Нет, это не то. В scmRTOS под "программным прерыванием" понимается обычное прерывание, которое генерится из программы
[/quote]
Я считал "программным прерыванием" SWI. Отсюда вся путаница.
Теперь мне надо возвратиться в исходное и все продумать сначала. 07.gif

[quote name='Сергей Борщ' date='Oct 2 2007, 11:57' post='301622']
Его преимущество именно в том, что даже если его сгенерировать внутри прерывания, в обработчик мы попадем "с чистого листа", т.е. из фона, когда на стеке нет данных из обработчиков других прерываний.
[/quote]
Я считал, что в Supervisor (если не разрешать вложенные прерывания) можно попасть только из System режима (т.е. из фона). Т.е. SWI является отложенным прерыванием, хотя и с высоким приоритетом.
Опять какая-то неувязка. sad.gif
[/quote]

Теперь, еще один вопрос.
С каким приоритетом внутри VIC лучше использовать прерывание по системному таймеру ?
Сергей Борщ
Цитата(alexander55 @ Oct 2 2007, 12:19) *
С каким приоритетом внутри VIC лучше использовать прерывание по системному таймеру ?
В идеале так: самый низкий приоритет у переключателя контекста, чуть выше - у системного таймера, остальные - еще выше. Подробно обсуждалось тут: http://caxapa.ru/98558.html
alexander55
Вопрос. Как в scmRTOS организовать карусель скажем из трех процессов ?
dxp
Цитата(alexander55 @ Oct 3 2007, 13:28) *
Вопрос. Как в scmRTOS организовать карусель скажем из трех процессов ?

Никак. А зачем?
spf
Цитата(alexander55 @ Oct 3 2007, 12:28) *
Вопрос. Как в scmRTOS организовать карусель скажем из трех процессов ?

В доке это написано wink.gif
alexander55
Цитата(dxp @ Oct 3 2007, 11:24) *
Никак. А зачем?

Вопрос, конечно, правильный.
Можно все завести в один процесс, но хочется для самообразования это знать.
alexander55
Цитата(alexander55 @ Oct 3 2007, 11:40) *
Вопрос, конечно, правильный.
Можно все завести в один процесс, но хочется для самообразования это знать.

Вопрос решил так.

OS::TEventFlag FL1;
OS::TEventFlag FL2;
OS::TEventFlag FL3;

//---------------------------------------------------------------------------
OS_PROCESS void TProc1::Exec()
{
FL1.Signal();
for(;;)
{
if(FL1.Wait())
{ ...
FL2.Signal();
}
}
}
//---------------------------------------------------------------------------
OS_PROCESS void TProc2::Exec()
{
for(;;)
{
if(FL2.Wait())
{ ...
FL3.Signal();
}
}
}
//---------------------------------------------------------------------------
OS_PROCESS void TProc3::Exec()
{
for(;;)
{
if(FL3.Wait())
{ ...
FL1.Signal();
}
}
}
//---------------------------------------------------------------------------
Хочу увидеть критику и ценные замечания.
Сергей Борщ
Цитата(alexander55 @ Oct 3 2007, 12:46) *
Хочу увидеть критику и ценные замечания.
Код
OS::TEventFlag FL1(OS::TEventFlag::efOn);
OS_PROCESS void TProc1::Exec()
{
   for(;;)
Но это шлифовка. В остальном должно работать.
alexander55
Цитата(Сергей Борщ @ Oct 3 2007, 14:38) *
[code]OS::TEventFlag FL1(OS::TEventFlag::efOn);

Спасибо.
alexander55
Правильно ли я понимаю, что
минимальный джентальментский набор средств межпроцессного взаимодействия (при этом сохраняя всю функциональность):
1.OS:message
2.OS::channel
Сергей Борщ
Цитата(alexander55 @ Oct 4 2007, 10:34) *
Правильно ли я понимаю, что
минимальный джентальментский набор средств межпроцессного взаимодействия (при этом сохраняя всю функциональность):
1.OS:message
2.OS::channel
Нет, OS::TService smile.gif Оно работает, но еще не готово к выпуску в широкие массы.
А если серьезно - вопрос философский. Я TEventFlag и TMutex использую чаще чем channel и message.
alexander55
Цитата(Сергей Борщ @ Oct 4 2007, 14:00) *
Нет, OS::TService smile.gif Оно работает, но еще не готово к выпуску в широкие массы.

И когда ждать? Я себя отношу к широким массам.

Цитата(Сергей Борщ @ Oct 4 2007, 14:00) *
А если серьезно - вопрос философский.

Вот меня и интересует философия scmRTOS. Мне казалось, автор хотел дать минимальный набор универсальных инструментов для решения максимального количества задач.
dxp
Цитата(alexander55 @ Oct 4 2007, 17:36) *
И когда ждать? Я себя отношу к широким массам.

Возьмите из репозитория и пробуйте себя в роли автора. smile.gif

Цитата(alexander55 @ Oct 4 2007, 17:36) *
Вот меня и интересует философия scmRTOS. Мне казалось, автор хотел дать минимальный набор универсальных инструментов для решения максимального количества задач.

Универсальных в полном смысле нет и быть не может. Как правило, наиболее часто используемые TEventFlag и TMutex. Исходная идея была, действительно, иметь минимально необходимый набор разнокачественных средств, но так, чтобы не страдала производительность и гибкость от недостатка оных. smile.gif Движение в сторону TService обусловлено тем, что все-таки есть случаи, когда кому-то хочется более специализированного поведения и функциональности, чем имеется в наборе.
alexander55
Спасибо всем за ответы.
Предлагаю выкладывать в этом топике ответы на вопросы по использованию встроенных средств межпроцессного взаимодействия в scmRTOS. Это будет интересно всем, кто использует scmRTOS.
Например (мой скромный вклад) biggrin.gif .
Вопрос. Как средствами scmRTOS организуется выполнение процесса с заданной частотой.
Ответ.
...
OS::TEventFlag FL3;
...
OS_PROCESS void TProc3::Exec()
{
for(;;)
{
FL3.Wait(100);
...
}
}
Пояснение. Процесс 3 запускается через 100 тактов системного таймера (период процесса 3 - 100 мс при периоде таймера 1 мс).
dxp
Цитата(alexander55 @ Oct 8 2007, 12:44) *
Спасибо всем за ответы.
Предлагаю выкладывать в этом топике ответы на вопросы по использованию встроенных средств межпроцессного взаимодействия в scmRTOS. Это будет интересно всем, кто использует scmRTOS.
Например (мой скромный вклад) biggrin.gif .
Вопрос. Как средствами scmRTOS организуется выполнение процесса с заданной частотой.
Ответ.
...
OS::TEventFlag FL3;
...
OS_PROCESS void TProc3::Exec()
{
for(;;)
{
FL3.Wait(100);
...
}
}
Пояснение. Процесс 3 запускается через 100 тактов системного таймера (период процесса 3 - 100 мс при периоде таймера 1 мс).

Код
OS_PROCESS void TProc3::Exec()
{
    for(;;)
    {
        Sleep(100);
        ...
    }
}
alexander55
Цитата(dxp @ Oct 8 2007, 10:03) *
Код
OS_PROCESS void TProc3::Exec()
{
    for(;;)
    {
        Sleep(100);
        ...
    }
}

Спасибо, Ваш вариант лучше. a14.gif
Сергей Борщ
Цитата(alexander55 @ Oct 8 2007, 08:44) *
Как средствами scmRTOS организуется выполнение процесса с заданной частотой.
Оба варианта неправильные - не учитывают время исполнения самого процесса. По-честному надо бы считывать системное время, смотреть сколько осталось до "Часа Х" и засыпать уже на это время. Вот только есть одна грабля - если времени не осталось, то вместо исполнения без ожидания получим Sleep(0), т.е. навечно, а если не успели и "час Х" уже прошел - то опять же вместо исполнения без паузы получим ожидание на время переполнения системного таймера.
alexander55
Цитата(Сергей Борщ @ Oct 8 2007, 12:05) *
Оба варианта неправильные - не учитывают время исполнения самого процесса. По-честному надо бы считывать системное время, смотреть сколько осталось до "Часа Х" и засыпать уже на это время. Вот только есть одна грабля - если времени не осталось, то вместо исполнения без ожидания получим Sleep(0), т.е. навечно, а если не успели и "час Х" уже прошел - то опять же вместо исполнения без паузы получим ожидание на время переполнения системного таймера.

Вы правы Сергей. Если понадобится точное время, я могу предложить такой вариант.
//-------------------------------------------------
class TTimer {
int Delay;
int Setting;
public:
TTimer(x) { Setting=x;Delay=x;};
void Run(void) { if(--!Delay) {Delay=Setting; FL.Signal();};};
};
//--------------------------------------------------
TTimer Tim100(100);
...
И где-то в системном таймере
...
Tim100.Run();
...
//--------------------------------------------------
Ну а в процессе

OS::TEventFlag FL3;
...
OS_PROCESS void TProc3::Exec()
{
for(;;)
{
FL.Wait();
...
}
}
PS. Так вроде чисто получается. yeah.gif
Сергей Борщ
Цитата(alexander55 @ Oct 8 2007, 14:12) *
PS. Так вроде чисто получается. yeah.gif
Ну, совсем для красоты я бы сделал FL3 членом TTImer. Инкапсуляция, так сказать. А сам решаю так:
Код
typedef TTimeout timeout_t;
    timeout_t Time_X = OS::GetTickCount() + timeout;     // now + timeout

    for(;;)
    {
        timeout_t Timeout = Time_X - OS::GetTickCount();
        if((timeout_t)(Timeout - 1) > timeout )
            return 0;
        if(!pUART->getchar(RxData, Timeout))            // timeout, packet broken
            return 0;
alexander55
Цитата(Сергей Борщ @ Oct 8 2007, 15:27) *
Ну, совсем для красоты я бы сделал FL3 членом TTImer.

Здесь есть подводный камень с инициализацией (хотя можно наследовать виртуально). Я бы не стал так делать.

Цитата(Сергей Борщ @ Oct 8 2007, 15:27) *
Код
typedef TTimeout timeout_t;
    timeout_t Time_X = OS::GetTickCount() + timeout;     // now + timeout

    for(;;)
    {
        timeout_t Timeout = Time_X - OS::GetTickCount();
        if((timeout_t)(Timeout - 1) > timeout )
            return 0;
        if(!pUART->getchar(RxData, Timeout))            // timeout, packet broken
            return 0;

return 0;
Здесь будет выход из цикла for. Это потенциально опасно. sad.gif
Сергей Борщ
Цитата(alexander55 @ Oct 8 2007, 14:58) *
Здесь есть подводный камень с инициализацией (хотя можно наследовать виртуально). Я бы не стал так делать.
Какой камень? Что-то я сегодня туго соображаю.
Цитата(alexander55 @ Oct 8 2007, 14:58) *
return 0;
Здесь будет выход из цикла for. Это потенциально опасно. sad.gif
Это только кусочек функции, которая возвращает количество принятых байт в пакете или 0 если прием не сложился. Этим куском я хотел продемонстрировать вычисление оставшегося тайм-аута и обход упомянутых в предыдущем сообщении "граблей"
alexander55
Цитата(Сергей Борщ @ Oct 8 2007, 17:27) *
Какой камень? Что-то я сегодня туго соображаю.

Ну допустим
//-------------------------------------------------
class TTimer : public OS::TEventFlag
{
int Delay;
int Setting;
public:
TTimer(x) { Setting=x;Delay=x;};
void Run(void) { if(--!Delay) {Delay=Setting; FL.Signal();};};
};

TTimer Tim100(100);
Все нормально, но мы откажемся от возможности начальной инициализации TEventFlag (только по умолчанию). Но это не страшно.

Цитата(Сергей Борщ @ Oct 8 2007, 17:27) *
Это только кусочек функции, которая возвращает количество принятых байт в пакете или 0 если прием не сложился. Этим куском я хотел продемонстрировать вычисление оставшегося тайм-аута и обход упомянутых в предыдущем сообщении "граблей"

Понятно. Я почему-то подумал про for процесса. biggrin.gif
PS. Я вчера тоже под конец дня зациклился.
Сергей Борщ
Цитата(alexander55 @ Oct 9 2007, 07:41) *
class TTimer : public OS::TEventFlag
Вчера был явно день торможения, хотя у меня, например, выходные прошли без возлияний wink.gif :
Код
class TTimer
{
    int Delay;
    int Setting;
    OS::TEventFlag Flag;
public:
    TTimer(x) : Flag(OS::TEventFlag::efOff) { Setting=x;Delay=x;}
    void Run(void) { if(--!Delay) {Delay=Setting; Flag.Signal();}}
    bool Wait() { return Flag.Wait(); }
};
dxp
Цитата(Сергей Борщ @ Oct 9 2007, 17:24) *
Вчера был явно день торможения, хотя у меня, например, выходные прошли без возлияний wink.gif :
Код
class TTimer
{
    int Delay;
    int Setting;
    OS::TEventFlag Flag;
public:
    TTimer(x) : Flag(OS::TEventFlag::efOff) { Setting=x;Delay=x;}
    void Run(void) { if(--!Delay) {Delay=Setting; Flag.Signal();}}
    bool Wait() { return Flag.Wait(); }
};

Мущщины, я в упор не понимаю, почему вы используете для генерации задержек флаг события, а не специально существующую для этого функцию Sleep. Ведь она легче и быстрее, а флаг тянет за собой дополнительную функциональность, которая здесь не используется. Оверхед и загромождение кода.
alexander55
Цитата(dxp @ Oct 9 2007, 16:47) *
Мущщины, я в упор не понимаю, почему вы используете для генерации задержек флаг события, а не специально существующую для этого функцию Sleep. Ведь она легче и быстрее, а флаг тянет за собой дополнительную функциональность, которая здесь не используется. Оверхед и загромождение кода.

Вопрос стал о точном среднем выдерживании по времени процессных задач (ради чистого искусства).
PS. Предложение. Давайте обсудим какую-нибудь полезную тему типа "Обмен ModBus пакетами средствами scmRTOS".
Я знаю, у Сергея есть наработки, у меня тоже кое-что есть.
Сергей Борщ
Цитата(alexander55 @ Oct 9 2007, 16:05) *
Я знаю, у Сергея есть наработки, у меня тоже кое-что есть.
Нету. С MODBUS никогда не работал.


Цитата(dxp @ Oct 9 2007, 15:47) *
Мущщины, я в упор не понимаю, почему вы используете для генерации задержек флаг события, а не специально существующую для этого функцию Sleep.
Мы всех окончательно запутали smile.gif Я в последних сообщениях обсуждал возможность использовать какой-либо сервис как члена какого-либо объекта. А против Sleep() не возражал, только отметил, что для периодического выполнения какого-либо куска время задержки надо бы рассчитывать, чтобы вычесть из него собственно время выполнения самого полезного кода.
dxp
Цитата(alexander55 @ Oct 9 2007, 20:05) *
Вопрос стал о точном среднем выдерживании по времени процессных задач (ради чистого искусства).

Ну, и пожалуйста - заверните Sleep в свой объект TTimer, внутри которого будут вычисляться точные значения аргумента Sleep, и все. Флаг события-то тут зачем?
alexander55
Цитата(Сергей Борщ @ Oct 9 2007, 18:24) *
Нету. С MODBUS никогда не работал.

Хорошо, тогда предлагаемая тема для обсуждения "Обмен пакетами по RS485 с помощью средств scmRTOS".

Цитата(dxp @ Oct 10 2007, 07:57) *
Ну, и пожалуйста - заверните Sleep в свой объект TTimer, внутри которого будут вычисляться точные значения аргумента Sleep, и все. Флаг события-то тут зачем?

Идея ясна.
alexander55
Цитата(alexander55 @ Oct 10 2007, 08:27) *
Хорошо, тогда предлагаемая тема для обсуждения "Обмен пакетами по RS485 с помощью средств scmRTOS".

Я так понял, что молчание - знак согласия. Ну тогда поехали.

Вопросы для обсуждения (хочется применительно к LPC).
Выскажу свое видение вопроса.
1. Приоритет прерывания по приему символов .
Для определенности. Выше системного таймера, но ниже, чем готовность данных ADC.
2. Для обработки принятого пакета - формирования пакета ответа - передачи подготовленного пакета организуется свой процесс (назовем процессом на передачу).
2.1. Запуск процесса на передачу для master.
- запуск процесса осуществляется по таймеру временных интервалов (пакет запроса с передачей);
- запуск процесса от органов управления (с передачей);
- обработка принятых данных от slave (без передачи).
2.2. Запуск процесса на передачу для slave.
- по истечению таймаута на отсутствие принятых символов (с передачей или без нее);
- по каким-то явным признакам прошедшего или сбойного пакета запроса (с передачей или без нее).
3. Прерывание по приему символов осуществляет запись в приемный буфер, с которым и производится работа в процессе на передачу.

Думаю, вопросов для начала обсуждения пока достаточно.
ReAl
"UP" smile.gif

Цитата(dxp @ Oct 10 2007, 05:57) *
Ну, и пожалуйста - заверните Sleep в свой объект TTimer, внутри которого будут вычисляться точные значения аргумента Sleep, и все. Флаг события-то тут зачем?
+1
Более того - если от момента, когда время Sleep для данного процесса истекло (его занесли в готовые), до того, как он реально получит управление, проходит меньше времени одного системного тика - то вообще ничего не надо. В среднем будет всё нормально.
Конечно - если процесс по приоритету где-то внизу и старшие вечно толпятся - то будет проскакивать. Тогда действительно обернуть в класс с поведением "типа OCR += PERIOD".
А если задержки до "всплытия" процесса могут быть такими большими, что оставшееся время может
оказаться равно 0 - то оно и "отрицательным" может оказаться, тут уж переход к TEventFlag тоже ничего не даст.
alexander55
Цитата(ReAl @ Nov 9 2007, 19:15) *
А если задержки до "всплытия" процесса могут быть такими большими, что оставшееся время может
оказаться равно 0 - то оно и "отрицательным" может оказаться, тут уж переход к TEventFlag тоже ничего не даст.

Проблема решается на уровне соответствующего приоритета. А если приоритет низкий, то автор знает на что идет и, вероятно, это его устраивает. smile.gif
prottoss
Привет всем!
решил поиграться с scmRTOS. Скачал исходники версии 3.0. Скомпилил - НО то ли день не мой, то ли дело не в бобине... smile.gif
Компилятор IAR 4.30A/W32 [Evaluation] (4.30.1.3). Попробовал поэмулировать ОС с примером из папки [3-Channel] в AVRStudio 4.12 SP2.
В конфиге scmRTOS_config.h установил
Код

#define  scmRTOS_CONTEXT_SWITCH_SCHEME      0

После запуска симулятор выдает предупреждение
Цитата
AVR Simulator: Invalid opcode 0xffff at address 0x00ffff

Это возникает после выхода из процедуры OS_Start(sp)
Где грабли, не пойму. Просвятите, плиз. Сенькс.
dxp
Цитата(prottoss @ Dec 8 2007, 20:37) *
Это возникает после выхода из процедуры OS_Start(sp)
Где грабли, не пойму. Просвятите, плиз. Сенькс.

А разве оно должно выходить из этой функции? Оно в нее заходит и далее запускаются все процессы, никакого выхода быть не должно. Посмотрите код этой функции, он очень простой и короткий.
prottoss
Цитата(dxp @ Dec 8 2007, 22:29) *
А разве оно должно выходить из этой функции? Оно в нее заходит и далее запускаются все процессы, никакого выхода быть не должно. Посмотрите код этой функции, он очень простой и короткий.




Расскажу по порядку, что у меня происходит:

1. выполняется конструктор OS::Kernel

2. выполянется конструктор OS::PrioMaskTable

3. выполняются последовательно кострукторы 3-х процессов

4. вызывается OS::Run()

5. в OS::Run() вызывается OS_Start(sp)

6. Попадаем в OS_Target_asm.s90 на метку OS_Start:

7. Далее переход на метку L_RestoreContext:

8. После команды RET симулятор вываливает

Код
AVR Simulator: Invalid opcode 0xffff at address 0x00ffff
prottoss
Вроде бы нашел косяк:
Я использую в проекте ATmega128, под него и компилил проект. После мучительных размышлений на 1,7 кБайтами кода smile.gif попробовал сменить МК на м64 - все заработало!!! Сразу возникла мысль про RAMPZ!
В файле OS_Target_asm.s90 есть макросы #if HAS_RAMPZ == 1 ... #endif - так вот, они почемуто не хотятЪ работать:-( Сделал в данном файле принудительно #define HAS_RAMPZ 1 - все заработало... Я в тонкостях компиляторов не сильно силен, как победить баг?
dxp
Цитата(prottoss @ Dec 9 2007, 00:06) *
В файле OS_Target_asm.s90 есть макросы #if HAS_RAMPZ == 1 ... #endif - так вот, они почемуто не хотятЪ работать:-( Сделал в данном файле принудительно #define HAS_RAMPZ 1 - все заработало... Я в тонкостях компиляторов не сильно силен, как победить баг?

Макрос HAS_RAMPZ генерируется компилятором из заданного процессора. Но это компилятором. А ассемблер, насколько помню, не поддерживает задание конкретного типа процессора, там все опции целевого процессора надо задавать через -v и -m опции. Соответственно, означенный макрос ассемблер не генерирует, поэтому его надо задавать руками. Удобно сделать это через опции проекта, а не править исходник. Если сборка идет из командной строки (makefile etc), то задать макрос через ключ командной строки -D, если из оболочки, что в опциях проекта, в разделе асма, во вкладке define указать макрос.
prottoss
Цитата(dxp @ Dec 9 2007, 03:12) *
Макрос HAS_RAMPZ генерируется компилятором из заданного процессора. Но это компилятором. А ассемблер, насколько помню, не поддерживает задание конкретного типа процессора, там все опции целевого процессора надо задавать через -v и -m опции. Соответственно, означенный макрос ассемблер не генерирует, поэтому его надо задавать руками. Удобно сделать это через опции проекта, а не править исходник. Если сборка идет из командной строки (makefile etc), то задать макрос через ключ командной строки -D, если из оболочки, что в опциях проекта, в разделе асма, во вкладке define указать макрос.
Да, наверное так и надо... НО, думаю тогда надо вписать данное предупреждение в начале S90-файла, типа /* ... Warning! bla-bla-bla ... */ smile.gif
ReAl
В порте для avr-gcc с этим проще. Тип процессора передаётся и ассемблеру, достаточно включить <avr/io.h> и символ RAMPZ определён только для тех процессоров, у которых он есть. После чего #ifdef RAMPZ что в С, что в асме.
prottoss
Цитата(ReAl @ Dec 13 2007, 17:07) *
В порте для avr-gcc с этим проще. Тип процессора передаётся и ассемблеру, достаточно включить <avr/io.h> и символ RAMPZ определён только для тех процессоров, у которых он есть. После чего #ifdef RAMPZ что в С, что в асме.
кстати, в ассемблер на IAR тоже можно включать C-шные хедеры, так что я думаю, что можно побороть эту проблему. К сожалению,я счас загружен по макушку проектом, и не могу все это попробовать:-(
bus16
Вот тоже появилось пара вопросов по мютексам:
1 Ситуация: несколько процессов стоят в очереди - ждут захваченный mutex. Процесс, который этот mutex захватил - освобождает его. Перейдет-ли все процессы, ожидавшие его в активное состояние или управление получит только процесс с наивысшим приоритетом (стр. 61 описания "Если семафора ожидали несколько процессов, то управление получит самый приоритетный из них ")
2 "Мягкий" захват mutex-а. Ситуация: mutex захвачен. Какой-то процесс пытается его "мягко" захватить. В случае с "жестким" захватом - ситуация ясна - процесс перейдёт в неактивное состояние до разблокировки mutex-а. А что произойдёт в случае "мягкого" захвата? TMutex::LockSoftly(); просто проскочит? Но ведь за блокировкой всегда следует обращение к защищённому ресурсу. Что делать в такой ситуации? Может проще вызвать TMutex::IsLocked(); и не париться?
jorikdima
Цитата(bus16 @ Dec 27 2007, 10:28) *
Вот тоже появилось пара вопросов по мютексам:
1 Ситуация: несколько процессов стоят в очереди - ждут захваченный mutex. Процесс, который этот mutex захватил - освобождает его. Перейдет-ли все процессы, ожидавшие его в активное состояние или управление получит только процесс с наивысшим приоритетом (стр. 61 описания "Если семафора ожидали несколько процессов, то управление получит самый приоритетный из них ")
2 "Мягкий" захват mutex-а. Ситуация: mutex захвачен. Какой-то процесс пытается его "мягко" захватить. В случае с "жестким" захватом - ситуация ясна - процесс перейдёт в неактивное состояние до разблокировки mutex-а. А что произойдёт в случае "мягкого" захвата? TMutex::LockSoftly(); просто проскочит? Но ведь за блокировкой всегда следует обращение к защищённому ресурсу. Что делать в такой ситуации? Может проще вызвать TMutex::IsLocked(); и не париться?

1. В активное состояние перейдет процесс с наивысшим приоритетом. В приведенной цитате все четко написано. Остальные так и будут спать.

2. За блокировкой идет то, что вы напишете, а не захват ресурса. И если вы проверите результат TMutex::LockSoftly() на правду/ложь и будете захватывать ресурс только в случае true, то все будет в порядке.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.