В настоящее время я портирую свой DCF77 library (вы можете найти source code at GitHub) от Arduino (на базе AVR) до Arduino Due (ARM Cortex M3). Я абсолютно новичок с платформой ARM.Атомный блок для чтения против ARM SysTicks
С помощью Arduino, основанного на AVR, я могу использовать avr-libc для получения атомных блоков. В основном это блокирует все прерывания во время блока и позволяет прерываниям позже снова. Для AVR это было хорошо. Теперь для ARM Cortex вещи начинают усложняться.
Прежде всего: для использования в настоящее время библиотеки этот подход будет работать. Итак, мой первый вопрос: есть ли аналогичные макросы «ATOMIC» avr-libc для ARM? Очевидно, другие люди думали о something in this directions. Поскольку я использую gcc, я мог бы улучшить эти макросы, чтобы работать почти так же, как avr-libv ATOMIC macors. Я уже нашел некоторый CMSIS documentation, но это похоже только на макрос «enable_irq» вместо макроса «restore_irq».
Вопрос 1: есть ли там библиотека (для gcc), которая уже делает это?
Поскольку ARM имеет разные приоритетные прерывания, я мог бы установить атомарность по-разному. В моем случае «атомные» блоки должны только удостовериться, что они не прерываются прерыванием systick. Так что на самом деле мне не нужно было бы блокировать все, чтобы мои блоки были «достаточно атомными». В дальнейшем я нашел ARM synchronization primitives article in the developer infocenter. Особенно есть намек на lockless programming. Согласно этой статье, это передовая концепция и что на ней много публикаций. Поиск в сети я нашел только общие объяснения концепции, например. here. Я предполагаю, что беззаконная реализация будет очень крутой, но в это время я чувствую себя недостаточно уверенно в ARM, чтобы реализовать это с нуля.
Вопрос 2: Есть ли у кого-нибудь какие-то подсказки для меня на блокированных чтениях блоков памяти на ARM Cortex M3?
Как я уже сказал, мне нужно защитить только нижний приоритетный поток от sysTicks. Таким образом, еще одним вариантом было бы короткое время отключить sysTicks. Поскольку я реализую алгоритм синхронизации с учетом времени, это не должно замедлять общую частоту sysTick в долгосрочной перспективе. Тем не менее, введение небольшого джиттера было бы в порядке. В это время я бы нашел это самым привлекательным.
Вопрос 3: Есть ли хороший способ блокировки прерываний sysTick без потери тиков?
Я также нашел CMSIS documentation for semaphores. Однако я несколько ошеломлен. Особенно мне интересно, следует ли мне использовать CMSIS и как это сделать на Arduino Due.
Вопрос 4: Какой будет мой лучший вариант? Или где я должен продолжать читать?
Частичный ответ: с намеком из Notlikethat я реализовал
#if defined(ARDUINO_ARCH_AVR)
#include <util/atomic.h>
#define CRITICAL_SECTION ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
#elif defined(ARDUINO_ARCH_SAM)
// Workaround as suggested by Stackoverflow user "Notlikethat"
// http://stackoverflow.com/questions/27998059/atomic-block-for-reading-vs-arm-systicks
static inline int __int_disable_irq(void) {
int primask;
asm volatile("mrs %0, PRIMASK\n" : "=r"(primask));
asm volatile("cpsid i\n");
return primask & 1;
}
static inline void __int_restore_irq(int *primask) {
if (!(*primask)) {
asm volatile ("" ::: "memory");
asm volatile("cpsie i\n");
}
}
// This critical section macro borrows heavily from
// avr-libc util/atomic.h
// --> http://www.nongnu.org/avr-libc/user-manual/atomic_8h_source.html
#define CRITICAL_SECTION for (int primask_save __attribute__((__cleanup__(__int_restore_irq))) = __int_disable_irq(), __ToDo = 1; __ToDo; __ToDo = 0)
#else
#error Unsupported controller architecture
#endif
Этот макрос делает более или менее то, что мне нужно. Однако я нахожу, что есть место для улучшения, поскольку это блокирует все прерывания, хотя было бы достаточно блокировать только систолы. Так что вопрос 3 по-прежнему открыт.
Я уверен, что 'asm volatile (" mrs% 0, PRIMASK \ n "::" r "(primask));' Плохая сборка, потому что она отмечает переменную primask как вход вместо вывода, что приведет к тому, что GCC будет повторно использовать регистр. Я видел серьезные недостатки. Исправлено: 'asm volatile (" mrs% 0, PRIMASK \ n ":" = r "(primask));' –