|
|
  |
Библиотека атомарных операций для STM32 |
|
|
|
Jun 23 2015, 07:21
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(ViKo @ Jun 23 2015, 11:55)  Если бы эксклюзивные операции отслеживали только сами себя, толку от них было бы никакого. Так можно и обычным флагом обойтись, когда захотел - установил, когда надо - проверил... Смысл именно в том, что мониторится любое обращение к памяти А зачем Вам мониторить все обращения? Ведь нужны только те обращения, которые могут использоваться для доступа к переменным синхронизации. Если Вам нужна чтение-модификация-запись переменной синхронизации, или неатомарное чтение (несколькиим командами) этой переменной, или запись (любая) в эту переменную, то извольте все эти операции выполнять только инструкциями LDREX/STREX. Тогда всё будет нормально и ставить этот бит по каждому обращению к памяти совсем излишне (но конечно возможно для упрощения реализации ядра CPU). А просто чтение этой-же переменной синхронизации можно делать и вообще одной командой LDR (которая априори атомарна) пусть даже она и попадёт между LDREX и STREX выполняющимися в другом потоке - это никак не повлияет на результат. Цитата(AlexandrY @ Jun 23 2015, 12:45)  В Cortex-M4 операция STREX даст отбой даже если в прерывании запись была сделана командой STR и совсем в другую ячейку памяти. Вполне возможно для упрощения реализации механизма в ядре сделали срабатывание не только на эксклюзивный доступ.
|
|
|
|
|
Jun 23 2015, 17:24
|

Ally
     
Группа: Модераторы
Сообщений: 6 232
Регистрация: 19-01-05
Пользователь №: 2 050

|
Цитата(jcxz @ Jun 23 2015, 10:21)  Вполне возможно для упрощения реализации механизма в ядре сделали срабатывание не только на эксклюзивный доступ. С LDREX/STREX все еще более запутанней. Решил тут протестировать как там насчет работы из разных областей памяти. Выяснилось, что LDREX/STREX правильно работает когда переменные находятся в RAM вблизи 0x1000_0000-0x3000_0000 То, что кэширование разное сверху и снизу границы 0x2000_0000 никак не влияет, барьеры памяти можно не ставить. А вот если использовать память которая находится после границы 0x4000_0000 , то пара LDREX/STREX там никакого эффекта не дает, хотя и исключений не вызывает. Т.е. можно спокойно испортить переменную, а STREX ничего не покажет. Ну и как положительный момент можно отметить, что выполнение кода из RAM на работу LDREX/STREX тоже не влияет. А с DMA вопрос еще темный. Мутный момент также с областями внешней памяти.
|
|
|
|
|
Jun 23 2015, 18:42
|
Частый гость
 
Группа: Участник
Сообщений: 142
Регистрация: 10-11-12
Пользователь №: 74 318

|
Цитата(AlexandrY @ Jun 23 2015, 23:25)  Странно, у меня не на любое, а только такое где был STREX или STR во внутреннюю RAM , а вот на PUSH в ту же RAM не реагирует Вообще, в прерывании был STR. Не подумал когда тестировал, что это имеет значение
--------------------
|
|
|
|
|
Jun 24 2015, 02:48
|
Частый гость
 
Группа: Участник
Сообщений: 142
Регистрация: 10-11-12
Пользователь №: 74 318

|
Цитата(ArtDenis @ Jun 23 2015, 23:42)  Вообще, в прерывании был STR. Не подумал когда тестировал, что это имеет значение Проверил ещё раз. Достаточно любого прерывания.
--------------------
|
|
|
|
|
Jun 24 2015, 04:19
|
Частый гость
 
Группа: Участник
Сообщений: 142
Регистрация: 10-11-12
Пользователь №: 74 318

|
Цитата(ViKo @ Jun 24 2015, 09:00)  Программы - в студию. К сожалению по мере тестирования программа менялась  Последний вариант - тестирование пустого прерывания. Устроит? А выводы - вроде как работает, но не настолько эффективно как хотелось. Скорее всего буду использовать.
Сообщение отредактировал ArtDenis - Jun 24 2015, 07:40
--------------------
|
|
|
|
|
Jun 24 2015, 08:00
|
Частый гость
 
Группа: Участник
Сообщений: 142
Регистрация: 10-11-12
Пользователь №: 74 318

|
Цитата(ViKo @ Jun 24 2015, 12:44)  Устроят любые программы, как образец. И тестировщиков прибавится. И выводы скорректируются. Ну держи. Правда, используется собственная либа для работы с периферией. Если светодиод загорелся, то монитор не отловил нарушений, если не загорелся, то отловил. К сожалению, светодиод на плате один. Поскупился я на них )) Код #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 - Jun 24 2015, 08:01
--------------------
|
|
|
|
|
Jun 24 2015, 09:02
|
Частый гость
 
Группа: Участник
Сообщений: 142
Регистрация: 10-11-12
Пользователь №: 74 318

|
Недокопипастил. Там в конце main() ещё Код for (;;) {} стоит
--------------------
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|