Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: __LDREX __STREX в STM32F407
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
Страницы: 1, 2, 3
_lexa_
Всем доброе время суток!

IDE - IAR+плагин IAR для eclipse+eclipse.
Решил проверить, как работает синхронизация с использованием __LDREX/__STREX. Пишем следующий код
CODE
typedef struct
{
...
volatile unsigned long sync; //переменная для синхонизации доступа к данному элементу
} burst_measur;

burst_measur cur_mes;

void mpu_cfg_test()
{
//настраиваем область внутренней RAM, как разделяемую
__DMB();
SCB->SHCSR &= ~SCB_SHCSR_MEMFAULTENA_Msk;
MPU->CTRL = 0U;

MPU->RNR = 0UL;
MPU->RBAR = 0x20000000UL;
MPU->RASR = (0x10UL << MPU_RASR_SIZE_Pos) | MPU_RASR_C_Msk | MPU_RASR_S_Msk | (0x3 << MPU_RASR_AP_Pos) | MPU_RASR_ENABLE_Msk;

MPU->CTRL = MPU_CTRL_PRIVDEFENA_Msk | MPU_CTRL_ENABLE_Msk;
SCB->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk;
__DSB();
__ISB();

//выполняем запрос эксклюзивного доступа к переменной cur_mes.sync
DWORD sync=0;
sync = __LDREX(&cur_mes.sync);
__DMB();
soft_int_ini(); //настойка программного прерывания
soft_int_on(); //вызов программного прерывания
__WFI();
}


в обработчике программного прерывания:
CODE
DWORD sync;
do
{
sync = __LDREX(&cur_mes.sync);
sync++;
sync = __STREX(sync, &cur_mes.sync);
}
while (sync);


Т.е. сначала выполняется __LDREX(&cur_mes.sync), потом происходит прерывание и выполняется __LDREX(&cur_mes.sync) + __STREX(sync, &cur_mes.sync).
По всем документациям, как я их понял, __STREX(sync, &cur_mes.sync) должна возвратить "не ноль", однако возвращает "ноль".

Помогите, пожалуйста, разобраться, что я делаю не правильно?

jcxz
Цитата(_lexa_ @ Jun 4 2017, 15:18) *
что я делаю не правильно?

Ожидаете "не ноль".
STREX всё верно возвращает.
_lexa_
Цитата(jcxz @ Jun 4 2017, 17:10) *
STREX всё верно возвращает.

если не верно задал вопрос -
от __LDREX() + __STREX() ожидаю следующее:
если выполнено__LDREX(&cur_mes.sync)
тогда в случае выполнения в другой части кода "__LDREX(&cur_mes.sync) + __STREX(sync, &cur_mes.sync)" __STREX вернет "не ноль".
однако возвращается ноль.

Где-то ошибся! Не понятно только где. Поясните вкратце, куда смотреть.
KnightIgor
Цитата(_lexa_ @ Jun 4 2017, 19:39) *
Где-то ошибся! Не понятно только где. Поясните вкратце, куда смотреть.

Каждый раз вспоминаю и снова забываю эти проклятые LDREX/STREX, но суть в том, что если между LDREX и последующим STREX "что-то пошло не так, Карл", а именно - возникло некоторое событие, прерывание, которое СТАВИТ ПОД УГРОЗУ целостность переменной-флага, то STREX вернет типа "ай-ай". То есть, даже если саму переменную-флаг никто и трогать не собирался где-то в недрах прерываний, но прерывание нарушило непрерывное исполнение между LDREX и STREX, то ресурс считается занятым. Поэтому у меня глубокое сомнение, можно ли строить код, как у ТС, - захватывать ресурс в основном коде и выяснять отношения в прерывании: в прерывании по определению ресурс будет занят.
Если хотите организовать всякие мъютексы и прочие разделяемые флаги на системе bare bone с наличествующими прерываниями, гляньте на команду SVC. Могу даже код кинуть, если есть интерес.
_lexa_
Цитата(KnightIgor @ Jun 4 2017, 19:34) *
... Могу даже код кинуть, если есть интерес.


Интерес есть. Кидайте.
KnightIgor
Цитата(_lexa_ @ Jun 4 2017, 21:14) *
Интерес есть. Кидайте.

