Cortex M3 obsługuje użyteczną parę operacji operacyjnych (wspólnych również w wielu innych maszynach) o nazwie „Load-Exclusive” (LDREX) i „Store-Exclusive” (STREX). Koncepcyjnie operacja LDREX wykonuje ładowanie, ustawia także specjalny sprzęt, aby obserwować, czy załadowana lokalizacja może być zapisana przez coś innego. Wykonanie STREX na adres użyty przez ostatni LDREX spowoduje, że adres zostanie zapisany tylko wtedy, gdy nic innego nie zostanie napisane najpierw . Instrukcja STREX załaduje rejestr z wartością 0, jeśli sklep miał miejsce, lub 1, jeśli został przerwany.
Pamiętaj, że STREX jest często pesymistyczny. Istnieje wiele sytuacji, w których może zdecydować się nie prowadzić sklepu, nawet jeśli dane miejsce nie zostało dotknięte. Na przykład przerwanie między LDREX a STREX spowoduje, że STREX przyjmie, że obserwowana lokalizacja mogła zostać trafiona. Z tego powodu zwykle dobrym pomysłem jest zminimalizowanie ilości kodu między LDREX a STREX. Rozważmy na przykład coś takiego:
inline void safe_increment (uint32_t * addr)
{
uint32_t nowa_wartość;
zrobić
{
nowa_wartość = __ldrex (addr) + 1;
} while (__ strex (nowa_wartość, adres));
}
który kompiluje się do czegoś takiego:
; Załóżmy, że R0 zawiera dany adres; r1 zniszczony
lp:
ldrex r1, [r0]
dodaj r1, r1, # 1
strex r1, r1, [r0]
cmp r1, # 0; Sprawdź, czy niezerowa
bne lp
.. kod trwa
Przez większość czasu wykonywania kodu między LDREX i STREX nic się nie stanie, aby je „zakłócić”, więc STREX odniesie sukces bez zbędnych ceregieli. Jeśli jednak nastąpi natychmiastowe przerwanie po instrukcji LDREX lub ADD, STREX nie wykona zapisu, ale zamiast tego kod wróci do odczytu (ewentualnie zaktualizowanej) wartości [r0] i wyliczy nową wartość przyrostową w oparciu o to.
Wykorzystanie LDREX / STREX do tworzenia operacji takich jak safe_increment pozwala nie tylko zarządzać krytycznymi sekcjami, ale także w wielu przypadkach, aby uniknąć ich potrzeby.
while(STREXW(new_value, addr);
Jak możemy uważać, że to, co uważasz za poprawne, jeśli Twój kod nawet się nie skompiluje?Wygląda na to, że potrzebujesz oprogramowania okrągłych buforów lub FIFO w oprogramowaniu MCU. Śledząc dwa wskaźniki lub wskaźniki do tablicy w celu odczytu i zapisu, możesz mieć dostęp do tego samego bufora zarówno na pierwszym planie, jak iw tle bez zakłóceń.
Kod pierwszego planu można w dowolnym momencie zapisać w buforze cyklicznym. Wstawia dane we wskaźniku zapisu, a następnie zwiększa wskaźnik zapisu.
Kod w tle (obsługa przerwań) zużywa dane ze wskaźnika odczytu i zwiększa wskaźnik odczytu.
Gdy wskaźniki odczytu i zapisu są równe, bufor jest pusty, a proces w tle nie wysyła danych. Gdy bufor jest pełny, proces pierwszego planu odmawia zapisania (lub może zastąpić stare dane, w zależności od potrzeb).
Używanie okrągłych buforów do oddzielania czytników i programów piszących powinno wyeliminować potrzebę wyłączania przerwań.
źródło
Nie pamiętam dokładnej lokalizacji, ale w bibliotekach pochodzących z ARM (nie TI, ARM, powinien być pod CMSIS lub coś w tym rodzaju, używam ST, ale pamiętam gdzieś, że ten plik pochodzi z ARM, więc powinieneś go również mieć ) dostępna jest opcja globalnego wyłączenia przerwań. Jest to wywołanie funkcji. (Nie jestem w pracy, ale jutro sprawdzę dokładną funkcję). Chciałbym zakończyć to ładną nazwą w twoim systemie i wyłączyć przerwania, zrób swoje i włącz ponownie. Powiedziawszy to, lepszym rozwiązaniem byłoby zaimplementowanie semafora lub struktury kolejki zamiast globalnego wyłączenia przerwań.
źródło