|
Библиотека атомарных операций для STM32 |
|
|
|
 |
Ответов
(1 - 50)
|
Jun 18 2015, 19:27
|

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

|
Цитата(ArtDenis @ Jun 18 2015, 19:31)  Кто-нибудь встречал в природе готовую библиотеку для атомарных операций над целочисленными значениями? Интересуют стандартные операции типа "сравнить и обменять", арифметические операции (сложить и вернуть предыдущее значение), битовые и т.д. STM32 мало чем отличается от других чипов на архитектуре ARMv7-M поэтому вам подойдет и такое - http://mintomic.github.io/Кстати, спасибо что напомнили. Самому уже надоело запрещение прерываний расставлять по всем углам. В том проекте только один файл и интересен. Это - https://github.com/mintomic/mintomic/blob/m.../mintomic_gcc.cТам несколько примеров ассемблерных функций сравнения, сложения и логические, но и их хватает чтобы полностью понять тему.
|
|
|
|
|
Jun 19 2015, 04:40
|

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

|
Цитата(AHTOXA @ Jun 18 2015, 23:40)  Не то, чтобы библиотека, но часть примитивов там точно есть: тынц. Ну это уж совсем низкий уровень. Там в SoC-ах на ARM Cortex столько нюансов, что писать это на C значит просто "прострелить себе ногу". Лучше тогда дать ссылку на первоисточник: http://infocenter.arm.com/help/index.jsp?t...008a/index.htmlГде выяснится, что реализация эксклюзивных мониторов зависит от производителя SoC-а. От него же зависит и такая вещь как Exclusives Reservation Granule. Совершенно темной остается тема конфликтов с DMA. Помнить надо и о типе памяти (normal, device, ordered), т.е. совершенно четко его знать. И проч.
|
|
|
|
|
Jun 19 2015, 07:48
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Вот моя реализация инкремента/декремента, обмена и сравнения-обмена для разных типов: CODE PUBLIC _Z9AtomicIncPVh, _Z9AtomicDecPVh PUBLIC _Z10AtomicSwapPVhj, _Z10AtomicSwapPVtj _Z10AtomicSwapPVjj PUBLIC _Z13AtomicCmpSwapPVhjj, _Z13AtomicCmpSwapPVtjj, _Z13AtomicCmpSwapPVjjj
;uint AtomicInc(u8 volatile *); _Z9AtomicIncPVh: aInc8_01: LDREXB R3, [R0] ADDS R1, R3, #1 STREXB R2, R1, [R0] CMP R2, #0 BNE aInc8_01 MOV R0, R3 BX LR
;uint AtomicDec(u8 volatile *); _Z9AtomicDecPVh: aDec8_01: LDREXB R3, [R0] SUBS R1, R3, #1 STREXB R2, R1, [R0] CMP R2, #0 BNE aDec8_01 MOV R0, R3 BX LR
;АтомарнаЯ операциЯ "обмен" длЯ типа u8. ;uint AtomicSwap(u8 volatile *, uint); _Z10AtomicSwapPVhj: aSwap8_01: LDREXB R3, [R0] STREXB R2, R1, [R0] CMP R2, #0 BNE aSwap8_01 MOV R0, R3 BX LR
;АтомарнаЯ операциЯ "обмен" длЯ типа u16. ;uint AtomicSwap(u16 volatile *, uint); _Z10AtomicSwapPVtj: aSwap16_01: LDREXH R3, [R0] STREXH R2, R1, [R0] CMP R2, #0 BNE aSwap16_01 MOV R0, R3 BX LR
;АтомарнаЯ операциЯ "обмен" длЯ типа u32. ;u32 AtomicSwap(u32 volatile *, u32); _Z10AtomicSwapPVjj: aSwap32_01: LDREX R3, [R0] STREX R2, R1, [R0] CMP R2, #0 BNE aSwap32_01 MOV R0, R3 BX LR
;АтомарнаЯ операциЯ "сравнение и обмен" длЯ типа u8. ;uint AtomicCmpSwap(u8 volatile *ptr, uint newVal, uint cmpVal); _Z13AtomicCmpSwapPVhjj: aCmpSwap8_01: LDREXB R12, [R0] CMP R12, R2 ITT EQ STREXBEQ R3, R1, [R0] CMPEQ R3, #1 BEQ aCmpSwap8_01 MOV R0, R12 BX LR
;АтомарнаЯ операциЯ "сравнение и обмен" длЯ типа u16. ;uint AtomicCmpSwap(u16 volatile *ptr, uint newVal, uint cmpVal); _Z13AtomicCmpSwapPVtjj: aCmpSwap16_01: LDREXH R12, [R0] CMP R12, R2 ITT EQ STREXHEQ R3, R1, [R0] CMPEQ R3, #1 BEQ aCmpSwap16_01 MOV R0, R12 BX LR
;АтомарнаЯ операциЯ "сравнение и обмен" длЯ типа u32. ;u32 AtomicCmpSwap(u32 volatile *ptr, u32 newVal, u32 cmpVal); _Z13AtomicCmpSwapPVjjj: aCmpSwap32_01: LDREX R12, [R0] CMP R12, R2 ITT EQ STREXEQ R3, R1, [R0] CMPEQ R3, #1 BEQ aCmpSwap32_01 MOV R0, R12 BX LR
си++ - хидеры: Код uint AtomicInc(u8 volatile *); uint AtomicDec(u8 volatile *); uint AtomicSwap(u8 volatile *, uint); uint AtomicSwap(u16 volatile *, uint); u32 AtomicSwap(u32 volatile *, u32); uint AtomicCmpSwap(u8 volatile *, uint newVal, uint cmpVal); uint AtomicCmpSwap(u16 volatile *, uint newVal, uint cmpVal); u32 AtomicCmpSwap(u32 volatile *, u32 newVal, u32 cmpVal); Все остальные операции сможете сами реализовать если прочитаете доку о командах LDREX/STREX.
|
|
|
|
|
Jun 19 2015, 08:27
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(AlexandrY @ Jun 19 2015, 14:24)  А оно работает? Тут самое интересное как это тестировалось и на чем или ком.  Работает. На LPC17xx в нескольких проектах, под uCOS. Хотя довольно редко использую. А что там тестировать? Три строчки... Совместно с DMA не использую конечно, да и не нужно это. А для взаимодействия между разными задачами ОС и ISR - вполне подходит. И тип памяти никакой роли не играет.
|
|
|
|
|
Jun 19 2015, 08:34
|

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

