Перейти к содержанию
    

Библиотека атомарных операций для STM32

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

А зачем Вам мониторить все обращения? Ведь нужны только те обращения, которые могут использоваться для доступа к переменным синхронизации.

Если Вам нужна чтение-модификация-запись переменной синхронизации, или неатомарное чтение (несколькиим командами) этой переменной, или запись (любая) в эту переменную,

то извольте все эти операции выполнять только инструкциями LDREX/STREX. Тогда всё будет нормально и ставить этот бит по каждому обращению к памяти совсем излишне

(но конечно возможно для упрощения реализации ядра CPU).

А просто чтение этой-же переменной синхронизации можно делать и вообще одной командой LDR (которая априори атомарна) пусть даже она и попадёт между LDREX и STREX

выполняющимися в другом потоке - это никак не повлияет на результат.

 

 

В Cortex-M4 операция STREX даст отбой даже если в прерывании запись была сделана командой STR и совсем в другую ячейку памяти.

Вполне возможно для упрощения реализации механизма в ядре сделали срабатывание не только на эксклюзивный доступ.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вполне возможно для упрощения реализации механизма в ядре сделали срабатывание не только на эксклюзивный доступ.

 

С LDREX/STREX все еще более запутанней.

 

Решил тут протестировать как там насчет работы из разных областей памяти.

Выяснилось, что LDREX/STREX правильно работает когда переменные находятся в RAM вблизи 0x1000_0000-0x3000_0000

То, что кэширование разное сверху и снизу границы 0x2000_0000 никак не влияет, барьеры памяти можно не ставить.

А вот если использовать память которая находится после границы 0x4000_0000 , то пара LDREX/STREX там никакого эффекта не дает, хотя и исключений не вызывает.

Т.е. можно спокойно испортить переменную, а STREX ничего не покажет.

 

Ну и как положительный момент можно отметить, что выполнение кода из RAM на работу LDREX/STREX тоже не влияет.

 

А с DMA вопрос еще темный.

Мутный момент также с областями внешней памяти.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Выяснилось, что LDREX/STREX правильно работает когда переменные находятся в RAM вблизи 0x1000_0000-0x3000_0000

А какой контроллер вы тестировали?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

На моём STM32L151 получились такие результаты:

 

Монитор НЕ отлавливает нарушение эксклюзивного доступа при простом изменение области памяти для которой был вызван LDREX или любой другой области памяти

 

Монитор отлавливает нарушение эксклюзивного доступа если

1. Был вызван STREX на любую область ОЗУ (не обязательно на ту, для которой был вызван LDREX)

2. Произошло любое прерывание

Изменено пользователем ArtDenis

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Т.е. можно спокойно испортить переменную, а STREX ничего не покажет.

Вы портили при помощи другой STREX или просто STR? Если второе - эксперимент некорректный.

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Монитор отлавливает нарушение эксклюзивного доступа если

2. Произошло любое прерывание

 

Странно, у меня не на любое, а только такое где был STREX или STR во внутреннюю RAM , а вот на PUSH в ту же RAM не реагирует.

 

 

Вы портили при помощи другой STREX или просто STR? Если второе - эксперимент некорректный.

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

 

Конечно использовал STREX.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Странно, у меня не на любое, а только такое где был STREX или STR во внутреннюю RAM , а вот на PUSH в ту же RAM не реагирует

Вообще, в прерывании был STR. Не подумал когда тестировал, что это имеет значение

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вообще, в прерывании был STR. Не подумал когда тестировал, что это имеет значение

Проверил ещё раз. Достаточно любого прерывания.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Программы - в студию.

И выводы, желательно, не противоречивые. :rolleyes:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Программы - в студию.