Обработчик прерывания SVC выглядит у меня следующим образом. Много подсмотрено по ссылкам, указанным в комментариях.
Код
// ---------------------------------------------------------------------------
//
//    SVC_Handler used for "atomic" operations based on the the fact, that
//  SVC handler cannot be interrupted by higher placed interrupts.
//
//  Upon call to SVC vector the stack holds saved register:
//            xPSR          0x1C (7)
//            PC            0x18 (6)
//            R14(LR)       0x14 (5)
//            R12           0x10 (4)
//            R3            0x0C (3)
//            R2            0x08 (2)
//            R1            0x04 (1)
//     [SP]-> R0            0x00 (0)
//
//  The registers will be restored upon leaving the handler. The handler
//  to return a result, a value in the stack must be modified.
//
//  Via stacked R0..R3 the parameters can be passed through to the
//  handler. For this purpose the definition of the user SVC call can
//  be done as (the type 'int' is for example):
//
//      __svc(n) myfunc(int [,int, int, int]);
//
//  See Chapter 6.19, Figure 6.5 in:
//  http://infocenter.arm.com/help/topic/com.arm.doc.dui0471c/  \
//         DUI0471C_developing_for_arm_processors.pdf
//
//                  and    
//      
//    http://www.mikrocontroller.net/topic/295183
//    http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0471j/pge1358787038365.html
//    http://sites.fas.harvard.edu/~libe251/spring2014/CauseOfDefaultISR.txt
//
//  To PRESERVE8 for stack 8 bytes alignment see
//    http://infocenter.arm.com/help/topic/com.arm.doc.faqs/ka4127.html
//
__asm
void SVC_Handler(void) {
    
    PRESERVE8  
    EXPORT  SVC_Handler

  ; get the pointer to the saved R0-R3 to pass it
  ; to SVC_Dispatcher() as the second parameter
  ; (via R1):
    
#ifdef  SVC_OS_MODE
    
    TST     LR, #4            ; kernel mode?  
    ITE     EQ
    MRSEQ   R1, MSP        ; kernel stack
    MRSNE   R1, PSP        ; user stack    

  ; get SVC n instruction code field and
  ; pass it to SVC_Dispatcher() as the first
  ; parameter (via R0):

    LDR     R0, [R1, #6*4]    ; PC
#if defined(__CORE_CM0_H_GENERIC) || defined(__CORE_CM0PLUS_H_GENERIC)
    SUBS    R0, R0,  #2
    LDRB    R0, [R0, #0]      ; SVC OPCODE low byte
#else
    LDRB    R0, [R0, #-2]     ; SVC OPCODE low byte
#endif    

    PUSH    {LR, R1}            
    EXTERN  SVC_Dispatcher
    BL      SVC_Dispatcher    ; return value in R0
    POP     {R1}    

  ; return the result in R0 via stacked R0:

    STR     R0, [R1]        
    
#else                          
    MOV     R1, SP            ; kernel=user stack (no OS)

  ; get SVC n instruction code field and
  ; pass it to SVC_Dispatcher() as the first
  ; parameter (via R0):

    LDR     R0, [R1, #6*4]    ; PC
#if defined(__CORE_CM0_H_GENERIC) || defined(__CORE_CM0PLUS_H_GENERIC)
    SUBS    R0, R0,  #2
    LDRB    R0, [R0, #0]      ; SVC OPCODE low byte M0/M0+
#else
    LDRB    R0, [R0, #-2]     ; SVC OPCODE low byte M3 and higher
#endif    

    PUSH    {LR}              ; preserve return address
    EXTERN  SVC_Dispatcher
    BL      SVC_Dispatcher    ; return value in R0

  ; return the result in R0 via stacked R0:

    STR     R0, [SP, #4]      ; #4 to skip LR in the stack    
#endif
    
    POP    {PC}            ; exit by LR
}    
//------------------------------------------------------------------------------

Если исключить условные трансляции, которые разбирают варианты под OS, а также оставить универсальный вариант, работающий и на -M0 (не поддерживающих отрицательные смещения), то обработчик упростится для исполнения и понимания:
Код
__asm
void SVC_Handler(void) {
    
    PRESERVE8  
    EXPORT  SVC_Handler

  ; get the pointer to the saved R0-R3 to pass it
  ; to SVC_Dispatcher() as the second parameter
  ; (via R1):
    
    MOV     R1, SP            ; kernel=user stack (no OS)

  ; get SVC n instruction code field and
  ; pass it to SVC_Dispatcher() as the first
  ; parameter (via R0):

    LDR     R0, [R1, #6*4]    ; PC
    SUBS    R0, R0,  #2
    LDRB    R0, [R0, #0]      ; SVC OPCODE low byte M0/M0+

    PUSH    {LR}              ; preserve return address
    EXTERN  SVC_Dispatcher
    BL      SVC_Dispatcher    ; return value in R0

  ; return the result in R0 via stacked R0:

    STR     R0, [SP, #4]      ; #4 to skip LR in the stack    
    
    POP    {PC}            ; exit by LR
}    
//------------------------------------------------------------------------------

Как видно, все готовилось для вызова C-шной процедуры-обработчика ниже. Я выбросил многие мои специфические ветви, оставив те, что иллюстрируют идею:
Код
uint32_t SVC_Dispatcher(int svc, SVC_Param_TypeDef *ptr)
{
    uint32_t res = UINT32_MAX;
    switch (svc) {
        case _SVC_ATOMIC_FLAG8:     // atomic clear of an U8 flag
            res = *(uint8_t *)ptr->R0;      // return the last state
                  *(uint8_t *)ptr->R0 = 0;  // clear it
        break;
        case _SVC_ATOMIC_FLAG16:     // atomic clear of an U16 flag
            res = *(uint16_t *)ptr->R0;      // return the last state
                  *(uint16_t *)ptr->R0 = 0;  // clear it
        break;
        case _SVC_ATOMIC_ADD32:     // atomic add 32
            res =
            *(uint32_t *)ptr->R0 += (int32_t)ptr->R1;      
        break;
        case _SVC_ATOMIC_DEC8:
            res = *(uint8_t *)ptr->R0;
            if (res)
            {
                *(uint8_t *)ptr->R0 = --res;
            }
        break;
        case _SVC_MUTEX8:     // mutex in an U8 variable
            res = !(*(uint8_t *)ptr->R0);   // current mutex state
            *(uint8_t *)ptr->R0 = ptr->R1;  // set the value
        break;      
    }
    return res;
}

К этому пристегивается заголовок (существенный фрагмент):
Код
typedef struct svc_params_s {

    uint32_t R0, R1, R2, R3;
    
} SVC_Param_TypeDef;    

#define _SVC_GETSYSCLOCKVALUE   4
#define _SVC_ATOMIC_FLAG8       8
#define _SVC_ATOMIC_FLAG16      9
#define _SVC_ATOMIC_FLAG32      10
#define _SVC_ATOMIC_ADD8        11
#define _SVC_ATOMIC_ADD16       12
#define _SVC_ATOMIC_ADD32       13
#define _SVC_ATOMIC_DEC8        14
#define _SVC_MUTEX8             16
#define _SVC_ATOMIC_SET8        21
#define _SVC_ATOMIC_SET16       22
#define _SVC_ATOMIC_SET32       23
#define _SVC_CALL_ME_PAR        25

//------------------------------------------------------------------------------
//
//  Clears an U8 flag pointed by 'pflag' but returns its latest value.
//
uint8_t __svc(_SVC_ATOMIC_FLAG8) Atomic_Flag8(uint8_t *pflag);

//------------------------------------------------------------------------------
//
//  Adds an I32 value to the value pointed by 'pvalue' and returns the result
//
uint32_t __svc(_SVC_ATOMIC_ADD32) Atomic_Add32(uint32_t *pvalue, int32_t val);

//------------------------------------------------------------------------------
//
//  Decrements a non zero value pointed by 'pvalue' and returns the result
//
uint8_t __svc(_SVC_ATOMIC_DEC8) Atomic_Dec8(uint8_t *pvalue);

//------------------------------------------------------------------------------
//
//  Sets the mutex ('setit'=true) pointed by 'pflag' and returns true if success.
//  Otherwise the mutex has been busy.
//
//  Clears ('setit'=false) the mutex unconditionally. It's up to the user to take
//  care, if the mutex is allowed to be cleared. The return result to be ignored.
//
//  NOTE: THE MUTEX VALUE AND THE SETIT PARAMETER ARE EXPECTED TO BE ONLY 0 OR 1.
//        NO OTHER VALUES ARE ALLOWED, SHOULD FOR INSTANCE THE MUTEX VARIABLE BE
//        CHANGED ELSEWHERE.
//
int __svc(_SVC_MUTEX8) Mutex8(uint8_t *pflag, uint8_t setit);

//------------------------------------------------------------------------------

extern uint32_t SVC_Dispatcher(int svc, SVC_Param_TypeDef *ptr);

Теперь о вызове на примере флага:
Код
uint8_t sb = Atomic_Flag8(&flag); // atomic reset
if (sb) {
// ...
}

Там для некой переменной uint8_t flag, которая устанавливается в прерывании, функция возвращает мне последнее состояние флага и сбрасывает его. Благодаря непрерываемости SVC операция по сбросу флага является атомарной.
AHTOXA
Цитата(KnightIgor @ Jun 5 2017, 02:14) *
Благодаря непрерываемости SVC операция по сбросу флага является атомарной.

А в чём выгода такого метода по сравнению с простым запретом/разрешением прерываний? Я думаю, что по скорости это даже медленнее (тратится время на сохранение и восстановление контекста).
Прелесть же LDREX/STREX как раз в том, что они не блокируют прерывания.
jcxz
Цитата(_lexa_ @ Jun 4 2017, 20:39) *
Где-то ошибся! Не понятно только где. Поясните вкратце, куда смотреть.

Если между LDREX и STREX произошло прерывание или был выполнен другой эксклюзивный доступ, до будет нарушение эксклюзивности.
Ну и где у вас между LDREX и STREX нарушение эксклюзивности?

Цитата(KnightIgor @ Jun 4 2017, 23:14) *
// SVC_Handler used for "atomic" operations based on the the fact, that
// SVC handler cannot be interrupted by higher placed interrupts.

Жесть какая. Вот уж действительно - одевание трусов через голову biggrin.gif
Чем способы: LDREX/STREX или запрет прерываний не угодили? Они в разы менее громоздки.
А для SVC можно придумать гораздо более полезные применения.
Forger
Цитата(AHTOXA @ Jun 5 2017, 08:38) *
А в чём выгода такого метода по сравнению с простым запретом/разрешением прерываний?

Полагаю, что выгода в полным отсутствием этих самых запретов/разрешений.
Дабы иметь возможность гарантировать стабильную скорость реакции на критичные высокоприоритетные прерывания.
Причем, в независимости используется ось или нет.
Сам поглядываю на подобные решения, но таких у меня проектов очень мало, поэтому пока вполне хватает "классического" запрет/разрешение прерываний.
Хожу как "кот вокруг сметаны" sm.gif

Цитата
Я думаю, что по скорости это даже медленнее (тратится время на сохранение и восстановление контекста).

Если производительность камня выбрана хотя бы с небольшим запасом (в случае применения оси загрузка cpu никогда не достигает допустимого предела), то это не имеет значения.
Смысл svc - дать гарантию реакции на важные высокоприоритетные прерывания.
AHTOXA
Цитата(Forger @ Jun 5 2017, 13:17) *
Полагаю, что выгода в полным отсутствием этих самых запретов/разрешений.

Если, как пишет, KnightIgor, svc является непрерываемым, то чем это отличается от запрета остальных прерываний?
Forger
Цитата(AHTOXA @ Jun 5 2017, 11:22) *
Если, как пишет, KnightIgor, svc является непрерываемым, то чем это отличается от запрета остальных прерываний?

Почему непрерывный? Любое более приоритетное прерывание может его прервать в любой момент, иначе от этого SVC почти нет никакого проку .
Лишь нужно правильно настроить NVIC.
Причем, это более "мощное" прерывание может вызвать это же самое SVC, а когда выйдет, продолжится обработка прерванного SVC, и после его завершения тут же опять вызовется новое, отложенное.
Так по сути SVC дает гарантию целостности кусков кода.
Безусловно, оверхед заметно растет, но цена этому - гарантия реакции на действительно важные события.
Под SVC вообще идеально ложатся все сервисы RTOS, судя по всему прям для них SVC и задумывалось.
Только вот мне не попадались готовые оси, где это используется ...
jcxz
Цитата(Forger @ Jun 5 2017, 10:17) *
Полагаю, что выгода в полным отсутствием этих самых запретов/разрешений.
Дабы иметь возможность гарантировать стабильную скорость реакции на критичные высокоприоритетные прерывания.

Так обработчик SVC задержит эти самые "высокоприоритетные прерывания" на ещё в разы большее время!

Цитата(Forger @ Jun 5 2017, 10:24) *
Почему непрерывный? Любое более приоритетное прерывание может его прервать в любой момент, иначе от этого SVC почти нет никакого проку .
Лишь нужно правильно настроить NVIC.

Потому что для работоспособности этого способа, обработчик SVC должен быть самым высокоприоритетным.

Цитата(Forger @ Jun 5 2017, 10:24) *
Безусловно, оверхед заметно растет, но цена этому - гарантия реакции на действительно важные события.
Под SVC вообще идеально ложатся все сервисы RTOS, судя по всему прям для них SVC и задумывалось.
Только вот мне не попадались готовые оси, где это используется ...

SVC задумывалось совсем не для этого. Для этого задумывались LDREX/STREX. Именно поэтому и нет.
Если у Вас другой обработчик может прерывать SVC, то никакой эксклюзивности уже нет. По определению.

Цитата(Forger @ Jun 5 2017, 10:24) *
Причем, это более "мощное" прерывание может вызвать это же самое SVC, а когда выйдет, продолжится обработка прерванного SVC

ну-ну... учите матчасть biggrin.gif
Если это "мощное" прерывание попытается так сделать, то получит HardFault, а не SVC.
AHTOXA
Цитата(Forger @ Jun 5 2017, 13:24) *
Почему непрерывный? Любое более приоритетное прерывание может его прервать в любой момент, иначе от этого SVC почти нет никакого проку .

Ну вы хоть читайте, на что отвечаете...

KnightIgor написал:
Цитата(KnightIgor @ Jun 5 2017, 02:14) *
Благодаря непрерываемости SVC операция по сбросу флага является атомарной.

Видите, "благодаря непрерываемости SVC". Это значит, что у svc в его случае самый высокий приоритет. А значит, вход в обработчик SVC блокирует остальные прерывания. Вот я и поинтересовался:
Цитата(AHTOXA @ Jun 5 2017, 10:38) *
А в чём выгода такого метода по сравнению с простым запретом/разрешением прерываний?

А теперь вы спрашиваете, "почему непрерывный".
Теперь понимаете нить?
Forger
Цитата(jcxz @ Jun 5 2017, 11:49) *
Так обработчик SVC задержит эти самые "высокоприоритетные прерывания" на ещё в разы большее время!
Потому что для работоспособности этого способа, обработчик SVC должен быть самым высокоприоритетным.

Как раз наоборот - приоритет SVC должен быть самым низким ! (ну кроме разве что PendSV).

Цитата
SVC задумывалось совсем не для этого. Для этого задумывались LDREX/STREX. Именно поэтому и нет.
Если у Вас другой обработчик может прерывать SVC, то никакой эксклюзивности уже нет. По определению.

Не путайте вызов SVC с вызовом обычной функции!

Цитата
Если это "мощное" прерывание попытается так сделать, то получит HardFault, а не SVC.

Да неужели? И по какой причине?


Цитата(AHTOXA @ Jun 5 2017, 11:54) *
Видите, "благодаря непрерываемости SVC". Это значит, что у svc в его случае самый высокий приоритет.

Вовсе нет, непрерываемость реализуется благодаря тому, что один вызов SVC не может прервать другой на уровне ЯДРА.
Другими словами все возникшие вызовы SVC становятся в очередь.

Цитата
А значит, вход в обработчик SVC блокирует остальные прерывания. Вот я и поинтересовался:

Я смотрю, что суть SVC понятна далеко не всем. Это как раз тот самый случай - изучить матчасть.



jcxz
Цитата(Forger @ Jun 5 2017, 11:11) *
Как раз наоборот - приоритет SVC должен быть самым низким ! (ну кроме разве что PendSV).
Да неужели? И по какой причине?

Если бы Вы открыли мануал на ядро, то узнали бы, что SVC является синхронным исключением. Т.е. - должно обработаться сразу же.
А если это не возможно (например - запрещены исключения или, как Вы советуете, оно вызвано внутри более приоритетного ISR), то будет активирован механизм эскалации до Hard Fault.

Цитата(Forger @ Jun 5 2017, 11:11) *
Не путайте вызов SVC с вызовом обычной функции!

Я то как раз не путаю, потому что у меня много где SVC используется. А вот Вам следовало бы хотя-бы ознакомиться с предметом, прежде чем советовать что-то.
И вызов SVC - как раз очень похож на вызов обычной функции. Для вызывающего процесса. Только на другом уровне привилегий.
Именно это и есть его главное предназначение - вызов функций с привилегиями системного уровня из прикладного уровня.

Цитата(Forger @ Jun 5 2017, 11:11) *
Другими словами все возникшие вызовы SVC становятся в очередь.

Какая ОЧЕРЕДЬ??? Откройте наконец-то мануал! Хватит фантазировать.
SVC - это синхронное прерывание, если оно не может быть активировано немедленно, то будет HF.

Цитата(Forger @ Jun 5 2017, 11:11) *
Я смотрю, что суть SVC понятна далеко не всем. Это как раз тот самый случай - изучить матчасть.

Вот именно.... Хватит чушь нести. Здесь не одни чайники собрались. Я думаю - много кто реально использует SVC в проектах.
Forger
Цитата(jcxz @ Jun 5 2017, 12:37) *
Вот именно....

Согласен, я поспешил с выводами sad.gif
Выходит, что в более приоритетных прерываниях нельзя использовать svc, а можно лишь в задачах/потоках. Этого я не знал ((

Я рассчитывал в реализациях программных очередей (queue) отказаться от критических секций (простое запрет/разрешение прерываний),
но коли в прерываниях это создает трудности (скажем, прерывание от usart), то выходит, что svc ипользовать не получится. А жаль ((
Или можно просто поднять приоритет svc до уровня чуть ниже важных прерываний (в которых запрещены вызовы серсвисов оси), тогда задача решится. Я прав?
_lexa_
Цитата(jcxz @ Jun 5 2017, 07:49) *
Если между LDREX и STREX произошло прерывание или был выполнен другой эксклюзивный доступ, до будет нарушение эксклюзивности.
Ну и где у вас между LDREX и STREX нарушение эксклюзивности?


Если смотреть по коду, который я привел - первый запрос на эксклюзивный доступ здесь:
CODE
void mpu_cfg_test()
{ ...
//выполняем запрос эксклюзивного доступа к переменной cur_mes.sync
DWORD sync=0;
sync = __LDREX(&cur_mes.sync);
__DMB();
soft_int_ini(); //настойка программного прерывания
soft_int_on(); //вызов программного прерывания
__WFI();
}


второй запрос в обработчике программного прерывания:
CODE
DWORD sync;
do
{
sync = __LDREX(&cur_mes.sync);
sync++;
sync = __STREX(sync, &cur_mes.sync);
}
while (sync);
jcxz
Цитата(Forger @ Jun 5 2017, 11:49) *
Выходит, что в более приоритетных прерываниях нельзя использовать svc, а можно лишь в задачах/потоках. Этого я не знал ((

Надо только обеспечить, чтобы в любой точке вызова SVC текущий уровень приоритета прерывания был ниже чем у SVC. И были разрешены faults. Тогда не будет HF, а будет корректный вход в ISR SVC.

Цитата(Forger @ Jun 5 2017, 11:49) *
Я рассчитывал в реализациях программных очередей (queue) отказаться от критических секций (простое запрет/разрешение прерываний),
но коли в прерываниях это создает трудности (скажем, прерывание от usart), то выходит, что svc ипользовать не получится. А жаль ((
Или можно просто поднять приоритет svc до уровня чуть ниже важных прерываний (в которых запрещены вызовы серсвисов оси), тогда задача решится. Я прав?

Можно конечно, но ещё раз спрашиваю: зачем надевать трусы через голову?? laughing.gif
Ведь если уж никак нельзя запрещать прерывания, то есть механизм LDREX/STREX, который именно для этого и создан.
А SVC - даже из названия видно - это для вызова системных функций. Привилегированных.
Можно конечно работу с очередями (или что там ещё) вынести на этот уровень, но зачем??? Это будет во много раз медленнее и громоздко чем LDREX/STREX.

Цитата(_lexa_ @ Jun 5 2017, 12:17) *
Если смотреть по коду, который я привел - первый запрос на эксклюзивный доступ здесь

А что такое "запрос на эксклюзивный доступ"? Откуда Вы это взяли?? Нет такого понятия. Нет никаких запросов там.
Эксклюзивный доступ read-modify-write - это пара инструкций LDREX/STREX работающих с некоей переменной.
Эксклюзивно - это означает, что никто другой (другой процесс) не обращается к этой переменной между LDREX и STREX. А если это условие нарушается - это нарушение эксклюзивности.
В Вашем случае есть одна только пара LDREX/STREX, её эксклюзивный доступ никто не нарушает.
Похоже Вы совсем не поняли, что написано в мануале и для чего это вообще нужно. Перечитайте ещё раз.
Forger
Цитата(jcxz @ Jun 5 2017, 13:50) *
Надо только обеспечить, чтобы в любой точке вызова SVC текущий уровень приоритета прерывания был ниже чем у SVC.

Это решаемо, просто, запрещается вызов SVC в критичных прерываниях, где запрещен вызов сервисов оси (соотв. assert).

Цитата
И были разрешены faults. Тогда не будет HF, а будет корректный вход в ISR SVC.

Не понял ((( Т.е. запрещенные faults нарушают нормальную работу SVC?
jcxz
Цитата(Forger @ Jun 5 2017, 13:00) *
Не понял ((( Т.е. запрещенные faults нарушают нормальную работу SVC?

Естественно. Я же писал уже несколько раз:
Цитата(jcxz @ Jun 5 2017, 11:37) *
Если бы Вы открыли мануал на ядро, то узнали бы, что SVC является синхронным исключением. Т.е. - должно обработаться сразу же.
А если это не возможно (например - запрещены исключения или, как Вы советуете, оно вызвано внутри более приоритетного ISR), то будет активирован механизм эскалации до Hard Fault.

Ещё раз: если SVC по каким-то причинам не может быть активировано немедленно, будет эскалация до HF.
Считайте что SVC - это вызов функции. Если у Вас в коде идёт команда BL, то ведь процессор обязан её выполнить, он не может её перескочить.
То же самое и с SVC - это считается вызовом системной функции. Она не может быть не выполнена. А если запрещены fault-ы - значит активировать исключение нельзя. Из-за этого конфликта и будет эскалация до HardFault. Процессор будет стоять на SVC и повышать-повышать приоритет её до тех пор, пока не сможет выполнить. Он и повысит до HF, которое может выполнить даже с запрещёнными fault-ами.
Так как это синхронное прерывание, значит оно должно быть выполнено немедленно.
Forger
Цитата(jcxz @ Jun 5 2017, 14:09) *
Так как это синхронное прерывание, значит оно должно быть выполнено немедленно.

Цитата(jcxz @ Jun 5 2017, 14:09) *
И были разрешены faults.

Речь как я понял идет про конкретно один fault - SVCall Handler. Или я опять не так понял?


Forger
Попался полезный документ по теме:
http://infocenter.arm.com/help/topic/com.a..._primitives.pdf
KnightIgor
Цитата(AHTOXA @ Jun 5 2017, 06:38) *
А в чём выгода такого метода по сравнению с простым запретом/разрешением прерываний? Я думаю, что по скорости это даже медленнее (тратится время на сохранение и восстановление контекста).
Прелесть же LDREX/STREX как раз в том, что они не блокируют прерывания.

Я не претендую на истину в последней инстанции и рассматриваю применение SVC в моих проектах как один из методов программирования с использованием предоставленных возможностей процессора. Ноги где-то растут из старых времен MS DOS и использованием INT 2F wink.gif.

Как кто-то в теме догадался, не люблю я всякие запреты-разрешения прерываний. Зачем меня должно в участке кода заботить, какие разрешены, а какие нет? Если работать с запретом и последующим разрешением общего прерывания, надо тоже хоть немного контекст сохранять: надо бы знать, а было ли вообще разрешено прерывание на момент необходимости его запрета, чтобы потом не разрешить случаем то, что было запрещено? Затем необходимо множить такие блоки во всех фрагментах, которые критическую секцию используют: хоть макросы напиши, код получается громоздкий для написания и понимания. Не нравится мне это чисто стилистически. На круг получится, что суммарный код обрамления критических секций станет больше обработчика SVC. Синтаксически - как следует из заголовка, который я привел, - я работаю с на вид обычными функциями, которые порождают единственную инструкцию.

И еще. Тут многие забалованы F4xx и выше. А у меня есть проекты на одной плате с опциональными F103 и F051 (ценообразование). Вы будете смеяться, но на Cortex-M0 F051 LDREX/STREX отсутствуют. А механизм SVC работает на обоих.
_lexa_
Цитата(jcxz @ Jun 5 2017, 10:59) *
А что такое "запрос на эксклюзивный доступ"? Откуда Вы это взяли?? Нет такого понятия. Нет никаких запросов там.

например, отсюда:
"PM0214. STM32F3xxx and STM32F4xxx Cortex-M4 programming manual.
2.2.7 Synchronization primitives
...
A pair of synchronization primitives comprises:
● A Load-Exclusive instruction: Used to read the value of a memory location, requesting
exclusive access
to that location."

Цитата(jcxz @ Jun 5 2017, 10:59) *
Эксклюзивный доступ read-modify-write - это пара инструкций LDREX/STREX работающих с некоей переменной.
Эксклюзивно - это означает, что никто другой (другой процесс) не обращается к этой переменной между LDREX и STREX. А если это условие нарушается - это нарушение эксклюзивности.
В Вашем случае есть одна только пара LDREX/STREX, её эксклюзивный доступ никто не нарушает.

Эта пара нужна, чтобы монитор эксклюзивного доступа отметил выполнение LDREX, затем при выполнении STREX снял эту метку, разумеется при условии, что данной парой LDREX/STREX мы не влезли между LDREX и STREX другой части программы, например в случае возникновения прерывания. Если переписать код следующим образом:
Код
void mpu_cfg_test()
{    ...
        //выполняем запрос эксклюзивного доступа к переменной cur_mes.sync
    DWORD sync=0;
    sync = __LDREX(&cur_mes.sync);
    __DMB();
    soft_int_ini();    //настойка программного прерывания
    soft_int_on();    //вызов программного прерывания
    __WFI();
    __STREX(sync, &cur_mes.sync);
}

ничего не изменится (на всякий случай я это даже проверил). Каким образом монитор эксклюзивного доступа должен увидеть, что использована именно пара LDREX/STREX
Напоминаю, это не какая-то реальная программа. Я всего лишь смоделировал ситуацию, когда после выполнения LDREX произошло прерывание и в этом прерывание производится эксклюзивный доступ к той же ячейке памяти.

Цитата(jcxz @ Jun 5 2017, 10:59) *
Похоже Вы совсем не поняли, что написано в мануале и для чего это вообще нужно. Перечитайте ещё раз.

В таком случае, если не сложно, приведите, пожалуйста, небольшой пример кода, когда происходит нарушение эксклюзивности.
jcxz
Цитата(Forger @ Jun 5 2017, 13:18) *
Речь как я понял идет про конкретно один fault - SVCall Handler. Или я опять не так понял?

Бит разрешения на все fault-ы один общий.
AHTOXA
Цитата(_lexa_ @ Jun 5 2017, 18:26) *
В таком случае, если не сложно, приведите, пожалуйста, небольшой пример кода, когда происходит нарушение эксклюзивности.

Вот тут посмотрите: тынц. И вообще всю тему посмотрите. Там очень подробно всё разобрали, с учётом особенностей STM32.
_lexa_
Цитата(Forger @ Jun 5 2017, 12:22) *
Попался полезный документ по теме:
http://infocenter.arm.com/help/topic/com.a..._primitives.pdf


Я тоже его нашел, сейчас как раз изучаю. Тема также освещена в ARMv7-M Architecture Reference Manual, где среди прочего написано про разделяемую память, про глобальный и локальный мониторы эксклюзивного доступа, многопроцессорность и т.д. Все эти документы ARM-овские.
У ST LDREX/STREX описаны в PM0214. STM32F3xxx and STM32F4xxx Cortex-M4 programming manual. Причем довольно коротко, многое не по какой-то причине не затронуто и даже ссылок на АРМ-овские документы не даны.
В общем, поизучав все это приходит мысль, что я просто в каком-то регистре не поставил какой-то флаг и у меня, например, не работает глобальный монитор.
jcxz
Цитата(KnightIgor @ Jun 5 2017, 14:40) *
Если работать с запретом и последующим разрешением общего прерывания, надо тоже хоть немного контекст сохранять: надо бы знать, а было ли вообще разрешено прерывание на момент необходимости его запрета, чтобы потом не разрешить случаем то, что было запрещено?

void f1()
{
CPU_SR_ALLOCATE(); //выделение переменной (регистра) для сохранения состояния прерываний
ENTR_CRT_SECTION(); //вход в критическую секцию (запрет прерываний)
...
EXIT_CRT_SECTION(); //выход из критической секции (восстановление состояния прерываний)
}
void f2()
{
CPU_SR_ALLOCATE(); //выделение переменной (регистра) для сохранения состояния прерываний
ENTR_CRT_SECTION(); //вход в критическую секцию (запрет прерываний)
f1();
...
EXIT_CRT_SECTION(); //выход из критической секции (восстановление состояния прерываний)
f1();
}
Вот и всё отслеживание. Больше никаких проверок не нужно и можно вызывать сколько угодно вложенно - всё работает корректно.
ENTR_CRT_SECTION() - компилится в 2 команды CPU;
EXIT_CRT_SECTION() - компилится в 1 команду CPU.
Теперь сравните со своим огородом в десятки команд.
AHTOXA
Цитата(KnightIgor @ Jun 5 2017, 17:40) *
Как кто-то в теме догадался, не люблю я всякие запреты-разрешения прерываний. Зачем меня должно в участке кода заботить, какие разрешены, а какие нет? Если работать с запретом и последующим разрешением общего прерывания, надо тоже хоть немного контекст сохранять: надо бы знать, а было ли вообще разрешено прерывание на момент необходимости его запрета, чтобы потом не разрешить случаем то, что было запрещено?


Ох, ну вот уж проблема так проблема sm.gif
Это может выглядеть, например, просто как объявление
Код
{
    TCritSect cs;
    ...
}

в начале блока кода. При выходе из блока прерывания автоматически возвращаются в исходное состояние.

Я не говорю, что ваш способ ошибочен, я говорю, что он не даёт преимуществ по сравнению с простым запретом/разрешением прерываний, и к тому же он (гораздо) медленнее. Думаю, что на маленьких процессорах (типа M0(+)) это может быть критично.
Кроме того, как тут выяснили, этот способ требует правильной расстановки приоритетов, а иначе способен вызвать HardFault.
jcxz
Цитата(_lexa_ @ Jun 5 2017, 15:26) *
● A Load-Exclusive instruction: Used to read the value of a memory location, requesting
exclusive access
to that location."

Видимо это какое-то изобретение терминологии деятелей из STM. laughing.gif
Изучать ядро нужно по первоисточнику http://infocenter.arm.com/help/index.jsp, а не по переводам и толкованиям. А в первоисточнике нет никаких "requesting".

Цитата(_lexa_ @ Jun 5 2017, 15:26) *
ничего не изменится (на всякий случай я это даже проверил). Каким образом монитор эксклюзивного доступа должен увидеть, что использована именно пара LDREX/STREX

Вот именно в таком случае - оно и сработает и обнаружит нарушение эксклюзивности.
Команда LDREX взводит некий триггер в "1". STREX атомарно сбрасывает его и, если в в момент своего выполнения триггер стоял - выполняет операцию, если не стоял - не выполняет. И возвращает соотв. значение.
Также любое прерывание сбрасывает этот триггер. А также команда CLREX тоже сбрасывает.
Вот и всё. Всё просто.
scifi
Цитата(jcxz @ Jun 5 2017, 17:21) *
Изучать ядро нужно по первоисточнику http://infocenter.arm.com/help/index.jsp, а не по переводам и толкованиям. А в первоисточнике нет никаких "requesting".

В первоисточнике немного намудрили, так как объясняют концепцию применительно к многопроцессорным системам в том числе, а там несколько сложнее.
тынц
тынц
AVI-crak
Начали за упокой, кончили за здравие.

Как уже было сказано, LDREX выставляет атомарный флаг при использовании команды в потоке, конкретно на используемый адрес. Точнее конкретный адрес чтения выставляется на мониторе, и отслеживается аппаратными механизмами сразу на интерфейсе памяти.
Атомарный флаг может сбросить любое прерывание, любое аппаратное чтение/запись по этому адресу (например DMA).
Флаг не сбрасывается в момент применения команды LDREX в прерывании и перебивании его более высоким приоритетом. Отчего костыль для использования в прерывании содержит собственный сброс до и после.
STREX выполняется, или не выполняется без использования программной проверки атомарного флага, этот механизм выполнен полностью аппаратно.
STREX выдаёт флаг, видимый для программы - для проверки успешности операции.

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

+Ещё один важный прикол - конвейер. Лучше перебздеть, и подтверждать полный сброс данных в память.
+Ещё грабли - LDREX STREX могут применяться на той памяти, что имеет прямое подключение к ядру мк. Например в М7 часть памяти заведена через ускоритель, в результате применение LDREX STREX моментально вешает мк.

------------

SVC - безусловное прерывание. Отрабатывается без вытеснения из любой позиции. Перебить SVC - просто невозможно.
SVC - это рыба для сервисов ОС, с небольшим количеством шаманства - превращается в очень удобную функцию.
У меня на SVC полностью работает собственная ось.
_lexa_
Цитата(jcxz @ Jun 5 2017, 14:21) *
Видимо это какое-то изобретение терминологии деятелей из STM. laughing.gif
Изучать ядро нужно по первоисточнику http://infocenter.arm.com/help/index.jsp, а не по переводам и толкованиям. А в первоисточнике нет никаких "requesting".


Вот в первоисточнике ARMv7-M Architecture Reference Manual:
A3.4.2 Exclusive access instructions and Shareable memory regions.
Operation of the global monitor.
Load-Exclusive from Shareable memory performs a load from memory, and causes the physical address of
the access to be tagged as exclusive access for the requesting processor (эксклюзивный доступ для запрашивающего процессора)

Да и как не читать? Это целевой мануал, для процессора с которым я работаю.

Цитата(jcxz @ Jun 5 2017, 14:21) *
Вот именно в таком случае - оно и сработает и обнаружит нарушение эксклюзивности.
Команда LDREX взводит некий триггер в "1". STREX атомарно сбрасывает его и, если в в момент своего выполнения триггер стоял - выполняет операцию, если не стоял - не выполняет. И возвращает соотв. значение.
Вот и всё. Всё просто.

Именно так я себе все это и представлял.

Цитата(AHTOXA @ Jun 5 2017, 13:51) *
Вот тут посмотрите: тынц. И вообще всю тему посмотрите. Там очень подробно всё разобрали, с учётом особенностей STM32.

Спасибо за ссылку. Узнал много интересного.
AVI-crak
Цитата(_lexa_ @ Jun 5 2017, 23:40) *
Спасибо за ссылку. Узнал много интересного. В частности, что LDREX/STREX, по крайней мере для STM32 на cortex-m4, не могут использоваться для синхронизации доступа к памяти, т.к. любое прерывание сбрасывает тег монитор и все дальнейшее выполнение программы происходит, как будто LDREX до этого не выполнялась. Бесполезность LDREX/STREX для синхронизации косвенно подтверждается еще и тем, что в CMSIS-RTOS эти команды в мутексах и семафорах не используются.


Сброс тег монитора из потока в прерывание - это нормальное поведение LDREX/STREX, именно для этого они и задумывались.
Нет широкого распространения по другой причине - память должна подключаться к ядру без цепочек ускорителей. То-есть команды LDREX/STREX гарантированно выполняются на всех arm чипах, но не на всей используемой памяти. Делить на можно/нельзя - слишком сложно, проще не использовать вовсе. Однако применение LDREX/STREX даёт очень ощутимое ускорение на операциях с атомарными флагами. Словом можно - если руки растут из нужного места.
Весь смысл в том чтобы не испортить другие флаги.
_lexa_
Цитата(AVI-crak @ Jun 5 2017, 18:00) *
Сброс тег монитора из потока в прерывание - это нормальное поведение LDREX/STREX, именно для этого они и задумывались.
Нет широкого распространения по другой причине - память должна подключаться к ядру без цепочек ускорителей. То-есть команды LDREX/STREX гарантированно выполняются на всех arm чипах, но не на всей используемой памяти. Делить на можно/нельзя - слишком сложно, проще не использовать вовсе. Однако применение LDREX/STREX даёт очень ощутимое ускорение на операциях с атомарными флагами. Словом можно - если руки растут из нужного места.
Весь смысл в том чтобы не испортить другие флаги.

Пожалуй я в самом деле погорячился по поводу невозможности синхронизации с помощью LDREX/STREX.
KnightIgor
Цитата(jcxz @ Jun 5 2017, 14:57) *

У меня вопросы по Вашему примеру.
Что будет, если после сохранения текущего статуса разрешения прерываний в выделеной переменной (оно было разрешено), но до исполнения самой инструкции запрета прерывания произойдет-таки прерывание, которое по какой-либо логике всей программы запретит прерывания? Как я понимаю, после выхода из критической секции прерывание будет-таки разрешено , т.к. будет восстановлено из переменной?
jcxz
Цитата(AVI-crak @ Jun 5 2017, 19:37) *
Как уже было сказано, LDREX выставляет атомарный флаг при использовании команды в потоке, конкретно на используемый адрес. Точнее конкретный адрес чтения выставляется на мониторе, и отслеживается аппаратными механизмами сразу на интерфейсе памяти.
Атомарный флаг может сбросить любое прерывание, любое аппаратное чтение/запись по этому адресу (например DMA).

Монитор эксклюзивного доступа не контролирует адрес. Об этом явно сказано в мануале.
Да и как вы это себе представляете? Если у процессора 4гига адресное пространство - это-ж нужна 4^32 триггеров иметь в CPU - для каждого адреса.
Опять-же - любое чтение/запись не может и не должно. Может только STREX, CLREX или любое изменение текущего уровня прерывания.
DMA, как и прочие bus-master-ы, тоже не должны влиять - они не относятся к ядру процессора.

Цитата(_lexa_ @ Jun 5 2017, 19:40) *
т.к. любое прерывание сбрасывает тег монитор и все дальнейшее выполнение программы происходит, как будто LDREX до этого не выполнялась.

И что???
Так в этом и заключается вся полезность LDREX/STREX! Именно для того оно и предназначено - если между LDREX и STREX было прерывание (или переключение контекста, которое тоже выполняется через прерывание), то значит - нет гарантии, что операция чтение-модификация-запись была эксклюзивной.
Похоже Вы так и не поняли зачем нужен и как работает этот эксклюзивный доступ... sad.gif

Цитата(_lexa_ @ Jun 5 2017, 19:40) *
Бесполезность LDREX/STREX для синхронизации косвенно подтверждается еще и тем, что в CMSIS-RTOS эти команды в мутексах и семафорах не используются.

Они и не должны там использоваться если ОС должна быть мультиплатформенной. Они могут использоваться в портах ОС.
Понятно - все дураки, и создатели ядра и создатели IAR-а например, да все кто поддерживает эти LDREX/STREX - не понимают они их бесполезность. Объясните им biggrin.gif

Цитата(AVI-crak @ Jun 5 2017, 20:00) *
Нет широкого распространения по другой причине - память должна подключаться к ядру без цепочек ускорителей. То-есть команды LDREX/STREX гарантированно выполняются на всех arm чипах, но не на всей используемой памяти.

Эксклюзивный доступ нужен не к массивам памяти, а к отдельным переменным, коих в программе обычно мало. Достаточно вынести их в отдельный регион памяти и объявить его некешируемым (через MPU).

Цитата(KnightIgor @ Jun 5 2017, 21:42) *
Что будет, если после сохранения текущего статуса разрешения прерываний в выделеной переменной (оно было разрешено), но до исполнения самой инструкции запрета прерывания произойдет-таки прерывание, которое по какой-либо логике всей программы запретит прерывания? Как я понимаю, после выхода из критической секции прерывание будет-таки разрешено , т.к. будет восстановлено из переменной?

Ну наверное.
А что это за прерывание такое, которое внутри себя запрещает прерывания??? Аппаратное асинхронное?
Т.е. - оно может вызваться в любой точке и в произвольный момент времени запретить прерывания?
А зачем это нужно и как может такая программа вообще функционировать?
_lexa_
Цитата(jcxz @ Jun 5 2017, 21:35) *
Похоже Вы так и не поняли зачем нужен и как работает этот эксклюзивный доступ... sad.gif

AVI-crak доходчиво объяснил:
Цитата(AVI-crak @ Jun 5 2017, 18:00) *
Сброс тег монитора из потока в прерывание - это нормальное поведение LDREX/STREX, именно для этого они и задумывались.


Цитата(jcxz @ Jun 5 2017, 21:35) *
Они и не должны там использоваться если ОС должна быть мультиплатформенной. Они могут использоваться в портах ОС.
Понятно - все дураки, и создатели ядра и создатели IAR-а например, да все кто поддерживает эти LDREX/STREX - не понимают они их бесполезность. Объясните им biggrin.gif

Я же чуть ниже написал, что погорячился. И сообщение поправил, чтоб глаза не резало.
AVI-crak
Цитата(jcxz @ Jun 6 2017, 03:35) *
Монитор эксклюзивного доступа не контролирует адрес. Об этом явно сказано в мануале.
Да и как вы это себе представляете? Если у процессора 4гига адресное пространство - это-ж нужна 4^32 триггеров иметь в CPU - для каждого адреса.

Там всё просто, один единственный 32b регистр и схема сравнения на коммутаторе памяти, уже после арбитра и коммутатора нагрузки. Эти команды не выполняются целиком и полностью в ядре мк, они большей частью размазаны по всему кристаллу.
Точно так-же как и команды DSB, ISB, ISB, WFE, и так далее.
jcxz
Цитата(AVI-crak @ Jun 6 2017, 09:24) *
Там всё просто, один единственный 32b регистр и схема сравнения на коммутаторе памяти, уже после арбитра и коммутатора нагрузки. Эти команды не выполняются целиком и полностью в ядре мк, они большей частью размазаны по всему кристаллу.

Открываем мануал на M4, читаем:
"The Cortex-M4 processor implements a local exclusive monitor. The local monitor within the processor
has been constructed so that it does not hold any physical address, but instead treats any access as
matching the address of the previous LDREX
. This means that the implemented exclusives reservation
granule is the entire memory address range."
Фантазии про некий регистр рассеиваются laughing.gif
Влияние доступов от DMA и прочих bus-masters на exclusive monitor - также представляется крайне сомнительным, так как:
1. зачем оно нужно?
2. где про это сказано?
3. exclusive monitor относится к ядру, а DMA- и прочие bus-masters к ядру не относятся и у каждого МК-мэйкера свои.
KnightIgor
Цитата(jcxz @ Jun 5 2017, 22:35) *
Ну наверное.

То есть, предложенное решение не на все случаи? Вы также признаете очевидность, Мистер Андерсон? wink.gif

Цитата
А что это за прерывание такое, которое внутри себя запрещает прерывания??? Аппаратное асинхронное?
Т.е. - оно может вызваться в любой точке и в произвольный момент времени запретить прерывания?
А зачем это нужно и как может такая программа вообще функционировать?

Да кто же его знает! Однако, такое возможно. Например, прерывание, сделав дело и установив флаг, запрещает прерывания до момента, пока синхронная часть не обработает флаг и не сочтет нужным прерывание снова разрешить. И Ваш код породит огород, на котором пожнут не то, что сеяли.
AVI-crak
Цитата(jcxz @ Jun 6 2017, 14:20) *
1. зачем оно нужно?
2. где про это сказано?
3. exclusive monitor относится к ядру, а DMA- и прочие bus-masters к ядру не относятся и у каждого МК-мэйкера свои.

Это результат проверки с отладчиком на реальном камне М3-7. В последнее время я чаще доверяю собственным экспериментам, чем расплывчатому переводу гугла.
Кстати, чтобы убрать последствия действий самого отладчика - точки останова необходимо ставить за пределами тестовой функции, иначе будут увлекательные результаты.


Цитата(KnightIgor @ Jun 6 2017, 16:22) *
Да кто же его знает! Однако, такое возможно. Например, прерывание, сделав дело и установив флаг, запрещает прерывания до момента


Находясь в прерывании нельзя запретить само прерывание, получите сбой. Однако можно сбросить те сработавшие прерывания - что имеют более низкий приоритет, те что находятся в ожидании. Но не те что уже сработали и были вытеснены. Иначе будет разрушение стека.
Кстати, эти действия могут понадобится в случае просто огромного кода в теле прерывания. То-есть нужно сначала создать себе проблемы, и только потом героически их решать.
Юзайте SVC, и будет вам счастье.
jcxz
Цитата(KnightIgor @ Jun 6 2017, 12:22) *
То есть, предложенное решение не на все случаи? Вы также признаете очевидность, Мистер Андерсон? wink.gif

Для каких-то высосанных из пальца случае разве что. Для реальных задач из жизни - бесполезно.

Цитата(KnightIgor @ Jun 6 2017, 12:22) *
Да кто же его знает! Однако, такое возможно. Например, прерывание, сделав дело и установив флаг, запрещает прерывания до момента, пока синхронная часть не обработает флаг и не сочтет нужным прерывание снова разрешить. И Ваш код породит огород, на котором пожнут не то, что сеяли.

Вы сами-то хоть верите в то, что пишете? У Вас реально были такие алгоритмы? Или может у кого-то из здесь присутствующих (чайников не считаем)?
Конечно - можно лисапет и с 5-ю колёсами изобрести. Ездить будет? Ну а почему бы и нет. Нужно это кому-то реально? Вопрос риторический.
А если на дороге встретится 2 ямки - лисапет с 2-я колёсами ведь в них провалится, а с 5-ю - нет! Это значит что 2-колёсный лисапет никуда не годится и все кто на нём ездят - идиоты, а кто на 5-колёсном - умные?
И можно ещё напридумывать кучу причин, почему 2-колёсный плох. Только все почему-то на нём ездят и не жужжат, а у Вас - не получается никак и Вам обязательно нужен 5-колёсный laughing.gif

Цитата(AVI-crak @ Jun 6 2017, 13:02) *
эти действия могут понадобится в случае просто огромного кода в теле прерывания.

В этом случае надо просто перенести этот код в задачу ОС и всё.
Да и без ОС можно решить задачу нормально: возбудив программное прерывание с меньшим приоритетом и продолжив работу там, отпустив аппаратный ISR.
Как видно - для всего есть штатные решения, а необходимость запрета прерываний внутри ISR - высосана из пальца.

Цитата(AVI-crak @ Jun 6 2017, 13:02) *
Это результат проверки с отладчиком на реальном камне М3-7. В последнее время я чаще доверяю собственным экспериментам, чем расплывчатому переводу гугла.

А зачем Вам нужно, чтобы DMA-операция влияла на монитор эксклюзивности? Ну т.е. - реально, а не по надуманным причинам?
KnightIgor
Цитата(AVI-crak @ Jun 6 2017, 12:02) *
Юзайте SVC, и будет вам счастье.

Это не по адресу: я и так юзаю - почитайте сначала. Меня отговаривают и предлагают варианты, которые не всегда работоспособны.
Цитата
Находясь в прерывании нельзя запретить само прерывание, получите сбой.

Я предполагаю, что это Вы сгоряча. Очень даже легко можно запретить прерывание, находясь в нем. Без последствий.

Цитата(jcxz @ Jun 6 2017, 13:08) *
Для каких-то высосанных из пальца случае разве что. Для реальных задач из жизни - бесполезно.

Почитайте Мерфи: если что-то может случиться, оно случится.
Цитата
Вы сами-то хоть верите в то, что пишете?

Инженерная наука не оперирует понятием веры. Есть факты, есть опыт. ОТ: правда, слышал, что ныне за такое высказывание в РФ и сесть можно.
Цитата
Как видно - для всего есть штатные решения, а необходимость запрета прерываний внутри ISR - высосана из пальца.

Утверждение более чем недальновидное.
Рассмотрим пример. Сразу оговорюсь, что речь не о глобальном запрете прерывания, а о запрете периферийного. Но и Вы пишете об ISR вообще.

В прерывании от устройства обнаруживается, что буфер приема заполнен, т.е. недовыбран синхронным циклом. Есть два варианта: выбросить данные или таки еще немного подождать, дать возможность выбрать, тем более, что передача данных по каналу сама по себе требует времени, и можно успеть до переполнения периферийного регистра. Одно из решений: запретить прерывание, оставив флаг, выйти, дать синхронному циклу поработать. Синхронный цикл после выбоки данных просто разрешает прерывание снова. Поскольку флаг взведен, прерывание щелкнет незамедлительно еще раз, данные будут записаны в освободившееся место. Это одно из возможных решений, которое я никому не навязываю. У меня так работают многие каналы. На результаты жалоб нет.
_lexa_
Цитата(jcxz @ Jun 6 2017, 08:20) *
Открываем мануал на M4, читаем:
"The Cortex-M4 processor implements a local exclusive monitor. The local monitor within the processor
has been constructed so that it does not hold any physical address, but instead treats any access as
matching the address of the previous LDREX
. This means that the implemented exclusives reservation
granule is the entire memory address range."

судя по этому абзацу да по остальному в мануалах (применительно к cortex-m4) для синхронизации на LDREX/STREX достаточно одной единственной ячейки памяти, которую будут читать/писать LDREX/STREX, на весь исполняемый процессором код. А для STM32f4 даже настройки MPU не потребуется (кэша на RAM там нет)

Цитата(jcxz @ Jun 6 2017, 08:20) *
Влияние доступов от DMA и прочих bus-masters на exclusive monitor - также представляется крайне сомнительным, так как:

Я так понимаю, AVI-crak просто провел эксперимент, в результате которого DMA сбросил тэг монитора, и здесь не стоит вопрос нужно ли это или не нужно. По поводу того, где это сказано, конечно не совсем про то, но в принципе сюда можно взглянуть:
ARMv7-M Architecture Reference Manual
A3.4.5 Load-Exclusive and Store-Exclusive usage restrictions
• An explicit store to memory can cause the clearing of exclusive monitors associated with other
processors, therefore, performing a store between the LDREX and the STREX can result in a livelock
situation. As a result, code must avoid placing an explicit store between an LDREX and an STREX in a
single code sequence.
jcxz
Цитата(KnightIgor @ Jun 6 2017, 22:34) *
Рассмотрим пример. Сразу оговорюсь, что речь не о глобальном запрете прерывания, а о запрете периферийного. Но и Вы пишете об ISR вообще.

Передёргиваете. При чём тут маскирование определённого прерывания? Это вполне штатная ситуация, сам так часто делаю. Разговор был о глобальном флаге запрета всех прерываний.
Если даже это вдруг по каким-то причинам нужно, то это не является штатным случаем. Но для таких особых случаев и код особый. В остальных 99.9% - те критические секции что я описал вполне работоспособны.
Да вообще - какой смысл спорить то? О чём?? Откройте исходники какой-нить ОС - посмотрите как эти критические секции реализованы. И объясняйте их создателем что они дураки, а Вы один умный.
Откройте любые примеры идущие с компилятором - посмотрите.
Понятно что все вокруг дураки, один Вы умный.....

Цитата(_lexa_ @ Jun 6 2017, 22:56) *
для синхронизации на LDREX/STREX достаточно одной единственной ячейки памяти

Ну если Вашему коду достаточно - Вы счастливый человек, так как у Вас очень простая программа.
Обычно таких мест в программе - десятки.

Цитата(_lexa_ @ Jun 6 2017, 22:56) *
По поводу того, где это сказано, конечно не совсем про то, но в принципе сюда можно взглянуть:

Это не то что "не совсем то", а совсем не то. Там речь о "других CPU". Для других CPU - кто-ж спорит - это конечно нужно, если программа выполняется на нескольких ядрах.
Я писал про другие bus-masters типа DMA, Ethernet-контроллеров и прочего, которое не выполняет программы, задачи, не выполняет какой-то код, задачи которого не нужно синхронизировать с другими задачами.
Alechek
Цитата(jcxz @ Jun 6 2017, 13:20) *
Фантазии про некий регистр рассеиваются laughing.gif


Опять открываем мануалs

Цитата(ARM ® v7-M Architecture Reference Manual)
A3.4 Synchronization and semaphores
The model for the use of a Load-Exclusive/Store-Exclusive instruction pair, accessing memory address x is:
• The Load-Exclusive instruction always successfully reads a value from memory address x
• The corresponding Store-Exclusive instruction succeeds in writing back to memory address x only if no other
processor or process has performed a more recent store of address x
. The Store-Exclusive operation returns
a status bit that indicates whether the memory write succeeded.
A Load-Exclusive instruction tags a small block of memory for exclusive access. The size of the tagged block is
IMPLEMENTATION DEFINED, see Tagging and the size of the tagged memory block on page A3-75. A Store-Exclusive
instruction to the same address clears the tag.

A3.4.3 Tagging and the size of the tagged memory block
As shown in Figure A3-6 on page A3-71 and Figure A3-7 on page A3-74, when a LDREX instruction is executed, the
resulting tag address ignores the least significant bits of the memory address:
Tagged_address == Memory_address[31:a]
The value of a in this assignment is IMPLEMENTATION DEFINED, between a minimum value of 2 and a maximum
value of 11. For example, in an implementation where a = 4, a successful LDREX of address 0x000341B4 gives a tag
value of bits[31:4] of the address, giving 0x000341B. This means that the four words of memory from 0x000341B0 to
0x000341BF are tagged for exclusive access. Subsequently, a valid STREX to any address in this block will remove the
tag.A3 ARM Architecture Memory Model
A3.4 Synchronization and semaphores
A3-76 Copyright © 2006-2008, 2010, 2014 ARM. All rights reserved. ARM DDI 0403E.b
Non-Confidential ID120114
The size of the tagged memory block is called the Exclusives reservation granule. The Exclusives reservation
granule is IMPLEMENTATION DEFINED between:
• One word, in an implementation with a == 2.
• 512 words, in an implementation with a == 11.
Note
For the local monitor, one of the IMPLEMENTATION DEFINED options is for the monitor to treat any access as
matching the address of the previous Load-Exclusive access. In such an implementation, the Exclusives reservation
granule is the entire memory address range.


Цитата(ARM® Cortex®‑M4 Processor Technical Reference Manual )
3.6 Exclusive monitor

The Cortex-M4 processor implements a local exclusive monitor. The local monitor within the processor has been constructed so that it does not hold any physical address, but instead treats any access as matching the address of the previous LDREX. This means that the implemented exclusives reservation granule is the entire memory address range.



Цитата(Cortex-M3 Technical Reference Manual (r2p0))
3.6. Exclusive monitor
The Cortex-M3 processor implements a local exclusive monitor. For more information about semaphores and the local exclusive monitor see the ARMv7M ARM Architecture Reference Manual.


Так что вырисовывается вот что:
- вся память поделена на регионы размером [Exclusives reservation granule]
- есть N регистров эксклюзивного доступа к памяти, где N от 1 до RAM_SIZE/[Exclusives reservation granule]
- сбрасывается эксклюзивный доступ РЕГИОНА при ЛЮБОЙ явной записи в этот РЕГИОН
- для Cortex-M3 размер [Exclusives reservation granule] явно не определен и, по всей видимости, определяется производителем.
- для Cortex-M4 размер [Exclusives reservation granule] равен всей памяти.
jcxz
Цитата(Alechek @ Jun 7 2017, 10:31) *
Опять открываем мануалs

Не тот мануал открываете. Этот мануал - на архитектуру в целом (по которой построены разные ядра), а я Вам приводил на конкретное ядро, соответствующее топику - читайте внимательнее.
И даже в выделенном Вами фрагменте архитектурного мануала уже указано "IMPLEMENTATION DEFINED", а в мануале на ядро M4, основанное на этой архитектуре это NOT IMPLEMENTED - вполне законно.

Цитата(Alechek @ Jun 7 2017, 10:31) *
- есть N регистров эксклюзивного доступа к памяти, где N от 1 до RAM_SIZE/[Exclusives reservation granule]
...

Ещё раз, для самых непонятливых: откройте мануал на конкретное ядро, то есть - "ARM Cortex-M4 Processor Technical Reference Manual" и оставьте свои пустые фантазии.

Цитата(Alechek @ Jun 7 2017, 10:31) *
- вся память поделена на регионы размером [Exclusives reservation granule]

Эта фраза из TRM: "This means that the implemented exclusives reservation granule is the entire memory address range." - означает что "есть только одна гранула, размером со всю память".

А эта фраза TRM:
"The local monitor within the processor has been constructed so that it does not hold any physical address, but instead treats any access as matching the address of the previous LDREX."
Означает что инструкция LDREX относится к предыдущей инструкции STREX с любым адресом (т.е. - любой адрес является "matching the address") вне зависимости от адреса.
Alechek
Цитата
Не тот мануал открываете

Ну почему же не тот? Я все открыл, смотрите выше.
И мануалы на М4 и на М3 там тоже есть.
Выводы подправил.

А вот Вы вводите людей в заблуждение:
Цитата(jcxz @ Jun 5 2017, 12:49) *
Если между LDREX и STREX произошло прерывание или был выполнен другой эксклюзивный доступ, до будет нарушение эксклюзивности.
Ну и где у вас между LDREX и STREX нарушение эксклюзивности?


Про условие эксклюзивной записи для нарушения эксклюзивности - нет такого!
jcxz
Цитата(Alechek @ Jun 7 2017, 11:18) *
Про условие эксклюзивной записи для нарушения эксклюзивности - нет такого!

В смысле нет?
Если у Вас есть пара LDREX_1/STREX_1 и Вы внутри этой пары, между LDREX_1 и STREX_1 поставите другую STREX_2, то STREX_1 вернёт статус - нарушение эксклюзивности.
Потому что триггер эксклюзивного доступа был сброшен STREX_2.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.