|
Цитата(jcxz @ Jun 19 2015, 11:27)  Работает. На LPC17xx в нескольких проектах, под uCOS. Хотя довольно редко использую. А что там тестировать? Три строчки... Совместно с DMA не использую конечно, да и не нужно это. А для взаимодействия между разными задачами ОС и ISR - вполне подходит. И тип памяти никакой роли не играет. Т.е. даете честное слово? Без тестирования? Но при этом ни Exclusives Reservation Granule, ни влияние DMA не знаете? Смысл то этой штуки быть быстрой, а какой толк если задача на ней застрянет пока не исполнится все, что так или иначе использует RAM. А если есть код в RAM? Вообще капец?
|
|
|
|
|
Jun 19 2015, 08:42
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(AlexandrY @ Jun 19 2015, 14:34)  Но при этом ни Exclusives Reservation Granule, ни влияние DMA не знаете? Зачем тут DMA??? Это средство синхронизации задач/ISR. Вы задачи между собой при помощи DMA синхронизируете??? Зачем к переменным, служащим для синхронизации задач, обращаться через DMA??? Цитата(AlexandrY @ Jun 19 2015, 14:34)  Смысл то этой штуки быть быстрой, а какой толк если задача на ней застрянет пока не исполнится все, что так или иначе использует RAM. А если есть код в RAM? Вообще капец? Тогда используйте обычный запрет прерываний.
|
|
|
|
|
Jun 19 2015, 12:40
|
Частый гость
 
Группа: Участник
Сообщений: 142
Регистрация: 10-11-12
Пользователь №: 74 318