К сожалению по мере тестирования программа менялась :( Последний вариант - тестирование пустого прерывания. Устроит?

 

А выводы - вроде как работает, но не настолько эффективно как хотелось. Скорее всего буду использовать.

Изменено пользователем ArtDenis

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

К сожалению по мере тестирования программа менялась :( Последний вариант - тестирование пустого прерывания. Устроит?

 

А выводы - вроде как работает, но не настолько эффективно как хотелось. Скорее всего буду использовать.

Устроят любые программы, как образец. И тестировщиков прибавится. И выводы скорректируются.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Устроят любые программы, как образец. И тестировщиков прибавится. И выводы скорректируются.

 

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

#include <stdint.h>
#include "stm32_lib/stm32l1xx/hl_gpio.hpp"
#include "stm32_lib/stm32l1xx/hl_adc.hpp"
#include "stm32_lib/stm32l1xx/hl_rcc.hpp"

using namespace hl;

typedef PA8 LedPin;

static void init_led()
{
    PA::clock_on();
    PA::reset();
    LedPin::conf_out_push_pull();
    LedPin::off();
}

static void adc_init()
{
    rcc_enable_hsi();
    ADC_<1>::clock_on();
    ADC_<1>::reset();
    ADC_<1>::set_regular_len(1);
    ADC_<1>::set_regular_channel_pos(1, 0);
    ADC_<1>::enable_eoc_interrupt();
    ADC_<1>::enable();
    NVIC_EnableIRQ(ADC1_IRQn);
}

static void led_on(bool value)
{
    LedPin::set_out(value);
}

// Нулевой тест. Между LDREXW и STREXW почти ничего нету
// Монитор НЕ отлавливает нарушение 
static void test0()
{
    volatile uint32_t var = 0;
    __LDREXW(&var);
    bool res = __STREXW(10, &var) == 0;
    led_on(res);
}

// Изменение памяти при помощи STR
// Монитор НЕ отлавливает нарушение 
static void test1()
{
    volatile uint32_t var = 0;
    __LDREXW(&var);
    var = 20;
    bool res = __STREXW(10, &var) == 0;
    led_on(res);
}

// Изменение одного участка памяти при помощи STREX
// Монитор отлавливает нарушение 
static void test2()
{
    volatile uint32_t var = 0;
    __LDREXW(&var);
    __STREXW(20, &var);
    bool res = __STREXW(10, &var) == 0;
    led_on(res);
}

// Изменение разных участков памяти при помощи STREX
// Монитор отлавливает нарушение 
static void test3()
{
    volatile uint32_t var = 0;
    volatile uint32_t var2 = 0;
    __LDREXW(&var);
    __STREXW(20, &var2);
    bool res = __STREXW(10, &var) == 0;
    led_on(res);
}

// Прерывание между LDREX и STREX
// Монитор отлавливает нарушение 
// volatile bool interrupt_executed = false;
static void test4()
{
    volatile uint32_t var = 0;
    __LDREXW(&var);

    // Вот таким вот нехитрым образом добиваемся прерывания ))
    ADC_<1>::start_regular_conversion();
    ADC_<1>::start_regular_conversion();
    ADC_<1>::start_regular_conversion();
    ADC_<1>::start_regular_conversion();
    ADC_<1>::start_regular_conversion();
    ADC_<1>::start_regular_conversion();
    ADC_<1>::start_regular_conversion();
    ADC_<1>::start_regular_conversion();
    ADC_<1>::start_regular_conversion();
    ADC_<1>::start_regular_conversion();
    ADC_<1>::start_regular_conversion();
    ADC_<1>::start_regular_conversion();
    ADC_<1>::start_regular_conversion();
    ADC_<1>::start_regular_conversion();
    ADC_<1>::start_regular_conversion();
    ADC_<1>::start_regular_conversion();
    ADC_<1>::start_regular_conversion();
    ADC_<1>::start_regular_conversion();
    ADC_<1>::start_regular_conversion();
    ADC_<1>::start_regular_conversion();
    ADC_<1>::start_regular_conversion();
    ADC_<1>::start_regular_conversion();
    // Тут прерывание точно произошло, т.к. мы работаем на частоте 2 МГц, а АЦП на 16 Мгц

    // Это осталось от предыдущего теста:
    // while (!interrupt_executed) {}

    bool res = __STREXW(10, &var) == 0;
    led_on(res);
}

extern "C" void ADC1_IRQHandler()
{
//    interrupt_executed = true;
    ADC_<1>::clear_eoc_flag();
}

int main()
{
    init_led();
    adc_init();
//    test0();
//    test1();
//    test2();
//    test3();
    test4();
}

 

Один из старых вариантов тестирования прерывания был таким:

 

static void test4()
{
    volatile uint32_t var = 0;
    __LDREXW(&var);

    ADC_<1>::start_regular_conversion();
    while (!interrupt_executed) {}

    bool res = __STREXW(10, &var) == 0;
    led_on(res);
}

extern "C" void ADC1_IRQHandler()
{
    interrupt_executed = true;
    ADC_<1>::clear_eoc_flag();
}

Он тоже показывал что монитор отловил нарушение эксклюзивного доступа.

 

PS: критика крайне приветствуется ))

Изменено пользователем ArtDenis

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ну, вроде всё вполне согласуется с моими опытами.

Единственный момент, ADC_<1>::clear_eoc_flag() - наверняка делает STR в область периферии. Для чистоты эксперимента хорошо бы сделать совсем пустой обработчик прерывания.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...