|
|
  |
STM32 - Атомарная операция в обработчике прерывания. |
|
|
|
Jan 8 2015, 09:47
|
Профессионал
    
Группа: Свой
Сообщений: 1 719
Регистрация: 13-09-05
Из: Novosibirsk
Пользователь №: 8 528

|
Нет, не приведёт. У AVR просто бит I выполнял две функции - (1) запрет/разрешение прерываний и (2) приоритет исполняемого кода. У ARM эти функции разделены, disable_irq и enable_irq управляют только битом в регистре PRIMASK (запрет/разрешение), а текущий приоритет вычисляется довольно хитрым способом, описанном в ARMv7-M Architecture Reference Manual, на основе BASEPRI, PRIMASK, FAULTMASK и приоритетов всех активных обработчиков, т.е. тех, что начали исполняться, но были прерваны более приоритетным запросом. Смотреть "Execution priority and priority boosting" в упомянутом мануале.
--------------------
Russia est omnis divisa in partes octo.
|
|
|
|
|
Jan 8 2015, 13:32
|
Знающий
   
Группа: Участник
Сообщений: 537
Регистрация: 22-02-06
Пользователь №: 14 594

|
Перед выполнением атомарных операций с GPIO в прерывании в STM32 выключать прерывания не нужно. Спасибо, что есть регистры BRR, BSRR. При работе через библиотеку они так же используются: Код void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin) { /* Check the parameters */ assert_param(IS_GPIO_ALL_PERIPH(GPIOx)); assert_param(IS_GPIO_PIN(GPIO_Pin)); GPIOx->BSRR = GPIO_Pin; }
... void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin) { /* Check the parameters */ assert_param(IS_GPIO_ALL_PERIPH(GPIOx)); assert_param(IS_GPIO_PIN(GPIO_Pin)); GPIOx->BRR = GPIO_Pin; } Если нужно работать атомарно с любым битом в любом регистре, включая RAM, то можно еще дальше пойти, используя атомарные возможности Cortex-M3-4, но если используется M0, то этой возможности уже не будет.
Сообщение отредактировал kan35 - Jan 8 2015, 13:33
|
|
|
|
|
Jan 9 2015, 19:02
|
Знающий
   
Группа: Участник
Сообщений: 537
Регистрация: 22-02-06
Пользователь №: 14 594

|
Цитата(Alt.F4 @ Jan 8 2015, 19:06)  SSerge, спасибо! kan35, да, я в курсе атомарного bitbanding'a, но у меня в прерывании надо в один буфер срочно толкнуть байт, поэтому одним тактом там не обойдется.
Спасибо большое за разъяснение вопроса! Буду использовать в обработчике disable_irq и enable_irq. Но все таки... Если писать байт в RAM, то атомарность итак будет, или в Cortex-M работа идет только со словами и полусловами? Люди, кто знает его ассемблер - подскажите.
|
|
|
|
|
Jan 12 2015, 14:37
|
Профессионал
    
Группа: Свой
Сообщений: 1 468
Регистрация: 28-03-10
Из: Беларусь
Пользователь №: 56 256

|
Цитата А Вы знаете, что работу с FIFO-буфером можно реализовать вообще без блокировок? Подскажите, пожалуйста, как это можно реализовать? Спасибо.
|
|
|
|
|
Jan 12 2015, 14:59
|
Профессионал
    
Группа: Свой
Сообщений: 1 719
Регистрация: 13-09-05
Из: Novosibirsk
Пользователь №: 8 528

|
Цитата(Alt.F4 @ Jan 12 2015, 21:37)  Подскажите, пожалуйста, как это можно реализовать? Спасибо. Как ни странно - легко и без затей. Фокус в том, что если поразбираться, то окажется что каждая функция меняет только один указатель/индекс, а второй только читает. Поэтому при "внезапном" изменении значения этого второго индекса ничего страшного не происходит. Единственное, что требуется - чтобы операции чтения и записи индексов были атомарны, по этой причине на 8-битниках индексы придётся сделать тоже uint8_t, но там и этого будет достаточно. CODE typedef struct { uint32_t PushIndx; uint32_t PopIndx; uint8_t Buffer[UART_FIFO_SIZE]; } UartFifo_t;
inline static bool FifoPush( UartFifo_t* Fifo, uint8_t Data) { // calculate next push index uint32_t IndxTmp = Fifo->PushIndx + 1; if( IndxTmp == UART_FIFO_SIZE ) IndxTmp = 0;
if (IndxTmp == Fifo->PopIndx) // Check FIFO state return(false); // The FIFO is full
Fifo->Buffer[Fifo->PushIndx] = Data; // Push the data
Fifo->PushIndx = IndxTmp; // Updating the push's index return(true); }
static bool FifoPop( UartFifo_t *Fifo, uint8_t *pData) { if (Fifo->PushIndx == Fifo->PopIndx) // Check FIFO state return(false);// The FIFO is empty
*pData = Fifo->Buffer[Fifo->PopIndx]; // Pop the data
// Calculate the next pop index uint32_t IndxTmp = Fifo->PopIndx + 1; if( IndxTmp == UART_FIFO_SIZE ) IndxTmp = 0; Fifo->PopIndx = IndxTmp; // Updating of the pop's index return(true); }
--------------------
Russia est omnis divisa in partes octo.
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|