|
Цитата(Gleb80 @ Jun 18 2015, 23:47)  Атомарная, тоесть выполняющаяся за один машинный цикл? Может лучше использовать ассемблер для конкретного контроллера? Атомарная - это "выглядящая" как одно изменение для кода, который придерживается правил использования атомарных операций. В общем, судя по ответам, с этим довольно-таки грустно у STM32. Для начала попробую встроенные в gcc функции, которые тут посоветовали: https://gcc.gnu.org/onlinedocs/gcc-4.4.3/gc...c-Builtins.html Их кто-нибудь проверял для STM32? Насколько надёжно они работают? Ещё в C++11 в стандартную библиотеку добавлена поддержка атомарности через шаблон std::atomic. Интересно есть ли его реализация для STM32?
--------------------
|
|
|
|
|
Jun 22 2015, 04:01
|
Частый гость
 
Группа: Участник
Сообщений: 142
Регистрация: 10-11-12
Пользователь №: 74 318

|
Ковыряю std::atomic. Оказывается они работают для STM32 под GCC. Вот какой код генерируются при их использовании: Код ; std::atomic<unsigned> lalala; ; unsigned to_test = 20; ; ........
; lalala = 10; 8000a8a: f3bf 8f5f dmb sy 8000a8e: 4a0d ldr r2, [pc, #52]; (8000ac4 <main+0x3c>) 8000a90: 210a movs r1, #10 8000a92: 6011 str r1, [r2, #0] 8000a94: f3bf 8f5f dmb sy
; lalala.compare_exchange_strong(to_test, 10); 8000a98: 4b0b ldr r3, [pc, #44]; (8000ac8 <main+0x40>) 8000a9a: 681c ldr r4, [r3, #0] 8000a9c: f3bf 8f5f dmb sy 8000aa0: e852 0f00 ldrex r0, [r2] 8000aa4: 42a0 cmp r0, r4 8000aa6: d104 bne.n 8000ab2 <main+0x2a> 8000aa8: e842 1e00 strex lr, r1, [r2] 8000aac: f1be 0f00 cmp.w lr, #0 8000ab0: d1f6 bne.n 8000aa0 <main+0x18> 8000ab2: f3bf 8f5f dmb sy 8000ab6: bf18 it ne 8000ab8: 6018 strne r0, [r3, #0] В ассемблере армов разбираюсь плохо. Насколько всё хорошо/плохо в данном случае?
--------------------
|
|
|
|
|
Jun 22 2015, 13:53
|
Частый гость
 
Группа: Участник
Сообщений: 142
Регистрация: 10-11-12
Пользователь №: 74 318

|
Цитата(AlexandrY @ Jun 22 2015, 18:26)  Тему можно закрывать. Эксклюзивный монитор у Cortex-M4 всю память считает как одно целое. Значит атомная операция будет длится до тех пор пока все не перестанут пользоваться памятью. Т.е. возможно вечно !  А можно для тех кто в танке объяснить что это означает? И как обстоят дела у M3?
--------------------
|
|
|
|
|
Jun 22 2015, 18:40
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Цитата(ArtDenis @ Jun 22 2015, 18:53)  А можно для тех кто в танке объяснить что это означает? И как обстоят дела у M3? Это означает, что любая запись в память в промежутке между LDREX и STREX приведёт к неудаче STREX и повтору попытки. Другими словами, если между LDREX и STREX возникнет прерывание, то попытку атомарного доступа почти наверняка придётся повторить, даже если обработчик прерывания не обращался к защищаемой переменной. Это происходит потому, что монитор отслеживает не обращение к конкретному адресу, а обращение к памяти вообще. Насчёт "возможно вечно" - это конечно гипербола, хотя при наличии, скажем, DMA, который непрерывно пишет в буфер в ОЗУ, проскочить будет довольно трудно. Надо, кстати, попробовать... ЗЫ. У M3 дела обстоят точно так же.
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Jun 23 2015, 02:44
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(AlexandrY @ Jun 22 2015, 19:26)  Значит атомная операция будет длится до тех пор пока все не перестанут пользоваться памятью. Т.е. возможно вечно !  Расстояние между LDREX и STREX в моих функциях всего несколько тактов. С какой частотой у Вас в системе должны идти прерывания чтобы обеспечивалось 100% попадание между LDREX и STREX эксклюзивного доступа другого процесса? Цитата(AHTOXA @ Jun 23 2015, 00:40)  Это означает, что любая запись в память в промежутке между LDREX и STREX приведёт к неудаче STREX и повтору попытки. Даташит на эту тему не читал, но с выскокой вероятностью могу предположить, что скорей всего не любая, а только эксклюзивная (LDREX/STREX). Цитата(AHTOXA @ Jun 23 2015, 00:40)  Насчёт "возможно вечно" - это конечно гипербола, хотя при наличии, скажем, DMA, который непрерывно пишет в буфер в ОЗУ, проскочить будет довольно трудно. Ещё раз оговорюсь, что даташит не читал, но логика подсказывает, что DMA никак не будет влиять на LDREX/STREX, так как скорей всего не является эксклюзивным доступом (не нужно это для DMA).
|
|
|
|
|
Jun 23 2015, 05:01
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Цитата(jcxz @ Jun 23 2015, 07:44)  Даташит на эту тему не читал, но с выскокой вероятностью могу предположить, что скорей всего не любая, а только эксклюзивная (LDREX/STREX). Да, так логичнее, но, когда я проводил эксперименты с LDREX/STREX, то, вроде бы, любое прерывание приводило к сбою STREX, вне зависимости от того, что было в обработчике этого прерывания. Хотя, я не углублялся, возможно, что-то было не так в условиях моего эксперимента. Посмотрим, что получится у ArtDenis.
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Jun 23 2015, 05:55
|

Универсальный солдатик
     
Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362

|
Если бы эксклюзивные операции отслеживали только сами себя, толку от них было бы никакого. Так можно и обычным флагом обойтись, когда захотел - установил, когда надо - проверил... Смысл именно в том, что мониторится любое обращение к памяти (надо думать, запись). Типа, триггера. LDREX разрешает работу триггера, любая запись в память устанавливает его в 1, CLREX сбрасывает его. STREX проверяет триггер, и если он установлен, не пишет в память, и выдает 1 в регистр. И запрещает мониторинг (триггер).
|
|
|
|
|
Jun 23 2015, 06:45
|

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

|
Цитата(ViKo @ Jun 23 2015, 08:55)  Если бы эксклюзивные операции отслеживали только сами себя, толку от них было бы никакого. Так можно и обычным флагом обойтись, когда захотел - установил, когда надо - проверил... Смысл именно в том, что мониторится любое обращение к памяти (надо думать, запись). Типа, триггера. LDREX разрешает работу триггера, любая запись в память устанавливает его в 1, CLREX сбрасывает его. STREX проверяет триггер, и если он установлен, не пишет в память, и выдает 1 в регистр. И запрещает мониторинг (триггер). Да, это проверенно. В Cortex-M4 операция STREX даст отбой даже если в прерывании запись была сделана командой STR и совсем в другую ячейку памяти.
|
|
|
|
|
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 (;;) {} стоит
--------------------
|
|
|
|
|
Jun 24 2015, 09:31
|
Частый гость
 
Группа: Участник
Сообщений: 142
Регистрация: 10-11-12
Пользователь №: 74 318

|
Цитата(AHTOXA @ Jun 24 2015, 14:19)  Ну, вроде всё вполне согласуется с моими опытами. Единственный момент, ADC_<1>::clear_eoc_flag() - наверняка делает STR в область периферии. Для чистоты эксперимента хорошо бы сделать совсем пустой обработчик прерывания. Так вроде как область адресов периферии не относится к ОЗУ, которое защищает монитор? И без ADC_<1>::clear_eoc_flag() флаг не сбросится и прерывание будет происходить снова и снова как только оно завершиться. Убрал ADC_<1>::clear_eoc_flag(). Поток выполнения перестал доходить до Код bool res = __STREXW(10, &var) == 0; Есть в STM32 такие прерывания для которых не надо сбрасывать флаг при выходе из обработчика?
Сообщение отредактировал ArtDenis - Jun 24 2015, 09:36
--------------------
|
|
|
|
|
Jun 24 2015, 09:42
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(ArtDenis @ Jun 24 2015, 14:00)  PS: критика крайне приветствуется )) Все тесты, кроме test4() бессмысленны. Непонятно - что там тестируется? LDREX/STREX призваны для обнаружения нарушения эксклюзивного доступа (когда при работе одного процесса с переменной, происходит доступ к ней другого процесса). Везде кроме test4() имеется только работа одного процесса. Цитата(ArtDenis @ Jun 24 2015, 15:31)  Есть в STM32 такие прерывания для которых не надо сбрасывать флаг при выходе из обработчика? Все прерывания M-ядра квитируются (переходят в разряд обслуживаемых со снятием запроса). Путаете мух с котлетами. Сбрасывать возможно нужно флаги периферии, вызвавшие срабатывание этих прерываний. Ничего не мешает возбудить эти прерывания программно через NVIC. Читайте мануал на M-ядро.
|
|
|
|
|
Jun 24 2015, 09:49
|
Частый гость
 
Группа: Участник
Сообщений: 142
Регистрация: 10-11-12
Пользователь №: 74 318

|
Цитата(jcxz @ Jun 24 2015, 14:42)  Все тесты, кроме test4() бессмысленны. Непонятно - что там тестируется? LDREX/STREX призваны для обнаружения нарушения эксклюзивного доступа (когда при работе одного процесса с переменной, происходит доступ к ней другого процесса). Везде кроме test4() имеется только работа одного процесса. Вообще тестируется работа монитора эксклюзивного доступа, которому все эти потоки и процессы по барабану. Он вообще не знает о таких вещах. Цитата(jcxz @ Jun 24 2015, 14:42)  Все прерывания M-ядра квитируются (переходят в разряд обслуживаемых со снятием запроса). Путаете мух с котлетами. Сбрасывать возможно нужно флаги периферии, вызвавшие срабатывание этих прерываний. Ничего не мешает возбудить эти прерывания программно через NVIC. Читайте мануал на M-ядро. Так что мне сделать, чтобы был пустой обработчик прерывания, в котором не надо сбрасывать флаг? И кстати, я не понял что именно я путаю и в каком месте ))
--------------------
|
|
|
|
|
Jun 24 2015, 10:27
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Цитата(ArtDenis @ Jun 24 2015, 14:31)  Так вроде как область адресов периферии не относится к ОЗУ, которое защищает монитор? Ну, для полноты охвата тестами  Цитата(ArtDenis @ Jun 24 2015, 14:31)  Есть в STM32 такие прерывания для которых не надо сбрасывать флаг при выходе из обработчика? Например, SysTick. Или, вот, PendSV. Взводится вот так: Код SCB->ICSR = SCB_ICSR_PENDSVSET_Msk;
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Jun 24 2015, 10:34
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(ArtDenis @ Jun 24 2015, 15:49)  Вообще тестируется работа монитора эксклюзивного доступа, которому все эти потоки и процессы по барабану. Он вообще не знает о таких вещах. Вообще этот монитор как раз и создан для этих процессов и потоков. Если что. Цитата(ArtDenis @ Jun 24 2015, 15:49)  Так что мне сделать, чтобы был пустой обработчик прерывания, в котором не надо сбрасывать флаг? И кстати, я не понял что именно я путаю и в каком месте )) Программно активировать любое прерывание через NVIC. Открываете мануал на M-ядро и читаете про "Interrupt Set-Pending Register". Путаете NVIC с периферией посылающей запросы к NVIC.
|
|
|
|
|
Jun 24 2015, 10:44
|
Частый гость
 
Группа: Участник
Сообщений: 142
Регистрация: 10-11-12
Пользователь №: 74 318

|
Цитата(jcxz @ Jun 24 2015, 15:34)  Вообще этот монитор как раз и создан для этих процессов и потоков. Если что. Если он создан для процессов и потоков, это ещё не означает, что для тестирования и проверки как он работает, нам надо обязательно использовать процессы и потоки. Цитата(jcxz @ Jun 24 2015, 15:34)  Программно активировать любое прерывание через NVIC. Путаете NVIC с периферией посылающей запросы к NVIC. А в каком конкретно месте путаю? Цитата(AHTOXA @ Jun 24 2015, 15:27)  Ну, для полноты охвата тестами  Например, SysTick. Или, вот, PendSV. Взводится вот так: Код SCB->ICSR = SCB_ICSR_PENDSVSET_Msk; О. Отлично. Код static void test4() { NVIC_EnableIRQ(PendSV_IRQn);
volatile uint32_t var = 0; __LDREXW(&var);
SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk; __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP();
bool res = __STREXW(10, &var) == 0; led_on(res); }
extern "C" void PendSV_Handler() { } Монитор отловил нарушение доступа
--------------------
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|